@vzn/vx 0.0.332 → 0.0.334
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vzn/vx",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.334",
|
|
4
4
|
"description": "A fast, correct task runner and build cache for JavaScript monorepos.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -21,10 +21,10 @@
|
|
|
21
21
|
"node": ">=18"
|
|
22
22
|
},
|
|
23
23
|
"optionalDependencies": {
|
|
24
|
-
"@vzn/vx-linux-x64": "0.0.
|
|
25
|
-
"@vzn/vx-linux-arm64": "0.0.
|
|
26
|
-
"@vzn/vx-darwin-x64": "0.0.
|
|
27
|
-
"@vzn/vx-darwin-arm64": "0.0.
|
|
24
|
+
"@vzn/vx-linux-x64": "0.0.334",
|
|
25
|
+
"@vzn/vx-linux-arm64": "0.0.334",
|
|
26
|
+
"@vzn/vx-darwin-x64": "0.0.334",
|
|
27
|
+
"@vzn/vx-darwin-arm64": "0.0.334"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"@anthropic-ai/sandbox-runtime": "^0.0.76"
|
|
@@ -737,6 +737,30 @@ function canonicalBaselines(
|
|
|
737
737
|
}
|
|
738
738
|
}
|
|
739
739
|
|
|
740
|
+
/**
|
|
741
|
+
* Linux: does some mount hold the task's cwd? bwrap enters the old cwd
|
|
742
|
+
* only if it exists in the new root, and otherwise `$HOME`, with no word:
|
|
743
|
+
* a project granted no read ran in the home directory, where `cat x.txt`
|
|
744
|
+
* read `~/x.txt`. A grant at or above the cwd holds it, and so does an
|
|
745
|
+
* existing one below (bwrap builds the path to a bind), and so does a
|
|
746
|
+
* deny that IS the cwd (a single-package workspace's anchor). When none does,
|
|
747
|
+
* the cwd is denied instead: an empty directory the task enters, whose
|
|
748
|
+
* reads are refused and reported as the anchor's are.
|
|
749
|
+
*/
|
|
750
|
+
function cwdMounted(
|
|
751
|
+
cwd: string,
|
|
752
|
+
fs: {
|
|
753
|
+
allowRead?: readonly string[] | undefined
|
|
754
|
+
allowWrite?: readonly string[] | undefined
|
|
755
|
+
denyRead?: readonly string[] | undefined
|
|
756
|
+
},
|
|
757
|
+
): boolean {
|
|
758
|
+
if (fs.denyRead?.includes(cwd) === true) return true
|
|
759
|
+
return [...(fs.allowRead ?? []), ...(fs.allowWrite ?? [])].some(
|
|
760
|
+
(p) => atOrUnder(cwd, p) || (atOrUnder(p, cwd) && existsSync(p)),
|
|
761
|
+
)
|
|
762
|
+
}
|
|
763
|
+
|
|
740
764
|
/**
|
|
741
765
|
* A write grant that names a path in the project must BIND one there. The
|
|
742
766
|
* grant was realpath'd, so `out.txt -> ../b/src/x` (committed, or planted
|
|
@@ -958,6 +982,9 @@ export async function wrapSandboxedCommand(
|
|
|
958
982
|
const customConfig = buildCustomConfig(args, baselines)
|
|
959
983
|
const scratch = pendingWriteGrants(args.config, customConfig!.filesystem!, baselines.denyRead)
|
|
960
984
|
customConfig!.filesystem!.denyRead!.push(toRealPath(taskTmpRoot()))
|
|
985
|
+
if (process.platform === 'linux' && !cwdMounted(baselines.cwd, customConfig!.filesystem!)) {
|
|
986
|
+
customConfig!.filesystem!.denyRead!.push(baselines.cwd)
|
|
987
|
+
}
|
|
961
988
|
customConfig!.filesystem!.allowWrite!.push(toRealPath(tmp))
|
|
962
989
|
if (scopedDenyScan) {
|
|
963
990
|
customConfig!.filesystem!.denyWrite!.push(
|
|
@@ -1268,10 +1295,11 @@ const TRACER_RETRY_LINE =
|
|
|
1268
1295
|
* On Linux the task runs under strace, which only REPORTS what the sandbox
|
|
1269
1296
|
* denied. strace failing on its own (`ptrace(PTRACE_LISTEN,…): Input/output
|
|
1270
1297
|
* error`, after a build that had finished) turned green work red on CI five
|
|
1271
|
-
* times (STATUS Next 24): its exit was the task's. Since B-11
|
|
1272
|
-
*
|
|
1273
|
-
*
|
|
1274
|
-
*
|
|
1298
|
+
* times (STATUS Next 24): its exit was the task's. Since B-11 strace runs
|
|
1299
|
+
* detached (`-DD`), yet under `--seccomp-bpf` (strace 6.8 implies
|
|
1300
|
+
* `--kill-on-exit`) a tracer that dies still SIGKILLs the command: exit
|
|
1301
|
+
* 137 on CI (M-18). Untraced or killed, the trace stopped short and a
|
|
1302
|
+
* denial after it goes unreported. So an attempt whose stderr carries strace's own word is
|
|
1275
1303
|
* run once more, whatever its exit, unless the run is stopping: the sandbox kept its writes to what it
|
|
1276
1304
|
* declared, so a second run redoes, not doubles, it.
|
|
1277
1305
|
*/
|
|
@@ -1329,8 +1357,13 @@ function collectRecords(
|
|
|
1329
1357
|
}
|
|
1330
1358
|
}
|
|
1331
1359
|
|
|
1332
|
-
/**
|
|
1333
|
-
|
|
1360
|
+
/**
|
|
1361
|
+
* strace's own message, a line of a traced task's stderr. strace names
|
|
1362
|
+
* itself by its argv[0], the absolute path vx runs it by
|
|
1363
|
+
* (`/usr/bin/strace: ptrace(PTRACE_LISTEN,…)` on CI), so a bare
|
|
1364
|
+
* `strace: ` never matched there and the retry never fired.
|
|
1365
|
+
*/
|
|
1366
|
+
const STRACE_OWN_ERROR = /^(?:[^\s:]*\/)?strace: /
|
|
1334
1367
|
|
|
1335
1368
|
/**
|
|
1336
1369
|
* One attempt of `runSandboxed`.
|
|
@@ -1437,7 +1470,7 @@ async function runSandboxedOnce(
|
|
|
1437
1470
|
// Read whatever the capture setting: a line of strace's own says
|
|
1438
1471
|
// the trace stopped short.
|
|
1439
1472
|
const lines = (partial + chunk).split('\n')
|
|
1440
|
-
partial = (lines.pop() ?? '').slice(0,
|
|
1473
|
+
partial = (lines.pop() ?? '').slice(0, 512)
|
|
1441
1474
|
if (lines.some((l) => STRACE_OWN_ERROR.test(l))) straceSpoke = true
|
|
1442
1475
|
args.onStderr?.(chunk)
|
|
1443
1476
|
},
|
|
@@ -252,7 +252,37 @@ function upstreamBuildOnWorker(tasks: GeneratedTask[]): void {
|
|
|
252
252
|
* task again beside the member's own (D-45).
|
|
253
253
|
*/
|
|
254
254
|
const RUNS_MEMBERS =
|
|
255
|
-
/(^|[\s;&|(])(turbo|nx|lerna|ultra|wireit|nps|moon|rush|vx)(\s|$)|\
|
|
255
|
+
/(^|[\s;&|(])(turbo|nx|lerna|ultra|wireit|nps|moon|rush|vx)(\s|$)|\bworkspaces?\s+(foreach|run)\b|\bvp\s+run\s|\bcd\s/
|
|
256
|
+
|
|
257
|
+
/** A workspace flag, read only where a package manager takes it (`pmRunsMembers`). */
|
|
258
|
+
const MEMBER_FLAG =
|
|
259
|
+
/^(-r|--recursive|--filter|-F|--workspaces|-ws|--workspace|-w|-C|--dir|--cwd|--prefix|--if-present|--parallel|--stream)(=|$)/
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* The workspace flags are a package manager's: on the program it runs they
|
|
263
|
+
* mean something else, and berry's `bench` (`yarn node -r ./setup.ts …`,
|
|
264
|
+
* node's `--require`) was left out as running the members (D-81). With no
|
|
265
|
+
* manager named, a `run` verb is one.
|
|
266
|
+
*/
|
|
267
|
+
function pmRunsMembers(script: string): boolean {
|
|
268
|
+
for (const segment of script.split(/&&|\|\||[;|()]/)) {
|
|
269
|
+
const words = segment.trim().split(/\s+/)
|
|
270
|
+
let i = words.findIndex((w) => /^(pnpm|npm|yarn|bun)$/.test(w))
|
|
271
|
+
// npm/cli runs itself: `node . run test --workspaces`.
|
|
272
|
+
if (i < 0) i = words.indexOf('run')
|
|
273
|
+
if (i < 0) continue
|
|
274
|
+
// `exec`, `dlx` and `x` take the manager's flags up to the program name.
|
|
275
|
+
let program = false
|
|
276
|
+
for (i++; i < words.length; i++) {
|
|
277
|
+
const w = words[i]!
|
|
278
|
+
if (MEMBER_FLAG.test(w)) return true
|
|
279
|
+
if (program && !w.startsWith('-')) break
|
|
280
|
+
if (w === 'node') break
|
|
281
|
+
if (w === 'exec' || w === 'dlx' || w === 'x') program = true
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
return false
|
|
285
|
+
}
|
|
256
286
|
|
|
257
287
|
/** A package manager running a script by name: `pnpm build`, `npm run x`, `bun run x`. */
|
|
258
288
|
const RUNS_SCRIPT =
|
|
@@ -267,7 +297,9 @@ function runningMembers(scripts: Readonly<Record<string, unknown>>): Set<string>
|
|
|
267
297
|
const text = Object.entries(scripts).filter(
|
|
268
298
|
(e): e is [string, string] => typeof e[1] === 'string',
|
|
269
299
|
)
|
|
270
|
-
const out = new Set(
|
|
300
|
+
const out = new Set(
|
|
301
|
+
text.filter(([, v]) => RUNS_MEMBERS.test(` ${v}`) || pmRunsMembers(v)).map(([n]) => n),
|
|
302
|
+
)
|
|
271
303
|
for (let grew = true; grew;) {
|
|
272
304
|
grew = false
|
|
273
305
|
for (const [n, v] of text) {
|