Skip to main content

Phase 12. npm Trusted-Publishing publish

FieldValue
MEPMEP-72 §Phases
StatusNOT STARTED
Tracking issue(pending)
Tracking PR(pending)
Commit(pending)

Gate

TestPhase12NpmPublish in package3/typescript/publish/phase12_test.go: subtests emit_workflow, oidc_token_exchange_recorded, attestation_generated, consumer_verification, npm_audit_signatures. The first asserts that mochi pkg publish --target=npm-library produces a GitHub Actions workflow at .github/workflows/mochi-publish-npm.yml that runs npm publish --provenance --access=public under the id-token: write permission. The second replays a recorded OIDC token-exchange flow (using a fixture-mode npm registry) and asserts the token is exchanged correctly. The third runs the publish flow end-to-end against the fixture registry and asserts the resulting _attestations entry on the packument carries a valid Sigstore signature. The fourth runs npm install @mochi/example from a downstream consumer fixture and asserts the install verifies the attestation. The fifth runs npm audit signatures against the same install and asserts the audit passes.

Lowering decisions

The phase emits a GitHub Actions workflow (already shipping in MEP-52 Phase 18 under the TargetReleaseWorkflow):

name: Publish to npm

on:
push:
tags: ['v*']

permissions:
contents: read
id-token: write

jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '22'
registry-url: 'https://registry.npmjs.org'
- name: Build Mochi package
run: mochi build --target=npm-library
- name: Publish to npm with provenance
working-directory: ./target/ts/npm-library
run: npm publish --provenance --access=public
- name: Attest build provenance
uses: actions/attest-build-provenance@v2
with:
subject-path: 'target/ts/npm-library/dist/**'

The id-token: write permission lets actions/attest-build-provenance exchange the GitHub Actions OIDC token for a Sigstore certificate via Fulcio. npm publish --provenance flag triggers npm's server-side attestation recording.

The workflow has NO NPM_TOKEN secret (matches MEP-52 §A11 + MEP-73 §A9 + MEP-74 §A9): authentication is OIDC token exchange only. The user pre-configures the package's npm registry settings to enable Trusted Publishing for the specific GitHub repository (one-time UI flow at https://www.npmjs.com/settings//packages//access).

The workflow uploads only target/ts/npm-library/ (the Phase 10 emit output). The bridge's reference Go skeleton does NOT shell out to npm publish from inside Mochi; the publish is GitHub-Actions-driven, the bridge only emits the workflow.

The phase's gate runs against a fixture-mode npm registry (the npm-registry-fake test server) so the test suite is hermetic and does not require a real npm publish.

Files changed

FilePurpose
package3/typescript/publish/npm.goEmitNpmPublishWorkflow, EmitProvenanceStep
package3/typescript/publish/oidc.goOIDC token-exchange helper (used in fixture mode)
package3/typescript/publish/phase12_test.goTestPhase12NpmPublish sentinel
package3/typescript/publish/testdata/npm-registry-fake/fixture-mode registry server
.github/workflows/templates/mochi-publish-npm.ymlthe canonical workflow template emitted by Phase 18

Test set

5 subtests as listed in the Gate section.

Cross-references