Skip to content

fix: use writable npm prefix to avoid EROFS on global npm installs#28384

Closed
Copilot wants to merge 3 commits into
mainfrom
copilot/aw-failures-fix-crush-install
Closed

fix: use writable npm prefix to avoid EROFS on global npm installs#28384
Copilot wants to merge 3 commits into
mainfrom
copilot/aw-failures-fix-crush-install

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 25, 2026

npm install -g defaults to writing into /opt/hostedtoolcache/node/.../lib/node_modules/, which is read-only after actions/setup-node runs on GitHub-hosted runners — causing an immediate EROFS failure for any engine that installs its CLI this way (Crush, Claude, Codex, Gemini, OpenCode).

Changes

  • GenerateNpmInstallStepsWithScope — global installs now set a writable prefix using $RUNNER_TEMP (the official GitHub Actions temp directory) and register the bin dir:

    run: |
      npm config set prefix "${RUNNER_TEMP:-/tmp}/npm-global"
      npm install --ignore-scripts -g @charmland/crush@0.59.0
      echo "${RUNNER_TEMP:-/tmp}/npm-global/bin" >> "$GITHUB_PATH"
  • GetNpmBinPathSetup — prepends ${RUNNER_TEMP:-/tmp}/npm-global/bin to the PATH used inside AWF-wrapped execution containers, so the binary is found in both firewall and non-firewall modes:

    export PATH="${RUNNER_TEMP:-/tmp}/npm-global/bin:$(find /opt/hostedtoolcache ...)$PATH"

    The /tmp fallback handles AWF container contexts where RUNNER_TEMP may not be inherited from the host runner.

  • Updated TestGetNpmBinPathSetup to assert RUNNER_TEMP-based npm-global/bin appears before /opt/hostedtoolcache in the generated PATH.

  • All 201 lock files recompiled.

`npm install -g` without a custom prefix tries to write into
`/opt/hostedtoolcache`, which is read-only on GitHub-hosted runners after
`setup-node` completes. Fix by:

1. Setting `npm config set prefix /tmp/npm-global` before each global
   npm install and appending `/tmp/npm-global/bin` to `$GITHUB_PATH` so
   subsequent steps (including non-AWF mode) find the installed binary.

2. Prepending `/tmp/npm-global/bin` to the PATH constructed by
   `GetNpmBinPathSetup()` so AWF-wrapped execution steps (Crush, Claude,
   Codex, Gemini, OpenCode) also find the binary inside the container.

Affects all engines that use `npm install -g` (Crush, Claude, Codex,
Gemini, OpenCode). Recompile regenerates all 201 lock files.

Agent-Logs-Url: https://github.com/github/gh-aw/sessions/25bf0aec-23d9-499f-9c5b-54365990ef30

Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix Crush CLI installation to use writable prefix fix: use writable npm prefix to avoid EROFS on global npm installs Apr 25, 2026
Copilot AI requested a review from gh-aw-bot April 25, 2026 02:08
@pelikhan pelikhan added the awf label Apr 25, 2026
@pelikhan
Copy link
Copy Markdown
Collaborator

@copilot use RUNNER_TEMP location

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 25, 2026

@copilot use RUNNER_TEMP location

Done in f49480e. The npm prefix and the PATH setup in GetNpmBinPathSetup() now both use ${RUNNER_TEMP:-/tmp}/npm-global, with /tmp as a fallback for AWF container contexts where RUNNER_TEMP may not be set.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • https://api.github.com/graphql
    • Triggering command: /usr/bin/gh /usr/bin/gh api graphql -f query=query($owner: String!, $name: String!) { repository(owner: $owner, name: $name) { hasDiscussionsEnabled } } -f owner=github -f name=gh-aw (http block)
  • https://api.github.com/repos/astral-sh/setup-uv/git/ref/tags/eac588ad8def6316056a12d4907a9d4d84ff7a3b
    • Triggering command: /usr/bin/gh gh api /repos/astral-sh/setup-uv/git/ref/tags/eac588ad8def6316056a12d4907a9d4d84ff7a3b --jq [.object.sha, .object.type] | @tsv (http block)
    • Triggering command: /usr/bin/gh gh api /repos/astral-sh/setup-uv/git/ref/tags/eac588ad8def6316056a12d4907a9d4d84ff7a3b --jq [.object.sha, .object.type] | @tsv h ../../../.prettierignore (http block)
    • Triggering command: /usr/bin/gh gh api /repos/astral-sh/setup-uv/git/ref/tags/eac588ad8def6316056a12d4907a9d4d84ff7a3b --jq [.object.sha, .object.type] | @tsv h ../../../.pret--log-level=error (http block)
  • https://api.github.com/repos/github/gh-aw
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw --jq .default_branch (http block)

If you need me to access, download, or install something from one of these locations, you can either:

Copilot AI requested a review from pelikhan April 25, 2026 04:32
@github-actions
Copy link
Copy Markdown
Contributor

Hey @Copilot 👋 — great work tracking down the EROFS failure on global npm installs! Fixing the writable prefix issue for Crush, Claude, Codex, Gemini, and OpenCode in one focused change is exactly the right approach. This PR looks well-structured and ready for maintainer review. 🎉

The checklist came back clean:

  • ✅ Authored by a core team agent (Copilot)
  • ✅ Focused on a single bug fix (npm prefix writability)
  • ✅ Test coverage updated (TestGetNpmBinPathSetup)
  • ✅ Clear description explaining the root cause, fix, and affected engines
  • ✅ No new external dependencies introduced
  • ✅ Lock files regenerated as expected

Nothing blocking here — this is aligned with contribution guidelines and looks ready for review once the draft is marked ready.

Generated by Contribution Check · ● 1.3M ·

@github-actions github-actions Bot mentioned this pull request Apr 25, 2026
@pelikhan pelikhan closed this Apr 25, 2026
@github-actions github-actions Bot deleted the copilot/aw-failures-fix-crush-install branch May 3, 2026 03:00
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.

[aw-failures] smoke-crush: EROFS on npm global install to read-only hostedtoolcache

3 participants