Skip to content

Publish from CI with npm provenance (--provenance / OIDC trusted publisher) #2028

Open

Description

@thymikee

From the MCP registry security assessment (its item 4). release:publish runs npm publish from a maintainer laptop, so the published tarball has only npm's registry signature — dist.attestations is null, and there is no verifiable link from the tarball back to the commit that produced it.

Goal

Publish from CI with npm publish --provenance under an OIDC trusted publisher, so consumers get a signed provenance statement pinning the tarball to its source commit and workflow run.

Work

  • Configure the npm package's trusted-publisher / OIDC settings on npmjs.com (maintainer action — cannot be scripted from the repo; blocks the rest).
  • Add a release workflow (or extend the existing tag-triggered one) that runs release:prepare then npm publish --provenance with id-token: write permission, instead of a local npm publish.
  • Keep release:mark-dev running post-publish (added in Harden the MCP surface: registry rug-pull fix, operator-only credentials/endpoints, device-shell argv gate, declared timeouts #2023) so main still moves off the released version.
  • The MCP-registry publish workflow already uses OIDC (publish-mcp-registry.yml) — mirror its trusted-publisher pattern.

Notes

Activity

  1. mahirhir commented on Aug 28, 2026

    @mahirhir

    Here is the complete .github/workflows/release.yml workflow implementing zero-secret npm Trusted Publishing with cryptographic build provenance:

    .github/workflows/release.yml

    name: Release
    
    on:
      push:
        tags:
          - "v*.*.*"
    
    permissions:
      contents: write
      id-token: write # Required for npm OIDC Trusted Publishing & Sigstore SLSA provenance
      attestations: write
    
    jobs:
      publish:
        runs-on: ubuntu-latest
        steps:
          - name: Checkout repository
            uses: actions/checkout@v4
            with:
              fetch-depth: 0
              token: ${{ secrets.GITHUB_TOKEN }}
    
          - name: Set up Node.js
            uses: actions/setup-node@v4
            with:
              node-version: 22
              registry-url: "https://registry.npmjs.org"
    
          - name: Install dependencies
            run: npm ci
    
          - name: Run test & verification suite
            run: |
              npm run typecheck
              npm test
              npm run build
    
          - name: Prepare release
            run: npm run release:prepare
    
          - name: Publish to npm with Provenance
            run: npm publish --provenance --access public
            env:
              NODE_AUTH_TOKEN: "" # Explicitly omitted; npm uses GitHub Actions OIDC token exchange
    
          - name: Mark development version on main branch
            run: |
              git config user.name "github-actions[bot]"
              git config user.email "github-actions[bot]@users.noreply.github.com"
              npm run release:mark-dev
              git push origin HEAD:main

    Verification

    Once configured on npmjs.com (Settings -> Publishing Access -> GitHub Actions OIDC), consumers can independently verify:

    npm view agent-device dist.attestations

    This produces a cryptographically signed Sigstore certificate linking the exact npm tarball SHA-512 back to the release workflow and commit SHA.

  2. thymikee commented on Oct 9, 2026

    @thymikee
    MemberAuthor

    Decision: accepted, but it's more than the npm setting. We don't publish from CI today: releases go through scripts/release-workspace.mjs publish locally, and it publishes several workspace packages. So:

    1. Maintainer (npmjs.com), for each published package: add a trusted publisher with GitHub owner callstack, repository agent-device, the exact workflow filename, and the environment name if the job uses one.
    2. Repo: a release workflow on a GitHub-hosted runner with id-token: write, npm ≥ 11.5.1 and Node ≥ 22.14, driving release-workspace.mjs with pnpm. The contributed Ubuntu npm ci workflow doesn't fit our pnpm workspace or the macOS-built native Apple artifacts, so it needs adapting rather than dropping in.

    Step 2 can be written now; step 1 has to be done by the maintainer.

  3. added
    ready-for-humanValid work that needs human implementation, judgment, or maintainer merge
    and removed
    needs-infoWaiting on reporter or external input
    on Oct 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    ready-for-humanValid work that needs human implementation, judgment, or maintainer merge

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions