
cottage v0.6.7
一款面向团队的、基于 git 的现代化 age 加密机密管理器。
cottage 是一个 GitOps 工具,供团队在 Git 仓库中管理 age 加密 的机密。
它提供了一种简单的工作流来加密/解密机密、管理接收方,并且可以在通过 VCS 轻松共享的同时,将机密排除在仓库之外。cottage 还会生成加密机密的脱敏预览以提高可见性;同时支持持久化和临时两种解密工作流,并确保机密永远不会以明文形式提交。

功能
- 防暴露:利用 Rust 的类型系统确保 bug 永远不可能意外泄露机密。
- 团队友好:在仓库中共享公钥(接收方),将私钥(身份)保留在本地。
- 访问控制:简单的允许/拒绝规则,控制哪些机密为哪些接收方加密。
- 管理 .gitignore:自动更新
.gitignore,将未加密的机密排除在仓库之外。 - 预览:生成带时间戳的脱敏加密机密预览,便于直观查看。
- 丰富的 diff:保持 git diff 干净且可审查,同时
ctg diff可显示本地修改的机密与已跟踪加密版本之间的差异。 - 校验和验证:通过验证加密机密和接收方列表与元数据是否匹配来防止篡改。
- Git 钩子:轻松设置 git 钩子,在提交前自动检查/加密机密,并在检出后解密。
- 持久化机密工作流:
ctg decrypt/edit/sync将解密后的机密保留在磁盘上。 - 临时机密工作流:
ctg run(简写ctgx)临时解密机密以运行命令,然后无论命令成功与否都会删除它们。 - 环境注入工作流:
ctg env将解密后的机密作为环境变量注入以运行命令,完全不写入磁盘。 - 清理:
ctg clean删除本地仓库中所有已解密的机密,让你运行 AI 代理时少一些顾虑。 - 支持 jj 和非 Git 目录:
ctg init将任意目录变成机密存储。 - 与任意提供商同步:可将任何提供 API 的提供商配置为上游,并开始像使用
git pull/diff/push一样使用ctg pull/diff/push。 - 与任意设备同步:使用 cottage 加密并在 Git 仓库中管理的机密,可通过 Cottage Sync 跨设备同步。
安装
# rust: cargo-binstall/cargo
cargo binstall --locked cottage
cargo install --locked cottage
# python: pip/uv/uvx
pip install cottage
uv pip install cottage
uvx --from cottage ctg --version
# node: yarn/pnpm/npx
yarn global add @sayanarijit/cottage
pnpm add -g @sayanarijit/cottage
npx -p @sayanarijit/cottage ctg --version
也可作为 Docker 镜像使用:
# Docker
docker run --rm -v $PWD:/app sayanarijit/cottage --version
# Podman
podman run --rm -v $PWD:/app quay.io/sayanarijit/cottage --version
或者从 GitHub 下载最新版本。
编辑器集成
VS Code 扩展
使用 Cottage VS Code 扩展 可以安装 ctg、添加 Copilot 安全钩子、从资源管理器中加密文件,并通过编辑器工作流打开 .cott.age 文件。
可从 Visual Studio Marketplace 安装,或从 vscode-plugin-cottage 在本地构建并安装。
AI 代理集成
以下所有集成都会阻止 AI 代理直接运行 ctg/ctgx,并阻止其查看或编辑机密文件:.cottage/ 内的任何内容、任何 *.cott.* 文件(加密的 *.cott.age 数据块和脱敏的 *.cott.toml 预览),以及磁盘上仍存在对应 *.cott.age 文件的任何已解密文件。
Claude Code 集成
如果你在使用 Claude Code,请将 .claude/settings.json 和 .claude/hooks/deny-secrets.py 添加到包含机密的仓库中,以便 Claude Code 会话安全地处理机密;或者安装 claude-plugin-cottage 插件。
GitHub Copilot 集成
如果你在 VS Code 中使用 GitHub Copilot,请将 .github/hooks/ctg-policy.json 和 .github/hooks/scripts/deny_ctg_command.py 添加到包含机密的仓库中,以便 Copilot 会话清理已解密的文件、阻止直接的 ctg shell 命令,并阻止访问机密文件;或者安装 vscode-plugin-cottage 扩展,从 VS Code 中完成设置。
VS Code 也会加载 .claude/settings.json 钩子定义。如果你在同一个仓库中同时保留 Claude 和 Copilot 的钩子文件,请确保不会意外地重复运行同一个清理钩子。
Codex 集成
如果你在使用 Codex,请将 .codex/hooks.json 和 .codex/hooks/deny-ctg.py 添加到包含机密的仓库中,以便 Codex 会话安全地处理机密;或者安装 codex-plugin-cottage 插件。
Codex 要求本地钩子在运行前经过审查。添加文件后,在仓库中启动 Codex,并使用 /hooks 审查并信任项目钩子。
Antigravity (agy) 集成
如果你在使用 Antigravity(agy),请将 .agents/hooks.json 和 .agents/scripts/deny-ctg.py 添加到包含机密的仓库中,以便 Antigravity 会话安全地处理机密;或者安装 agy-plugin-cottage 插件。
Cursor 集成
如果你在使用 Cursor,请将 .cursor/hooks.json、.cursor/hooks/deny-ctg.py、.cursor/hooks/deny-read-secrets.py、.cursor/rules/deny-ctg.mdc 和 .cursorignore 添加到包含机密的仓库中,以便 Cursor 会话安全地处理机密。
Cursor 需要先启用钩子。打开 Cursor 设置 > Hooks 并启用钩子,然后重启代理会话,使项目钩子生效。.cursorignore 还会将机密文件排除在 Cursor 的索引和 Agent 的上下文之外。
快速入门
初始化项目:
mkdir project && cd project
git init # Optional, cottage works better with git but it's not required
ctg init # Sets up the .cottage directory and necessary files
tree -a
# .
# ├ .cottage/ <- Auto-generated by `ctg init`
# │ ├ identity <- Your private key, keep it safe. Move it to `~/.config/cottage/identity` to use it globally, or replace it with a soft link to one of your existing private keys.
# │ └ recipients/ <- This is where your team keeps the public keys of all the recipients.
# │ └ sayanarijit <- Your public key. Commit it. To use an existing public key, just copy (don't softlink) that key here.
# ├ .git/...
# ├ .gitattributes <- Added `*.cott.age binary export-ignore filter=cottage-encrypted -diff` to avoid polluting git diff
# └ .gitignore <- Added `/.cottage/identity` for obvious reasons
# You can run `ctg clean --all` anytime to clean up everything cottage ever did.
创建或编辑机密。
ctg edit secret.yml --clean # Opens secret.yml in $EDITOR
ctg encrypt secret.yml --clean # Another way to encrypt secrets
# encrypt secret.yml
# into secret.yml.cott.age
# edit secret.yml.cott.toml
# edit .gitignore
# delete secret.yml
使用临时解密的机密运行命令:
cat secret.yml
# cat: secret.yml: No such file or directory
ctg run kubectl apply -f secret.yml # decrypts secret.yml.cott.age to secret.yml and runs the command
ctg run kubectl apply -f secret.yml.cott.age # also replaces the path argument with the decrypted file path
ctg run kubectl apply -f . # decrypts all .cott.age files in . and runs the command
ctg run ./deploy.sh # decrypts all .cott.age files in repo and runs the command
cat secret.yml
# cat: secret.yml: No such file or directory
或使用简写:
ctgx ./deploy.sh # same as ctg run -- ./deploy.sh
在完全不写入磁盘的情况下,通过环境变量注入机密来运行命令:
ctg env -- ./deploy.sh # Export secrets from .env.cott.age (default) without writing them to disk, then run deploy.sh
ctg env -F .env.prod.cott.age -- ./deploy.sh # exports from .env.prod.cott.age instead of .env.cott.age
ctg env -F secrets.json.cott.age -- printenv COTTAGE_SECRET # Also supports non-dotenv files.
GitOps
要团队成员共享你的机密,只需推送到 Git 仓库。
git add .
git commit -m "Add secret.yml"
git push origin main
请你的队友将公钥添加到 .cottage/recipients 并推送更改。然后你就可以拉取并为他们重新加密这些机密。
git pull origin main
ctg decrypt --skip-verify-recipients # Decrypt missing secrets for re-encryption
ctg encrypt # Re-encrypt all secrets
# encrypt secret.yml
# into secret.yml.cott.age
# edit secret.yml.cott.toml
ctg clean # optional
# delete secret.yml
# review changes, commit and push
git add .
git commit -m "Add new recipient to secrets"
git push origin main
现在你的队友可以拉取最新更改并自行解密机密。
Git 钩子
你可以使用 prek 或 pre-commit 设置 git 钩子,在提交前自动检查/加密机密,并在检出后解密。
添加 prek.toml 文件后运行:
prek install
prek install --hook-type post-checkout
prek install --hook-type post-merge
prek install --hook-type post-rewrite
访问控制
规则
在元数据文件中,可以标注该机密应为哪些接收方加密。这使你能够为不同环境(例如 staging 与 production)配置不同的机密,并且只针对相关接收方加密。
# secret.yml.cott.toml
[secret]
allow = ["sayanarijit"] # Only encrypt for sayanarijit
# secret.yml.cott.toml
[secret]
deny = ["sayanarijit"] # Encrypt for everyone except sayanarijit
# secret.yml.cott.toml
[secret]
allow = ["env/staging/*"] # Supports glob patterns, only encrypt for recipients in env/staging
deny = ["env/staging/badservice"] # Encrypt for everyone in env/staging except badservice
拒绝规则优先于允许规则。
更多细节请参阅元数据规范。
验证
可以在 CI 中运行 ctg verify,验证加密机密和接收方列表是否与元数据规则匹配,以防篡改。
# .github/workflows/cottage-verify.yml
name: Cottage Verify
on: [push, pull_request]
permissions:
contents: read
jobs:
verify-secrets:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Verify secrets
run: docker run --rm -v "${{ github.workspace }}:/app" ghcr.io/sayanarijit/cottage verify
任意提供商作为上游
使用 cottage,你可以与任何提供 API 的提供商同步机密,而不仅仅是 git。
为此,请在项目根目录创建名为 cottage.toml 的文件,并配置上游设置。
参见这里的 cottage.toml 示例,以及这里的机密特定上游配置示例。
参见这里的示例插件实现。
工作流与 git 类似,但不再使用 git pull 和 git push,而是运行 ctg pull 和 ctg push 与配置的上游同步机密。
示例:
# Pull latest changes into local encrypted secrets
# Similar to `git pull origin`
ctg pull myvault
# Compare diff with local decrypted secrets
ctg diff
# Sync local decrypted secrets with local encrypted secrets
ctg sync
# Push changes from local encrypted secrets to upstream
# Similar to `git push origin main`
ctg push myvault
更多细节请参阅上游配置规范。
示例插件
Cottage 支持各种插件提供商来同步你的机密。在 examples/plugins 目录中提供了可直接使用的插件脚本:
- 1Password
- AWS Secrets Manager
- Azure Key Vault
- Bitwarden
- Dashlane
- Doppler
- ejson
- Google Cloud Secret Manager
- HashiCorp Vault(另见 Vault in Kubernetes)
- Keeper Security
- KeePass (Passhole)
- LastPass
- pass (password-store)
- Proton Pass
- System Keyring
- Zoho Vault
同步到任意设备
使用 Cottage Sync 跨设备同步你的机密,无需 CLI 即可浏览。
了解更多
更多用法示例请参阅 examples 目录。
故障排除
# See debug logs with -v, -vv or -vvv
ctg run -vvv -- ./deploy.sh
对比
age vs 其他加密
age 使用一种现代、简单的算法,专为安全的文件加密而优化,注重易用性和最小攻击面。它还支持 SSH RSA 和 Ed25519 密钥,不过建议为不同的用途和作用域使用不同的密钥。
cottage vs SOPS
尽管 SOPS 和 cottage 有许多重叠功能,但 cottage 具有以下优势:
- 自动管理 .gitignore,确保未加密的机密永远不会提交到 git。
- 加密后的机密是纯 age 加密的
.age文件,能够与更广泛的工具生态系统更好地互操作。 - 更干净的 diff——与 SOPS 不同,SOPS 会对每个机密的每个值生成 diff,即使实际更改只是添加/移除一个接收方;而 cottage 每个文件只生成一个 diff,并明确指出接收方校验和的变化。
cottage vs dotenvx
cottage 借用了 dotenvx 的 ctg env API。
- 支持任意文件类型,而不仅仅是 dotenv 文件。
- 在仓库中管理多个机密。
- 访问控制规则,可为特定接收方加密机密。
- 更干净的 diff——参见 cottage vs SOPS。
