Context
For SUB-7 v0.1.0 publish, we used a granular access token with "bypass 2FA" enabled, generated and revoked per publish. This works but has friction (~10 minutes per publish: generate token → set in npmrc → publish → revoke token → remove from npmrc).
npm deprecated TOTP authenticator app 2FA as a new-enrollment option in September 2025. Existing TOTP setups are grandfathered; new enrollments only see Security Keys (WebAuthn). The npm CLI can't do WebAuthn from the terminal, so npm publish is blocked unless you (a) use a grandfathered TOTP setup, (b) use granular tokens with bypass-2FA, or (c) use Trusted Publishing.
Trusted Publishing is npm's recommended modern approach. It uses OIDC to verify GitHub Actions runner identity. No tokens stored anywhere.
Why this is worth doing
- Reduces manual publish friction from ~10 minutes to ~30 seconds (push a git tag → workflow runs → done)
- Removes need for granular tokens entirely
- Bound to a specific repo + workflow path, so credentials can't be reused even if exfiltrated
- Standard pattern for active npm-published projects (shadcn/ui, Anthropic SDKs, others)
- Plays nicely with Changesets for version management
Acceptance criteria
Setup steps (rough sketch)
-
Add .github/workflows/publish.yml:
name: Publish
on:
push:
tags: ['v*.*.*']
permissions:
contents: read
id-token: write # required for OIDC
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v3
- uses: actions/setup-node@v4
with:
node-version: 20
registry-url: 'https://registry.npmjs.org'
- run: pnpm install
- run: pnpm --filter sub100 build
- run: pnpm --filter sub100 publish --access public --no-git-checks
-
On npmjs.com → sub100 package settings → Trusted Publishers → Add publisher:
- Subject:
repo:LongTangGithub/sub100:ref:refs/tags/v*
- Workflow path:
.github/workflows/publish.yml
- Environment: (leave blank or set to
production if using environment protection rules)
-
Test with a patch release:
# Bump version in packages/cli/package.json to 0.1.1
git tag v0.1.1
git push --tags
# Watch workflow run, verify npm publish succeeds
Reference
Why not now
SUB-7 already shipped 0.1.0 via the granular-token path. Setting up Trusted Publishing mid-Phase 8 would burn the remaining time we need for Lighthouse, PR description, and merge. Better to add this as a one-time setup task before the next publish.
Estimated effort
~30-60 minutes one-time setup + one test publish to verify.
Context
For SUB-7 v0.1.0 publish, we used a granular access token with "bypass 2FA" enabled, generated and revoked per publish. This works but has friction (~10 minutes per publish: generate token → set in npmrc → publish → revoke token → remove from npmrc).
npm deprecated TOTP authenticator app 2FA as a new-enrollment option in September 2025. Existing TOTP setups are grandfathered; new enrollments only see Security Keys (WebAuthn). The npm CLI can't do WebAuthn from the terminal, so
npm publishis blocked unless you (a) use a grandfathered TOTP setup, (b) use granular tokens with bypass-2FA, or (c) use Trusted Publishing.Trusted Publishing is npm's recommended modern approach. It uses OIDC to verify GitHub Actions runner identity. No tokens stored anywhere.
Why this is worth doing
Acceptance criteria
.github/workflows/publish.ymlexists with OIDC permissions configuredv*.*.*pattern (or on Changesets release PR merge — pick the better fit)sub100configured to trust the specific GitHub repo + workflow pathsub100@0.1.1(or whatever next version) succeeds via tag push with no manual OTP or token handlinggit tag v0.1.x && git push --tags"Setup steps (rough sketch)
Add
.github/workflows/publish.yml:On npmjs.com → sub100 package settings → Trusted Publishers → Add publisher:
repo:LongTangGithub/sub100:ref:refs/tags/v*.github/workflows/publish.ymlproductionif using environment protection rules)Test with a patch release:
Reference
Why not now
SUB-7 already shipped 0.1.0 via the granular-token path. Setting up Trusted Publishing mid-Phase 8 would burn the remaining time we need for Lighthouse, PR description, and merge. Better to add this as a one-time setup task before the next publish.
Estimated effort
~30-60 minutes one-time setup + one test publish to verify.