tamperward 2.41.0 → 2.43.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/dist/cli/index.js +172 -34
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -11328,7 +11328,7 @@ var init_signoff = __esm({
|
|
|
11328
11328
|
function machineOutput(payload) {
|
|
11329
11329
|
return { ...payload, schema_version: MACHINE_SCHEMA_VERSION };
|
|
11330
11330
|
}
|
|
11331
|
-
var MACHINE_SCHEMA_VERSION, VERIFY_VERDICTS, RUN_VERDICTS;
|
|
11331
|
+
var MACHINE_SCHEMA_VERSION, VERIFY_VERDICTS, VERIFY_CANNOT_VERIFY_REASONS, RUN_VERDICTS;
|
|
11332
11332
|
var init_machine_output = __esm({
|
|
11333
11333
|
"src/machine-output.ts"() {
|
|
11334
11334
|
"use strict";
|
|
@@ -11340,6 +11340,23 @@ var init_machine_output = __esm({
|
|
|
11340
11340
|
"BUDGET_EXCEEDED",
|
|
11341
11341
|
"CANNOT_VERIFY"
|
|
11342
11342
|
];
|
|
11343
|
+
VERIFY_CANNOT_VERIFY_REASONS = [
|
|
11344
|
+
"INVALID_ARGUMENTS",
|
|
11345
|
+
"POLICY_ERROR",
|
|
11346
|
+
"BASE_NOT_ANCESTOR",
|
|
11347
|
+
"NO_SUITE_COMMAND",
|
|
11348
|
+
"VERIFIER_BACKEND_UNAVAILABLE",
|
|
11349
|
+
"LOCAL_VERIFIER_UNSUPPORTED_PLATFORM",
|
|
11350
|
+
"DEPENDENCY_ENVIRONMENT_UNATTESTABLE",
|
|
11351
|
+
"BASE_UNRESOLVABLE",
|
|
11352
|
+
"DEPENDENCY_DRIFT",
|
|
11353
|
+
"MATERIALIZATION_FAILED",
|
|
11354
|
+
"VERIFIER_BACKEND_RUNTIME_FAILURE",
|
|
11355
|
+
"VERIFIER_RESOURCE_EXHAUSTED",
|
|
11356
|
+
"WORKTREE_CHANGED",
|
|
11357
|
+
"PRISTINE_INTEGRITY_CHANGED",
|
|
11358
|
+
"PATH_CASE_COLLISION"
|
|
11359
|
+
];
|
|
11343
11360
|
RUN_VERDICTS = [
|
|
11344
11361
|
"VERIFIED",
|
|
11345
11362
|
"AGENT_TIMEOUT",
|
|
@@ -15746,7 +15763,9 @@ function runCapturedProcessSync(executable, args, opts) {
|
|
|
15746
15763
|
detached: Boolean(opts.detached),
|
|
15747
15764
|
killGroupOnFinish: Boolean(opts.killGroupOnFinish),
|
|
15748
15765
|
drainMs: opts.drainMs ?? 1e3,
|
|
15749
|
-
captureBytes: DIAGNOSTIC_TAIL_BYTES
|
|
15766
|
+
captureBytes: DIAGNOSTIC_TAIL_BYTES,
|
|
15767
|
+
progressStage: opts.progressStage,
|
|
15768
|
+
progressIntervalMs: opts.progressIntervalMs
|
|
15750
15769
|
}),
|
|
15751
15770
|
{ mode: 384 }
|
|
15752
15771
|
);
|
|
@@ -15757,7 +15776,7 @@ function runCapturedProcessSync(executable, args, opts) {
|
|
|
15757
15776
|
cwd: opts.cwd,
|
|
15758
15777
|
env: opts.env,
|
|
15759
15778
|
encoding: "utf8",
|
|
15760
|
-
stdio: ["ignore", "pipe", "ignore"],
|
|
15779
|
+
stdio: ["ignore", "pipe", opts.progressStage ? "inherit" : "ignore"],
|
|
15761
15780
|
// The trusted result is at most two 16 KiB tails plus small metadata.
|
|
15762
15781
|
// A candidate that somehow writes into the supervisor's stdout through
|
|
15763
15782
|
// same-UID /proc can only overflow/corrupt this bounded channel and make
|
|
@@ -15911,6 +15930,16 @@ let timedOut = false;
|
|
|
15911
15930
|
let exitInfo = { exit: null, signal: null };
|
|
15912
15931
|
let descendantTracker = null;
|
|
15913
15932
|
let drainTimer = null;
|
|
15933
|
+
let progressTimer = null;
|
|
15934
|
+
const started = Date.now();
|
|
15935
|
+
function progress() {
|
|
15936
|
+
if (cfg.progressStage !== 'visible' && cfg.progressStage !== 'pristine') return;
|
|
15937
|
+
try {
|
|
15938
|
+
fs.writeSync(2, 'verify: ' + cfg.progressStage + ' suite running (' +
|
|
15939
|
+
Math.floor((Date.now() - started) / 1000) + 's; ' +
|
|
15940
|
+
(stdout.total + stderr.total) + ' output bytes captured)\n');
|
|
15941
|
+
} catch {}
|
|
15942
|
+
}
|
|
15914
15943
|
|
|
15915
15944
|
function killOwned() {
|
|
15916
15945
|
if (!child || !child.pid) return;
|
|
@@ -15933,6 +15962,7 @@ function finish(extra) {
|
|
|
15933
15962
|
done = true;
|
|
15934
15963
|
if (descendantTracker) clearInterval(descendantTracker);
|
|
15935
15964
|
if (drainTimer) clearTimeout(drainTimer);
|
|
15965
|
+
if (progressTimer) clearInterval(progressTimer);
|
|
15936
15966
|
// fd 1 is the reserved result channel (suite streams are separate pipes).
|
|
15937
15967
|
// Write synchronously: process.stdout.write is async on a POSIX pipe, so an
|
|
15938
15968
|
// immediate process.exit(0) can truncate the result before it flushes.
|
|
@@ -15971,6 +16001,11 @@ try {
|
|
|
15971
16001
|
}
|
|
15972
16002
|
|
|
15973
16003
|
if (child) {
|
|
16004
|
+
if (cfg.progressStage === 'visible' || cfg.progressStage === 'pristine') {
|
|
16005
|
+
progress();
|
|
16006
|
+
progressTimer = setInterval(progress, Number(cfg.progressIntervalMs) || 30000);
|
|
16007
|
+
progressTimer.unref();
|
|
16008
|
+
}
|
|
15974
16009
|
if (process.platform === 'linux') {
|
|
15975
16010
|
trackDescendants();
|
|
15976
16011
|
descendantTracker = setInterval(trackDescendants, 5);
|
|
@@ -16375,7 +16410,7 @@ function containerStateResult(state, secs) {
|
|
|
16375
16410
|
}
|
|
16376
16411
|
return { exit: state.ExitCode, secs };
|
|
16377
16412
|
}
|
|
16378
|
-
function runContainerStage(backend, dir, command, budgetSecs) {
|
|
16413
|
+
function runContainerStage(backend, dir, command, budgetSecs, progressStage) {
|
|
16379
16414
|
const t0 = Date.now();
|
|
16380
16415
|
if (backend.kind !== "container" || !backend.available || !backend.image || !backend.enginePath || !backend.engineSha256 || !backend.daemonHost || !engineStable(backend)) {
|
|
16381
16416
|
return {
|
|
@@ -16405,7 +16440,8 @@ function runContainerStage(backend, dir, command, budgetSecs) {
|
|
|
16405
16440
|
cwd: dirname7(backend.enginePath),
|
|
16406
16441
|
env: engineClientEnv(),
|
|
16407
16442
|
timeoutMs: budgetSecs * 1e3,
|
|
16408
|
-
backstopMs: 3e4
|
|
16443
|
+
backstopMs: 3e4,
|
|
16444
|
+
progressStage
|
|
16409
16445
|
}
|
|
16410
16446
|
);
|
|
16411
16447
|
const secs = Math.round((Date.now() - t0) / 1e3);
|
|
@@ -17148,7 +17184,7 @@ var init_verification_receipt = __esm({
|
|
|
17148
17184
|
// src/cli/verify.ts
|
|
17149
17185
|
import { execFileSync as execFileSync9, spawnSync as spawnSync3 } from "node:child_process";
|
|
17150
17186
|
import { createHash as createHash14 } from "node:crypto";
|
|
17151
|
-
import { chmodSync as chmodSync2, cpSync, lstatSync as lstatSync10, mkdirSync as mkdirSync10, mkdtempSync as mkdtempSync3, readFileSync as readFileSync13, readlinkSync as readlinkSync3, rmSync as rmSync9, symlinkSync, writeFileSync as writeFileSync8, existsSync as existsSync10 } from "node:fs";
|
|
17187
|
+
import { chmodSync as chmodSync2, cpSync, lstatSync as lstatSync10, mkdirSync as mkdirSync10, mkdtempSync as mkdtempSync3, readFileSync as readFileSync13, readlinkSync as readlinkSync3, realpathSync as realpathSync8, rmSync as rmSync9, symlinkSync, writeFileSync as writeFileSync8, existsSync as existsSync10 } from "node:fs";
|
|
17152
17188
|
import { tmpdir as tmpdir4 } from "node:os";
|
|
17153
17189
|
import { dirname as dirname10, isAbsolute as isAbsolute11, join as join22, relative as relative6, resolve as resolve9, sep as sep4 } from "node:path";
|
|
17154
17190
|
function oracleAssuranceReport() {
|
|
@@ -17491,7 +17527,28 @@ function localVerifierShell(platform = process.platform, command) {
|
|
|
17491
17527
|
return null;
|
|
17492
17528
|
}
|
|
17493
17529
|
}
|
|
17494
|
-
function
|
|
17530
|
+
function cargoStageTargets(root, cwd) {
|
|
17531
|
+
const absolute = resolve9(cwd, root);
|
|
17532
|
+
mkdirSync10(absolute, { recursive: true });
|
|
17533
|
+
const canonical2 = realpathSync8(absolute);
|
|
17534
|
+
const checkout = realpathSync8(cwd);
|
|
17535
|
+
const contains = (parent, child) => {
|
|
17536
|
+
const rel = relative6(parent, child);
|
|
17537
|
+
return rel === "" || !rel.startsWith(".." + sep4) && rel !== ".." && !isAbsolute11(rel);
|
|
17538
|
+
};
|
|
17539
|
+
if (contains(checkout, canonical2) || contains(canonical2, checkout)) {
|
|
17540
|
+
throw new Error("Cargo target root must be outside the checkout and cannot contain it");
|
|
17541
|
+
}
|
|
17542
|
+
const targets = { visible: join22(canonical2, "visible"), pristine: join22(canonical2, "pristine") };
|
|
17543
|
+
for (const target of Object.values(targets)) {
|
|
17544
|
+
mkdirSync10(target, { recursive: true });
|
|
17545
|
+
if (lstatSync10(target).isSymbolicLink() || realpathSync8(target) !== target) {
|
|
17546
|
+
throw new Error("Cargo stage targets must be distinct real directories, not links");
|
|
17547
|
+
}
|
|
17548
|
+
}
|
|
17549
|
+
return targets;
|
|
17550
|
+
}
|
|
17551
|
+
function runLocalSuite(dir, cmd, budgetSecs, stage, target, progress) {
|
|
17495
17552
|
const t0 = Date.now();
|
|
17496
17553
|
const shell = localVerifierShell(process.platform, cmd);
|
|
17497
17554
|
if (!shell) {
|
|
@@ -17504,13 +17561,26 @@ function runLocalSuite(dir, cmd, budgetSecs) {
|
|
|
17504
17561
|
}
|
|
17505
17562
|
const scratch = mkdtempSync3(join22(tmpdir4(), "tw-verify-run-"));
|
|
17506
17563
|
try {
|
|
17564
|
+
const env = suiteEnv(scratch);
|
|
17565
|
+
if (target) {
|
|
17566
|
+
let valid = false;
|
|
17567
|
+
try {
|
|
17568
|
+
valid = realpathSync8(target) === target && !lstatSync10(target).isSymbolicLink();
|
|
17569
|
+
} catch {
|
|
17570
|
+
}
|
|
17571
|
+
if (!valid) {
|
|
17572
|
+
return { exit: null, secs: 0, failure: "backend", reason: "Cargo stage target changed before execution" };
|
|
17573
|
+
}
|
|
17574
|
+
env.CARGO_TARGET_DIR = target;
|
|
17575
|
+
}
|
|
17507
17576
|
const r = runCapturedProcessSync(shell.executable, shell.args, {
|
|
17508
17577
|
cwd: dir,
|
|
17509
|
-
env
|
|
17578
|
+
env,
|
|
17510
17579
|
timeoutMs: budgetSecs * 1e3,
|
|
17511
17580
|
detached: true,
|
|
17512
17581
|
killGroupOnFinish: true,
|
|
17513
|
-
backstopMs: 3e4
|
|
17582
|
+
backstopMs: 3e4,
|
|
17583
|
+
progressStage: progress ? stage : void 0
|
|
17514
17584
|
});
|
|
17515
17585
|
const secs = Math.round((Date.now() - t0) / 1e3);
|
|
17516
17586
|
if (r.timedOut) {
|
|
@@ -17676,6 +17746,15 @@ function runVerifyImpl(opts) {
|
|
|
17676
17746
|
return 2;
|
|
17677
17747
|
}
|
|
17678
17748
|
const isolated = verifierBackend.kind === "container";
|
|
17749
|
+
let cargoTargets;
|
|
17750
|
+
if (opts.cargoTargetRoot !== void 0) {
|
|
17751
|
+
if (isolated) return cannotVerify("INVALID_ARGUMENTS", "--cargo-target-root is supported only by the checkpointed-local backend");
|
|
17752
|
+
try {
|
|
17753
|
+
cargoTargets = cargoStageTargets(opts.cargoTargetRoot, cwd);
|
|
17754
|
+
} catch (e) {
|
|
17755
|
+
return cannotVerify("INVALID_ARGUMENTS", `cannot configure Cargo stage targets (${e instanceof Error ? e.message : String(e)})`);
|
|
17756
|
+
}
|
|
17757
|
+
}
|
|
17679
17758
|
if (!isolated && !localVerifierShell(process.platform, cmd)) {
|
|
17680
17759
|
opts.onVerdict?.({ verdict: "CANNOT_VERIFY", reason: "LOCAL_VERIFIER_UNSUPPORTED_PLATFORM", detail: `checkpointed-local verifier is unsupported on ${process.platform}` });
|
|
17681
17760
|
if (opts.json) {
|
|
@@ -17719,7 +17798,7 @@ function runVerifyImpl(opts) {
|
|
|
17719
17798
|
}
|
|
17720
17799
|
const frozenNodeModules = dependencyEnvironment ? dependencyEnvironment.roots.find((root) => root.kind === "node_modules")?.realPath ?? null : null;
|
|
17721
17800
|
const checkDeps = () => dependencyEnvironment ? checkDependencyEnvironment(cwd, dependencyEnvironment) : { ok: true };
|
|
17722
|
-
const runStage = opts.runStage
|
|
17801
|
+
const runStage = (dir, stage) => opts.runStage ? opts.runStage(dir) : isolated ? runContainerStage(verifierBackend, dir, cmd, budget, opts.silent ? void 0 : stage) : runLocalSuite(dir, cmd, budget, stage, cargoTargets?.[stage], !opts.silent);
|
|
17723
17802
|
const notQuiescent = (stage, r) => {
|
|
17724
17803
|
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`;
|
|
17725
17804
|
opts.onVerdict?.({ verdict: "CANNOT_VERIFY", reason: "VERIFIER_BACKEND_RUNTIME_FAILURE", detail });
|
|
@@ -17800,7 +17879,7 @@ function runVerifyImpl(opts) {
|
|
|
17800
17879
|
{ verifier_backend: backendReport(), dependency_environment: dependencyReport(), oracle_assurance: oracleAssuranceReport(), materialization_reason: materializationFailureReason(e) }
|
|
17801
17880
|
);
|
|
17802
17881
|
}
|
|
17803
|
-
const visible = runStage(visDir);
|
|
17882
|
+
const visible = runStage(visDir, "visible");
|
|
17804
17883
|
if (visible.pipeHeldOpen) {
|
|
17805
17884
|
cleanup([visRoot]);
|
|
17806
17885
|
return notQuiescent("visible", visible);
|
|
@@ -17916,7 +17995,7 @@ function runVerifyImpl(opts) {
|
|
|
17916
17995
|
);
|
|
17917
17996
|
}
|
|
17918
17997
|
const overlayBefore = overlayDigest(priDir, restored);
|
|
17919
|
-
const pristine = runStage(priDir);
|
|
17998
|
+
const pristine = runStage(priDir, "pristine");
|
|
17920
17999
|
if (pristine.pipeHeldOpen) {
|
|
17921
18000
|
cleanup([visRoot, priRoot]);
|
|
17922
18001
|
return notQuiescent("pristine", pristine);
|
|
@@ -18092,13 +18171,14 @@ function parseVerify(args) {
|
|
|
18092
18171
|
if (a === "--json") o.json = true;
|
|
18093
18172
|
else if (a === "--keep") o.keep = true;
|
|
18094
18173
|
else if (a === "--require-ancestor") o.requireAncestor = true;
|
|
18095
|
-
else if (a === "--base" || a === "--cmd" || a === "--cwd" || a === "--budget") {
|
|
18174
|
+
else if (a === "--base" || a === "--cmd" || a === "--cwd" || a === "--budget" || a === "--cargo-target-root") {
|
|
18096
18175
|
const v = value(i, a);
|
|
18097
18176
|
if (v === void 0) continue;
|
|
18098
18177
|
i++;
|
|
18099
18178
|
if (a === "--base") o.base = v;
|
|
18100
18179
|
else if (a === "--cmd") o.cmd = v;
|
|
18101
18180
|
else if (a === "--cwd") o.cwd = v;
|
|
18181
|
+
else if (a === "--cargo-target-root") o.cargoTargetRoot = v;
|
|
18102
18182
|
else {
|
|
18103
18183
|
o.budget = Number(v);
|
|
18104
18184
|
if (!Number.isFinite(o.budget) || o.budget <= 0)
|
|
@@ -18222,7 +18302,7 @@ var init_verify = __esm({
|
|
|
18222
18302
|
// src/cli/run.ts
|
|
18223
18303
|
import { execFileSync as execFileSync10, spawn, spawnSync as spawnSync4 } from "node:child_process";
|
|
18224
18304
|
import { randomBytes as randomBytes3 } from "node:crypto";
|
|
18225
|
-
import { accessSync as accessSync3, constants as fsConstants, mkdtempSync as mkdtempSync4, readdirSync as readdirSync5, readFileSync as readFileSync14, readlinkSync as readlinkSync4, realpathSync as
|
|
18305
|
+
import { accessSync as accessSync3, constants as fsConstants, mkdtempSync as mkdtempSync4, readdirSync as readdirSync5, readFileSync as readFileSync14, readlinkSync as readlinkSync4, realpathSync as realpathSync9, rmSync as rmSync10, statSync as statSync6, writeFileSync as writeFileSync9 } from "node:fs";
|
|
18226
18306
|
import { tmpdir as tmpdir5 } from "node:os";
|
|
18227
18307
|
import { dirname as dirname11, join as join23, resolve as resolve10 } from "node:path";
|
|
18228
18308
|
function authoritativeRunLifecyclePlatform(platform = process.platform) {
|
|
@@ -18277,7 +18357,7 @@ function trustedLinuxPython(candidates = DEFAULT_TRUSTED_PYTHON_CANDIDATES) {
|
|
|
18277
18357
|
}
|
|
18278
18358
|
for (const candidate of candidates) {
|
|
18279
18359
|
try {
|
|
18280
|
-
const real =
|
|
18360
|
+
const real = realpathSync9(candidate);
|
|
18281
18361
|
const st = statSync6(real);
|
|
18282
18362
|
if (!st.isFile() || writableByCaller2(real)) continue;
|
|
18283
18363
|
const probe = spawnSync4(
|
|
@@ -18550,7 +18630,7 @@ function survivorsHoldingTree(cwd, spawnedAfterTicks) {
|
|
|
18550
18630
|
const out3 = [];
|
|
18551
18631
|
let real;
|
|
18552
18632
|
try {
|
|
18553
|
-
real =
|
|
18633
|
+
real = realpathSync9(cwd);
|
|
18554
18634
|
} catch {
|
|
18555
18635
|
return out3;
|
|
18556
18636
|
}
|
|
@@ -19965,7 +20045,7 @@ import {
|
|
|
19965
20045
|
mkdtempSync as mkdtempSync5,
|
|
19966
20046
|
readFileSync as readFileSync16,
|
|
19967
20047
|
readdirSync as readdirSync7,
|
|
19968
|
-
realpathSync as
|
|
20048
|
+
realpathSync as realpathSync10,
|
|
19969
20049
|
rmSync as rmSync11,
|
|
19970
20050
|
symlinkSync as symlinkSync2
|
|
19971
20051
|
} from "node:fs";
|
|
@@ -20238,7 +20318,7 @@ function rewriteTraceRoot(accesses, actualRoot) {
|
|
|
20238
20318
|
if (!inside3(actualRoot, abs)) return { ...item, path: abs };
|
|
20239
20319
|
const rel = relative7(actualRoot, abs).split(sep5).join("/");
|
|
20240
20320
|
try {
|
|
20241
|
-
const real = resolve12(
|
|
20321
|
+
const real = resolve12(realpathSync10(abs));
|
|
20242
20322
|
if (!inside3(actualRoot, real)) return { ...item, path: real };
|
|
20243
20323
|
} catch {
|
|
20244
20324
|
}
|
|
@@ -21475,7 +21555,7 @@ var init_adapter3 = __esm({
|
|
|
21475
21555
|
|
|
21476
21556
|
// src/adapters/copilot-sdk/changes.ts
|
|
21477
21557
|
import { execFileSync as execFileSync13 } from "node:child_process";
|
|
21478
|
-
import { mkdtempSync as mkdtempSync6, writeFileSync as writeFileSync10, readFileSync as readFileSync17, rmSync as rmSync12, existsSync as existsSync13, realpathSync as
|
|
21558
|
+
import { mkdtempSync as mkdtempSync6, writeFileSync as writeFileSync10, readFileSync as readFileSync17, rmSync as rmSync12, existsSync as existsSync13, realpathSync as realpathSync11 } from "node:fs";
|
|
21479
21559
|
import { tmpdir as tmpdir7 } from "node:os";
|
|
21480
21560
|
import { basename as basename5, dirname as dirname12, isAbsolute as isAbsolute16, relative as relative11, resolve as resolve15, join as join26 } from "node:path";
|
|
21481
21561
|
function asStr4(v) {
|
|
@@ -21488,7 +21568,7 @@ function relForDisplay5(path, cwd) {
|
|
|
21488
21568
|
function canonicalContainedTarget(abs, root) {
|
|
21489
21569
|
let realRoot;
|
|
21490
21570
|
try {
|
|
21491
|
-
realRoot =
|
|
21571
|
+
realRoot = realpathSync11(root);
|
|
21492
21572
|
} catch (e) {
|
|
21493
21573
|
throw new Error(`trusted repository root ${root} cannot be resolved: ${e instanceof Error ? e.message : String(e)}`);
|
|
21494
21574
|
}
|
|
@@ -21502,7 +21582,7 @@ function canonicalContainedTarget(abs, root) {
|
|
|
21502
21582
|
}
|
|
21503
21583
|
let realDir;
|
|
21504
21584
|
try {
|
|
21505
|
-
realDir =
|
|
21585
|
+
realDir = realpathSync11(dir);
|
|
21506
21586
|
} catch (e) {
|
|
21507
21587
|
throw new Error(`write target ${abs} cannot be resolved: ${e instanceof Error ? e.message : String(e)}`);
|
|
21508
21588
|
}
|
|
@@ -22832,7 +22912,7 @@ var init_runtime = __esm({
|
|
|
22832
22912
|
|
|
22833
22913
|
// src/cli/onboard.ts
|
|
22834
22914
|
import { execFileSync as execFileSync15 } from "node:child_process";
|
|
22835
|
-
import { lstatSync as lstatSync11, mkdtempSync as mkdtempSync7, readFileSync as readFileSync19, realpathSync as
|
|
22915
|
+
import { lstatSync as lstatSync11, mkdtempSync as mkdtempSync7, readFileSync as readFileSync19, realpathSync as realpathSync12, rmSync as rmSync13 } from "node:fs";
|
|
22836
22916
|
import { tmpdir as tmpdir8 } from "node:os";
|
|
22837
22917
|
import { join as join28, relative as relative12, resolve as resolve16, sep as sep6 } from "node:path";
|
|
22838
22918
|
import { createInterface } from "node:readline";
|
|
@@ -22965,7 +23045,7 @@ async function runOnboard(opts, io = {}) {
|
|
|
22965
23045
|
const cwd = resolve16(rootText);
|
|
22966
23046
|
let sameRoot = cwd === requestedCwd;
|
|
22967
23047
|
try {
|
|
22968
|
-
sameRoot =
|
|
23048
|
+
sameRoot = realpathSync12(cwd) === realpathSync12(requestedCwd);
|
|
22969
23049
|
} catch {
|
|
22970
23050
|
}
|
|
22971
23051
|
if (!sameRoot) {
|
|
@@ -23348,8 +23428,8 @@ function runDemo(cwd, head, runners, out3) {
|
|
|
23348
23428
|
let worktreeRoot;
|
|
23349
23429
|
let realTarget;
|
|
23350
23430
|
try {
|
|
23351
|
-
worktreeRoot =
|
|
23352
|
-
realTarget =
|
|
23431
|
+
worktreeRoot = realpathSync12(wt);
|
|
23432
|
+
realTarget = realpathSync12(targetPath);
|
|
23353
23433
|
} catch {
|
|
23354
23434
|
out3("Demo skipped: the selected test could not be resolved safely inside the disposable worktree.");
|
|
23355
23435
|
return;
|
|
@@ -24599,7 +24679,7 @@ var init_run2 = __esm({
|
|
|
24599
24679
|
});
|
|
24600
24680
|
|
|
24601
24681
|
// src/research/ledger-files.ts
|
|
24602
|
-
import { closeSync as closeSync6, constants as constants5, fstatSync as fstatSync3, lstatSync as lstatSync12, openSync as openSync5, readFileSync as readFileSync23, readdirSync as readdirSync8, realpathSync as
|
|
24682
|
+
import { closeSync as closeSync6, constants as constants5, fstatSync as fstatSync3, lstatSync as lstatSync12, openSync as openSync5, readFileSync as readFileSync23, readdirSync as readdirSync8, realpathSync as realpathSync13 } from "node:fs";
|
|
24603
24683
|
import { join as join30, resolve as resolve20 } from "node:path";
|
|
24604
24684
|
function lstatOrNull(path) {
|
|
24605
24685
|
try {
|
|
@@ -24625,7 +24705,7 @@ function readRegularFile(path, realPairsDir, name) {
|
|
|
24625
24705
|
if (listed.nlink !== 1) {
|
|
24626
24706
|
throw new ResearchError(`ledger record ${path} has ${listed.nlink} links; a hard link can name a file outside pairs/, so only a singly linked regular file is read`);
|
|
24627
24707
|
}
|
|
24628
|
-
const real =
|
|
24708
|
+
const real = realpathSync13.native(path);
|
|
24629
24709
|
if (real !== join30(realPairsDir, name)) {
|
|
24630
24710
|
throw new ResearchError(`ledger record ${path} resolves outside the pairs directory (${real}); refusing to read it`);
|
|
24631
24711
|
}
|
|
@@ -24655,7 +24735,7 @@ function readPairFiles(ledger) {
|
|
|
24655
24735
|
throw new ResearchError(`ledger pairs directory ${pairsDir} is a symlink; only a real directory is read`);
|
|
24656
24736
|
}
|
|
24657
24737
|
if (dirStat === null || !dirStat.isDirectory()) throw new ResearchError(`ledger ${root} has no pairs directory`);
|
|
24658
|
-
const realPairsDir =
|
|
24738
|
+
const realPairsDir = realpathSync13.native(pairsDir);
|
|
24659
24739
|
let names;
|
|
24660
24740
|
try {
|
|
24661
24741
|
names = readdirSync8(pairsDir).filter((n2) => n2.endsWith(".json")).sort();
|
|
@@ -25281,6 +25361,41 @@ var init_research = __esm({
|
|
|
25281
25361
|
}
|
|
25282
25362
|
});
|
|
25283
25363
|
|
|
25364
|
+
// src/cli/render/verify-github.ts
|
|
25365
|
+
function safeDetail(value) {
|
|
25366
|
+
const normalized = value.replace(/[\u0000-\u001f\u007f-\u009f]/g, " ").replace(/\s+/g, " ").trim();
|
|
25367
|
+
if (normalized.length <= DETAIL_LIMIT) return normalized;
|
|
25368
|
+
return normalized.slice(0, DETAIL_LIMIT - 1).trimEnd() + "\u2026";
|
|
25369
|
+
}
|
|
25370
|
+
function workflowData(value) {
|
|
25371
|
+
return value.replace(/%/g, "%25").replace(/\r/g, "%0D").replace(/\n/g, "%0A");
|
|
25372
|
+
}
|
|
25373
|
+
function verifyWorkflowCommand(verdict2, exitCode, details = {}, env = process.env) {
|
|
25374
|
+
if (env.GITHUB_ACTIONS !== "true" || verdict2 === "VERIFIED") return void 0;
|
|
25375
|
+
if (verdict2 === "MASKED_FAILURE" && exitCode === 0) {
|
|
25376
|
+
return "::warning title=TamperWard verify::MASKED_FAILURE: a trusted out-of-band sign-off was accepted; this is not a VERIFIED result. Review the verification summary.";
|
|
25377
|
+
}
|
|
25378
|
+
const parts = [ERROR_MESSAGES[verdict2]];
|
|
25379
|
+
if (verdict2 === "CANNOT_VERIFY") {
|
|
25380
|
+
if (details.reason) parts.push(`Reason: ${details.reason}`);
|
|
25381
|
+
if (details.detail) parts.push(`Detail: ${safeDetail(details.detail)}`);
|
|
25382
|
+
}
|
|
25383
|
+
return `::error title=TamperWard verify::${workflowData(parts.join("\n"))}`;
|
|
25384
|
+
}
|
|
25385
|
+
var ERROR_MESSAGES, DETAIL_LIMIT;
|
|
25386
|
+
var init_verify_github = __esm({
|
|
25387
|
+
"src/cli/render/verify-github.ts"() {
|
|
25388
|
+
"use strict";
|
|
25389
|
+
ERROR_MESSAGES = {
|
|
25390
|
+
MASKED_FAILURE: "MASKED_FAILURE: the visible suite passed, but the suite restored from the trusted base failed. Review the test changes and verification summary.",
|
|
25391
|
+
SUITE_RED: "SUITE_RED: the visible suite failed. Fix the failing change before merging.",
|
|
25392
|
+
BUDGET_EXCEEDED: "BUDGET_EXCEEDED: verification exceeded its configured budget; CI could not establish a clean result.",
|
|
25393
|
+
CANNOT_VERIFY: "CANNOT_VERIFY: CI could not establish a trusted verification result."
|
|
25394
|
+
};
|
|
25395
|
+
DETAIL_LIMIT = 320;
|
|
25396
|
+
}
|
|
25397
|
+
});
|
|
25398
|
+
|
|
25284
25399
|
// src/cli/receipt.ts
|
|
25285
25400
|
import { appendFileSync as appendFileSync3, readFileSync as readFileSync26, writeFileSync as writeFileSync14 } from "node:fs";
|
|
25286
25401
|
function parseReceipt(args) {
|
|
@@ -25413,12 +25528,17 @@ function ciAdjudicate(cwd, opts) {
|
|
|
25413
25528
|
} catch (e) {
|
|
25414
25529
|
return {
|
|
25415
25530
|
ci: { verdict: "CANNOT_VERIFY", binding, binding_error: `unreadable CI verify result: ${e instanceof Error ? e.message : String(e)}` },
|
|
25416
|
-
exit: 2
|
|
25531
|
+
exit: 2,
|
|
25532
|
+
annotation: { detail: "The CI verify result could not be read. Check the verify step output and artifact path." }
|
|
25417
25533
|
};
|
|
25418
25534
|
}
|
|
25419
25535
|
const check2 = readCiVerify(doc, binding, cwd, opts);
|
|
25420
25536
|
if (check2.reason !== void 0) {
|
|
25421
|
-
return {
|
|
25537
|
+
return {
|
|
25538
|
+
ci: { verdict: "CANNOT_VERIFY", binding, binding_error: check2.reason },
|
|
25539
|
+
exit: 2,
|
|
25540
|
+
annotation: { detail: check2.reason }
|
|
25541
|
+
};
|
|
25422
25542
|
}
|
|
25423
25543
|
const oob = oobFromEnv();
|
|
25424
25544
|
const oobHead = oobHeadFromEnv();
|
|
@@ -25433,7 +25553,8 @@ function ciAdjudicate(cwd, opts) {
|
|
|
25433
25553
|
...check2.adjudicated_tree !== void 0 ? { adjudicated_tree: check2.adjudicated_tree } : {},
|
|
25434
25554
|
...bindingError ? { binding_error: bindingError } : {}
|
|
25435
25555
|
},
|
|
25436
|
-
exit: verdictExit(check2.verdict, signedOff)
|
|
25556
|
+
exit: verdictExit(check2.verdict, signedOff),
|
|
25557
|
+
annotation: { reason: check2.verifierReason, detail: check2.detail }
|
|
25437
25558
|
};
|
|
25438
25559
|
}
|
|
25439
25560
|
const impl = opts.runVerifyImpl ?? runVerify;
|
|
@@ -25458,7 +25579,8 @@ function ciAdjudicate(cwd, opts) {
|
|
|
25458
25579
|
...binding ? { adjudicated_tree: binding.tree } : {},
|
|
25459
25580
|
...bindingError ? { binding_error: bindingError } : {}
|
|
25460
25581
|
},
|
|
25461
|
-
exit
|
|
25582
|
+
exit,
|
|
25583
|
+
annotation: { reason: summary?.reason, detail: summary?.detail }
|
|
25462
25584
|
};
|
|
25463
25585
|
}
|
|
25464
25586
|
function isCommitId(v) {
|
|
@@ -25492,7 +25614,9 @@ function readCiVerify(doc, binding, cwd, opts) {
|
|
|
25492
25614
|
}
|
|
25493
25615
|
}
|
|
25494
25616
|
const adjudicated_tree = typeof d.adjudicated_tree === "string" && d.adjudicated_tree.length > 0 ? d.adjudicated_tree : void 0;
|
|
25495
|
-
|
|
25617
|
+
const verifierReason = isOneOf(VERIFY_CANNOT_VERIFY_REASONS, d.reason) ? d.reason : void 0;
|
|
25618
|
+
const detail = typeof d.detail === "string" ? d.detail : void 0;
|
|
25619
|
+
return { verdict: d.verdict, verifierReason, detail, adjudicated_tree };
|
|
25496
25620
|
}
|
|
25497
25621
|
function isRecordObject(v) {
|
|
25498
25622
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
@@ -25571,7 +25695,7 @@ function runReceiptReconcile(opts = {}) {
|
|
|
25571
25695
|
const cwd = opts.cwd ?? process.cwd();
|
|
25572
25696
|
const guard = needRepo(cwd, "reconcile");
|
|
25573
25697
|
if (guard !== null) return guard;
|
|
25574
|
-
const { ci, exit } = ciAdjudicate(cwd, opts);
|
|
25698
|
+
const { ci, exit, annotation: annotationDetails } = ciAdjudicate(cwd, opts);
|
|
25575
25699
|
const claimed = loadClaimedReceipt(opts.receipt);
|
|
25576
25700
|
const r = reconcile(ci, claimed);
|
|
25577
25701
|
const claimedReceipt = claimed.disposition === "PRESENT" ? claimed.receipt : null;
|
|
@@ -25581,6 +25705,16 @@ function runReceiptReconcile(opts = {}) {
|
|
|
25581
25705
|
process.stdout.write(renderReconcile(r, claimedReceipt, ci.binding, ci.adjudicated_tree, colourEnabled(process.env, process.stdout)));
|
|
25582
25706
|
}
|
|
25583
25707
|
writeJobSummary(r, claimedReceipt, ci.binding, ci.adjudicated_tree);
|
|
25708
|
+
if (!opts.json) {
|
|
25709
|
+
const annotation = verifyWorkflowCommand(ci.verdict, exit, annotationDetails);
|
|
25710
|
+
if (annotation) process.stdout.write(`${annotation}
|
|
25711
|
+
`);
|
|
25712
|
+
}
|
|
25713
|
+
if (!opts.json) {
|
|
25714
|
+
const annotation = verifyWorkflowCommand(ci.verdict, exit);
|
|
25715
|
+
if (annotation) process.stdout.write(`${annotation}
|
|
25716
|
+
`);
|
|
25717
|
+
}
|
|
25584
25718
|
return exit;
|
|
25585
25719
|
}
|
|
25586
25720
|
function writeJobSummary(r, receipt, ciBinding, adjudicatedTree) {
|
|
@@ -25621,6 +25755,7 @@ var init_receipt = __esm({
|
|
|
25621
25755
|
init_verify();
|
|
25622
25756
|
init_signoff();
|
|
25623
25757
|
init_text();
|
|
25758
|
+
init_verify_github();
|
|
25624
25759
|
init_status();
|
|
25625
25760
|
RECEIPT_SUBCOMMANDS = ["export", "reconcile"];
|
|
25626
25761
|
AGREEMENT_SEVERITY = {
|
|
@@ -25979,6 +26114,7 @@ function validateCliArgs(cmd, args) {
|
|
|
25979
26114
|
"--base": "string",
|
|
25980
26115
|
"--cmd": "string",
|
|
25981
26116
|
"--cwd": "string",
|
|
26117
|
+
"--cargo-target-root": "string",
|
|
25982
26118
|
"--budget": "positive"
|
|
25983
26119
|
}
|
|
25984
26120
|
}).error;
|
|
@@ -26156,6 +26292,8 @@ Formats:
|
|
|
26156
26292
|
(exit 1, or 0 under a compact tw1:<digest>
|
|
26157
26293
|
or legacy verify@<full-sha> approval); cannot-verify
|
|
26158
26294
|
fails closed (2)
|
|
26295
|
+
[--cargo-target-root D] separate local Cargo targets D/visible
|
|
26296
|
+
and D/pristine (operator-owned cache)
|
|
26159
26297
|
tamperward trace-verify [--base R] advisory Linux verifier-input discovery:
|
|
26160
26298
|
[--cmd C] [--budget S] [--runs N] trace a trusted/known-good base with
|
|
26161
26299
|
[--json] [--cwd D] strace, union repeated observations,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tamperward",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.43.0",
|
|
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",
|