vouchington-tooling 0.19.2 → 0.21.0
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/README.md +14 -9
- package/dist/cli/commands/gha-runtime-audit.mjs +6 -0
- package/dist/cli/commands/retrospective-facts.mjs +20 -7
- package/dist/cli/index.mjs +4 -1
- package/dist/cli/parse-gha-runtime-audit.d.mts +2 -0
- package/dist/cli/parse-gha-runtime-audit.mjs +33 -1
- package/dist/cli/parse.d.mts +7 -0
- package/dist/cli/parse.mjs +15 -0
- package/dist/cli/usage.d.mts +3 -1
- package/dist/cli/usage.mjs +44 -1
- package/dist/dependency-license-policy/audit-directory.d.mts +28 -0
- package/dist/dependency-license-policy/audit-directory.mjs +115 -0
- package/dist/dependency-license-policy/audit-signals.d.mts +12 -0
- package/dist/dependency-license-policy/audit-signals.mjs +44 -0
- package/dist/dependency-license-policy/audit-store.d.mts +12 -0
- package/dist/dependency-license-policy/audit-store.mjs +32 -0
- package/dist/dependency-license-policy/collect.d.mts +3 -1
- package/dist/dependency-license-policy/collect.mjs +16 -21
- package/dist/dependency-license-policy/execute-pnpm.d.mts +10 -0
- package/dist/dependency-license-policy/execute-pnpm.mjs +83 -0
- package/dist/dependency-license-policy/types.d.mts +11 -9
- package/dist/dependency-license-policy/workspace.d.mts +3 -1
- package/dist/dependency-license-policy/workspace.mjs +12 -5
- package/dist/gha-runtime-audit/audit.mjs +12 -4
- package/dist/gha-runtime-audit/family.d.mts +7 -0
- package/dist/gha-runtime-audit/family.mjs +79 -0
- package/dist/gha-runtime-audit/index.test-helpers.d.mts +5 -0
- package/dist/gha-runtime-audit/model.d.mts +11 -1
- package/dist/gha-runtime-audit/model.mjs +26 -0
- package/dist/gha-runtime-audit/scope.d.mts +2 -0
- package/dist/gha-runtime-audit/scope.mjs +16 -1
- package/dist/pnpm-install/support.mjs +1 -1
- package/package.json +1 -1
- package/scripts/allocate-browser-safe-ports.py +2 -583
- package/dist/cli/commands/allocate-browser-safe-ports.slot-fixtures.test-helpers.d.mts +0 -6
- package/dist/cli/commands/allocate-browser-safe-ports.slot-fixtures.test-helpers.mjs +0 -103
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
import { spawn } from 'node:child_process';
|
|
2
|
-
import { existsSync } from 'node:fs';
|
|
3
|
-
import { mkdtemp, rm, writeFile } from 'node:fs/promises';
|
|
4
|
-
import { tmpdir } from 'node:os';
|
|
5
|
-
import { join, resolve } from 'node:path';
|
|
6
|
-
import { runnerPortPolicy } from '../../runner-port-policy/index.mjs';
|
|
7
|
-
const hostLockScriptPath = resolve('packages/vouchington-tooling/scripts/host-lock/with-host-lock.sh');
|
|
8
|
-
// Slot `maximumRunnerSlot` is the fleet's established synthetic ceiling for boundary tests (see
|
|
9
|
-
// allocate-browser-safe-ports.test.mts's "uses the slot-50 boundary" case) — no host runs that
|
|
10
|
-
// many runner slots, so this range never collides with a real runner's live port allocation.
|
|
11
|
-
export const synthesizedRunnerSlot = runnerPortPolicy.maximumRunnerSlot;
|
|
12
|
-
export const synthesizedPortRangeStart = runnerPortPolicy.reservedPortStart +
|
|
13
|
-
(synthesizedRunnerSlot - runnerPortPolicy.minimumRunnerSlot) * runnerPortPolicy.portsPerRunner;
|
|
14
|
-
export const synthesizedPortRangeEnd = synthesizedPortRangeStart + runnerPortPolicy.portsPerRunner - 1;
|
|
15
|
-
export function requiredPort(port) {
|
|
16
|
-
if (port === undefined)
|
|
17
|
-
throw new Error('expected an allocated port');
|
|
18
|
-
return port;
|
|
19
|
-
}
|
|
20
|
-
const hostLockName = 'allocate-browser-safe-ports-synthesized-slot';
|
|
21
|
-
const hostLockTimeoutSeconds = 60;
|
|
22
|
-
const hostLockCommandTimeoutSeconds = 60;
|
|
23
|
-
// Grace this wrapper waits past with-host-lock.sh's own --timeout-seconds before giving up on the
|
|
24
|
-
// acquired marker (mirrors the script's internal polling/teardown overhead around acquisition).
|
|
25
|
-
const hostLockAcquireGraceSeconds = 15;
|
|
26
|
-
// Fixed overhead for this wrapper's own teardown once body() returns: writing the release marker,
|
|
27
|
-
// waiting for the placeholder to exit, and removing the marker dir.
|
|
28
|
-
const hostLockWrapperTeardownMarginSeconds = 15;
|
|
29
|
-
// Single source of truth for how long a vitest `it()` calling withSynthesizedSlotHostLock must be
|
|
30
|
-
// allowed to run: the full lock-acquisition window, then a critical section that may legitimately
|
|
31
|
-
// run right up to with-host-lock's own --command-timeout-seconds watchdog, plus fixed wrapper
|
|
32
|
-
// teardown. Deriving this -- instead of a second, independent literal on the `it()` call -- is what
|
|
33
|
-
// guarantees with-host-lock's watchdog can never force-release the lock while the calling test
|
|
34
|
-
// still believes it's within its own timeout budget: with-host-lock.sh's
|
|
35
|
-
// start_command_timeout_watchdog force-kills the placeholder and unconditionally releases the lock
|
|
36
|
-
// once command_timeout_seconds elapses, regardless of whether body() has finished, so the vitest
|
|
37
|
-
// timeout must always exceed that watchdog's own worst case, never fall short of it.
|
|
38
|
-
export const synthesizedSlotHostLockTestTimeoutMs = (hostLockTimeoutSeconds +
|
|
39
|
-
hostLockAcquireGraceSeconds +
|
|
40
|
-
hostLockCommandTimeoutSeconds +
|
|
41
|
-
hostLockWrapperTeardownMarginSeconds) *
|
|
42
|
-
1000;
|
|
43
|
-
async function waitForMarker(path, timeoutMs) {
|
|
44
|
-
const deadline = Date.now() + timeoutMs;
|
|
45
|
-
while (!existsSync(path)) {
|
|
46
|
-
if (Date.now() >= deadline)
|
|
47
|
-
throw new Error(`timed out waiting for marker: ${path}`);
|
|
48
|
-
await new Promise((resolveWait) => setTimeout(resolveWait, 50));
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
// ci/with-host-lock.sh only wraps a subprocess command, but the racy resource here (binding real
|
|
52
|
-
// host ports) is in-process Node.js code. The wrapped command is therefore a placeholder that
|
|
53
|
-
// writes an "acquired" marker the instant it starts running — which is exactly when the lock is
|
|
54
|
-
// held, per with-host-lock.sh's start-release handshake — and blocks on a "release" marker until
|
|
55
|
-
// told to stop. That gates the Node-side critical section on lock acquisition/release instead of
|
|
56
|
-
// trying to run that section as the locked subprocess itself, so two concurrent copies of a test
|
|
57
|
-
// using the synthesized slot take turns instead of colliding on the same synthetic port range.
|
|
58
|
-
export async function withSynthesizedSlotHostLock(body) {
|
|
59
|
-
const markerDir = await mkdtemp(join(tmpdir(), 'host-lock-marker-'));
|
|
60
|
-
const acquiredMarker = join(markerDir, 'acquired');
|
|
61
|
-
const releaseMarker = join(markerDir, 'release');
|
|
62
|
-
const stderrChunks = [];
|
|
63
|
-
const holder = spawn('bash', [
|
|
64
|
-
hostLockScriptPath,
|
|
65
|
-
'--name',
|
|
66
|
-
hostLockName,
|
|
67
|
-
'--timeout-seconds',
|
|
68
|
-
String(hostLockTimeoutSeconds),
|
|
69
|
-
'--command-timeout-seconds',
|
|
70
|
-
String(hostLockCommandTimeoutSeconds),
|
|
71
|
-
'--',
|
|
72
|
-
'bash',
|
|
73
|
-
'-c',
|
|
74
|
-
'touch "$1"; while [ ! -e "$2" ]; do sleep 0.05; done',
|
|
75
|
-
'_',
|
|
76
|
-
acquiredMarker,
|
|
77
|
-
releaseMarker,
|
|
78
|
-
], { stdio: ['ignore', 'ignore', 'pipe'] });
|
|
79
|
-
holder.stderr?.on('data', (chunk) => stderrChunks.push(chunk));
|
|
80
|
-
const exited = new Promise((resolveExit) => {
|
|
81
|
-
holder.once('close', (code) => resolveExit(code));
|
|
82
|
-
});
|
|
83
|
-
const acquireTimeoutMs = (hostLockTimeoutSeconds + hostLockAcquireGraceSeconds) * 1000;
|
|
84
|
-
const acquired = await Promise.race([
|
|
85
|
-
waitForMarker(acquiredMarker, acquireTimeoutMs).then(() => true),
|
|
86
|
-
exited.then(() => false),
|
|
87
|
-
]);
|
|
88
|
-
if (!acquired) {
|
|
89
|
-
const code = await exited;
|
|
90
|
-
throw new Error(`with-host-lock exited before acquiring "${hostLockName}" (code ${code}): ${Buffer.concat(stderrChunks).toString('utf8')}`);
|
|
91
|
-
}
|
|
92
|
-
try {
|
|
93
|
-
return await body();
|
|
94
|
-
}
|
|
95
|
-
finally {
|
|
96
|
-
await releasePlaceholderAndAwaitExit(releaseMarker, exited);
|
|
97
|
-
await rm(markerDir, { force: true, recursive: true });
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
async function releasePlaceholderAndAwaitExit(releaseMarker, exited) {
|
|
101
|
-
await writeFile(releaseMarker, '');
|
|
102
|
-
await exited;
|
|
103
|
-
}
|