Skip to content

workflows: replace softprops/action-gh-release with gh CLI (main) - #20

Open
harshita-gupta wants to merge 3 commits into
mainfrom
harshitagupta/migrate-gh-release-upload-main
Open

workflows: replace softprops/action-gh-release with gh CLI (main)#20
harshita-gupta wants to merge 3 commits into
mainfrom
harshitagupta/migrate-gh-release-upload-main

Conversation

@harshita-gupta

@harshita-guptaharshita-gupta commented Apr 23, 2026

Copy link
Copy Markdown
Member

Summary

Supply-chain hardening: softprops/action-gh-release is a single-maintainer third-party action pinned to the mutable @v1 tag. If that account is compromised or the tag is re-pointed, every workflow depending on it runs whatever the new code does. Replacing it with the first-party gh CLI (pre-installed on GitHub-hosted runners, maintained by GitHub) removes that dependency from the release-upload path.

This is a follow-up to #18, which migrated build-node-packages.yml. It migrates the remaining three workflows that still used softprops/action-gh-release@v1 on main:

  • .github/workflows/build-node.yml
  • .github/workflows/build-node-fibers.yml
  • .github/workflows/build-node-openssl-fips.yml

After this PR: zero references to third-party release-upload actions on main.

Canary + downstream PRs

This is the canary PR. It must be merged and end-to-end validated before any of the downstream per-branch PRs:

branchPRfiles migrated
main (this PR)#20build-node, build-node-fibers, build-node-openssl-fips
v22.21.1#21build-node, build-node-fibers, build-node-openssl-fips, build-node-packages
v22.21.1-profiler#22build-node, build-node-fibers, build-node-openssl-fips, build-node-packages
v24.13.0#23build-node, build-node-fibers, build-node-packages
v20.18.3#24build-node, build-node-fibers, build-node-packages

Each downstream PR is draft and references this PR's validation requirement. They are not yet ready for review.

Validation steps to complete on this PR before unblocking #21#24

  • Merge this PR.
  • Manually trigger Build Node on main via workflow_dispatch. Both matrix arms (linux-x64, linux-arm64) succeed without a race failure on gh release create.
  • Verify the asset appears in the node-${NODE_VERSION}-release release and that the release title is node-${NODE_VERSION}-LATEST.
  • Verify the downstream Build Node-Packages (already on gh CLI from workflows: swap softprops for gh CLI, add CloudFront reachability check, remove --acl #18) succeeds end-to-end.
  • Manually trigger Build node-fibers with prebuilt Node via workflow_dispatch. Verify the fibers archive appears in the same release.
  • Manually trigger Build Node with options around OpenSSL dynamic linking and FIPS via workflow_dispatch (needs a BUILD_REF input). Verify the asset appears in node-${NODE_VERSION}-fips-static-release with title node-${NODE_VERSION}-fips-static-LATEST.
  • Byte-identity check: download one asset uploaded pre-merge via softprops and one uploaded post-merge via gh CLI; confirm sha256sum matches.
  • Concurrency smoke: the matrix runs linux-x64 and linux-arm64 in parallel — confirm no step fails when both try to create the release at the same time.

Once all of those pass, mark #21#24 ready for review and merge them in any order.

Replacement shape

Each softprops step becomes (shell-quoted, set -euo pipefail):

- name: Upload <...> archive to releaseenv:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}run: | set -euo pipefail TAG="node-${NODE_VERSION}-release" RELEASE_NAME="node-${NODE_VERSION}-LATEST" FILE="./artifacts/${NODE_ARCHIVE_LATEST}" if ! gh release view "$TAG" --repo "$REPO" >/dev/null 2>&1; then gh release create "$TAG" --title "$RELEASE_NAME" --notes "" --repo "$REPO" \ || gh release view "$TAG" --repo "$REPO" >/dev/null fi gh release upload "$TAG" "$FILE" --clobber --repo "$REPO" gh release edit "$TAG" --title "$RELEASE_NAME" --repo "$REPO"

Each job also picks up REPO: ${{ github.repository }} in its job-level env:, matching the pattern from #18.

Behavior deltas vs. softprops/action-gh-release@v1

Based on reading the source of both tools — softprops at the v1 tag SHA (de2c0eb8, src/main.ts + src/github.ts) and gh CLI at the installed v2.90.0 (pkg/cmd/release/{upload,create}/*.go).

#deltaclassnotes
1softprops creates-if-missing in one call; gh release upload requires release to existreplaceableadded view || create preamble
2softprops has internal 3× retry on create (comment says "presume a race with competing matrix runs"); gh release create has no retryreplaceablecreate || view idiom: the loser of the race falls through via view
3softprops always deletes-then-uploads on same-name conflict; gh release upload default errors, --clobber matches softpropsno-opwe pass --clobber
4softprops always sets name on upload (via updateRelease); gh release upload doesn't touch namepreserved via gh release edit --title after upload
5softprops updateRelease also resets body/draft/prerelease to existing values; gh release edit without those flags is a no-op for themno-opneither approach modifies body; both leave draft/prerelease false
6softprops glob-expands files:; gh release upload also glob-expands via GlobPathsno-opall call-sites pass a single explicit filename
7softprops logs warning on missing files (opt-in to fail); gh release upload fails on missing literal path via os.Statstricter, beneficialno action required
8tag auto-creation: both create lightweight tag from default-branch HEAD when missingno-opidentical
9retries on upload: softprops has Octokit throttling plugin (1 retry on rate-limit); gh release upload retries 3× on 5xx or network errorno-opgh is slightly more robust
10step outputs url, id, upload_url, assets are not set by run: blocksno-opno consumers of these outputs anywhere in the repo
11auth: softprops uses GITHUB_TOKEN; gh accepts either GH_TOKEN or GITHUB_TOKENno-opwe keep GITHUB_TOKEN for consistency with #18

Out of scope

Supply-chain hardening: softprops/action-gh-release is a single-maintainer
third-party action pinned to the mutable @v1 tag. Replacing it with the
first-party `gh` CLI (pre-installed on GitHub-hosted runners, maintained by
GitHub) removes that dependency from the release-upload path.
Follow-up to #18, which migrated build-node-packages.yml. This migrates the
remaining three workflows that still used the action:
- build-node.yml
- build-node-fibers.yml
- build-node-openssl-fips.yml
Each Upload step becomes:
- view-or-create guard so the first matrix arm creates the release (and
the second arm tolerates the race);
- `gh release upload --clobber` for the asset (matches softprops's
always-delete-then-upload behavior on name collision);
- `gh release edit --title` to preserve softprops's behavior of always
re-setting the release name on every upload.
Each job also picks up `REPO: ${{ github.repository }}` in its env block
for consistency with the pattern established in #18.
The previous comment blocks were framed as migration notes ("instead of
softprops..."). Rewrite them as forward-looking descriptions of what each
step does and the decisions/pitfalls that matter to a future maintainer:
matrix-race behavior, --clobber tradeoff, deterministic-title reasoning.

@skeggseskeggse left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

tyyy

Comment thread.github/workflows/build-node.yml Outdated
Co-authored-by: Eli Skeggs <1348991+skeggse@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@harshita-gupta@skeggse@JackStrohm-asana