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.
- package/dist/cli/index.js +35 -12
- 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(", ")}
|
|
@@ -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
|
-
|
|
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
|
|
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
|
|
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.
|
|
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",
|