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.
Files changed (2) hide show
  1. package/dist/cli/index.js +46 -9
  2. 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: opts.cmd, budget: opts.budget });
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.0",
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",