tamperward 1.11.0 → 1.11.1
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 +53 -7
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -2791,7 +2791,7 @@ tamperward init: ${changed} change(s) applied. Commit them so the gate travels w
|
|
|
2791
2791
|
import { execFileSync as execFileSync4, spawnSync } from "node:child_process";
|
|
2792
2792
|
import { chmodSync as chmodSync2, cpSync, mkdirSync as mkdirSync6, mkdtempSync as mkdtempSync2, rmSync as rmSync2, statSync as statSync5, symlinkSync, writeFileSync as writeFileSync6, existsSync as existsSync8 } from "node:fs";
|
|
2793
2793
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
2794
|
-
import { dirname as dirname4, join as join9 } from "node:path";
|
|
2794
|
+
import { dirname as dirname4, join as join9, resolve } from "node:path";
|
|
2795
2795
|
var OVERLAY_CLASSES = ["tests", "snapshots", "config"];
|
|
2796
2796
|
function git2(args, cwd) {
|
|
2797
2797
|
return execFileSync4("git", args, { cwd, encoding: "utf8", maxBuffer: 1 << 28 });
|
|
@@ -2820,7 +2820,7 @@ function materialize(cwd, dest) {
|
|
|
2820
2820
|
cpSync(src, out2);
|
|
2821
2821
|
chmodSync2(out2, st.mode);
|
|
2822
2822
|
}
|
|
2823
|
-
const nm =
|
|
2823
|
+
const nm = resolve(cwd, "node_modules");
|
|
2824
2824
|
if (existsSync8(nm)) symlinkSync(nm, join9(dest, "node_modules"), "dir");
|
|
2825
2825
|
}
|
|
2826
2826
|
function overlayPristine(cwd, base, dest, policy) {
|
|
@@ -2955,8 +2955,8 @@ function parseVerify(args) {
|
|
|
2955
2955
|
// src/cli/run.ts
|
|
2956
2956
|
import { execFileSync as execFileSync5, spawnSync as spawnSync2 } from "node:child_process";
|
|
2957
2957
|
import { createHash as createHash5 } from "node:crypto";
|
|
2958
|
-
import { readdirSync as readdirSync3, readFileSync as readFileSync11, realpathSync } from "node:fs";
|
|
2959
|
-
import { join as join10 } from "node:path";
|
|
2958
|
+
import { readdirSync as readdirSync3, readFileSync as readFileSync11, readlinkSync, realpathSync, statSync as statSync6 } from "node:fs";
|
|
2959
|
+
import { join as join10, resolve as resolve2 } from "node:path";
|
|
2960
2960
|
var out = (s) => process.stdout.write(s + "\n");
|
|
2961
2961
|
var err = (s) => process.stderr.write(s + "\n");
|
|
2962
2962
|
function git3(args, cwd) {
|
|
@@ -2977,6 +2977,45 @@ function treeFingerprint(cwd) {
|
|
|
2977
2977
|
}
|
|
2978
2978
|
return h.digest("hex");
|
|
2979
2979
|
}
|
|
2980
|
+
function depsFingerprint(cwd) {
|
|
2981
|
+
const root = join10(cwd, "node_modules");
|
|
2982
|
+
const h = createHash5("sha256");
|
|
2983
|
+
const walk = (dir) => {
|
|
2984
|
+
let entries;
|
|
2985
|
+
try {
|
|
2986
|
+
entries = readdirSync3(dir, { withFileTypes: true });
|
|
2987
|
+
} catch {
|
|
2988
|
+
return;
|
|
2989
|
+
}
|
|
2990
|
+
for (const e of [...entries].sort((a, b) => a.name.localeCompare(b.name))) {
|
|
2991
|
+
const p = join10(dir, e.name);
|
|
2992
|
+
if (e.isDirectory()) walk(p);
|
|
2993
|
+
else if (e.isFile()) {
|
|
2994
|
+
h.update(p);
|
|
2995
|
+
try {
|
|
2996
|
+
h.update(readFileSync11(p));
|
|
2997
|
+
h.update(String(statSync6(p).mode));
|
|
2998
|
+
} catch {
|
|
2999
|
+
h.update("<unreadable>");
|
|
3000
|
+
}
|
|
3001
|
+
} else if (e.isSymbolicLink()) {
|
|
3002
|
+
h.update(p);
|
|
3003
|
+
try {
|
|
3004
|
+
h.update(readlinkSync(p));
|
|
3005
|
+
} catch {
|
|
3006
|
+
h.update("<unreadable-link>");
|
|
3007
|
+
}
|
|
3008
|
+
}
|
|
3009
|
+
}
|
|
3010
|
+
};
|
|
3011
|
+
try {
|
|
3012
|
+
if (!statSync6(root).isDirectory()) return "none";
|
|
3013
|
+
} catch {
|
|
3014
|
+
return "none";
|
|
3015
|
+
}
|
|
3016
|
+
walk(root);
|
|
3017
|
+
return h.digest("hex");
|
|
3018
|
+
}
|
|
2980
3019
|
function nowTicks() {
|
|
2981
3020
|
try {
|
|
2982
3021
|
return Math.floor(parseFloat(readFileSync11("/proc/uptime", "utf8").split(" ")[0]) * 100);
|
|
@@ -3018,7 +3057,7 @@ function survivorsHoldingTree(cwd, spawnedAfterTicks) {
|
|
|
3018
3057
|
return out2;
|
|
3019
3058
|
}
|
|
3020
3059
|
function runEnvelope(opts) {
|
|
3021
|
-
const cwd = opts.cwd ?? process.cwd();
|
|
3060
|
+
const cwd = resolve2(opts.cwd ?? process.cwd());
|
|
3022
3061
|
if (!opts.argv.length) {
|
|
3023
3062
|
err("tamperward run: no agent command given (usage: tamperward run [options] -- <command...>)");
|
|
3024
3063
|
return 2;
|
|
@@ -3055,6 +3094,7 @@ function runEnvelope(opts) {
|
|
|
3055
3094
|
}
|
|
3056
3095
|
}
|
|
3057
3096
|
out(`tamperward run \u2014 trusted base ${base.slice(0, 10)}; agent exit is untrusted.`);
|
|
3097
|
+
const depsBefore = depsFingerprint(cwd);
|
|
3058
3098
|
const spawnTicks = nowTicks();
|
|
3059
3099
|
const agent = spawnSync2(opts.argv[0], opts.argv.slice(1), { cwd, stdio: "inherit" });
|
|
3060
3100
|
const agentExit = agent.status ?? 1;
|
|
@@ -3089,16 +3129,21 @@ tamperward run \u2014 agent exit ${agentExit}; HISTORY_REWRITE \u2192 ENFORCEMEN
|
|
|
3089
3129
|
err("tamperward run: the working tree changed while it was being adjudicated \u2014");
|
|
3090
3130
|
err("the verdict below would describe a tree that no longer exists.");
|
|
3091
3131
|
}
|
|
3132
|
+
const depsDrifted = !opts.allowDepDrift && depsFingerprint(cwd) !== depsBefore;
|
|
3133
|
+
if (depsDrifted) {
|
|
3134
|
+
err("tamperward run: the installed dependency tree changed during this run \u2014 the program that");
|
|
3135
|
+
err("runs the suite is not the one we started with. Both verification runs execute it.");
|
|
3136
|
+
}
|
|
3092
3137
|
const survivors = survivorsHoldingTree(cwd, spawnTicks);
|
|
3093
3138
|
if (survivors.length) {
|
|
3094
3139
|
err(`tamperward run: ${survivors.length} process(es) started during this run still hold the`);
|
|
3095
3140
|
err(`working tree (pid ${survivors.join(", ")}). A verdict cannot outlive the tree it describes.`);
|
|
3096
3141
|
}
|
|
3097
|
-
const notQuiescent = mutatedDuringAdjudication || survivors.length > 0;
|
|
3142
|
+
const notQuiescent = mutatedDuringAdjudication || survivors.length > 0 || depsDrifted;
|
|
3098
3143
|
const cannot = diffCode === 2 || workCode === 2 || verifyCode === 2;
|
|
3099
3144
|
const blocked = diffCode === 1 || workCode === 1 || verifyCode === 1 || notQuiescent;
|
|
3100
3145
|
const enforcement = cannot ? 2 : blocked ? 1 : 0;
|
|
3101
|
-
const verdict2 = enforcement === 2 ? "CANNOT_ADJUDICATE (fail closed)" : notQuiescent ? "NOT_QUIESCENT \u2014 the tree moved, or something still holds it" : enforcement === 1 ? "ENFORCEMENT_FAILED \u2014 the tree the runtime released does not stand" : agentExit !== 0 ? `agent exited ${agentExit} (enforcement clean)` : "GREEN MEANS GREEN";
|
|
3146
|
+
const verdict2 = enforcement === 2 ? "CANNOT_ADJUDICATE (fail closed)" : depsDrifted ? "DEPENDENCY_DRIFT \u2014 the suite runner changed under the envelope" : notQuiescent ? "NOT_QUIESCENT \u2014 the tree moved, or something still holds it" : enforcement === 1 ? "ENFORCEMENT_FAILED \u2014 the tree the runtime released does not stand" : agentExit !== 0 ? `agent exited ${agentExit} (enforcement clean)` : "GREEN MEANS GREEN";
|
|
3102
3147
|
out(`
|
|
3103
3148
|
tamperward run \u2014 agent exit ${agentExit}; checks diff=${diffCode} worktree=${workCode} verify=${verifyCode} \u2192 ${verdict2}`);
|
|
3104
3149
|
return enforcement !== 0 ? enforcement : agentExit;
|
|
@@ -3115,6 +3160,7 @@ function parseRun(args) {
|
|
|
3115
3160
|
else if (a === "--budget") o.budget = Number(args[++i]);
|
|
3116
3161
|
else if (a === "--allow-dirty") o.allowDirty = true;
|
|
3117
3162
|
else if (a === "--settle") o.settle = Number(args[++i]);
|
|
3163
|
+
else if (a === "--allow-dep-drift") o.allowDepDrift = true;
|
|
3118
3164
|
else if (a === "--cwd") o.cwd = args[++i];
|
|
3119
3165
|
else {
|
|
3120
3166
|
o.argv = args.slice(i);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tamperward",
|
|
3
|
-
"version": "1.11.
|
|
3
|
+
"version": "1.11.1",
|
|
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",
|