Skip to content

Replace the Node.js action with a composite action running a Bash script - #35

Merged
aneshlya merged 10 commits into
mainfrom
composite-switch
Oct 8, 2026
Merged

aneshlya merged 10 commits into
mainfrom
composite-switch

Conversation

@aneshlya

@aneshlya aneshlya commented Oct 7, 2026 •

Copy link
Copy Markdown
Collaborator

Rewrites the action as a composite action that runs one Bash script (install.sh), replacing the Node.js bundle. Inputs, behavior and log messages are unchanged for users of ispc/install-ispc-action@main.

Why

  • Fewer vulnerabilities to chase. The action only downloads and extracts one archive, yet it ships a bundled npm dependency tree (@actions/core, @actions/tool-cache, undici, esbuild). Recent history is mostly CVE bumps and rebuilds (undici overrides, esbuild and @actions/* upgrades). The shell version has no third-party code and only calls tools already on the runner (curl, tar, jq, git).
  • Lower maintenance cost. There's no build step, no committed build/main.cjs to keep in sync, no npm Dependabot churn, and no forced Node runtime migrations like node20 → node24. It also works on older and GHES runners without a recent Node runtime.
  • Easy to review and test. The logic is about 300 lines of shellcheck-clean Bash that can be run locally with INPUT_VERSION=1.23.0 bash install.sh.

Changes

  • install.sh: a port of src/main.js with the same version, platform and arch resolution, URLs, retry policy, error annotations and GITHUB_PATH output.
  • action.yml: only runs: changes, to composite. Name, description, author and inputs are byte-identical.
  • Tests:
    • parity.yml: shellcheck, offline unit tests, download-timeout tests, and a differential test of old (build/main.cjs) vs new on every hosted OS/arch.
    • test.yml: end-to-end tests across pinned Ubuntu, Windows and macOS images (including ARM), plus the README examples, negative cases, a hostile caller environment, and container jobs.
  • README: a new section on the tools self-hosted runners and containers need, plus the @v1-node fallback.

The Node sources stay until the cleanup PR after a soak period, so reverting the switch commit restores the old action.

aneshlya and others added 10 commits October 7, 2026 11:23
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Ports src/main.js to a standalone Bash script with the same inputs,
messages, download URL, retry policy, extraction directory and
GITHUB_PATH output. It isn't wired into action.yml yet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sources install.sh with a stubbed curl and backoff to cover input
validation, URL construction, retry policy, error escaping, the git
fallback and lazy tool checks without network access.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Runs build/main.cjs and install.sh over the input matrix in the same
workspace path and compares exit code, error annotations, GITHUB_PATH
bytes, download URL, info log lines, extracted tree, stray workspace
files and the installed compiler's version output.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
test/composite/action.yml is the planned composite action.yml, pointing
at install.sh. parity.yml lints and unit-tests install.sh, runs the
old-vs-new parity test on every hosted OS/arch, and exercises the
composite action end to end: version and PATH checks across pinned
images, repeated installs, caller defaults, negative cases, a hostile
caller environment, container jobs with and without required tools,
and the windows-11-arm Bash start-up spike.

The root action.yml still uses node24, so users aren't affected.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Only runs: changes in action.yml; name, description, author and inputs
are untouched. The end-to-end tests move from parity.yml to test.yml and
now target uses: ./, adding the pinned-image matrix, a static interface
check against 11452bc, the README examples as written, and the
repeated-install, caller-defaults, negative, hostile-environment,
container and windows-11-arm cases. The temporary test/composite copy
is removed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Lists the tools the Bash implementation needs, when each one is needed,
and the @v1-node fallback for users who can't provide them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Trim exactly the whitespace JavaScript's String.trim() removes,
  including NBSP and BOM, in bash 3.2 and any locale.
- Bound curl connection and stalled-transfer time to three minutes,
  like the old HTTP client's socket timeout, and retry timeouts.
- Give extensionless downloads a .zip suffix before Windows PowerShell
  5.1's Expand-Archive, which rejects other extensions.
- Test real stalled downloads against a loopback server, and the
  PowerShell extraction fallback on Windows.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- install.sh: report the physical cwd in the PATH entry, like Node's
  path.resolve(): symlinks resolved (/var -> /private/var on macOS) and
  long rather than 8.3 names on Windows (cygpath -l).
- test.yml: shells put their own directories in front of PATH, so C3
  now checks which ispc bash, pwsh and cmd resolve rather than PATH[0].
- unit.sh: set a git identity for annotated tags in the fallback
  fixture, use a physical scratch path, and silence SC2317, the older
  shellcheck name for SC2329.
- parity.sh: drop the linux-archive-on-Windows case; the Node action
  fails there too, since Windows can't create the archive's symlinks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Drops TRANSITION.md and its section and criterion IDs from test names
and comments, which would be meaningless without it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@aneshlya
aneshlya requested a review from azwolski October 7, 2026 22:02
@aneshlya
aneshlya merged commit 61c68f4 into main Oct 8, 2026
57 checks passed
@azwolski

azwolski commented Oct 8, 2026

Copy link
Copy Markdown
Collaborator

Claude (Opus 5.5), non-blocking: This request has no timeout, unlike download(). If api.github.com accepts the connection and then stalls, the step hangs until the job timeout (6 h by default), where Node's fetch gave up after 300 s. It only affects runs where version is empty or latest. The existing unit and timeout tests pass with this change.

  code=$(curl -sSL --http1.1 --connect-timeout 10 --max-time 300 \
    -D "$hdr" -o "$body" -w '%{http_code}' "$ISPC_API_URL") || fail 'fetch failed'

@aneshlya
aneshlya deleted the composite-switch branch October 9, 2026 20:36
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.

2 participants