feat: auto-skip actions/setup-node on Alpine Linux#19
Conversation
actions/setup-node only ships glibc Node binaries via the GitHub toolcache, so installing Node into an Alpine container shadows the container's musl-native Node with a binary that cannot run. Subprocesses that spawn `node` then fail with ENOENT (the glibc dynamic linker is missing on Alpine). Add an `install-node` input defaulting to `auto`: detect Alpine via /etc/alpine-release and skip actions/setup-node when present, falling back to the container's Node. Users can force-install with `'true'` or opt out entirely with `'false'`. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 482f5c8dc7
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| - uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 | ||
| if: ${{ inputs.install-node == 'true' || (inputs.install-node == 'auto' && steps.detect.outputs.is-alpine != 'true') }} |
There was a problem hiding this comment.
Keep registry auth setup when skipping Node installation
The new if guard skips the entire actions/setup-node step on Alpine when install-node is auto, but this step is also where registry-url/scope auth setup happens (creation of .npmrc using NODE_AUTH_TOKEN). In Alpine jobs that install from private registries or publish packages, this change causes pnpm install/publish auth failures because those inputs are no longer applied. This regression is introduced by conditionally skipping the whole step rather than separating Node installation from registry configuration.
Useful? React with 👍 / 👎.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Points at oxc-project/setup-node#19 (auto-skip-alpine), which detects Alpine via /etc/alpine-release and skips actions/setup-node so the container's musl Node is preserved. Replaces the npm-install workaround. Will re-pin to the merge SHA once #19 lands. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The tri-state input added more surface area than it earned: - install-node: true is nonsensical (glibc Node can't run on musl) - install-node: false has no real use case (skip the action entirely) - install-node: auto is the only useful behavior Just auto-detect /etc/alpine-release on Linux and skip actions/setup-node when present. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Summary
`actions/setup-node` only ships glibc Node binaries via the GitHub toolcache, so when this action runs inside an Alpine container (e.g. `node:22-alpine`) it installs a glibc binary into PATH that shadows the container's musl-native Node. Subprocesses that spawn `node` then fail with ENOENT — Linux returns ENOENT when the dynamic linker (`/lib64/ld-linux-x86-64.so.2`) is missing, which it is on Alpine.
Repro from voidzero-dev/vite-task: https://github.com/voidzero-dev/vite-task/actions/runs/25104547071/job/73562308469?pr=367 — fspy's `node_fs` tests fail with `Error: underlying os error: No such file or directory (os error 2)` after `oxc-project/setup-node` runs in a `node:22-alpine3.21` container.
Change
Add an `install-node` input defaulting to `auto`. A new detection step checks `/etc/alpine-release`; on Alpine, `auto` skips `actions/setup-node` and the workflow uses the container's existing musl Node. Users can force-install with `true` or opt out entirely with `false`. Existing non-Alpine users see no change.
🤖 Generated with Claude Code