Skip to content

fix(ci): publish to npm with provenance instead of bun publish#12

Merged
amondnet merged 1 commit into
mainfrom
fix/npm-publish-provenance
Jun 27, 2026
Merged

fix(ci): publish to npm with provenance instead of bun publish#12
amondnet merged 1 commit into
mainfrom
fix/npm-publish-provenance

Conversation

@amondnet

@amondnet amondnet commented Jun 27, 2026

Copy link
Copy Markdown
Contributor

The v0.3.0 release tag + GitHub release were created, but the npm-publish job failed:

404 Not Found: https://registry.npmjs.org/@pleaseai%2fcli-toolkit
'@pleaseai/cli-toolkit@0.3.0' does not exist in this registry

bun publish fails auth here and can't emit npm provenance, which the repo standard (CLAUDE.md) explicitly requires.

Changes

  • Publish via npm publish --provenance from a bun pm pack tarball (bun still does install/build)
  • Add actions/setup-node (pinned to SHA) for registry auth + Node, and job-level id-token: write for OIDC provenance
  • Add the repository field to package.json (required by --provenance)
  • Add a workflow_dispatch trigger (with a ref input) so the already-tagged v0.3.0 can be re-published manually after this merges

Follow-up after merge

Run the workflow manually for the existing tag:

gh workflow run release-please.yml --ref main -f ref=v0.3.0

Note: if NPM_TOKEN itself is expired/invalid, publish will still 401/404 — the secret may need refreshing (automation token with publish rights).


Summary by cubic

Fixes the failed npm publish by switching from bun publish to npm publish --provenance with OIDC, so releases publish correctly and include required provenance.

  • Bug Fixes

    • Publish via npm publish --provenance using a tarball from bun pm pack.
    • Add actions/setup-node for registry auth and set id-token: write for provenance.
    • Add the repository field to package.json (required by provenance).
    • Add workflow_dispatch with a ref input to manually publish existing tags (e.g., v0.3.0).
  • Migration

    • After merge, republish the existing tag: gh workflow run release-please.yml --ref main -f ref=v0.3.0

Written for commit 9fd0060. Summary will update on new commits.

Summary by CodeRabbit

  • Chores
    • Added support for manually triggering release publishing with a selected tag.
    • Updated publishing to include npm provenance and improved release authentication.
    • Added package repository metadata for better package publishing and traceability.

The npm-publish job used `bun publish`, which fails auth here (404 on the
scoped package) and cannot emit npm provenance — contrary to the repo standard.

- publish via `npm publish --provenance` from a `bun pm pack` tarball
- add actions/setup-node (registry auth) and job-level `id-token: write` for
  OIDC provenance
- add the required `repository` field to package.json (provenance needs it)
- add a workflow_dispatch trigger so an already-tagged release (v0.3.0) can be
  (re)published manually
@coderabbitai

coderabbitai Bot commented Jun 27, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: fb64a00c-f84c-4d5f-a79d-65a13df7f5b9

📥 Commits

Reviewing files that changed from the base of the PR and between d27fc22 and 9fd0060.

📒 Files selected for processing (2)
  • .github/workflows/release-please.yml
  • package.json

📝 Walkthrough

Walkthrough

The release workflow now accepts manual tag/ref input, runs publishing for manual or Release Please releases, checks out the requested ref, packs the release tarball, and publishes it with npm provenance. package.json now includes repository metadata.

Changes

Release publishing workflow

Layer / File(s) Summary
Manual trigger and job setup
.github/workflows/release-please.yml
Adds workflow_dispatch with a required ref input, expands the publish job condition, checks out that ref, and sets up Node.js 22 with npm registry configuration.
Provenance publish and package metadata
.github/workflows/release-please.yml, package.json
Replaces bun publish with bun pm pack plus npm publish --provenance using NODE_AUTH_TOKEN, and adds repository metadata to package.json.

Sequence Diagram(s)

sequenceDiagram
  participant GitHubActions as GitHub Actions
  participant ReleasePleaseWorkflow as release-please workflow
  participant ActionsCheckout as actions/checkout
  participant ActionsSetupNode as actions/setup-node
  participant BunPmPack as bun pm pack
  participant NpmPublish as npm publish

  GitHubActions->>ReleasePleaseWorkflow: workflow_dispatch with ref
  ReleasePleaseWorkflow->>ActionsCheckout: checkout ref
  ReleasePleaseWorkflow->>ActionsSetupNode: set up Node.js 22
  ReleasePleaseWorkflow->>BunPmPack: pack tarball
  ReleasePleaseWorkflow->>NpmPublish: publish with --provenance and NODE_AUTH_TOKEN
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related issues

  • pleaseai/claude-code-plugins issue 200 — The PR updates the Bun-to-npm release path, including bun pm pack, npm publish --provenance, and release-please integration.

Poem

🐰 I hopped to the release gate tonight,
Packed tarballs neat and provenance bright.
A ref to guide my springy way,
Then npm sent the bundle away.
Hooray for tags and bunny feet!

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/npm-publish-provenance

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

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request updates the package.json file to include the repository metadata for the cli-toolkit project. No review comments were provided, and there is no additional feedback.

@codecov

codecov Bot commented Jun 27, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@amondnet
amondnet merged commit cf508f1 into main Jun 27, 2026
5 of 7 checks passed
@amondnet
amondnet deleted the fix/npm-publish-provenance branch June 27, 2026 13:15
@greptile-apps

greptile-apps Bot commented Jun 27, 2026

Copy link
Copy Markdown

Greptile Summary

This PR fixes the broken npm publish step by replacing bun publish (which lacks OIDC provenance support and had auth issues) with bun pm pack + npm publish --provenance, and adds a workflow_dispatch trigger so the already-created v0.3.0 tag can be re-published manually.

  • Publish flow: Bun still handles install and build; the tarball is built with bun pm pack and published via npm publish ./*.tgz --provenance --access public using NODE_AUTH_TOKEN configured by actions/setup-node.
  • Provenance: Job-level id-token: write permission enables OIDC; actions/setup-node is SHA-pinned and sets up the .npmrc registry auth correctly. The repository field is added to package.json as required by --provenance.
  • Manual re-publish: A workflow_dispatch input (ref) lets the workflow check out any existing tag and publish it, bypassing the release-please output gate via the || condition.

Confidence Score: 3/5

The publish flow itself is correct, but the manual re-publish path can be silently skipped if the upstream release-please job fails, leaving the team with no indication that publish did not run.

The npm publish --provenance wiring is sound: correct env var, correct OIDC permission, correct glob. The fragility is in the workflow_dispatch path: because npm-publish depends on release-please without if: always(), a transient failure in the release-please job will silently skip the publish step. For a workflow specifically designed to unblock a stuck release, this silent-skip behaviour is the kind of defect that only surfaces at the worst possible moment.

.github/workflows/release-please.yml — the needs/if interaction on the npm-publish job needs attention before relying on the workflow_dispatch path in production.

Important Files Changed

Filename Overview
.github/workflows/release-please.yml Switches npm publish from bun publish to npm publish --provenance via a bun-built tarball; adds workflow_dispatch for manual re-publish. The needs dependency on release-please without if: always() means the manual re-publish path is silently skipped if release-please fails; action pinning is also inconsistent across the job steps.
package.json Adds the repository field required by npm publish --provenance; no functional changes to the package itself.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant GH as GitHub Event
    participant RP as release-please job
    participant NP as npm-publish job
    participant NPM as registry.npmjs.org
    participant OIDC as GitHub OIDC

    alt push to main
        GH->>RP: trigger (push)
        RP->>RP: create-github-app-token
        RP->>RP: release-please-action (may create release)
        RP-->>NP: "output: release_created=true"
        NP->>NP: checkout (github.ref)
        NP->>NP: setup-bun + setup-node (registry auth)
        NP->>NP: bun install + bun run build
        NP->>NP: bun pm pack to tgz
        NP->>OIDC: request OIDC token (id-token: write)
        OIDC-->>NP: OIDC token
        NP->>NPM: npm publish tgz --provenance
        NPM-->>NP: published with provenance attestation
    else "workflow_dispatch (ref=v0.3.0)"
        GH->>RP: trigger (dispatch)
        RP->>RP: release-please-action (no-op)
        RP-->>NP: "release_created='' (falsy)"
        Note over NP: github.event_name==workflow_dispatch is true
        NP->>NP: "checkout (github.event.inputs.ref = v0.3.0)"
        NP->>NP: setup-bun + setup-node
        NP->>NP: bun install + bun run build
        NP->>NP: bun pm pack to tgz
        NP->>OIDC: request OIDC token
        OIDC-->>NP: OIDC token
        NP->>NPM: npm publish tgz --provenance
        NPM-->>NP: published
    end
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant GH as GitHub Event
    participant RP as release-please job
    participant NP as npm-publish job
    participant NPM as registry.npmjs.org
    participant OIDC as GitHub OIDC

    alt push to main
        GH->>RP: trigger (push)
        RP->>RP: create-github-app-token
        RP->>RP: release-please-action (may create release)
        RP-->>NP: "output: release_created=true"
        NP->>NP: checkout (github.ref)
        NP->>NP: setup-bun + setup-node (registry auth)
        NP->>NP: bun install + bun run build
        NP->>NP: bun pm pack to tgz
        NP->>OIDC: request OIDC token (id-token: write)
        OIDC-->>NP: OIDC token
        NP->>NPM: npm publish tgz --provenance
        NPM-->>NP: published with provenance attestation
    else "workflow_dispatch (ref=v0.3.0)"
        GH->>RP: trigger (dispatch)
        RP->>RP: release-please-action (no-op)
        RP-->>NP: "release_created='' (falsy)"
        Note over NP: github.event_name==workflow_dispatch is true
        NP->>NP: "checkout (github.event.inputs.ref = v0.3.0)"
        NP->>NP: setup-bun + setup-node
        NP->>NP: bun install + bun run build
        NP->>NP: bun pm pack to tgz
        NP->>OIDC: request OIDC token
        OIDC-->>NP: OIDC token
        NP->>NPM: npm publish tgz --provenance
        NPM-->>NP: published
    end
Loading

Fix All in Claude Code

Prompt To Fix All With AI
Fix the following 2 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 2
.github/workflows/release-please.yml:37-40
**Manual re-publish silently skipped when `release-please` fails**

`npm-publish` uses `needs: release-please` without `if: always()`. If the `release-please` job exits with a failure (transient API error, GitHub App token scope issue, etc.), GitHub Actions skips — not fails — any downstream job, bypassing the `if` condition entirely. On a `workflow_dispatch` run this means the whole manual re-publish path silently does nothing, which is exactly the scenario this PR is designed to unblock.

Adding `always()` to the condition guards against this:
```yaml
if: ${{ always() && (needs.release-please.outputs.release_created || github.event_name == 'workflow_dispatch') }}
```
This still correctly prevents a publish when a `push` run completes without creating a release (`release_created` is falsy and `event_name` is `push`).

### Issue 2 of 2
.github/workflows/release-please.yml:46-48
**Inconsistent action pinning**

`actions/setup-node` is pinned to a full commit SHA (good practice), but `actions/checkout@v4`, `oven-sh/setup-bun@v2`, and `actions/cache@v4` still use floating mutable tags. A compromised or accidentally force-pushed tag in any of those actions would run untrusted code in the same job that holds the `NPM_TOKEN` secret and the OIDC token. Pinning all actions to SHAs would make the supply-chain posture consistent.

Reviews (1): Last reviewed commit: "fix(ci): publish to npm with provenance ..." | Re-trigger Greptile

Comment on lines 37 to +40
npm-publish:
needs: release-please
if: ${{ needs.release-please.outputs.release_created }}
# Publish on a fresh release, or manually for a given tag via workflow_dispatch.
if: ${{ needs.release-please.outputs.release_created || github.event_name == 'workflow_dispatch' }}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Manual re-publish silently skipped when release-please fails

npm-publish uses needs: release-please without if: always(). If the release-please job exits with a failure (transient API error, GitHub App token scope issue, etc.), GitHub Actions skips — not fails — any downstream job, bypassing the if condition entirely. On a workflow_dispatch run this means the whole manual re-publish path silently does nothing, which is exactly the scenario this PR is designed to unblock.

Adding always() to the condition guards against this:

if: ${{ always() && (needs.release-please.outputs.release_created || github.event_name == 'workflow_dispatch') }}

This still correctly prevents a publish when a push run completes without creating a release (release_created is falsy and event_name is push).

Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/release-please.yml
Line: 37-40

Comment:
**Manual re-publish silently skipped when `release-please` fails**

`npm-publish` uses `needs: release-please` without `if: always()`. If the `release-please` job exits with a failure (transient API error, GitHub App token scope issue, etc.), GitHub Actions skips — not fails — any downstream job, bypassing the `if` condition entirely. On a `workflow_dispatch` run this means the whole manual re-publish path silently does nothing, which is exactly the scenario this PR is designed to unblock.

Adding `always()` to the condition guards against this:
```yaml
if: ${{ always() && (needs.release-please.outputs.release_created || github.event_name == 'workflow_dispatch') }}
```
This still correctly prevents a publish when a `push` run completes without creating a release (`release_created` is falsy and `event_name` is `push`).

How can I resolve this? If you propose a fix, please make it concise.

Fix in Claude Code

Comment on lines 46 to +48
- uses: actions/checkout@v4
with:
ref: ${{ github.event.inputs.ref || github.ref }}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Inconsistent action pinning

actions/setup-node is pinned to a full commit SHA (good practice), but actions/checkout@v4, oven-sh/setup-bun@v2, and actions/cache@v4 still use floating mutable tags. A compromised or accidentally force-pushed tag in any of those actions would run untrusted code in the same job that holds the NPM_TOKEN secret and the OIDC token. Pinning all actions to SHAs would make the supply-chain posture consistent.

Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/release-please.yml
Line: 46-48

Comment:
**Inconsistent action pinning**

`actions/setup-node` is pinned to a full commit SHA (good practice), but `actions/checkout@v4`, `oven-sh/setup-bun@v2`, and `actions/cache@v4` still use floating mutable tags. A compromised or accidentally force-pushed tag in any of those actions would run untrusted code in the same job that holds the `NPM_TOKEN` secret and the OIDC token. Pinning all actions to SHAs would make the supply-chain posture consistent.

How can I resolve this? If you propose a fix, please make it concise.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Fix in Claude Code

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