用途
swain-keys 用于为单个 Git 项目按项目维度供给密钥,覆盖 Git 提交签名(signing)与身份认证(authentication)两类需求。它面向两类代码托管平台(forge),并为每类平台选用对应的签名模式,避免全局配置相互干扰。
主要能力
支持两类 forge,各自使用合适的签名模式:
- GitHub:使用 SSH 签名,通过
gh ssh-key add注册公钥。 - Forgejo:使用 GPG 签名,通过
fj user gpg upload上传公钥。
forge 会从 origin 远程 URL 自动识别,也可通过 SWAIN_FORGE 覆盖。
使用方式
技能调用时,定位并运行供给脚本(相对于本技能目录):
REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
SCRIPT="$REPO_ROOT/.agents/bin/swain-keys.sh"
若路径查找失败,则用 glob 搜索 **/swain-keys/scripts/swain-keys.sh。
工作流:
默认(无参数或“set up keys”):先运行 --status 显示当前状态,若密钥未完全供给,询问用户是否继续供给。
bash "$SCRIPT" --status
供给(“provision keys”“configure signing”“set up SSH”):运行完整供给流程。
bash "$SCRIPT" --provision
在 GitHub 上,脚本会:
- 从 git 远程或目录推导项目名。
- 若不存在,生成
~/.ssh/<project>_signing(ed25519,无口令)。 - 使用配置的 git 邮箱创建
~/.ssh/allowed_signers_<project>。 - 通过
gh ssh-key add将公钥添加到 GitHub,同时用于认证与签名。 - 创建
~/.ssh/config.d/<project>.conf,其中包含一个主机别名,用于绕过全局 SSH 代理,并将 GitHub SSH 路由到 ssh.github.com:443。 - 更新 git 远程 URL 以使用项目专属主机别名。
- 设置本地 git 配置以启用 SSH 提交与标签签名。
- 验证 SSH 连通性与签名能力。
在 Forgejo 上,脚本会:
- 从 git 远程或目录推导项目名。
- 若不存在,通过
gpg --batch --generate-key(无人值守,%no-protection)生成 OpenPGP ed25519 密钥。 - 通过
fj user gpg upload将 GPG 公钥上传到 Forgejo。 - 配置本地 git 使用 OpenPGP 签名(gpg.format=openpgp),覆盖任何全局 SSH 签名配置。
- 保持远程 URL 不变(Forgejo SSH 认证由用户现有的 SSH 配置处理)。
- 验证签名能力与 Forgejo GPG 密钥状态。
状态(“key status”“check keys”):
bash "$SCRIPT" --status
显示 forge 类型、密钥状态、git 配置和 forge 注册状态。适用时报告“GPG key registered on Forgejo as signing key (Verified: true)”。
验证(“verify keys”“test signing”):
bash "$SCRIPT" --verify
测试签名能力和 forge 密钥注册。对 Forgejo,验证 GPG 密钥在 forge 上具有 Can Sign: true。
环境变量
SWAIN_FORGE— 设为github或forgejo以覆盖自动识别。SWAIN_FORGEJO_HOST— 设置 Forgejo 实例 URL(例如https://codeberg.org)。当 origin 包含 localhost 时,默认使用http://localhost:3000。
处理作用域刷新(scope refresh)
GitHub:若 gh ssh-key add 因作用域不足而失败,脚本会打印需要操作的提示。此时:
- 告知用户需要授权额外的 GitHub 作用域。
- 向其展示命令:
gh auth refresh -s admin:public_key,admin:ssh_signing_key。
这会打开浏览器进行 OAuth —— 需要人工交互。用户确认后,重新运行 --provision(幂等,会跳过已完成的步骤)。
Forgejo:若 fj user gpg upload 失败,检查 fj 是否已认证:
fj auth login
然后重新运行 --provision。
与 swain-init 集成
当从 swain-init 调用时,直接运行 --provision,不走先执行 status 的流程;swain-init 负责处理“是否继续”的询问。
会话书签
供给完成后,更新书签:
bash "$REPO_ROOT/.agents/bin/swain-bookmark.sh" "Provisioned keys for {project}"
错误处理
- 若不在 git 仓库中:以清晰消息失败。
- 若 gh CLI 不可用(GitHub):跳过 GitHub 注册步骤,警告用户手动添加密钥。
- 若 fj CLI 不可用(Forgejo):跳过 Forgejo 注册,警告用户手动上传 GPG 密钥。
- 若未安装 gpg(Forgejo):失败并给出安装说明。
- 若未配置 git 邮箱:提前失败并给出说明。
所有步骤均为幂等 —— 修复问题后重复运行是安全的。