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.
Files changed (2) hide show
  1. package/dist/cli/index.js +172 -34
  2. 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 runLocalSuite(dir, cmd, budgetSecs) {
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: suiteEnv(scratch),
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 ?? ((dir) => isolated ? runContainerStage(verifierBackend, dir, cmd, budget) : runLocalSuite(dir, cmd, budget));
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 realpathSync8, rmSync as rmSync10, statSync as statSync6, writeFileSync as writeFileSync9 } from "node:fs";
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 = realpathSync8(candidate);
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 = realpathSync8(cwd);
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 realpathSync9,
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(realpathSync9(abs));
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 realpathSync10 } from "node:fs";
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 = realpathSync10(root);
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 = realpathSync10(dir);
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 realpathSync11, rmSync as rmSync13 } from "node:fs";
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 = realpathSync11(cwd) === realpathSync11(requestedCwd);
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 = realpathSync11(wt);
23352
- realTarget = realpathSync11(targetPath);
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 realpathSync12 } from "node:fs";
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 = realpathSync12.native(path);
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 = realpathSync12.native(pairsDir);
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 { ci: { verdict: "CANNOT_VERIFY", binding, binding_error: check2.reason }, exit: 2 };
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
- return { verdict: d.verdict, adjudicated_tree };
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.41.0",
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",