diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f846cbc7..f59051ce 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -315,14 +315,15 @@ jobs: publish-npm: needs: [release-context, asset-gate] - # Temporarily disable npm publishing by setting repo variable SKIP_NPM=true - # (e.g. while the npm token can't publish — 2FA-bypass granular token not yet - # configured). The job is cleanly SKIPPED (gray), not failed/masked. Clear - # the SKIP_NPM repo variable to re-enable. See RELEASE.md. + # Temporarily disable npm publishing by setting repo variable SKIP_NPM=true. + # The job is cleanly SKIPPED (gray), not failed/masked. Clear the SKIP_NPM + # repo variable to re-enable. Publishing authenticates through npm trusted + # publishing (OIDC), configured per package on npmjs.com. See RELEASE.md. if: ${{ vars.SKIP_NPM != 'true' }} runs-on: ubuntu-latest permissions: contents: read + id-token: write # npm trusted publishing (OIDC), no token secret steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: @@ -333,6 +334,11 @@ jobs: node-version: 22 registry-url: https://registry.npmjs.org + # Trusted publishing needs npm 11.5.1 or later; the npm bundled with + # Node 22 is older. + - name: Update npm for trusted publishing + run: npm install -g npm@latest + - name: Download and verify platform release assets shell: bash env: @@ -352,7 +358,6 @@ jobs: - name: Idempotent publish (platform packages) shell: bash env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} VERSION: ${{ needs.release-context.outputs.version }} run: | set -euo pipefail @@ -405,7 +410,6 @@ jobs: - name: Idempotent publish (main package) shell: bash env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} VERSION: ${{ needs.release-context.outputs.version }} run: | set -euo pipefail @@ -576,6 +580,7 @@ jobs: runs-on: ubuntu-latest permissions: contents: read + id-token: write # npm trusted publishing (OIDC), no token secret steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: @@ -586,6 +591,11 @@ jobs: node-version: 22 registry-url: https://registry.npmjs.org + # Trusted publishing needs npm 11.5.1 or later; the npm bundled with + # Node 22 is older. + - name: Update npm for trusted publishing + run: npm install -g npm@latest + - name: Build + test shell: bash run: | @@ -598,7 +608,6 @@ jobs: - name: Idempotent publish shell: bash env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} VERSION: ${{ needs.release-context.outputs.version }} run: | set -euo pipefail diff --git a/RELEASE.md b/RELEASE.md index f3fa9ecf..9f497b43 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -48,15 +48,17 @@ The pipeline is idempotent — re-run is safe. ### Temporarily disabling npm publishing -If the npm token can't publish (npm now rejects classic automation tokens with -`403 ... two-factor authentication ... required`), set the repo variable -`SKIP_NPM=true` (`gh variable set SKIP_NPM --body true`). `publish-npm` is then -cleanly **skipped** (gray, not failed) and `verify-publish` records npm as -`skipped` — the release goes green on every other registry. **Re-enable** by -clearing it (`gh variable delete SKIP_NPM`) once `NPM_TOKEN` is a *granular* -access token with publish permission (these bypass 2FA), or after configuring -npm OIDC trusted publishing for each package (the workflow already grants -`id-token: write`). +npm publishing uses **trusted publishing** (OIDC): no token secret, nothing to +rotate. Each package on npmjs.com lists this repository and `release.yml` as its +trusted publisher (package page > Settings > Trusted Publisher > GitHub Actions: +user `us`, repository `crw`, workflow filename `release.yml`, no environment). +The packages are `crw-mcp`, `crw-mcp-darwin-arm64`, `crw-mcp-darwin-x64`, +`crw-mcp-linux-arm64`, `crw-mcp-linux-x64` and `crw-sdk`. A new platform +package needs that entry once before its first release. If npm publishing has +to be paused, set the repo variable `SKIP_NPM=true` +(`gh variable set SKIP_NPM --body true`): `publish-npm` and `publish-npm-sdk` are +then cleanly **skipped** (gray, not failed) and `verify-publish` records npm as +`skipped`. Re-enable with `gh variable delete SKIP_NPM`. ### A version was published with broken metadata (e.g. wrong npm optionalDeps) @@ -77,7 +79,7 @@ These tags were cut while the release pipeline silently failed (cargo publish ou | -------------------- | -------------------------------- | -------------------------------------------- | | `CARGO_REGISTRY_TOKEN` | `publish-crates` | crates.io account → API tokens → revoke + create new with `publish-update` scope | | `PYPI_TOKEN` | `publish-pypi` | pypi.org account → API tokens → scoped to project `crw` | -| `NPM_TOKEN` | `publish-npm` | npmjs.com → access tokens → automation token | +| npm (no secret) | `publish-npm`, `publish-npm-sdk` | trusted publishing, configured per package on npmjs.com; nothing to rotate | | `GH_DISPATCH_PAT` | `dispatch-release`, `update-apt`, `update-homebrew` | GitHub fine-grained PAT with `actions:write` on this repo + `us/apt-crw` + `us/homebrew-crw` | `GITHUB_TOKEN` is auto-provisioned and does not need rotation.