Skip to content

Commit dc272cf

Browse files
czlonkowskiclaude
andauthored
ci(release): switch npm publishing to Trusted Publishers (OIDC) (czlonkowski#796)
* ci(release): switch npm publishing to Trusted Publishers (OIDC) Replace long-lived NPM_TOKEN auth with short-lived OIDC tokens minted by GitHub Actions via npm Trusted Publishers. Publishes now ship with provenance attestations linking the package back to the exact workflow run and commit. Workflow changes (.github/workflows/release.yml): - Add `environment: npm-publish` and `permissions: id-token: write` to publish-npm - Upgrade runner npm to >= 11.5.1 (Node 20 bundles npm 10.x; Trusted Publishing requires 11.5.1+) - Drop NODE_AUTH_TOKEN / NPM_TOKEN; add --provenance to npm publish Docs (docs/AUTOMATED_RELEASES.md): - Replace NPM_TOKEN setup with Trusted Publisher configuration steps - Update troubleshooting and security sections Preflight (scripts/test-release-automation.js): - Check for id-token: write and environment: npm-publish instead of NPM_TOKEN - Update Next Steps to reference the new auth model Requires (one-time, before next release): - npmjs.com: configure Trusted Publisher for repo czlonkowski/n8n-mcp, workflow release.yml, environment npm-publish - GitHub: create environment `npm-publish` (no protection rules needed) - After first successful release, NPM_TOKEN secret can be deleted Conceived by Romuald Członkowski - https://www.aiadvisors.pl/en Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * ci(release): address Copilot review on PR czlonkowski#796 - Pin runner npm to ^11.5.1 instead of @latest, and echo version after install for easier troubleshooting. Avoids exposing the release flow to future npm major releases. - Scope OIDC preflight checks (id-token: write, environment: npm-publish) to the publish-npm job block instead of the entire workflow file, so the checks can't false-positive on keys belonging to other jobs. Conceived by Romuald Członkowski - https://www.aiadvisors.pl/en Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent f1edbc9 commit dc272cf

3 files changed

Lines changed: 76 additions & 21 deletions

File tree

.github/workflows/release.yml

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,10 @@ jobs:
309309
runs-on: ubuntu-latest
310310
needs: [detect-version-change, build-and-verify, create-release]
311311
if: needs.detect-version-change.outputs.version-changed == 'true'
312+
environment: npm-publish
313+
permissions:
314+
contents: read
315+
id-token: write
312316
steps:
313317
- name: Checkout repository
314318
uses: actions/checkout@v4
@@ -318,7 +322,11 @@ jobs:
318322
with:
319323
node-version: 20
320324
cache: 'npm'
321-
registry-url: 'https://registry.npmjs.org'
325+
326+
- name: Upgrade npm to >= 11.5.1 (Trusted Publisher support)
327+
run: |
328+
npm install -g 'npm@^11.5.1'
329+
npm --version
322330
323331
- name: Install dependencies
324332
# See test.yml for the --legacy-peer-deps rationale (mappersmith / diff conflict).
@@ -397,9 +405,7 @@ jobs:
397405
max_attempts: 3
398406
command: |
399407
cd npm-publish-temp
400-
npm publish --access public
401-
env:
402-
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
408+
npm publish --access public --provenance
403409
404410
- name: Clean up
405411
if: always()

docs/AUTOMATED_RELEASES.md

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -116,15 +116,29 @@ Set these in GitHub repository settings → Secrets:
116116

117117
| Secret | Description | Required |
118118
|--------|-------------|----------|
119-
| `NPM_TOKEN` | NPM authentication token for publishing | ✅ Yes |
119+
| `DOCKERHUB_USERNAME` | Docker Hub username for image pushes | ✅ Yes |
120+
| `DOCKERHUB_TOKEN` | Docker Hub access token | ✅ Yes |
120121
| `GITHUB_TOKEN` | Automatically provided by GitHub Actions | ✅ Auto |
121122

122-
### NPM Token Setup
123+
NPM publishing uses [npm Trusted Publishers](https://docs.npmjs.com/trusted-publishers) (OIDC) — no `NPM_TOKEN` secret is required.
123124

124-
1. Login to [npmjs.com](https://www.npmjs.com)
125-
2. Go to Account Settings → Access Tokens
126-
3. Create a new **Automation** token
127-
4. Add as `NPM_TOKEN` secret in GitHub
125+
### NPM Trusted Publisher Setup
126+
127+
The `publish-npm` job authenticates to npm via short-lived OIDC tokens minted by GitHub Actions. This is configured once on the npm side:
128+
129+
1. Login to [npmjs.com](https://www.npmjs.com) as a maintainer of `n8n-mcp`.
130+
2. Go to the package page → **Settings** → **Trusted Publishers** → **Add publisher**.
131+
3. Configure:
132+
- **Publisher**: GitHub Actions
133+
- **Organization or user**: `czlonkowski`
134+
- **Repository**: `n8n-mcp`
135+
- **Workflow filename**: `release.yml`
136+
- **Environment**: `npm-publish`
137+
4. Save.
138+
139+
The matching GitHub environment must exist (Settings → Environments → `npm-publish`). No protection rules are required, though a required reviewer can be added for an approval gate before each release.
140+
141+
The workflow declares `id-token: write` and `environment: npm-publish` on the `publish-npm` job; `npm publish` detects the OIDC runtime and authenticates automatically. Provenance attestations are published with every release.
128142

129143
## Testing
130144

@@ -230,7 +244,17 @@ The workflow provides comprehensive summaries:
230244
```
231245
Error: 401 Unauthorized
232246
```
233-
**Solution**: Check NPM_TOKEN secret is valid and has publishing permissions.
247+
or
248+
```
249+
npm error code ENEEDAUTH
250+
npm error need auth This command requires you to be logged in
251+
```
252+
**Solution**: Verify the Trusted Publisher configuration on npmjs.com matches the workflow:
253+
- Repository: `czlonkowski/n8n-mcp`
254+
- Workflow filename: `release.yml` (filename only, no path)
255+
- Environment: `npm-publish`
256+
257+
Also confirm the `publish-npm` job in the workflow still has `permissions: id-token: write` and `environment: npm-publish`. Runner npm must be ≥ 11.5.1 — the `Upgrade npm` step handles this.
234258
235259
#### Docker Build Fails
236260
```
@@ -282,7 +306,9 @@ Version not incremented
282306
## Security
283307

284308
### Secrets Management
285-
- NPM_TOKEN has limited scope (publish only)
309+
- NPM auth uses Trusted Publishers (OIDC) — no long-lived npm token stored in the repo
310+
- Each release mints a short-lived token scoped to the workflow run
311+
- Provenance attestations are signed and published with every release, linking the package back to the exact commit + workflow run
286312
- GITHUB_TOKEN has automatic scoping
287313
- No secrets are logged or exposed
288314

scripts/test-release-automation.js

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -419,14 +419,35 @@ class ReleaseAutomationTester {
419419
}
420420
}
421421

422-
// Check for secrets usage
423-
if (workflowContent.includes('${{ secrets.NPM_TOKEN }}')) {
424-
success('Workflow: NPM_TOKEN secret configured');
422+
// Check for npm Trusted Publisher (OIDC) configuration — scoped to the publish-npm job
423+
// Slice from " publish-npm:" to the next job at the same indent (2 spaces, non-space char)
424+
const publishNpmMatch = workflowContent.match(/^ {2}publish-npm:\n([\s\S]*?)(?=^ {2}\S|\Z)/m);
425+
const publishNpmBlock = publishNpmMatch ? publishNpmMatch[1] : '';
426+
427+
if (!publishNpmBlock) {
428+
error('Workflow: could not locate publish-npm job block for OIDC checks');
429+
this.errors.push('publish-npm job not found in workflow');
425430
} else {
426-
warning('Workflow: NPM_TOKEN secret may be missing');
427-
this.warnings.push('NPM_TOKEN secret may need to be configured');
431+
if (/\bid-token:\s*write\b/.test(publishNpmBlock)) {
432+
success('Workflow: publish-npm has id-token: write permission (OIDC)');
433+
} else {
434+
error('Workflow: publish-npm is missing id-token: write permission');
435+
this.errors.push('Trusted Publishing requires id-token: write on publish-npm job');
436+
}
437+
438+
if (/\benvironment:\s*npm-publish\b/.test(publishNpmBlock)) {
439+
success('Workflow: publish-npm uses npm-publish environment');
440+
} else {
441+
error('Workflow: publish-npm is missing environment: npm-publish');
442+
this.errors.push('Trusted Publishing requires environment: npm-publish on publish-npm job');
443+
}
428444
}
429-
445+
446+
if (workflowContent.includes('${{ secrets.NPM_TOKEN }}')) {
447+
warning('Workflow: stale NPM_TOKEN reference found — Trusted Publishing makes this unnecessary');
448+
this.warnings.push('Remove ${{ secrets.NPM_TOKEN }} from workflow now that OIDC is used');
449+
}
450+
430451
if (workflowContent.includes('${{ secrets.GITHUB_TOKEN }}')) {
431452
success('Workflow: GITHUB_TOKEN secret configured');
432453
} else {
@@ -535,9 +556,11 @@ class ReleaseAutomationTester {
535556

536557
// Next steps
537558
log('\n📋 Next Steps:', 'cyan');
538-
log('1. Ensure all secrets are configured in GitHub repository settings:', 'cyan');
539-
log(' • NPM_TOKEN (required for npm publishing)', 'cyan');
540-
log(' • GITHUB_TOKEN (automatically available)', 'cyan');
559+
log('1. Ensure GitHub repository settings are configured:', 'cyan');
560+
log(' • Secrets: DOCKERHUB_USERNAME, DOCKERHUB_TOKEN', 'cyan');
561+
log(' • Environment "npm-publish" exists (Settings → Environments)', 'cyan');
562+
log(' • npm Trusted Publisher configured on npmjs.com (no NPM_TOKEN secret needed)', 'cyan');
563+
log(' • GITHUB_TOKEN is provided automatically', 'cyan');
541564
log('\n2. To trigger a release:', 'cyan');
542565
log(' • Update version in package.json', 'cyan');
543566
log(' • Update changelog in docs/CHANGELOG.md', 'cyan');

0 commit comments

Comments
 (0)