tamperward 2.39.7 → 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.
- package/dist/cli/index.js +30 -10
- 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 =
|
|
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 (!
|
|
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 (!
|
|
11049
|
-
|
|
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
|
|
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
|
|
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(", ")}
|
|
@@ -17350,8 +17360,13 @@ function runVerifyImpl(opts) {
|
|
|
17350
17360
|
} catch {
|
|
17351
17361
|
}
|
|
17352
17362
|
}
|
|
17353
|
-
const
|
|
17363
|
+
const oob = oobFromEnv();
|
|
17364
|
+
const oobHead = oobHeadFromEnv();
|
|
17365
|
+
const signedOff = verdict2 === "MASKED_FAILURE" ? oobToken("verify", oob, oobHead) : null;
|
|
17354
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
|
+
`);
|
|
17355
17370
|
if (opts.json) {
|
|
17356
17371
|
out3(
|
|
17357
17372
|
JSON.stringify({
|
|
@@ -24793,7 +24808,12 @@ function ciAdjudicate(cwd, opts) {
|
|
|
24793
24808
|
if (check2.reason !== void 0) {
|
|
24794
24809
|
return { ci: { verdict: "CANNOT_VERIFY", binding, binding_error: check2.reason }, exit: 2 };
|
|
24795
24810
|
}
|
|
24796
|
-
const
|
|
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
|
+
`);
|
|
24797
24817
|
return {
|
|
24798
24818
|
ci: {
|
|
24799
24819
|
verdict: check2.verdict,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tamperward",
|
|
3
|
-
"version": "2.39.
|
|
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",
|