Skip to content

fix(verify-npm-provenance): write outputs in heredoc form (#4) - #5

Merged
asafgolombek merged 1 commit into
mainfrom
dev/asafgolombek/provenance-output-heredoc
Jul 22, 2026
Merged

fix(verify-npm-provenance): write outputs in heredoc form (#4)#5
asafgolombek merged 1 commit into
mainfrom
dev/asafgolombek/provenance-output-heredoc

Conversation

@asafgolombek

Copy link
Copy Markdown
Contributor

Closes #4.

detail is not a fixed vocabulary — it is built from registry-supplied data (the DSSE repository field among others). With the plain key=value form, a newline in that value emitted a second status= line into $GITHUB_OUTPUT, and GitHub resolves duplicate keys last-wins — so a source-mismatch could be read downstream as ok.

Low severity, as filed: it needs an attacker who already controls the registry response, and gate mode still fails because the exit code is computed in-process and never round-trips through $GITHUB_OUTPUT. The realistic impact is a false-healthy row in monitor mode (the Nimbus weekly secret-health run). Worth fixing regardless — this action exists so that its verdict can be trusted.

Change

renderOutputs() is exported and emits the heredoc-delimiter form with a random per-call delimiter, so a value can never close its own block and therefore can never start a line the runner would parse as a key assignment.

Tests

The new tests parse the rendered output the way the runner does (a key<<DELIM block is literal data until a line equal to DELIM; later keys win) and assert the real verdict survives an injected status=ok. My first attempt asserted on raw line counts and was wrong — the injected text does appear, correctly, as data inside the detail block.

Red-proved: reverting renderOutputs to key=value fails the new test (3 failures); restoring it gives 29/29.

Run with CI'''s glob form — node --test "actions/**/test/*.test.js" — since a bare directory arg is MODULE_NOT_FOUND on Node 24.

🤖 Generated with Claude Code

`detail` is not a fixed vocabulary — it is built from registry-supplied data
(the DSSE `repository` field among others). With the plain `key=value` form a
newline in that value emitted a second `status=` line into $GITHUB_OUTPUT, and
GitHub resolves duplicate keys last-wins, so a `source-mismatch` could be read
downstream as `ok`.

Low severity as filed: it needs an attacker who already controls the registry
response, and `gate` mode still fails because the exit code is computed
in-process and never round-trips through $GITHUB_OUTPUT. The realistic impact
is a false-healthy row in `monitor` mode (the Nimbus weekly secret-health run).
Worth fixing regardless — this action exists so its verdict can be trusted.

renderOutputs() is exported and uses a random per-call delimiter, so a value can
never close its own block. Tests parse the result the way the runner does
(heredoc blocks are literal data, later keys win) and assert the real verdict
survives an injected `status=ok`. Red-proved: reverting to `key=value` fails
the new test. 29/29 green via CI'\''s glob form.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 59 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6cdbe718-24cd-4a95-808e-69330e13c948

📥 Commits

Reviewing files that changed from the base of the PR and between 5fb4279 and f85d29c.

📒 Files selected for processing (2)
  • actions/verify-npm-provenance/src/main.js
  • actions/verify-npm-provenance/test/main.test.js
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch dev/asafgolombek/provenance-output-heredoc

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

@sonarqubecloud

Copy link
Copy Markdown

@asafgolombek
asafgolombek merged commit d26c5f2 into main Jul 22, 2026
3 checks passed
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.

verify-npm-provenance: use heredoc form for GITHUB_OUTPUT (detail is registry-derived)

1 participant