tamperward 2.39.4 → 2.39.5
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 +178 -106
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -10885,8 +10885,8 @@ var init_policy_load = __esm({
|
|
|
10885
10885
|
|
|
10886
10886
|
// src/signoff.ts
|
|
10887
10887
|
import { createHash as createHash3 } from "node:crypto";
|
|
10888
|
-
import { appendFileSync, mkdirSync,
|
|
10889
|
-
import { dirname as dirname2, join as join9 } from "node:path";
|
|
10888
|
+
import { appendFileSync, closeSync as closeSync2, constants as constants3, fstatSync as fstatSync2, lstatSync as lstatSync3, mkdirSync, openSync as openSync2, readFileSync as readFileSync6 } from "node:fs";
|
|
10889
|
+
import { dirname as dirname2, join as join9, posix as posix4 } from "node:path";
|
|
10890
10890
|
function compactOobToken(want, head) {
|
|
10891
10891
|
const normalizedHead = head.trim().toLowerCase();
|
|
10892
10892
|
if (!want || !FULL_OBJECT_ID.test(normalizedHead)) return null;
|
|
@@ -10905,17 +10905,75 @@ function fingerprint(rule, file, evidence) {
|
|
|
10905
10905
|
return createHash3("sha256").update(`${rule}\0${file ?? ""}\0${evidence}`).digest("hex").slice(0, 16);
|
|
10906
10906
|
}
|
|
10907
10907
|
function ledgerPath(cwd, policy) {
|
|
10908
|
-
const rel = policy.signoff?.ledger ??
|
|
10908
|
+
const rel = policy.signoff?.ledger ?? DEFAULT_LEDGER;
|
|
10909
10909
|
if (!ledgerInsideRepo(rel)) {
|
|
10910
10910
|
throw new PolicyError(`signoff.ledger must be a relative path inside the repository, got ${JSON.stringify(rel)}`);
|
|
10911
10911
|
}
|
|
10912
10912
|
return join9(cwd, rel);
|
|
10913
10913
|
}
|
|
10914
|
+
function lstatOrAbsent(rel, shown, path) {
|
|
10915
|
+
try {
|
|
10916
|
+
return lstatSync3(path);
|
|
10917
|
+
} catch (e) {
|
|
10918
|
+
if (errnoCode(e) === "ENOENT") return null;
|
|
10919
|
+
throw new PolicyError(
|
|
10920
|
+
`signoff.ledger ${JSON.stringify(rel)}: cannot stat ${shown} (${errorMessage(e)}); refusing to treat the sign-off ledger as absent`
|
|
10921
|
+
);
|
|
10922
|
+
}
|
|
10923
|
+
}
|
|
10924
|
+
function kindOf(st) {
|
|
10925
|
+
if (st.isSymbolicLink()) return "a symbolic link";
|
|
10926
|
+
if (st.isDirectory()) return "a directory";
|
|
10927
|
+
if (st.isFIFO()) return "a FIFO";
|
|
10928
|
+
if (st.isSocket()) return "a socket";
|
|
10929
|
+
if (st.isCharacterDevice() || st.isBlockDevice()) return "a device";
|
|
10930
|
+
return "not a regular file";
|
|
10931
|
+
}
|
|
10932
|
+
function ledgerOnDisk(cwd, policy) {
|
|
10933
|
+
const rel = policy.signoff?.ledger ?? DEFAULT_LEDGER;
|
|
10934
|
+
ledgerPath(cwd, policy);
|
|
10935
|
+
const parts = posix4.normalize(rel.replace(/\\/g, "/")).split("/").filter((part) => part && part !== ".");
|
|
10936
|
+
let path = cwd;
|
|
10937
|
+
for (let i = 0; i < parts.length; i++) {
|
|
10938
|
+
const next = join9(path, parts[i]);
|
|
10939
|
+
const shown = parts.slice(0, i + 1).join("/");
|
|
10940
|
+
const st = lstatOrAbsent(rel, shown, next);
|
|
10941
|
+
if (st === null) return { rel, path: join9(cwd, ...parts), exists: false };
|
|
10942
|
+
const last = i === parts.length - 1;
|
|
10943
|
+
if (st.isSymbolicLink() || (last ? !st.isFile() : !st.isDirectory())) {
|
|
10944
|
+
throw new PolicyError(
|
|
10945
|
+
`signoff.ledger ${JSON.stringify(rel)}: ${shown} is ${kindOf(st)}; the sign-off ledger is honored only as a regular file inside the repository, reached without following a link`
|
|
10946
|
+
);
|
|
10947
|
+
}
|
|
10948
|
+
path = next;
|
|
10949
|
+
}
|
|
10950
|
+
return { rel, path, exists: true };
|
|
10951
|
+
}
|
|
10952
|
+
function openLedger(rel, path, flags) {
|
|
10953
|
+
let fd;
|
|
10954
|
+
try {
|
|
10955
|
+
fd = openSync2(path, flags | (constants3.O_NOFOLLOW ?? 0), 420);
|
|
10956
|
+
} catch (e) {
|
|
10957
|
+
throw new PolicyError(`signoff.ledger ${JSON.stringify(rel)}: cannot open ${path} (${e instanceof Error ? e.message : String(e)})`);
|
|
10958
|
+
}
|
|
10959
|
+
if (!fstatSync2(fd).isFile()) {
|
|
10960
|
+
closeSync2(fd);
|
|
10961
|
+
throw new PolicyError(`signoff.ledger ${JSON.stringify(rel)}: ${path} is not a regular file; refusing to use it`);
|
|
10962
|
+
}
|
|
10963
|
+
return fd;
|
|
10964
|
+
}
|
|
10914
10965
|
function readLedger(cwd, policy) {
|
|
10915
|
-
const
|
|
10916
|
-
if (!
|
|
10966
|
+
const { rel, path, exists } = ledgerOnDisk(cwd, policy);
|
|
10967
|
+
if (!exists) return [];
|
|
10968
|
+
const fd = openLedger(rel, path, constants3.O_RDONLY);
|
|
10969
|
+
let text;
|
|
10970
|
+
try {
|
|
10971
|
+
text = readFileSync6(fd, "utf8");
|
|
10972
|
+
} finally {
|
|
10973
|
+
closeSync2(fd);
|
|
10974
|
+
}
|
|
10917
10975
|
const out3 = [];
|
|
10918
|
-
for (const line of
|
|
10976
|
+
for (const line of text.split("\n")) {
|
|
10919
10977
|
if (!line.trim()) continue;
|
|
10920
10978
|
try {
|
|
10921
10979
|
const e = ledgerEntryFrom(JSON.parse(line));
|
|
@@ -10926,15 +10984,27 @@ function readLedger(cwd, policy) {
|
|
|
10926
10984
|
return out3;
|
|
10927
10985
|
}
|
|
10928
10986
|
function appendEntry(cwd, policy, e) {
|
|
10929
|
-
const
|
|
10930
|
-
|
|
10931
|
-
|
|
10987
|
+
const { rel, path } = ledgerOnDisk(cwd, policy);
|
|
10988
|
+
try {
|
|
10989
|
+
mkdirSync(dirname2(path), { recursive: true });
|
|
10990
|
+
} catch (err3) {
|
|
10991
|
+
throw new PolicyError(`signoff.ledger ${JSON.stringify(rel)}: cannot create ${dirname2(path)} (${errorMessage(err3)})`);
|
|
10992
|
+
}
|
|
10993
|
+
const fd = openLedger(rel, path, constants3.O_WRONLY | constants3.O_APPEND | constants3.O_CREAT);
|
|
10994
|
+
try {
|
|
10995
|
+
appendFileSync(fd, JSON.stringify(e) + "\n");
|
|
10996
|
+
} finally {
|
|
10997
|
+
closeSync2(fd);
|
|
10998
|
+
}
|
|
10932
10999
|
}
|
|
10933
11000
|
function makeEntry(f, reason, now, ttlMs = DEFAULT_TTL_MS) {
|
|
10934
11001
|
return { rule: f.rule, file: f.file, fingerprint: fingerprintOf(f), reason, recordedAt: now, expiresAt: now + ttlMs };
|
|
10935
11002
|
}
|
|
11003
|
+
function honoredAt(e, now) {
|
|
11004
|
+
return e.expiresAt > now && e.recordedAt <= now && e.expiresAt - e.recordedAt <= LEDGER_TTL_MS;
|
|
11005
|
+
}
|
|
10936
11006
|
function applyLocalSignoffs(findings, cwd, policy, now = Date.now()) {
|
|
10937
|
-
const ledger = readLedger(cwd, policy).filter((e) => e
|
|
11007
|
+
const ledger = readLedger(cwd, policy).filter((e) => honoredAt(e, now));
|
|
10938
11008
|
const valid = new Set(ledger.map((e) => e.fingerprint));
|
|
10939
11009
|
const cleared = [];
|
|
10940
11010
|
const remaining = [];
|
|
@@ -10985,13 +11055,15 @@ function oobHeadFromEnv(env = process.env) {
|
|
|
10985
11055
|
function oobFromEnv(env = process.env) {
|
|
10986
11056
|
return (env.TAMPERWARD_OOB_SIGNOFF ?? "").split(",").map((s) => s.trim().replace(/^tamperward:allow:/, "")).filter(Boolean);
|
|
10987
11057
|
}
|
|
10988
|
-
var DEFAULT_TTL_MS, COMPACT_OOB_PREFIX, FULL_OBJECT_ID, fingerprintOf;
|
|
11058
|
+
var LEDGER_TTL_MS, DEFAULT_TTL_MS, DEFAULT_LEDGER, COMPACT_OOB_PREFIX, FULL_OBJECT_ID, fingerprintOf;
|
|
10989
11059
|
var init_signoff = __esm({
|
|
10990
11060
|
"src/signoff.ts"() {
|
|
10991
11061
|
"use strict";
|
|
10992
11062
|
init_policy_load();
|
|
10993
11063
|
init_narrow();
|
|
10994
|
-
|
|
11064
|
+
LEDGER_TTL_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
11065
|
+
DEFAULT_TTL_MS = LEDGER_TTL_MS;
|
|
11066
|
+
DEFAULT_LEDGER = ".tamperward/ledger.jsonl";
|
|
10995
11067
|
COMPACT_OOB_PREFIX = "tw1:";
|
|
10996
11068
|
FULL_OBJECT_ID = /^(?:[0-9a-f]{40}|[0-9a-f]{64})$/i;
|
|
10997
11069
|
fingerprintOf = (f) => fingerprint(f.rule, f.file, f.evidence);
|
|
@@ -11437,7 +11509,7 @@ var init_deny = __esm({
|
|
|
11437
11509
|
});
|
|
11438
11510
|
|
|
11439
11511
|
// src/session.ts
|
|
11440
|
-
import { existsSync as
|
|
11512
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync2, readFileSync as readFileSync7, renameSync, rmSync as rmSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
11441
11513
|
import { dirname as dirname3, join as join10 } from "node:path";
|
|
11442
11514
|
function writeBaseline(p, sha3) {
|
|
11443
11515
|
mkdirSync2(dirname3(p), { recursive: true });
|
|
@@ -11463,7 +11535,7 @@ function turnBaseline(cwd, sessionId) {
|
|
|
11463
11535
|
const p = baselinePath(cwd, sessionId);
|
|
11464
11536
|
if (!p) return null;
|
|
11465
11537
|
try {
|
|
11466
|
-
if (
|
|
11538
|
+
if (existsSync6(p)) {
|
|
11467
11539
|
const v = readFileSync7(p, "utf8").trim();
|
|
11468
11540
|
if (SHA.test(v)) return v;
|
|
11469
11541
|
}
|
|
@@ -11507,7 +11579,7 @@ var init_session = __esm({
|
|
|
11507
11579
|
|
|
11508
11580
|
// src/effect.ts
|
|
11509
11581
|
import { createHash as createHash4 } from "node:crypto";
|
|
11510
|
-
import { existsSync as
|
|
11582
|
+
import { existsSync as existsSync7, lstatSync as lstatSync4, mkdirSync as mkdirSync3, readdirSync, readFileSync as readFileSync8, renameSync as renameSync2, rmSync as rmSync3, writeFileSync as writeFileSync3 } from "node:fs";
|
|
11511
11583
|
import { join as join11 } from "node:path";
|
|
11512
11584
|
function ptreeFrom(value) {
|
|
11513
11585
|
if (!isRecord(value)) return null;
|
|
@@ -11572,7 +11644,7 @@ function snapshotProtected(cwd, policy, prev, cache3) {
|
|
|
11572
11644
|
if (pruned.has(r)) continue;
|
|
11573
11645
|
let st;
|
|
11574
11646
|
try {
|
|
11575
|
-
st =
|
|
11647
|
+
st = lstatSync4(join11(cwd, r));
|
|
11576
11648
|
} catch {
|
|
11577
11649
|
continue;
|
|
11578
11650
|
}
|
|
@@ -11599,7 +11671,7 @@ function driftBetween(expected, current) {
|
|
|
11599
11671
|
return { changed, deleted, added };
|
|
11600
11672
|
}
|
|
11601
11673
|
function loadTree(p) {
|
|
11602
|
-
if (!p || !
|
|
11674
|
+
if (!p || !existsSync7(p)) return null;
|
|
11603
11675
|
try {
|
|
11604
11676
|
return ptreeFrom(JSON.parse(readFileSync8(p, "utf8")));
|
|
11605
11677
|
} catch {
|
|
@@ -11654,7 +11726,7 @@ var init_effect = __esm({
|
|
|
11654
11726
|
});
|
|
11655
11727
|
|
|
11656
11728
|
// src/cli/watch.ts
|
|
11657
|
-
import { appendFileSync as appendFileSync3, lstatSync as
|
|
11729
|
+
import { appendFileSync as appendFileSync3, lstatSync as lstatSync5, mkdirSync as mkdirSync4, readFileSync as readFileSync9, readdirSync as readdirSync2, watch, writeFileSync as writeFileSync4 } from "node:fs";
|
|
11658
11730
|
import { join as join12 } from "node:path";
|
|
11659
11731
|
import { createHash as createHash5 } from "node:crypto";
|
|
11660
11732
|
function snap(abs) {
|
|
@@ -11757,7 +11829,7 @@ function watchTree(dir, cb, onState, onError, watchFn = watch) {
|
|
|
11757
11829
|
const child = rel ? `${rel}/${String(fname)}` : String(fname);
|
|
11758
11830
|
cb(kind, child);
|
|
11759
11831
|
try {
|
|
11760
|
-
if (
|
|
11832
|
+
if (lstatSync5(join12(dir, child)).isDirectory()) addDir(child);
|
|
11761
11833
|
} catch {
|
|
11762
11834
|
}
|
|
11763
11835
|
});
|
|
@@ -11793,7 +11865,7 @@ function watchTree(dir, cb, onState, onError, watchFn = watch) {
|
|
|
11793
11865
|
const child = rel ? `${rel}/${name}` : name;
|
|
11794
11866
|
if (SKIP2.test(child + "/")) continue;
|
|
11795
11867
|
try {
|
|
11796
|
-
if (
|
|
11868
|
+
if (lstatSync5(join12(dir, child)).isDirectory()) walk2(child);
|
|
11797
11869
|
} catch {
|
|
11798
11870
|
}
|
|
11799
11871
|
}
|
|
@@ -11944,7 +12016,7 @@ var init_watch = __esm({
|
|
|
11944
12016
|
});
|
|
11945
12017
|
|
|
11946
12018
|
// src/detectors/fs-events.ts
|
|
11947
|
-
import { closeSync as
|
|
12019
|
+
import { closeSync as closeSync3, openSync as openSync3, readSync as readSync2, statSync as statSync2 } from "node:fs";
|
|
11948
12020
|
function fsEventFrom(line) {
|
|
11949
12021
|
let value;
|
|
11950
12022
|
try {
|
|
@@ -11991,12 +12063,12 @@ function readEvents(log, offset, maxBytes = MAX_EVENT_READ_BYTES, io = DEFAULT_E
|
|
|
11991
12063
|
const available = size - start;
|
|
11992
12064
|
const requested = Math.min(available, cap);
|
|
11993
12065
|
const buffer = Buffer.allocUnsafe(requested);
|
|
11994
|
-
const fd =
|
|
12066
|
+
const fd = openSync3(log, "r");
|
|
11995
12067
|
let bytesRead = 0;
|
|
11996
12068
|
try {
|
|
11997
12069
|
bytesRead = io.read(fd, buffer, 0, requested, start);
|
|
11998
12070
|
} finally {
|
|
11999
|
-
|
|
12071
|
+
closeSync3(fd);
|
|
12000
12072
|
}
|
|
12001
12073
|
if (bytesRead <= 0) {
|
|
12002
12074
|
return {
|
|
@@ -12201,7 +12273,7 @@ var init_fs_events = __esm({
|
|
|
12201
12273
|
|
|
12202
12274
|
// src/cli/audit.ts
|
|
12203
12275
|
import { createHash as createHash6, randomBytes } from "node:crypto";
|
|
12204
|
-
import { appendFileSync as appendFileSync4, closeSync as
|
|
12276
|
+
import { appendFileSync as appendFileSync4, closeSync as closeSync4, existsSync as existsSync8, mkdirSync as mkdirSync5, openSync as openSync4, readSync as readSync3 } from "node:fs";
|
|
12205
12277
|
import { dirname as dirname4, isAbsolute as isAbsolute8, join as join13, resolve as resolve4 } from "node:path";
|
|
12206
12278
|
function sessionHash(sessionId) {
|
|
12207
12279
|
if (!sessionId) return void 0;
|
|
@@ -12321,7 +12393,7 @@ function parseAuditLine(line, lineNumber) {
|
|
|
12321
12393
|
return parseAuditEvent(value, lineNumber);
|
|
12322
12394
|
}
|
|
12323
12395
|
function forEachAuditLine(file, onLine, maxLineBytes = MAX_AUDIT_LINE_BYTES) {
|
|
12324
|
-
const fd =
|
|
12396
|
+
const fd = openSync4(file, "r");
|
|
12325
12397
|
try {
|
|
12326
12398
|
const chunk = Buffer.allocUnsafe(64 * 1024);
|
|
12327
12399
|
let pending = [];
|
|
@@ -12359,7 +12431,7 @@ function forEachAuditLine(file, onLine, maxLineBytes = MAX_AUDIT_LINE_BYTES) {
|
|
|
12359
12431
|
}
|
|
12360
12432
|
if (pending.length) emit3(pending);
|
|
12361
12433
|
} finally {
|
|
12362
|
-
|
|
12434
|
+
closeSync4(fd);
|
|
12363
12435
|
}
|
|
12364
12436
|
}
|
|
12365
12437
|
function parseSince(value, nowMs = Date.now()) {
|
|
@@ -12460,7 +12532,7 @@ function runStats(opts = {}) {
|
|
|
12460
12532
|
const file = opts.file ? isAbsolute8(opts.file) ? opts.file : resolve4(cwd, opts.file) : configured && configured !== "auto" ? isAbsolute8(configured) ? configured : resolve4(cwd, configured) : defaultAuditPath(cwd);
|
|
12461
12533
|
const cutoff = opts.since ? parseSince(opts.since) : null;
|
|
12462
12534
|
if (!file) throw new Error("stats needs --file outside a Git repository");
|
|
12463
|
-
if (!
|
|
12535
|
+
if (!existsSync8(file)) {
|
|
12464
12536
|
if (explicitFile) throw new Error(`audit file not found: ${file}`);
|
|
12465
12537
|
const empty2 = summarizeAudit([]);
|
|
12466
12538
|
process.stdout.write(opts.json ? JSON.stringify(empty2) + "\n" : renderAuditStats(empty2));
|
|
@@ -12499,7 +12571,7 @@ var init_audit = __esm({
|
|
|
12499
12571
|
});
|
|
12500
12572
|
|
|
12501
12573
|
// src/cli/hook.ts
|
|
12502
|
-
import { readFileSync as readFileSync10, appendFileSync as appendFileSync5, writeFileSync as writeFileSync5, existsSync as
|
|
12574
|
+
import { readFileSync as readFileSync10, appendFileSync as appendFileSync5, writeFileSync as writeFileSync5, existsSync as existsSync9 } from "node:fs";
|
|
12503
12575
|
import { createHash as createHash7 } from "node:crypto";
|
|
12504
12576
|
function setSnapshotCache(cache3) {
|
|
12505
12577
|
snapshotCache = cache3;
|
|
@@ -12796,9 +12868,9 @@ function turnTransientBlocks(cwd, sessionId, policy, changes) {
|
|
|
12796
12868
|
recordObserverHealth(cwd, sessionId, telemetry.state, telemetry.reason);
|
|
12797
12869
|
}
|
|
12798
12870
|
const cp = cursorPath(cwd, sessionId);
|
|
12799
|
-
if (!
|
|
12871
|
+
if (!existsSync9(log)) return none;
|
|
12800
12872
|
let offset = 0;
|
|
12801
|
-
if (cp &&
|
|
12873
|
+
if (cp && existsSync9(cp)) {
|
|
12802
12874
|
const n2 = Number(readFileSync10(cp, "utf8"));
|
|
12803
12875
|
offset = Number.isFinite(n2) ? n2 : 0;
|
|
12804
12876
|
}
|
|
@@ -12979,7 +13051,7 @@ var init_hook = __esm({
|
|
|
12979
13051
|
});
|
|
12980
13052
|
|
|
12981
13053
|
// src/ptree-cache.ts
|
|
12982
|
-
import { lstatSync as
|
|
13054
|
+
import { lstatSync as lstatSync6 } from "node:fs";
|
|
12983
13055
|
import { join as join14 } from "node:path";
|
|
12984
13056
|
function keyOf(st) {
|
|
12985
13057
|
return `${st.dev}:${st.ino}:${st.size}:${st.mode}:${st.mtimeNs}:${st.ctimeNs}`;
|
|
@@ -13033,7 +13105,7 @@ var init_ptree_cache = __esm({
|
|
|
13033
13105
|
const abs = join14(cwd, rel);
|
|
13034
13106
|
let st;
|
|
13035
13107
|
try {
|
|
13036
|
-
st =
|
|
13108
|
+
st = lstatSync6(abs, { bigint: true });
|
|
13037
13109
|
} catch {
|
|
13038
13110
|
this.map.delete(abs);
|
|
13039
13111
|
this.stats.misses++;
|
|
@@ -13055,7 +13127,7 @@ var init_ptree_cache = __esm({
|
|
|
13055
13127
|
const entry = compute();
|
|
13056
13128
|
let after;
|
|
13057
13129
|
try {
|
|
13058
|
-
after =
|
|
13130
|
+
after = lstatSync6(abs, { bigint: true });
|
|
13059
13131
|
} catch {
|
|
13060
13132
|
this.map.delete(abs);
|
|
13061
13133
|
return entry;
|
|
@@ -13073,7 +13145,7 @@ var init_ptree_cache = __esm({
|
|
|
13073
13145
|
});
|
|
13074
13146
|
|
|
13075
13147
|
// src/cli/hook-service.ts
|
|
13076
|
-
import { chmodSync, existsSync as
|
|
13148
|
+
import { chmodSync, existsSync as existsSync10, lstatSync as lstatSync7, mkdirSync as mkdirSync6, readFileSync as readFileSync11, rmSync as rmSync4, writeFileSync as writeFileSync6 } from "node:fs";
|
|
13077
13149
|
import { createConnection as createConnection2, createServer } from "node:net";
|
|
13078
13150
|
import { realpathSync as realpathSync4 } from "node:fs";
|
|
13079
13151
|
import { sep } from "node:path";
|
|
@@ -13161,8 +13233,8 @@ function removeQuietly(p) {
|
|
|
13161
13233
|
}
|
|
13162
13234
|
}
|
|
13163
13235
|
function ensurePrivateDir(dir, uid) {
|
|
13164
|
-
if (!
|
|
13165
|
-
const st =
|
|
13236
|
+
if (!existsSync10(dir)) mkdirSync6(dir, { recursive: true, mode: 448 });
|
|
13237
|
+
const st = lstatSync7(dir);
|
|
13166
13238
|
if (!st.isDirectory()) throw new Error(`${dir} is not a directory`);
|
|
13167
13239
|
if (st.uid !== uid) throw new Error(`${dir} is owned by uid ${st.uid}, not ${uid}; refusing to serve from it`);
|
|
13168
13240
|
if ((st.mode & 63) !== 0) chmodSync(dir, 448);
|
|
@@ -13358,7 +13430,7 @@ async function stopHookService(paths, expectedRoot) {
|
|
|
13358
13430
|
process.kill(st.pid, "SIGTERM");
|
|
13359
13431
|
} catch {
|
|
13360
13432
|
}
|
|
13361
|
-
const gone = () => !pidAlive2(st.pid) || !
|
|
13433
|
+
const gone = () => !pidAlive2(st.pid) || !existsSync10(paths.socket);
|
|
13362
13434
|
const until = Date.now() + STOP_WAIT_MS;
|
|
13363
13435
|
while (!gone() && Date.now() < until) sleepSync(50);
|
|
13364
13436
|
if (!gone()) throw new Error(`hook service pid ${st.pid} did not exit within ${STOP_WAIT_MS / 1e3}s`);
|
|
@@ -13594,11 +13666,11 @@ var init_verifier_limits = __esm({
|
|
|
13594
13666
|
|
|
13595
13667
|
// src/safe-write.ts
|
|
13596
13668
|
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
13597
|
-
import { lstatSync as
|
|
13669
|
+
import { lstatSync as lstatSync8, renameSync as renameSync3, rmSync as rmSync5, writeFileSync as writeFileSync7 } from "node:fs";
|
|
13598
13670
|
function writeTargetKind(path) {
|
|
13599
13671
|
let st;
|
|
13600
13672
|
try {
|
|
13601
|
-
st =
|
|
13673
|
+
st = lstatSync8(path, { throwIfNoEntry: false });
|
|
13602
13674
|
} catch (e) {
|
|
13603
13675
|
if (errnoCode(e) === "ENOTDIR") return "absent";
|
|
13604
13676
|
throw e;
|
|
@@ -13619,7 +13691,7 @@ function refuseNonRegular(path) {
|
|
|
13619
13691
|
}
|
|
13620
13692
|
function existingMode(path, fallback) {
|
|
13621
13693
|
if (writeTargetKind(path) !== "file") return fallback;
|
|
13622
|
-
return
|
|
13694
|
+
return lstatSync8(path).mode & 511;
|
|
13623
13695
|
}
|
|
13624
13696
|
function atomicReplaceFile(path, content, mode) {
|
|
13625
13697
|
const tmp = `${path}.${process.pid}.${randomBytes2(8).toString("hex")}.tmp`;
|
|
@@ -13640,7 +13712,7 @@ var init_safe_write = __esm({
|
|
|
13640
13712
|
// src/cli/init.ts
|
|
13641
13713
|
import { execFileSync as execFileSync6 } from "node:child_process";
|
|
13642
13714
|
import { createHash as createHash8 } from "node:crypto";
|
|
13643
|
-
import { existsSync as
|
|
13715
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync7, readFileSync as readFileSync12, realpathSync as realpathSync5 } from "node:fs";
|
|
13644
13716
|
import { basename as basename3, dirname as dirname5, isAbsolute as isAbsolute9, join as join15, relative as relative4, resolve as resolve6 } from "node:path";
|
|
13645
13717
|
function gitConfig(cwd, key2) {
|
|
13646
13718
|
try {
|
|
@@ -13744,7 +13816,7 @@ function verifierCandidates(cwd) {
|
|
|
13744
13816
|
if (/^\s*\[tool\.pytest(?:\.ini_options)?\]\s*$/m.test(pyproject)) add("pytest");
|
|
13745
13817
|
} catch {
|
|
13746
13818
|
}
|
|
13747
|
-
if (
|
|
13819
|
+
if (existsSync11(join15(cwd, "pytest.ini"))) add("pytest");
|
|
13748
13820
|
try {
|
|
13749
13821
|
const setupCfg = readFileSync12(join15(cwd, "setup.cfg"), "utf8");
|
|
13750
13822
|
if (/^\s*\[tool:pytest\]\s*$/m.test(setupCfg)) add("pytest");
|
|
@@ -13804,7 +13876,7 @@ function planPolicy(cwd) {
|
|
|
13804
13876
|
const path = join15(cwd, POLICY_FILE);
|
|
13805
13877
|
const refused = refuseNonRegular(path);
|
|
13806
13878
|
if (refused) return { item: "policy", path: POLICY_FILE, status: "error", detail: refused };
|
|
13807
|
-
if (
|
|
13879
|
+
if (existsSync11(path)) {
|
|
13808
13880
|
try {
|
|
13809
13881
|
loadPolicy(cwd);
|
|
13810
13882
|
} catch (e) {
|
|
@@ -13823,7 +13895,7 @@ function planPolicy(cwd) {
|
|
|
13823
13895
|
function planGitignore(cwd) {
|
|
13824
13896
|
const rel = ".gitignore";
|
|
13825
13897
|
const path = join15(cwd, rel);
|
|
13826
|
-
if (!
|
|
13898
|
+
if (!existsSync11(join15(cwd, "node_modules"))) return null;
|
|
13827
13899
|
let existing = "";
|
|
13828
13900
|
let kind;
|
|
13829
13901
|
try {
|
|
@@ -13888,7 +13960,7 @@ function planClaudeHooks(cwd) {
|
|
|
13888
13960
|
const refused = refuseNonRegular(path);
|
|
13889
13961
|
if (refused) return { item: "agent", path: rel, status: "error", detail: refused };
|
|
13890
13962
|
let settings = {};
|
|
13891
|
-
if (
|
|
13963
|
+
if (existsSync11(path)) {
|
|
13892
13964
|
let parsed;
|
|
13893
13965
|
try {
|
|
13894
13966
|
parsed = JSON.parse(readFileSync12(path, "utf8"));
|
|
@@ -13940,7 +14012,7 @@ function planClaudeHooks(cwd) {
|
|
|
13940
14012
|
return {
|
|
13941
14013
|
item: "agent",
|
|
13942
14014
|
path: rel,
|
|
13943
|
-
status:
|
|
14015
|
+
status: existsSync11(path) ? "update" : "create",
|
|
13944
14016
|
detail: [
|
|
13945
14017
|
needPre && "wire PreToolUse deny",
|
|
13946
14018
|
needStop && "wire Stop sweep",
|
|
@@ -13984,7 +14056,7 @@ function hooksDir(cwd) {
|
|
|
13984
14056
|
if (out3) return resolve6(cwd, out3);
|
|
13985
14057
|
} catch {
|
|
13986
14058
|
}
|
|
13987
|
-
return
|
|
14059
|
+
return existsSync11(join15(cwd, ".git")) ? join15(cwd, ".git", "hooks") : null;
|
|
13988
14060
|
}
|
|
13989
14061
|
function display(cwd, path) {
|
|
13990
14062
|
const rel = relative4(cwd, path);
|
|
@@ -14011,11 +14083,11 @@ function planPreCommit(cwd) {
|
|
|
14011
14083
|
const skip = (detail) => ({ item: "pre-commit", path: "(none)", status: "skip", detail });
|
|
14012
14084
|
let path;
|
|
14013
14085
|
let note;
|
|
14014
|
-
if (
|
|
14086
|
+
if (existsSync11(join15(cwd, ".husky"))) {
|
|
14015
14087
|
path = join15(cwd, ".husky", "pre-commit");
|
|
14016
14088
|
note = "husky";
|
|
14017
14089
|
} else {
|
|
14018
|
-
const managed = MANAGED_HOOKS.find((m) => m.configs.some((c) =>
|
|
14090
|
+
const managed = MANAGED_HOOKS.find((m) => m.configs.some((c) => existsSync11(join15(cwd, c))));
|
|
14019
14091
|
if (managed) {
|
|
14020
14092
|
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}`);
|
|
14021
14093
|
}
|
|
@@ -14033,7 +14105,7 @@ function planPreCommit(cwd) {
|
|
|
14033
14105
|
const rel = display(cwd, path);
|
|
14034
14106
|
const refused = refuseNonRegular(path);
|
|
14035
14107
|
if (refused) return { item: "pre-commit", path: rel, status: "error", detail: refused };
|
|
14036
|
-
const existing =
|
|
14108
|
+
const existing = existsSync11(path) ? readFileSync12(path, "utf8") : null;
|
|
14037
14109
|
const hookMode = () => existingMode(path, 493) | 73;
|
|
14038
14110
|
if (existing === null) {
|
|
14039
14111
|
return {
|
|
@@ -14164,7 +14236,7 @@ function planWorkflow(cwd, force) {
|
|
|
14164
14236
|
};
|
|
14165
14237
|
const refused = refuseNonRegular(path);
|
|
14166
14238
|
if (refused) return { item: "ci", path: rel, status: "error", detail: refused };
|
|
14167
|
-
if (!
|
|
14239
|
+
if (!existsSync11(path)) {
|
|
14168
14240
|
return {
|
|
14169
14241
|
item: "ci",
|
|
14170
14242
|
path: rel,
|
|
@@ -14522,8 +14594,8 @@ var init_fingerprint = __esm({
|
|
|
14522
14594
|
// src/dependency-env.ts
|
|
14523
14595
|
import { createHash as createHash10 } from "node:crypto";
|
|
14524
14596
|
import {
|
|
14525
|
-
existsSync as
|
|
14526
|
-
lstatSync as
|
|
14597
|
+
existsSync as existsSync12,
|
|
14598
|
+
lstatSync as lstatSync9,
|
|
14527
14599
|
readdirSync as readdirSync3,
|
|
14528
14600
|
readFileSync as readFileSync13,
|
|
14529
14601
|
readlinkSync as readlinkSync2,
|
|
@@ -14548,7 +14620,7 @@ function inside(root, candidate) {
|
|
|
14548
14620
|
return rel === "" || rel !== ".." && !rel.startsWith(".." + sep3) && !isAbsolute10(rel);
|
|
14549
14621
|
}
|
|
14550
14622
|
function modeKind(path) {
|
|
14551
|
-
const st =
|
|
14623
|
+
const st = lstatSync9(path);
|
|
14552
14624
|
if (st.isFile()) return { kind: "file", mode: st.mode };
|
|
14553
14625
|
if (st.isDirectory()) return { kind: "dir", mode: st.mode };
|
|
14554
14626
|
if (st.isSymbolicLink()) return { kind: "symlink", mode: st.mode };
|
|
@@ -14558,7 +14630,7 @@ function fingerprintRoot(root, cwd, h) {
|
|
|
14558
14630
|
let rootStat;
|
|
14559
14631
|
let currentReal;
|
|
14560
14632
|
try {
|
|
14561
|
-
rootStat =
|
|
14633
|
+
rootStat = lstatSync9(root.path);
|
|
14562
14634
|
currentReal = realpathSync6(root.path);
|
|
14563
14635
|
} catch (e) {
|
|
14564
14636
|
throw new Unattestable(
|
|
@@ -14676,7 +14748,7 @@ function snapshot(roots, probes, cwd) {
|
|
|
14676
14748
|
const h = createHash10("sha256");
|
|
14677
14749
|
for (const probe of probes) {
|
|
14678
14750
|
h.update(
|
|
14679
|
-
"probe\0" + probe.kind + "\0" + probe.path + "\0" + (
|
|
14751
|
+
"probe\0" + probe.kind + "\0" + probe.path + "\0" + (existsSync12(probe.path) ? "present" : "absent") + "\0"
|
|
14680
14752
|
);
|
|
14681
14753
|
}
|
|
14682
14754
|
for (const root of roots) fingerprintRoot(root, cwd, h);
|
|
@@ -14735,7 +14807,7 @@ function resolveExecutable(token, cwd, env) {
|
|
|
14735
14807
|
if (token.includes("/") || token.includes("\\")) {
|
|
14736
14808
|
const path = isAbsolute10(token) ? token : resolve7(cwd, token);
|
|
14737
14809
|
try {
|
|
14738
|
-
return
|
|
14810
|
+
return existsSync12(path) ? realpathSync6(path) : null;
|
|
14739
14811
|
} catch {
|
|
14740
14812
|
return null;
|
|
14741
14813
|
}
|
|
@@ -14743,7 +14815,7 @@ function resolveExecutable(token, cwd, env) {
|
|
|
14743
14815
|
for (const entry of (env.PATH ?? "").split(delimiter).filter(Boolean)) {
|
|
14744
14816
|
const candidate = resolve7(entry, token);
|
|
14745
14817
|
try {
|
|
14746
|
-
if (
|
|
14818
|
+
if (existsSync12(candidate) && statSync3(candidate).isFile()) return realpathSync6(candidate);
|
|
14747
14819
|
} catch {
|
|
14748
14820
|
}
|
|
14749
14821
|
}
|
|
@@ -14766,7 +14838,7 @@ function inferredVenvFromToken(token, cwd) {
|
|
|
14766
14838
|
const parentName = basename4(parent).toLowerCase();
|
|
14767
14839
|
if (parentName !== "bin" && parentName !== "scripts") return null;
|
|
14768
14840
|
const root = dirname6(parent);
|
|
14769
|
-
return
|
|
14841
|
+
return existsSync12(join16(root, "pyvenv.cfg")) ? root : null;
|
|
14770
14842
|
}
|
|
14771
14843
|
function unsupportedEcosystem(command, token) {
|
|
14772
14844
|
const name = token ? basename4(token).toLowerCase() : "";
|
|
@@ -14782,11 +14854,11 @@ function inferredVenv(executable) {
|
|
|
14782
14854
|
const parentName = basename4(parent).toLowerCase();
|
|
14783
14855
|
if (parentName !== "bin" && parentName !== "scripts") return null;
|
|
14784
14856
|
const root = dirname6(parent);
|
|
14785
|
-
return
|
|
14857
|
+
return existsSync12(join16(root, "pyvenv.cfg")) ? root : null;
|
|
14786
14858
|
}
|
|
14787
14859
|
function venvProblem(root) {
|
|
14788
14860
|
const cfg = join16(root, "pyvenv.cfg");
|
|
14789
|
-
if (!
|
|
14861
|
+
if (!existsSync12(cfg)) return "VIRTUAL_ENV " + JSON.stringify(root) + " has no pyvenv.cfg";
|
|
14790
14862
|
try {
|
|
14791
14863
|
const body = readFileSync13(cfg, "utf8");
|
|
14792
14864
|
if (/^\s*include-system-site-packages\s*=\s*true\s*$/im.test(body)) {
|
|
@@ -14813,7 +14885,7 @@ function discoverDependencyEnvironment(cwdInput, command, env = process.env) {
|
|
|
14813
14885
|
};
|
|
14814
14886
|
try {
|
|
14815
14887
|
const nodeModules = join16(cwd, "node_modules");
|
|
14816
|
-
if (
|
|
14888
|
+
if (existsSync12(nodeModules)) addRoot("node_modules", nodeModules);
|
|
14817
14889
|
else probes.push({ kind: "node_modules", path: nodeModules });
|
|
14818
14890
|
const token = firstExecutable(command);
|
|
14819
14891
|
const executable = resolveExecutable(token, cwd, env);
|
|
@@ -14825,7 +14897,7 @@ function discoverDependencyEnvironment(cwdInput, command, env = process.env) {
|
|
|
14825
14897
|
venv = resolve7(env.VIRTUAL_ENV);
|
|
14826
14898
|
} else {
|
|
14827
14899
|
venv = inferredVenv(executable) ?? inferredVenvFromToken(token, cwd);
|
|
14828
|
-
if (!venv && /(?:^|\s)uv\s+run(?:\s|$)/.test(command) &&
|
|
14900
|
+
if (!venv && /(?:^|\s)uv\s+run(?:\s|$)/.test(command) && existsSync12(join16(cwd, ".venv", "pyvenv.cfg"))) {
|
|
14829
14901
|
venv = join16(cwd, ".venv");
|
|
14830
14902
|
}
|
|
14831
14903
|
}
|
|
@@ -15304,7 +15376,7 @@ if (child) {
|
|
|
15304
15376
|
// src/verifier-backend.ts
|
|
15305
15377
|
import { createHash as createHash11, randomUUID } from "node:crypto";
|
|
15306
15378
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
15307
|
-
import { accessSync as accessSync2, constants as
|
|
15379
|
+
import { accessSync as accessSync2, constants as constants4, readFileSync as readFileSync14, realpathSync as realpathSync7, statSync as statSync4 } from "node:fs";
|
|
15308
15380
|
import { delimiter as delimiter2, dirname as dirname7, join as join18, resolve as resolve8 } from "node:path";
|
|
15309
15381
|
function identity() {
|
|
15310
15382
|
const uid = typeof process.getuid === "function" ? process.getuid() : null;
|
|
@@ -15341,7 +15413,7 @@ function findExecutable(name) {
|
|
|
15341
15413
|
if (!raw) continue;
|
|
15342
15414
|
const candidate = join18(raw, name);
|
|
15343
15415
|
try {
|
|
15344
|
-
accessSync2(candidate,
|
|
15416
|
+
accessSync2(candidate, constants4.X_OK);
|
|
15345
15417
|
return realpathSync7(candidate);
|
|
15346
15418
|
} catch {
|
|
15347
15419
|
}
|
|
@@ -16405,7 +16477,7 @@ var init_verification_receipt = __esm({
|
|
|
16405
16477
|
// src/cli/verify.ts
|
|
16406
16478
|
import { execFileSync as execFileSync9, spawnSync as spawnSync3 } from "node:child_process";
|
|
16407
16479
|
import { createHash as createHash14 } from "node:crypto";
|
|
16408
|
-
import { chmodSync as chmodSync2, cpSync, lstatSync as
|
|
16480
|
+
import { chmodSync as chmodSync2, cpSync, lstatSync as lstatSync10, mkdirSync as mkdirSync10, mkdtempSync as mkdtempSync3, readFileSync as readFileSync16, readlinkSync as readlinkSync3, rmSync as rmSync9, symlinkSync, writeFileSync as writeFileSync11, existsSync as existsSync13 } from "node:fs";
|
|
16409
16481
|
import { tmpdir as tmpdir4 } from "node:os";
|
|
16410
16482
|
import { dirname as dirname10, isAbsolute as isAbsolute11, join as join21, relative as relative6, resolve as resolve9, sep as sep4 } from "node:path";
|
|
16411
16483
|
function oracleAssuranceReport() {
|
|
@@ -16499,7 +16571,7 @@ function validateSymlinkGraph(target, out3, root, dependencyRoot, label) {
|
|
|
16499
16571
|
const current = join21(base, ...stack);
|
|
16500
16572
|
let st;
|
|
16501
16573
|
try {
|
|
16502
|
-
st =
|
|
16574
|
+
st = lstatSync10(current);
|
|
16503
16575
|
} catch {
|
|
16504
16576
|
continue;
|
|
16505
16577
|
}
|
|
@@ -16541,7 +16613,7 @@ function rejectLinkedParent(cwd, rel) {
|
|
|
16541
16613
|
current = join21(current, part);
|
|
16542
16614
|
let st;
|
|
16543
16615
|
try {
|
|
16544
|
-
st =
|
|
16616
|
+
st = lstatSync10(current);
|
|
16545
16617
|
} catch {
|
|
16546
16618
|
continue;
|
|
16547
16619
|
}
|
|
@@ -16567,7 +16639,7 @@ function materialize(cwd, dest, dependencyRoot) {
|
|
|
16567
16639
|
rejectLinkedParent(cwd, rel);
|
|
16568
16640
|
let st;
|
|
16569
16641
|
try {
|
|
16570
|
-
st =
|
|
16642
|
+
st = lstatSync10(src);
|
|
16571
16643
|
} catch {
|
|
16572
16644
|
continue;
|
|
16573
16645
|
}
|
|
@@ -16601,7 +16673,7 @@ function probeFilesystemCaseSensitivity(dir) {
|
|
|
16601
16673
|
const lower = join21(dir, ".tw-case-probe-a");
|
|
16602
16674
|
try {
|
|
16603
16675
|
writeFileSync11(upper, "", { flag: "wx" });
|
|
16604
|
-
return !
|
|
16676
|
+
return !existsSync13(lower);
|
|
16605
16677
|
} finally {
|
|
16606
16678
|
rmSync9(upper, { force: true });
|
|
16607
16679
|
}
|
|
@@ -16621,7 +16693,7 @@ function caseFoldCollision(paths) {
|
|
|
16621
16693
|
}
|
|
16622
16694
|
function dropSymlink(p) {
|
|
16623
16695
|
try {
|
|
16624
|
-
if (
|
|
16696
|
+
if (lstatSync10(p).isSymbolicLink()) rmSync9(p, { force: true });
|
|
16625
16697
|
} catch {
|
|
16626
16698
|
}
|
|
16627
16699
|
}
|
|
@@ -16663,7 +16735,7 @@ function overlayDigest(dest, paths) {
|
|
|
16663
16735
|
h.update("\0");
|
|
16664
16736
|
const p = join21(dest, rel);
|
|
16665
16737
|
try {
|
|
16666
|
-
const st =
|
|
16738
|
+
const st = lstatSync10(p);
|
|
16667
16739
|
h.update(String(st.mode));
|
|
16668
16740
|
h.update(st.isSymbolicLink() ? readlinkSync3(p) : readFileSync16(p));
|
|
16669
16741
|
} catch {
|
|
@@ -17015,7 +17087,7 @@ function runVerifyImpl(opts) {
|
|
|
17015
17087
|
if (!filesystemCaseSensitive) {
|
|
17016
17088
|
const present = (rel) => {
|
|
17017
17089
|
try {
|
|
17018
|
-
|
|
17090
|
+
lstatSync10(join21(cwd, rel));
|
|
17019
17091
|
return true;
|
|
17020
17092
|
} catch {
|
|
17021
17093
|
return false;
|
|
@@ -18390,7 +18462,7 @@ raise SystemExit(0)
|
|
|
18390
18462
|
|
|
18391
18463
|
// src/cli/doctor.ts
|
|
18392
18464
|
import { execFileSync as execFileSync11 } from "node:child_process";
|
|
18393
|
-
import { existsSync as
|
|
18465
|
+
import { existsSync as existsSync14, readFileSync as readFileSync18, readdirSync as readdirSync5 } from "node:fs";
|
|
18394
18466
|
import { join as join23, resolve as resolve11 } from "node:path";
|
|
18395
18467
|
function lifecyclePlatformCheck(platform = process.platform, linuxPython = platform === "linux" ? trustedLinuxPython() : null) {
|
|
18396
18468
|
if (platform === "linux") {
|
|
@@ -18446,7 +18518,7 @@ function wiringState(status, authority) {
|
|
|
18446
18518
|
return authority ? "BROKEN" : "WARN";
|
|
18447
18519
|
}
|
|
18448
18520
|
function pinsInFile(path) {
|
|
18449
|
-
if (!
|
|
18521
|
+
if (!existsSync14(path)) return [];
|
|
18450
18522
|
let src = "";
|
|
18451
18523
|
try {
|
|
18452
18524
|
src = readFileSync18(path, "utf8");
|
|
@@ -18470,7 +18542,7 @@ function workflowPermissionCheck(cwd, workflowRels = [".github/workflows/tamperw
|
|
|
18470
18542
|
const warnings = [];
|
|
18471
18543
|
for (const rel of workflowRels) {
|
|
18472
18544
|
const path = resolve11(cwd, rel);
|
|
18473
|
-
if (!
|
|
18545
|
+
if (!existsSync14(path)) {
|
|
18474
18546
|
broken.push(`${rel} is missing`);
|
|
18475
18547
|
continue;
|
|
18476
18548
|
}
|
|
@@ -18875,7 +18947,7 @@ function diagnose(opts = {}) {
|
|
|
18875
18947
|
} else {
|
|
18876
18948
|
const workflowDirRel = ".github/workflows";
|
|
18877
18949
|
const workflowDir = resolve11(cwd, workflowDirRel);
|
|
18878
|
-
if (!
|
|
18950
|
+
if (!existsSync14(workflowDir)) {
|
|
18879
18951
|
return fail("ci-verifier", `${workflowDirRel}: workflow directory does not exist`);
|
|
18880
18952
|
}
|
|
18881
18953
|
let entries;
|
|
@@ -18895,7 +18967,7 @@ function diagnose(opts = {}) {
|
|
|
18895
18967
|
const authorityWorkflows = [];
|
|
18896
18968
|
for (const workflowRel of workflowRels) {
|
|
18897
18969
|
const workflowPath = resolve11(cwd, workflowRel);
|
|
18898
|
-
if (!
|
|
18970
|
+
if (!existsSync14(workflowPath)) {
|
|
18899
18971
|
return fail("ci-verifier", `${workflowRel}: workflow does not exist`);
|
|
18900
18972
|
}
|
|
18901
18973
|
let doc;
|
|
@@ -19211,7 +19283,7 @@ var init_status2 = __esm({
|
|
|
19211
19283
|
// src/cli/trace-verify.ts
|
|
19212
19284
|
import { execFileSync as execFileSync12, spawnSync as spawnSync5 } from "node:child_process";
|
|
19213
19285
|
import {
|
|
19214
|
-
existsSync as
|
|
19286
|
+
existsSync as existsSync15,
|
|
19215
19287
|
mkdtempSync as mkdtempSync5,
|
|
19216
19288
|
readFileSync as readFileSync19,
|
|
19217
19289
|
readdirSync as readdirSync6,
|
|
@@ -19470,7 +19542,7 @@ function materializeBase(base, cwd, dest) {
|
|
|
19470
19542
|
}
|
|
19471
19543
|
const hostModules = join24(cwd, "node_modules");
|
|
19472
19544
|
const tracedModules = join24(dest, "node_modules");
|
|
19473
|
-
if (
|
|
19545
|
+
if (existsSync15(hostModules) && !existsSync15(tracedModules)) {
|
|
19474
19546
|
symlinkSync2(resolve12(hostModules), tracedModules, "dir");
|
|
19475
19547
|
}
|
|
19476
19548
|
}
|
|
@@ -19782,7 +19854,7 @@ var init_immutable = __esm({
|
|
|
19782
19854
|
});
|
|
19783
19855
|
|
|
19784
19856
|
// src/runtimes.ts
|
|
19785
|
-
import { existsSync as
|
|
19857
|
+
import { existsSync as existsSync16, readFileSync as readFileSync20 } from "node:fs";
|
|
19786
19858
|
import { join as join25 } from "node:path";
|
|
19787
19859
|
function isRecord6(x) {
|
|
19788
19860
|
return typeof x === "object" && x !== null && !Array.isArray(x);
|
|
@@ -19812,7 +19884,7 @@ function claudeSettingsBeyondTamperward(cwd) {
|
|
|
19812
19884
|
const path = join25(cwd, ".claude", "settings.json");
|
|
19813
19885
|
let raw;
|
|
19814
19886
|
try {
|
|
19815
|
-
if (!
|
|
19887
|
+
if (!existsSync16(path)) return false;
|
|
19816
19888
|
raw = readFileSync20(path, "utf8");
|
|
19817
19889
|
} catch {
|
|
19818
19890
|
return false;
|
|
@@ -19839,7 +19911,7 @@ function detectRuntimes(cwd) {
|
|
|
19839
19911
|
for (const rt of KNOWN_RUNTIMES) {
|
|
19840
19912
|
const marker = rt.markers.find((m) => {
|
|
19841
19913
|
try {
|
|
19842
|
-
return
|
|
19914
|
+
return existsSync16(join25(cwd, m));
|
|
19843
19915
|
} catch {
|
|
19844
19916
|
return false;
|
|
19845
19917
|
}
|
|
@@ -20864,7 +20936,7 @@ var init_adapter3 = __esm({
|
|
|
20864
20936
|
|
|
20865
20937
|
// src/adapters/copilot-sdk/changes.ts
|
|
20866
20938
|
import { execFileSync as execFileSync13 } from "node:child_process";
|
|
20867
|
-
import { mkdtempSync as mkdtempSync6, writeFileSync as writeFileSync13, readFileSync as readFileSync21, rmSync as rmSync12, existsSync as
|
|
20939
|
+
import { mkdtempSync as mkdtempSync6, writeFileSync as writeFileSync13, readFileSync as readFileSync21, rmSync as rmSync12, existsSync as existsSync17, realpathSync as realpathSync10 } from "node:fs";
|
|
20868
20940
|
import { tmpdir as tmpdir7 } from "node:os";
|
|
20869
20941
|
import { basename as basename5, dirname as dirname12, isAbsolute as isAbsolute16, relative as relative11, resolve as resolve15, join as join26 } from "node:path";
|
|
20870
20942
|
function asStr4(v) {
|
|
@@ -20883,7 +20955,7 @@ function canonicalContainedTarget(abs, root) {
|
|
|
20883
20955
|
}
|
|
20884
20956
|
let dir = abs;
|
|
20885
20957
|
const tail = [];
|
|
20886
|
-
while (!
|
|
20958
|
+
while (!existsSync17(dir)) {
|
|
20887
20959
|
const parent = dirname12(dir);
|
|
20888
20960
|
if (parent === dir) break;
|
|
20889
20961
|
tail.unshift(basename5(dir));
|
|
@@ -21711,7 +21783,7 @@ var init_runtime_qualification = __esm({
|
|
|
21711
21783
|
|
|
21712
21784
|
// src/cli/runtime.ts
|
|
21713
21785
|
import { execFileSync as execFileSync14 } from "node:child_process";
|
|
21714
|
-
import { existsSync as
|
|
21786
|
+
import { existsSync as existsSync18, mkdirSync as mkdirSync11, readFileSync as readFileSync22, writeFileSync as writeFileSync14 } from "node:fs";
|
|
21715
21787
|
import { join as join27, dirname as dirname13 } from "node:path";
|
|
21716
21788
|
function storePath(cwd) {
|
|
21717
21789
|
const dir = gitDir(cwd);
|
|
@@ -21719,7 +21791,7 @@ function storePath(cwd) {
|
|
|
21719
21791
|
}
|
|
21720
21792
|
function readStore(cwd) {
|
|
21721
21793
|
const path = storePath(cwd);
|
|
21722
|
-
if (!path || !
|
|
21794
|
+
if (!path || !existsSync18(path)) return null;
|
|
21723
21795
|
try {
|
|
21724
21796
|
const parsed = JSON.parse(readFileSync22(path, "utf8"));
|
|
21725
21797
|
if (parsed && typeof parsed === "object" && parsed.records && typeof parsed.records === "object") return parsed;
|
|
@@ -21890,7 +21962,7 @@ function resolveHookConfigHash(canonicalId, cwd) {
|
|
|
21890
21962
|
"github-copilot-cli": join27(cwd, ".github", "hooks", "tamperward.json")
|
|
21891
21963
|
};
|
|
21892
21964
|
const file = files[canonicalId];
|
|
21893
|
-
if (!file || !
|
|
21965
|
+
if (!file || !existsSync18(file)) return null;
|
|
21894
21966
|
try {
|
|
21895
21967
|
const raw = readFileSync22(file, "utf8");
|
|
21896
21968
|
let hooks = raw;
|
|
@@ -22171,7 +22243,7 @@ var init_runtime = __esm({
|
|
|
22171
22243
|
|
|
22172
22244
|
// src/cli/onboard.ts
|
|
22173
22245
|
import { execFileSync as execFileSync15 } from "node:child_process";
|
|
22174
|
-
import { lstatSync as
|
|
22246
|
+
import { lstatSync as lstatSync11, mkdtempSync as mkdtempSync7, readFileSync as readFileSync23, realpathSync as realpathSync11, rmSync as rmSync13 } from "node:fs";
|
|
22175
22247
|
import { tmpdir as tmpdir8 } from "node:os";
|
|
22176
22248
|
import { join as join28, relative as relative12, resolve as resolve16, sep as sep6 } from "node:path";
|
|
22177
22249
|
import { createInterface } from "node:readline";
|
|
@@ -22679,7 +22751,7 @@ function runDemo(cwd, head, runners, out3) {
|
|
|
22679
22751
|
return;
|
|
22680
22752
|
}
|
|
22681
22753
|
const targetPath = join28(wt, target.path);
|
|
22682
|
-
const targetStat =
|
|
22754
|
+
const targetStat = lstatSync11(targetPath, { throwIfNoEntry: false });
|
|
22683
22755
|
if (!targetStat || !targetStat.isFile() || targetStat.isSymbolicLink()) {
|
|
22684
22756
|
out3("Demo skipped: the selected test is not a regular file in the disposable worktree.");
|
|
22685
22757
|
return;
|
|
@@ -23352,7 +23424,7 @@ var init_record = __esm({
|
|
|
23352
23424
|
// src/research/run.ts
|
|
23353
23425
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
23354
23426
|
import { execFileSync as execFileSync16 } from "node:child_process";
|
|
23355
|
-
import { closeSync as
|
|
23427
|
+
import { closeSync as closeSync5, existsSync as existsSync19, linkSync, mkdirSync as mkdirSync12, openSync as openSync5, readFileSync as readFileSync25, renameSync as renameSync4, rmSync as rmSync14, unlinkSync, writeFileSync as writeFileSync15, writeSync } from "node:fs";
|
|
23356
23428
|
import { hostname } from "node:os";
|
|
23357
23429
|
import { join as join29, resolve as resolve19 } from "node:path";
|
|
23358
23430
|
function git7(args, cwd) {
|
|
@@ -23389,7 +23461,7 @@ function lockHolder(path) {
|
|
|
23389
23461
|
function acquireResearchLock(ledger, breakStaleLock = false) {
|
|
23390
23462
|
mkdirSync12(ledger, { recursive: true });
|
|
23391
23463
|
const path = researchLockPath(ledger);
|
|
23392
|
-
if (breakStaleLock &&
|
|
23464
|
+
if (breakStaleLock && existsSync19(path)) {
|
|
23393
23465
|
const owner2 = readLockOwner(path);
|
|
23394
23466
|
if (!owner2) {
|
|
23395
23467
|
throw new ResearchError(`research output ${ledger} has an unreadable lock at ${path}; verify no run is active, then remove it deliberately`);
|
|
@@ -23432,12 +23504,12 @@ function acquireResearchLock(ledger, breakStaleLock = false) {
|
|
|
23432
23504
|
const text = JSON.stringify(owner) + "\n";
|
|
23433
23505
|
let fd = -1;
|
|
23434
23506
|
try {
|
|
23435
|
-
fd =
|
|
23507
|
+
fd = openSync5(path, "wx", 384);
|
|
23436
23508
|
writeSync(fd, text);
|
|
23437
|
-
|
|
23509
|
+
closeSync5(fd);
|
|
23438
23510
|
fd = -1;
|
|
23439
23511
|
} catch (e) {
|
|
23440
|
-
if (fd !== -1)
|
|
23512
|
+
if (fd !== -1) closeSync5(fd);
|
|
23441
23513
|
if (e.code === "EEXIST") {
|
|
23442
23514
|
throw new ResearchError(
|
|
23443
23515
|
`research output ${ledger} is already locked by ${lockHolder(path)}; refusing concurrent writers. Verify the owner is not running, then remove ${path} deliberately or rerun with --break-lock`
|
|
@@ -23762,7 +23834,7 @@ function runResearch(opts) {
|
|
|
23762
23834
|
try {
|
|
23763
23835
|
for (let pair = 1; pair <= pairs; pair++) {
|
|
23764
23836
|
const path = pairRecordPath(ledger, task.id, pair);
|
|
23765
|
-
if (!
|
|
23837
|
+
if (!existsSync19(path)) continue;
|
|
23766
23838
|
const existing = resumableRecord(path, {
|
|
23767
23839
|
task: task.id,
|
|
23768
23840
|
pair,
|
|
@@ -23882,16 +23954,16 @@ var init_run2 = __esm({
|
|
|
23882
23954
|
});
|
|
23883
23955
|
|
|
23884
23956
|
// src/research/ledger-files.ts
|
|
23885
|
-
import { closeSync as
|
|
23957
|
+
import { closeSync as closeSync6, constants as constants5, fstatSync as fstatSync3, lstatSync as lstatSync12, openSync as openSync6, readFileSync as readFileSync26, readdirSync as readdirSync7, realpathSync as realpathSync12 } from "node:fs";
|
|
23886
23958
|
import { join as join30, resolve as resolve20 } from "node:path";
|
|
23887
23959
|
function lstatOrNull(path) {
|
|
23888
23960
|
try {
|
|
23889
|
-
return
|
|
23961
|
+
return lstatSync12(path);
|
|
23890
23962
|
} catch {
|
|
23891
23963
|
return null;
|
|
23892
23964
|
}
|
|
23893
23965
|
}
|
|
23894
|
-
function
|
|
23966
|
+
function kindOf2(st) {
|
|
23895
23967
|
if (st.isSymbolicLink()) return "a symlink";
|
|
23896
23968
|
if (st.isDirectory()) return "a directory";
|
|
23897
23969
|
if (st.isFIFO()) return "a FIFO";
|
|
@@ -23903,7 +23975,7 @@ function readRegularFile(path, realPairsDir, name) {
|
|
|
23903
23975
|
const listed = lstatOrNull(path);
|
|
23904
23976
|
if (listed === null) throw new ResearchError(`ledger record ${path} vanished while the ledger was being read`);
|
|
23905
23977
|
if (!listed.isFile()) {
|
|
23906
|
-
throw new ResearchError(`ledger record ${path} is ${
|
|
23978
|
+
throw new ResearchError(`ledger record ${path} is ${kindOf2(listed)}; only a regular file placed directly in pairs/ is read`);
|
|
23907
23979
|
}
|
|
23908
23980
|
if (listed.nlink !== 1) {
|
|
23909
23981
|
throw new ResearchError(`ledger record ${path} has ${listed.nlink} links; a hard link can name a file outside pairs/, so only a singly linked regular file is read`);
|
|
@@ -23912,22 +23984,22 @@ function readRegularFile(path, realPairsDir, name) {
|
|
|
23912
23984
|
if (real !== join30(realPairsDir, name)) {
|
|
23913
23985
|
throw new ResearchError(`ledger record ${path} resolves outside the pairs directory (${real}); refusing to read it`);
|
|
23914
23986
|
}
|
|
23915
|
-
const flags =
|
|
23987
|
+
const flags = constants5.O_RDONLY | (constants5.O_NOFOLLOW ?? 0);
|
|
23916
23988
|
let fd;
|
|
23917
23989
|
try {
|
|
23918
|
-
fd =
|
|
23990
|
+
fd = openSync6(path, flags);
|
|
23919
23991
|
} catch (e) {
|
|
23920
23992
|
throw new ResearchError(`cannot open ledger record ${path}: ${errorMessage(e)}`);
|
|
23921
23993
|
}
|
|
23922
23994
|
try {
|
|
23923
|
-
const opened =
|
|
23995
|
+
const opened = fstatSync3(fd);
|
|
23924
23996
|
const sameInode = process.platform === "win32" || opened.dev === listed.dev && opened.ino === listed.ino;
|
|
23925
23997
|
if (!opened.isFile() || !sameInode || opened.nlink !== 1) {
|
|
23926
23998
|
throw new ResearchError(`ledger record ${path} changed between listing and reading; refusing to read it`);
|
|
23927
23999
|
}
|
|
23928
24000
|
return readFileSync26(fd);
|
|
23929
24001
|
} finally {
|
|
23930
|
-
|
|
24002
|
+
closeSync6(fd);
|
|
23931
24003
|
}
|
|
23932
24004
|
}
|
|
23933
24005
|
function readPairFiles(ledger) {
|
|
@@ -24098,7 +24170,7 @@ var init_summarize = __esm({
|
|
|
24098
24170
|
|
|
24099
24171
|
// src/research/init.ts
|
|
24100
24172
|
import { createHash as createHash17 } from "node:crypto";
|
|
24101
|
-
import { existsSync as
|
|
24173
|
+
import { existsSync as existsSync20, mkdirSync as mkdirSync13, readFileSync as readFileSync27, writeFileSync as writeFileSync16 } from "node:fs";
|
|
24102
24174
|
import { basename as basename6, dirname as dirname15, resolve as resolve21 } from "node:path";
|
|
24103
24175
|
function idFrom(repo) {
|
|
24104
24176
|
const clean = repo.replace(/[\\/]$/, "").split(/[\\/]/).pop() || "task";
|
|
@@ -24110,7 +24182,7 @@ function createResearchManifest(opts) {
|
|
|
24110
24182
|
if (!opts.prompt) throw new ResearchError("research init requires --prompt");
|
|
24111
24183
|
if (!opts.verifyCommand) throw new ResearchError("research init requires --verify-command");
|
|
24112
24184
|
const out3 = resolve21(opts.out);
|
|
24113
|
-
if (
|
|
24185
|
+
if (existsSync20(out3)) throw new ResearchError(`research init refuses to overwrite ${out3}; choose a new path`);
|
|
24114
24186
|
const id = opts.id ?? idFrom(opts.repo);
|
|
24115
24187
|
if (!/^[A-Za-z0-9._-]+$/.test(id)) throw new ResearchError(`research init id must match [A-Za-z0-9._-] (got "${id}")`);
|
|
24116
24188
|
if (opts.verifyBudget !== void 0 && (!Number.isFinite(opts.verifyBudget) || opts.verifyBudget <= 0)) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tamperward",
|
|
3
|
-
"version": "2.39.
|
|
3
|
+
"version": "2.39.5",
|
|
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",
|