tamperward 2.39.11 → 2.39.13
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 +207 -122
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -788,9 +788,54 @@ function readStateFile(abs) {
|
|
|
788
788
|
if (e.kind === "absent") return null;
|
|
789
789
|
if (e.kind === "file") return textOf2(e) ?? "";
|
|
790
790
|
throw new StateFileError(
|
|
791
|
-
`${abs} ${notARegularFile(e)}; the gate reads its
|
|
791
|
+
`${abs} ${notARegularFile(e)}; the gate reads its state files only as regular files \u2014 remove what stands there so the state can be re-established`
|
|
792
792
|
);
|
|
793
793
|
}
|
|
794
|
+
function openRegular(abs, refused) {
|
|
795
|
+
let st;
|
|
796
|
+
try {
|
|
797
|
+
st = lstatSync2(abs);
|
|
798
|
+
} catch (e) {
|
|
799
|
+
const code2 = errCode(e);
|
|
800
|
+
if (code2 === "ENOENT" || code2 === "ENOTDIR") return null;
|
|
801
|
+
throw new StateFileError(`${abs} cannot be read (${errText(e)})${refused}`);
|
|
802
|
+
}
|
|
803
|
+
if (!st.isFile()) throw new StateFileError(`${abs} ${notARegularFile(classify(abs, st))}${refused}`);
|
|
804
|
+
let fd;
|
|
805
|
+
try {
|
|
806
|
+
fd = openSync(abs, O_READ);
|
|
807
|
+
} catch (e) {
|
|
808
|
+
const code2 = errCode(e);
|
|
809
|
+
if (code2 === "ENOENT") return null;
|
|
810
|
+
throw new StateFileError(
|
|
811
|
+
`${abs} ${code2 === "ELOOP" || code2 === "ENXIO" ? `changed shape while it was being opened (${errText(e)})` : `cannot be read (${errText(e)})`}${refused}`
|
|
812
|
+
);
|
|
813
|
+
}
|
|
814
|
+
let now;
|
|
815
|
+
try {
|
|
816
|
+
now = fstatSync(fd);
|
|
817
|
+
} catch (e) {
|
|
818
|
+
closeSync(fd);
|
|
819
|
+
throw new StateFileError(`${abs} cannot be read (${errText(e)})${refused}`);
|
|
820
|
+
}
|
|
821
|
+
if (now.isFile()) return fd;
|
|
822
|
+
closeSync(fd);
|
|
823
|
+
throw new StateFileError(`${abs} is a ${now.isDirectory() ? "directory" : irregularName(now)}${refused}`);
|
|
824
|
+
}
|
|
825
|
+
function stateDirectory(gitDir3) {
|
|
826
|
+
const dir = join3(gitDir3, "tamperward");
|
|
827
|
+
const st = lstatSync2(dir, { throwIfNoEntry: false });
|
|
828
|
+
if (st === void 0 || st.isDirectory()) return dir;
|
|
829
|
+
if (st.isSymbolicLink()) {
|
|
830
|
+
let target = "";
|
|
831
|
+
try {
|
|
832
|
+
target = readlinkSync(dir);
|
|
833
|
+
} catch {
|
|
834
|
+
}
|
|
835
|
+
throw new StateFileError(`${dir} is a symbolic link to ${escapeControl(target)}${STATE_DIR_REFUSED}`);
|
|
836
|
+
}
|
|
837
|
+
throw new StateFileError(`${dir} is a ${st.isFile() ? "regular file" : irregularName(st)}${STATE_DIR_REFUSED}`);
|
|
838
|
+
}
|
|
794
839
|
function multiplyLinked(st) {
|
|
795
840
|
return st.nlink === 1 ? null : `has ${st.nlink} names \u2014 a hard link is the same file under another name, the session marker's or the policy's, say`;
|
|
796
841
|
}
|
|
@@ -861,7 +906,7 @@ function unjudgeableProtected(cwd, policy, changes) {
|
|
|
861
906
|
}
|
|
862
907
|
return out3;
|
|
863
908
|
}
|
|
864
|
-
var READ_CAP, NO_META, O_READ, StateFileError, O_APPEND_REGULAR, APPEND_REFUSED;
|
|
909
|
+
var READ_CAP, NO_META, O_READ, StateFileError, STATE_DIR_REFUSED, O_APPEND_REGULAR, APPEND_REFUSED;
|
|
865
910
|
var init_disk = __esm({
|
|
866
911
|
"src/disk.ts"() {
|
|
867
912
|
"use strict";
|
|
@@ -872,6 +917,7 @@ var init_disk = __esm({
|
|
|
872
917
|
O_READ = constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0) | (constants.O_NONBLOCK ?? 0);
|
|
873
918
|
StateFileError = class extends Error {
|
|
874
919
|
};
|
|
920
|
+
STATE_DIR_REFUSED = "; the gate keeps its state only in a directory of its own under the git directory \u2014 replace what stands there with a directory, or remove it";
|
|
875
921
|
O_APPEND_REGULAR = constants.O_WRONLY | constants.O_APPEND | constants.O_CREAT | (constants.O_NOFOLLOW ?? 0) | (constants.O_NONBLOCK ?? 0);
|
|
876
922
|
APPEND_REFUSED = "; the gate appends its records only to a regular file with one name \u2014 remove what stands there so the record can be kept";
|
|
877
923
|
}
|
|
@@ -11614,7 +11660,13 @@ function writeBaseline(p, sha3) {
|
|
|
11614
11660
|
function baselinePath(cwd, sessionId) {
|
|
11615
11661
|
const gd = gitDir(cwd);
|
|
11616
11662
|
if (!gd) return null;
|
|
11617
|
-
|
|
11663
|
+
const name = `session-${sessionId.replace(UNSAFE, "")}`;
|
|
11664
|
+
try {
|
|
11665
|
+
return join10(stateDirectory(gd), name);
|
|
11666
|
+
} catch (e) {
|
|
11667
|
+
if (e instanceof StateFileError) throw new BaselineWriteError(join10(gd, "tamperward", name), e);
|
|
11668
|
+
throw e;
|
|
11669
|
+
}
|
|
11618
11670
|
}
|
|
11619
11671
|
function turnBaseline(cwd, sessionId) {
|
|
11620
11672
|
if (!sessionId) return null;
|
|
@@ -11681,7 +11733,7 @@ function statePath(cwd, sessionId, kind) {
|
|
|
11681
11733
|
if (!sessionId) return null;
|
|
11682
11734
|
const gd = gitDir2(cwd);
|
|
11683
11735
|
if (!gd) return null;
|
|
11684
|
-
const dir =
|
|
11736
|
+
const dir = stateDirectory(gd);
|
|
11685
11737
|
return join11(dir, `${kind}-${sessionId.replace(UNSAFE2, "")}.json`);
|
|
11686
11738
|
}
|
|
11687
11739
|
function ptreePath(cwd, sessionId) {
|
|
@@ -11867,7 +11919,7 @@ function snap(abs) {
|
|
|
11867
11919
|
}
|
|
11868
11920
|
function defaultEventLog(cwd) {
|
|
11869
11921
|
if (process.env.TAMPERWARD_FSEVENTS) return process.env.TAMPERWARD_FSEVENTS;
|
|
11870
|
-
return join12(gitDir(cwd) ?? join12(cwd, ".git"), "
|
|
11922
|
+
return join12(stateDirectory(gitDir(cwd) ?? join12(cwd, ".git")), "fsevents.jsonl");
|
|
11871
11923
|
}
|
|
11872
11924
|
function watcherHealthPath(log) {
|
|
11873
11925
|
return `${log}.health.json`;
|
|
@@ -12411,7 +12463,7 @@ var init_fs_events = __esm({
|
|
|
12411
12463
|
|
|
12412
12464
|
// src/cli/audit.ts
|
|
12413
12465
|
import { createHash as createHash6, randomBytes as randomBytes2 } from "node:crypto";
|
|
12414
|
-
import { closeSync as closeSync4,
|
|
12466
|
+
import { closeSync as closeSync4, mkdirSync as mkdirSync5, readSync as readSync3 } from "node:fs";
|
|
12415
12467
|
import { dirname as dirname4, isAbsolute as isAbsolute8, join as join13, resolve as resolve4 } from "node:path";
|
|
12416
12468
|
function sessionHash(sessionId) {
|
|
12417
12469
|
if (!sessionId) return void 0;
|
|
@@ -12425,19 +12477,19 @@ function configuredAuditPath(cwd, env = process.env) {
|
|
|
12425
12477
|
if (!value) return null;
|
|
12426
12478
|
if (value === "auto") {
|
|
12427
12479
|
const ctx = repoContext(cwd);
|
|
12428
|
-
return ctx ? join13(ctx.gitDir, "
|
|
12480
|
+
return ctx ? join13(stateDirectory(ctx.gitDir), "audit.jsonl") : null;
|
|
12429
12481
|
}
|
|
12430
12482
|
return isAbsolute8(value) ? value : resolve4(cwd, value);
|
|
12431
12483
|
}
|
|
12432
12484
|
function defaultAuditPath(cwd) {
|
|
12433
12485
|
const ctx = repoContext(cwd);
|
|
12434
|
-
return ctx ? join13(ctx.gitDir, "
|
|
12486
|
+
return ctx ? join13(stateDirectory(ctx.gitDir), "audit.jsonl") : null;
|
|
12435
12487
|
}
|
|
12436
12488
|
function recordAuditFindings(findings, context) {
|
|
12437
12489
|
if (findings.length === 0) return;
|
|
12438
|
-
const path = configuredAuditPath(context.cwd);
|
|
12439
|
-
if (!path) return;
|
|
12440
12490
|
try {
|
|
12491
|
+
const path = configuredAuditPath(context.cwd);
|
|
12492
|
+
if (!path) return;
|
|
12441
12493
|
mkdirSync5(dirname4(path), { recursive: true });
|
|
12442
12494
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
12443
12495
|
const session = sessionHash(context.sessionId);
|
|
@@ -12531,7 +12583,8 @@ function parseAuditLine(line, lineNumber) {
|
|
|
12531
12583
|
return parseAuditEvent(value, lineNumber);
|
|
12532
12584
|
}
|
|
12533
12585
|
function forEachAuditLine(file, onLine, maxLineBytes = MAX_AUDIT_LINE_BYTES) {
|
|
12534
|
-
const fd =
|
|
12586
|
+
const fd = openRegular(file, STATS_READ_REFUSED);
|
|
12587
|
+
if (fd === null) return false;
|
|
12535
12588
|
try {
|
|
12536
12589
|
const chunk = Buffer.allocUnsafe(64 * 1024);
|
|
12537
12590
|
let pending = [];
|
|
@@ -12571,6 +12624,7 @@ function forEachAuditLine(file, onLine, maxLineBytes = MAX_AUDIT_LINE_BYTES) {
|
|
|
12571
12624
|
} finally {
|
|
12572
12625
|
closeSync4(fd);
|
|
12573
12626
|
}
|
|
12627
|
+
return true;
|
|
12574
12628
|
}
|
|
12575
12629
|
function parseSince(value, nowMs = Date.now()) {
|
|
12576
12630
|
const relative13 = /^(\d+)(m|h|d)$/.exec(value);
|
|
@@ -12633,11 +12687,6 @@ function createAuditAggregator() {
|
|
|
12633
12687
|
}
|
|
12634
12688
|
};
|
|
12635
12689
|
}
|
|
12636
|
-
function summarizeAudit(events) {
|
|
12637
|
-
const aggregator = createAuditAggregator();
|
|
12638
|
-
for (const event of events) aggregator.add(event);
|
|
12639
|
-
return aggregator.finish();
|
|
12640
|
-
}
|
|
12641
12690
|
function renderAuditStats(summary) {
|
|
12642
12691
|
const out3 = [
|
|
12643
12692
|
"TamperWard audit stats",
|
|
@@ -12670,23 +12719,18 @@ function runStats(opts = {}) {
|
|
|
12670
12719
|
const file = opts.file ? isAbsolute8(opts.file) ? opts.file : resolve4(cwd, opts.file) : configured && configured !== "auto" ? isAbsolute8(configured) ? configured : resolve4(cwd, configured) : defaultAuditPath(cwd);
|
|
12671
12720
|
const cutoff = opts.since ? parseSince(opts.since) : null;
|
|
12672
12721
|
if (!file) throw new Error("stats needs --file outside a Git repository");
|
|
12673
|
-
if (!existsSync5(file)) {
|
|
12674
|
-
if (explicitFile) throw new Error(`audit file not found: ${file}`);
|
|
12675
|
-
const empty2 = summarizeAudit([]);
|
|
12676
|
-
process.stdout.write(opts.json ? JSON.stringify(empty2) + "\n" : renderAuditStats(empty2));
|
|
12677
|
-
return 0;
|
|
12678
|
-
}
|
|
12679
12722
|
const aggregator = createAuditAggregator();
|
|
12680
|
-
forEachAuditLine(file, (line, lineNumber) => {
|
|
12723
|
+
const read = forEachAuditLine(file, (line, lineNumber) => {
|
|
12681
12724
|
const event = parseAuditLine(line, lineNumber);
|
|
12682
12725
|
if (cutoff !== null && Date.parse(event.timestamp) < cutoff) return;
|
|
12683
12726
|
aggregator.add(event);
|
|
12684
12727
|
});
|
|
12728
|
+
if (!read && explicitFile) throw new Error(`audit file not found: ${file}`);
|
|
12685
12729
|
const summary = aggregator.finish();
|
|
12686
12730
|
process.stdout.write(opts.json ? JSON.stringify(summary) + "\n" : renderAuditStats(summary));
|
|
12687
12731
|
return 0;
|
|
12688
12732
|
}
|
|
12689
|
-
var AUDIT_SCHEMA_VERSION, AUDIT_LOG_ENV, MAX_AUDIT_LINE_BYTES, ALLOWED_KEYS;
|
|
12733
|
+
var AUDIT_SCHEMA_VERSION, AUDIT_LOG_ENV, MAX_AUDIT_LINE_BYTES, ALLOWED_KEYS, STATS_READ_REFUSED;
|
|
12690
12734
|
var init_audit = __esm({
|
|
12691
12735
|
"src/cli/audit.ts"() {
|
|
12692
12736
|
"use strict";
|
|
@@ -12706,11 +12750,12 @@ var init_audit = __esm({
|
|
|
12706
12750
|
"decision",
|
|
12707
12751
|
"session"
|
|
12708
12752
|
]);
|
|
12753
|
+
STATS_READ_REFUSED = "; stats reads the audit log only as a regular file \u2014 remove what stands there so the log can be read";
|
|
12709
12754
|
}
|
|
12710
12755
|
});
|
|
12711
12756
|
|
|
12712
12757
|
// src/cli/hook.ts
|
|
12713
|
-
import { readFileSync as readFileSync6, writeFileSync as writeFileSync5, existsSync as
|
|
12758
|
+
import { readFileSync as readFileSync6, writeFileSync as writeFileSync5, existsSync as existsSync5 } from "node:fs";
|
|
12714
12759
|
import { createHash as createHash7 } from "node:crypto";
|
|
12715
12760
|
function setSnapshotCache(cache3) {
|
|
12716
12761
|
snapshotCache = cache3;
|
|
@@ -13007,7 +13052,7 @@ function turnTransientBlocks(cwd, sessionId, policy, changes) {
|
|
|
13007
13052
|
recordObserverHealth(cwd, sessionId, telemetry.state, telemetry.reason);
|
|
13008
13053
|
}
|
|
13009
13054
|
const cp = cursorPath(cwd, sessionId);
|
|
13010
|
-
if (!
|
|
13055
|
+
if (!existsSync5(log)) return none;
|
|
13011
13056
|
let offset = 0;
|
|
13012
13057
|
const cursorText = cp ? readStateFile(cp) : null;
|
|
13013
13058
|
if (cursorText !== null) {
|
|
@@ -13285,7 +13330,7 @@ var init_ptree_cache = __esm({
|
|
|
13285
13330
|
});
|
|
13286
13331
|
|
|
13287
13332
|
// src/cli/hook-service.ts
|
|
13288
|
-
import { chmodSync, existsSync as
|
|
13333
|
+
import { chmodSync, existsSync as existsSync6, lstatSync as lstatSync8, mkdirSync as mkdirSync6, readFileSync as readFileSync7, rmSync as rmSync5, writeFileSync as writeFileSync6 } from "node:fs";
|
|
13289
13334
|
import { createConnection as createConnection2, createServer } from "node:net";
|
|
13290
13335
|
import { realpathSync as realpathSync4 } from "node:fs";
|
|
13291
13336
|
import { sep } from "node:path";
|
|
@@ -13373,7 +13418,7 @@ function removeQuietly(p) {
|
|
|
13373
13418
|
}
|
|
13374
13419
|
}
|
|
13375
13420
|
function ensurePrivateDir(dir, uid) {
|
|
13376
|
-
if (!
|
|
13421
|
+
if (!existsSync6(dir)) mkdirSync6(dir, { recursive: true, mode: 448 });
|
|
13377
13422
|
const st = lstatSync8(dir);
|
|
13378
13423
|
if (!st.isDirectory()) throw new Error(`${dir} is not a directory`);
|
|
13379
13424
|
if (st.uid !== uid) throw new Error(`${dir} is owned by uid ${st.uid}, not ${uid}; refusing to serve from it`);
|
|
@@ -13570,7 +13615,7 @@ async function stopHookService(paths, expectedRoot) {
|
|
|
13570
13615
|
process.kill(st.pid, "SIGTERM");
|
|
13571
13616
|
} catch {
|
|
13572
13617
|
}
|
|
13573
|
-
const gone = () => !pidAlive2(st.pid) || !
|
|
13618
|
+
const gone = () => !pidAlive2(st.pid) || !existsSync6(paths.socket);
|
|
13574
13619
|
const until = Date.now() + STOP_WAIT_MS;
|
|
13575
13620
|
while (!gone() && Date.now() < until) sleepSync(50);
|
|
13576
13621
|
if (!gone()) throw new Error(`hook service pid ${st.pid} did not exit within ${STOP_WAIT_MS / 1e3}s`);
|
|
@@ -13807,7 +13852,7 @@ var init_verifier_limits = __esm({
|
|
|
13807
13852
|
// src/cli/init.ts
|
|
13808
13853
|
import { execFileSync as execFileSync6 } from "node:child_process";
|
|
13809
13854
|
import { createHash as createHash8 } from "node:crypto";
|
|
13810
|
-
import { existsSync as
|
|
13855
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync7, readFileSync as readFileSync8, realpathSync as realpathSync5 } from "node:fs";
|
|
13811
13856
|
import { basename as basename3, dirname as dirname5, isAbsolute as isAbsolute9, join as join15, relative as relative4, resolve as resolve6 } from "node:path";
|
|
13812
13857
|
function gitConfig(cwd, key2) {
|
|
13813
13858
|
try {
|
|
@@ -13911,7 +13956,7 @@ function verifierCandidates(cwd) {
|
|
|
13911
13956
|
if (/^\s*\[tool\.pytest(?:\.ini_options)?\]\s*$/m.test(pyproject)) add("pytest");
|
|
13912
13957
|
} catch {
|
|
13913
13958
|
}
|
|
13914
|
-
if (
|
|
13959
|
+
if (existsSync7(join15(cwd, "pytest.ini"))) add("pytest");
|
|
13915
13960
|
try {
|
|
13916
13961
|
const setupCfg = readFileSync8(join15(cwd, "setup.cfg"), "utf8");
|
|
13917
13962
|
if (/^\s*\[tool:pytest\]\s*$/m.test(setupCfg)) add("pytest");
|
|
@@ -13971,7 +14016,7 @@ function planPolicy(cwd) {
|
|
|
13971
14016
|
const path = join15(cwd, POLICY_FILE);
|
|
13972
14017
|
const refused = refuseNonRegular(path);
|
|
13973
14018
|
if (refused) return { item: "policy", path: POLICY_FILE, status: "error", detail: refused };
|
|
13974
|
-
if (
|
|
14019
|
+
if (existsSync7(path)) {
|
|
13975
14020
|
try {
|
|
13976
14021
|
loadPolicy(cwd);
|
|
13977
14022
|
} catch (e) {
|
|
@@ -13990,7 +14035,7 @@ function planPolicy(cwd) {
|
|
|
13990
14035
|
function planGitignore(cwd) {
|
|
13991
14036
|
const rel = ".gitignore";
|
|
13992
14037
|
const path = join15(cwd, rel);
|
|
13993
|
-
if (!
|
|
14038
|
+
if (!existsSync7(join15(cwd, "node_modules"))) return null;
|
|
13994
14039
|
let existing = "";
|
|
13995
14040
|
let kind;
|
|
13996
14041
|
try {
|
|
@@ -14055,7 +14100,7 @@ function planClaudeHooks(cwd) {
|
|
|
14055
14100
|
const refused = refuseNonRegular(path);
|
|
14056
14101
|
if (refused) return { item: "agent", path: rel, status: "error", detail: refused };
|
|
14057
14102
|
let settings = {};
|
|
14058
|
-
if (
|
|
14103
|
+
if (existsSync7(path)) {
|
|
14059
14104
|
let parsed;
|
|
14060
14105
|
try {
|
|
14061
14106
|
parsed = JSON.parse(readFileSync8(path, "utf8"));
|
|
@@ -14107,7 +14152,7 @@ function planClaudeHooks(cwd) {
|
|
|
14107
14152
|
return {
|
|
14108
14153
|
item: "agent",
|
|
14109
14154
|
path: rel,
|
|
14110
|
-
status:
|
|
14155
|
+
status: existsSync7(path) ? "update" : "create",
|
|
14111
14156
|
detail: [
|
|
14112
14157
|
needPre && "wire PreToolUse deny",
|
|
14113
14158
|
needStop && "wire Stop sweep",
|
|
@@ -14151,7 +14196,7 @@ function hooksDir(cwd) {
|
|
|
14151
14196
|
if (out3) return resolve6(cwd, out3);
|
|
14152
14197
|
} catch {
|
|
14153
14198
|
}
|
|
14154
|
-
return
|
|
14199
|
+
return existsSync7(join15(cwd, ".git")) ? join15(cwd, ".git", "hooks") : null;
|
|
14155
14200
|
}
|
|
14156
14201
|
function display(cwd, path) {
|
|
14157
14202
|
const rel = relative4(cwd, path);
|
|
@@ -14178,11 +14223,11 @@ function planPreCommit(cwd) {
|
|
|
14178
14223
|
const skip = (detail) => ({ item: "pre-commit", path: "(none)", status: "skip", detail });
|
|
14179
14224
|
let path;
|
|
14180
14225
|
let note;
|
|
14181
|
-
if (
|
|
14226
|
+
if (existsSync7(join15(cwd, ".husky"))) {
|
|
14182
14227
|
path = join15(cwd, ".husky", "pre-commit");
|
|
14183
14228
|
note = "husky";
|
|
14184
14229
|
} else {
|
|
14185
|
-
const managed = MANAGED_HOOKS.find((m) => m.configs.some((c) =>
|
|
14230
|
+
const managed = MANAGED_HOOKS.find((m) => m.configs.some((c) => existsSync7(join15(cwd, c))));
|
|
14186
14231
|
if (managed) {
|
|
14187
14232
|
return skip(`${managed.name} manages this repository's hooks and regenerates them on install, so a line in the hooks directory would not last \u2014 ${managed.hint}`);
|
|
14188
14233
|
}
|
|
@@ -14200,7 +14245,7 @@ function planPreCommit(cwd) {
|
|
|
14200
14245
|
const rel = display(cwd, path);
|
|
14201
14246
|
const refused = refuseNonRegular(path);
|
|
14202
14247
|
if (refused) return { item: "pre-commit", path: rel, status: "error", detail: refused };
|
|
14203
|
-
const existing =
|
|
14248
|
+
const existing = existsSync7(path) ? readFileSync8(path, "utf8") : null;
|
|
14204
14249
|
const hookMode = () => existingMode(path, 493) | 73;
|
|
14205
14250
|
if (existing === null) {
|
|
14206
14251
|
return {
|
|
@@ -14331,7 +14376,7 @@ function planWorkflow(cwd, force) {
|
|
|
14331
14376
|
};
|
|
14332
14377
|
const refused = refuseNonRegular(path);
|
|
14333
14378
|
if (refused) return { item: "ci", path: rel, status: "error", detail: refused };
|
|
14334
|
-
if (!
|
|
14379
|
+
if (!existsSync7(path)) {
|
|
14335
14380
|
return {
|
|
14336
14381
|
item: "ci",
|
|
14337
14382
|
path: rel,
|
|
@@ -14689,7 +14734,7 @@ var init_fingerprint = __esm({
|
|
|
14689
14734
|
// src/dependency-env.ts
|
|
14690
14735
|
import { createHash as createHash10 } from "node:crypto";
|
|
14691
14736
|
import {
|
|
14692
|
-
existsSync as
|
|
14737
|
+
existsSync as existsSync8,
|
|
14693
14738
|
lstatSync as lstatSync9,
|
|
14694
14739
|
readdirSync as readdirSync3,
|
|
14695
14740
|
readFileSync as readFileSync9,
|
|
@@ -14843,7 +14888,7 @@ function snapshot(roots, probes, cwd) {
|
|
|
14843
14888
|
const h = createHash10("sha256");
|
|
14844
14889
|
for (const probe of probes) {
|
|
14845
14890
|
h.update(
|
|
14846
|
-
"probe\0" + probe.kind + "\0" + probe.path + "\0" + (
|
|
14891
|
+
"probe\0" + probe.kind + "\0" + probe.path + "\0" + (existsSync8(probe.path) ? "present" : "absent") + "\0"
|
|
14847
14892
|
);
|
|
14848
14893
|
}
|
|
14849
14894
|
for (const root of roots) fingerprintRoot(root, cwd, h);
|
|
@@ -14902,7 +14947,7 @@ function resolveExecutable(token, cwd, env) {
|
|
|
14902
14947
|
if (token.includes("/") || token.includes("\\")) {
|
|
14903
14948
|
const path = isAbsolute10(token) ? token : resolve7(cwd, token);
|
|
14904
14949
|
try {
|
|
14905
|
-
return
|
|
14950
|
+
return existsSync8(path) ? realpathSync6(path) : null;
|
|
14906
14951
|
} catch {
|
|
14907
14952
|
return null;
|
|
14908
14953
|
}
|
|
@@ -14910,7 +14955,7 @@ function resolveExecutable(token, cwd, env) {
|
|
|
14910
14955
|
for (const entry of (env.PATH ?? "").split(delimiter).filter(Boolean)) {
|
|
14911
14956
|
const candidate = resolve7(entry, token);
|
|
14912
14957
|
try {
|
|
14913
|
-
if (
|
|
14958
|
+
if (existsSync8(candidate) && statSync3(candidate).isFile()) return realpathSync6(candidate);
|
|
14914
14959
|
} catch {
|
|
14915
14960
|
}
|
|
14916
14961
|
}
|
|
@@ -14933,7 +14978,7 @@ function inferredVenvFromToken(token, cwd) {
|
|
|
14933
14978
|
const parentName = basename4(parent).toLowerCase();
|
|
14934
14979
|
if (parentName !== "bin" && parentName !== "scripts") return null;
|
|
14935
14980
|
const root = dirname6(parent);
|
|
14936
|
-
return
|
|
14981
|
+
return existsSync8(join16(root, "pyvenv.cfg")) ? root : null;
|
|
14937
14982
|
}
|
|
14938
14983
|
function unsupportedEcosystem(command, token) {
|
|
14939
14984
|
const name = token ? basename4(token).toLowerCase() : "";
|
|
@@ -14949,11 +14994,11 @@ function inferredVenv(executable) {
|
|
|
14949
14994
|
const parentName = basename4(parent).toLowerCase();
|
|
14950
14995
|
if (parentName !== "bin" && parentName !== "scripts") return null;
|
|
14951
14996
|
const root = dirname6(parent);
|
|
14952
|
-
return
|
|
14997
|
+
return existsSync8(join16(root, "pyvenv.cfg")) ? root : null;
|
|
14953
14998
|
}
|
|
14954
14999
|
function venvProblem(root) {
|
|
14955
15000
|
const cfg = join16(root, "pyvenv.cfg");
|
|
14956
|
-
if (!
|
|
15001
|
+
if (!existsSync8(cfg)) return "VIRTUAL_ENV " + JSON.stringify(root) + " has no pyvenv.cfg";
|
|
14957
15002
|
try {
|
|
14958
15003
|
const body = readFileSync9(cfg, "utf8");
|
|
14959
15004
|
if (/^\s*include-system-site-packages\s*=\s*true\s*$/im.test(body)) {
|
|
@@ -14980,7 +15025,7 @@ function discoverDependencyEnvironment(cwdInput, command, env = process.env) {
|
|
|
14980
15025
|
};
|
|
14981
15026
|
try {
|
|
14982
15027
|
const nodeModules = join16(cwd, "node_modules");
|
|
14983
|
-
if (
|
|
15028
|
+
if (existsSync8(nodeModules)) addRoot("node_modules", nodeModules);
|
|
14984
15029
|
else probes.push({ kind: "node_modules", path: nodeModules });
|
|
14985
15030
|
const token = firstExecutable(command);
|
|
14986
15031
|
const executable = resolveExecutable(token, cwd, env);
|
|
@@ -14992,7 +15037,7 @@ function discoverDependencyEnvironment(cwdInput, command, env = process.env) {
|
|
|
14992
15037
|
venv = resolve7(env.VIRTUAL_ENV);
|
|
14993
15038
|
} else {
|
|
14994
15039
|
venv = inferredVenv(executable) ?? inferredVenvFromToken(token, cwd);
|
|
14995
|
-
if (!venv && /(?:^|\s)uv\s+run(?:\s|$)/.test(command) &&
|
|
15040
|
+
if (!venv && /(?:^|\s)uv\s+run(?:\s|$)/.test(command) && existsSync8(join16(cwd, ".venv", "pyvenv.cfg"))) {
|
|
14996
15041
|
venv = join16(cwd, ".venv");
|
|
14997
15042
|
}
|
|
14998
15043
|
}
|
|
@@ -15950,7 +15995,7 @@ var init_verifier_backend = __esm({
|
|
|
15950
15995
|
// src/verification-state.ts
|
|
15951
15996
|
import { execFileSync as execFileSync8 } from "node:child_process";
|
|
15952
15997
|
import { createHash as createHash12 } from "node:crypto";
|
|
15953
|
-
import { mkdirSync as mkdirSync8, readFileSync as readFileSync11, rmSync as rmSync7
|
|
15998
|
+
import { mkdirSync as mkdirSync8, readFileSync as readFileSync11, rmSync as rmSync7 } from "node:fs";
|
|
15954
15999
|
import { dirname as dirname8, join as join19 } from "node:path";
|
|
15955
16000
|
function git2(args, cwd) {
|
|
15956
16001
|
return execFileSync8("git", args, {
|
|
@@ -16067,7 +16112,7 @@ function computeBinding(cwd, inputs, precomputed) {
|
|
|
16067
16112
|
}
|
|
16068
16113
|
function stateDir(cwd) {
|
|
16069
16114
|
const ctx = repoContext(cwd);
|
|
16070
|
-
return ctx ?
|
|
16115
|
+
return ctx ? stateDirectory(ctx.gitDir) : null;
|
|
16071
16116
|
}
|
|
16072
16117
|
function verificationRecordPath(cwd) {
|
|
16073
16118
|
const dir = stateDir(cwd);
|
|
@@ -16094,11 +16139,17 @@ function recordVerification(cwd, inputs, treeFingerprintValue) {
|
|
|
16094
16139
|
binding
|
|
16095
16140
|
};
|
|
16096
16141
|
mkdirSync8(dirname8(path), { recursive: true });
|
|
16097
|
-
|
|
16142
|
+
atomicReplaceFile(path, JSON.stringify(record) + "\n", 438);
|
|
16098
16143
|
return true;
|
|
16099
16144
|
}
|
|
16100
16145
|
function invalidateVerificationRecordIfCurrent(cwd) {
|
|
16101
|
-
|
|
16146
|
+
let record;
|
|
16147
|
+
try {
|
|
16148
|
+
record = readVerificationRecord(cwd);
|
|
16149
|
+
} catch (e) {
|
|
16150
|
+
if (e instanceof StateFileError) return false;
|
|
16151
|
+
throw e;
|
|
16152
|
+
}
|
|
16102
16153
|
if (!record) return false;
|
|
16103
16154
|
let live;
|
|
16104
16155
|
try {
|
|
@@ -16160,12 +16211,8 @@ function parseVerificationRecord(value) {
|
|
|
16160
16211
|
function readVerificationRecord(cwd) {
|
|
16161
16212
|
const path = verificationRecordPath(cwd);
|
|
16162
16213
|
if (!path) return null;
|
|
16163
|
-
|
|
16164
|
-
|
|
16165
|
-
raw = readFileSync11(path, "utf8");
|
|
16166
|
-
} catch {
|
|
16167
|
-
return null;
|
|
16168
|
-
}
|
|
16214
|
+
const raw = readStateFile(path);
|
|
16215
|
+
if (raw === null) return null;
|
|
16169
16216
|
let parsed;
|
|
16170
16217
|
try {
|
|
16171
16218
|
parsed = JSON.parse(raw);
|
|
@@ -16183,25 +16230,25 @@ function pidAlive3(pid) {
|
|
|
16183
16230
|
}
|
|
16184
16231
|
}
|
|
16185
16232
|
function beginVerifying(cwd) {
|
|
16186
|
-
const path = verifyingMarkerPath(cwd);
|
|
16187
|
-
if (!path) return false;
|
|
16188
16233
|
try {
|
|
16234
|
+
const path = verifyingMarkerPath(cwd);
|
|
16235
|
+
if (!path) return false;
|
|
16189
16236
|
const marker = {
|
|
16190
16237
|
schema_version: VERIFICATION_STATE_SCHEMA_VERSION,
|
|
16191
16238
|
pid: process.pid,
|
|
16192
16239
|
started_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
16193
16240
|
};
|
|
16194
16241
|
mkdirSync8(dirname8(path), { recursive: true });
|
|
16195
|
-
|
|
16242
|
+
atomicReplaceFile(path, JSON.stringify(marker) + "\n", 438);
|
|
16196
16243
|
return true;
|
|
16197
16244
|
} catch {
|
|
16198
16245
|
return false;
|
|
16199
16246
|
}
|
|
16200
16247
|
}
|
|
16201
16248
|
function endVerifying(cwd) {
|
|
16202
|
-
const path = verifyingMarkerPath(cwd);
|
|
16203
|
-
if (!path) return;
|
|
16204
16249
|
try {
|
|
16250
|
+
const path = verifyingMarkerPath(cwd);
|
|
16251
|
+
if (!path) return;
|
|
16205
16252
|
rmSync7(path, { force: true });
|
|
16206
16253
|
} catch {
|
|
16207
16254
|
}
|
|
@@ -16209,9 +16256,11 @@ function endVerifying(cwd) {
|
|
|
16209
16256
|
function readVerifyingMarker(cwd) {
|
|
16210
16257
|
const path = verifyingMarkerPath(cwd);
|
|
16211
16258
|
if (!path) return null;
|
|
16259
|
+
const raw = readStateFile(path);
|
|
16260
|
+
if (raw === null) return null;
|
|
16212
16261
|
let parsed;
|
|
16213
16262
|
try {
|
|
16214
|
-
parsed = JSON.parse(
|
|
16263
|
+
parsed = JSON.parse(raw);
|
|
16215
16264
|
} catch {
|
|
16216
16265
|
return null;
|
|
16217
16266
|
}
|
|
@@ -16238,10 +16287,22 @@ function environmentInputDivergences(recorded, live) {
|
|
|
16238
16287
|
return ENVIRONMENT_INPUTS.filter((input) => recorded[input] !== live[input]);
|
|
16239
16288
|
}
|
|
16240
16289
|
function evaluateVerificationState(cwd) {
|
|
16241
|
-
|
|
16290
|
+
let marker;
|
|
16291
|
+
let record;
|
|
16292
|
+
try {
|
|
16293
|
+
marker = readVerifyingMarker(cwd);
|
|
16294
|
+
record = marker ? null : readVerificationRecord(cwd);
|
|
16295
|
+
} catch (e) {
|
|
16296
|
+
if (!(e instanceof StateFileError)) throw e;
|
|
16297
|
+
return {
|
|
16298
|
+
state: "UNVERIFIED",
|
|
16299
|
+
reason: "the verification store cannot be read: something other than a regular file stands at a record path",
|
|
16300
|
+
detail: e.message
|
|
16301
|
+
};
|
|
16302
|
+
}
|
|
16303
|
+
if (marker) {
|
|
16242
16304
|
return { state: "VERIFYING", reason: "a verification is in progress" };
|
|
16243
16305
|
}
|
|
16244
|
-
const record = readVerificationRecord(cwd);
|
|
16245
16306
|
if (!record) {
|
|
16246
16307
|
return {
|
|
16247
16308
|
state: "UNVERIFIED",
|
|
@@ -16296,6 +16357,8 @@ var init_verification_state = __esm({
|
|
|
16296
16357
|
init_repo_context();
|
|
16297
16358
|
init_wiring();
|
|
16298
16359
|
init_dependency_env();
|
|
16360
|
+
init_disk();
|
|
16361
|
+
init_safe_write();
|
|
16299
16362
|
VERIFICATION_STATE_SCHEMA_VERSION = 1;
|
|
16300
16363
|
BINDING_INPUTS = [
|
|
16301
16364
|
"tree",
|
|
@@ -16345,7 +16408,7 @@ var init_verification_state = __esm({
|
|
|
16345
16408
|
|
|
16346
16409
|
// src/verification-receipt.ts
|
|
16347
16410
|
import { createHash as createHash13 } from "node:crypto";
|
|
16348
|
-
import { mkdirSync as mkdirSync9, rmSync as rmSync8
|
|
16411
|
+
import { mkdirSync as mkdirSync9, rmSync as rmSync8 } from "node:fs";
|
|
16349
16412
|
import { dirname as dirname9, join as join20 } from "node:path";
|
|
16350
16413
|
function isRecord5(v) {
|
|
16351
16414
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
@@ -16385,23 +16448,23 @@ function receiptFromRecord(record) {
|
|
|
16385
16448
|
}
|
|
16386
16449
|
function receiptPath(cwd) {
|
|
16387
16450
|
const ctx = repoContext(cwd);
|
|
16388
|
-
return ctx ? join20(ctx.gitDir, "
|
|
16451
|
+
return ctx ? join20(stateDirectory(ctx.gitDir), "verification-receipt.json") : null;
|
|
16389
16452
|
}
|
|
16390
16453
|
function storeReceipt(cwd, receipt) {
|
|
16391
|
-
const path = receiptPath(cwd);
|
|
16392
|
-
if (!path) return false;
|
|
16393
16454
|
try {
|
|
16455
|
+
const path = receiptPath(cwd);
|
|
16456
|
+
if (!path) return false;
|
|
16394
16457
|
mkdirSync9(dirname9(path), { recursive: true });
|
|
16395
|
-
|
|
16458
|
+
atomicReplaceFile(path, JSON.stringify(receipt) + "\n", 438);
|
|
16396
16459
|
return true;
|
|
16397
16460
|
} catch {
|
|
16398
16461
|
return false;
|
|
16399
16462
|
}
|
|
16400
16463
|
}
|
|
16401
16464
|
function removeStoredReceipt(cwd) {
|
|
16402
|
-
const path = receiptPath(cwd);
|
|
16403
|
-
if (!path) return;
|
|
16404
16465
|
try {
|
|
16466
|
+
const path = receiptPath(cwd);
|
|
16467
|
+
if (!path) return;
|
|
16405
16468
|
rmSync8(path, { force: true });
|
|
16406
16469
|
} catch {
|
|
16407
16470
|
}
|
|
@@ -16563,6 +16626,8 @@ var RECEIPT_SCHEMA_VERSION, RECEIPT_STAGE_RESULTS, RECEIPT_INTEGRITY_RESULTS;
|
|
|
16563
16626
|
var init_verification_receipt = __esm({
|
|
16564
16627
|
"src/verification-receipt.ts"() {
|
|
16565
16628
|
"use strict";
|
|
16629
|
+
init_disk();
|
|
16630
|
+
init_safe_write();
|
|
16566
16631
|
init_repo_context();
|
|
16567
16632
|
init_verification_state();
|
|
16568
16633
|
init_machine_output();
|
|
@@ -16575,7 +16640,7 @@ var init_verification_receipt = __esm({
|
|
|
16575
16640
|
// src/cli/verify.ts
|
|
16576
16641
|
import { execFileSync as execFileSync9, spawnSync as spawnSync3 } from "node:child_process";
|
|
16577
16642
|
import { createHash as createHash14 } from "node:crypto";
|
|
16578
|
-
import { chmodSync as chmodSync2, cpSync, lstatSync as lstatSync10, mkdirSync as mkdirSync10, mkdtempSync as mkdtempSync3, readFileSync as readFileSync12, readlinkSync as readlinkSync3, rmSync as rmSync9, symlinkSync, writeFileSync as
|
|
16643
|
+
import { chmodSync as chmodSync2, cpSync, lstatSync as lstatSync10, mkdirSync as mkdirSync10, mkdtempSync as mkdtempSync3, readFileSync as readFileSync12, readlinkSync as readlinkSync3, rmSync as rmSync9, symlinkSync, writeFileSync as writeFileSync8, existsSync as existsSync9 } from "node:fs";
|
|
16579
16644
|
import { tmpdir as tmpdir4 } from "node:os";
|
|
16580
16645
|
import { dirname as dirname10, isAbsolute as isAbsolute11, join as join21, relative as relative6, resolve as resolve9, sep as sep4 } from "node:path";
|
|
16581
16646
|
function oracleAssuranceReport() {
|
|
@@ -16770,8 +16835,8 @@ function probeFilesystemCaseSensitivity(dir) {
|
|
|
16770
16835
|
const upper = join21(dir, ".tw-case-probe-A");
|
|
16771
16836
|
const lower = join21(dir, ".tw-case-probe-a");
|
|
16772
16837
|
try {
|
|
16773
|
-
|
|
16774
|
-
return !
|
|
16838
|
+
writeFileSync8(upper, "", { flag: "wx" });
|
|
16839
|
+
return !existsSync9(lower);
|
|
16775
16840
|
} finally {
|
|
16776
16841
|
rmSync9(upper, { force: true });
|
|
16777
16842
|
}
|
|
@@ -16873,7 +16938,7 @@ function overlayPristine(cwd, base, dest, policy, cmd, dependencyRoot, caseSensi
|
|
|
16873
16938
|
safeSymlink(target, out3, dest, `the base's ${e.path}`);
|
|
16874
16939
|
restoredLinks.push({ path: e.path, out: out3, target });
|
|
16875
16940
|
} else {
|
|
16876
|
-
|
|
16941
|
+
writeFileSync8(out3, content);
|
|
16877
16942
|
chmodSync2(out3, parseInt(e.mode.slice(-4), 8) & 511);
|
|
16878
16943
|
}
|
|
16879
16944
|
restored.push(e.path);
|
|
@@ -16898,7 +16963,7 @@ function suiteEnv(scratch) {
|
|
|
16898
16963
|
}
|
|
16899
16964
|
const userRc = join21(scratch, "npmrc-user");
|
|
16900
16965
|
const globalRc = join21(scratch, "npmrc-global");
|
|
16901
|
-
for (const f of [userRc, globalRc])
|
|
16966
|
+
for (const f of [userRc, globalRc]) writeFileSync8(f, "", { mode: 292 });
|
|
16902
16967
|
env.npm_config_userconfig = userRc;
|
|
16903
16968
|
env.npm_config_globalconfig = globalRc;
|
|
16904
16969
|
env.npm_config_node_options = " ";
|
|
@@ -17649,7 +17714,7 @@ var init_verify = __esm({
|
|
|
17649
17714
|
// src/cli/run.ts
|
|
17650
17715
|
import { execFileSync as execFileSync10, spawn, spawnSync as spawnSync4 } from "node:child_process";
|
|
17651
17716
|
import { randomBytes as randomBytes3 } from "node:crypto";
|
|
17652
|
-
import { accessSync as accessSync3, constants as fsConstants, mkdtempSync as mkdtempSync4, readdirSync as readdirSync4, readFileSync as readFileSync13, readlinkSync as readlinkSync4, realpathSync as realpathSync8, rmSync as rmSync10, statSync as statSync5, writeFileSync as
|
|
17717
|
+
import { accessSync as accessSync3, constants as fsConstants, mkdtempSync as mkdtempSync4, readdirSync as readdirSync4, readFileSync as readFileSync13, readlinkSync as readlinkSync4, realpathSync as realpathSync8, rmSync as rmSync10, statSync as statSync5, writeFileSync as writeFileSync9 } from "node:fs";
|
|
17653
17718
|
import { tmpdir as tmpdir5 } from "node:os";
|
|
17654
17719
|
import { dirname as dirname11, join as join22, resolve as resolve10 } from "node:path";
|
|
17655
17720
|
function authoritativeRunLifecyclePlatform(platform = process.platform) {
|
|
@@ -17746,7 +17811,7 @@ function runAgentSupervised(argv, cwd, budgetSecs, linuxPythonCandidates, lifecy
|
|
|
17746
17811
|
failure: trustedPython.reason ?? "trusted Linux python3 interpreter is unavailable"
|
|
17747
17812
|
};
|
|
17748
17813
|
}
|
|
17749
|
-
|
|
17814
|
+
writeFileSync9(agentEnvFile, JSON.stringify(process.env), { mode: 384 });
|
|
17750
17815
|
executable = trustedPython.path;
|
|
17751
17816
|
args = [
|
|
17752
17817
|
"-I",
|
|
@@ -17857,8 +17922,7 @@ function observerExited(pid) {
|
|
|
17857
17922
|
function supervisedObserverLog(cwd) {
|
|
17858
17923
|
const gd = gitDir(cwd) ?? join22(cwd, ".git");
|
|
17859
17924
|
return join22(
|
|
17860
|
-
gd,
|
|
17861
|
-
"tamperward",
|
|
17925
|
+
stateDirectory(gd),
|
|
17862
17926
|
`run-observer-${process.pid}-${Date.now()}-${randomBytes3(4).toString("hex")}.jsonl`
|
|
17863
17927
|
);
|
|
17864
17928
|
}
|
|
@@ -18565,7 +18629,7 @@ raise SystemExit(0)
|
|
|
18565
18629
|
|
|
18566
18630
|
// src/cli/doctor.ts
|
|
18567
18631
|
import { execFileSync as execFileSync11 } from "node:child_process";
|
|
18568
|
-
import { existsSync as
|
|
18632
|
+
import { existsSync as existsSync10, readFileSync as readFileSync14, readdirSync as readdirSync5 } from "node:fs";
|
|
18569
18633
|
import { join as join23, resolve as resolve11 } from "node:path";
|
|
18570
18634
|
function lifecyclePlatformCheck(platform = process.platform, linuxPython = platform === "linux" ? trustedLinuxPython() : null) {
|
|
18571
18635
|
if (platform === "linux") {
|
|
@@ -18621,7 +18685,7 @@ function wiringState(status, authority) {
|
|
|
18621
18685
|
return authority ? "BROKEN" : "WARN";
|
|
18622
18686
|
}
|
|
18623
18687
|
function pinsInFile(path) {
|
|
18624
|
-
if (!
|
|
18688
|
+
if (!existsSync10(path)) return [];
|
|
18625
18689
|
let src = "";
|
|
18626
18690
|
try {
|
|
18627
18691
|
src = readFileSync14(path, "utf8");
|
|
@@ -18645,7 +18709,7 @@ function workflowPermissionCheck(cwd, workflowRels = [".github/workflows/tamperw
|
|
|
18645
18709
|
const warnings = [];
|
|
18646
18710
|
for (const rel of workflowRels) {
|
|
18647
18711
|
const path = resolve11(cwd, rel);
|
|
18648
|
-
if (!
|
|
18712
|
+
if (!existsSync10(path)) {
|
|
18649
18713
|
broken.push(`${rel} is missing`);
|
|
18650
18714
|
continue;
|
|
18651
18715
|
}
|
|
@@ -19050,7 +19114,7 @@ function diagnose(opts = {}) {
|
|
|
19050
19114
|
} else {
|
|
19051
19115
|
const workflowDirRel = ".github/workflows";
|
|
19052
19116
|
const workflowDir = resolve11(cwd, workflowDirRel);
|
|
19053
|
-
if (!
|
|
19117
|
+
if (!existsSync10(workflowDir)) {
|
|
19054
19118
|
return fail("ci-verifier", `${workflowDirRel}: workflow directory does not exist`);
|
|
19055
19119
|
}
|
|
19056
19120
|
let entries;
|
|
@@ -19070,7 +19134,7 @@ function diagnose(opts = {}) {
|
|
|
19070
19134
|
const authorityWorkflows = [];
|
|
19071
19135
|
for (const workflowRel of workflowRels) {
|
|
19072
19136
|
const workflowPath = resolve11(cwd, workflowRel);
|
|
19073
|
-
if (!
|
|
19137
|
+
if (!existsSync10(workflowPath)) {
|
|
19074
19138
|
return fail("ci-verifier", `${workflowRel}: workflow does not exist`);
|
|
19075
19139
|
}
|
|
19076
19140
|
let doc;
|
|
@@ -19304,7 +19368,10 @@ function renderStatus(model, colour) {
|
|
|
19304
19368
|
if (v.state === "STALE" && v.reason) rows.push(["Reason", v.reason]);
|
|
19305
19369
|
else if (v.state === "BROKEN") rows.push(["Reason", v.detail ?? v.reason ?? "authority wiring is invalid"]);
|
|
19306
19370
|
else if (v.state === "VERIFYING") rows.push(["Reason", v.reason ?? "a verification is in progress"]);
|
|
19307
|
-
else if (v.state === "UNVERIFIED"
|
|
19371
|
+
else if (v.state === "UNVERIFIED" && v.detail) {
|
|
19372
|
+
rows.push(["Reason", v.detail]);
|
|
19373
|
+
rows.push(["Next", "remove what stands at that path, then run `tamperward verify`"]);
|
|
19374
|
+
} else if (v.state === "UNVERIFIED") rows.push(["Next", "run `tamperward verify` to establish a verified baseline"]);
|
|
19308
19375
|
if (rows.length) {
|
|
19309
19376
|
lines.push("");
|
|
19310
19377
|
const width = Math.max(...rows.map(([k]) => k.length));
|
|
@@ -19386,7 +19453,7 @@ var init_status2 = __esm({
|
|
|
19386
19453
|
// src/cli/trace-verify.ts
|
|
19387
19454
|
import { execFileSync as execFileSync12, spawnSync as spawnSync5 } from "node:child_process";
|
|
19388
19455
|
import {
|
|
19389
|
-
existsSync as
|
|
19456
|
+
existsSync as existsSync11,
|
|
19390
19457
|
mkdtempSync as mkdtempSync5,
|
|
19391
19458
|
readFileSync as readFileSync15,
|
|
19392
19459
|
readdirSync as readdirSync6,
|
|
@@ -19645,7 +19712,7 @@ function materializeBase(base, cwd, dest) {
|
|
|
19645
19712
|
}
|
|
19646
19713
|
const hostModules = join24(cwd, "node_modules");
|
|
19647
19714
|
const tracedModules = join24(dest, "node_modules");
|
|
19648
|
-
if (
|
|
19715
|
+
if (existsSync11(hostModules) && !existsSync11(tracedModules)) {
|
|
19649
19716
|
symlinkSync2(resolve12(hostModules), tracedModules, "dir");
|
|
19650
19717
|
}
|
|
19651
19718
|
}
|
|
@@ -19957,7 +20024,7 @@ var init_immutable = __esm({
|
|
|
19957
20024
|
});
|
|
19958
20025
|
|
|
19959
20026
|
// src/runtimes.ts
|
|
19960
|
-
import { existsSync as
|
|
20027
|
+
import { existsSync as existsSync12, readFileSync as readFileSync16 } from "node:fs";
|
|
19961
20028
|
import { join as join25 } from "node:path";
|
|
19962
20029
|
function isRecord6(x) {
|
|
19963
20030
|
return typeof x === "object" && x !== null && !Array.isArray(x);
|
|
@@ -19987,7 +20054,7 @@ function claudeSettingsBeyondTamperward(cwd) {
|
|
|
19987
20054
|
const path = join25(cwd, ".claude", "settings.json");
|
|
19988
20055
|
let raw;
|
|
19989
20056
|
try {
|
|
19990
|
-
if (!
|
|
20057
|
+
if (!existsSync12(path)) return false;
|
|
19991
20058
|
raw = readFileSync16(path, "utf8");
|
|
19992
20059
|
} catch {
|
|
19993
20060
|
return false;
|
|
@@ -20014,7 +20081,7 @@ function detectRuntimes(cwd) {
|
|
|
20014
20081
|
for (const rt of KNOWN_RUNTIMES) {
|
|
20015
20082
|
const marker = rt.markers.find((m) => {
|
|
20016
20083
|
try {
|
|
20017
|
-
return
|
|
20084
|
+
return existsSync12(join25(cwd, m));
|
|
20018
20085
|
} catch {
|
|
20019
20086
|
return false;
|
|
20020
20087
|
}
|
|
@@ -21039,7 +21106,7 @@ var init_adapter3 = __esm({
|
|
|
21039
21106
|
|
|
21040
21107
|
// src/adapters/copilot-sdk/changes.ts
|
|
21041
21108
|
import { execFileSync as execFileSync13 } from "node:child_process";
|
|
21042
|
-
import { mkdtempSync as mkdtempSync6, writeFileSync as
|
|
21109
|
+
import { mkdtempSync as mkdtempSync6, writeFileSync as writeFileSync10, readFileSync as readFileSync17, rmSync as rmSync12, existsSync as existsSync13, realpathSync as realpathSync10 } from "node:fs";
|
|
21043
21110
|
import { tmpdir as tmpdir7 } from "node:os";
|
|
21044
21111
|
import { basename as basename5, dirname as dirname12, isAbsolute as isAbsolute16, relative as relative11, resolve as resolve15, join as join26 } from "node:path";
|
|
21045
21112
|
function asStr4(v) {
|
|
@@ -21058,7 +21125,7 @@ function canonicalContainedTarget(abs, root) {
|
|
|
21058
21125
|
}
|
|
21059
21126
|
let dir = abs;
|
|
21060
21127
|
const tail = [];
|
|
21061
|
-
while (!
|
|
21128
|
+
while (!existsSync13(dir)) {
|
|
21062
21129
|
const parent = dirname12(dir);
|
|
21063
21130
|
if (parent === dir) break;
|
|
21064
21131
|
tail.unshift(basename5(dir));
|
|
@@ -21116,9 +21183,9 @@ function reconstructAfterViaGit(rawDiff, display2, before, isCreate) {
|
|
|
21116
21183
|
const dir = mkdtempSync6(join26(tmpdir7(), "hf-sdk-apply-"));
|
|
21117
21184
|
try {
|
|
21118
21185
|
const targetPath = join26(dir, TARGET);
|
|
21119
|
-
if (op !== "create")
|
|
21186
|
+
if (op !== "create") writeFileSync10(targetPath, before ?? "");
|
|
21120
21187
|
const patchPath = join26(dir, "change.patch");
|
|
21121
|
-
|
|
21188
|
+
writeFileSync10(patchPath, patch);
|
|
21122
21189
|
const git8 = (extra) => execFileSync13("git", ["apply", ...extra, patchPath], {
|
|
21123
21190
|
cwd: dir,
|
|
21124
21191
|
encoding: "utf8",
|
|
@@ -21886,17 +21953,19 @@ var init_runtime_qualification = __esm({
|
|
|
21886
21953
|
|
|
21887
21954
|
// src/cli/runtime.ts
|
|
21888
21955
|
import { execFileSync as execFileSync14 } from "node:child_process";
|
|
21889
|
-
import { existsSync as
|
|
21956
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync11, readFileSync as readFileSync18 } from "node:fs";
|
|
21890
21957
|
import { join as join27, dirname as dirname13 } from "node:path";
|
|
21891
21958
|
function storePath(cwd) {
|
|
21892
21959
|
const dir = gitDir(cwd);
|
|
21893
|
-
return dir ? join27(dir, "
|
|
21960
|
+
return dir ? join27(stateDirectory(dir), "runtime-qualification.json") : null;
|
|
21894
21961
|
}
|
|
21895
21962
|
function readStore(cwd) {
|
|
21896
21963
|
const path = storePath(cwd);
|
|
21897
|
-
if (!path
|
|
21964
|
+
if (!path) return null;
|
|
21965
|
+
const raw = readStateFile(path);
|
|
21966
|
+
if (raw === null) return null;
|
|
21898
21967
|
try {
|
|
21899
|
-
const parsed = JSON.parse(
|
|
21968
|
+
const parsed = JSON.parse(raw);
|
|
21900
21969
|
if (parsed && typeof parsed === "object" && parsed.records && typeof parsed.records === "object") return parsed;
|
|
21901
21970
|
} catch {
|
|
21902
21971
|
return null;
|
|
@@ -22027,7 +22096,7 @@ function writeRecord(cwd, id, report2) {
|
|
|
22027
22096
|
store.updated_at = report2.timestamp;
|
|
22028
22097
|
try {
|
|
22029
22098
|
mkdirSync11(dirname13(path), { recursive: true });
|
|
22030
|
-
|
|
22099
|
+
atomicReplaceFile(path, JSON.stringify(store, null, 2) + "\n", 384);
|
|
22031
22100
|
return true;
|
|
22032
22101
|
} catch {
|
|
22033
22102
|
return false;
|
|
@@ -22065,7 +22134,7 @@ function resolveHookConfigHash(canonicalId, cwd) {
|
|
|
22065
22134
|
"github-copilot-cli": join27(cwd, ".github", "hooks", "tamperward.json")
|
|
22066
22135
|
};
|
|
22067
22136
|
const file = files[canonicalId];
|
|
22068
|
-
if (!file || !
|
|
22137
|
+
if (!file || !existsSync14(file)) return null;
|
|
22069
22138
|
try {
|
|
22070
22139
|
const raw = readFileSync18(file, "utf8");
|
|
22071
22140
|
let hooks = raw;
|
|
@@ -22207,7 +22276,13 @@ function emit2(report2, opts, cwd) {
|
|
|
22207
22276
|
renderText3(report2, cwd);
|
|
22208
22277
|
}
|
|
22209
22278
|
function storedQualification(adapter, cwd, opts = {}) {
|
|
22210
|
-
|
|
22279
|
+
let raw;
|
|
22280
|
+
try {
|
|
22281
|
+
raw = readStore(cwd)?.records[adapter.name];
|
|
22282
|
+
} catch (e) {
|
|
22283
|
+
if (e instanceof StateFileError) return { state: "rejected", reason: e.message };
|
|
22284
|
+
throw e;
|
|
22285
|
+
}
|
|
22211
22286
|
if (raw === void 0) return { state: "none" };
|
|
22212
22287
|
const validated = validateStoredReport(raw);
|
|
22213
22288
|
if ("reason" in validated) return { state: "rejected", reason: validated.reason };
|
|
@@ -22246,10 +22321,18 @@ function runRuntime(sub, opts) {
|
|
|
22246
22321
|
}
|
|
22247
22322
|
const { binding, assessments } = buildQualification(target, opts, cwd);
|
|
22248
22323
|
const report2 = reportFrom("verify", binding, assessments);
|
|
22249
|
-
|
|
22324
|
+
let wrote = false;
|
|
22325
|
+
let refused;
|
|
22326
|
+
try {
|
|
22327
|
+
wrote = writeRecord(cwd, target.name, report2);
|
|
22328
|
+
} catch (e) {
|
|
22329
|
+
if (!(e instanceof StateFileError)) throw e;
|
|
22330
|
+
refused = e.message;
|
|
22331
|
+
}
|
|
22250
22332
|
if (!wrote) {
|
|
22251
|
-
const
|
|
22252
|
-
const
|
|
22333
|
+
const dir = gitDir(cwd);
|
|
22334
|
+
const dest = dir ? join27(dir, "tamperward", "runtime-qualification.json") : null;
|
|
22335
|
+
const reason = `could not persist the qualification to ${dest ?? "the git-local store (no repository found)"}${refused ? ` (${refused})` : ""}; nothing was recorded, so \`tamperward runtime status\` will report UNQUALIFIED`;
|
|
22253
22336
|
const failure = {
|
|
22254
22337
|
...report2,
|
|
22255
22338
|
recorded: false,
|
|
@@ -22319,6 +22402,8 @@ var HONESTY_NOTE, CAP_ID_SET, STATE_SEVERITY, AGGREGATE_SEVERITY, RUNTIME_SUBCOM
|
|
|
22319
22402
|
var init_runtime = __esm({
|
|
22320
22403
|
"src/cli/runtime.ts"() {
|
|
22321
22404
|
"use strict";
|
|
22405
|
+
init_disk();
|
|
22406
|
+
init_safe_write();
|
|
22322
22407
|
init_build();
|
|
22323
22408
|
init_wiring();
|
|
22324
22409
|
init_machine_output();
|
|
@@ -23527,7 +23612,7 @@ var init_record = __esm({
|
|
|
23527
23612
|
// src/research/run.ts
|
|
23528
23613
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
23529
23614
|
import { execFileSync as execFileSync16 } from "node:child_process";
|
|
23530
|
-
import { closeSync as closeSync5, existsSync as
|
|
23615
|
+
import { closeSync as closeSync5, existsSync as existsSync15, linkSync, mkdirSync as mkdirSync12, openSync as openSync4, readFileSync as readFileSync21, renameSync as renameSync4, rmSync as rmSync14, unlinkSync, writeFileSync as writeFileSync11, writeSync as writeSync2 } from "node:fs";
|
|
23531
23616
|
import { hostname } from "node:os";
|
|
23532
23617
|
import { join as join29, resolve as resolve19 } from "node:path";
|
|
23533
23618
|
function git7(args, cwd) {
|
|
@@ -23564,7 +23649,7 @@ function lockHolder(path) {
|
|
|
23564
23649
|
function acquireResearchLock(ledger, breakStaleLock = false) {
|
|
23565
23650
|
mkdirSync12(ledger, { recursive: true });
|
|
23566
23651
|
const path = researchLockPath(ledger);
|
|
23567
|
-
if (breakStaleLock &&
|
|
23652
|
+
if (breakStaleLock && existsSync15(path)) {
|
|
23568
23653
|
const owner2 = readLockOwner(path);
|
|
23569
23654
|
if (!owner2) {
|
|
23570
23655
|
throw new ResearchError(`research output ${ledger} has an unreadable lock at ${path}; verify no run is active, then remove it deliberately`);
|
|
@@ -23607,7 +23692,7 @@ function acquireResearchLock(ledger, breakStaleLock = false) {
|
|
|
23607
23692
|
const text = JSON.stringify(owner) + "\n";
|
|
23608
23693
|
let fd = -1;
|
|
23609
23694
|
try {
|
|
23610
|
-
fd =
|
|
23695
|
+
fd = openSync4(path, "wx", 384);
|
|
23611
23696
|
writeSync2(fd, text);
|
|
23612
23697
|
closeSync5(fd);
|
|
23613
23698
|
fd = -1;
|
|
@@ -23672,7 +23757,7 @@ function resumableRecord(path, expected) {
|
|
|
23672
23757
|
}
|
|
23673
23758
|
function writeRecordAtomically(path, text) {
|
|
23674
23759
|
const tmp = `${path}.${process.pid}.tmp`;
|
|
23675
|
-
|
|
23760
|
+
writeFileSync11(tmp, text);
|
|
23676
23761
|
renameSync4(tmp, path);
|
|
23677
23762
|
}
|
|
23678
23763
|
function cloneArgs(repo, ws3) {
|
|
@@ -23937,7 +24022,7 @@ function runResearch(opts) {
|
|
|
23937
24022
|
try {
|
|
23938
24023
|
for (let pair = 1; pair <= pairs; pair++) {
|
|
23939
24024
|
const path = pairRecordPath(ledger, task.id, pair);
|
|
23940
|
-
if (!
|
|
24025
|
+
if (!existsSync15(path)) continue;
|
|
23941
24026
|
const existing = resumableRecord(path, {
|
|
23942
24027
|
task: task.id,
|
|
23943
24028
|
pair,
|
|
@@ -24057,7 +24142,7 @@ var init_run2 = __esm({
|
|
|
24057
24142
|
});
|
|
24058
24143
|
|
|
24059
24144
|
// src/research/ledger-files.ts
|
|
24060
|
-
import { closeSync as closeSync6, constants as constants5, fstatSync as fstatSync3, lstatSync as lstatSync12, openSync as
|
|
24145
|
+
import { closeSync as closeSync6, constants as constants5, fstatSync as fstatSync3, lstatSync as lstatSync12, openSync as openSync5, readFileSync as readFileSync22, readdirSync as readdirSync7, realpathSync as realpathSync12 } from "node:fs";
|
|
24061
24146
|
import { join as join30, resolve as resolve20 } from "node:path";
|
|
24062
24147
|
function lstatOrNull(path) {
|
|
24063
24148
|
try {
|
|
@@ -24090,7 +24175,7 @@ function readRegularFile(path, realPairsDir, name) {
|
|
|
24090
24175
|
const flags = constants5.O_RDONLY | (constants5.O_NOFOLLOW ?? 0);
|
|
24091
24176
|
let fd;
|
|
24092
24177
|
try {
|
|
24093
|
-
fd =
|
|
24178
|
+
fd = openSync5(path, flags);
|
|
24094
24179
|
} catch (e) {
|
|
24095
24180
|
throw new ResearchError(`cannot open ledger record ${path}: ${errorMessage(e)}`);
|
|
24096
24181
|
}
|
|
@@ -24273,7 +24358,7 @@ var init_summarize = __esm({
|
|
|
24273
24358
|
|
|
24274
24359
|
// src/research/init.ts
|
|
24275
24360
|
import { createHash as createHash17 } from "node:crypto";
|
|
24276
|
-
import { existsSync as
|
|
24361
|
+
import { existsSync as existsSync16, mkdirSync as mkdirSync13, readFileSync as readFileSync23, writeFileSync as writeFileSync12 } from "node:fs";
|
|
24277
24362
|
import { basename as basename6, dirname as dirname15, resolve as resolve21 } from "node:path";
|
|
24278
24363
|
function idFrom(repo) {
|
|
24279
24364
|
const clean = repo.replace(/[\\/]$/, "").split(/[\\/]/).pop() || "task";
|
|
@@ -24285,7 +24370,7 @@ function createResearchManifest(opts) {
|
|
|
24285
24370
|
if (!opts.prompt) throw new ResearchError("research init requires --prompt");
|
|
24286
24371
|
if (!opts.verifyCommand) throw new ResearchError("research init requires --verify-command");
|
|
24287
24372
|
const out3 = resolve21(opts.out);
|
|
24288
|
-
if (
|
|
24373
|
+
if (existsSync16(out3)) throw new ResearchError(`research init refuses to overwrite ${out3}; choose a new path`);
|
|
24289
24374
|
const id = opts.id ?? idFrom(opts.repo);
|
|
24290
24375
|
if (!/^[A-Za-z0-9._-]+$/.test(id)) throw new ResearchError(`research init id must match [A-Za-z0-9._-] (got "${id}")`);
|
|
24291
24376
|
if (opts.verifyBudget !== void 0 && (!Number.isFinite(opts.verifyBudget) || opts.verifyBudget <= 0)) {
|
|
@@ -24303,7 +24388,7 @@ function createResearchManifest(opts) {
|
|
|
24303
24388
|
};
|
|
24304
24389
|
const text = JSON.stringify(doc, null, 2) + "\n";
|
|
24305
24390
|
mkdirSync13(dirname15(out3), { recursive: true });
|
|
24306
|
-
|
|
24391
|
+
writeFileSync12(out3, text, { flag: "wx", mode: 384 });
|
|
24307
24392
|
const parsed = readManifest(out3);
|
|
24308
24393
|
if (parsed.tasks.length !== 1 || parsed.tasks[0].id !== id) throw new ResearchError(`research init wrote an invalid manifest ${out3}`);
|
|
24309
24394
|
return out3;
|
|
@@ -24393,7 +24478,7 @@ var init_report2 = __esm({
|
|
|
24393
24478
|
import { createHash as createHash18 } from "node:crypto";
|
|
24394
24479
|
import { isDeepStrictEqual } from "node:util";
|
|
24395
24480
|
import { gzipSync, gunzipSync } from "node:zlib";
|
|
24396
|
-
import { mkdirSync as mkdirSync14, readFileSync as readFileSync24, writeFileSync as
|
|
24481
|
+
import { mkdirSync as mkdirSync14, readFileSync as readFileSync24, writeFileSync as writeFileSync13 } from "node:fs";
|
|
24397
24482
|
import { dirname as dirname16, resolve as resolve22 } from "node:path";
|
|
24398
24483
|
function octal(value, width) {
|
|
24399
24484
|
return value.toString(8).padStart(width - 1, "0") + "\0";
|
|
@@ -24593,7 +24678,7 @@ function createResearchBundle(opts) {
|
|
|
24593
24678
|
entries.push({ name: "provenance.json", bytes: jsonBytes(provenance) });
|
|
24594
24679
|
const out3 = resolve22(opts.out);
|
|
24595
24680
|
mkdirSync14(dirname16(out3), { recursive: true });
|
|
24596
|
-
|
|
24681
|
+
writeFileSync13(out3, gzipSync(makeTar(entries)), { flag: "wx", mode: 384 });
|
|
24597
24682
|
return out3;
|
|
24598
24683
|
}
|
|
24599
24684
|
function runResearchBundle(opts) {
|
|
@@ -24740,7 +24825,7 @@ var init_research = __esm({
|
|
|
24740
24825
|
});
|
|
24741
24826
|
|
|
24742
24827
|
// src/cli/receipt.ts
|
|
24743
|
-
import { appendFileSync as appendFileSync3, readFileSync as readFileSync25, writeFileSync as
|
|
24828
|
+
import { appendFileSync as appendFileSync3, readFileSync as readFileSync25, writeFileSync as writeFileSync14 } from "node:fs";
|
|
24744
24829
|
function parseReceipt(args) {
|
|
24745
24830
|
const [sub, ...rest] = args;
|
|
24746
24831
|
const exportOpts = {};
|
|
@@ -24842,7 +24927,7 @@ function runReceiptExport(opts = {}) {
|
|
|
24842
24927
|
const serialized = JSON.stringify(receipt) + "\n";
|
|
24843
24928
|
if (opts.out) {
|
|
24844
24929
|
try {
|
|
24845
|
-
|
|
24930
|
+
writeFileSync14(opts.out, serialized);
|
|
24846
24931
|
} catch (e) {
|
|
24847
24932
|
process.stderr.write(`tamperward: could not write receipt to ${opts.out} (${e instanceof Error ? e.message : String(e)})
|
|
24848
24933
|
`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tamperward",
|
|
3
|
-
"version": "2.39.
|
|
3
|
+
"version": "2.39.13",
|
|
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",
|