tamperward 2.39.4 → 2.39.6
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 +195 -108
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -1239,11 +1239,26 @@ function git(args, cwd) {
|
|
|
1239
1239
|
throw new Error(detail ? `git ${args[0]}: ${detail}` : failure.message || `git ${args[0]} failed`);
|
|
1240
1240
|
}
|
|
1241
1241
|
}
|
|
1242
|
+
function entryKindAt(rev2, path, cwd) {
|
|
1243
|
+
const listing = rev2 === "" ? git(["ls-files", "-s", "-z", "--", `:(literal)${path}`], cwd) : git(["ls-tree", "-z", rev2, "--", `:(literal)${path}`], cwd);
|
|
1244
|
+
for (const record of listing.split("\0")) {
|
|
1245
|
+
const tab = record.indexOf(" ");
|
|
1246
|
+
if (tab === -1 || record.slice(tab + 1) !== path) continue;
|
|
1247
|
+
const meta2 = record.slice(0, tab).split(" ");
|
|
1248
|
+
const mode = meta2[0] ?? "";
|
|
1249
|
+
const isBlob = rev2 === "" ? mode !== "160000" && !mode.startsWith("04") : meta2[1] === "blob";
|
|
1250
|
+
return isBlob ? "blob" : "other";
|
|
1251
|
+
}
|
|
1252
|
+
return "absent";
|
|
1253
|
+
}
|
|
1242
1254
|
function blobAt(rev2, path, cwd) {
|
|
1243
1255
|
try {
|
|
1244
1256
|
return git(["show", `${rev2}:${path}`], cwd);
|
|
1245
|
-
} catch {
|
|
1246
|
-
return null;
|
|
1257
|
+
} catch (e) {
|
|
1258
|
+
if (entryKindAt(rev2, path, cwd) !== "blob") return null;
|
|
1259
|
+
const detail = (e instanceof Error ? e.message : String(e)).split("\n")[0];
|
|
1260
|
+
const where = rev2 === "" ? "the index entry " : `${rev2}:`;
|
|
1261
|
+
throw new Error(`cannot read ${where}${path} although the tree lists it as a blob (${detail}); refusing to judge it as absent`);
|
|
1247
1262
|
}
|
|
1248
1263
|
}
|
|
1249
1264
|
function fromDisk(path, cwd) {
|
|
@@ -10885,8 +10900,8 @@ var init_policy_load = __esm({
|
|
|
10885
10900
|
|
|
10886
10901
|
// src/signoff.ts
|
|
10887
10902
|
import { createHash as createHash3 } from "node:crypto";
|
|
10888
|
-
import { appendFileSync, mkdirSync,
|
|
10889
|
-
import { dirname as dirname2, join as join9 } from "node:path";
|
|
10903
|
+
import { appendFileSync, closeSync as closeSync2, constants as constants3, fstatSync as fstatSync2, lstatSync as lstatSync3, mkdirSync, openSync as openSync2, readFileSync as readFileSync6 } from "node:fs";
|
|
10904
|
+
import { dirname as dirname2, join as join9, posix as posix4 } from "node:path";
|
|
10890
10905
|
function compactOobToken(want, head) {
|
|
10891
10906
|
const normalizedHead = head.trim().toLowerCase();
|
|
10892
10907
|
if (!want || !FULL_OBJECT_ID.test(normalizedHead)) return null;
|
|
@@ -10905,17 +10920,75 @@ function fingerprint(rule, file, evidence) {
|
|
|
10905
10920
|
return createHash3("sha256").update(`${rule}\0${file ?? ""}\0${evidence}`).digest("hex").slice(0, 16);
|
|
10906
10921
|
}
|
|
10907
10922
|
function ledgerPath(cwd, policy) {
|
|
10908
|
-
const rel = policy.signoff?.ledger ??
|
|
10923
|
+
const rel = policy.signoff?.ledger ?? DEFAULT_LEDGER;
|
|
10909
10924
|
if (!ledgerInsideRepo(rel)) {
|
|
10910
10925
|
throw new PolicyError(`signoff.ledger must be a relative path inside the repository, got ${JSON.stringify(rel)}`);
|
|
10911
10926
|
}
|
|
10912
10927
|
return join9(cwd, rel);
|
|
10913
10928
|
}
|
|
10929
|
+
function lstatOrAbsent(rel, shown, path) {
|
|
10930
|
+
try {
|
|
10931
|
+
return lstatSync3(path);
|
|
10932
|
+
} catch (e) {
|
|
10933
|
+
if (errnoCode(e) === "ENOENT") return null;
|
|
10934
|
+
throw new PolicyError(
|
|
10935
|
+
`signoff.ledger ${JSON.stringify(rel)}: cannot stat ${shown} (${errorMessage(e)}); refusing to treat the sign-off ledger as absent`
|
|
10936
|
+
);
|
|
10937
|
+
}
|
|
10938
|
+
}
|
|
10939
|
+
function kindOf(st) {
|
|
10940
|
+
if (st.isSymbolicLink()) return "a symbolic link";
|
|
10941
|
+
if (st.isDirectory()) return "a directory";
|
|
10942
|
+
if (st.isFIFO()) return "a FIFO";
|
|
10943
|
+
if (st.isSocket()) return "a socket";
|
|
10944
|
+
if (st.isCharacterDevice() || st.isBlockDevice()) return "a device";
|
|
10945
|
+
return "not a regular file";
|
|
10946
|
+
}
|
|
10947
|
+
function ledgerOnDisk(cwd, policy) {
|
|
10948
|
+
const rel = policy.signoff?.ledger ?? DEFAULT_LEDGER;
|
|
10949
|
+
ledgerPath(cwd, policy);
|
|
10950
|
+
const parts = posix4.normalize(rel.replace(/\\/g, "/")).split("/").filter((part) => part && part !== ".");
|
|
10951
|
+
let path = cwd;
|
|
10952
|
+
for (let i = 0; i < parts.length; i++) {
|
|
10953
|
+
const next = join9(path, parts[i]);
|
|
10954
|
+
const shown = parts.slice(0, i + 1).join("/");
|
|
10955
|
+
const st = lstatOrAbsent(rel, shown, next);
|
|
10956
|
+
if (st === null) return { rel, path: join9(cwd, ...parts), exists: false };
|
|
10957
|
+
const last = i === parts.length - 1;
|
|
10958
|
+
if (st.isSymbolicLink() || (last ? !st.isFile() : !st.isDirectory())) {
|
|
10959
|
+
throw new PolicyError(
|
|
10960
|
+
`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`
|
|
10961
|
+
);
|
|
10962
|
+
}
|
|
10963
|
+
path = next;
|
|
10964
|
+
}
|
|
10965
|
+
return { rel, path, exists: true };
|
|
10966
|
+
}
|
|
10967
|
+
function openLedger(rel, path, flags) {
|
|
10968
|
+
let fd;
|
|
10969
|
+
try {
|
|
10970
|
+
fd = openSync2(path, flags | (constants3.O_NOFOLLOW ?? 0), 420);
|
|
10971
|
+
} catch (e) {
|
|
10972
|
+
throw new PolicyError(`signoff.ledger ${JSON.stringify(rel)}: cannot open ${path} (${e instanceof Error ? e.message : String(e)})`);
|
|
10973
|
+
}
|
|
10974
|
+
if (!fstatSync2(fd).isFile()) {
|
|
10975
|
+
closeSync2(fd);
|
|
10976
|
+
throw new PolicyError(`signoff.ledger ${JSON.stringify(rel)}: ${path} is not a regular file; refusing to use it`);
|
|
10977
|
+
}
|
|
10978
|
+
return fd;
|
|
10979
|
+
}
|
|
10914
10980
|
function readLedger(cwd, policy) {
|
|
10915
|
-
const
|
|
10916
|
-
if (!
|
|
10981
|
+
const { rel, path, exists } = ledgerOnDisk(cwd, policy);
|
|
10982
|
+
if (!exists) return [];
|
|
10983
|
+
const fd = openLedger(rel, path, constants3.O_RDONLY);
|
|
10984
|
+
let text;
|
|
10985
|
+
try {
|
|
10986
|
+
text = readFileSync6(fd, "utf8");
|
|
10987
|
+
} finally {
|
|
10988
|
+
closeSync2(fd);
|
|
10989
|
+
}
|
|
10917
10990
|
const out3 = [];
|
|
10918
|
-
for (const line of
|
|
10991
|
+
for (const line of text.split("\n")) {
|
|
10919
10992
|
if (!line.trim()) continue;
|
|
10920
10993
|
try {
|
|
10921
10994
|
const e = ledgerEntryFrom(JSON.parse(line));
|
|
@@ -10926,15 +10999,27 @@ function readLedger(cwd, policy) {
|
|
|
10926
10999
|
return out3;
|
|
10927
11000
|
}
|
|
10928
11001
|
function appendEntry(cwd, policy, e) {
|
|
10929
|
-
const
|
|
10930
|
-
|
|
10931
|
-
|
|
11002
|
+
const { rel, path } = ledgerOnDisk(cwd, policy);
|
|
11003
|
+
try {
|
|
11004
|
+
mkdirSync(dirname2(path), { recursive: true });
|
|
11005
|
+
} catch (err3) {
|
|
11006
|
+
throw new PolicyError(`signoff.ledger ${JSON.stringify(rel)}: cannot create ${dirname2(path)} (${errorMessage(err3)})`);
|
|
11007
|
+
}
|
|
11008
|
+
const fd = openLedger(rel, path, constants3.O_WRONLY | constants3.O_APPEND | constants3.O_CREAT);
|
|
11009
|
+
try {
|
|
11010
|
+
appendFileSync(fd, JSON.stringify(e) + "\n");
|
|
11011
|
+
} finally {
|
|
11012
|
+
closeSync2(fd);
|
|
11013
|
+
}
|
|
10932
11014
|
}
|
|
10933
11015
|
function makeEntry(f, reason, now, ttlMs = DEFAULT_TTL_MS) {
|
|
10934
11016
|
return { rule: f.rule, file: f.file, fingerprint: fingerprintOf(f), reason, recordedAt: now, expiresAt: now + ttlMs };
|
|
10935
11017
|
}
|
|
11018
|
+
function honoredAt(e, now) {
|
|
11019
|
+
return e.expiresAt > now && e.recordedAt <= now && e.expiresAt - e.recordedAt <= LEDGER_TTL_MS;
|
|
11020
|
+
}
|
|
10936
11021
|
function applyLocalSignoffs(findings, cwd, policy, now = Date.now()) {
|
|
10937
|
-
const ledger = readLedger(cwd, policy).filter((e) => e
|
|
11022
|
+
const ledger = readLedger(cwd, policy).filter((e) => honoredAt(e, now));
|
|
10938
11023
|
const valid = new Set(ledger.map((e) => e.fingerprint));
|
|
10939
11024
|
const cleared = [];
|
|
10940
11025
|
const remaining = [];
|
|
@@ -10985,13 +11070,15 @@ function oobHeadFromEnv(env = process.env) {
|
|
|
10985
11070
|
function oobFromEnv(env = process.env) {
|
|
10986
11071
|
return (env.TAMPERWARD_OOB_SIGNOFF ?? "").split(",").map((s) => s.trim().replace(/^tamperward:allow:/, "")).filter(Boolean);
|
|
10987
11072
|
}
|
|
10988
|
-
var DEFAULT_TTL_MS, COMPACT_OOB_PREFIX, FULL_OBJECT_ID, fingerprintOf;
|
|
11073
|
+
var LEDGER_TTL_MS, DEFAULT_TTL_MS, DEFAULT_LEDGER, COMPACT_OOB_PREFIX, FULL_OBJECT_ID, fingerprintOf;
|
|
10989
11074
|
var init_signoff = __esm({
|
|
10990
11075
|
"src/signoff.ts"() {
|
|
10991
11076
|
"use strict";
|
|
10992
11077
|
init_policy_load();
|
|
10993
11078
|
init_narrow();
|
|
10994
|
-
|
|
11079
|
+
LEDGER_TTL_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
11080
|
+
DEFAULT_TTL_MS = LEDGER_TTL_MS;
|
|
11081
|
+
DEFAULT_LEDGER = ".tamperward/ledger.jsonl";
|
|
10995
11082
|
COMPACT_OOB_PREFIX = "tw1:";
|
|
10996
11083
|
FULL_OBJECT_ID = /^(?:[0-9a-f]{40}|[0-9a-f]{64})$/i;
|
|
10997
11084
|
fingerprintOf = (f) => fingerprint(f.rule, f.file, f.evidence);
|
|
@@ -11437,7 +11524,7 @@ var init_deny = __esm({
|
|
|
11437
11524
|
});
|
|
11438
11525
|
|
|
11439
11526
|
// src/session.ts
|
|
11440
|
-
import { existsSync as
|
|
11527
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync2, readFileSync as readFileSync7, renameSync, rmSync as rmSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
11441
11528
|
import { dirname as dirname3, join as join10 } from "node:path";
|
|
11442
11529
|
function writeBaseline(p, sha3) {
|
|
11443
11530
|
mkdirSync2(dirname3(p), { recursive: true });
|
|
@@ -11463,7 +11550,7 @@ function turnBaseline(cwd, sessionId) {
|
|
|
11463
11550
|
const p = baselinePath(cwd, sessionId);
|
|
11464
11551
|
if (!p) return null;
|
|
11465
11552
|
try {
|
|
11466
|
-
if (
|
|
11553
|
+
if (existsSync6(p)) {
|
|
11467
11554
|
const v = readFileSync7(p, "utf8").trim();
|
|
11468
11555
|
if (SHA.test(v)) return v;
|
|
11469
11556
|
}
|
|
@@ -11507,7 +11594,7 @@ var init_session = __esm({
|
|
|
11507
11594
|
|
|
11508
11595
|
// src/effect.ts
|
|
11509
11596
|
import { createHash as createHash4 } from "node:crypto";
|
|
11510
|
-
import { existsSync as
|
|
11597
|
+
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
11598
|
import { join as join11 } from "node:path";
|
|
11512
11599
|
function ptreeFrom(value) {
|
|
11513
11600
|
if (!isRecord(value)) return null;
|
|
@@ -11572,7 +11659,7 @@ function snapshotProtected(cwd, policy, prev, cache3) {
|
|
|
11572
11659
|
if (pruned.has(r)) continue;
|
|
11573
11660
|
let st;
|
|
11574
11661
|
try {
|
|
11575
|
-
st =
|
|
11662
|
+
st = lstatSync4(join11(cwd, r));
|
|
11576
11663
|
} catch {
|
|
11577
11664
|
continue;
|
|
11578
11665
|
}
|
|
@@ -11599,7 +11686,7 @@ function driftBetween(expected, current) {
|
|
|
11599
11686
|
return { changed, deleted, added };
|
|
11600
11687
|
}
|
|
11601
11688
|
function loadTree(p) {
|
|
11602
|
-
if (!p || !
|
|
11689
|
+
if (!p || !existsSync7(p)) return null;
|
|
11603
11690
|
try {
|
|
11604
11691
|
return ptreeFrom(JSON.parse(readFileSync8(p, "utf8")));
|
|
11605
11692
|
} catch {
|
|
@@ -11654,7 +11741,7 @@ var init_effect = __esm({
|
|
|
11654
11741
|
});
|
|
11655
11742
|
|
|
11656
11743
|
// src/cli/watch.ts
|
|
11657
|
-
import { appendFileSync as appendFileSync3, lstatSync as
|
|
11744
|
+
import { appendFileSync as appendFileSync3, lstatSync as lstatSync5, mkdirSync as mkdirSync4, readFileSync as readFileSync9, readdirSync as readdirSync2, watch, writeFileSync as writeFileSync4 } from "node:fs";
|
|
11658
11745
|
import { join as join12 } from "node:path";
|
|
11659
11746
|
import { createHash as createHash5 } from "node:crypto";
|
|
11660
11747
|
function snap(abs) {
|
|
@@ -11757,7 +11844,7 @@ function watchTree(dir, cb, onState, onError, watchFn = watch) {
|
|
|
11757
11844
|
const child = rel ? `${rel}/${String(fname)}` : String(fname);
|
|
11758
11845
|
cb(kind, child);
|
|
11759
11846
|
try {
|
|
11760
|
-
if (
|
|
11847
|
+
if (lstatSync5(join12(dir, child)).isDirectory()) addDir(child);
|
|
11761
11848
|
} catch {
|
|
11762
11849
|
}
|
|
11763
11850
|
});
|
|
@@ -11793,7 +11880,7 @@ function watchTree(dir, cb, onState, onError, watchFn = watch) {
|
|
|
11793
11880
|
const child = rel ? `${rel}/${name}` : name;
|
|
11794
11881
|
if (SKIP2.test(child + "/")) continue;
|
|
11795
11882
|
try {
|
|
11796
|
-
if (
|
|
11883
|
+
if (lstatSync5(join12(dir, child)).isDirectory()) walk2(child);
|
|
11797
11884
|
} catch {
|
|
11798
11885
|
}
|
|
11799
11886
|
}
|
|
@@ -11944,7 +12031,7 @@ var init_watch = __esm({
|
|
|
11944
12031
|
});
|
|
11945
12032
|
|
|
11946
12033
|
// src/detectors/fs-events.ts
|
|
11947
|
-
import { closeSync as
|
|
12034
|
+
import { closeSync as closeSync3, openSync as openSync3, readSync as readSync2, statSync as statSync2 } from "node:fs";
|
|
11948
12035
|
function fsEventFrom(line) {
|
|
11949
12036
|
let value;
|
|
11950
12037
|
try {
|
|
@@ -11991,12 +12078,12 @@ function readEvents(log, offset, maxBytes = MAX_EVENT_READ_BYTES, io = DEFAULT_E
|
|
|
11991
12078
|
const available = size - start;
|
|
11992
12079
|
const requested = Math.min(available, cap);
|
|
11993
12080
|
const buffer = Buffer.allocUnsafe(requested);
|
|
11994
|
-
const fd =
|
|
12081
|
+
const fd = openSync3(log, "r");
|
|
11995
12082
|
let bytesRead = 0;
|
|
11996
12083
|
try {
|
|
11997
12084
|
bytesRead = io.read(fd, buffer, 0, requested, start);
|
|
11998
12085
|
} finally {
|
|
11999
|
-
|
|
12086
|
+
closeSync3(fd);
|
|
12000
12087
|
}
|
|
12001
12088
|
if (bytesRead <= 0) {
|
|
12002
12089
|
return {
|
|
@@ -12201,7 +12288,7 @@ var init_fs_events = __esm({
|
|
|
12201
12288
|
|
|
12202
12289
|
// src/cli/audit.ts
|
|
12203
12290
|
import { createHash as createHash6, randomBytes } from "node:crypto";
|
|
12204
|
-
import { appendFileSync as appendFileSync4, closeSync as
|
|
12291
|
+
import { appendFileSync as appendFileSync4, closeSync as closeSync4, existsSync as existsSync8, mkdirSync as mkdirSync5, openSync as openSync4, readSync as readSync3 } from "node:fs";
|
|
12205
12292
|
import { dirname as dirname4, isAbsolute as isAbsolute8, join as join13, resolve as resolve4 } from "node:path";
|
|
12206
12293
|
function sessionHash(sessionId) {
|
|
12207
12294
|
if (!sessionId) return void 0;
|
|
@@ -12321,7 +12408,7 @@ function parseAuditLine(line, lineNumber) {
|
|
|
12321
12408
|
return parseAuditEvent(value, lineNumber);
|
|
12322
12409
|
}
|
|
12323
12410
|
function forEachAuditLine(file, onLine, maxLineBytes = MAX_AUDIT_LINE_BYTES) {
|
|
12324
|
-
const fd =
|
|
12411
|
+
const fd = openSync4(file, "r");
|
|
12325
12412
|
try {
|
|
12326
12413
|
const chunk = Buffer.allocUnsafe(64 * 1024);
|
|
12327
12414
|
let pending = [];
|
|
@@ -12359,7 +12446,7 @@ function forEachAuditLine(file, onLine, maxLineBytes = MAX_AUDIT_LINE_BYTES) {
|
|
|
12359
12446
|
}
|
|
12360
12447
|
if (pending.length) emit3(pending);
|
|
12361
12448
|
} finally {
|
|
12362
|
-
|
|
12449
|
+
closeSync4(fd);
|
|
12363
12450
|
}
|
|
12364
12451
|
}
|
|
12365
12452
|
function parseSince(value, nowMs = Date.now()) {
|
|
@@ -12460,7 +12547,7 @@ function runStats(opts = {}) {
|
|
|
12460
12547
|
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
12548
|
const cutoff = opts.since ? parseSince(opts.since) : null;
|
|
12462
12549
|
if (!file) throw new Error("stats needs --file outside a Git repository");
|
|
12463
|
-
if (!
|
|
12550
|
+
if (!existsSync8(file)) {
|
|
12464
12551
|
if (explicitFile) throw new Error(`audit file not found: ${file}`);
|
|
12465
12552
|
const empty2 = summarizeAudit([]);
|
|
12466
12553
|
process.stdout.write(opts.json ? JSON.stringify(empty2) + "\n" : renderAuditStats(empty2));
|
|
@@ -12499,7 +12586,7 @@ var init_audit = __esm({
|
|
|
12499
12586
|
});
|
|
12500
12587
|
|
|
12501
12588
|
// src/cli/hook.ts
|
|
12502
|
-
import { readFileSync as readFileSync10, appendFileSync as appendFileSync5, writeFileSync as writeFileSync5, existsSync as
|
|
12589
|
+
import { readFileSync as readFileSync10, appendFileSync as appendFileSync5, writeFileSync as writeFileSync5, existsSync as existsSync9 } from "node:fs";
|
|
12503
12590
|
import { createHash as createHash7 } from "node:crypto";
|
|
12504
12591
|
function setSnapshotCache(cache3) {
|
|
12505
12592
|
snapshotCache = cache3;
|
|
@@ -12796,9 +12883,9 @@ function turnTransientBlocks(cwd, sessionId, policy, changes) {
|
|
|
12796
12883
|
recordObserverHealth(cwd, sessionId, telemetry.state, telemetry.reason);
|
|
12797
12884
|
}
|
|
12798
12885
|
const cp = cursorPath(cwd, sessionId);
|
|
12799
|
-
if (!
|
|
12886
|
+
if (!existsSync9(log)) return none;
|
|
12800
12887
|
let offset = 0;
|
|
12801
|
-
if (cp &&
|
|
12888
|
+
if (cp && existsSync9(cp)) {
|
|
12802
12889
|
const n2 = Number(readFileSync10(cp, "utf8"));
|
|
12803
12890
|
offset = Number.isFinite(n2) ? n2 : 0;
|
|
12804
12891
|
}
|
|
@@ -12979,7 +13066,7 @@ var init_hook = __esm({
|
|
|
12979
13066
|
});
|
|
12980
13067
|
|
|
12981
13068
|
// src/ptree-cache.ts
|
|
12982
|
-
import { lstatSync as
|
|
13069
|
+
import { lstatSync as lstatSync6 } from "node:fs";
|
|
12983
13070
|
import { join as join14 } from "node:path";
|
|
12984
13071
|
function keyOf(st) {
|
|
12985
13072
|
return `${st.dev}:${st.ino}:${st.size}:${st.mode}:${st.mtimeNs}:${st.ctimeNs}`;
|
|
@@ -13033,7 +13120,7 @@ var init_ptree_cache = __esm({
|
|
|
13033
13120
|
const abs = join14(cwd, rel);
|
|
13034
13121
|
let st;
|
|
13035
13122
|
try {
|
|
13036
|
-
st =
|
|
13123
|
+
st = lstatSync6(abs, { bigint: true });
|
|
13037
13124
|
} catch {
|
|
13038
13125
|
this.map.delete(abs);
|
|
13039
13126
|
this.stats.misses++;
|
|
@@ -13055,7 +13142,7 @@ var init_ptree_cache = __esm({
|
|
|
13055
13142
|
const entry = compute();
|
|
13056
13143
|
let after;
|
|
13057
13144
|
try {
|
|
13058
|
-
after =
|
|
13145
|
+
after = lstatSync6(abs, { bigint: true });
|
|
13059
13146
|
} catch {
|
|
13060
13147
|
this.map.delete(abs);
|
|
13061
13148
|
return entry;
|
|
@@ -13073,7 +13160,7 @@ var init_ptree_cache = __esm({
|
|
|
13073
13160
|
});
|
|
13074
13161
|
|
|
13075
13162
|
// src/cli/hook-service.ts
|
|
13076
|
-
import { chmodSync, existsSync as
|
|
13163
|
+
import { chmodSync, existsSync as existsSync10, lstatSync as lstatSync7, mkdirSync as mkdirSync6, readFileSync as readFileSync11, rmSync as rmSync4, writeFileSync as writeFileSync6 } from "node:fs";
|
|
13077
13164
|
import { createConnection as createConnection2, createServer } from "node:net";
|
|
13078
13165
|
import { realpathSync as realpathSync4 } from "node:fs";
|
|
13079
13166
|
import { sep } from "node:path";
|
|
@@ -13161,8 +13248,8 @@ function removeQuietly(p) {
|
|
|
13161
13248
|
}
|
|
13162
13249
|
}
|
|
13163
13250
|
function ensurePrivateDir(dir, uid) {
|
|
13164
|
-
if (!
|
|
13165
|
-
const st =
|
|
13251
|
+
if (!existsSync10(dir)) mkdirSync6(dir, { recursive: true, mode: 448 });
|
|
13252
|
+
const st = lstatSync7(dir);
|
|
13166
13253
|
if (!st.isDirectory()) throw new Error(`${dir} is not a directory`);
|
|
13167
13254
|
if (st.uid !== uid) throw new Error(`${dir} is owned by uid ${st.uid}, not ${uid}; refusing to serve from it`);
|
|
13168
13255
|
if ((st.mode & 63) !== 0) chmodSync(dir, 448);
|
|
@@ -13358,7 +13445,7 @@ async function stopHookService(paths, expectedRoot) {
|
|
|
13358
13445
|
process.kill(st.pid, "SIGTERM");
|
|
13359
13446
|
} catch {
|
|
13360
13447
|
}
|
|
13361
|
-
const gone = () => !pidAlive2(st.pid) || !
|
|
13448
|
+
const gone = () => !pidAlive2(st.pid) || !existsSync10(paths.socket);
|
|
13362
13449
|
const until = Date.now() + STOP_WAIT_MS;
|
|
13363
13450
|
while (!gone() && Date.now() < until) sleepSync(50);
|
|
13364
13451
|
if (!gone()) throw new Error(`hook service pid ${st.pid} did not exit within ${STOP_WAIT_MS / 1e3}s`);
|
|
@@ -13594,11 +13681,11 @@ var init_verifier_limits = __esm({
|
|
|
13594
13681
|
|
|
13595
13682
|
// src/safe-write.ts
|
|
13596
13683
|
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
13597
|
-
import { lstatSync as
|
|
13684
|
+
import { lstatSync as lstatSync8, renameSync as renameSync3, rmSync as rmSync5, writeFileSync as writeFileSync7 } from "node:fs";
|
|
13598
13685
|
function writeTargetKind(path) {
|
|
13599
13686
|
let st;
|
|
13600
13687
|
try {
|
|
13601
|
-
st =
|
|
13688
|
+
st = lstatSync8(path, { throwIfNoEntry: false });
|
|
13602
13689
|
} catch (e) {
|
|
13603
13690
|
if (errnoCode(e) === "ENOTDIR") return "absent";
|
|
13604
13691
|
throw e;
|
|
@@ -13619,7 +13706,7 @@ function refuseNonRegular(path) {
|
|
|
13619
13706
|
}
|
|
13620
13707
|
function existingMode(path, fallback) {
|
|
13621
13708
|
if (writeTargetKind(path) !== "file") return fallback;
|
|
13622
|
-
return
|
|
13709
|
+
return lstatSync8(path).mode & 511;
|
|
13623
13710
|
}
|
|
13624
13711
|
function atomicReplaceFile(path, content, mode) {
|
|
13625
13712
|
const tmp = `${path}.${process.pid}.${randomBytes2(8).toString("hex")}.tmp`;
|
|
@@ -13640,7 +13727,7 @@ var init_safe_write = __esm({
|
|
|
13640
13727
|
// src/cli/init.ts
|
|
13641
13728
|
import { execFileSync as execFileSync6 } from "node:child_process";
|
|
13642
13729
|
import { createHash as createHash8 } from "node:crypto";
|
|
13643
|
-
import { existsSync as
|
|
13730
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync7, readFileSync as readFileSync12, realpathSync as realpathSync5 } from "node:fs";
|
|
13644
13731
|
import { basename as basename3, dirname as dirname5, isAbsolute as isAbsolute9, join as join15, relative as relative4, resolve as resolve6 } from "node:path";
|
|
13645
13732
|
function gitConfig(cwd, key2) {
|
|
13646
13733
|
try {
|
|
@@ -13744,7 +13831,7 @@ function verifierCandidates(cwd) {
|
|
|
13744
13831
|
if (/^\s*\[tool\.pytest(?:\.ini_options)?\]\s*$/m.test(pyproject)) add("pytest");
|
|
13745
13832
|
} catch {
|
|
13746
13833
|
}
|
|
13747
|
-
if (
|
|
13834
|
+
if (existsSync11(join15(cwd, "pytest.ini"))) add("pytest");
|
|
13748
13835
|
try {
|
|
13749
13836
|
const setupCfg = readFileSync12(join15(cwd, "setup.cfg"), "utf8");
|
|
13750
13837
|
if (/^\s*\[tool:pytest\]\s*$/m.test(setupCfg)) add("pytest");
|
|
@@ -13804,7 +13891,7 @@ function planPolicy(cwd) {
|
|
|
13804
13891
|
const path = join15(cwd, POLICY_FILE);
|
|
13805
13892
|
const refused = refuseNonRegular(path);
|
|
13806
13893
|
if (refused) return { item: "policy", path: POLICY_FILE, status: "error", detail: refused };
|
|
13807
|
-
if (
|
|
13894
|
+
if (existsSync11(path)) {
|
|
13808
13895
|
try {
|
|
13809
13896
|
loadPolicy(cwd);
|
|
13810
13897
|
} catch (e) {
|
|
@@ -13823,7 +13910,7 @@ function planPolicy(cwd) {
|
|
|
13823
13910
|
function planGitignore(cwd) {
|
|
13824
13911
|
const rel = ".gitignore";
|
|
13825
13912
|
const path = join15(cwd, rel);
|
|
13826
|
-
if (!
|
|
13913
|
+
if (!existsSync11(join15(cwd, "node_modules"))) return null;
|
|
13827
13914
|
let existing = "";
|
|
13828
13915
|
let kind;
|
|
13829
13916
|
try {
|
|
@@ -13888,7 +13975,7 @@ function planClaudeHooks(cwd) {
|
|
|
13888
13975
|
const refused = refuseNonRegular(path);
|
|
13889
13976
|
if (refused) return { item: "agent", path: rel, status: "error", detail: refused };
|
|
13890
13977
|
let settings = {};
|
|
13891
|
-
if (
|
|
13978
|
+
if (existsSync11(path)) {
|
|
13892
13979
|
let parsed;
|
|
13893
13980
|
try {
|
|
13894
13981
|
parsed = JSON.parse(readFileSync12(path, "utf8"));
|
|
@@ -13940,7 +14027,7 @@ function planClaudeHooks(cwd) {
|
|
|
13940
14027
|
return {
|
|
13941
14028
|
item: "agent",
|
|
13942
14029
|
path: rel,
|
|
13943
|
-
status:
|
|
14030
|
+
status: existsSync11(path) ? "update" : "create",
|
|
13944
14031
|
detail: [
|
|
13945
14032
|
needPre && "wire PreToolUse deny",
|
|
13946
14033
|
needStop && "wire Stop sweep",
|
|
@@ -13984,7 +14071,7 @@ function hooksDir(cwd) {
|
|
|
13984
14071
|
if (out3) return resolve6(cwd, out3);
|
|
13985
14072
|
} catch {
|
|
13986
14073
|
}
|
|
13987
|
-
return
|
|
14074
|
+
return existsSync11(join15(cwd, ".git")) ? join15(cwd, ".git", "hooks") : null;
|
|
13988
14075
|
}
|
|
13989
14076
|
function display(cwd, path) {
|
|
13990
14077
|
const rel = relative4(cwd, path);
|
|
@@ -14011,11 +14098,11 @@ function planPreCommit(cwd) {
|
|
|
14011
14098
|
const skip = (detail) => ({ item: "pre-commit", path: "(none)", status: "skip", detail });
|
|
14012
14099
|
let path;
|
|
14013
14100
|
let note;
|
|
14014
|
-
if (
|
|
14101
|
+
if (existsSync11(join15(cwd, ".husky"))) {
|
|
14015
14102
|
path = join15(cwd, ".husky", "pre-commit");
|
|
14016
14103
|
note = "husky";
|
|
14017
14104
|
} else {
|
|
14018
|
-
const managed = MANAGED_HOOKS.find((m) => m.configs.some((c) =>
|
|
14105
|
+
const managed = MANAGED_HOOKS.find((m) => m.configs.some((c) => existsSync11(join15(cwd, c))));
|
|
14019
14106
|
if (managed) {
|
|
14020
14107
|
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
14108
|
}
|
|
@@ -14033,7 +14120,7 @@ function planPreCommit(cwd) {
|
|
|
14033
14120
|
const rel = display(cwd, path);
|
|
14034
14121
|
const refused = refuseNonRegular(path);
|
|
14035
14122
|
if (refused) return { item: "pre-commit", path: rel, status: "error", detail: refused };
|
|
14036
|
-
const existing =
|
|
14123
|
+
const existing = existsSync11(path) ? readFileSync12(path, "utf8") : null;
|
|
14037
14124
|
const hookMode = () => existingMode(path, 493) | 73;
|
|
14038
14125
|
if (existing === null) {
|
|
14039
14126
|
return {
|
|
@@ -14164,7 +14251,7 @@ function planWorkflow(cwd, force) {
|
|
|
14164
14251
|
};
|
|
14165
14252
|
const refused = refuseNonRegular(path);
|
|
14166
14253
|
if (refused) return { item: "ci", path: rel, status: "error", detail: refused };
|
|
14167
|
-
if (!
|
|
14254
|
+
if (!existsSync11(path)) {
|
|
14168
14255
|
return {
|
|
14169
14256
|
item: "ci",
|
|
14170
14257
|
path: rel,
|
|
@@ -14522,8 +14609,8 @@ var init_fingerprint = __esm({
|
|
|
14522
14609
|
// src/dependency-env.ts
|
|
14523
14610
|
import { createHash as createHash10 } from "node:crypto";
|
|
14524
14611
|
import {
|
|
14525
|
-
existsSync as
|
|
14526
|
-
lstatSync as
|
|
14612
|
+
existsSync as existsSync12,
|
|
14613
|
+
lstatSync as lstatSync9,
|
|
14527
14614
|
readdirSync as readdirSync3,
|
|
14528
14615
|
readFileSync as readFileSync13,
|
|
14529
14616
|
readlinkSync as readlinkSync2,
|
|
@@ -14548,7 +14635,7 @@ function inside(root, candidate) {
|
|
|
14548
14635
|
return rel === "" || rel !== ".." && !rel.startsWith(".." + sep3) && !isAbsolute10(rel);
|
|
14549
14636
|
}
|
|
14550
14637
|
function modeKind(path) {
|
|
14551
|
-
const st =
|
|
14638
|
+
const st = lstatSync9(path);
|
|
14552
14639
|
if (st.isFile()) return { kind: "file", mode: st.mode };
|
|
14553
14640
|
if (st.isDirectory()) return { kind: "dir", mode: st.mode };
|
|
14554
14641
|
if (st.isSymbolicLink()) return { kind: "symlink", mode: st.mode };
|
|
@@ -14558,7 +14645,7 @@ function fingerprintRoot(root, cwd, h) {
|
|
|
14558
14645
|
let rootStat;
|
|
14559
14646
|
let currentReal;
|
|
14560
14647
|
try {
|
|
14561
|
-
rootStat =
|
|
14648
|
+
rootStat = lstatSync9(root.path);
|
|
14562
14649
|
currentReal = realpathSync6(root.path);
|
|
14563
14650
|
} catch (e) {
|
|
14564
14651
|
throw new Unattestable(
|
|
@@ -14676,7 +14763,7 @@ function snapshot(roots, probes, cwd) {
|
|
|
14676
14763
|
const h = createHash10("sha256");
|
|
14677
14764
|
for (const probe of probes) {
|
|
14678
14765
|
h.update(
|
|
14679
|
-
"probe\0" + probe.kind + "\0" + probe.path + "\0" + (
|
|
14766
|
+
"probe\0" + probe.kind + "\0" + probe.path + "\0" + (existsSync12(probe.path) ? "present" : "absent") + "\0"
|
|
14680
14767
|
);
|
|
14681
14768
|
}
|
|
14682
14769
|
for (const root of roots) fingerprintRoot(root, cwd, h);
|
|
@@ -14735,7 +14822,7 @@ function resolveExecutable(token, cwd, env) {
|
|
|
14735
14822
|
if (token.includes("/") || token.includes("\\")) {
|
|
14736
14823
|
const path = isAbsolute10(token) ? token : resolve7(cwd, token);
|
|
14737
14824
|
try {
|
|
14738
|
-
return
|
|
14825
|
+
return existsSync12(path) ? realpathSync6(path) : null;
|
|
14739
14826
|
} catch {
|
|
14740
14827
|
return null;
|
|
14741
14828
|
}
|
|
@@ -14743,7 +14830,7 @@ function resolveExecutable(token, cwd, env) {
|
|
|
14743
14830
|
for (const entry of (env.PATH ?? "").split(delimiter).filter(Boolean)) {
|
|
14744
14831
|
const candidate = resolve7(entry, token);
|
|
14745
14832
|
try {
|
|
14746
|
-
if (
|
|
14833
|
+
if (existsSync12(candidate) && statSync3(candidate).isFile()) return realpathSync6(candidate);
|
|
14747
14834
|
} catch {
|
|
14748
14835
|
}
|
|
14749
14836
|
}
|
|
@@ -14766,7 +14853,7 @@ function inferredVenvFromToken(token, cwd) {
|
|
|
14766
14853
|
const parentName = basename4(parent).toLowerCase();
|
|
14767
14854
|
if (parentName !== "bin" && parentName !== "scripts") return null;
|
|
14768
14855
|
const root = dirname6(parent);
|
|
14769
|
-
return
|
|
14856
|
+
return existsSync12(join16(root, "pyvenv.cfg")) ? root : null;
|
|
14770
14857
|
}
|
|
14771
14858
|
function unsupportedEcosystem(command, token) {
|
|
14772
14859
|
const name = token ? basename4(token).toLowerCase() : "";
|
|
@@ -14782,11 +14869,11 @@ function inferredVenv(executable) {
|
|
|
14782
14869
|
const parentName = basename4(parent).toLowerCase();
|
|
14783
14870
|
if (parentName !== "bin" && parentName !== "scripts") return null;
|
|
14784
14871
|
const root = dirname6(parent);
|
|
14785
|
-
return
|
|
14872
|
+
return existsSync12(join16(root, "pyvenv.cfg")) ? root : null;
|
|
14786
14873
|
}
|
|
14787
14874
|
function venvProblem(root) {
|
|
14788
14875
|
const cfg = join16(root, "pyvenv.cfg");
|
|
14789
|
-
if (!
|
|
14876
|
+
if (!existsSync12(cfg)) return "VIRTUAL_ENV " + JSON.stringify(root) + " has no pyvenv.cfg";
|
|
14790
14877
|
try {
|
|
14791
14878
|
const body = readFileSync13(cfg, "utf8");
|
|
14792
14879
|
if (/^\s*include-system-site-packages\s*=\s*true\s*$/im.test(body)) {
|
|
@@ -14813,7 +14900,7 @@ function discoverDependencyEnvironment(cwdInput, command, env = process.env) {
|
|
|
14813
14900
|
};
|
|
14814
14901
|
try {
|
|
14815
14902
|
const nodeModules = join16(cwd, "node_modules");
|
|
14816
|
-
if (
|
|
14903
|
+
if (existsSync12(nodeModules)) addRoot("node_modules", nodeModules);
|
|
14817
14904
|
else probes.push({ kind: "node_modules", path: nodeModules });
|
|
14818
14905
|
const token = firstExecutable(command);
|
|
14819
14906
|
const executable = resolveExecutable(token, cwd, env);
|
|
@@ -14825,7 +14912,7 @@ function discoverDependencyEnvironment(cwdInput, command, env = process.env) {
|
|
|
14825
14912
|
venv = resolve7(env.VIRTUAL_ENV);
|
|
14826
14913
|
} else {
|
|
14827
14914
|
venv = inferredVenv(executable) ?? inferredVenvFromToken(token, cwd);
|
|
14828
|
-
if (!venv && /(?:^|\s)uv\s+run(?:\s|$)/.test(command) &&
|
|
14915
|
+
if (!venv && /(?:^|\s)uv\s+run(?:\s|$)/.test(command) && existsSync12(join16(cwd, ".venv", "pyvenv.cfg"))) {
|
|
14829
14916
|
venv = join16(cwd, ".venv");
|
|
14830
14917
|
}
|
|
14831
14918
|
}
|
|
@@ -15304,7 +15391,7 @@ if (child) {
|
|
|
15304
15391
|
// src/verifier-backend.ts
|
|
15305
15392
|
import { createHash as createHash11, randomUUID } from "node:crypto";
|
|
15306
15393
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
15307
|
-
import { accessSync as accessSync2, constants as
|
|
15394
|
+
import { accessSync as accessSync2, constants as constants4, readFileSync as readFileSync14, realpathSync as realpathSync7, statSync as statSync4 } from "node:fs";
|
|
15308
15395
|
import { delimiter as delimiter2, dirname as dirname7, join as join18, resolve as resolve8 } from "node:path";
|
|
15309
15396
|
function identity() {
|
|
15310
15397
|
const uid = typeof process.getuid === "function" ? process.getuid() : null;
|
|
@@ -15341,7 +15428,7 @@ function findExecutable(name) {
|
|
|
15341
15428
|
if (!raw) continue;
|
|
15342
15429
|
const candidate = join18(raw, name);
|
|
15343
15430
|
try {
|
|
15344
|
-
accessSync2(candidate,
|
|
15431
|
+
accessSync2(candidate, constants4.X_OK);
|
|
15345
15432
|
return realpathSync7(candidate);
|
|
15346
15433
|
} catch {
|
|
15347
15434
|
}
|
|
@@ -16405,7 +16492,7 @@ var init_verification_receipt = __esm({
|
|
|
16405
16492
|
// src/cli/verify.ts
|
|
16406
16493
|
import { execFileSync as execFileSync9, spawnSync as spawnSync3 } from "node:child_process";
|
|
16407
16494
|
import { createHash as createHash14 } from "node:crypto";
|
|
16408
|
-
import { chmodSync as chmodSync2, cpSync, lstatSync as
|
|
16495
|
+
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
16496
|
import { tmpdir as tmpdir4 } from "node:os";
|
|
16410
16497
|
import { dirname as dirname10, isAbsolute as isAbsolute11, join as join21, relative as relative6, resolve as resolve9, sep as sep4 } from "node:path";
|
|
16411
16498
|
function oracleAssuranceReport() {
|
|
@@ -16499,7 +16586,7 @@ function validateSymlinkGraph(target, out3, root, dependencyRoot, label) {
|
|
|
16499
16586
|
const current = join21(base, ...stack);
|
|
16500
16587
|
let st;
|
|
16501
16588
|
try {
|
|
16502
|
-
st =
|
|
16589
|
+
st = lstatSync10(current);
|
|
16503
16590
|
} catch {
|
|
16504
16591
|
continue;
|
|
16505
16592
|
}
|
|
@@ -16541,7 +16628,7 @@ function rejectLinkedParent(cwd, rel) {
|
|
|
16541
16628
|
current = join21(current, part);
|
|
16542
16629
|
let st;
|
|
16543
16630
|
try {
|
|
16544
|
-
st =
|
|
16631
|
+
st = lstatSync10(current);
|
|
16545
16632
|
} catch {
|
|
16546
16633
|
continue;
|
|
16547
16634
|
}
|
|
@@ -16567,7 +16654,7 @@ function materialize(cwd, dest, dependencyRoot) {
|
|
|
16567
16654
|
rejectLinkedParent(cwd, rel);
|
|
16568
16655
|
let st;
|
|
16569
16656
|
try {
|
|
16570
|
-
st =
|
|
16657
|
+
st = lstatSync10(src);
|
|
16571
16658
|
} catch {
|
|
16572
16659
|
continue;
|
|
16573
16660
|
}
|
|
@@ -16601,7 +16688,7 @@ function probeFilesystemCaseSensitivity(dir) {
|
|
|
16601
16688
|
const lower = join21(dir, ".tw-case-probe-a");
|
|
16602
16689
|
try {
|
|
16603
16690
|
writeFileSync11(upper, "", { flag: "wx" });
|
|
16604
|
-
return !
|
|
16691
|
+
return !existsSync13(lower);
|
|
16605
16692
|
} finally {
|
|
16606
16693
|
rmSync9(upper, { force: true });
|
|
16607
16694
|
}
|
|
@@ -16621,7 +16708,7 @@ function caseFoldCollision(paths) {
|
|
|
16621
16708
|
}
|
|
16622
16709
|
function dropSymlink(p) {
|
|
16623
16710
|
try {
|
|
16624
|
-
if (
|
|
16711
|
+
if (lstatSync10(p).isSymbolicLink()) rmSync9(p, { force: true });
|
|
16625
16712
|
} catch {
|
|
16626
16713
|
}
|
|
16627
16714
|
}
|
|
@@ -16663,7 +16750,7 @@ function overlayDigest(dest, paths) {
|
|
|
16663
16750
|
h.update("\0");
|
|
16664
16751
|
const p = join21(dest, rel);
|
|
16665
16752
|
try {
|
|
16666
|
-
const st =
|
|
16753
|
+
const st = lstatSync10(p);
|
|
16667
16754
|
h.update(String(st.mode));
|
|
16668
16755
|
h.update(st.isSymbolicLink() ? readlinkSync3(p) : readFileSync16(p));
|
|
16669
16756
|
} catch {
|
|
@@ -17015,7 +17102,7 @@ function runVerifyImpl(opts) {
|
|
|
17015
17102
|
if (!filesystemCaseSensitive) {
|
|
17016
17103
|
const present = (rel) => {
|
|
17017
17104
|
try {
|
|
17018
|
-
|
|
17105
|
+
lstatSync10(join21(cwd, rel));
|
|
17019
17106
|
return true;
|
|
17020
17107
|
} catch {
|
|
17021
17108
|
return false;
|
|
@@ -18390,7 +18477,7 @@ raise SystemExit(0)
|
|
|
18390
18477
|
|
|
18391
18478
|
// src/cli/doctor.ts
|
|
18392
18479
|
import { execFileSync as execFileSync11 } from "node:child_process";
|
|
18393
|
-
import { existsSync as
|
|
18480
|
+
import { existsSync as existsSync14, readFileSync as readFileSync18, readdirSync as readdirSync5 } from "node:fs";
|
|
18394
18481
|
import { join as join23, resolve as resolve11 } from "node:path";
|
|
18395
18482
|
function lifecyclePlatformCheck(platform = process.platform, linuxPython = platform === "linux" ? trustedLinuxPython() : null) {
|
|
18396
18483
|
if (platform === "linux") {
|
|
@@ -18446,7 +18533,7 @@ function wiringState(status, authority) {
|
|
|
18446
18533
|
return authority ? "BROKEN" : "WARN";
|
|
18447
18534
|
}
|
|
18448
18535
|
function pinsInFile(path) {
|
|
18449
|
-
if (!
|
|
18536
|
+
if (!existsSync14(path)) return [];
|
|
18450
18537
|
let src = "";
|
|
18451
18538
|
try {
|
|
18452
18539
|
src = readFileSync18(path, "utf8");
|
|
@@ -18470,7 +18557,7 @@ function workflowPermissionCheck(cwd, workflowRels = [".github/workflows/tamperw
|
|
|
18470
18557
|
const warnings = [];
|
|
18471
18558
|
for (const rel of workflowRels) {
|
|
18472
18559
|
const path = resolve11(cwd, rel);
|
|
18473
|
-
if (!
|
|
18560
|
+
if (!existsSync14(path)) {
|
|
18474
18561
|
broken.push(`${rel} is missing`);
|
|
18475
18562
|
continue;
|
|
18476
18563
|
}
|
|
@@ -18875,7 +18962,7 @@ function diagnose(opts = {}) {
|
|
|
18875
18962
|
} else {
|
|
18876
18963
|
const workflowDirRel = ".github/workflows";
|
|
18877
18964
|
const workflowDir = resolve11(cwd, workflowDirRel);
|
|
18878
|
-
if (!
|
|
18965
|
+
if (!existsSync14(workflowDir)) {
|
|
18879
18966
|
return fail("ci-verifier", `${workflowDirRel}: workflow directory does not exist`);
|
|
18880
18967
|
}
|
|
18881
18968
|
let entries;
|
|
@@ -18895,7 +18982,7 @@ function diagnose(opts = {}) {
|
|
|
18895
18982
|
const authorityWorkflows = [];
|
|
18896
18983
|
for (const workflowRel of workflowRels) {
|
|
18897
18984
|
const workflowPath = resolve11(cwd, workflowRel);
|
|
18898
|
-
if (!
|
|
18985
|
+
if (!existsSync14(workflowPath)) {
|
|
18899
18986
|
return fail("ci-verifier", `${workflowRel}: workflow does not exist`);
|
|
18900
18987
|
}
|
|
18901
18988
|
let doc;
|
|
@@ -19211,7 +19298,7 @@ var init_status2 = __esm({
|
|
|
19211
19298
|
// src/cli/trace-verify.ts
|
|
19212
19299
|
import { execFileSync as execFileSync12, spawnSync as spawnSync5 } from "node:child_process";
|
|
19213
19300
|
import {
|
|
19214
|
-
existsSync as
|
|
19301
|
+
existsSync as existsSync15,
|
|
19215
19302
|
mkdtempSync as mkdtempSync5,
|
|
19216
19303
|
readFileSync as readFileSync19,
|
|
19217
19304
|
readdirSync as readdirSync6,
|
|
@@ -19470,7 +19557,7 @@ function materializeBase(base, cwd, dest) {
|
|
|
19470
19557
|
}
|
|
19471
19558
|
const hostModules = join24(cwd, "node_modules");
|
|
19472
19559
|
const tracedModules = join24(dest, "node_modules");
|
|
19473
|
-
if (
|
|
19560
|
+
if (existsSync15(hostModules) && !existsSync15(tracedModules)) {
|
|
19474
19561
|
symlinkSync2(resolve12(hostModules), tracedModules, "dir");
|
|
19475
19562
|
}
|
|
19476
19563
|
}
|
|
@@ -19782,7 +19869,7 @@ var init_immutable = __esm({
|
|
|
19782
19869
|
});
|
|
19783
19870
|
|
|
19784
19871
|
// src/runtimes.ts
|
|
19785
|
-
import { existsSync as
|
|
19872
|
+
import { existsSync as existsSync16, readFileSync as readFileSync20 } from "node:fs";
|
|
19786
19873
|
import { join as join25 } from "node:path";
|
|
19787
19874
|
function isRecord6(x) {
|
|
19788
19875
|
return typeof x === "object" && x !== null && !Array.isArray(x);
|
|
@@ -19812,7 +19899,7 @@ function claudeSettingsBeyondTamperward(cwd) {
|
|
|
19812
19899
|
const path = join25(cwd, ".claude", "settings.json");
|
|
19813
19900
|
let raw;
|
|
19814
19901
|
try {
|
|
19815
|
-
if (!
|
|
19902
|
+
if (!existsSync16(path)) return false;
|
|
19816
19903
|
raw = readFileSync20(path, "utf8");
|
|
19817
19904
|
} catch {
|
|
19818
19905
|
return false;
|
|
@@ -19839,7 +19926,7 @@ function detectRuntimes(cwd) {
|
|
|
19839
19926
|
for (const rt of KNOWN_RUNTIMES) {
|
|
19840
19927
|
const marker = rt.markers.find((m) => {
|
|
19841
19928
|
try {
|
|
19842
|
-
return
|
|
19929
|
+
return existsSync16(join25(cwd, m));
|
|
19843
19930
|
} catch {
|
|
19844
19931
|
return false;
|
|
19845
19932
|
}
|
|
@@ -20864,7 +20951,7 @@ var init_adapter3 = __esm({
|
|
|
20864
20951
|
|
|
20865
20952
|
// src/adapters/copilot-sdk/changes.ts
|
|
20866
20953
|
import { execFileSync as execFileSync13 } from "node:child_process";
|
|
20867
|
-
import { mkdtempSync as mkdtempSync6, writeFileSync as writeFileSync13, readFileSync as readFileSync21, rmSync as rmSync12, existsSync as
|
|
20954
|
+
import { mkdtempSync as mkdtempSync6, writeFileSync as writeFileSync13, readFileSync as readFileSync21, rmSync as rmSync12, existsSync as existsSync17, realpathSync as realpathSync10 } from "node:fs";
|
|
20868
20955
|
import { tmpdir as tmpdir7 } from "node:os";
|
|
20869
20956
|
import { basename as basename5, dirname as dirname12, isAbsolute as isAbsolute16, relative as relative11, resolve as resolve15, join as join26 } from "node:path";
|
|
20870
20957
|
function asStr4(v) {
|
|
@@ -20883,7 +20970,7 @@ function canonicalContainedTarget(abs, root) {
|
|
|
20883
20970
|
}
|
|
20884
20971
|
let dir = abs;
|
|
20885
20972
|
const tail = [];
|
|
20886
|
-
while (!
|
|
20973
|
+
while (!existsSync17(dir)) {
|
|
20887
20974
|
const parent = dirname12(dir);
|
|
20888
20975
|
if (parent === dir) break;
|
|
20889
20976
|
tail.unshift(basename5(dir));
|
|
@@ -21711,7 +21798,7 @@ var init_runtime_qualification = __esm({
|
|
|
21711
21798
|
|
|
21712
21799
|
// src/cli/runtime.ts
|
|
21713
21800
|
import { execFileSync as execFileSync14 } from "node:child_process";
|
|
21714
|
-
import { existsSync as
|
|
21801
|
+
import { existsSync as existsSync18, mkdirSync as mkdirSync11, readFileSync as readFileSync22, writeFileSync as writeFileSync14 } from "node:fs";
|
|
21715
21802
|
import { join as join27, dirname as dirname13 } from "node:path";
|
|
21716
21803
|
function storePath(cwd) {
|
|
21717
21804
|
const dir = gitDir(cwd);
|
|
@@ -21719,7 +21806,7 @@ function storePath(cwd) {
|
|
|
21719
21806
|
}
|
|
21720
21807
|
function readStore(cwd) {
|
|
21721
21808
|
const path = storePath(cwd);
|
|
21722
|
-
if (!path || !
|
|
21809
|
+
if (!path || !existsSync18(path)) return null;
|
|
21723
21810
|
try {
|
|
21724
21811
|
const parsed = JSON.parse(readFileSync22(path, "utf8"));
|
|
21725
21812
|
if (parsed && typeof parsed === "object" && parsed.records && typeof parsed.records === "object") return parsed;
|
|
@@ -21890,7 +21977,7 @@ function resolveHookConfigHash(canonicalId, cwd) {
|
|
|
21890
21977
|
"github-copilot-cli": join27(cwd, ".github", "hooks", "tamperward.json")
|
|
21891
21978
|
};
|
|
21892
21979
|
const file = files[canonicalId];
|
|
21893
|
-
if (!file || !
|
|
21980
|
+
if (!file || !existsSync18(file)) return null;
|
|
21894
21981
|
try {
|
|
21895
21982
|
const raw = readFileSync22(file, "utf8");
|
|
21896
21983
|
let hooks = raw;
|
|
@@ -22171,7 +22258,7 @@ var init_runtime = __esm({
|
|
|
22171
22258
|
|
|
22172
22259
|
// src/cli/onboard.ts
|
|
22173
22260
|
import { execFileSync as execFileSync15 } from "node:child_process";
|
|
22174
|
-
import { lstatSync as
|
|
22261
|
+
import { lstatSync as lstatSync11, mkdtempSync as mkdtempSync7, readFileSync as readFileSync23, realpathSync as realpathSync11, rmSync as rmSync13 } from "node:fs";
|
|
22175
22262
|
import { tmpdir as tmpdir8 } from "node:os";
|
|
22176
22263
|
import { join as join28, relative as relative12, resolve as resolve16, sep as sep6 } from "node:path";
|
|
22177
22264
|
import { createInterface } from "node:readline";
|
|
@@ -22679,7 +22766,7 @@ function runDemo(cwd, head, runners, out3) {
|
|
|
22679
22766
|
return;
|
|
22680
22767
|
}
|
|
22681
22768
|
const targetPath = join28(wt, target.path);
|
|
22682
|
-
const targetStat =
|
|
22769
|
+
const targetStat = lstatSync11(targetPath, { throwIfNoEntry: false });
|
|
22683
22770
|
if (!targetStat || !targetStat.isFile() || targetStat.isSymbolicLink()) {
|
|
22684
22771
|
out3("Demo skipped: the selected test is not a regular file in the disposable worktree.");
|
|
22685
22772
|
return;
|
|
@@ -23352,7 +23439,7 @@ var init_record = __esm({
|
|
|
23352
23439
|
// src/research/run.ts
|
|
23353
23440
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
23354
23441
|
import { execFileSync as execFileSync16 } from "node:child_process";
|
|
23355
|
-
import { closeSync as
|
|
23442
|
+
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
23443
|
import { hostname } from "node:os";
|
|
23357
23444
|
import { join as join29, resolve as resolve19 } from "node:path";
|
|
23358
23445
|
function git7(args, cwd) {
|
|
@@ -23389,7 +23476,7 @@ function lockHolder(path) {
|
|
|
23389
23476
|
function acquireResearchLock(ledger, breakStaleLock = false) {
|
|
23390
23477
|
mkdirSync12(ledger, { recursive: true });
|
|
23391
23478
|
const path = researchLockPath(ledger);
|
|
23392
|
-
if (breakStaleLock &&
|
|
23479
|
+
if (breakStaleLock && existsSync19(path)) {
|
|
23393
23480
|
const owner2 = readLockOwner(path);
|
|
23394
23481
|
if (!owner2) {
|
|
23395
23482
|
throw new ResearchError(`research output ${ledger} has an unreadable lock at ${path}; verify no run is active, then remove it deliberately`);
|
|
@@ -23432,12 +23519,12 @@ function acquireResearchLock(ledger, breakStaleLock = false) {
|
|
|
23432
23519
|
const text = JSON.stringify(owner) + "\n";
|
|
23433
23520
|
let fd = -1;
|
|
23434
23521
|
try {
|
|
23435
|
-
fd =
|
|
23522
|
+
fd = openSync5(path, "wx", 384);
|
|
23436
23523
|
writeSync(fd, text);
|
|
23437
|
-
|
|
23524
|
+
closeSync5(fd);
|
|
23438
23525
|
fd = -1;
|
|
23439
23526
|
} catch (e) {
|
|
23440
|
-
if (fd !== -1)
|
|
23527
|
+
if (fd !== -1) closeSync5(fd);
|
|
23441
23528
|
if (e.code === "EEXIST") {
|
|
23442
23529
|
throw new ResearchError(
|
|
23443
23530
|
`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 +23849,7 @@ function runResearch(opts) {
|
|
|
23762
23849
|
try {
|
|
23763
23850
|
for (let pair = 1; pair <= pairs; pair++) {
|
|
23764
23851
|
const path = pairRecordPath(ledger, task.id, pair);
|
|
23765
|
-
if (!
|
|
23852
|
+
if (!existsSync19(path)) continue;
|
|
23766
23853
|
const existing = resumableRecord(path, {
|
|
23767
23854
|
task: task.id,
|
|
23768
23855
|
pair,
|
|
@@ -23882,16 +23969,16 @@ var init_run2 = __esm({
|
|
|
23882
23969
|
});
|
|
23883
23970
|
|
|
23884
23971
|
// src/research/ledger-files.ts
|
|
23885
|
-
import { closeSync as
|
|
23972
|
+
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
23973
|
import { join as join30, resolve as resolve20 } from "node:path";
|
|
23887
23974
|
function lstatOrNull(path) {
|
|
23888
23975
|
try {
|
|
23889
|
-
return
|
|
23976
|
+
return lstatSync12(path);
|
|
23890
23977
|
} catch {
|
|
23891
23978
|
return null;
|
|
23892
23979
|
}
|
|
23893
23980
|
}
|
|
23894
|
-
function
|
|
23981
|
+
function kindOf2(st) {
|
|
23895
23982
|
if (st.isSymbolicLink()) return "a symlink";
|
|
23896
23983
|
if (st.isDirectory()) return "a directory";
|
|
23897
23984
|
if (st.isFIFO()) return "a FIFO";
|
|
@@ -23903,7 +23990,7 @@ function readRegularFile(path, realPairsDir, name) {
|
|
|
23903
23990
|
const listed = lstatOrNull(path);
|
|
23904
23991
|
if (listed === null) throw new ResearchError(`ledger record ${path} vanished while the ledger was being read`);
|
|
23905
23992
|
if (!listed.isFile()) {
|
|
23906
|
-
throw new ResearchError(`ledger record ${path} is ${
|
|
23993
|
+
throw new ResearchError(`ledger record ${path} is ${kindOf2(listed)}; only a regular file placed directly in pairs/ is read`);
|
|
23907
23994
|
}
|
|
23908
23995
|
if (listed.nlink !== 1) {
|
|
23909
23996
|
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 +23999,22 @@ function readRegularFile(path, realPairsDir, name) {
|
|
|
23912
23999
|
if (real !== join30(realPairsDir, name)) {
|
|
23913
24000
|
throw new ResearchError(`ledger record ${path} resolves outside the pairs directory (${real}); refusing to read it`);
|
|
23914
24001
|
}
|
|
23915
|
-
const flags =
|
|
24002
|
+
const flags = constants5.O_RDONLY | (constants5.O_NOFOLLOW ?? 0);
|
|
23916
24003
|
let fd;
|
|
23917
24004
|
try {
|
|
23918
|
-
fd =
|
|
24005
|
+
fd = openSync6(path, flags);
|
|
23919
24006
|
} catch (e) {
|
|
23920
24007
|
throw new ResearchError(`cannot open ledger record ${path}: ${errorMessage(e)}`);
|
|
23921
24008
|
}
|
|
23922
24009
|
try {
|
|
23923
|
-
const opened =
|
|
24010
|
+
const opened = fstatSync3(fd);
|
|
23924
24011
|
const sameInode = process.platform === "win32" || opened.dev === listed.dev && opened.ino === listed.ino;
|
|
23925
24012
|
if (!opened.isFile() || !sameInode || opened.nlink !== 1) {
|
|
23926
24013
|
throw new ResearchError(`ledger record ${path} changed between listing and reading; refusing to read it`);
|
|
23927
24014
|
}
|
|
23928
24015
|
return readFileSync26(fd);
|
|
23929
24016
|
} finally {
|
|
23930
|
-
|
|
24017
|
+
closeSync6(fd);
|
|
23931
24018
|
}
|
|
23932
24019
|
}
|
|
23933
24020
|
function readPairFiles(ledger) {
|
|
@@ -24098,7 +24185,7 @@ var init_summarize = __esm({
|
|
|
24098
24185
|
|
|
24099
24186
|
// src/research/init.ts
|
|
24100
24187
|
import { createHash as createHash17 } from "node:crypto";
|
|
24101
|
-
import { existsSync as
|
|
24188
|
+
import { existsSync as existsSync20, mkdirSync as mkdirSync13, readFileSync as readFileSync27, writeFileSync as writeFileSync16 } from "node:fs";
|
|
24102
24189
|
import { basename as basename6, dirname as dirname15, resolve as resolve21 } from "node:path";
|
|
24103
24190
|
function idFrom(repo) {
|
|
24104
24191
|
const clean = repo.replace(/[\\/]$/, "").split(/[\\/]/).pop() || "task";
|
|
@@ -24110,7 +24197,7 @@ function createResearchManifest(opts) {
|
|
|
24110
24197
|
if (!opts.prompt) throw new ResearchError("research init requires --prompt");
|
|
24111
24198
|
if (!opts.verifyCommand) throw new ResearchError("research init requires --verify-command");
|
|
24112
24199
|
const out3 = resolve21(opts.out);
|
|
24113
|
-
if (
|
|
24200
|
+
if (existsSync20(out3)) throw new ResearchError(`research init refuses to overwrite ${out3}; choose a new path`);
|
|
24114
24201
|
const id = opts.id ?? idFrom(opts.repo);
|
|
24115
24202
|
if (!/^[A-Za-z0-9._-]+$/.test(id)) throw new ResearchError(`research init id must match [A-Za-z0-9._-] (got "${id}")`);
|
|
24116
24203
|
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.6",
|
|
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",
|