Skip to content

feat(npm-pr-version): add tarball support#45

Merged
codfish merged 2 commits into
mainfrom
feat/tarballs
Feb 7, 2026
Merged

feat(npm-pr-version): add tarball support#45
codfish merged 2 commits into
mainfrom
feat/tarballs

Conversation

@codfish
Copy link
Copy Markdown
Owner

@codfish codfish commented Feb 7, 2026

Note

Medium Risk
Changes the npm-pr-version publishing path and adds new tarball-based behavior that affects how packages are built/versioned/published; mistakes could break PR publishing or alter what gets released, though the change is scoped and includes new integration tests.

Overview
Adds a new tarball input to npm-pr-version to publish a pre-built *.tgz via npm publish ... --ignore-scripts, extracting name/version from the tarball and bypassing package.json version mutation when enabled.

Updates docs to recommend a two-job pull_request_target workflow (build untrusted code → npm/pnpm pack artifact → publish from trusted base) and expands security guidance around lifecycle-script credential exfiltration; also adjusts doc generation to prefer yml code fences and adds Bats integration tests plus a refute_output_contains helper.

Written by Cursor Bugbot for commit 3048dc9. Configure here.

Summary by CodeRabbit

  • New Features

    • Optional tarball-based publishing mode with secure handling and --ignore-scripts behavior; action emits package-name, version, and error-message outputs.
  • Documentation

    • Expanded secure two-job workflow examples with explicit permissions and tarball flow; added detailed security guidance and updated code-block language hints (yaml→yml).
  • Tests

    • Added comprehensive integration tests for tarball mode and a test helper for negative-output assertions.
  • Style

    • Replaced Prettier guards with ESLint disable/enable markers in docs.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 7, 2026

📝 Walkthrough

Walkthrough

Adds a tarball publishing mode to npm-publish-pr that validates and extracts package metadata from a tarball, publishes using secure flags (e.g., --ignore-scripts, --provenance), expands documentation and workflows to a two-job artifact pattern, updates code fence language hints, and adds integration tests and helpers.

Changes

Cohort / File(s) Summary
Core Action Implementation
npm-publish-pr/action.yml
Adds optional tarball input and tarball_mode flow: resolves/validates tarball globs, extracts package.json to obtain package-name and version, publishes tarball with --ignore-scripts (and --provenance for OIDC), exposes INPUT_TARBALL and tarball_mode, and centralizes error handling/outputs.
Documentation & Examples
README.md, SECURITY.md, npm-publish-pr/README.md, comment/README.md, setup-node-and-install/README.md, CONTRIBUTING.md, AGENT.md
Expanded security guidance and examples to show a two-job build→publish artifact workflow, added tarball-mode docs and warnings, moved/nested permissions into publish job examples, changed many code-fence language hints from yamlyml, and updated wording and troubleshooting.
Generated Docs Script
bin/generate-docs.js
Switched YAML parser alias/usage and code-fence generation from yamlyml; updated regexes to detect and emit ```yml usage blocks.
Tests & Test Helpers
tests/integration/npm-pr-version/tarball.bats, tests/scripts/test-helpers.sh
Adds comprehensive tarball-mode integration tests (detection, extraction, errors, scoped packages, glob resolution, OIDC vs token paths, --ignore-scripts, secure temp handling) and a new refute_output_contains() test helper for negative assertions.
Minor Presentational Edits
AGENT.md, CONTRIBUTING.md, comment/README.md, setup-node-and-install/README.md
Replaced prettier guard markers with eslint-disable/eslint-enable, adjusted code-fence languages and small TOC/content edits (presentational only).

Sequence Diagram(s)

sequenceDiagram
    participant Workflow as "GitHub Workflow"
    participant BuildJob as "build-and-test Job"
    participant Artifacts as "GitHub Artifacts"
    participant PublishJob as "publish Job"
    participant Action as "npm-publish-pr Action"
    participant Registry as "npm Registry"

    Workflow->>BuildJob: trigger (pull_request / workflow_run)
    BuildJob->>BuildJob: build & pack (create tarball)
    BuildJob->>Artifacts: upload tarball artifact

    Workflow->>PublishJob: triggered after build job
    PublishJob->>Artifacts: download tarball artifact
    PublishJob->>Action: run with `tarball` input

    Action->>Action: resolve & validate tarball path(s)
    Action->>Action: extract package.json → derive name & version
    Action->>Registry: npm publish (--ignore-scripts [--provenance])
    Registry-->>Action: publish result
    Action-->>PublishJob: set outputs (`package-name`, `version`, `error-message`)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰 I wrapped the package snug and tight,
No scripts will run on the publish night,
From build to artifact, I hop and send,
A tarball trail to a careful end. 🥕📦

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(npm-pr-version): add tarball support' directly and accurately reflects the main objective of the PR—adding tarball input support to npm-pr-version for secure tarball-based publishing.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/tarballs

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Feb 7, 2026

🚀 Integration Test Results

npm-pr-version action test:

  • ✅ Version generation: 0.0.0-PR-45--d2a4507
  • ✅ package.json update: Successful
  • ✅ Format validation: Passed

The action is working correctly! 🎉

@codfish codfish marked this pull request as ready for review February 7, 2026 18:32
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Feb 7, 2026

🧪 Test Results

✅ All tests passed successfully!

  • Linting: ✅ Passed
  • Unit tests: ✅ Passed
  • Integration tests: ✅ Passed

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Feb 7, 2026

Claude finished @codfish's task in 3m 8s —— View job


Comprehensive Code Review Complete ✅

I've completed a thorough review of the tarball support feature. This is a valuable security enhancement that addresses real risks in pull_request_target workflows.


Summary

Overall Assessment:Approve with Minor Fixes Required

This PR adds important security functionality with solid documentation and test coverage. The implementation is sound, but there are a few security and code quality issues that should be addressed before merging.


🔒 Security Review

Critical Issues

  1. TOCTOU Vulnerability (npm-publish-pr/action.yml:112) ⚠️

    • Using fixed path /tmp/package.json.tarball creates race condition
    • Should use mktemp for unique temporary files
    • See inline comment for fix
  2. Missing Temporary File Cleanup (npm-publish-pr/action.yml:122) ⚠️

    • Temporary file never cleaned up → information disclosure risk
    • Should add trap or explicit cleanup
    • See inline comment for implementation
  3. OIDC Token Exposure Clarification (npm-publish-pr/action.yml:230) ℹ️

    • Documentation should emphasize that OIDC secrets must be isolated during build phase, not just publish
    • Current SECURITY.md example is correct but could be clearer

Positive Security Aspects ✅

  • Excellent use of --ignore-scripts to prevent lifecycle script execution
  • Comprehensive security documentation with realistic attack scenarios
  • Well-designed two-job workflow pattern to isolate secrets
  • Good awareness of both token-based and OIDC attack vectors

🧪 Testing Review

Test Coverage: Good ✅

The new tarball.bats file adds 11 comprehensive test cases covering:

  • ✅ Tarball mode detection
  • ✅ Package extraction from tarballs
  • ✅ Version extraction
  • ✅ Error handling for missing files
  • --ignore-scripts flag verification
  • ✅ OIDC with --provenance
  • ✅ Scoped packages
  • ✅ Backward compatibility

Test Quality Issues

  1. Tests only verify command construction, not execution (tarball.bats:112) ℹ️

    • Tests don't actually run npm publish with tarballs
    • Consider adding at least one end-to-end test
    • See inline comment
  2. Missing glob pattern test (tarball.bats:47) ℹ️

    • Documentation shows tarball: '*.tgz' but glob expansion isn't tested
    • Unclear if globs are supported or require explicit expansion

📚 Documentation Review

Excellent Documentation ✅

  • Clear migration guide from token to OIDC
  • Comprehensive security considerations
  • Multiple usage examples for different scenarios
  • Updated main README with new input

Documentation Issues

  1. Markdown Formatting Errors (SECURITY.md:186, 192, 236) 🐛
    • Multiple code blocks have malformed closing fences ( ```json / ```yaml as text instead of fence closers)
    • This will cause rendering issues on GitHub
    • See inline comments with suggestions for fixes

💻 Code Quality Review

Implementation: Very Good ✅

Strengths:

  • Clean separation of tarball vs normal mode
  • Consistent error handling with detailed messages
  • Good validation of inputs
  • Proper output variable handling
  • Cross-platform compatibility (BSD tar note)

Code Quality Suggestions

  1. Script Length (action.yml:62) ℹ️

    • The bash script is now 320 lines
    • Consider extracting functions for better maintainability
    • Not critical but worth considering for future refactoring
    • See inline comment
  2. Follows Repository Guidelines

    • Uses file descriptors in generate-docs.js per AGENT.md security guidelines
    • Proper error handling throughout
    • Consistent with existing patterns

📊 Specific Findings by Category

1. Code Quality ✅

  • Architecture: Clean implementation with good separation of concerns
  • Readability: Well-commented with clear variable names
  • Error Handling: Comprehensive with informative messages
  • Maintainability: Could benefit from function extraction but acceptable

2. Security ⚠️

  • Input Validation: ✅ Excellent (tarball existence, JSON validation)
  • Temp File Handling: ⚠️ Needs fix (TOCTOU + no cleanup)
  • Script Execution Prevention: ✅ Excellent (--ignore-scripts)
  • Documentation: ✅ Outstanding security awareness

3. Performance ✅

  • Efficiency: No obvious bottlenecks
  • Resource Management: Could improve temp file cleanup

4. Testing ✅

  • Coverage: Good (11 new tests)
  • Quality: Tests are well-structured and clear
  • Gaps: Missing end-to-end tests and glob pattern tests

5. Documentation ✅

  • Completeness: Excellent coverage of use cases
  • Clarity: Very clear with good examples
  • Issues: 🐛 Markdown formatting needs fixing (see inline comments)

🔧 Required Changes

Before merging, please address:

  1. Fix temporary file handling (critical for security)

    • Use mktemp instead of fixed path
    • Add cleanup with trap
  2. Fix markdown code fence formatting in SECURITY.md (affects documentation rendering)

    • Lines 186, 192, 236 and similar
    • See inline comments with suggestions

💡 Recommended Improvements (Optional)

These would be nice to have but not blocking:

  1. Add at least one end-to-end integration test
  2. Clarify glob pattern support in tarball input
  3. Extract bash functions for better maintainability
  4. Emphasize in docs that build phase must also be secure (not just publish)

✨ Positive Highlights

  • Security First: Excellent security-focused design and documentation
  • User Experience: Great migration guide and multiple usage examples
  • Backward Compatible: Doesn't break existing workflows
  • Well Tested: Comprehensive test coverage for new functionality
  • Clear Intent: Feature solves a real security problem effectively

🎯 Recommendation

APPROVE with fixes required for:

  1. Temporary file security issue
  2. Markdown formatting in docs

Once these are addressed, this is ready to merge! Great work on addressing a real security concern with thoughtful implementation. 🎉


Comment thread npm-publish-pr/action.yml Outdated
Comment thread npm-publish-pr/action.yml Outdated
Comment thread npm-publish-pr/action.yml
Comment thread npm-publish-pr/action.yml
Comment thread tests/integration/npm-pr-version/tarball.bats Outdated
Comment thread tests/integration/npm-pr-version/tarball.bats
Comment thread SECURITY.md
Comment thread SECURITY.md Outdated
Comment thread SECURITY.md Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
SECURITY.md (1)

77-86: ⚠️ Potential issue | 🔴 Critical

Broken markdown fences render most of the document as a single code block.

Line 77 opens a 4-backtick fence (````yaml), but line 86 uses only 3 backticks (```yaml) which cannot close a 4-backtick fence. The only matching 4-backtick close is line 277, so everything from line 78 to line 276 renders as one giant code block in GitHub's markdown renderer.

Additionally, closing fences should not have a language hint — ```yaml on a closing fence is invalid markdown and will be treated as content or a new opening fence depending on context.

The same closing-fence-with-language-hint pattern repeats at lines 99, 116, 186, 195, and 236.

Proposed fix — use consistent 3-backtick fences with plain closers
-````yaml
+```yaml
 # ✅ Good - Using secrets properly
 - uses: codfish/actions/npm-pr-version@v3
   with:
     npm-token: ${{ secrets.NPM_TOKEN }}

 # ❌ Bad - Exposing secrets
 - name: Debug
   run: echo "Token: ${{ secrets.NPM_TOKEN }}"
-```yaml
+```

Apply the same fix at every closing fence (lines 99, 116, 186, 195, 236) — remove the language hint from the closing ```. And change line 277 from ```` back to a regular document-end (or remove it if nothing needs closing).

🤖 Fix all issues with AI agents
In `@npm-publish-pr/action.yml`:
- Around line 99-106: The tarball glob from the tarball input is never expanded
because the script treats INPUT_TARBALL as a literal (used as "$INPUT_TARBALL"
in the tarball_mode branch and in the existence check [ ! -f "$INPUT_TARBALL"
]); resolve the glob immediately after tarball_mode is detected by expanding
INPUT_TARBALL into a concrete filename (for example enable globbing/nullglob,
expand the pattern and set INPUT_TARBALL to the first match) before running the
file-exists check and the rest of the logic so subsequent uses of
"$INPUT_TARBALL" are safe and refer to a real file.

In `@npm-publish-pr/README.md`:
- Line 252: Replace the incorrect lockfile name `pnpm-lock.yml` with the correct
`pnpm-lock.yaml` in the README entry (the line showing "`pnpm-lock.yml` →
pnpm"); ensure the README text matches the action's check (action.yml uses
`pnpm-lock.yaml`) so both references are consistent.

In `@README.md`:
- Line 6: Replace the doctoc block wrappers that currently use "<!--
eslint-disable -->" / "<!-- eslint-enable -->" with Prettier ignore markers:
wrap the entire doctoc TOC section using "<!-- prettier-ignore-start -->" before
the block and "<!-- prettier-ignore-end -->" after it (ensure you update both
occurrences noted around the block, e.g., the markers currently at lines around
the top and the one at 22), so Prettier will skip formatting the
doctoc-generated TOC instead of disabling ESLint.

In `@SECURITY.md`:
- Around line 180-195: Two JSON example blocks showing malicious
"prepublishOnly" scripts use incorrect closing fences: the blocks start with
"```json" but are improperly closed with "```json" which opens new blocks;
locate the two example code blocks containing the "scripts": { "prepublishOnly":
... } JSON (the block that references $NPM_TOKEN and the block that references
$ACTIONS_ID_TOKEN_REQUEST_URL/$ACTIONS_ID_TOKEN_REQUEST_TOKEN) and replace their
closing fences from ```json to plain ``` so each JSON block is properly closed.
- Line 238: In SECURITY.md update the broken link: decide whether it should
point to npm-pr-version/README.md or npm-publish-pr/README.md (the diff
currently uses ./npm-publish-pr/README.md but the text says
npm-pr-version/README.md), then change the URL to the correct README and either
add or correct the anchor (replace or create the fragment matching the actual
heading name instead of `#security-considerations`) or remove the fragment
entirely so the link resolves; ensure the link text and target file
(npm-pr-version/README.md or npm-publish-pr/README.md) match and that the
referenced heading exists.
🧹 Nitpick comments (4)
tests/integration/npm-pr-version/tarball.bats (2)

16-32: Tests re-implement action logic inline rather than testing the actual action script.

These tests validate the pattern of tarball mode detection by reimplementing the logic in bash -c blocks, but they don't exercise the actual shell code from npm-publish-pr/action.yml. If the action's implementation drifts from these patterns, the tests will still pass while the action is broken. Consider extracting shared logic into a sourced script that both the action and tests use, or at minimum add a comment clarifying these are "logic pattern" tests, not integration tests of the action itself.


47-47: Hardcoded /tmp/package.json.test path could collide across parallel test runs.

Multiple tests write to /tmp/package.json.test. While BATS defaults to sequential execution, using mktemp would be more robust and consistent with the $TEST_DIR pattern already in setup().

Example fix (apply similarly to all occurrences)
-        tar -xzf "$INPUT_TARBALL" -O package/package.json > /tmp/package.json.test 2>/dev/null
+        tmpfile=$(mktemp)
+        tar -xzf "$INPUT_TARBALL" -O package/package.json > "$tmpfile" 2>/dev/null
 
-        if [ -s /tmp/package.json.test ]; then
-            package_name=$(jq -r ".name // empty" /tmp/package.json.test)
+        if [ -s "$tmpfile" ]; then
+            package_name=$(jq -r ".name // empty" "$tmpfile")
             echo "package-name=$package_name"
         else
             echo "error=Could not extract package.json"
         fi
 
-        rm -f /tmp/package.json.test
+        rm -f "$tmpfile"

Also applies to: 75-75, 112-112, 199-199, 223-223

npm-publish-pr/action.yml (2)

110-119: Temporary file /tmp/package.json.tarball is never cleaned up.

The extracted file is written to /tmp/package.json.tarball but never removed after use. Consider adding rm -f /tmp/package.json.tarball after extracting the needed values (after line 137).


185-201: Package manager detection runs in tarball mode but the result is unused.

When tarball_mode=true, the publish path (lines 224-246) always uses npm regardless of the detected package_manager. The detection block at lines 192-201 still runs and logs "Detected package manager: yarn/pnpm", which would be misleading. Consider skipping detection in tarball mode or logging that tarball mode forces npm.

Proposed fix
       if [ "$INPUT_NPM_TOKEN" ]; then
         echo "🔐 Using token-based authentication"

         # Token mode: set NODE_AUTH_TOKEN so publishing works
         export NODE_AUTH_TOKEN="$INPUT_NPM_TOKEN"

-        # Detect package manager for token-based publishing
-        if [ -f "./yarn.lock" ]; then
-          package_manager="yarn"
-          echo "📦 Detected package manager: yarn"
-        elif [ -f "./pnpm-lock.yaml" ]; then
-          package_manager="pnpm"
-          echo "📦 Detected package manager: pnpm"
-        else
-          package_manager="npm"
-          echo "📦 Detected package manager: npm"
-        fi
+        if [ "$tarball_mode" = true ]; then
+          echo "📦 Using npm for tarball publishing (tarball mode always uses npm)"
+        else
+          # Detect package manager for token-based publishing
+          if [ -f "./yarn.lock" ]; then
+            package_manager="yarn"
+            echo "📦 Detected package manager: yarn"
+          elif [ -f "./pnpm-lock.yaml" ]; then
+            package_manager="pnpm"
+            echo "📦 Detected package manager: pnpm"
+          else
+            package_manager="npm"
+            echo "📦 Detected package manager: npm"
+          fi
+        fi
       fi

Comment thread npm-publish-pr/action.yml
Comment thread npm-publish-pr/README.md Outdated
Comment thread README.md
Comment thread SECURITY.md Outdated
Comment thread SECURITY.md Outdated
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 3 potential issues.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

This PR is being reviewed by Cursor Bugbot

Details

You are on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle.

To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

Comment thread npm-publish-pr/action.yml
Comment thread bin/generate-docs.js
Comment thread npm-publish-pr/action.yml
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In `@CONTRIBUTING.md`:
- Line 5: The doctoc TOC currently uses <!-- eslint-disable -->/<!--
eslint-enable --> which removed the Prettier guard; update the doctoc block to
include <!-- prettier-ignore-start --> and <!-- prettier-ignore-end --> around
the TOC and, if ESLint disabling is still required, stack the markers so both
appear (e.g., place <!-- prettier-ignore-start --> before <!-- eslint-disable
--> and <!-- prettier-ignore-end --> after <!-- eslint-enable -->) ensuring the
TOC is wrapped by the prettier-ignore markers while preserving any
eslint-disable lines.

In `@npm-publish-pr/action.yml`:
- Around line 66-69: The current unquoted glob expansion
tarball_files=($INPUT_TARBALL) will split filenames on spaces; change the logic
that builds tarball_files to use a safe glob expansion (e.g., use compgen -G
"$INPUT_TARBALL" or a loop that reads compgen output and appends each match as a
single quoted element) so filenames containing spaces are preserved, keeping the
surrounding shopt -s nullglob / shopt -u nullglob lines intact and ensuring each
entry in the tarball_files array is a single properly quoted filename.

In `@tests/integration/npm-pr-version/tarball.bats`:
- Around line 245-287: The test "npm-pr-version: tarball mode uses secure
temporary files (mktemp)" is fragile because the mktemp path regex and hardcoded
"permissions=600" assertion assume specific platforms; update the test to stop
asserting a specific TMPDIR pattern and exact permissions: in the subshell that
sets temp_file_path, keep the mktemp invocation and checks that produce
"mktemp-created=true" and "file-exists=true" but remove or relax the regex match
for temp file path and drop the strict "permissions=600" assertion; instead
assert only that the temp file was created and that the trap removed it (retain
the "trap-cleanup=true" check), or optionally gate the strict checks behind a
platform detection (e.g., check uname and only assert permissions on Linux/macOS
where known). Reference symbols: the test name, the temp_file_path variable, the
emitted markers "mktemp-created=true", "file-exists=true", "permissions=600",
and "trap-cleanup=true".
🧹 Nitpick comments (3)
tests/integration/npm-pr-version/tarball.bats (1)

16-32: Tests re-implement action logic inline rather than exercising the actual action code.

All tests in this file replicate shell snippets from action.yml instead of sourcing/invoking the real action script. If the action's logic diverges from these copies, the tests will still pass while the action is broken. Consider extracting the core tarball logic into a sourceable shell script that both the action and tests can share, or at minimum add a comment acknowledging this is intentional (testing the pattern, not the implementation).

This is fine for an initial PR — just flagging the drift risk.

npm-publish-pr/README.md (1)

218-226: The tarball input is documented in the table but has no usage example in this README.

The inputs table correctly lists the tarball input, and SECURITY.md has the two-job workflow example. However, users looking for how to use this action's tarball mode would naturally look here first. Consider adding a "Tarball Mode (Secure)" usage section alongside the existing OIDC and Token examples — even a brief one that references SECURITY.md for the full workflow.

SECURITY.md (1)

173-176: Nit: "Open Source" as a compound adjective modifying "Projects" could be hyphenated.

Per the static analysis hint, "open source project" used as a compound adjective before a noun is conventionally hyphenated: "open-source project" (line 175) and "Open-Source Projects" (line 173 heading).

Comment thread CONTRIBUTING.md
Comment thread npm-publish-pr/action.yml
Comment thread tests/integration/npm-pr-version/tarball.bats
@codfish codfish merged commit adea81b into main Feb 7, 2026
16 of 17 checks passed
@codfish codfish deleted the feat/tarballs branch February 7, 2026 20:16
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 Fix all issues with AI agents
In `@npm-publish-pr/action.yml`:
- Around line 118-166: Tarball mode currently reads version from the archive
(variables package_name/version) and publishes that unmodified; change it to
produce the PR-specific version like normal mode by computing the PR version
(e.g., "0.0.0-PR-{number}--{short-sha}") and applying it to the extracted
package.json before publishing: after extracting to temp_pkg_json update its
"version" field to the computed pr_version (or regenerate/rewrap the tarball
with the modified package.json), then set version=$pr_version and write
"version=$version" to GITHUB_OUTPUT; alternatively, if you prefer option B/C
implement a validation branch that checks extracted version matches the
0.0.0-PR-* pattern (using package_name/version) and fails with a clear error if
not, but do not leave the action publishing the original tarball version.

In `@npm-publish-pr/README.md`:
- Around line 129-168: The README's Tarball Mode example doesn't show
PR-specific versioning and thus will pack the original package.json version;
update the docs to either state explicitly that tarball mode uses the tarball's
existing package.json version (i.e., it does NOT auto-generate PR-specific
versions) or add a step in the build job before running npm pack that sets a
PR-specific version (e.g., run npm version with --no-git-tag-version using
GitHub variables) so the tarball contains the expected 0.0.0-PR-... format;
reference the build job steps (npm pack) and the publish step using
codfish/actions/npm-pr-version@v3 with tarball to make clear which behavior
applies.
- Around line 154-168: The publish job requires npm >=11.5.1 for OIDC but
doesn't upgrade npm; add a step in the "publish" job (before the
codfish/actions/npm-pr-version@v3 step and after the download-artifact step)
that upgrades/activates npm 11.5.1+, e.g. run Corepack to prepare/activate npm
11.5.1 (corepack enable && corepack prepare npm@11.5.1 --activate) or otherwise
install npm@11.5.1 globally so the npm-pr-version action
(codfish/actions/npm-pr-version@v3) can use OIDC successfully.

In `@SECURITY.md`:
- Around line 241-256: The publish job currently uses id-token: write for OIDC
but misses the setup step that ensures a new enough npm; add a step calling
setup-node-and-install@v3 (or the project's equivalent setup action) immediately
before the codfish/actions/npm-pr-version@v3 step in the publish job so npm is
upgraded to ^11.5.1 and OIDC publishing will succeed; ensure the step targets
the desired node version (e.g., node-version input) and appears before the uses:
codfish/actions/npm-pr-version@v3 entry.
🧹 Nitpick comments (3)
SECURITY.md (1)

173-176: Nit: "open source" → "open-source" when used as a compound adjective.

Static analysis flags "open source project" — hyphenate when it modifies a noun.

-If you're an **open source project** using `pull_request_target` to publish PR packages from external contributors,
+If you're an **open-source project** using `pull_request_target` to publish PR packages from external contributors,
npm-publish-pr/action.yml (2)

74-74: Quote $GITHUB_OUTPUT for robustness.

Throughout the script, $GITHUB_OUTPUT is used unquoted in >> $GITHUB_OUTPUT. While GitHub controls this path, quoting is a shell best practice to guard against paths with spaces.

Example fix (apply throughout)
-echo "error-message=$error_message" >> $GITHUB_OUTPUT
+echo "error-message=$error_message" >> "$GITHUB_OUTPUT"

249-271: Tarball mode always uses npm even when token-based auth with yarn/pnpm is detected.

Lines 263–264 have a comment "Token mode with tarball - always use npm for tarball publishing", but this isn't explained to the user. If someone uses pnpm and provides an npm-token, they might expect pnpm to be used. Consider adding a log message explaining why npm is used (e.g., pnpm/yarn don't support publishing pre-built tarballs the same way), or documenting this in the README.

Comment thread npm-publish-pr/action.yml
Comment on lines +118 to +166
# In tarball mode, extract package info from tarball
# In normal mode, validate package.json
if [ "$tarball_mode" = true ]; then
# Validate tarball exists
if [ ! -f "$INPUT_TARBALL" ]; then
error_message="❌ ERROR: Tarball not found at path: $INPUT_TARBALL"
echo "$error_message"
echo "error-message=$error_message" >> $GITHUB_OUTPUT
exit 1
fi

# Validate package.json is valid JSON
if ! jq empty package.json 2>/dev/null; then
error_message="❌ ERROR: package.json is not valid JSON"
echo "$error_message"
echo "error-message=$(extract_error "$error_message")" >> $GITHUB_OUTPUT
exit 1
fi
echo "📦 Extracting package info from tarball: $INPUT_TARBALL"

# Check if package has a name
package_name=$(jq -r '.name // empty' package.json)
if [ -z "$package_name" ] || [ "$package_name" = "null" ]; then
error_message="❌ ERROR: package.json must have a 'name' field"
echo "$error_message"
echo "error-message=$(extract_error "$error_message")" >> $GITHUB_OUTPUT
exit 1
fi
# Create secure temporary file with proper permissions
temp_pkg_json=$(mktemp)
trap 'rm -f "$temp_pkg_json"' EXIT

# Extract package.json from tarball to get name and version
# Note: Use -O without --wildcards for BSD tar (macOS) compatibility
tar -xzf "$INPUT_TARBALL" -O package/package.json > "$temp_pkg_json" 2>/dev/null

# Output package name for use in error handling
echo "package-name=$package_name" >> $GITHUB_OUTPUT
if [ ! -s "$temp_pkg_json" ]; then
error_message="❌ ERROR: Could not extract package.json from tarball"
echo "$error_message"
echo "error-message=$error_message" >> $GITHUB_OUTPUT
exit 1
fi

# Get package name from tarball
package_name=$(jq -r '.name // empty' "$temp_pkg_json")
if [ -z "$package_name" ] || [ "$package_name" = "null" ]; then
error_message="❌ ERROR: Tarball's package.json must have a 'name' field"
echo "$error_message"
echo "error-message=$error_message" >> $GITHUB_OUTPUT
exit 1
fi

# Get version from tarball
version=$(jq -r '.version // empty' "$temp_pkg_json")
if [ -z "$version" ] || [ "$version" = "null" ]; then
error_message="❌ ERROR: Tarball's package.json must have a 'version' field"
echo "$error_message"
echo "error-message=$error_message" >> $GITHUB_OUTPUT
exit 1
fi

echo "📦 Tarball package: $package_name@$version"
echo "package-name=$package_name" >> $GITHUB_OUTPUT
echo "version=$version" >> $GITHUB_OUTPUT
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Tarball mode publishes the tarball's original version, not a PR-specific version.

In normal mode, the action generates 0.0.0-PR-{number}--{short-sha} and mutates package.json. In tarball mode (lines 155–166), the version is extracted from the tarball as-is — no PR-specific version is generated.

This means if the tarball contains "version": "1.0.0", the action publishes 1.0.0 to the pr tag, which:

  1. Breaks the action's core promise of PR-specific versions (0.0.0-PR-…).
  2. Could overwrite a real published version (version immutability violation on npm).
  3. None of the workflow examples (SECURITY.md, README.md) show the user mutating the version before npm pack.

Consider either:

  • (A) Generating the PR version inside the action and re-packing/rewriting the tarball's package.json, or
  • (B) Requiring the user to pass the version pre-baked, and validating it matches the 0.0.0-PR-* pattern, or
  • (C) At minimum, clearly documenting that the user must set the version before npm pack, and adding a warning if the extracted version doesn't look like a PR version.
🤖 Prompt for AI Agents
In `@npm-publish-pr/action.yml` around lines 118 - 166, Tarball mode currently
reads version from the archive (variables package_name/version) and publishes
that unmodified; change it to produce the PR-specific version like normal mode
by computing the PR version (e.g., "0.0.0-PR-{number}--{short-sha}") and
applying it to the extracted package.json before publishing: after extracting to
temp_pkg_json update its "version" field to the computed pr_version (or
regenerate/rewrap the tarball with the modified package.json), then set
version=$pr_version and write "version=$version" to GITHUB_OUTPUT;
alternatively, if you prefer option B/C implement a validation branch that
checks extracted version matches the 0.0.0-PR-* pattern (using
package_name/version) and fails with a clear error if not, but do not leave the
action publishing the original tarball version.

Comment thread npm-publish-pr/README.md
Comment on lines +129 to +168
### Tarball Mode (Secure for pull_request_target)

For `pull_request_target` workflows, use tarball mode to prevent execution of malicious lifecycle scripts from untrusted
PRs:

```yml
on: pull_request_target

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
ref: ${{ github.event.pull_request.head.sha }}

- uses: codfish/actions/setup-node-and-install@v3
- run: npm run build
- run: npm pack

- uses: actions/upload-artifact@v4
with:
name: package-tarball
path: '*.tgz'

publish:
needs: build
runs-on: ubuntu-latest
permissions:
id-token: write
pull-requests: write
steps:
- uses: actions/download-artifact@v4
with:
name: package-tarball

- uses: codfish/actions/npm-pr-version@v3
with:
tarball: '*.tgz' # Publishes with --ignore-scripts
```
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Tarball mode examples don't show PR-specific version generation.

As noted in the action.yml review, tarball mode uses the version from the tarball's package.json as-is. The build job (lines 141–152) runs npm pack without first setting a PR-specific version, so the published package will have whatever version is in the source package.json (e.g., 1.0.0), not the expected 0.0.0-PR-123--abc1234 format.

If this is by design, the documentation should explicitly state that tarball mode does not generate PR-specific versions, and show how users should set the version before packing (e.g., npm version 0.0.0-PR-${{ github.event.number }}--... --no-git-tag-version).

🤖 Prompt for AI Agents
In `@npm-publish-pr/README.md` around lines 129 - 168, The README's Tarball Mode
example doesn't show PR-specific versioning and thus will pack the original
package.json version; update the docs to either state explicitly that tarball
mode uses the tarball's existing package.json version (i.e., it does NOT
auto-generate PR-specific versions) or add a step in the build job before
running npm pack that sets a PR-specific version (e.g., run npm version with
--no-git-tag-version using GitHub variables) so the tarball contains the
expected 0.0.0-PR-... format; reference the build job steps (npm pack) and the
publish step using codfish/actions/npm-pr-version@v3 with tarball to make clear
which behavior applies.

Comment thread npm-publish-pr/README.md
Comment on lines +154 to +168
publish:
needs: build
runs-on: ubuntu-latest
permissions:
id-token: write
pull-requests: write
steps:
- uses: actions/download-artifact@v4
with:
name: package-tarball

- uses: codfish/actions/npm-pr-version@v3
with:
tarball: '*.tgz' # Publishes with --ignore-scripts
```
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Tarball publish job needs npm 11.5.1+ for OIDC but has no upgrade step.

The publish job uses OIDC (id-token: write) which requires npm 11.5.1+. GitHub-hosted runners ship with an older npm. Without a checkout step, setup-node-and-install@v3 can't be used (it needs package.json).

Consider adding a manual npm upgrade:

Proposed fix
     steps:
       - uses: actions/download-artifact@v4
         with:
           name: package-tarball
 
+      - name: Upgrade npm for OIDC support
+        run: npm install -g npm@^11.5.1
+
       - uses: codfish/actions/npm-pr-version@v3
         with:
           tarball: '*.tgz' # Publishes with --ignore-scripts

Based on learnings: "The npm-pr-version action requires npm 11.5.1+ for OIDC (automatically provided by setup-node-and-install v3)".

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
publish:
needs: build
runs-on: ubuntu-latest
permissions:
id-token: write
pull-requests: write
steps:
- uses: actions/download-artifact@v4
with:
name: package-tarball
- uses: codfish/actions/npm-pr-version@v3
with:
tarball: '*.tgz' # Publishes with --ignore-scripts
```
publish:
needs: build
runs-on: ubuntu-latest
permissions:
id-token: write
pull-requests: write
steps:
- uses: actions/download-artifact@v4
with:
name: package-tarball
- name: Upgrade npm for OIDC support
run: npm install -g npm@^11.5.1
- uses: codfish/actions/npm-pr-version@v3
with:
tarball: '*.tgz' # Publishes with --ignore-scripts
🤖 Prompt for AI Agents
In `@npm-publish-pr/README.md` around lines 154 - 168, The publish job requires
npm >=11.5.1 for OIDC but doesn't upgrade npm; add a step in the "publish" job
(before the codfish/actions/npm-pr-version@v3 step and after the
download-artifact step) that upgrades/activates npm 11.5.1+, e.g. run Corepack
to prepare/activate npm 11.5.1 (corepack enable && corepack prepare npm@11.5.1
--activate) or otherwise install npm@11.5.1 globally so the npm-pr-version
action (codfish/actions/npm-pr-version@v3) can use OIDC successfully.

Comment thread SECURITY.md
Comment on lines +241 to +256
publish:
needs: build
# Publish with secrets and --ignore-scripts
permissions:
contents: read
id-token: write # For OIDC (or omit if using npm-token)
pull-requests: write # For commenting
steps:
- uses: actions/checkout@v6 # Trusted base branch
- uses: actions/download-artifact@v4
with:
name: package-tarball
- uses: codfish/actions/npm-pr-version@v3
with:
tarball: '*.tgz'
```
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Publish job example may need setup-node-and-install@v3 for OIDC.

The publish job uses id-token: write (OIDC), which requires npm 11.5.1+. GitHub-hosted runners ship with an older npm version. Without setup-node-and-install@v3 (which auto-upgrades npm to ^11.5.1), OIDC publishing will fail.

Consider adding the setup step before the publish step, consistent with the npm-publish-pr/README.md tarball example:

Proposed fix
     steps:
       - uses: actions/checkout@v6 # Trusted base branch
+      - uses: codfish/actions/setup-node-and-install@v3
       - uses: actions/download-artifact@v4
         with:
           name: package-tarball
       - uses: codfish/actions/npm-pr-version@v3
         with:
           tarball: '*.tgz'

Based on learnings: "The npm-pr-version action requires npm 11.5.1+ for OIDC (automatically provided by setup-node-and-install v3)".

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
publish:
needs: build
# Publish with secrets and --ignore-scripts
permissions:
contents: read
id-token: write # For OIDC (or omit if using npm-token)
pull-requests: write # For commenting
steps:
- uses: actions/checkout@v6 # Trusted base branch
- uses: actions/download-artifact@v4
with:
name: package-tarball
- uses: codfish/actions/npm-pr-version@v3
with:
tarball: '*.tgz'
```
publish:
needs: build
# Publish with secrets and --ignore-scripts
permissions:
contents: read
id-token: write # For OIDC (or omit if using npm-token)
pull-requests: write # For commenting
steps:
- uses: actions/checkout@v6 # Trusted base branch
- uses: codfish/actions/setup-node-and-install@v3
- uses: actions/download-artifact@v4
with:
name: package-tarball
- uses: codfish/actions/npm-pr-version@v3
with:
tarball: '*.tgz'
🤖 Prompt for AI Agents
In `@SECURITY.md` around lines 241 - 256, The publish job currently uses id-token:
write for OIDC but misses the setup step that ensures a new enough npm; add a
step calling setup-node-and-install@v3 (or the project's equivalent setup
action) immediately before the codfish/actions/npm-pr-version@v3 step in the
publish job so npm is upgraded to ^11.5.1 and OIDC publishing will succeed;
ensure the step targets the desired node version (e.g., node-version input) and
appears before the uses: codfish/actions/npm-pr-version@v3 entry.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Feb 8, 2026

🎉 This PR is included in version 3.2.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant