diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 38f8313..53e5e4b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -32,10 +32,10 @@ jobs: - name: Require release credentials env: DISTRIBUTION_TOKEN: ${{ secrets.GLOSS_DISTRIBUTION_TOKEN }} - EXTENSION_TOKEN: ${{ secrets.GLOSS_EXTENSION_TOKEN }} + EXTENSION_SSH_KEY: ${{ secrets.GLOSS_EXTENSION_SSH_KEY }} run: | missing=() - [[ -n "$EXTENSION_TOKEN" ]] || missing+=("GLOSS_EXTENSION_TOKEN") + [[ -n "$EXTENSION_SSH_KEY" ]] || missing+=("GLOSS_EXTENSION_SSH_KEY") if [[ "$GITHUB_EVENT_NAME" == "push" ]]; then [[ -n "$DISTRIBUTION_TOKEN" ]] || missing+=("GLOSS_DISTRIBUTION_TOKEN") fi @@ -73,7 +73,8 @@ jobs: repository: SunChJ/personal-immersive-translator ref: 3e9c7c8cb75ce4b08e56a714ee0e4eb7ebaa652e path: personal-immersive-translator - token: ${{ secrets.GLOSS_EXTENSION_TOKEN }} + ssh-key: ${{ secrets.GLOSS_EXTENSION_SSH_KEY }} + ssh-strict: true persist-credentials: false - name: Validate release version and runner architecture working-directory: gloss diff --git a/README.md b/README.md index 545ca8f..58e5c41 100644 --- a/README.md +++ b/README.md @@ -182,9 +182,9 @@ brew update brew upgrade --cask sunchj/tap/gloss ``` -Release workflow 使用只读 `GLOSS_EXTENSION_TOKEN` 检出私有浏览器扩展;正式 tag 另外要求 -跨仓库 `GLOSS_DISTRIBUTION_TOKEN`。缺失时 workflow 会在构建和上传前 fail closed。手工 -workflow 不发布,但仍需要 extension token 才能生成完整 App artifact。 +Release workflow 使用只读 `GLOSS_EXTENSION_SSH_KEY` 检出私有浏览器扩展;正式 tag 另外 +要求跨仓库 `GLOSS_DISTRIBUTION_TOKEN`。缺失时 workflow 会在构建和上传前 fail closed。 +手工 workflow 不发布,但仍需要 extension deploy key 才能生成完整 App artifact。 Cask 的 `postflight` 会重新 ad-hoc 签名、移除 quarantine 并验证签名,让安装后启动不弹 Gatekeeper 交互;这也意味着 macOS 无法验证 Apple 开发者身份或公证票据。公开仓库初始化、 fine-grained token 权限、完整安全取舍、发行顺序与恢复步骤见 diff --git a/docs/runtime-distribution.md b/docs/runtime-distribution.md index 73e900e..c173bba 100644 --- a/docs/runtime-distribution.md +++ b/docs/runtime-distribution.md @@ -99,20 +99,19 @@ active runtime。 6. Release 上传成功后,dispatch `SunChJ/homebrew-tap` 的 `update-cask.yml`,由公开 tap 下载并二次校验 Release,再更新 `Casks/gloss.rb`。 -完整 App 会同时检出并构建私有浏览器扩展仓库。Release workflow 使用两个职责分离的 -fine-grained token: +完整 App 会同时检出并构建私有浏览器扩展仓库。Release workflow 使用两个职责分离的凭据: | Secret | 用途 | | --- | --- | -| `GLOSS_EXTENSION_TOKEN` | 只读检出私有 `SunChJ/personal-immersive-translator` | +| `GLOSS_EXTENSION_SSH_KEY` | 只读检出私有 `SunChJ/personal-immersive-translator` | | `GLOSS_DISTRIBUTION_TOKEN` | 向公开 binary repo 上传 Release,并 dispatch 公开 tap workflow | -workflow 的第一个 job 始终检查 `GLOSS_EXTENSION_TOKEN`;tag 事件还会检查 +workflow 的第一个 job 始终检查 `GLOSS_EXTENSION_SSH_KEY`;tag 事件还会检查 `GLOSS_DISTRIBUTION_TOKEN`。缺失即 fail closed,不会开始正式构建。手工 `workflow_dispatch` 不走 public publication 路径,因此不需要 distribution token,但仍需 -只读 extension token 才能构建完整 App。 +只读 extension deploy key 才能构建完整 App。 -### 公开仓库与 token 初始化 +### 公开仓库与凭据初始化 公开分发使用两个独立仓库,私有 `SunChJ/gloss` 不承载匿名下载: @@ -137,10 +136,10 @@ workflow 的第一个 job 始终检查 `GLOSS_EXTENSION_TOKEN`;tag 事件还 权限的并集。Token 不需要访问私有 `SunChJ/gloss`;workflow 通过该仓库自己的 `GITHUB_TOKEN` 只读检出源码。 -另建一个 fine-grained token,只选择私有 -`SunChJ/personal-immersive-translator`,仅授予 `Contents: Read-only`,并保存为 -`GLOSS_EXTENSION_TOKEN`。不要让这个只读 token 访问公开发行仓库,也不要让 -`GLOSS_DISTRIBUTION_TOKEN` 访问私有扩展源码。 +为私有 `SunChJ/personal-immersive-translator` 创建独立 Ed25519 SSH key pair,把 public +key 添加为该仓库的 read-only deploy key,把 private key 保存为 +`GLOSS_EXTENSION_SSH_KEY`。不要为 deploy key 启用 write access,也不要复用个人 SSH key。 +`GLOSS_DISTRIBUTION_TOKEN` 不应访问私有扩展源码。 `homebrew-tap` 的 `update-cask.yml` 必须声明两个 required `workflow_dispatch` inputs: `release_tag` 和 `release_repository`。它应只接受 @@ -194,7 +193,7 @@ brew upgrade --cask sunchj/tap/gloss 1. 先发布兼容的 `SunChJ/BabelDOC` signed runtime,并确认 stable manifest 可下载。 2. 合并 Gloss 的发行提交,确认 `Resources/Info.plist` 版本与准备创建的 `v*` tag 完全一致。 -3. 确认两个公开仓库、`update-cask.yml`、`GLOSS_EXTENSION_TOKEN`、 +3. 确认两个公开仓库、`update-cask.yml`、`GLOSS_EXTENSION_SSH_KEY`、 `GLOSS_DISTRIBUTION_TOKEN` 和 tap 的 Actions/branch protection 设置均已就绪。 4. 在私有 Gloss 仓库的目标 commit 上创建并推送 tag,例如 `v0.8.0`。 5. 等待 Gloss Release workflow 完成 ad-hoc 签名;workflow 会先创建 draft Release,上传全部