Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions .changeset/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,22 @@ Select the affected packages, choose the semantic version bump, and describe the
tests, CI, and internal refactors that do not change a published package may omit a changeset.

The three public packages are kept in a fixed group and release with the same version.

## Manual Version PR

GitHub Actions is intentionally not allowed to create or approve pull requests. A maintainer prepares each Version PR:

```sh
git switch main
git pull --ff-only origin main
git switch -c release/version-packages
pnpm version-packages
pnpm check
git add .changeset package.json pnpm-lock.yaml packages
git commit -m "chore: release packages"
git push -u origin release/version-packages
```

Open a pull request, review the generated versions and changelogs, and merge it with rebase. Only after that Version PR
is merged should `NPM_RELEASE_ENABLED` be set to `true` and the Release workflow dispatched. Restore the variable to
`false` after registry verification.
30 changes: 18 additions & 12 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ jobs:
environment: npm
permissions:
contents: write
pull-requests: write
id-token: write
steps:
- name: Check out repository
Expand Down Expand Up @@ -53,14 +52,21 @@ jobs:
- name: Run quality gate
run: pnpm check

- name: Create version pull request or publish
id: changesets
uses: changesets/action@a45c4d594aa4e2c509dc14a9f2b3b67ba3780d0d # v1.9.0
with:
publish: pnpm release
version: pnpm version-packages
title: "chore: release packages"
commit: "chore: release packages"
commitMode: github-api
env:
GITHUB_TOKEN: ${{ github.token }}
- name: Detect pending Changesets
id: release-state
shell: bash
run: |
if find .changeset -maxdepth 1 -type f -name '*.md' ! -name README.md | grep -q .; then
echo "publish=false" >> "${GITHUB_OUTPUT}"
echo "::notice::Pending Changesets found. Create and review a manual Version PR before publishing."
else
echo "publish=true" >> "${GITHUB_OUTPUT}"
fi

- name: Publish packages with npm OIDC
if: steps.release-state.outputs.publish == 'true'
run: pnpm release

- name: Push release tags
if: steps.release-state.outputs.publish == 'true'
run: git push origin --tags
49 changes: 16 additions & 33 deletions specs/20260729-public-monorepo-release-governance/TECH.md
Original file line number Diff line number Diff line change
Expand Up @@ -254,8 +254,7 @@ checkout 必须使用完整 history。Version PR branch `changeset-release/main`
#### Actions

- Default `GITHUB_TOKEN` permissions:read-only
- 允许 GitHub Actions 创建 pull requests,以便 Changesets 创建 Version PR
- 不允许 workflow 使用 `GITHUB_TOKEN` 自动提交 approving review
- 禁止 GitHub Actions 创建或批准 pull requests;Version PR 由 maintainer 本地生成并人工创建
- public fork workflow policy:所有 external contributors 都需要 maintainer approval
- 只允许 GitHub-owned actions 和明确 allowlisted third-party actions
- policy 支持时,要求所有 `uses:` 使用完整 40-character commit SHA
Expand Down Expand Up @@ -364,11 +363,11 @@ SHA 更新 PR,维护者 review upstream diff 后合并。

### 8. Release workflow

新增 `.github/workflows/release.yml`,保留 Changesets 的单 workflow state machine:
新增 `.github/workflows/release.yml`,使用人工 Version PR 与自动 OIDC publish 分离的 state machine:

1. `main` 上仍有未消费 Changesets 时,创建或更新 `chore: release packages` Version PR。
2. Version PR 合并后,package versions 已更新且 Changesets 已消费;下一次 run 执行正式 npm publish、tags 和
GitHub Releases
1. Maintainer 从最新 `main` 创建 release branch,运行 `pnpm version-packages`,提交人工 Version PR。
2. Version PR 经人工 review 并合并后,package versions 已更新且 Changesets 已消费
3. Maintainer 打开 release window 并运行 workflow;workflow 执行正式 npm publish 和 tags

Triggers:

Expand All @@ -383,42 +382,26 @@ Controls:
- job 绑定 protected Environment `npm`;
- permissions 只包含:
- `contents: write`
- `pull-requests: write`
- `id-token: write`
- install 使用 frozen lockfile;
- release build 禁用 package-manager cache;
- 先执行完整 `pnpm check`;
- `changesets/action` 使用已验证的完整 SHA;
- action 使用 GitHub API commit mode,使 Version PR commits 和 release tags 由 GitHub App 签名;
- action 的 `publish` command 为 `pnpm release`;
- action 的 `version` command 为 `pnpm version-packages`;
- 只向 action 提供 GitHub 自动生成的 `GITHUB_TOKEN`;
- 检测到未消费 Changesets 时 fail closed,不执行 publish;
- 没有未消费 Changesets 时执行 `pnpm release`,再 push Changesets 创建的 release tags;
- workflow 不拥有 `pull-requests: write`,也不使用 `GITHUB_TOKEN` 创建或批准 PR;
- 不设置 `NPM_TOKEN`、`NODE_AUTH_TOKEN` 或其他 npm write credential。

`npm` Environment settings:

- required reviewer:至少一名独立 maintainer;
- prevent self-review:启用;
- deployment branches:只允许 protected `main`;
- disallow administrators bypass:启用;
- Environment name 必须与 npm Trusted Publisher 中的 `Environment name` 精确一致。

因为 Version PR creation 和 publish 复用一个 protected job,一个 release window 通常出现两次 Environment
approval:

1. 第一次批准运行后,Changesets 创建或更新 Version PR;不会 publish。
2. Version PR 被 review 并 merge 后,第二次批准运行才会 publish。

这是有意的双重人工边界,不应通过注入长期 Token 或移除 Environment 来简化。
`npm` Environment 只允许 protected branches,且 Environment name 必须与 npm Trusted Publisher 中的
`Environment name` 精确一致。有第二名 maintainer 后,应增加 required reviewer 并启用 prevent self-review;在此之前,
人工 Version PR 是发布前的人类检查边界。

`NPM_RELEASE_ENABLED` 默认和日常值为 `false`。打开 release window 的顺序:

1. 确认 Trusted Publishers、Environment reviewers 和 `main` ruleset;
2. 设置为 `true`;
3. 手动运行 Release 或等待 `main` push;
4. review 并 merge Version PR;
5. 批准正式 publish deployment;
6. registry 验证成功后立即恢复为 `false`。
2. 从最新 `main` 运行 `pnpm version-packages`,创建、review 并 merge Version PR;
3. 设置为 `true`;
4. 手动运行 Release;
5. registry 验证成功后立即恢复为 `false`。

### 9. npm Trusted Publishing

Expand Down Expand Up @@ -633,7 +616,7 @@ docs/release/npm-release.md
- 若需要,执行一次性 `0.0.0` bootstrap。
- 配置 Trusted Publishers。
- 删除并撤销 bootstrap credentials。
- 通过 Version PR 和 OIDC 发布 `0.1.0`。
- 通过人工 Version PR 和 OIDC 发布 `0.1.0`。
- 验证 provenance、tags、GitHub Releases 和 registry consumer。
- 关闭 release window,并把 package publishing access 改为 disallow tokens。

Expand Down
Loading