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 +25 -25
- package/dist/cli/index.js +36 -9
- package/package.json +1 -1
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
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
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
|
|
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 (
|
|
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 &&
|
|
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
|
-
|
|
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.
|
|
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",
|