Skip to content

Commit bf86dd8

Browse files
Switch npm release to trusted publishing (OIDC).
Remove NPM_TOKEN-based auth from the release workflow and document npm Trusted Publisher setup in RELEASING.md and AGENTS.md.
1 parent 7561a52 commit bf86dd8

3 files changed

Lines changed: 41 additions & 14 deletions

File tree

.github/workflows/release.yml

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ on:
1818
permissions:
1919
contents: write # create GitHub release artifacts for installers
2020
packages: write # push to GitHub Container Registry (Docker)
21-
id-token: write # required for npm provenance attestations (sigstore)
21+
id-token: write # required for npm trusted publishing and provenance (OIDC)
2222

2323
jobs:
2424
goreleaser:
@@ -112,8 +112,9 @@ jobs:
112112
- name: Set up Node.js
113113
uses: actions/setup-node@v6
114114
with:
115-
node-version: "20"
115+
node-version: "24"
116116
registry-url: "https://registry.npmjs.org"
117+
package-manager-cache: false
117118

118119
- name: Resolve target version
119120
id: ver
@@ -257,10 +258,23 @@ jobs:
257258
' packaging/npm/agoraio-cli/package.json > "$tmp"
258259
mv "$tmp" packaging/npm/agoraio-cli/package.json
259260
261+
- name: Prepare npm for trusted publishing
262+
if: steps.mode.outputs.mode == 'publish'
263+
shell: bash
264+
run: |
265+
set -euo pipefail
266+
# Trusted publishing requires npm CLI 11.5.1+.
267+
npm install -g npm@latest
268+
npm --version
269+
# setup-node writes an empty _authToken placeholder when registry-url is set
270+
# without NODE_AUTH_TOKEN; remove it so npm uses OIDC trusted publishing.
271+
if [ -n "${NPM_CONFIG_USERCONFIG:-}" ] && [ -f "$NPM_CONFIG_USERCONFIG" ]; then
272+
sed -i '/^\/\/registry\.npmjs\.org\/:_authToken=/d' "$NPM_CONFIG_USERCONFIG"
273+
fi
274+
260275
- name: Publish platform packages
261276
shell: bash
262277
env:
263-
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
264278
PUBLISH_ARGS: ${{ steps.mode.outputs.publish_args }}
265279
run: |
266280
set -euo pipefail
@@ -271,9 +285,15 @@ jobs:
271285
packaging/npm/agoraio-cli-linux-x64 \
272286
packaging/npm/agoraio-cli-win32-x64 \
273287
packaging/npm/agoraio-cli-win32-arm64; do
288+
package_name="$(node -p "require('./${pkg}/package.json').name")"
289+
package_version="$(node -p "require('./${pkg}/package.json').version")"
290+
if [ -z "$PUBLISH_ARGS" ] && npm view "${package_name}@${package_version}" version >/dev/null 2>&1; then
291+
echo "${package_name}@${package_version} is already published; skipping."
292+
continue
293+
fi
274294
echo "Publishing $pkg ${PUBLISH_ARGS}"
295+
# Authenticates via npm trusted publishing (OIDC) when not in dry-run mode.
275296
# --provenance is honored by publishConfig.provenance; passing here for clarity.
276-
# When PUBLISH_ARGS contains --dry-run, no provenance attestation is created.
277297
if [ -n "$PUBLISH_ARGS" ]; then
278298
npm publish "$pkg" --access public $PUBLISH_ARGS
279299
else
@@ -284,11 +304,16 @@ jobs:
284304
- name: Publish wrapper package
285305
shell: bash
286306
env:
287-
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
288307
PUBLISH_ARGS: ${{ steps.mode.outputs.publish_args }}
289308
run: |
290309
set -euo pipefail
291310
pkg="packaging/npm/agoraio-cli"
311+
package_name="$(node -p "require('./${pkg}/package.json').name")"
312+
package_version="$(node -p "require('./${pkg}/package.json').version")"
313+
if [ -z "$PUBLISH_ARGS" ] && npm view "${package_name}@${package_version}" version >/dev/null 2>&1; then
314+
echo "${package_name}@${package_version} is already published; skipping."
315+
exit 0
316+
fi
292317
echo "Publishing $pkg ${PUBLISH_ARGS}"
293318
if [ -n "$PUBLISH_ARGS" ]; then
294319
npm publish "$pkg" --access public $PUBLISH_ARGS

AGENTS.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -258,8 +258,8 @@ packaging/npm/
258258
6. Smoke-tests the published wrapper with `npx --yes agoraio-cli@<tag> --version` (retry/backoff for registry propagation)
259259

260260
**Prerequisites:**
261-
- `NPM_TOKEN` secret in the repo, with publish access to `agoraio-cli` and all unscoped `agoraio-cli-*` platform packages.
262-
- `id-token: write` workflow permission (already set in `release.yml`) — required for npm provenance.
261+
- npm **Trusted Publisher** configured on each package (`agoraio-cli` and all `agoraio-cli-*`), pointing at repo `AgoraIO/cli` and workflow `release.yml`.
262+
- `id-token: write` workflow permission (already set in `release.yml`) — required for trusted publishing and provenance.
263263

264264
**Manual dry-run:** the workflow exposes `workflow_dispatch` with a `dry_run` input that runs `npm publish --dry-run` against a synthetic version, validating packaging without publishing.
265265

RELEASING.md

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ The release workflow (`.github/workflows/release.yml`) then:
2525
- Publishes the six per-platform packages with `npm publish --provenance`
2626
- Publishes the wrapper package (`agoraio-cli`) with `npm publish --provenance`
2727
- Runs a post-publish smoke test: `npx --yes agoraio-cli@<tag> --version` with retry/backoff to handle registry propagation
28-
- Requires `NPM_TOKEN` secret with publish access to `agoraio-cli` and `agoraio-cli-*`
29-
- Requires `id-token: write` workflow permission for sigstore-backed npm provenance attestations
28+
- Authenticates via [npm trusted publishing](https://docs.npmjs.com/trusted-publishers/) (OIDC from GitHub Actions — no `NPM_TOKEN` secret)
29+
- Requires `id-token: write` workflow permission (already set in `release.yml`)
3030

3131
3. **Apt repository** job (triggered by the published release):
3232
- Downloads `.deb` files from the release
@@ -63,17 +63,19 @@ The release workflow exposes a `workflow_dispatch` trigger that runs the npm pub
6363

6464
Before tagging the first real release that ships npm, confirm:
6565

66-
- [ ] `NPM_TOKEN` secret is set in the repo (Settings → Secrets and variables → Actions). Token must have publish access to `agoraio-cli` and all unscoped `agoraio-cli-*` platform packages.
66+
- [ ] Each npm package has a **Trusted Publisher** configured on [npmjs.com](https://www.npmjs.com) (Package → Settings → Trusted Publisher → GitHub Actions):
67+
- Repository: `AgoraIO/cli`
68+
- Workflow filename: `release.yml`
69+
- Configure for `agoraio-cli` and all six `agoraio-cli-{os}-{arch}` platform packages
6770
- [ ] `agoraio-cli` and `agoraio-cli-*` package names on npmjs.com are owned by the Agora npm org / publisher and not squatted.
68-
- [ ] The workflow has `id-token: write` permission (already set in `release.yml`); npm provenance requires it.
69-
- [ ] A `workflow_dispatch` dry-run on the current `main` succeeds end-to-end (validates packaging, scripts, provenance).
71+
- [ ] The workflow has `id-token: write` permission (already set in `release.yml`); trusted publishing and provenance require it.
72+
- [ ] A `workflow_dispatch` dry-run on the current `main` succeeds end-to-end (validates packaging and tarball contents).
7073
- [ ] First publish should be a release-candidate tag (e.g. `v0.1.x-rc.1`) so an unexpected failure does not affect a "latest" tag in the registry.
7174

7275
## Required Secrets and Variables
7376

7477
| Name | Type | Required for |
7578
| -------------------- | -------- | ------------------------------- |
76-
| `NPM_TOKEN` | secret | npm publish (active) |
7779
| `APT_SIGNING_KEY` | secret | Signed apt repo on GitHub Pages |
7880
| `APT_SIGNING_KEY_ID` | variable | Signed apt repo on GitHub Pages |
7981

@@ -105,7 +107,7 @@ If a published version is bad:
105107

106108
- [ ] Enable GitHub Pages on this repo (Settings → Pages → Source: GitHub Actions)
107109
- [ ] Generate GPG key for apt signing; set `APT_SIGNING_KEY` and `APT_SIGNING_KEY_ID`
108-
- [ ] Set `NPM_TOKEN` with publish access to `agoraio-cli` and all `agoraio-cli-*` packages
110+
- [ ] Configure npm **Trusted Publishers** for `agoraio-cli` and all `agoraio-cli-*` packages (repo: `AgoraIO/cli`, workflow: `release.yml`)
109111
- [ ] Run a `workflow_dispatch` dry-run of the release workflow to validate npm packaging
110112
- [ ] Add Homebrew and Scoop GoReleaser blocks before announcing those channels
111113
- [ ] Submit first Winget manifest PR to `microsoft/winget-pkgs` after the first release

0 commit comments

Comments
 (0)