tamperward 1.2.1 → 1.3.0

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/README.md CHANGED
@@ -102,7 +102,7 @@ with the same engine it ships.
102
102
  - `src/engine.ts` — runs the enabled rules over `Change[]`; honours `policy.ignore`.
103
103
  - `src/cli/` — `tamperward check --staged | --worktree | --diff <base>...<head>`,
104
104
  exit 1 on any blocking finding.
105
- - `test/` — 235 tests, including the AST-vs-regex, self-hosting precision, and
105
+ - `test/` — 248 tests, including the AST-vs-regex, self-hosting precision, and
106
106
  pre-go-live audit regression cases, and the renderer accessibility contract.
107
107
 
108
108
  - `src/adapters/claude/` + `src/cli/hook.ts` — the agent layer: `tamperward hook claude`
package/dist/cli/index.js CHANGED
@@ -371,6 +371,16 @@ function removedLines(c) {
371
371
  // src/policy.ts
372
372
  import picomatch from "picomatch";
373
373
  var POLICY_FILE = ".tamperward.yml";
374
+ var BLOCK_SINCE = {};
375
+ function applyVersionGates(rules, version, gates = BLOCK_SINCE) {
376
+ const out = { ...rules };
377
+ for (const [rule, since] of Object.entries(gates)) {
378
+ if (since > version && out[rule]?.severity === "block") {
379
+ out[rule] = { ...out[rule], severity: "warn" };
380
+ }
381
+ }
382
+ return out;
383
+ }
374
384
  var cache = /* @__PURE__ */ new Map();
375
385
  function matcher(glob) {
376
386
  let m = cache.get(glob);
@@ -407,9 +417,9 @@ function mergeProtected(base, user) {
407
417
  }
408
418
  return out;
409
419
  }
410
- function defaultPolicy() {
411
- return {
412
- version: 1,
420
+ function defaultPolicy(version = 1) {
421
+ const p = {
422
+ version,
413
423
  protected: {
414
424
  // Cover every JS/TS test extension, not just .test.ts — the multi-repo FP study found
415
425
  // .test.tsx/.spec.tsx (hono, zustand) slipped the glob, so legit test-file casts blocked
@@ -454,6 +464,8 @@ function defaultPolicy() {
454
464
  ignore: [],
455
465
  signoff: { requiredFor: ["block"], ledger: ".tamperward/ledger.jsonl" }
456
466
  };
467
+ p.rules = applyVersionGates(p.rules, version);
468
+ return p;
457
469
  }
458
470
 
459
471
  // src/detectors/files.ts
@@ -924,8 +936,11 @@ function safeParse(src) {
924
936
  }
925
937
  }
926
938
  function effective(raw) {
927
- const base = defaultPolicy();
939
+ const v = raw.version;
940
+ const version = typeof v === "number" && Number.isInteger(v) && v >= 1 ? v : 1;
941
+ const base = defaultPolicy(version);
928
942
  return {
943
+ version,
929
944
  rules: { ...base.rules, ...raw.rules ?? {} },
930
945
  ignore: raw.ignore ?? base.ignore ?? [],
931
946
  protected: mergeProtected(base.protected, raw.protected),
@@ -940,6 +955,11 @@ function policyWeakening(before, after) {
940
955
  const be = effective(b);
941
956
  const ae = effective(a);
942
957
  const reasons = [];
958
+ if (ae.version < be.version) {
959
+ reasons.push(
960
+ `policy version lowered ${be.version} \u2192 ${ae.version} \u2014 un-opts this repo from rule graduations gated above ${ae.version}`
961
+ );
962
+ }
943
963
  for (const name of /* @__PURE__ */ new Set([...Object.keys(be.rules), ...Object.keys(ae.rules)])) {
944
964
  const br = be.rules[name];
945
965
  const ar = ae.rules[name];
@@ -1349,11 +1369,19 @@ import { join as join2 } from "node:path";
1349
1369
  import { parse as parse2 } from "yaml";
1350
1370
  var PolicyError = class extends Error {
1351
1371
  };
1372
+ function normalizeVersion(v, where = POLICY_FILE) {
1373
+ if (v === void 0 || v === null) return 1;
1374
+ if (typeof v !== "number" || !Number.isInteger(v) || v < 1) {
1375
+ throw new PolicyError(`${where}: version must be a positive integer, got ${JSON.stringify(v)}`);
1376
+ }
1377
+ return v;
1378
+ }
1352
1379
  function parsePolicy(raw) {
1353
- const base = defaultPolicy();
1354
1380
  const r = raw ?? {};
1381
+ const version = normalizeVersion(r.version);
1382
+ const base = defaultPolicy(version);
1355
1383
  return {
1356
- version: 1,
1384
+ version,
1357
1385
  // Merge with the baseline, never replace. For an integrity tool, a config that sets
1358
1386
  // one rule's severity must NOT silently drop the other nine — nor may naming one
1359
1387
  // protected glob wipe out the rest of its category (see mergeProtected).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tamperward",
3
- "version": "1.2.1",
3
+ "version": "1.3.0",
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",