tamperward 2.30.2 → 2.30.4

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 +121 -88
  2. package/package.json +1 -1
package/dist/cli/index.js CHANGED
@@ -866,10 +866,10 @@ function headerPaths(line) {
866
866
  first = rest.slice(0, mid);
867
867
  rest = rest.slice(mid + 1);
868
868
  } else {
869
- const m = rest.match(/^(.*) (b\/.*)$/);
870
- if (!m) return [null, null];
871
- first = m[1];
872
- rest = m[2];
869
+ const at = rest.lastIndexOf(" b/");
870
+ if (at < 0) return [null, null];
871
+ first = rest.slice(0, at);
872
+ rest = rest.slice(at + 1);
873
873
  }
874
874
  }
875
875
  }
@@ -2874,7 +2874,6 @@ function expandShellPath(t, env = process.env) {
2874
2874
  function hookTests(policy, ctx) {
2875
2875
  const cwd = ctx?.cwd;
2876
2876
  const diskCwd = cwd !== void 0 && existsSync3(cwd) ? cwd : void 0;
2877
- const onDisk = diskCwd !== void 0;
2878
2877
  const root = diskCwd !== void 0 ? canonicalPath(diskCwd) : cwd;
2879
2878
  const memo = /* @__PURE__ */ new Map();
2880
2879
  const rel = (t) => {
@@ -2938,7 +2937,7 @@ function shellHookTarget(seg, toks, policy, ctx) {
2938
2937
  return null;
2939
2938
  }
2940
2939
  function shellWritesHook(seg, toks, policy, ctx) {
2941
- const { rel, hook, whole, holds, hookish } = hookTests(policy, ctx);
2940
+ const { hook, whole, holds, hookish } = hookTests(policy, ctx);
2942
2941
  for (const m of seg.matchAll(REDIRECT_TARGET)) {
2943
2942
  if (hook(m[1])) return "a redirect empties or rewrites a protected hook";
2944
2943
  }
@@ -2947,7 +2946,6 @@ function shellWritesHook(seg, toks, policy, ctx) {
2947
2946
  const cmd = (toks[at] ?? "").replace(/^.*\//, "");
2948
2947
  const args = toks.slice(at + 1);
2949
2948
  const positional = args.filter((a) => a !== "--" && !a.startsWith("-"));
2950
- const last = positional[positional.length - 1] ?? "";
2951
2949
  const anyHook = args.some(hook);
2952
2950
  const inPlace = args.some((a) => /^-[A-Za-z]*i|^--in-place/.test(a));
2953
2951
  const scripts = args.filter((_, i) => i > 0 && INLINE_FLAG.test(args[i - 1]));
@@ -11157,7 +11155,7 @@ function annotations(findings) {
11157
11155
  });
11158
11156
  }
11159
11157
  function cell(s) {
11160
- return stripControl(s).replace(/\s+/g, " ").replace(/\|/g, "\\|").trim();
11158
+ return stripControl(s).replace(/\s+/g, " ").replace(/\\/g, "\\\\").replace(/\|/g, "\\|").trim();
11161
11159
  }
11162
11160
  function mdCode(s) {
11163
11161
  return s.replace(/`/g, "'").replace(/[\r\n]/g, " ");
@@ -14525,7 +14523,7 @@ function freezeRoot(kind, path) {
14525
14523
  }
14526
14524
  }
14527
14525
  function shellTokens(command) {
14528
- const matches = command.match(/(?:[^\s"'\\]+|"(?:\\.|[^"])*"|'[^']*')+/g) ?? [];
14526
+ const matches = command.match(/(?:[^\s"'\\]|"[^"\\]*(?:\\.[^"\\]*)*"|'[^']*')+/g) ?? [];
14529
14527
  return matches.map((token) => {
14530
14528
  if (token.startsWith("'") && token.endsWith("'") || token.startsWith('"') && token.endsWith('"')) return token.slice(1, -1);
14531
14529
  return token;
@@ -14884,7 +14882,7 @@ function runCapturedProcessSync(executable, args, opts) {
14884
14882
  rmSync6(stateDir, { recursive: true, force: true });
14885
14883
  }
14886
14884
  }
14887
- var DIAGNOSTIC_TAIL_BYTES, EMPTY_STREAM, CAPTURE_SUPERVISOR;
14885
+ var DIAGNOSTIC_TAIL_BYTES, EMPTY_STREAM, CLEANUP_HELPERS_SRC, CAPTURE_SUPERVISOR;
14888
14886
  var init_suite_diagnostics = __esm({
14889
14887
  "src/suite-diagnostics.ts"() {
14890
14888
  "use strict";
@@ -14896,40 +14894,32 @@ var init_suite_diagnostics = __esm({
14896
14894
  truncated: false,
14897
14895
  tail: ""
14898
14896
  };
14899
- CAPTURE_SUPERVISOR = String.raw`
14900
- const cp = require('node:child_process');
14901
- const fs = require('node:fs');
14902
-
14903
- const [configFile] = process.argv.slice(1);
14904
- const cfg = JSON.parse(fs.readFileSync(configFile, 'utf8'));
14905
- const CAP = Number(cfg.captureBytes);
14906
-
14907
- const fresh = () => ({ total: 0, tail: Buffer.alloc(0) });
14908
- const stdout = fresh();
14909
- const stderr = fresh();
14910
-
14911
- // Linux ordinary-exit hardening (#371): process-group ownership alone misses a
14912
- // descendant that calls setsid(). Track the real descendant tree while the
14913
- // suite is alive so a reparented session escape is still known when the main
14914
- // child exits. This supplements, rather than replaces, group termination.
14915
- const trackedDescendants = new Set();
14897
+ CLEANUP_HELPERS_SRC = String.raw`
14898
+ function readStat(pid) {
14899
+ try {
14900
+ const stat = fs.readFileSync('/proc/' + pid + '/stat', 'utf8');
14901
+ const fields = stat.slice(stat.lastIndexOf(')') + 2).split(' ');
14902
+ const ppid = Number(fields[1]);
14903
+ const starttime = fields[19];
14904
+ if (!Number.isFinite(ppid) || starttime === undefined) return null;
14905
+ return { ppid: ppid, starttime: starttime };
14906
+ } catch (e) { return null; }
14907
+ }
14916
14908
 
14917
14909
  function linuxDescendants(rootPid) {
14918
14910
  if (process.platform !== 'linux' || !rootPid) return [];
14919
14911
  const byParent = new Map();
14912
+ const startById = new Map();
14920
14913
  let names = [];
14921
- try { names = fs.readdirSync('/proc').filter((x) => /^\d+$/.test(x)); } catch { return []; }
14914
+ try { names = fs.readdirSync('/proc').filter((x) => /^\d+$/.test(x)); } catch (e) { return []; }
14922
14915
  for (const name of names) {
14923
14916
  const pid = Number(name);
14924
- try {
14925
- const stat = fs.readFileSync('/proc/' + name + '/stat', 'utf8');
14926
- const fields = stat.slice(stat.lastIndexOf(')') + 2).split(' ');
14927
- const ppid = Number(fields[1]);
14928
- if (!Number.isFinite(ppid)) continue;
14929
- const kids = byParent.get(ppid) || [];
14930
- kids.push(pid);
14931
- byParent.set(ppid, kids);
14932
- } catch {}
14917
+ const st = readStat(pid);
14918
+ if (!st) continue;
14919
+ startById.set(pid, st.starttime);
14920
+ const kids = byParent.get(st.ppid) || [];
14921
+ kids.push(pid);
14922
+ byParent.set(st.ppid, kids);
14933
14923
  }
14934
14924
  const out = [];
14935
14925
  const seen = new Set([rootPid]);
@@ -14939,16 +14929,56 @@ function linuxDescendants(rootPid) {
14939
14929
  for (const pid of (byParent.get(parent) || [])) {
14940
14930
  if (seen.has(pid)) continue;
14941
14931
  seen.add(pid);
14942
- out.push(pid);
14932
+ out.push({ pid: pid, starttime: startById.get(pid) });
14943
14933
  stack.push(pid);
14944
14934
  }
14945
14935
  }
14946
14936
  return out;
14947
14937
  }
14948
14938
 
14939
+ function killableDescendants(tracked) {
14940
+ const out = [];
14941
+ for (const entry of tracked) {
14942
+ const pid = entry[0];
14943
+ const starttime = entry[1];
14944
+ const st = readStat(pid);
14945
+ if (st && st.starttime === starttime) out.push(pid);
14946
+ }
14947
+ return out;
14948
+ }
14949
+
14950
+ function cleanupPlan(child, cfg, platform, killable) {
14951
+ const live = !!child && child.exitCode === null && child.signalCode === null;
14952
+ return {
14953
+ signalGroup: !!(live && cfg.detached && platform !== 'win32'),
14954
+ signalMainChild: live,
14955
+ descendants: platform === 'linux' ? killable() : [],
14956
+ };
14957
+ }
14958
+ `;
14959
+ CAPTURE_SUPERVISOR = String.raw`
14960
+ const cp = require('node:child_process');
14961
+ const fs = require('node:fs');
14962
+
14963
+ const [configFile] = process.argv.slice(1);
14964
+ const cfg = JSON.parse(fs.readFileSync(configFile, 'utf8'));
14965
+ const CAP = Number(cfg.captureBytes);
14966
+
14967
+ const fresh = () => ({ total: 0, tail: Buffer.alloc(0) });
14968
+ const stdout = fresh();
14969
+ const stderr = fresh();
14970
+
14971
+ // Linux ordinary-exit hardening (#371): process-group ownership alone misses a
14972
+ // descendant that calls setsid(). Track the real descendant tree while the
14973
+ // suite is alive so a reparented session escape is still known when the main
14974
+ // child exits. This supplements, rather than replaces, group termination.
14975
+ // pid -> the /proc start-time observed for that pid, so cleanup can re-check
14976
+ // identity before signalling (a bare pid alone can be reused — #545).
14977
+ const trackedDescendants = new Map();
14978
+ ${CLEANUP_HELPERS_SRC}
14949
14979
  function trackDescendants() {
14950
14980
  if (!child || !child.pid || process.platform !== 'linux') return;
14951
- for (const pid of linuxDescendants(child.pid)) trackedDescendants.add(pid);
14981
+ for (const d of linuxDescendants(child.pid)) trackedDescendants.set(d.pid, d.starttime);
14952
14982
  }
14953
14983
 
14954
14984
  function append(state, chunk) {
@@ -14983,17 +15013,17 @@ let drainTimer = null;
14983
15013
  function killOwned() {
14984
15014
  if (!child || !child.pid) return;
14985
15015
  trackDescendants();
14986
- if (cfg.detached && process.platform !== 'win32') {
14987
- try { process.kill(-child.pid, 'SIGKILL'); } catch {}
14988
- }
14989
- try { child.kill('SIGKILL'); } catch {}
14990
- if (process.platform === 'linux') {
14991
- // Deepest-first is friendlier to short-lived process trees. PIDs are still
14992
- // rechecked by kill(2); races with natural exit are harmless.
14993
- for (const pid of Array.from(trackedDescendants).reverse()) {
14994
- try { process.kill(pid, 'SIGKILL'); } catch {}
14995
- }
14996
- }
15016
+ // The main child and its detached group are signalled only while the child is
15017
+ // still reported live: after its exit event the pid can be reused, and both
15018
+ // child.kill() and kill(-pid) resolve the current bearer of that number (#545).
15019
+ // Descendants are the independently identity-checked set (deepest-first, which
15020
+ // is friendlier to short-lived process trees).
15021
+ const plan = cleanupPlan(child, cfg, process.platform, function () {
15022
+ return killableDescendants(Array.from(trackedDescendants).reverse());
15023
+ });
15024
+ if (plan.signalGroup) { try { process.kill(-child.pid, 'SIGKILL'); } catch {} }
15025
+ if (plan.signalMainChild) { try { child.kill('SIGKILL'); } catch {} }
15026
+ for (const pid of plan.descendants) { try { process.kill(pid, 'SIGKILL'); } catch {} }
14997
15027
  }
14998
15028
 
14999
15029
  function finish(extra) {
@@ -15092,7 +15122,7 @@ if (child) {
15092
15122
  // src/verifier-backend.ts
15093
15123
  import { createHash as createHash11, randomUUID } from "node:crypto";
15094
15124
  import { spawnSync as spawnSync2 } from "node:child_process";
15095
- import { accessSync as accessSync2, constants as constants3, readFileSync as readFileSync16, realpathSync as realpathSync7, statSync as statSync4 } from "node:fs";
15125
+ import { accessSync as accessSync2, constants as constants3, readFileSync as readFileSync15, realpathSync as realpathSync7, statSync as statSync4 } from "node:fs";
15096
15126
  import { delimiter as delimiter2, dirname as dirname7, join as join18, resolve as resolve7 } from "node:path";
15097
15127
  function identity() {
15098
15128
  const uid = typeof process.getuid === "function" ? process.getuid() : null;
@@ -15137,7 +15167,7 @@ function findExecutable(name) {
15137
15167
  return null;
15138
15168
  }
15139
15169
  function fileSha256(path) {
15140
- return createHash11("sha256").update(readFileSync16(path)).digest("hex");
15170
+ return createHash11("sha256").update(readFileSync15(path)).digest("hex");
15141
15171
  }
15142
15172
  function engineClientEnv() {
15143
15173
  return {
@@ -15571,7 +15601,7 @@ var init_verifier_backend = __esm({
15571
15601
  // src/cli/verify.ts
15572
15602
  import { execFileSync as execFileSync8, spawnSync as spawnSync3 } from "node:child_process";
15573
15603
  import { createHash as createHash12 } from "node:crypto";
15574
- import { chmodSync as chmodSync2, cpSync, lstatSync as lstatSync9, mkdirSync as mkdirSync8, mkdtempSync as mkdtempSync3, readFileSync as readFileSync17, readlinkSync as readlinkSync3, rmSync as rmSync7, symlinkSync, writeFileSync as writeFileSync9, existsSync as existsSync14 } from "node:fs";
15604
+ import { chmodSync as chmodSync2, cpSync, lstatSync as lstatSync9, mkdirSync as mkdirSync8, mkdtempSync as mkdtempSync3, readFileSync as readFileSync16, readlinkSync as readlinkSync3, rmSync as rmSync7, symlinkSync, writeFileSync as writeFileSync9, existsSync as existsSync14 } from "node:fs";
15575
15605
  import { tmpdir as tmpdir4 } from "node:os";
15576
15606
  import { dirname as dirname8, isAbsolute as isAbsolute11, join as join19, relative as relative5, resolve as resolve8, sep as sep3 } from "node:path";
15577
15607
  function oracleAssuranceReport() {
@@ -15792,7 +15822,7 @@ function overlayDigest(dest, paths) {
15792
15822
  try {
15793
15823
  const st = lstatSync9(p);
15794
15824
  h.update(String(st.mode));
15795
- h.update(st.isSymbolicLink() ? readlinkSync3(p) : readFileSync17(p));
15825
+ h.update(st.isSymbolicLink() ? readlinkSync3(p) : readFileSync16(p));
15796
15826
  } catch {
15797
15827
  h.update("<gone>");
15798
15828
  }
@@ -16506,7 +16536,7 @@ var init_verify = __esm({
16506
16536
  // src/cli/run.ts
16507
16537
  import { execFileSync as execFileSync9, spawn, spawnSync as spawnSync4 } from "node:child_process";
16508
16538
  import { randomBytes as randomBytes3 } from "node:crypto";
16509
- import { accessSync as accessSync3, constants as fsConstants, mkdtempSync as mkdtempSync4, readdirSync as readdirSync4, readFileSync as readFileSync18, readlinkSync as readlinkSync4, realpathSync as realpathSync9, rmSync as rmSync8, statSync as statSync5, writeFileSync as writeFileSync10 } from "node:fs";
16539
+ import { accessSync as accessSync3, constants as fsConstants, mkdtempSync as mkdtempSync4, readdirSync as readdirSync4, readFileSync as readFileSync17, readlinkSync as readlinkSync4, realpathSync as realpathSync8, rmSync as rmSync8, statSync as statSync5, writeFileSync as writeFileSync10 } from "node:fs";
16510
16540
  import { tmpdir as tmpdir5 } from "node:os";
16511
16541
  import { dirname as dirname9, join as join20, resolve as resolve9 } from "node:path";
16512
16542
  function authoritativeRunLifecyclePlatform(platform = process.platform) {
@@ -16561,7 +16591,7 @@ function trustedLinuxPython(candidates = DEFAULT_TRUSTED_PYTHON_CANDIDATES) {
16561
16591
  }
16562
16592
  for (const candidate of candidates) {
16563
16593
  try {
16564
- const real = realpathSync9(candidate);
16594
+ const real = realpathSync8(candidate);
16565
16595
  const st = statSync5(real);
16566
16596
  if (!st.isFile() || writableByCaller2(real)) continue;
16567
16597
  const probe = spawnSync4(
@@ -16660,7 +16690,7 @@ function runAgentSupervised(argv, cwd, budgetSecs, linuxPythonCandidates, lifecy
16660
16690
  }
16661
16691
  let state = {};
16662
16692
  try {
16663
- state = JSON.parse(readFileSync18(resultFile, "utf8"));
16693
+ state = JSON.parse(readFileSync17(resultFile, "utf8"));
16664
16694
  } catch {
16665
16695
  return {
16666
16696
  exit: 1,
@@ -16704,7 +16734,7 @@ function observerExited(pid) {
16704
16734
  if (!pidAlive3(pid)) return true;
16705
16735
  if (process.platform !== "linux") return false;
16706
16736
  try {
16707
- const stat = readFileSync18(`/proc/${pid}/stat`, "utf8");
16737
+ const stat = readFileSync17(`/proc/${pid}/stat`, "utf8");
16708
16738
  const state = stat.slice(stat.lastIndexOf(")") + 2).split(" ")[0];
16709
16739
  return state === "Z" || state === "X";
16710
16740
  } catch (e) {
@@ -16826,7 +16856,7 @@ function git3(args, cwd) {
16826
16856
  }
16827
16857
  function nowTicks() {
16828
16858
  try {
16829
- return Math.floor(parseFloat(readFileSync18("/proc/uptime", "utf8").split(" ")[0]) * 100);
16859
+ return Math.floor(parseFloat(readFileSync17("/proc/uptime", "utf8").split(" ")[0]) * 100);
16830
16860
  } catch {
16831
16861
  return Number.POSITIVE_INFINITY;
16832
16862
  }
@@ -16835,7 +16865,7 @@ function survivorsHoldingTree(cwd, spawnedAfterTicks) {
16835
16865
  const out3 = [];
16836
16866
  let real;
16837
16867
  try {
16838
- real = realpathSync9(cwd);
16868
+ real = realpathSync8(cwd);
16839
16869
  } catch {
16840
16870
  return out3;
16841
16871
  }
@@ -16849,7 +16879,7 @@ function survivorsHoldingTree(cwd, spawnedAfterTicks) {
16849
16879
  const n = Number(pid);
16850
16880
  if (n === process.pid) continue;
16851
16881
  try {
16852
- const stat = readFileSync18(`/proc/${pid}/stat`, "utf8");
16882
+ const stat = readFileSync17(`/proc/${pid}/stat`, "utf8");
16853
16883
  const startTicks = Number(stat.slice(stat.lastIndexOf(")") + 2).split(" ")[19]);
16854
16884
  if (!Number.isFinite(startTicks) || startTicks < spawnedAfterTicks) continue;
16855
16885
  } catch {
@@ -17421,7 +17451,7 @@ raise SystemExit(0)
17421
17451
 
17422
17452
  // src/cli/doctor.ts
17423
17453
  import { execFileSync as execFileSync10 } from "node:child_process";
17424
- import { existsSync as existsSync15, readFileSync as readFileSync19, readdirSync as readdirSync5 } from "node:fs";
17454
+ import { existsSync as existsSync15, readFileSync as readFileSync18, readdirSync as readdirSync5 } from "node:fs";
17425
17455
  import { join as join21, resolve as resolve10 } from "node:path";
17426
17456
  function lifecyclePlatformCheck(platform = process.platform, linuxPython = platform === "linux" ? trustedLinuxPython() : null) {
17427
17457
  if (platform === "linux") {
@@ -17480,7 +17510,7 @@ function pinsInFile(path) {
17480
17510
  if (!existsSync15(path)) return [];
17481
17511
  let src = "";
17482
17512
  try {
17483
- src = readFileSync19(path, "utf8");
17513
+ src = readFileSync18(path, "utf8");
17484
17514
  } catch {
17485
17515
  return [];
17486
17516
  }
@@ -17507,7 +17537,7 @@ function workflowPermissionCheck(cwd, workflowRels = [".github/workflows/tamperw
17507
17537
  }
17508
17538
  let doc;
17509
17539
  try {
17510
- doc = yaml.parse(readFileSync19(path, "utf8"));
17540
+ doc = yaml.parse(readFileSync18(path, "utf8"));
17511
17541
  } catch (e) {
17512
17542
  broken.push(`${rel} is not valid YAML (${e instanceof Error ? e.message : String(e)})`);
17513
17543
  continue;
@@ -17931,7 +17961,7 @@ function diagnose(opts = {}) {
17931
17961
  }
17932
17962
  let doc;
17933
17963
  try {
17934
- doc = yaml.parse(readFileSync19(workflowPath, "utf8"));
17964
+ doc = yaml.parse(readFileSync18(workflowPath, "utf8"));
17935
17965
  } catch (e) {
17936
17966
  return fail(
17937
17967
  "ci-verifier",
@@ -18110,9 +18140,9 @@ import { execFileSync as execFileSync11, spawnSync as spawnSync5 } from "node:ch
18110
18140
  import {
18111
18141
  existsSync as existsSync16,
18112
18142
  mkdtempSync as mkdtempSync5,
18113
- readFileSync as readFileSync20,
18143
+ readFileSync as readFileSync19,
18114
18144
  readdirSync as readdirSync6,
18115
- realpathSync as realpathSync10,
18145
+ realpathSync as realpathSync9,
18116
18146
  rmSync as rmSync9,
18117
18147
  symlinkSync as symlinkSync2
18118
18148
  } from "node:fs";
@@ -18129,7 +18159,7 @@ function parseStraceFileAccess(raw) {
18129
18159
  const call = line.match(/\b(execveat|execve|openat2|openat|open|newfstatat|fstatat|statx|lstat|stat|access|readlinkat|readlink)\s*\(/);
18130
18160
  if (!call) continue;
18131
18161
  const afterCall = line.slice((call.index ?? 0) + call[0].length);
18132
- const quoted = afterCall.match(/"((?:\\.|[^"])*)"/);
18162
+ const quoted = afterCall.match(/"([^"\\]*(?:\\.[^"\\]*)*)"/);
18133
18163
  if (!quoted) continue;
18134
18164
  const path = unescapeStraceString(quoted[1]);
18135
18165
  if (!path) continue;
@@ -18276,7 +18306,7 @@ function rewriteTraceRoot(accesses, actualRoot) {
18276
18306
  if (!inside3(actualRoot, abs)) return { ...item, path: abs };
18277
18307
  const rel = relative6(actualRoot, abs).split(sep4).join("/");
18278
18308
  try {
18279
- const real = resolve11(realpathSync10(abs));
18309
+ const real = resolve11(realpathSync9(abs));
18280
18310
  if (!inside3(actualRoot, real)) return { ...item, path: real };
18281
18311
  } catch {
18282
18312
  }
@@ -18315,7 +18345,7 @@ function straceOnce(root, command, budget) {
18315
18345
  }
18316
18346
  );
18317
18347
  const logs = traced.error ? [] : traceFiles(prefix);
18318
- const accesses = logs.flatMap((path) => parseStraceFileAccess(readFileSync20(path, "utf8")));
18348
+ const accesses = logs.flatMap((path) => parseStraceFileAccess(readFileSync19(path, "utf8")));
18319
18349
  const raw = {
18320
18350
  spawnError: traced.error ? traced.error.message : null,
18321
18351
  status: traced.status,
@@ -18545,7 +18575,7 @@ var init_trace_verify = __esm({
18545
18575
  });
18546
18576
 
18547
18577
  // src/runtimes.ts
18548
- import { existsSync as existsSync17, readFileSync as readFileSync21 } from "node:fs";
18578
+ import { existsSync as existsSync17, readFileSync as readFileSync20 } from "node:fs";
18549
18579
  import { join as join23 } from "node:path";
18550
18580
  function isRecord4(x) {
18551
18581
  return typeof x === "object" && x !== null && !Array.isArray(x);
@@ -18576,7 +18606,7 @@ function claudeSettingsBeyondTamperward(cwd) {
18576
18606
  let raw;
18577
18607
  try {
18578
18608
  if (!existsSync17(path)) return false;
18579
- raw = readFileSync21(path, "utf8");
18609
+ raw = readFileSync20(path, "utf8");
18580
18610
  } catch {
18581
18611
  return false;
18582
18612
  }
@@ -18683,7 +18713,7 @@ var init_runtimes = __esm({
18683
18713
 
18684
18714
  // src/cli/onboard.ts
18685
18715
  import { execFileSync as execFileSync12 } from "node:child_process";
18686
- import { lstatSync as lstatSync10, mkdtempSync as mkdtempSync6, readFileSync as readFileSync22, realpathSync as realpathSync11, rmSync as rmSync10 } from "node:fs";
18716
+ import { lstatSync as lstatSync10, mkdtempSync as mkdtempSync6, readFileSync as readFileSync21, realpathSync as realpathSync10, rmSync as rmSync10 } from "node:fs";
18687
18717
  import { tmpdir as tmpdir7 } from "node:os";
18688
18718
  import { join as join24, relative as relative7, resolve as resolve12, sep as sep5 } from "node:path";
18689
18719
  import { createInterface } from "node:readline";
@@ -18756,7 +18786,7 @@ function writeVerifyCommand(cwd, command) {
18756
18786
  return `${POLICY_FILE} is not a regular file; refusing to follow or replace a symlink or special file`;
18757
18787
  }
18758
18788
  const mode = existingMode(path, 420);
18759
- const original = kind === "file" ? readFileSync22(path, "utf8") : null;
18789
+ const original = kind === "file" ? readFileSync21(path, "utf8") : null;
18760
18790
  let next;
18761
18791
  try {
18762
18792
  const doc = parseDocument(original && original.trim() ? original : "version: 1\n");
@@ -18816,7 +18846,7 @@ async function runOnboard(opts, io = {}) {
18816
18846
  const cwd = resolve12(rootText);
18817
18847
  let sameRoot = cwd === requestedCwd;
18818
18848
  try {
18819
- sameRoot = realpathSync11(cwd) === realpathSync11(requestedCwd);
18849
+ sameRoot = realpathSync10(cwd) === realpathSync10(requestedCwd);
18820
18850
  } catch {
18821
18851
  }
18822
18852
  if (!sameRoot) {
@@ -19156,8 +19186,8 @@ function runDemo(cwd, head, runners, out3) {
19156
19186
  let worktreeRoot;
19157
19187
  let realTarget;
19158
19188
  try {
19159
- worktreeRoot = realpathSync11(wt);
19160
- realTarget = realpathSync11(targetPath);
19189
+ worktreeRoot = realpathSync10(wt);
19190
+ realTarget = realpathSync10(targetPath);
19161
19191
  } catch {
19162
19192
  out3("Demo skipped: the selected test could not be resolved safely inside the disposable worktree.");
19163
19193
  return;
@@ -19341,8 +19371,8 @@ var init_capture = __esm({
19341
19371
  });
19342
19372
 
19343
19373
  // src/research/manifest.ts
19344
- import { createHash as createHash14 } from "node:crypto";
19345
- import { readFileSync as readFileSync23 } from "node:fs";
19374
+ import { createHash as createHash13 } from "node:crypto";
19375
+ import { readFileSync as readFileSync22 } from "node:fs";
19346
19376
  import { dirname as dirname10, resolve as resolve14 } from "node:path";
19347
19377
  function taskFrom(raw, index, manifestDir) {
19348
19378
  const where = `task #${index + 1}`;
@@ -19376,7 +19406,7 @@ function readManifest(path) {
19376
19406
  const abs = resolve14(path);
19377
19407
  let bytes;
19378
19408
  try {
19379
- bytes = readFileSync23(abs);
19409
+ bytes = readFileSync22(abs);
19380
19410
  } catch (e) {
19381
19411
  throw new ResearchError(`cannot read task manifest ${abs}: ${e instanceof Error ? e.message : String(e)}`);
19382
19412
  }
@@ -19399,7 +19429,7 @@ function readManifest(path) {
19399
19429
  if (seen.has(t.id)) throw new ResearchError(`task manifest ${abs}: duplicate task id "${t.id}"`);
19400
19430
  seen.add(t.id);
19401
19431
  }
19402
- return { path: abs, sha256: createHash14("sha256").update(bytes).digest("hex"), tasks };
19432
+ return { path: abs, sha256: createHash13("sha256").update(bytes).digest("hex"), tasks };
19403
19433
  }
19404
19434
  var MANIFEST_VERSION;
19405
19435
  var init_manifest = __esm({
@@ -19588,7 +19618,7 @@ var init_record = __esm({
19588
19618
 
19589
19619
  // src/research/run.ts
19590
19620
  import { execFileSync as execFileSync13 } from "node:child_process";
19591
- import { existsSync as existsSync18, mkdirSync as mkdirSync9, readFileSync as readFileSync24, renameSync as renameSync4, rmSync as rmSync11, writeFileSync as writeFileSync11 } from "node:fs";
19621
+ import { existsSync as existsSync18, mkdirSync as mkdirSync9, readFileSync as readFileSync23, renameSync as renameSync4, rmSync as rmSync11, writeFileSync as writeFileSync11 } from "node:fs";
19592
19622
  import { join as join25, resolve as resolve15 } from "node:path";
19593
19623
  function git6(args, cwd) {
19594
19624
  return execFileSync13("git", args, { cwd, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }).trim();
@@ -19599,7 +19629,7 @@ function pairRecordPath(ledger, task, pair) {
19599
19629
  function resumableRecord(path, expected) {
19600
19630
  let raw;
19601
19631
  try {
19602
- raw = JSON.parse(readFileSync24(path, "utf8"));
19632
+ raw = JSON.parse(readFileSync23(path, "utf8"));
19603
19633
  } catch (e) {
19604
19634
  throw new ResearchError(`ledger record ${path} is malformed (${errorMessage(e).split("\n")[0]}); remove it to regenerate the pair, or use a new --out`);
19605
19635
  }
@@ -19639,12 +19669,15 @@ function writeRecordAtomically(path, text) {
19639
19669
  writeFileSync11(tmp, text);
19640
19670
  renameSync4(tmp, path);
19641
19671
  }
19672
+ function cloneArgs(repo, ws3) {
19673
+ return ["-c", "protocol.ext.allow=never", "clone", "-q", "--no-hardlinks", "--", repo, ws3];
19674
+ }
19642
19675
  function freshWorkspace(ledger, task, pair, arm, sourceBase) {
19643
19676
  const ws3 = join25(ledger, "workspaces", `${task.id}--${pair}--${arm}`);
19644
19677
  rmSync11(ws3, { recursive: true, force: true });
19645
19678
  mkdirSync9(join25(ledger, "workspaces"), { recursive: true });
19646
19679
  try {
19647
- execFileSync13("git", ["clone", "-q", "--no-hardlinks", task.repo, ws3], { stdio: ["ignore", "ignore", "pipe"], encoding: "utf8" });
19680
+ execFileSync13("git", cloneArgs(task.repo, ws3), { stdio: ["ignore", "ignore", "pipe"], encoding: "utf8" });
19648
19681
  } catch (e) {
19649
19682
  throw new ResearchError(`task "${task.id}": cannot clone ${task.repo}: ${errorMessage(e).split("\n")[0]}`);
19650
19683
  }
@@ -20022,7 +20055,7 @@ var init_run2 = __esm({
20022
20055
  });
20023
20056
 
20024
20057
  // src/research/summarize.ts
20025
- import { readdirSync as readdirSync7, readFileSync as readFileSync25 } from "node:fs";
20058
+ import { readdirSync as readdirSync7, readFileSync as readFileSync24 } from "node:fs";
20026
20059
  import { join as join26, resolve as resolve16 } from "node:path";
20027
20060
  function readLedger2(dir) {
20028
20061
  const pairsDir = join26(resolve16(dir), "pairs");
@@ -20037,7 +20070,7 @@ function readLedger2(dir) {
20037
20070
  const path = join26(pairsDir, n);
20038
20071
  let raw;
20039
20072
  try {
20040
- raw = JSON.parse(readFileSync25(path, "utf8"));
20073
+ raw = JSON.parse(readFileSync24(path, "utf8"));
20041
20074
  } catch (e) {
20042
20075
  throw new ResearchError(`ledger record ${path} is not valid JSON: ${errorMessage(e)}`);
20043
20076
  }
@@ -20744,7 +20777,7 @@ var init_main = __esm({
20744
20777
  // src/cli/index.ts
20745
20778
  init_hook_client();
20746
20779
  init_exit();
20747
- import { readFileSync as readFileSync26 } from "node:fs";
20780
+ import { readFileSync as readFileSync25 } from "node:fs";
20748
20781
  function loadMain() {
20749
20782
  return Promise.resolve().then(() => (init_main(), main_exports));
20750
20783
  }
@@ -20757,7 +20790,7 @@ async function launch(argv) {
20757
20790
  if (kind && hookServiceEnabled()) {
20758
20791
  let raw = null;
20759
20792
  try {
20760
- raw = readFileSync26(0, "utf8");
20793
+ raw = readFileSync25(0, "utf8");
20761
20794
  } catch {
20762
20795
  raw = null;
20763
20796
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tamperward",
3
- "version": "2.30.2",
3
+ "version": "2.30.4",
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",