tamperward 2.20.0 → 2.20.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/README.md CHANGED
@@ -89,6 +89,9 @@ judged. In architectural terms, Tamperward separates **steering** from
89
89
  "pristine" verification restores the protected verification state from the
90
90
  trusted starting point and runs the checks again.
91
91
 
92
+ For the complete component map, trust boundaries, data flows, and deployment
93
+ surfaces, see [the full architecture diagram](./docs/architecture.md).
94
+
92
95
  > **Core invariant:** the agent may author the candidate tree, but it must not
93
96
  > choose the trusted baseline, the governing policy, the verifier, or the final
94
97
  > verdict.
@@ -110,31 +113,28 @@ trusted starting point and runs the checks again.
110
113
  ### The local enforcement envelope
111
114
 
112
115
  ```mermaid
113
- flowchart TB
114
- subgraph R["tamperward run — outer enforcement envelope"]
115
- E["Capture entry state"]
116
- subgraph U["Agent-controlled lifecycle"]
117
- H["In-loop steering hooks"]
118
- A["Agent runtime"]
119
- W["Candidate HEAD and worktree"]
120
- H -.-> A
121
- A --> W
122
- end
123
- J["Post-exit adjudication"]
124
- C["Committed and worktree checks"]
125
- V["Visible and pristine verification"]
126
- Q["Ancestry, dependency drift, quiescence"]
127
- X["Final exit verdict"]
128
- E --> A
129
- E --> J
130
- W --> J
131
- J --> C
132
- J --> V
133
- J --> Q
134
- C --> X
135
- V --> X
136
- Q --> X
137
- end
116
+ graph TD
117
+ entry["Trusted entry snapshot"]
118
+ hooks["In-loop hooks and observer"]
119
+ agent["Agent runtime"]
120
+ tree["Candidate commit and worktree"]
121
+ adjudicate["Post-exit adjudication"]
122
+ checks["Diff and worktree checks"]
123
+ verify["Visible and pristine verification"]
124
+ integrity["Ancestry dependency and quiescence"]
125
+ verdict["Final exit verdict"]
126
+
127
+ entry --> agent
128
+ hooks --> agent
129
+ agent --> tree
130
+ entry --> adjudicate
131
+ tree --> adjudicate
132
+ adjudicate --> checks
133
+ adjudicate --> verify
134
+ adjudicate --> integrity
135
+ checks --> verdict
136
+ verify --> verdict
137
+ integrity --> verdict
138
138
  ```
139
139
 
140
140
  Before starting the agent, the envelope
package/dist/cli/index.js CHANGED
@@ -1394,8 +1394,27 @@ function countAny(src) {
1394
1394
  }
1395
1395
  return r;
1396
1396
  }
1397
- var NARROW_LINE = /\bas\s+\(*\s*any\b|<\s*any\s*>|\bas\s+\(*\s*unknown\s*\)*\s+as\b|@ts-(?:ignore|expect-error|nocheck)\b/;
1397
+ var NARROW_LINE = /\bas\s+\(*\s*any\b|<\s*any\s*>|@ts-(?:ignore|expect-error|nocheck)\b/;
1398
1398
  var BROAD_LINE = /:\s*any\b|<[^<>]*\bany\b[^<>]*>/;
1399
+ function lineHasDoubleCast(line) {
1400
+ let sf;
1401
+ try {
1402
+ sf = ts2.createSourceFile("line.ts", line, ts2.ScriptTarget.Latest, true, ts2.ScriptKind.TS);
1403
+ } catch {
1404
+ return false;
1405
+ }
1406
+ let found = false;
1407
+ const visit = (n) => {
1408
+ if (found) return;
1409
+ if ((ts2.isAsExpression(n) || ts2.isTypeAssertionExpression(n)) && isDoubleCast(n)) {
1410
+ found = true;
1411
+ return;
1412
+ }
1413
+ ts2.forEachChild(n, visit);
1414
+ };
1415
+ visit(sf);
1416
+ return found;
1417
+ }
1399
1418
  var BLOCK_REMEDIATION = "Fix the underlying type instead of silencing the checker; do not cast to `any`.";
1400
1419
  var WARN_REMEDIATION = "Prefer a precise type or `unknown` + a guard over `any` here \u2014 flagged for review.";
1401
1420
  var tsAnyCast = {
@@ -1447,7 +1466,7 @@ var tsAnyCast = {
1447
1466
  }
1448
1467
  const jsdocCast = JS_FILE.test(c.path) ? new RegExp(JSDOC_ANY_CAST.source) : null;
1449
1468
  for (const l of addedLines(c)) {
1450
- if (NARROW_LINE.test(l.content) || jsdocCast && jsdocCast.test(l.content)) {
1469
+ if (NARROW_LINE.test(l.content) || lineHasDoubleCast(l.content) || jsdocCast && jsdocCast.test(l.content)) {
1451
1470
  out2.push(
1452
1471
  makeFinding(inTest ? WARN_RULE : BLOCK_RULE, policy, {
1453
1472
  file: c.path,
@@ -11964,6 +11983,17 @@ function pidAlive2(pid) {
11964
11983
  return errnoCode(e) === "EPERM";
11965
11984
  }
11966
11985
  }
11986
+ function observerExited(pid) {
11987
+ if (!pidAlive2(pid)) return true;
11988
+ if (process.platform !== "linux") return false;
11989
+ try {
11990
+ const stat = readFileSync16(`/proc/${pid}/stat`, "utf8");
11991
+ const state = stat.slice(stat.lastIndexOf(")") + 2).split(" ")[0];
11992
+ return state === "Z" || state === "X";
11993
+ } catch (e) {
11994
+ return errnoCode(e) === "ENOENT";
11995
+ }
11996
+ }
11967
11997
  function supervisedObserverLog(cwd) {
11968
11998
  const gd = gitDir(cwd) ?? join17(cwd, ".git");
11969
11999
  return join17(
@@ -11995,7 +12025,7 @@ function startSupervisedObserver(cwd, base, entry) {
11995
12025
  while (Date.now() < deadline) {
11996
12026
  const telemetry = watcherTelemetry(log);
11997
12027
  if (telemetry.state === "healthy" || telemetry.state === "degraded") break;
11998
- if (!pidAlive2(pid)) break;
12028
+ if (observerExited(pid)) break;
11999
12029
  waitMs(25);
12000
12030
  }
12001
12031
  return { log, pid, finished: false };
@@ -12004,17 +12034,14 @@ function stopObserverProcess(observer) {
12004
12034
  waitMs(100);
12005
12035
  const beforeStop = watcherTelemetry(observer.log);
12006
12036
  const pid = observer.pid;
12007
- if (pid !== null && pidAlive2(pid)) {
12037
+ if (pid !== null && !observerExited(pid)) {
12008
12038
  try {
12009
12039
  process.kill(pid, "SIGTERM");
12010
12040
  } catch {
12011
12041
  }
12012
12042
  const deadline = Date.now() + 2e3;
12013
- while (Date.now() < deadline) {
12014
- if (!pidAlive2(pid)) break;
12015
- waitMs(25);
12016
- }
12017
- if (pidAlive2(pid)) {
12043
+ while (!observerExited(pid) && Date.now() < deadline) waitMs(25);
12044
+ if (!observerExited(pid)) {
12018
12045
  try {
12019
12046
  process.kill(pid, "SIGKILL");
12020
12047
  } catch {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tamperward",
3
- "version": "2.20.0",
3
+ "version": "2.20.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",