Skip to content

Commit d559c0c

Browse files
authored
Merge branch 'main' into fix/1147-dropped-language-gap-test
2 parents 00cdc46 + 0198c57 commit d559c0c

4 files changed

Lines changed: 76 additions & 6 deletions

File tree

.github/workflows/ci.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,13 @@ jobs:
2121
with:
2222
node-version: 22
2323

24+
# Runs before `npm install` because npm 11 silently strips the `libc`
25+
# field from optional-dependency lockfile entries (see #1160). If the
26+
# check ran post-install we'd flag every CI run instead of the PRs that
27+
# actually introduce the regression.
28+
- name: Verify lockfile libc discriminators
29+
run: node scripts/verify-lockfile-libc.mjs
30+
2431
- name: Install dependencies
2532
timeout-minutes: 20
2633
shell: bash

package-lock.json

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

scripts/verify-lockfile-libc.mjs

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
#!/usr/bin/env node
2+
// Verifies that @optave/codegraph-linux-* entries in package-lock.json declare
3+
// the `libc` discriminator. npm 11 silently strips this field when generating
4+
// the lockfile on non-Linux hosts (and sometimes on Linux too), even though the
5+
// published packages declare it. Without it, npm cannot disambiguate
6+
// linux-x64-gnu vs linux-x64-musl when resolving from the lockfile and may
7+
// install (or load) the wrong native binary on Alpine/musl hosts.
8+
//
9+
// Run via `npm run lint` (or directly) in CI to catch silent regressions from
10+
// Dependabot bumps and contributor `npm install` runs.
11+
import { readFileSync } from 'node:fs';
12+
import { dirname, resolve } from 'node:path';
13+
import { fileURLToPath } from 'node:url';
14+
15+
const EXPECTED_LIBC = {
16+
'@optave/codegraph-linux-arm64-gnu': 'glibc',
17+
'@optave/codegraph-linux-x64-gnu': 'glibc',
18+
'@optave/codegraph-linux-x64-musl': 'musl',
19+
};
20+
21+
// Resolve relative to this script's location so it works regardless of CWD
22+
// (e.g. running `node scripts/verify-lockfile-libc.mjs` from the `scripts/`
23+
// subdirectory still finds the repo-root lockfile).
24+
const __dirname = dirname(fileURLToPath(import.meta.url));
25+
const lockfilePath = resolve(__dirname, '..', 'package-lock.json');
26+
const lock = JSON.parse(readFileSync(lockfilePath, 'utf8'));
27+
const failures = [];
28+
29+
for (const [pkgName, expectedLibc] of Object.entries(EXPECTED_LIBC)) {
30+
const entry = lock.packages?.[`node_modules/${pkgName}`];
31+
if (!entry) {
32+
failures.push(`${pkgName}: missing from package-lock.json`);
33+
continue;
34+
}
35+
const libc = entry.libc;
36+
if (!Array.isArray(libc) || !libc.includes(expectedLibc)) {
37+
failures.push(
38+
`${pkgName}: expected libc=["${expectedLibc}"], got ${JSON.stringify(libc)}`,
39+
);
40+
}
41+
}
42+
43+
if (failures.length > 0) {
44+
console.error('package-lock.json libc discriminator check failed:\n');
45+
for (const f of failures) console.error(` - ${f}`);
46+
console.error(
47+
'\nnpm install may have stripped the libc field. Restore it by editing\n' +
48+
'package-lock.json so each @optave/codegraph-linux-* entry includes\n' +
49+
'its libc field (see expected values above). Tracked in #1160.',
50+
);
51+
process.exit(1);
52+
}
53+
54+
console.log('package-lock.json libc discriminators OK');

tests/unit/snapshot.test.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -149,16 +149,16 @@ describe('snapshotSave', () => {
149149
// snapshotSave. better-sqlite3 is synchronous, so Promise-based
150150
// concurrency would queue two sequential microtasks — only separate
151151
// threads exercise the TOCTOU race.
152-
const nodeMajor = Number(process.versions.node.split('.')[0]);
153152
const raceWorkerPath = path.join(__dirname, 'snapshot-race-worker.mjs');
154153
// --import requires a URL (file://…) or a bare/relative specifier, not a
155154
// drive-letter path on Windows. Use the file:// URL directly.
156155
const loaderUrl = new URL('../../scripts/ts-resolve-loader.js', import.meta.url).href;
157-
const raceExecArgv = [
158-
nodeMajor >= 23 ? '--strip-types' : '--experimental-strip-types',
159-
'--import',
160-
loaderUrl,
161-
];
156+
// `--experimental-strip-types` is accepted by Worker execArgv across all
157+
// supported Node versions (≥ 22.6); the unprefixed `--strip-types` flag
158+
// is not in the Worker allowlist on Node 24 and causes
159+
// ERR_WORKER_INVALID_EXEC_ARGV. On Node ≥ 23.6 type stripping is on by
160+
// default, so the flag is a harmless no-op there.
161+
const raceExecArgv = ['--experimental-strip-types', '--import', loaderUrl];
162162
const spawnSaveWorker = (workerData: {
163163
dbPath: string;
164164
name: string;

0 commit comments

Comments
 (0)