Skip to content

feat(prd-048): npm Trusted Publishing (OIDC) — supersede D-2's Automation token#105

Merged
thenotoriousllama merged 2 commits into
mainfrom
legion/prd-048-trusted-publishing
Jun 25, 2026
Merged

feat(prd-048): npm Trusted Publishing (OIDC) — supersede D-2's Automation token#105
thenotoriousllama merged 2 commits into
mainfrom
legion/prd-048-trusted-publishing

Conversation

@thenotoriousllama

@thenotoriousllama thenotoriousllama commented Jun 25, 2026

Copy link
Copy Markdown
Collaborator

Summary

Amends PRD-048 to authenticate the npm publish with Trusted Publishing (tokenless OIDC) instead of a long-lived org Automation token — superseding decision D-2. OIDC provenance (D-7) stays. No NPM_TOKEN secret ever.

.github/workflows/release.yaml

  • Removed the NPM_TOKEN token gate and the NODE_AUTH_TOKEN env from the publish steps. Auth is now OIDC: Actions presents a short-lived id-token that npm verifies against the trusted publisher configured on the package. HONEYCOMB_POSTHOG_KEY becomes the only release secret.
  • Re-gated the real publish on a tag push (github.ref_type == 'tag' && !dry_run) rather than token presence; workflow_dispatch always dry-runs.
  • Added npm install -g npm@^11.5.1 after Setup Node — Node 22 ships npm 10.x, but OIDC Trusted Publishing requires npm ≥ 11.5.1 or the handshake never engages. Kept --provenance --access public, id-token: write, the dry-run rehearsal, the gate, the version guard, and the publishability preflight.

Docs (supersede, not erase)

  • index.md — D-2 struck + retained for the record; new D-2′ (Trusted Publishing). Go-public switch (d) → "configure the trusted publisher"; risks/ACs reconciled.
  • 048a — org-provisioning ACs kept; token ACs replaced by trusted-publisher-config ACs, with the first-publish bootstrap nuance documented (the trusted publisher can't be configured until the package exists, so the first publish is a one-time manual 2FA publish; OIDC for all CI publishes after).
  • RELEASING.md + 048d reconciled to the tokenless / trigger-gated model.

Notes

  • Flagged for 048d (not changed here): the publishability preflight still fails-closed even on a dry-run while private: true — that's 048d's rehearsal-green scope.
  • npm run ci green (3252). release.yaml parses; zero functional NPM_TOKEN refs remain.

Operator's remaining off-repo steps (unchanged count): create the npm org, the one bootstrap publish, and configure the trusted publisher on npm (org legioncodeinc + repo honeycomb + workflow release.yaml) — instead of minting/storing a token.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Switched npm publishing to tokenless Trusted Publishing with GitHub OIDC (provenance retained).
    • Added release-mode gating so real publishes happen only on version tag pushes; other runs use npm publish --dry-run.
    • Updated the workflow to upgrade npm before publishing to ensure Trusted Publishing works.
  • Bug Fixes

    • Removed prior token-based authentication behavior to prevent token-gate inconsistencies.
    • Strengthened safety preflights to keep non-release modes from producing real publishes.
  • Documentation

    • Updated release and planning docs for first-time bootstrap publishing and trusted publisher setup (no NPM_TOKEN).

…supersede D-2

Operator decision: use npm Trusted Publishing (tokenless OIDC) instead of a long-lived
Automation token. Keep OIDC provenance.

release.yaml:
- Remove the NPM_TOKEN token gate + NODE_AUTH_TOKEN env from the publish steps. Auth is now
  OIDC: GitHub Actions presents a short-lived id-token that npm verifies against the trusted
  publisher configured on the package. No stored npm secret (HONEYCOMB_POSTHOG_KEY is now the
  only release secret).
- Gate the real publish on a tag push (github.ref_type == 'tag' && !dry_run) rather than token
  presence; workflow_dispatch always dry-runs.
- Add `npm install -g npm@^11.5.1` after Setup Node — Node 22 ships npm 10.x, but OIDC Trusted
  Publishing needs npm >= 11.5.1 or the handshake never engages. Keep --provenance --access public.

Docs (supersede, not erase):
- index.md: D-2 struck + retained; new D-2′ (Trusted Publishing, no NPM_TOKEN). Go-public switch
  (d) → "configure the trusted publisher"; risks/ACs reconciled.
- 048a: org-provisioning ACs kept; token ACs → trusted-publisher config ACs + the first-publish
  bootstrap nuance (trusted publisher requires the package to exist → one manual 2FA publish, then
  OIDC for all CI publishes).
- RELEASING.md + 048d reconciled to the tokenless/trigger-gated model.

Note for 048d: the publishability preflight still fails-closed even on a dry-run while private:true
(unchanged by this auth swap) — left to 048d's rehearsal-green scope.

npm run ci green (3252 tests). release.yaml YAML parses; zero functional NPM_TOKEN refs remain.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 487472e7-3316-4dc8-aba3-ba80f8d199e9

📥 Commits

Reviewing files that changed from the base of the PR and between 3a0a30d and 0716b84.

📒 Files selected for processing (4)
  • .github/workflows/release.yaml
  • library/requirements/backlog/prd-048-npm-publishing-pipeline/prd-048-npm-publishing-pipeline-index.md
  • library/requirements/backlog/prd-048-npm-publishing-pipeline/prd-048a-npm-org-provisioning.md
  • library/requirements/backlog/prd-048-npm-publishing-pipeline/prd-048d-rehearsal-verification.md
🚧 Files skipped from review as they are similar to previous changes (4)
  • library/requirements/backlog/prd-048-npm-publishing-pipeline/prd-048a-npm-org-provisioning.md
  • library/requirements/backlog/prd-048-npm-publishing-pipeline/prd-048d-rehearsal-verification.md
  • library/requirements/backlog/prd-048-npm-publishing-pipeline/prd-048-npm-publishing-pipeline-index.md
  • .github/workflows/release.yaml

📝 Walkthrough

Walkthrough

The release workflow, release guidance, and PRD documents now describe npm Trusted Publishing with GitHub OIDC instead of NPM_TOKEN. Publish mode is gated by push/tag and dry-run inputs, and the docs add bootstrap and npm version requirements.

Changes

npm Trusted Publishing rollout

Layer / File(s) Summary
Workflow setup and permissions
.github/workflows/release.yaml
The release workflow adds OIDC permissions, updates npm setup, and installs npm 11.6.2 before publish steps.
Trigger-based publish path
.github/workflows/release.yaml
Publish mode now resolves from tag and dry-run triggers, and publish commands run without NODE_AUTH_TOKEN.
Release runbook
RELEASING.md
The release checklist, trusted-publisher setup, bootstrap publish guidance, and workflow reference are rewritten for OIDC publishing.
Pipeline PRD index
library/requirements/backlog/prd-048-npm-publishing-pipeline/prd-048-npm-publishing-pipeline-index.md
The PRD index updates the trusted-publisher decision, acceptance criteria, risks, and dependency notes.
Org provisioning PRD
library/requirements/backlog/prd-048-npm-publishing-pipeline/prd-048a-npm-org-provisioning.md
The org provisioning PRD replaces automation-token setup with npm trusted-publisher configuration and bootstrap requirements.
Rehearsal verification PRD
library/requirements/backlog/prd-048-npm-publishing-pipeline/prd-048d-rehearsal-verification.md
The rehearsal PRD redefines dry-run and accidental-publish behavior around tag-push-only publishing.

Sequence Diagram(s)

sequenceDiagram
  participant GitHubActions as GitHub Actions
  participant ReleaseWorkflow as release.yaml
  participant NpmTrustedPublishing as npm Trusted Publishing
  participant NpmRegistry as npm registry
  GitHubActions->>ReleaseWorkflow: start on tag push or workflow_dispatch
  ReleaseWorkflow->>ReleaseWorkflow: resolve publish mode from github.ref_type and dry_run
  alt real publish
    ReleaseWorkflow->>NpmTrustedPublishing: request OIDC auth with id-token: write
    NpmTrustedPublishing->>NpmRegistry: authorize npm publish --provenance --access public
    ReleaseWorkflow->>NpmRegistry: publish package
  else dry-run
    ReleaseWorkflow->>ReleaseWorkflow: run npm publish --dry-run
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

A bunny hops by, ears held high,
No token pouch beneath the sky.
OIDC hums, tags roll through,
Dry runs stay soft with morning dew.
Hooray for launches, bright and true! 🐇

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: replacing the Automation token with npm Trusted Publishing via OIDC.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch legion/prd-048-trusted-publishing

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/release.yaml:
- Around line 190-201: The publish-mode logic in the Resolve publish mode step
currently sets publish=true for any tag ref with dry_run=false, which can happen
on workflow_dispatch and allow an unintended real release. Update the condition
in the mode step to require a push event as well as a tag ref before enabling
real publish, and keep all other cases routed to the dry-run branch.
- Around line 93-95: The release workflow currently installs npm with a floating
major range, which can change the CLI version at publish time. In the release
job, update the npm upgrade step in the workflow to use one exact reviewed npm
version instead of the caret range, and keep bumping it intentionally when
needed; the Trusted Publishing requirement is still satisfied as long as the
chosen version is at least 11.5.1.
- Line 83: The release workflow still uses tag-based third-party actions, so
update the actions in the publish job to full commit SHAs instead of version
tags. Locate the workflow entries for actions/checkout, actions/setup-node, and
softprops/action-gh-release, and replace each referenced tag with the
corresponding reviewed SHA so the release process does not follow moved tags.
- Line 87: The publish workflow is still enabling setup-node package-manager
caching via the release job’s cache setting. Update the workflow configuration
around the setup-node step in the release/publish job to disable package-manager
caching by setting package-manager-cache to false, while keeping npm ci for
dependency installation.
- Around line 77-79: Clarify the npm publish auth setup in the release workflow
comments around the registry configuration: `registry-url` may still create
`.npmrc` scaffolding, but the important invariant is that no npm token is
provided anywhere in this trusted publishing path. Update the wording near the
release job setup to reflect that `npm publish` authorization comes from
OIDC/trusted publishing, not from `NODE_AUTH_TOKEN` or any token value, and keep
the explanation aligned with the existing release workflow symbols and comments.

In
`@library/requirements/backlog/prd-048-npm-publishing-pipeline/prd-048-npm-publishing-pipeline-index.md`:
- Around line 31-32: Update the superseded auth cross-reference in the PRD note
to point to D-2′ instead of D-2, since D-2 is already replaced later in the same
document. Find the supersession note near the D-2 reference in
prd-048-npm-publishing-pipeline-index.md and change the reference so readers
follow the newer decision history.

In
`@library/requirements/backlog/prd-048-npm-publishing-pipeline/prd-048a-npm-org-provisioning.md`:
- Around line 81-86: The Dependencies section conflates workflow auth with
npm-side setup; update the wording to separate `release.yaml`’s OIDC publish
path from the actual npm trusted publisher configuration. Clarify that GitHub
repo admin access is needed to configure the trusted publisher in npm, and
explicitly state the npm account ownership/maintainer requirement so it’s clear
who owns the npm-side setup.

In
`@library/requirements/backlog/prd-048-npm-publishing-pipeline/prd-048d-rehearsal-verification.md`:
- Around line 57-63: The risk text in the rehearsal verification section is
overstating the role of the workflow_dispatch dry_run checkbox; update the
wording in the “Risks / Out of scope” entry for this PRD so it makes clear that
workflow_dispatch stays dry-run because it is not a tag ref. Revise the
mitigation language to emphasize “no vX.Y.Z tag pushed” as the real safeguard,
and keep the focus on the tag-push publish path rather than implying dry_run
prevents publishing.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 64945f6f-b373-4d69-9422-53b996e7fd75

📥 Commits

Reviewing files that changed from the base of the PR and between 9f13362 and 3a0a30d.

📒 Files selected for processing (5)
  • .github/workflows/release.yaml
  • RELEASING.md
  • library/requirements/backlog/prd-048-npm-publishing-pipeline/prd-048-npm-publishing-pipeline-index.md
  • library/requirements/backlog/prd-048-npm-publishing-pipeline/prd-048a-npm-org-provisioning.md
  • library/requirements/backlog/prd-048-npm-publishing-pipeline/prd-048d-rehearsal-verification.md

Comment thread .github/workflows/release.yaml Outdated
Comment thread .github/workflows/release.yaml
Comment thread .github/workflows/release.yaml Outdated
Comment thread .github/workflows/release.yaml Outdated
Comment thread .github/workflows/release.yaml Outdated
…blish job

Three legitimate CodeRabbit/zizmor findings on the trusted-publishing workflow:
- Major (Data Integrity): a workflow_dispatch CAN target a tag ref, so 'ref_type==tag &&
  !dry_run' could flip publish=true on a manual run. Add github.event_name=='push' to the
  real-publish gate so a dispatch ALWAYS rehearses. (Real publishes only from a pushed tag.)
- Major (Security): drop 'cache: npm' on the publish job — a lower-privilege workflow could
  poison an npm cache that this high-privilege release build then executes (cache-poisoning).
  npm ci installs from the committed lockfile.
- Major (Security): pin the npm upgrade to an exact version (npm@11.6.2) instead of '^11.5.1'
  so a release never runs an unreviewed CLI; still satisfies the OIDC >= 11.5.1 floor.

Declined (with reason): full-SHA action pinning — these refs (checkout@v4.2.2, setup-node@v6.4.0,
action-gh-release@v2.4.1) are pre-existing version-tag pins matching the repo-wide convention; not
changing pinning granularity for one workflow.

Doc minors: index xref → D-2′; 048a clarifies release.yaml consumes (not configures) the publisher;
048d guard wording aligned to the new event_name=='push' gate.

release.yaml parses; npm run ci unaffected (workflow+docs only).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@thenotoriousllama thenotoriousllama merged commit c1e7516 into main Jun 25, 2026
15 checks passed
@github-actions github-actions Bot locked and limited conversation to collaborators Jun 25, 2026
@thenotoriousllama thenotoriousllama deleted the legion/prd-048-trusted-publishing branch June 26, 2026 01:54
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant