Repository navigation
Fix CI: upgrade Yarn to 4.14.1 + install libusb for native modules - #1958
Conversation
CI was failing on the test (25) job during `yarn install` with three
build errors:
YN0009: usb@npm:2.9.0 couldn't be built successfully
YN0009: unrs-resolver@npm:1.11.1 couldn't be built successfully
YN0009: node-hid@npm:2.1.2 couldn't be built successfully
Two unrelated root causes:
1. `unrs-resolver` (and any other dep loaded as CJS through Yarn PnP zip
archives) hits "Error: EBADF: bad file descriptor, fstat" on Node
25.7+ and Node 24.15+. Node's ESM loader started reading CJS source
through unpatched `fs.readFileSync`, which can't `fstat` Yarn's
zip-backed file descriptors. See
yarnpkg/berry#7065 and
nodejs/node#62012.
Fixed in Yarn 4.14.1, which detects affected Node versions
(`HAS_BROKEN_FSTAT_FOR_ZIP_FDS`) and returns the CJS source from the
PnP loader's `load` hook instead of letting Node `fstat` the fake fd.
2. `node-hid@2.1.2` and `usb@2.9.0` ship prebuilt binaries for older
Node versions but fall back to a libusb source build on Node 25.
The Linux runner doesn't have `libusb-1.0-0-dev` / `libudev-dev`
pre-installed.
Upgrade Yarn (.yarnrc.yml, package.json, .yarn/releases/, regenerated
.pnp.* + yarn.lock metadata version 9) and install the missing system
libs in `.github/workflows/test.yml` (all three jobs) and
`.github/workflows/coverage.yml`.
Made-with: Cursor
Greptile SummaryThis PR fixes a broken CI pipeline by upgrading Yarn from 4.12.0 to 4.14.1 (which contains the Node ≥25.7 PnP/
Confidence Score: 3/5The CI fix itself is correct, but two P1 security-relaxing settings in Two P1 findings in .yarnrc.yml requires attention for the two broad security-relaxing settings added.
|
| Filename | Overview |
|---|---|
| .yarnrc.yml | Yarn path correctly bumped to 4.14.1, but two broad security-relaxing settings were added: approvedGitRepositories: "**" (approves all git deps without review) and enableScripts: true (enables arbitrary postinstall scripts for all packages) |
| .github/workflows/test.yml | Adds libusb-1.0-0-dev and libudev-dev apt install step before yarn install in all three jobs; correctly placed and necessary for Node 25 source builds of node-hid/usb |
| .github/workflows/coverage.yml | Same native dependency install step added; consistent with test.yml changes |
| package.json | packageManager field updated from yarn@4.12.0 to yarn@4.14.1, straightforward version bump |
| yarn.lock | Only lockfile metadata version bumped (8 → 9); no dependency changes, as stated in PR description |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[CI Job Starts] --> B[actions/setup-node]
B --> C[apt-get install libusb-1.0-0-dev libudev-dev]
C --> D[yarn install --immutable]
D --> E{Node version}
E -->|Node 22/24 - prebuild exists| F[Install prebuilt node-hid / usb binary]
E -->|Node 25 - no prebuild| G[Source build via node-gyp]
G --> H[gcc links against libusb-1.0-0-dev ✓]
F --> I[Build & Test]
H --> I
D --> J{PnP fstat issue?}
J -->|Yarn 4.14.1 - fixed| K[PnP loader returns CJS source directly]
J -->|Yarn 4.12.0 - broken| L[EBADF error on Node ≥25.7]
K --> I
Reviews (1): Last reviewed commit: "[autofix.ci] apply automated fixes" | Re-trigger Greptile
Two settings slipped into .yarnrc.yml from a local `yarn install` run when generating the lockfile/PnP files for the 4.14.1 upgrade: - approvedGitRepositories: ["**"] - enableScripts: true Neither is needed: - The repo has no git-resolved dependencies (yarn.lock has only npm resolutions), so approving "**" is purely a future-facing footgun that bypasses Yarn's git-dep review prompt. - `enableScripts` already defaults to true in Yarn 4, so the explicit setting is a no-op functionally and just adds noise. Reverting both restores the pre-existing behavior on main. Reported by Greptile review on #1958. Made-with: Cursor
|
Thanks @greptile-apps. Both settings were accidental — they were auto-written into
The CI pipeline still works because:
|
|
Makes sense — both explanations check out:
The revert in e664c60 looks clean. No further concerns on this front. Tip: You can customize Greptile's behavior for this repo with |
Summary
CI was failing on the
test (25)job (Node 25 matrix entry) duringyarn installwith three build errors:This had been blocking every PR.
Root cause 1:
EBADFin PnP zip-loaded CJS modules on Node ≥25.7 / ≥24.15The
unrs-resolverfailure (and the cascadingError: EBADF: bad file descriptor, fstatnext tousb/node-hid) is a Yarn PnP / Node.js incompatibility, not a build script bug. Node's ESM loader started reading CJS source through an unpatchedfs.readFileSync, which can'tfstatYarn's zip-backed file descriptors:Tracked in yarnpkg/berry#7065, #7103 and nodejs/node#62012. Fixed in Yarn 4.14.1, which detects affected Node versions (
HAS_BROKEN_FSTAT_FOR_ZIP_FDS = major > 25 || (major === 25 && minor >= 7) || (major === 24 && minor >= 15)) and returns the CJS source from the PnP loader's `load` hook instead of letting Node `fstat` the fake fd.This repo pinned Yarn 4.12.0.
Root cause 2: missing
libusb-1.0-0-devfor Node 25 source buildsnode-hid@2.1.2andusb@2.9.0ship prebuilt binaries for older Node ABIs. On Node 25 they fall back to amakesource build:The GitHub Actions runner doesn't have
libusb-1.0-0-dev/libudev-devpre-installed.Changes
.yarnrc.yml,package.json(`packageManager`),.yarn/releases/yarn-4.14.1.cjs.pnp.cjs/.pnp.loader.mjs(the loader now contains the EBADF workaround)yarn.lockmetadata version bumped 8 → 9 (no dependency churn)libusb-1.0-0-devandlibudev-devbefore `yarn install` in.github/workflows/test.yml(all three jobs) and.github/workflows/coverage.ymlso `node-hid` / `usb` can build from source on Node versions that lack prebuilds.Test plan
node .yarn/releases/yarn-4.14.1.cjs --version→ `4.14.1`yarn installlocally regenerates.pnp.cjs/.pnp.loader.mjscleanly with theHAS_BROKEN_FSTAT_FOR_ZIP_FDSworkaroundyarn.lockmetadataversion: 8→9Note
This PR stacks cleanly on top of #1957 (evmd CI fix). Either order should work.
Made with Cursor