Skip to content

Set up Trusted Publishing for sub100 CLI via GitHub Actions #10

@LongTangGithub

Description

@LongTangGithub

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

  • .github/workflows/publish.yml exists with OIDC permissions configured
  • Workflow triggers on git tag push matching v*.*.* pattern (or on Changesets release PR merge — pick the better fit)
  • npm package sub100 configured to trust the specific GitHub repo + workflow path
  • Test publish of sub100@0.1.1 (or whatever next version) succeeds via tag push with no manual OTP or token handling
  • Documented in repo README: "To publish, tag a release with git tag v0.1.x && git push --tags"
  • Granular token workflow removed from publish docs

Setup steps (rough sketch)

  1. 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
  2. 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)
  3. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions