Skip to content

feat(release): migrate npm publication to Trusted Publishing/OIDC (Beta.2 slice of #1187) - #1293

Merged
SisyphusZheng merged 1 commit into
devfrom
kimi/v044-b212-npm-trusted-publishing
Sep 3, 2026
Merged

feat(release): migrate npm publication to Trusted Publishing/OIDC (Beta.2 slice of #1187)#1293
SisyphusZheng merged 1 commit into
devfrom
kimi/v044-b212-npm-trusted-publishing

Conversation

@SisyphusZheng

Copy link
Copy Markdown
Member

Beta.2 slice of #1187 (tracked as B2.12 on stage issue #1288; umbrella #1155; ADR-0151). NOT closing #1187 — the machine-readable closure-evidence gate (PR #1191 lineage) remains Beta.3 scope.

Problem

npm publication authenticated with a long-lived NPM_TOKEN written to ~/.npmrc and passed as NODE_AUTH_TOKEN/NPM_TOKEN env in autoflow-release.yml. Policy (SECURITY.md, docs/governance/RELEASE_POLICY.md) already declares Trusted Publishing/OIDC as the only authorized publication path; the implementation lagged the policy.

Owner

B2.12 implementer slice (kimi), under Beta.2 stage #1288.

Before

  • autoflow-release.yml: "Configure npm auth" step wrote //registry.npmjs.org/:_authToken=${NPM_TOKEN} to $HOME/.npmrc; publish step exported NODE_AUTH_TOKEN/NPM_TOKEN from secrets.NPM_TOKEN.
  • tools/autoflow/release.ts canPublishNpm() returned true when NPM_TOKEN/NODE_AUTH_TOKEN was set — any environment holding the token (including a local machine) could publish.
  • Node 22's bundled npm predates native OIDC support, so trusted publishing would have failed even with id-token: write (already granted).

After

  • No token, no .npmrc auth anywhere in the release workflow. id-token: write (already present) is the only npm credential.
  • New "Upgrade npm CLI for Trusted Publishing" step: npm install -g "npm@^11.5.1" + a runtime >=11.5.1 assertion, running before the publish step. registry-url: 'https://registry.npmjs.org' kept (registry/provenance config, not auth). --provenance stays explicit in tools/publish-npm.ts for the Actions lane.
  • canPublishNpm() now returns true only when GITHUB_ACTIONS === 'true' — publication capability exists only in the hosted OIDC lane; local/manual runs never publish, even if a legacy token variable is set.
  • Mechanical enforcement: tools/autoflow/__tests__/pr-ci-workflow.test.ts fails closed on any NPM_TOKEN/NODE_AUTH_TOKEN/_authToken reference in autoflow-release.yml, requires id-token: write, the pinned npm floor, upgrade-before-publish ordering, and a token-free publish-step env.

Why not second owner

Single bounded slice per the Beta.2 per-slice completion semantics on #1288; the OIDC migration is one coherent change (workflow + plan gate + tests + runbook) and the npm-side registration is a maintainer web action, not repo work.

Evidence (all local, allowed; no real publish dispatched)

  • RED: new B2.12 (#1187) workflow test failed on NPM_TOKEN before the workflow edit; the three updated plan tests failed against the old canPublishNpm — exact failing assertions recorded.
  • GREEN: deno test … tools/autoflow/ tools/publish-npm.test.ts → 148 passed, 0 failed.
  • deno task pack:dry-run → exit 0 (5 tarballs, 0.44.0-beta.1).
  • deno task package-artifacts:check → exit 0 (5 packages).
  • deno task publish:npm:dry-run → exit 0 (real npm CLI dry-run path, registry queried, no auth material present).
  • deno task workflow:check-slimming, actions:check-pins, docs:truth, release:state-machine:check, docs:check-role-neutral, freeze:semantics:check → all pass.
  • Workflow YAML validated by parse in the workflow test; no actionlint/zizmor is wired in this repo yet (tracked separately under governance offload).
  • autoflow:publish-existing --dry-run locally stops at the mandatory --pr-ci exact-SHA evidence requirement (fail-closed by design); the hosted dry_run: true dispatch remains the full rehearsal path post-merge.

Scope

Touched: .github/workflows/autoflow-release.yml, tools/autoflow/release.ts (canPublishNpm), tools/publish-npm.ts (comment only), tests (pr-ci-workflow.test.ts, policy.test.ts, release.test.ts), docs/adr/ADR-0108 (supersession note), new docs/runbooks/npm-trusted-publishing.md. Closure-evidence semantics untouched (Beta.3). Historical docs/release/v0.41.0-alpha.1-plan.md left as dated history.

Risk

Real publishes fail until the npm-side registration below is complete for all five packages — this is loud in the workflow itself (comments on id-token: write and the publish step) and intentional: there is no token fallback.

Maintainer runbook (npm-side precondition — verbatim from docs/runbooks/npm-trusted-publishing.md)

For each of the five packages — @openelement/element, @openelement/app, @openelement/adapter-vite, @openelement/create, @openelement/ui — register this exact trusted publisher on npmjs.com:

Field Value
Publisher type GitHub Actions
Organization / user open-element
Repository openelement
Workflow filename autoflow-release.yml
Environment name (leave blank — the workflow uses no GitHub environment)

Steps (per package):

  1. Sign in to https://www.npmjs.com with an account that administers the @openelement scope.
  2. Open the package page → SettingsPublishing accessTrusted publishers.
  3. Choose GitHub Actions and enter: Organization/user open-element, Repository openelement, Workflow filename autoflow-release.yml (filename only, no path prefix), Environment empty.
  4. Save; repeat for the remaining four packages.

Verification: dispatch autoflow-release.yml with dry_run: true first; the first real publish must show the Trusted Publishing provenance attestation on each package page. After the first successful trusted publish, the NPM_TOKEN repository secret can be deleted from GitHub — nothing references it.

 B2.12)

Remove the long-lived NPM_TOKEN/.npmrc auth path from autoflow-release.yml
and gate npm publication capability on the GitHub Actions OIDC lane instead
of token env vars. The release job pins an explicit npm CLI floor
(npm@^11.5.1, verified at runtime) because Node 22's bundled npm predates
native OIDC support. Publish keeps --provenance in the Actions lane.

The no-token shape is mechanically enforced: pr-ci-workflow.test.ts fails
closed on any NPM_TOKEN/NODE_AUTH_TOKEN/_authToken reference in the release
workflow and requires id-token: write plus the npm floor step before publish.

npm-side trusted-publisher registration for the five @OpenElement packages
is a maintainer web precondition; see docs/runbooks/npm-trusted-publishing.md.

Beta.2 slice of #1187 (B2.12 on #1288).
@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying openelement with  Cloudflare Pages  Cloudflare Pages

Latest commit: 835961e
Status: ✅  Deploy successful!
Preview URL: https://33c11d5a.lessjs.pages.dev
Branch Preview URL: https://kimi-v044-b212-npm-trusted-p.lessjs.pages.dev

View logs

@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

APIError: Insufficient Balance

opencode session  |  github run

@SisyphusZheng
SisyphusZheng merged commit 736138b into dev Sep 3, 2026
10 checks passed
@SisyphusZheng
SisyphusZheng deleted the kimi/v044-b212-npm-trusted-publishing branch September 3, 2026 16:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant