@vzn/vx 0.0.365 → 0.0.367
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.367",
|
|
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.367",
|
|
25
|
+
"@vzn/vx-linux-arm64": "0.0.367",
|
|
26
|
+
"@vzn/vx-darwin-x64": "0.0.367",
|
|
27
|
+
"@vzn/vx-darwin-arm64": "0.0.367"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"@anthropic-ai/sandbox-runtime": "^0.0.76"
|
|
@@ -543,6 +543,35 @@ function hostHasIpv6(): boolean {
|
|
|
543
543
|
return hasIpv6
|
|
544
544
|
}
|
|
545
545
|
|
|
546
|
+
/**
|
|
547
|
+
* Refuse a network entry SRT's own schema refuses, naming it. vx handed
|
|
548
|
+
* the union over unchecked, and SRT's proxy matched as it could: a URL
|
|
549
|
+
* (`https://example.com`), a dotless host or a port past 65535 matched
|
|
550
|
+
* nothing, so the grant silently reached no host, and `'*'`, which the
|
|
551
|
+
* schema refuses as too broad, opened every host to every sandboxed task
|
|
552
|
+
* of the run, the allowlist being the run's (2026-10-02).
|
|
553
|
+
*/
|
|
554
|
+
function assertDomains(
|
|
555
|
+
schema: SrtModule['NetworkConfigSchema'],
|
|
556
|
+
allowed: readonly string[],
|
|
557
|
+
denied: readonly string[],
|
|
558
|
+
): void {
|
|
559
|
+
const bad = [
|
|
560
|
+
...allowed
|
|
561
|
+
.filter((d) => !schema.shape.allowedDomains.safeParse([d]).success)
|
|
562
|
+
.map((d) => `allow.network "${d}"`),
|
|
563
|
+
...denied
|
|
564
|
+
.filter((d) => !schema.shape.deniedDomains.safeParse([d]).success)
|
|
565
|
+
.map((d) => `deny.network "${d}"`),
|
|
566
|
+
]
|
|
567
|
+
if (bad.length === 0) return
|
|
568
|
+
throw new UserError(
|
|
569
|
+
`sandbox: ${bad.join(', ')} is not a host pattern: name a host ("example.com"), a ` +
|
|
570
|
+
`subdomain wildcard ("*.example.com") or either with a port ("example.com:443"); no ` +
|
|
571
|
+
`scheme or path, and "*" or "*.com" is refused as too broad (a bare "*" only in deny)`,
|
|
572
|
+
)
|
|
573
|
+
}
|
|
574
|
+
|
|
546
575
|
/**
|
|
547
576
|
* One-time SRT initialization per orchestrator run. Starts the proxy
|
|
548
577
|
* servers + (on macOS) the violation log monitor. Safe to call repeatedly
|
|
@@ -586,7 +615,8 @@ export async function initSandbox(opts?: {
|
|
|
586
615
|
await resetting
|
|
587
616
|
// Before SRT starts, so the very first task already has one.
|
|
588
617
|
await mkdir(sandboxTmpdir(), { recursive: true })
|
|
589
|
-
const { SandboxManager } = await loadSrt()
|
|
618
|
+
const { SandboxManager, NetworkConfigSchema } = await loadSrt()
|
|
619
|
+
assertDomains(NetworkConfigSchema, opts?.allowedDomains ?? [], opts?.deniedDomains ?? [])
|
|
590
620
|
scopedDenyScan = process.platform === 'linux' && canScopeDenyScan(process.cwd())
|
|
591
621
|
const config: Parameters<typeof SandboxManager.initialize>[0] = {
|
|
592
622
|
network: {
|
|
@@ -11,6 +11,7 @@ import type { ExecConfig } from '../config.js'
|
|
|
11
11
|
import {
|
|
12
12
|
bindableWrites,
|
|
13
13
|
initSandbox,
|
|
14
|
+
resetSandbox,
|
|
14
15
|
probeSandbox,
|
|
15
16
|
punchWalls,
|
|
16
17
|
resolveSandboxConfig,
|
|
@@ -141,6 +142,10 @@ export function prepareSandbox(nodes: Iterable<TaskNode>): SandboxArmer | null {
|
|
|
141
142
|
...(gitConfig ? { gitConfig: true } : {}),
|
|
142
143
|
})
|
|
143
144
|
} catch (err) {
|
|
145
|
+
// The Linux probe brings the runtime up, and only an armed run
|
|
146
|
+
// resets it: a refusal past the probe left its proxy holding the
|
|
147
|
+
// process open, and the run hung after its summary (2026-10-02).
|
|
148
|
+
await resetSandbox().catch(() => {})
|
|
144
149
|
// A throw from the runtime itself (its bridge needs socat, which
|
|
145
150
|
// the dependency check does not cover) gets the same one-line
|
|
146
151
|
// verdict as a refused probe, not an internal error with a stack.
|
package/src/util/secret-mask.ts
CHANGED
|
@@ -63,7 +63,16 @@ export function secretMask(
|
|
|
63
63
|
): SecretMask | null {
|
|
64
64
|
const values = new Set<string>()
|
|
65
65
|
const add = (value: string | undefined): void => {
|
|
66
|
-
if (value
|
|
66
|
+
if (value === undefined || value.length < MIN_SECRET_CHARS) return
|
|
67
|
+
values.add(value)
|
|
68
|
+
// A multi-line value (a PEM key) is also masked line by line, as GitHub
|
|
69
|
+
// Actions does: a tool that indents or reflows it prints no copy of the
|
|
70
|
+
// whole value, and every line leaked (L-36).
|
|
71
|
+
if (!value.includes('\n')) return
|
|
72
|
+
for (const line of value.split(/\r?\n/)) {
|
|
73
|
+
const trimmed = line.trim()
|
|
74
|
+
if (trimmed.length >= MIN_SECRET_CHARS) values.add(trimmed)
|
|
75
|
+
}
|
|
67
76
|
}
|
|
68
77
|
for (const source of sources) {
|
|
69
78
|
if (source === undefined) continue
|