tamperward 2.39.6 → 2.39.8

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 +35 -12
  2. package/package.json +1 -1
package/dist/cli/index.js CHANGED
@@ -11030,25 +11030,25 @@ function applyLocalSignoffs(findings, cwd, policy, now = Date.now()) {
11030
11030
  return { findings: remaining, cleared };
11031
11031
  }
11032
11032
  function oobToken(want, oob, head) {
11033
+ const supplied = head !== void 0 && head.trim() !== "";
11034
+ const bound = supplied && FULL_OBJECT_ID.test(head.trim()) ? head.trim().toLowerCase() : null;
11033
11035
  for (const raw of oob) {
11034
11036
  const t = raw.trim();
11035
11037
  if (!t) continue;
11036
11038
  if (t.startsWith(COMPACT_OOB_PREFIX)) {
11037
- const expected = head === void 0 ? null : compactOobToken(want, head);
11039
+ const expected = bound === null ? null : compactOobToken(want, bound);
11038
11040
  if (expected !== null && t === expected) return t;
11039
11041
  continue;
11040
11042
  }
11041
11043
  const at = t.lastIndexOf("@");
11042
11044
  if (at === -1) {
11043
- if (!head && t === want) return t;
11045
+ if (!supplied && t === want) return t;
11044
11046
  continue;
11045
11047
  }
11046
11048
  const [rule, sha3] = [t.slice(0, at), t.slice(at + 1)];
11047
11049
  if (rule !== want) continue;
11048
- if (!head) return t;
11049
- const normalizedHead = head.trim().toLowerCase();
11050
- const normalizedSha = sha3.trim().toLowerCase();
11051
- if (/^[0-9a-f]+$/.test(normalizedHead) && normalizedSha === normalizedHead) return t;
11050
+ if (!supplied) return t;
11051
+ if (bound !== null && sha3.trim().toLowerCase() === bound) return t;
11052
11052
  }
11053
11053
  return null;
11054
11054
  }
@@ -11065,7 +11065,12 @@ function applyOobSignoffs(findings, oob, head) {
11065
11065
  }
11066
11066
  function oobHeadFromEnv(env = process.env) {
11067
11067
  const v = (env.TAMPERWARD_OOB_HEAD ?? "").trim().toLowerCase();
11068
- return /^(?:[0-9a-f]{40}|[0-9a-f]{64})$/.test(v) ? v : void 0;
11068
+ return v === "" ? void 0 : v;
11069
+ }
11070
+ function oobHeadProblem(head) {
11071
+ if (head === void 0 || head.trim() === "" || FULL_OBJECT_ID.test(head.trim())) return null;
11072
+ const shown = head.length > 72 ? `${head.slice(0, 69)}\u2026` : head;
11073
+ return `TAMPERWARD_OOB_HEAD is set to ${JSON.stringify(shown)}, which is not the full 40- or 64-character object id of the head under adjudication; no out-of-band approval is honored against a head the gate cannot identify`;
11069
11074
  }
11070
11075
  function oobFromEnv(env = process.env) {
11071
11076
  return (env.TAMPERWARD_OOB_SIGNOFF ?? "").split(",").map((s) => s.trim().replace(/^tamperward:allow:/, "")).filter(Boolean);
@@ -11459,8 +11464,13 @@ function check(opts) {
11459
11464
  const ignoredFiles = changes.filter((c) => isSuppressed(c, policy)).length;
11460
11465
  let findings = evaluate(changes, policy, void 0, view, { cwd });
11461
11466
  if (view === "worktree") findings = findings.concat(unjudgeableProtected(cwd, policy, changes));
11462
- const { findings: remaining, cleared } = layer === "local" ? applyLocalSignoffs(findings, cwd, policy) : applyOobSignoffs(findings, oobFromEnv(), oobHeadFromEnv());
11467
+ const oob = layer === "ci" ? oobFromEnv() : [];
11468
+ const oobHead = layer === "ci" ? oobHeadFromEnv() : void 0;
11469
+ const { findings: remaining, cleared } = layer === "local" ? applyLocalSignoffs(findings, cwd, policy) : applyOobSignoffs(findings, oob, oobHead);
11463
11470
  findings = remaining;
11471
+ const headProblem = oob.length > 0 ? oobHeadProblem(oobHead) : null;
11472
+ if (headProblem) process.stderr.write(`tamperward: ${headProblem}
11473
+ `);
11464
11474
  if (cleared.length) {
11465
11475
  const how = layer === "local" ? "local human sign-off (ledger)" : "out-of-band approval";
11466
11476
  process.stderr.write(`tamperward: ${cleared.length} blocking finding(s) cleared by ${how}: ${cleared.map((f) => f.rule + (f.file ? `(${f.file})` : "")).join(", ")}
@@ -15910,8 +15920,10 @@ function surfacePaths(base, cwd, policy) {
15910
15920
  let listing;
15911
15921
  try {
15912
15922
  listing = git2(["ls-tree", "-r", "--name-only", "-z", base], cwd);
15913
- } catch {
15914
- return [];
15923
+ } catch (e) {
15924
+ const failure = execFailure(e);
15925
+ const detail = failure.stderr.trim().split("\n")[0] || failure.message.split("\n")[0];
15926
+ throw new Error(`cannot list the protected verification surface at base ${base}: ${detail}`);
15915
15927
  }
15916
15928
  const inputs = policy.verify?.inputs ?? [];
15917
15929
  return listing.split("\0").filter(Boolean).filter((p) => isProtected(p, policy) || matchesAny(p, inputs)).sort();
@@ -16209,6 +16221,7 @@ var init_verification_state = __esm({
16209
16221
  init_trusted();
16210
16222
  init_fingerprint();
16211
16223
  init_policy();
16224
+ init_narrow();
16212
16225
  init_policy_load();
16213
16226
  init_repo_context();
16214
16227
  init_wiring();
@@ -17347,8 +17360,13 @@ function runVerifyImpl(opts) {
17347
17360
  } catch {
17348
17361
  }
17349
17362
  }
17350
- const signedOff = verdict2 === "MASKED_FAILURE" ? oobToken("verify", oobFromEnv(), oobHeadFromEnv()) : null;
17363
+ const oob = oobFromEnv();
17364
+ const oobHead = oobHeadFromEnv();
17365
+ const signedOff = verdict2 === "MASKED_FAILURE" ? oobToken("verify", oob, oobHead) : null;
17351
17366
  if (signedOff) code2 = 0;
17367
+ const headProblem = verdict2 === "MASKED_FAILURE" && oob.length > 0 ? oobHeadProblem(oobHead) : null;
17368
+ if (headProblem) process.stderr.write(`tamperward: ${headProblem}
17369
+ `);
17352
17370
  if (opts.json) {
17353
17371
  out3(
17354
17372
  JSON.stringify({
@@ -24790,7 +24808,12 @@ function ciAdjudicate(cwd, opts) {
24790
24808
  if (check2.reason !== void 0) {
24791
24809
  return { ci: { verdict: "CANNOT_VERIFY", binding, binding_error: check2.reason }, exit: 2 };
24792
24810
  }
24793
- const signedOff = check2.verdict === "MASKED_FAILURE" && oobToken("verify", oobFromEnv(), oobHeadFromEnv()) !== null;
24811
+ const oob = oobFromEnv();
24812
+ const oobHead = oobHeadFromEnv();
24813
+ const signedOff = check2.verdict === "MASKED_FAILURE" && oobToken("verify", oob, oobHead) !== null;
24814
+ const headProblem = check2.verdict === "MASKED_FAILURE" && oob.length > 0 ? oobHeadProblem(oobHead) : null;
24815
+ if (headProblem) process.stderr.write(`tamperward: ${headProblem}
24816
+ `);
24794
24817
  return {
24795
24818
  ci: {
24796
24819
  verdict: check2.verdict,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tamperward",
3
- "version": "2.39.6",
3
+ "version": "2.39.8",
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",