ci(npm): stop passing NPM_TOKEN to the CLI and xcrs publish steps
The stored token no longer works, and with trusted publishing in place it only hid the real problem: a package with no trusted publisher fell back to the token and failed with a 404 that looked like a missing package. Without it, npm publishes over OIDC or fails on auth. The xcrs packages have never been published over OIDC, so each of the seven needs a trusted publisher for release-xcrs-npm.yml before that workflow can pass. Also rewrite the npm section of the ci-cd skill, which still said npm had no trusted publishing and told readers to set NODE_AUTH_TOKEN. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Co-Authored-By: siGit Code v1.6.7 <noreply@sigit.si>
keypair34 committed
Oct 12, 2026 at 15:03 UTC
b09cafe5140d49165ca628570d56ccff60e00467
3 files changed
+16
-18
.agents/skills/ci-cd/SKILL.md
+16
-10
@@ -379,23 +379,29 @@ No `PYPI_TOKEN` secret needed. The action exchanges the GitHub OIDC JWT for a sh
379
380
If the trusted publisher is missing, the publish step fails with `invalid-publisher: valid token, but no corresponding publisher`.
381
382
-### npm — does NOT support trusted publishing natively
382
+### npm — trusted publishing, configured per package
383
384
-npm has no OIDC-based trusted publishing equivalent to PyPI. The `id-token: write` permission in the npm workflow is unused for auth.
385
-
386
-Authentication requires a stored secret:
384
+The npm workflows (`release-npm.yml`, `release-sdk-npm.yml`, `release-xcrs-npm.yml`) publish over OIDC. There is no `NPM_TOKEN` secret and no `NODE_AUTH_TOKEN` on the publish steps. Each workflow needs:
385
386
```yaml
389
-- name: Publish to NPM
390
- env:
391
- NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
387
+permissions:
388
+ id-token: write
389
+ contents: read
390
+```
391
+
392
+npm >= 11.5.1 and Node >= 22.14.0 are required, which `.nvmrc` covers.
393
+
394
+The trusted publisher is set on each package, not on the `@smbcloud` scope, and it names one workflow file. Every platform package needs its own entry:
395
+
396
+```sh
397
+npm trust github @smbcloud/cli-linux-arm64 --repo smbcloudXYZ/smbcloud-cli --file release-npm.yml
398
```
399
394
-`setup-node` with `registry-url` writes an `.npmrc` referencing `${NODE_AUTH_TOKEN}`. That variable must be in the step's `env` block at publish time. If it is missing, `npm publish` silently has no auth and returns 404 for new packages (existing packages that pass the `npm view` idempotency check are never attempted, masking the missing token).
400
+A package without one fails at `npm publish` while its siblings succeed. `@smbcloud/cli-linux-arm64` was missed this way: it kept publishing on the stored token until the token died, and for eight releases starting at v0.5.3 its 404 also skipped the base `@smbcloud/cli` job, which `needs` every platform job.
401
396
-The 404 on `npm publish` does not mean the package does not exist. npm returns 404 for auth failures to avoid leaking package existence.
402
+A 404 on `npm publish` does not mean the package does not exist. npm returns 404 for auth failures to avoid leaking package existence.
403
398
-**npm trusted publishing (future):** npm does support OIDC trusted publishing via `npm trust github`. It requires the package to exist on npm first. Configure it per-package after the first manual publish. See `smbcloud-cli-release` skill for details.
404
+`npm trust` only works on a package that already exists, so the first version of a new package name has to be published by hand. See the `smbcloud-cli-release` skill for details.
405
406
### crates.io — uses `CARGO_REGISTRY_TOKEN`
407
.github/workflows/release-npm.yml
-4
@@ -108,8 +108,6 @@ jobs:
108
registry-url: "https://registry.npmjs.org"
109
110
- name: Publish to NPM
111
- env:
112
- NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
111
shell: bash
112
run: |
113
# We want to name our npm package @smbcloud/cli, but the main command is smb.
@@ -184,8 +182,6 @@ jobs:
182
registry-url: "https://registry.npmjs.org"
183
184
- name: Publish the package
187
- env:
188
- NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
185
shell: bash
186
run: |
187
cd npm/smbcloud-cli
.github/workflows/release-xcrs-npm.yml
-4
@@ -101,8 +101,6 @@ jobs:
101
registry-url: "https://registry.npmjs.org"
102
103
- name: Publish to NPM
104
- env:
105
- NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
104
shell: bash
105
run: |
106
# We want to name our npm package @smbcloud/xcrs, and the command is xcrs.
@@ -177,8 +175,6 @@ jobs:
175
registry-url: "https://registry.npmjs.org"
176
177
- name: Publish the package
180
- env:
181
- NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
178
shell: bash
179
run: |
180
cd npm/xcrs