tamperward 2.29.14 → 2.29.15
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/dist/cli/index.js +48 -2
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -14640,6 +14640,7 @@ function parseCapturedSupervisorResult(stdoutText) {
|
|
|
14640
14640
|
signal: typeof raw.signal === "string" ? raw.signal : null,
|
|
14641
14641
|
timedOut: Boolean(raw.timedOut),
|
|
14642
14642
|
...typeof raw.error === "string" && raw.error ? { error: raw.error } : {},
|
|
14643
|
+
...raw.pipeHeldOpen === true ? { pipeHeldOpen: true } : {},
|
|
14643
14644
|
diagnostics
|
|
14644
14645
|
};
|
|
14645
14646
|
}
|
|
@@ -14657,6 +14658,7 @@ function runCapturedProcessSync(executable, args, opts) {
|
|
|
14657
14658
|
timeoutMs: opts.timeoutMs,
|
|
14658
14659
|
detached: Boolean(opts.detached),
|
|
14659
14660
|
killGroupOnFinish: Boolean(opts.killGroupOnFinish),
|
|
14661
|
+
drainMs: opts.drainMs ?? 1e3,
|
|
14660
14662
|
captureBytes: DIAGNOSTIC_TAIL_BYTES
|
|
14661
14663
|
}),
|
|
14662
14664
|
{ mode: 384 }
|
|
@@ -14789,6 +14791,7 @@ let done = false;
|
|
|
14789
14791
|
let timedOut = false;
|
|
14790
14792
|
let exitInfo = { exit: null, signal: null };
|
|
14791
14793
|
let descendantTracker = null;
|
|
14794
|
+
let drainTimer = null;
|
|
14792
14795
|
|
|
14793
14796
|
function killOwned() {
|
|
14794
14797
|
if (!child || !child.pid) return;
|
|
@@ -14810,6 +14813,7 @@ function finish(extra) {
|
|
|
14810
14813
|
if (done) return;
|
|
14811
14814
|
done = true;
|
|
14812
14815
|
if (descendantTracker) clearInterval(descendantTracker);
|
|
14816
|
+
if (drainTimer) clearTimeout(drainTimer);
|
|
14813
14817
|
try {
|
|
14814
14818
|
// stdout is reserved for the trusted supervisor result. Candidate suite
|
|
14815
14819
|
// stdout/stderr are separate pipes and are never inherited here.
|
|
@@ -14864,12 +14868,19 @@ if (child) {
|
|
|
14864
14868
|
signal: signal == null ? null : String(signal),
|
|
14865
14869
|
};
|
|
14866
14870
|
if (cfg.killGroupOnFinish) killOwned();
|
|
14871
|
+
// A leaked descendant can hold a pipe open so 'close' never fires; finish off
|
|
14872
|
+
// exit after a bounded drain instead of hanging. 'close' still wins if first.
|
|
14873
|
+
if (!drainTimer) {
|
|
14874
|
+
drainTimer = setTimeout(() => finish({ pipeHeldOpen: true }), Number(cfg.drainMs));
|
|
14875
|
+
drainTimer.unref();
|
|
14876
|
+
}
|
|
14867
14877
|
});
|
|
14868
14878
|
|
|
14869
14879
|
// close fires after the stdio pipes close, so the retained tails include all
|
|
14870
14880
|
// output that was drained before owned descendants were terminated.
|
|
14871
14881
|
child.on('close', (code, signal) => {
|
|
14872
14882
|
clearTimeout(timer);
|
|
14883
|
+
if (drainTimer) clearTimeout(drainTimer);
|
|
14873
14884
|
if (exitInfo.exit === null && code != null) exitInfo.exit = Number(code);
|
|
14874
14885
|
if (exitInfo.signal === null && signal != null) exitInfo.signal = String(signal);
|
|
14875
14886
|
finish({});
|
|
@@ -15714,7 +15725,12 @@ function runLocalSuite(dir, cmd, budgetSecs) {
|
|
|
15714
15725
|
diagnostics: r.diagnostics
|
|
15715
15726
|
};
|
|
15716
15727
|
}
|
|
15717
|
-
return {
|
|
15728
|
+
return {
|
|
15729
|
+
exit: r.exit,
|
|
15730
|
+
secs,
|
|
15731
|
+
...r.pipeHeldOpen ? { pipeHeldOpen: true } : {},
|
|
15732
|
+
diagnostics: r.diagnostics
|
|
15733
|
+
};
|
|
15718
15734
|
} finally {
|
|
15719
15735
|
rmSync7(scratch, { recursive: true, force: true });
|
|
15720
15736
|
}
|
|
@@ -15873,7 +15889,29 @@ function runVerify(opts) {
|
|
|
15873
15889
|
}
|
|
15874
15890
|
const frozenNodeModules = dependencyEnvironment ? dependencyEnvironment.roots.find((root) => root.kind === "node_modules")?.realPath ?? null : null;
|
|
15875
15891
|
const checkDeps = () => dependencyEnvironment ? checkDependencyEnvironment(cwd, dependencyEnvironment) : { ok: true };
|
|
15876
|
-
const runStage = (dir) => isolated ? runContainerStage(verifierBackend, dir, cmd, budget) : runLocalSuite(dir, cmd, budget);
|
|
15892
|
+
const runStage = opts.runStage ?? ((dir) => isolated ? runContainerStage(verifierBackend, dir, cmd, budget) : runLocalSuite(dir, cmd, budget));
|
|
15893
|
+
const notQuiescent = (stage, r) => {
|
|
15894
|
+
const detail = `the ${stage} suite exited (code ${r.exit ?? "unknown"}) but left a process holding stdout open after termination was attempted; the stage is not quiescent, so the run cannot be certified`;
|
|
15895
|
+
opts.onVerdict?.({ verdict: "CANNOT_VERIFY", reason: "VERIFIER_BACKEND_RUNTIME_FAILURE", detail });
|
|
15896
|
+
if (opts.json) {
|
|
15897
|
+
out3(JSON.stringify({
|
|
15898
|
+
schema_version: MACHINE_SCHEMA_VERSION,
|
|
15899
|
+
verdict: "CANNOT_VERIFY",
|
|
15900
|
+
reason: "VERIFIER_BACKEND_RUNTIME_FAILURE",
|
|
15901
|
+
stage,
|
|
15902
|
+
...caseReport(),
|
|
15903
|
+
detail,
|
|
15904
|
+
diagnostics: diagnosticsJson(r.diagnostics, true),
|
|
15905
|
+
verifier_backend: backendReport(),
|
|
15906
|
+
oracle_assurance: oracleAssuranceReport()
|
|
15907
|
+
}));
|
|
15908
|
+
} else {
|
|
15909
|
+
out3(`verify: the ${stage} suite exited but left a process holding stdout open \u2014 the stage is not quiescent, failing closed`);
|
|
15910
|
+
out3("verify: " + detail);
|
|
15911
|
+
renderStageDiagnostics(out3, stage, r);
|
|
15912
|
+
}
|
|
15913
|
+
return 2;
|
|
15914
|
+
};
|
|
15877
15915
|
let base;
|
|
15878
15916
|
try {
|
|
15879
15917
|
base = resolveBase(opts.base ?? "HEAD", cwd);
|
|
@@ -15933,6 +15971,10 @@ function runVerify(opts) {
|
|
|
15933
15971
|
);
|
|
15934
15972
|
}
|
|
15935
15973
|
const visible = runStage(visDir);
|
|
15974
|
+
if (visible.pipeHeldOpen) {
|
|
15975
|
+
cleanup([visRoot]);
|
|
15976
|
+
return notQuiescent("visible", visible);
|
|
15977
|
+
}
|
|
15936
15978
|
if (visible.failure === "backend" || visible.failure === "resource") {
|
|
15937
15979
|
cleanup([visRoot]);
|
|
15938
15980
|
const exhausted = visible.failure === "resource";
|
|
@@ -16002,6 +16044,10 @@ function runVerify(opts) {
|
|
|
16002
16044
|
}
|
|
16003
16045
|
const overlayBefore = overlayDigest(priDir, restored);
|
|
16004
16046
|
const pristine = runStage(priDir);
|
|
16047
|
+
if (pristine.pipeHeldOpen) {
|
|
16048
|
+
cleanup([visRoot, priRoot]);
|
|
16049
|
+
return notQuiescent("pristine", pristine);
|
|
16050
|
+
}
|
|
16005
16051
|
if (pristine.failure === "backend" || pristine.failure === "resource") {
|
|
16006
16052
|
cleanup([visRoot, priRoot]);
|
|
16007
16053
|
const exhausted = pristine.failure === "resource";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tamperward",
|
|
3
|
-
"version": "2.29.
|
|
3
|
+
"version": "2.29.15",
|
|
4
4
|
"description": "The deterministic agent-integrity gate. One ruleset, evaluated on the actual diff/commands as a verdict, enforced everywhere a change can be made.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "hexrift",
|