Impeccable Windows 引擎二进制如何做 Authenticode 签名?
【免费下载链接】impeccableThe design language that makes your AI harness better at design.项目地址: https://gitcode.com/GitHub_Trending/im/impeccable
当 impeccable 的引擎(engine)发布新版本时,Windows x64 产物impeccable.exe不能以未签名状态直接发布。项目用 Azure Artifact Signing 对二进制做 Authenticode 签名,签发方为Renaissance Geek, Inc.,签名必须在计算发布校验和之前完成。整条路径由bun run release:engine触发、在 GitHub Actions 的release-engine工作流中执行,本文说明这条路径上每一步做了什么、哪些权限是前提、以及如何确认签名有效。
完整依据见 Windows engine signing 与 release-engine 工作流。
前置条件:签名身份与访问边界
签名不是本地能完成的动作,它依赖一组预先配置好的 Azure 与 GitHub 资源。发布前需要确认以下条件都已存在(详见 docs/WINDOWS-SIGNING.md):
- Azure 账号
impeccable-signing,East US 端点;Public Trust 证书配置文件impeccable-windows。 - 用户指定的托管身份
impeccable-release-signing,与账号在同一资源组。它在 Azure 中唯一拥有的角色是Artifact Signing Certificate Profile Signer,且只限定在impeccable-signing/certificateProfiles/impeccable-windows,不覆盖整个账号或订阅。 - 联合凭据
github-windows-signing:issuer 为https://token.actions.githubusercontent.com,audience 为api://AzureADTokenExchange,subject 为repo:pbakaus/impeccable:environment:windows-signing。 - GitHub 环境
windows-signing:仅对匹配engine-v*的tag开放,pbakaus是必需审批人,且管理员旁路(administrator bypass)关闭。 - GitHub 环境变量
AZURE_CLIENT_ID、AZURE_TENANT_ID、AZURE_SUBSCRIPTION_ID,它们存放的是公开标识符而非密钥。GitHub 上不存任何客户端密钥、私钥或 PFX。
执行路径:从打 tag 到签名产物
1. 触发引擎发布
在仓库根目录运行:
bun run release:engine该命令对应node scripts/release.mjs engine,只负责本地校验与打 tag:它检查ENGINE_VERSION、npm platform-package 的版本 pin 和工作区是否干净,然后推送engine-v<ENGINE_VERSION>tag。构建、签名、发布全部由 CI 完成,维护者本机不需要五个平台的目标工具链。脚本也支持--dry-run,只做前置检查不推 tag。
2. build job:产出未签名 Windows 二进制
tag 匹配engine-v*后,.github/workflows/release-engine.yml 被触发。buildjob 的 matrix 构建五个目标(darwin-arm64 / darwin-x64 / linux-x64 / linux-arm64 / windows-x64),并先校验 tag 与ENGINE_VERSION一致。
Windows 构建的产物被刻意命名为unsigned-windows-x64artifact——这个名字不以impeccable-开头,是后面 publish job 收集模式(impeccable-*)无法误收它的关键设计。
3. sign-windows job:签名与验证
这是唯一拿到id-token: write(OIDC)权限的 job,绑定windows-signing环境,因此需要人工审批。审批前要检查该 tag 的 commit 与工作流内容:环境审批一旦通过,这个 job 就获得了以公司名义签名的能力。
job 的步骤顺序是固定的:
- 用
actions/download-artifact从同一次运行下载unsigned-windows-x64。job 不 checkout 仓库代码,也不执行下载来的引擎。 azure/login以 OIDC 方式登录 Azure,使用上面三个环境变量中的公开标识符。azure/artifact-signing-action(pin 到 commit SHA)执行签名,关键配置:
uses: azure/artifact-signing-action@c7ab2a863ab5f9a846ddb8265964877ef296ee82 # v2 with: endpoint: https://eus.codesigning.azure.net/ signing-account-name: impeccable-signing certificate-profile-name: impeccable-windows files: ${{ github.workspace }}\unsigned\impeccable.exe file-digest: SHA256 timestamp-rfc3161: http://timestamp.acs.microsoft.com timestamp-digest: SHA256 description: Impeccable engine description-url: https://impeccable.style exclude-environment-credential: true exclude-azure-cli-credential: false cache-dependencies: false签的恰好是impeccable.exe一个文件;RFC 3161 时间戳是必需的,因为 Azure 签发的是短生命周期签名证书。 4. 签名后、上传前,用 PowerShell 验证:
$ErrorActionPreference = 'Stop' $signature = Get-AuthenticodeSignature -LiteralPath 'unsigned/impeccable.exe' if ($signature.Status -ne 'Valid') { throw "Invalid Windows signature: $($signature.Status) — $($signature.StatusMessage)" } $publisher = $signature.SignerCertificate.GetNameInfo([System.Security.Cryptography.X509Certificates.X509NameType]::SimpleName, $false) if ($publisher -cne 'Renaissance Geek, Inc.') { throw "Unexpected Windows publisher: $publisher" } if ($null -eq $signature.TimeStamperCertificate) { throw 'The Windows signature has no timestamp.' } Write-Output "Verified publisher: $publisher; certificate: $($signature.SignerCertificate.Thumbprint)"验证同时检查三件事:签名状态为Valid、发布者名恰为Renaissance Geek, Inc.、时间戳证书存在。任何一项失败该步直接抛错,job 中没有任何continue-on-error。 5. 验证通过后才把产物以impeccable-windows-x64的名字上传,publish job 只收集得到带签名的版本。
4. publish job:等待签名后发布
publishjob 的needs是[build, sign-windows],且只下载匹配impeccable-*的 artifact——未签名的中间产物unsigned-windows-x64在名字层面就进不来。它为每个二进制生成.sha256侧车文件(此时计算,因此校验和对应的是已签名字节),再用gh release create发布;不带--clobber,已发布的 release 资产不可变。
结果验证
- 运行内验证:sign-windows job 的 PowerShell 步骤(上文)就是签名有效性的判定条件——
Status为Valid、发布者正确、有时间戳,三步全过才会走到上传。 - 工作流回归测试:
bun test tests/release-engine-workflow.test.js对 tests/release-engine-workflow.test.js 解析的 YAML 做断言:只有 sign-windows 拿到id-token: write、签名参数(证书配置、RFC 3161 时间戳、SHA256 digest)、验证步骤必须位于签名之后上传之前、publish 的下载模式收集不到未签名 artifact、第三方 action 全部 pin 到 commit。 - 端到端:docs/WINDOWS-SIGNING.md 明确说明,工作流配置已有回归测试覆盖,但一次真实的受保护引擎发布仍是验证 Azure OIDC 与 Authenticode 端到端流程所必需的。如果你刚配置完环境,用一次真实 tag 发布来确认是预期行为。
失败处理与边界
- 签名或验证失败:修复原因后重试。文档明确要求不要加 unsigned 回退,也不要放宽
windows-signing环境门槛。 - 不要 pin 叶子证书 thumbprint:Azure 会轮换它,pin 住会导致后续签名失败。
- 已发布资产不可替换:不能用签名字节替换同版本已发布的未签名二进制;修复方式是发新版本。
- 与 skill 包签名区分开:
impeccable install校验的 Ed25519 远程 skill ZIP 签名(docs/BUNDLE-SIGNING.md)是另一套机制,保护的是 skill bundle 下载,不认证引擎二进制;引擎二进制的完整性目前靠发布时的 SHA-256 侧车加上 Windows 平台的 Authenticode 签名。 - 权限面:只有 sign-windows job 拿到 OIDC token,只有 publish job 能写 release;sign job 不 checkout 代码,Azure 身份下不会执行仓库代码。
下一步
配置完成并通过bun test tests/release-engine-workflow.test.js后,按 docs/ENGINE.md 的发布顺序继续:bun run release:engine发出engine-v<版本>后,npm platform packages 与 skill/CLI 发布会被scripts/check-engine-release.mjs的门禁等待这次引擎发布完成。
【免费下载链接】impeccableThe design language that makes your AI harness better at design.项目地址: https://gitcode.com/GitHub_Trending/im/impeccable
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考