tamperward 1.10.0 → 1.10.2
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 +46 -9
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -272,6 +272,19 @@ function diffWorktree(opts = {}) {
|
|
|
272
272
|
(c) => enrich(c, (p) => blobAt("HEAD", p, opts.cwd), (p) => fromDisk(p, opts.cwd))
|
|
273
273
|
);
|
|
274
274
|
}
|
|
275
|
+
function diffWorktreeWithUntracked(opts = {}) {
|
|
276
|
+
const tracked = diffWorktree(opts);
|
|
277
|
+
const others = git(["ls-files", "--others", "--exclude-standard", "-z"], opts.cwd).split("\0").filter(Boolean);
|
|
278
|
+
const seen = new Set(tracked.filter((c) => c.kind === "file").map((c) => c.path));
|
|
279
|
+
const untracked = others.filter((rel) => !seen.has(rel)).map(
|
|
280
|
+
(rel) => enrich(
|
|
281
|
+
{ kind: "file", path: rel, oldPath: null, op: "add", before: null, after: null, binary: false, hunks: [] },
|
|
282
|
+
() => null,
|
|
283
|
+
(p) => fromDisk(p, opts.cwd)
|
|
284
|
+
)
|
|
285
|
+
);
|
|
286
|
+
return [...tracked, ...untracked];
|
|
287
|
+
}
|
|
275
288
|
|
|
276
289
|
// src/detectors/finding.ts
|
|
277
290
|
function severityOf(rule, policy, fallback = "block") {
|
|
@@ -1840,7 +1853,7 @@ function report(input) {
|
|
|
1840
1853
|
|
|
1841
1854
|
// src/cli/check.ts
|
|
1842
1855
|
function check(opts) {
|
|
1843
|
-
let policy = loadPolicy(opts.cwd);
|
|
1856
|
+
let policy = opts.policyOverride ?? loadPolicy(opts.cwd);
|
|
1844
1857
|
const cwd = opts.cwd ?? process.cwd();
|
|
1845
1858
|
let changes;
|
|
1846
1859
|
let layer;
|
|
@@ -1850,8 +1863,8 @@ function check(opts) {
|
|
|
1850
1863
|
layer = "local";
|
|
1851
1864
|
view = "staged";
|
|
1852
1865
|
} else if (opts.worktree) {
|
|
1853
|
-
changes = diffWorktree({ cwd: opts.cwd });
|
|
1854
|
-
layer = "local";
|
|
1866
|
+
changes = opts.includeUntracked ? diffWorktreeWithUntracked({ cwd: opts.cwd }) : diffWorktree({ cwd: opts.cwd });
|
|
1867
|
+
layer = opts.ciLayer ? "ci" : "local";
|
|
1855
1868
|
view = "worktree";
|
|
1856
1869
|
} else if (opts.diff) {
|
|
1857
1870
|
const [base, head] = opts.diff.split(/\.{2,3}/);
|
|
@@ -1863,7 +1876,7 @@ function check(opts) {
|
|
|
1863
1876
|
changes = diffRange(base, head, { cwd: opts.cwd });
|
|
1864
1877
|
layer = "ci";
|
|
1865
1878
|
view = "range";
|
|
1866
|
-
policy = loadPolicyAt(mergeBaseOf(base, head, { cwd: opts.cwd }), opts.cwd) ?? defaultPolicy();
|
|
1879
|
+
policy = opts.policyOverride ?? loadPolicyAt(mergeBaseOf(base, head, { cwd: opts.cwd }), opts.cwd) ?? defaultPolicy();
|
|
1867
1880
|
} else {
|
|
1868
1881
|
process.stderr.write("tamperward: specify --staged, --worktree, or --diff <base>...<head>\n");
|
|
1869
1882
|
return 2;
|
|
@@ -2820,7 +2833,7 @@ function runVerify(opts) {
|
|
|
2820
2833
|
const out2 = (s) => void process.stdout.write(s + "\n");
|
|
2821
2834
|
let policy;
|
|
2822
2835
|
try {
|
|
2823
|
-
policy = loadPolicy(cwd);
|
|
2836
|
+
policy = opts.policyOverride ?? loadPolicy(cwd);
|
|
2824
2837
|
} catch (e) {
|
|
2825
2838
|
out2(`verify: cannot load policy (${e instanceof Error ? e.message : String(e)}) \u2014 failing closed`);
|
|
2826
2839
|
return 2;
|
|
@@ -2932,6 +2945,22 @@ function runEnvelope(opts) {
|
|
|
2932
2945
|
err(`tamperward run: cannot resolve trusted base ${opts.base ?? "HEAD"} \u2014 failing closed.`);
|
|
2933
2946
|
return 2;
|
|
2934
2947
|
}
|
|
2948
|
+
let frozenPolicy;
|
|
2949
|
+
let frozenCmd;
|
|
2950
|
+
let frozenBudget;
|
|
2951
|
+
try {
|
|
2952
|
+
frozenPolicy = loadPolicyAt(base, cwd) ?? defaultPolicy();
|
|
2953
|
+
frozenCmd = opts.cmd ?? frozenPolicy.verify?.command;
|
|
2954
|
+
frozenBudget = opts.budget ?? frozenPolicy.verify?.budget;
|
|
2955
|
+
} catch (e) {
|
|
2956
|
+
err(`tamperward run: cannot load the entry-time policy (${e instanceof Error ? e.message : String(e)}) \u2014 failing closed.`);
|
|
2957
|
+
return 2;
|
|
2958
|
+
}
|
|
2959
|
+
if (!frozenCmd) {
|
|
2960
|
+
err("tamperward run: no suite command at entry (policy `verify: { command: ... }` or --cmd) \u2014");
|
|
2961
|
+
err("refusing to start: a verifier that appears after the agent runs would be agent-authored.");
|
|
2962
|
+
return 2;
|
|
2963
|
+
}
|
|
2935
2964
|
if (!opts.allowDirty) {
|
|
2936
2965
|
const dirty = git3(["status", "--porcelain"], cwd).trim();
|
|
2937
2966
|
if (dirty) {
|
|
@@ -2944,16 +2973,24 @@ function runEnvelope(opts) {
|
|
|
2944
2973
|
const agent = spawnSync2(opts.argv[0], opts.argv.slice(1), { cwd, stdio: "inherit" });
|
|
2945
2974
|
const agentExit = agent.status ?? 1;
|
|
2946
2975
|
const head = git3(["rev-parse", "HEAD"], cwd).trim();
|
|
2976
|
+
const isAncestor = spawnSync2("git", ["merge-base", "--is-ancestor", base, head], { cwd });
|
|
2977
|
+
if (isAncestor.status !== 0) {
|
|
2978
|
+
err(`tamperward run: HEAD ${head.slice(0, 10)} is not a descendant of the trusted base ${base.slice(0, 10)} \u2014`);
|
|
2979
|
+
err("the agent rewrote history out from under the anchor. That is the finding.");
|
|
2980
|
+
out(`
|
|
2981
|
+
tamperward run \u2014 agent exit ${agentExit}; HISTORY_REWRITE \u2192 ENFORCEMENT_FAILED`);
|
|
2982
|
+
return 1;
|
|
2983
|
+
}
|
|
2947
2984
|
let diffCode = 0;
|
|
2948
2985
|
if (head !== base) {
|
|
2949
2986
|
out(`
|
|
2950
2987
|
[envelope] policy check over committed changes (${base.slice(0, 10)}...${head.slice(0, 10)}):`);
|
|
2951
|
-
diffCode = runCheck({ diff: `${base}...${head}`, cwd });
|
|
2988
|
+
diffCode = runCheck({ diff: `${base}...${head}`, cwd, policyOverride: frozenPolicy });
|
|
2952
2989
|
}
|
|
2953
|
-
out("\n[envelope] policy check over the working tree:");
|
|
2954
|
-
const workCode = runCheck({ worktree: true, cwd });
|
|
2990
|
+
out("\n[envelope] policy check over the working tree (frozen policy, untracked included, no local ledger):");
|
|
2991
|
+
const workCode = runCheck({ worktree: true, cwd, policyOverride: frozenPolicy, includeUntracked: true, ciLayer: true });
|
|
2955
2992
|
out("\n[envelope] pristine verification against the trusted base:");
|
|
2956
|
-
const verifyCode = runVerify({ cwd, base, cmd:
|
|
2993
|
+
const verifyCode = runVerify({ cwd, base, cmd: frozenCmd, budget: frozenBudget, policyOverride: frozenPolicy });
|
|
2957
2994
|
const cannot = diffCode === 2 || workCode === 2 || verifyCode === 2;
|
|
2958
2995
|
const blocked = diffCode === 1 || workCode === 1 || verifyCode === 1;
|
|
2959
2996
|
const enforcement = cannot ? 2 : blocked ? 1 : 0;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tamperward",
|
|
3
|
-
"version": "1.10.
|
|
3
|
+
"version": "1.10.2",
|
|
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",
|