Skip to content

one secrets

one secrets 通过 Infisical 管理 monorepo 多子项目的环境变量。从 v0.3.0 起替换了原先的 SOPS+age 实现。详细流程 + 安全契约见 Secrets 指南;本页是命令面 + 字段速查。

Terminal window
one secrets init --project-id <id> [--site-url <url>] [--envs dev,staging,prod] [--default-env dev] [--root-path /] [--skip-verify]
one secrets set <KEY> [VALUE] [--env <e>] [--path <p>] [--yes]
one secrets get <KEY> [--env <e>] [--path <p>]
one secrets list [--env <e>] [--path <p>] [--recursive]
one secrets pull [--env <e>] [--path <p>] [--force] [--dry-run]

通用 flag:-d / --dir(工作区目录,默认当前目录)、--json(强制 JSON 输出)。

把 Infisical 配置写入 one.manifest.json#env。默认在线验证 Universal Auth 凭据 + projectId 可达;带 --skip-verify 跳过。

环境变量:

  • INFISICAL_UNIVERSAL_AUTH_CLIENT_ID — 必填(除非 --skip-verify
  • INFISICAL_UNIVERSAL_AUTH_CLIENT_SECRET — 必填(同上)

输出 schema:one-cli/secrets-init/v1

{
"schema": "one-cli/secrets-init/v1",
"project_id": "<id>",
"site_url": "https://app.infisical.com",
"environments": ["dev", "staging", "prod"],
"default_env": "dev",
"root_path": "/",
"auth_status": "verified",
"written_to": "/abs/path/to/one.manifest.json"
}

写入单个 key。智能选择 create / update:不存在就 create,已存在且不同需要 --yes,相同则返回 unchanged

--path 默认从 cwd 推导:在子项目目录里执行 → /<relativeDir>;在 workspace 根 → rootPath(默认 /)。

输出 schema:one-cli/secrets-set/v1

{
"schema": "one-cli/secrets-set/v1",
"env": "dev",
"path": "/services/user-api",
"key": "DATABASE_URL",
"action": "created" // created | updated | unchanged
}

读取单个 key 的值。JSON 模式 stdout 包含值(agent | jq -r .value | xargs ... 友好)。

输出 schema:one-cli/secrets-get/v1

{
"schema": "one-cli/secrets-get/v1",
"env": "dev",
"path": "/services/user-api",
"key": "DATABASE_URL",
"value": "postgres://..."
}

列出某个 path 下的所有 key 名(不显示值)。--recursive 可包括子 folder。

输出 schema:one-cli/secrets-list/v1

{
"schema": "one-cli/secrets-list/v1",
"env": "dev",
"path": "/services/user-api",
"keys": ["DATABASE_URL", "JWT_SECRET"],
"total": 2
}

核心命令:从 Infisical 拉取所有子项目的密钥,按各自 .env.example 过滤后写入 .env

默认行为(不传 --path):

  1. 遍历每个子项目(apps/*services/*packages/*
  2. 计算其 Infisical path(从 manifest 推导或该 subproject one.manifest.json 条目里的 env.path 覆盖)
  3. 沿继承链拉 key(root → ancestors → self,后者覆盖前者)
  4. 用该子项目的 .env.example 过滤
  5. 写入 .env0600 权限)

--path 时只处理映射到该 Infisical path 的子项目(或 workspace 根)。 带 --dry-run 时只汇报”会写哪些 key”不实际落盘。

输出 schema:one-cli/secrets-pull/v1

{
"schema": "one-cli/secrets-pull/v1",
"env": "dev",
"dry_run": false,
"written_count": 2,
"skipped_count": 1,
"per_subproject": [
{
"name": "user-api",
"relative_dir": "services/user-api",
"infisical_path": "/services/user-api",
"env_file_path": "/abs/.../services/user-api/.env",
"status": "written",
"keys_written": ["DATABASE_URL", "JWT_SECRET"]
},
{
"name": "docs-site",
"relative_dir": "apps/docs-site",
"infisical_path": "/apps/docs-site",
"env_file_path": "/abs/.../apps/docs-site/.env",
"status": "skipped",
"reason": "no .env.example declared"
}
]
}

每次 pull 都经过两层防护:

  1. Infisical folder 隔离:dashboard 子项目(path=/apps/dashboard)拿不到 /services/user-api 下的 key——根本不在它的继承链上
  2. .env.example 过滤:即使共享 folder 含多余 key,子项目 .env 只接收 .env.example 里声明过的

每个想消费 secrets 的子项目必须列出自己的 .env.example,否则 pull 跳过它(reason 字段写明)。

one.manifest.json#env

{
"version": 2,
"env": {
"provider": "infisical",
"projectId": "<id>",
"siteUrl": "https://app.infisical.com",
"environments": ["dev", "staging", "prod"],
"defaultEnv": "dev",
"rootPath": "/"
}
}

one.manifest.json#subprojects[].env

{
"subprojects": [
{
"name": "charge",
"relativeDir": "services/charge",
"templateId": "api-nest",
"toolchain": "node",
"env": {
"path": "/teams/payments/charge",
"inherits": true
}
}
]
}
  • path:覆盖默认推导(/<relativeDir>
  • inherits:默认 true;设 false 关闭父 folder 继承
  • "disabled": true:完全跳过此子项目
错误码处理
INFISICAL_NOT_CONFIGUREDone secrets init --project-id <id>
INFISICAL_AUTH_MISSINGexport INFISICAL_UNIVERSAL_AUTH_CLIENT_ID_CLIENT_SECRET
INFISICAL_AUTH_FAILEDInfisical Web 重新生成 client secret
INFISICAL_PROJECT_NOT_FOUND检查 projectId;确认机器身份在该 project 有访问权限
INFISICAL_NETWORK_ERROR检查网络 + siteUrl
SECRETS_PULL_CONFLICT已有 .env 跟 Infisical 不一致;--force 覆盖
SECRETS_KEY_NOT_FOUND该 env+path 下没有此 KEY;核对 --path 和拼写
SECRETS_INVALID_KEYKEY 必须匹配 ^[A-Za-z_][A-Za-z0-9_]*$
SECRETS_INVALID_ENV_NAMEenv 必须匹配 ^[a-zA-Z0-9][a-zA-Z0-9-_]*$
SECRETS_SET_OVERWRITE_REQUIRED已存在不同值;加 --yes 确认覆盖

完整错误码表见 error-codes

<workspace>/
├── one.manifest.json # env 配置块 + subprojects[].env 覆盖
├── package.json # 普通 pnpm 根(不含 one 字段)
├── apps/
│ └── web/
│ ├── .env.example # 提交(声明该子项目消费的 key)
│ └── .env # 不要提交(pull 的产物,0600)
└── services/
└── api/
├── .env.example
└── .env

不再有 .sops.yaml / .secrets/ 目录 / *.enc 文件——这些都是 SOPS 时代的东西,迁移到 Infisical 后删除即可。

我们支持环境变量传 Universal Auth 凭据。本地推荐 direnv 或 1Password CLI 这类不写盘的方案;CI 直接走 secret 注入。

不要把 INFISICAL_UNIVERSAL_AUTH_CLIENT_* 写到任何 git-tracked 文件——这会绕过整个安全模型。