@mnemonik/cli 7.154.2 → 7.155.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auth/credentials.js +35 -22
- package/dist/auth/index.js +35 -22
- package/dist/auth/installSession.js +21 -10
- package/dist/auth/status.js +21 -10
- package/dist/authorizationWords.js +21 -10
- package/dist/diagnostics.js +35 -22
- package/dist/digests.json +57 -53
- package/dist/hooksLog.js +3 -1
- package/dist/identity/migrate.js +35 -22
- package/dist/install/hosts.js +21 -10
- package/dist/install/journal.js +35 -22
- package/dist/install/journey.d.ts.map +1 -1
- package/dist/install/journey.js +42 -22
- package/dist/install/journey.js.map +1 -1
- package/dist/install/ownership.js +35 -22
- package/dist/install/transaction.js +35 -22
- package/dist/install/ui.js +35 -22
- package/dist/installSession.js +21 -10
- package/dist/installation.js +35 -22
- package/dist/launcher.js +35 -22
- package/dist/preflight.js +23 -10
- package/dist/project/eligibility.js +35 -22
- package/dist/project/records.js +35 -22
- package/dist/project.js +35 -22
- package/dist/router.d.ts +2 -0
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +66 -43
- package/dist/router.js.map +1 -1
- package/dist/runtime/releaseSource.js +35 -22
- package/dist/runtime/selfUpdate.d.ts +11 -1
- package/dist/runtime/selfUpdate.d.ts.map +1 -1
- package/dist/runtime/selfUpdate.js +52 -26
- package/dist/runtime/selfUpdate.js.map +1 -1
- package/dist/runtime/signers.js +177 -22
- package/dist/runtime/store.js +81 -22
- package/dist/runtime/updateCheck.js +35 -22
- package/dist/sbom.json +21 -21
- package/dist/scanner/control.js +35 -22
- package/dist/scanner/data.js +21 -10
- package/dist/scanner/discover.js +23 -10
- package/dist/scanner/enable.d.ts +5 -0
- package/dist/scanner/enable.d.ts.map +1 -1
- package/dist/scanner/enable.js +52 -22
- package/dist/scanner/enable.js.map +1 -1
- package/dist/scanner/estimate.d.ts +41 -0
- package/dist/scanner/estimate.d.ts.map +1 -0
- package/dist/scanner/estimate.js +2461 -0
- package/dist/scanner/estimate.js.map +1 -0
- package/dist/scanner/picker.js +23 -10
- package/dist/scanner/service.js +35 -22
- package/dist/scanner/update.js +35 -22
- package/dist/scanner-release.json +24 -24
- package/dist/status.d.ts +6 -0
- package/dist/status.d.ts.map +1 -1
- package/dist/status.js +39 -23
- package/dist/status.js.map +1 -1
- package/dist/vendor/local-setup.js +35 -22
- package/dist/vendor/shared/runtimeReader.js +110 -21
- package/package.json +31 -31
package/dist/runtime/signers.js
CHANGED
|
@@ -1090,6 +1090,7 @@ var init_secretPatterns = __esm({
|
|
|
1090
1090
|
import { randomBytes } from "node:crypto";
|
|
1091
1091
|
import { closeSync, constants, fstatSync, lstatSync as lstatSync2, mkdirSync as mkdirSync2, openSync, renameSync as renameSync2, statSync, unlinkSync as unlinkSync2, writeSync } from "node:fs";
|
|
1092
1092
|
import { dirname as dirname3, join as join4 } from "node:path";
|
|
1093
|
+
import { open as openAsync, stat as statAsync } from "node:fs/promises";
|
|
1093
1094
|
function hookTraceEnabled(env = process.env) {
|
|
1094
1095
|
const value = env[HOOK_TRACE_ENV]?.trim().toLowerCase();
|
|
1095
1096
|
return !value || !["off", "0", "false", "no", "disabled"].includes(value);
|
|
@@ -1279,7 +1280,88 @@ function startHookTrace(options) {
|
|
|
1279
1280
|
trace.open();
|
|
1280
1281
|
return trace;
|
|
1281
1282
|
}
|
|
1282
|
-
|
|
1283
|
+
async function summarizeRecentHookCalls(host, options = {}) {
|
|
1284
|
+
const empty = { missed: 0, total: 0 };
|
|
1285
|
+
const now = options.now ?? Date.now();
|
|
1286
|
+
const since = now - (options.windowMs ?? HOOK_MISS_WINDOW_MS);
|
|
1287
|
+
let text;
|
|
1288
|
+
try {
|
|
1289
|
+
const file = hookTraceFile(host, options.stateDir);
|
|
1290
|
+
const size = (await statAsync(file)).size;
|
|
1291
|
+
const handle = await openAsync(file, "r");
|
|
1292
|
+
try {
|
|
1293
|
+
const length = Math.min(size, HOOK_MISS_TAIL_BYTES);
|
|
1294
|
+
const buffer = Buffer.alloc(length);
|
|
1295
|
+
await handle.read(buffer, 0, length, size - length);
|
|
1296
|
+
text = buffer.toString("utf8");
|
|
1297
|
+
} finally {
|
|
1298
|
+
await handle.close();
|
|
1299
|
+
}
|
|
1300
|
+
} catch {
|
|
1301
|
+
return empty;
|
|
1302
|
+
}
|
|
1303
|
+
const started = /* @__PURE__ */ new Map();
|
|
1304
|
+
const ended = /* @__PURE__ */ new Set();
|
|
1305
|
+
let missed = 0;
|
|
1306
|
+
let total = 0;
|
|
1307
|
+
for (const line of text.split("\n")) {
|
|
1308
|
+
let record2;
|
|
1309
|
+
try {
|
|
1310
|
+
record2 = JSON.parse(line);
|
|
1311
|
+
} catch {
|
|
1312
|
+
continue;
|
|
1313
|
+
}
|
|
1314
|
+
const at = Date.parse(record2.ts);
|
|
1315
|
+
if (!(at >= since))
|
|
1316
|
+
continue;
|
|
1317
|
+
if (record2.phase === "start")
|
|
1318
|
+
started.set(record2.id, at);
|
|
1319
|
+
else if (record2.phase === "end") {
|
|
1320
|
+
ended.add(record2.id);
|
|
1321
|
+
const answeredByPath = /* @__PURE__ */ new Map();
|
|
1322
|
+
for (const call of record2.calls ?? []) {
|
|
1323
|
+
const status = call.status ?? 0;
|
|
1324
|
+
const answered = call.error === void 0 && call.pending !== true && status > 0 && status < 500 && status !== 408 && status !== 429;
|
|
1325
|
+
answeredByPath.set(call.path, (answeredByPath.get(call.path) ?? false) || answered);
|
|
1326
|
+
}
|
|
1327
|
+
for (const answered of answeredByPath.values()) {
|
|
1328
|
+
total++;
|
|
1329
|
+
if (!answered)
|
|
1330
|
+
missed++;
|
|
1331
|
+
}
|
|
1332
|
+
}
|
|
1333
|
+
}
|
|
1334
|
+
for (const [id, at] of started) {
|
|
1335
|
+
if (ended.has(id) || now - at < 6e4)
|
|
1336
|
+
continue;
|
|
1337
|
+
total++;
|
|
1338
|
+
missed++;
|
|
1339
|
+
}
|
|
1340
|
+
return { missed, total };
|
|
1341
|
+
}
|
|
1342
|
+
function summaryFor(host, options) {
|
|
1343
|
+
const key = `${host}\0${options.stateDir ?? ""}\0${options.now ?? ""}`;
|
|
1344
|
+
const cached = summaries.get(key);
|
|
1345
|
+
if (cached)
|
|
1346
|
+
return cached;
|
|
1347
|
+
const entry = {
|
|
1348
|
+
read: Promise.resolve({})
|
|
1349
|
+
};
|
|
1350
|
+
entry.read = summarizeRecentHookCalls(host, options).then(({ missed, total }) => {
|
|
1351
|
+
const value = total > 0 ? { [HOOK_MISSES_HEADER]: `${missed}/${total}` } : {};
|
|
1352
|
+
entry.value = value;
|
|
1353
|
+
return value;
|
|
1354
|
+
});
|
|
1355
|
+
summaries.set(key, entry);
|
|
1356
|
+
return entry;
|
|
1357
|
+
}
|
|
1358
|
+
function hookMissesHeaders(host, options = {}) {
|
|
1359
|
+
return summaryFor(host, options).read;
|
|
1360
|
+
}
|
|
1361
|
+
function hookMissesHeadersIfReady(host, options = {}) {
|
|
1362
|
+
return summaryFor(host, options).value ?? {};
|
|
1363
|
+
}
|
|
1364
|
+
var HOOK_TRACE_MAX_BYTES, HOOK_TRACE_ENV, MAX_FIELDS, MAX_CALLS, MAX_ERROR_CHARS, SAFE_ID, SAFE_NAME, SAFE_ENUM, preparedDirectories, STALE_LOCK_MS, isObject, HookTrace, active, HOOK_MISS_WINDOW_MS, HOOK_MISS_TAIL_BYTES, HOOK_MISSES_HEADER, summaries;
|
|
1283
1365
|
var init_hookTrace = __esm({
|
|
1284
1366
|
"packages/shared/dist/hookTrace.js"() {
|
|
1285
1367
|
"use strict";
|
|
@@ -1482,6 +1564,10 @@ var init_hookTrace = __esm({
|
|
|
1482
1564
|
});
|
|
1483
1565
|
}
|
|
1484
1566
|
};
|
|
1567
|
+
HOOK_MISS_WINDOW_MS = 30 * 60 * 1e3;
|
|
1568
|
+
HOOK_MISS_TAIL_BYTES = 64 * 1024;
|
|
1569
|
+
HOOK_MISSES_HEADER = "x-mnemonik-hook-misses";
|
|
1570
|
+
summaries = /* @__PURE__ */ new Map();
|
|
1485
1571
|
}
|
|
1486
1572
|
});
|
|
1487
1573
|
|
|
@@ -1495,7 +1581,40 @@ function safePath(path) {
|
|
|
1495
1581
|
throw new RuntimeError("permission");
|
|
1496
1582
|
return path;
|
|
1497
1583
|
}
|
|
1498
|
-
|
|
1584
|
+
function limiter(limit) {
|
|
1585
|
+
let active3 = 0;
|
|
1586
|
+
const waiting = [];
|
|
1587
|
+
return async (work) => {
|
|
1588
|
+
if (active3 >= limit)
|
|
1589
|
+
await new Promise((release) => waiting.push(release));
|
|
1590
|
+
active3 += 1;
|
|
1591
|
+
try {
|
|
1592
|
+
return await work();
|
|
1593
|
+
} finally {
|
|
1594
|
+
active3 -= 1;
|
|
1595
|
+
waiting.shift()?.();
|
|
1596
|
+
}
|
|
1597
|
+
};
|
|
1598
|
+
}
|
|
1599
|
+
async function ownedFileBytes(path, mode) {
|
|
1600
|
+
const fd = await open(path, constants2.O_RDONLY | constants2.O_NOFOLLOW).catch((error) => {
|
|
1601
|
+
throw error.code === "ELOOP" ? new RuntimeError("permission") : error;
|
|
1602
|
+
});
|
|
1603
|
+
try {
|
|
1604
|
+
const stat2 = await fd.stat();
|
|
1605
|
+
if (!stat2.isFile() || stat2.uid !== process.getuid?.() || (stat2.mode & 511) !== mode)
|
|
1606
|
+
throw new RuntimeError("permission");
|
|
1607
|
+
return await fd.readFile();
|
|
1608
|
+
} finally {
|
|
1609
|
+
await fd.close();
|
|
1610
|
+
}
|
|
1611
|
+
}
|
|
1612
|
+
async function settleAll(work) {
|
|
1613
|
+
const failed = (await Promise.allSettled(work)).find((result) => result.status === "rejected");
|
|
1614
|
+
if (failed)
|
|
1615
|
+
throw failed.reason;
|
|
1616
|
+
}
|
|
1617
|
+
var RuntimeError, hash, missing, versionName, VERIFY_CONCURRENCY, statIdentity, RuntimeReader;
|
|
1499
1618
|
var init_runtimeReader = __esm({
|
|
1500
1619
|
"packages/shared/dist/runtimeReader.js"() {
|
|
1501
1620
|
"use strict";
|
|
@@ -1516,6 +1635,7 @@ var init_runtimeReader = __esm({
|
|
|
1516
1635
|
throw new RuntimeError("permission");
|
|
1517
1636
|
return v;
|
|
1518
1637
|
};
|
|
1638
|
+
VERIFY_CONCURRENCY = 16;
|
|
1519
1639
|
statIdentity = (stat2) => [stat2.dev, stat2.ino, stat2.mode, stat2.uid, stat2.size, stat2.mtimeMs, stat2.ctimeMs].join(":");
|
|
1520
1640
|
RuntimeReader = class _RuntimeReader {
|
|
1521
1641
|
run;
|
|
@@ -1634,12 +1754,23 @@ var init_runtimeReader = __esm({
|
|
|
1634
1754
|
throw new RuntimeError(error instanceof Error && error.message === "acl_permissions" ? "permission" : "acl_unavailable");
|
|
1635
1755
|
}
|
|
1636
1756
|
}
|
|
1637
|
-
|
|
1757
|
+
/**
|
|
1758
|
+
* `proven` (one verification's own set, POSIX only) holds directories this
|
|
1759
|
+
* verification has already inspected in full: their components are not
|
|
1760
|
+
* inspected again for every file beneath them, and directories proven here
|
|
1761
|
+
* are added to it.
|
|
1762
|
+
*/
|
|
1763
|
+
async inspect(path, directory = false, allowMissing = false, replacing = false, proven) {
|
|
1638
1764
|
const absolute = this.guardedPath(path);
|
|
1639
1765
|
const windowsPaths = [];
|
|
1640
|
-
|
|
1641
|
-
|
|
1766
|
+
const remembered = process.platform === "win32" ? void 0 : proven;
|
|
1767
|
+
const checkedDirectories = [];
|
|
1768
|
+
const parent = dirname4(absolute);
|
|
1769
|
+
let part = remembered?.has(parent) ? parent : parse(absolute).root;
|
|
1770
|
+
for (const name of absolute.slice(part.length).split(sep2).filter(Boolean)) {
|
|
1642
1771
|
part = join5(part, name);
|
|
1772
|
+
if (part !== absolute && remembered?.has(part))
|
|
1773
|
+
continue;
|
|
1643
1774
|
const stat2 = await lstat3(part).catch((e) => {
|
|
1644
1775
|
if (allowMissing && missing(e))
|
|
1645
1776
|
return null;
|
|
@@ -1680,7 +1811,12 @@ var init_runtimeReader = __esm({
|
|
|
1680
1811
|
windowsPaths.push(part);
|
|
1681
1812
|
} else if (stat2.uid !== process.getuid?.() || (stat2.mode & 63) !== 0)
|
|
1682
1813
|
throw new RuntimeError("permission");
|
|
1814
|
+
if (stat2.isDirectory())
|
|
1815
|
+
checkedDirectories.push(part);
|
|
1683
1816
|
}
|
|
1817
|
+
if (remembered)
|
|
1818
|
+
for (const checked of checkedDirectories)
|
|
1819
|
+
remembered.add(checked);
|
|
1684
1820
|
await this.audit(windowsPaths);
|
|
1685
1821
|
for (const part2 of windowsPaths) {
|
|
1686
1822
|
const verdict = this.windowsAudit.get(part2)?.verdict;
|
|
@@ -1701,8 +1837,8 @@ var init_runtimeReader = __esm({
|
|
|
1701
1837
|
this.windowsAudit.delete(absolute);
|
|
1702
1838
|
this.windowsStats.delete(absolute);
|
|
1703
1839
|
}
|
|
1704
|
-
async bytes(path) {
|
|
1705
|
-
await this.inspect(path);
|
|
1840
|
+
async bytes(path, proven) {
|
|
1841
|
+
await this.inspect(path, false, false, false, proven);
|
|
1706
1842
|
const fd = await open(path, constants2.O_RDONLY | (process.platform === "win32" ? 0 : constants2.O_NOFOLLOW));
|
|
1707
1843
|
try {
|
|
1708
1844
|
return await fd.readFile();
|
|
@@ -1774,36 +1910,43 @@ var init_runtimeReader = __esm({
|
|
|
1774
1910
|
if (process.platform === "win32")
|
|
1775
1911
|
await this.audit(Object.keys(m.files).map((name) => join5(directory, safePath(name))));
|
|
1776
1912
|
const actual = [];
|
|
1913
|
+
const proven = /* @__PURE__ */ new Set();
|
|
1914
|
+
const limit = limiter(process.platform === "win32" ? 1 : VERIFY_CONCURRENCY);
|
|
1777
1915
|
const walk = async (dir, prefix = "") => {
|
|
1778
|
-
await
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
const
|
|
1784
|
-
if (
|
|
1916
|
+
const entries = await limit(async () => {
|
|
1917
|
+
await this.inspect(dir, true, false, false, proven);
|
|
1918
|
+
return readdir(dir, { withFileTypes: true });
|
|
1919
|
+
});
|
|
1920
|
+
await settleAll(entries.map(async (entry) => {
|
|
1921
|
+
const key = prefix + entry.name;
|
|
1922
|
+
if (!prefix && entry.name === "manifest.json")
|
|
1923
|
+
return;
|
|
1924
|
+
const path = join5(dir, entry.name);
|
|
1925
|
+
if (entry.isDirectory())
|
|
1785
1926
|
await walk(path, key + "/");
|
|
1786
1927
|
else {
|
|
1787
|
-
|
|
1928
|
+
if (process.platform === "win32")
|
|
1929
|
+
await limit(() => this.inspect(path, false, false, false, proven));
|
|
1930
|
+
else if (!entry.isFile())
|
|
1931
|
+
throw new RuntimeError("permission");
|
|
1788
1932
|
actual.push(key);
|
|
1789
1933
|
}
|
|
1790
|
-
}
|
|
1934
|
+
}));
|
|
1791
1935
|
};
|
|
1792
1936
|
await walk(directory);
|
|
1793
1937
|
if (actual.sort().join("\n") !== Object.keys(m.files).sort().join("\n"))
|
|
1794
1938
|
throw new RuntimeError("digest_mismatch");
|
|
1795
|
-
|
|
1796
|
-
for (const [name, expected] of Object.entries(m.files)) {
|
|
1939
|
+
for (const expected of Object.values(m.files))
|
|
1797
1940
|
if (!expected || !/^[a-f0-9]{64}$/.test(expected.sha256) || !Number.isSafeInteger(expected.size) || expected.size < 0 || typeof expected.executable !== "boolean")
|
|
1798
1941
|
throw new RuntimeError("digest_mismatch");
|
|
1942
|
+
let total = 0;
|
|
1943
|
+
await settleAll(Object.entries(m.files).map(([name, expected]) => limit(async () => {
|
|
1799
1944
|
const path = join5(directory, safePath(name));
|
|
1800
|
-
const contents = await this.bytes(path);
|
|
1945
|
+
const contents = process.platform === "win32" ? await this.bytes(path, proven) : await ownedFileBytes(path, expected.executable ? 448 : 384);
|
|
1801
1946
|
if (hash(contents) !== expected.sha256 || contents.length !== expected.size)
|
|
1802
1947
|
throw new RuntimeError("digest_mismatch");
|
|
1803
|
-
if (process.platform !== "win32" && ((await lstat3(path)).mode & 511) !== (expected.executable ? 448 : 384))
|
|
1804
|
-
throw new RuntimeError("permission");
|
|
1805
1948
|
total += contents.length;
|
|
1806
|
-
}
|
|
1949
|
+
})));
|
|
1807
1950
|
if (total !== m.totalSize)
|
|
1808
1951
|
throw new RuntimeError("digest_mismatch");
|
|
1809
1952
|
if (m.signer) {
|
|
@@ -2791,6 +2934,8 @@ __export(hookRuntime_exports, {
|
|
|
2791
2934
|
GATE_OUTBOX_MAX_AGE_MS: () => GATE_OUTBOX_MAX_AGE_MS,
|
|
2792
2935
|
GATE_OUTBOX_MAX_EVENTS: () => GATE_OUTBOX_MAX_EVENTS,
|
|
2793
2936
|
GATE_OUTBOX_STRAY_MS: () => GATE_OUTBOX_STRAY_MS,
|
|
2937
|
+
HOOK_MISSES_HEADER: () => HOOK_MISSES_HEADER,
|
|
2938
|
+
HOOK_MISS_WINDOW_MS: () => HOOK_MISS_WINDOW_MS,
|
|
2794
2939
|
HOOK_STDIN_MAX_BYTES: () => HOOK_STDIN_MAX_BYTES,
|
|
2795
2940
|
HOOK_TRACE_ENV: () => HOOK_TRACE_ENV,
|
|
2796
2941
|
HOOK_TRACE_MAX_BYTES: () => HOOK_TRACE_MAX_BYTES,
|
|
@@ -2802,6 +2947,7 @@ __export(hookRuntime_exports, {
|
|
|
2802
2947
|
RELEASE_MINISIGN_PUBLIC_KEY: () => RELEASE_MINISIGN_PUBLIC_KEY,
|
|
2803
2948
|
RuntimeError: () => RuntimeError,
|
|
2804
2949
|
RuntimeReader: () => RuntimeReader,
|
|
2950
|
+
VERIFY_CONCURRENCY: () => VERIFY_CONCURRENCY,
|
|
2805
2951
|
aclRecords: () => aclRecords,
|
|
2806
2952
|
adoptHookConversation: () => adoptHookConversation,
|
|
2807
2953
|
appendHookTraceLine: () => appendHookTraceLine,
|
|
@@ -2818,6 +2964,8 @@ __export(hookRuntime_exports, {
|
|
|
2818
2964
|
findProjectIdentityDetailed: () => findProjectIdentityDetailed,
|
|
2819
2965
|
handoffProjectSetup: () => handoffProjectSetup,
|
|
2820
2966
|
hash: () => hash,
|
|
2967
|
+
hookMissesHeaders: () => hookMissesHeaders,
|
|
2968
|
+
hookMissesHeadersIfReady: () => hookMissesHeadersIfReady,
|
|
2821
2969
|
hookTraceDirectory: () => hookTraceDirectory,
|
|
2822
2970
|
hookTraceEnabled: () => hookTraceEnabled,
|
|
2823
2971
|
hookTraceFile: () => hookTraceFile,
|
|
@@ -2839,6 +2987,7 @@ __export(hookRuntime_exports, {
|
|
|
2839
2987
|
setupResponse: () => setupResponse,
|
|
2840
2988
|
startHookTrace: () => startHookTrace,
|
|
2841
2989
|
summarizeHookOutput: () => summarizeHookOutput,
|
|
2990
|
+
summarizeRecentHookCalls: () => summarizeRecentHookCalls,
|
|
2842
2991
|
takeGateEvents: () => takeGateEvents,
|
|
2843
2992
|
validHookSessionId: () => validHookSessionId,
|
|
2844
2993
|
verifyMinisign: () => verifyMinisign,
|
|
@@ -3043,6 +3192,8 @@ export {
|
|
|
3043
3192
|
GATE_OUTBOX_MAX_AGE_MS,
|
|
3044
3193
|
GATE_OUTBOX_MAX_EVENTS,
|
|
3045
3194
|
GATE_OUTBOX_STRAY_MS,
|
|
3195
|
+
HOOK_MISSES_HEADER,
|
|
3196
|
+
HOOK_MISS_WINDOW_MS,
|
|
3046
3197
|
HOOK_STDIN_MAX_BYTES,
|
|
3047
3198
|
HOOK_TRACE_ENV,
|
|
3048
3199
|
HOOK_TRACE_MAX_BYTES,
|
|
@@ -3054,6 +3205,7 @@ export {
|
|
|
3054
3205
|
RELEASE_MINISIGN_PUBLIC_KEY,
|
|
3055
3206
|
RuntimeError,
|
|
3056
3207
|
RuntimeReader,
|
|
3208
|
+
VERIFY_CONCURRENCY,
|
|
3057
3209
|
aclRecords,
|
|
3058
3210
|
adoptHookConversation,
|
|
3059
3211
|
appendHookTraceLine,
|
|
@@ -3070,6 +3222,8 @@ export {
|
|
|
3070
3222
|
findProjectIdentityDetailed,
|
|
3071
3223
|
handoffProjectSetup,
|
|
3072
3224
|
hash,
|
|
3225
|
+
hookMissesHeaders,
|
|
3226
|
+
hookMissesHeadersIfReady,
|
|
3073
3227
|
hookTraceDirectory,
|
|
3074
3228
|
hookTraceEnabled,
|
|
3075
3229
|
hookTraceFile,
|
|
@@ -3091,6 +3245,7 @@ export {
|
|
|
3091
3245
|
setupResponse,
|
|
3092
3246
|
startHookTrace,
|
|
3093
3247
|
summarizeHookOutput,
|
|
3248
|
+
summarizeRecentHookCalls,
|
|
3094
3249
|
takeGateEvents,
|
|
3095
3250
|
validHookSessionId,
|
|
3096
3251
|
verifyMinisign,
|
package/dist/runtime/store.js
CHANGED
|
@@ -446,7 +446,7 @@ var init_secretPatterns = __esm({
|
|
|
446
446
|
});
|
|
447
447
|
|
|
448
448
|
// packages/shared/dist/hookTrace.js
|
|
449
|
-
var HOOK_TRACE_MAX_BYTES;
|
|
449
|
+
var HOOK_TRACE_MAX_BYTES, HOOK_MISS_WINDOW_MS, HOOK_MISS_TAIL_BYTES;
|
|
450
450
|
var init_hookTrace = __esm({
|
|
451
451
|
"packages/shared/dist/hookTrace.js"() {
|
|
452
452
|
"use strict";
|
|
@@ -454,6 +454,8 @@ var init_hookTrace = __esm({
|
|
|
454
454
|
init_runtimeSigners();
|
|
455
455
|
init_secretPatterns();
|
|
456
456
|
HOOK_TRACE_MAX_BYTES = 2 * 1024 * 1024;
|
|
457
|
+
HOOK_MISS_WINDOW_MS = 30 * 60 * 1e3;
|
|
458
|
+
HOOK_MISS_TAIL_BYTES = 64 * 1024;
|
|
457
459
|
}
|
|
458
460
|
});
|
|
459
461
|
|
|
@@ -467,7 +469,40 @@ function safePath(path) {
|
|
|
467
469
|
throw new RuntimeError("permission");
|
|
468
470
|
return path;
|
|
469
471
|
}
|
|
470
|
-
|
|
472
|
+
function limiter(limit) {
|
|
473
|
+
let active = 0;
|
|
474
|
+
const waiting = [];
|
|
475
|
+
return async (work) => {
|
|
476
|
+
if (active >= limit)
|
|
477
|
+
await new Promise((release) => waiting.push(release));
|
|
478
|
+
active += 1;
|
|
479
|
+
try {
|
|
480
|
+
return await work();
|
|
481
|
+
} finally {
|
|
482
|
+
active -= 1;
|
|
483
|
+
waiting.shift()?.();
|
|
484
|
+
}
|
|
485
|
+
};
|
|
486
|
+
}
|
|
487
|
+
async function ownedFileBytes(path, mode) {
|
|
488
|
+
const fd = await open(path, constants.O_RDONLY | constants.O_NOFOLLOW).catch((error) => {
|
|
489
|
+
throw error.code === "ELOOP" ? new RuntimeError("permission") : error;
|
|
490
|
+
});
|
|
491
|
+
try {
|
|
492
|
+
const stat = await fd.stat();
|
|
493
|
+
if (!stat.isFile() || stat.uid !== process.getuid?.() || (stat.mode & 511) !== mode)
|
|
494
|
+
throw new RuntimeError("permission");
|
|
495
|
+
return await fd.readFile();
|
|
496
|
+
} finally {
|
|
497
|
+
await fd.close();
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
async function settleAll(work) {
|
|
501
|
+
const failed = (await Promise.allSettled(work)).find((result) => result.status === "rejected");
|
|
502
|
+
if (failed)
|
|
503
|
+
throw failed.reason;
|
|
504
|
+
}
|
|
505
|
+
var RuntimeError, hash, missing, versionName, VERIFY_CONCURRENCY, statIdentity, RuntimeReader;
|
|
471
506
|
var init_runtimeReader = __esm({
|
|
472
507
|
"packages/shared/dist/runtimeReader.js"() {
|
|
473
508
|
"use strict";
|
|
@@ -488,6 +523,7 @@ var init_runtimeReader = __esm({
|
|
|
488
523
|
throw new RuntimeError("permission");
|
|
489
524
|
return v;
|
|
490
525
|
};
|
|
526
|
+
VERIFY_CONCURRENCY = 16;
|
|
491
527
|
statIdentity = (stat) => [stat.dev, stat.ino, stat.mode, stat.uid, stat.size, stat.mtimeMs, stat.ctimeMs].join(":");
|
|
492
528
|
RuntimeReader = class _RuntimeReader {
|
|
493
529
|
run;
|
|
@@ -606,12 +642,23 @@ var init_runtimeReader = __esm({
|
|
|
606
642
|
throw new RuntimeError(error instanceof Error && error.message === "acl_permissions" ? "permission" : "acl_unavailable");
|
|
607
643
|
}
|
|
608
644
|
}
|
|
609
|
-
|
|
645
|
+
/**
|
|
646
|
+
* `proven` (one verification's own set, POSIX only) holds directories this
|
|
647
|
+
* verification has already inspected in full: their components are not
|
|
648
|
+
* inspected again for every file beneath them, and directories proven here
|
|
649
|
+
* are added to it.
|
|
650
|
+
*/
|
|
651
|
+
async inspect(path, directory = false, allowMissing = false, replacing = false, proven) {
|
|
610
652
|
const absolute = this.guardedPath(path);
|
|
611
653
|
const windowsPaths = [];
|
|
612
|
-
|
|
613
|
-
|
|
654
|
+
const remembered = process.platform === "win32" ? void 0 : proven;
|
|
655
|
+
const checkedDirectories = [];
|
|
656
|
+
const parent = dirname2(absolute);
|
|
657
|
+
let part = remembered?.has(parent) ? parent : parse(absolute).root;
|
|
658
|
+
for (const name of absolute.slice(part.length).split(sep2).filter(Boolean)) {
|
|
614
659
|
part = join2(part, name);
|
|
660
|
+
if (part !== absolute && remembered?.has(part))
|
|
661
|
+
continue;
|
|
615
662
|
const stat = await lstat(part).catch((e) => {
|
|
616
663
|
if (allowMissing && missing(e))
|
|
617
664
|
return null;
|
|
@@ -652,7 +699,12 @@ var init_runtimeReader = __esm({
|
|
|
652
699
|
windowsPaths.push(part);
|
|
653
700
|
} else if (stat.uid !== process.getuid?.() || (stat.mode & 63) !== 0)
|
|
654
701
|
throw new RuntimeError("permission");
|
|
702
|
+
if (stat.isDirectory())
|
|
703
|
+
checkedDirectories.push(part);
|
|
655
704
|
}
|
|
705
|
+
if (remembered)
|
|
706
|
+
for (const checked of checkedDirectories)
|
|
707
|
+
remembered.add(checked);
|
|
656
708
|
await this.audit(windowsPaths);
|
|
657
709
|
for (const part2 of windowsPaths) {
|
|
658
710
|
const verdict = this.windowsAudit.get(part2)?.verdict;
|
|
@@ -673,8 +725,8 @@ var init_runtimeReader = __esm({
|
|
|
673
725
|
this.windowsAudit.delete(absolute);
|
|
674
726
|
this.windowsStats.delete(absolute);
|
|
675
727
|
}
|
|
676
|
-
async bytes(path) {
|
|
677
|
-
await this.inspect(path);
|
|
728
|
+
async bytes(path, proven) {
|
|
729
|
+
await this.inspect(path, false, false, false, proven);
|
|
678
730
|
const fd = await open(path, constants.O_RDONLY | (process.platform === "win32" ? 0 : constants.O_NOFOLLOW));
|
|
679
731
|
try {
|
|
680
732
|
return await fd.readFile();
|
|
@@ -746,36 +798,43 @@ var init_runtimeReader = __esm({
|
|
|
746
798
|
if (process.platform === "win32")
|
|
747
799
|
await this.audit(Object.keys(m.files).map((name) => join2(directory, safePath(name))));
|
|
748
800
|
const actual = [];
|
|
801
|
+
const proven = /* @__PURE__ */ new Set();
|
|
802
|
+
const limit = limiter(process.platform === "win32" ? 1 : VERIFY_CONCURRENCY);
|
|
749
803
|
const walk = async (dir, prefix = "") => {
|
|
750
|
-
await
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
const
|
|
756
|
-
if (
|
|
804
|
+
const entries = await limit(async () => {
|
|
805
|
+
await this.inspect(dir, true, false, false, proven);
|
|
806
|
+
return readdir(dir, { withFileTypes: true });
|
|
807
|
+
});
|
|
808
|
+
await settleAll(entries.map(async (entry) => {
|
|
809
|
+
const key = prefix + entry.name;
|
|
810
|
+
if (!prefix && entry.name === "manifest.json")
|
|
811
|
+
return;
|
|
812
|
+
const path = join2(dir, entry.name);
|
|
813
|
+
if (entry.isDirectory())
|
|
757
814
|
await walk(path, key + "/");
|
|
758
815
|
else {
|
|
759
|
-
|
|
816
|
+
if (process.platform === "win32")
|
|
817
|
+
await limit(() => this.inspect(path, false, false, false, proven));
|
|
818
|
+
else if (!entry.isFile())
|
|
819
|
+
throw new RuntimeError("permission");
|
|
760
820
|
actual.push(key);
|
|
761
821
|
}
|
|
762
|
-
}
|
|
822
|
+
}));
|
|
763
823
|
};
|
|
764
824
|
await walk(directory);
|
|
765
825
|
if (actual.sort().join("\n") !== Object.keys(m.files).sort().join("\n"))
|
|
766
826
|
throw new RuntimeError("digest_mismatch");
|
|
767
|
-
|
|
768
|
-
for (const [name, expected] of Object.entries(m.files)) {
|
|
827
|
+
for (const expected of Object.values(m.files))
|
|
769
828
|
if (!expected || !/^[a-f0-9]{64}$/.test(expected.sha256) || !Number.isSafeInteger(expected.size) || expected.size < 0 || typeof expected.executable !== "boolean")
|
|
770
829
|
throw new RuntimeError("digest_mismatch");
|
|
830
|
+
let total = 0;
|
|
831
|
+
await settleAll(Object.entries(m.files).map(([name, expected]) => limit(async () => {
|
|
771
832
|
const path = join2(directory, safePath(name));
|
|
772
|
-
const contents = await this.bytes(path);
|
|
833
|
+
const contents = process.platform === "win32" ? await this.bytes(path, proven) : await ownedFileBytes(path, expected.executable ? 448 : 384);
|
|
773
834
|
if (hash(contents) !== expected.sha256 || contents.length !== expected.size)
|
|
774
835
|
throw new RuntimeError("digest_mismatch");
|
|
775
|
-
if (process.platform !== "win32" && ((await lstat(path)).mode & 511) !== (expected.executable ? 448 : 384))
|
|
776
|
-
throw new RuntimeError("permission");
|
|
777
836
|
total += contents.length;
|
|
778
|
-
}
|
|
837
|
+
})));
|
|
779
838
|
if (total !== m.totalSize)
|
|
780
839
|
throw new RuntimeError("digest_mismatch");
|
|
781
840
|
if (m.signer) {
|
|
@@ -43,6 +43,17 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
43
43
|
mod
|
|
44
44
|
));
|
|
45
45
|
|
|
46
|
+
// packages/shared/dist/secretPatterns.js
|
|
47
|
+
var SECRET_LABEL, SECRET_LABEL_RE, LABELED_VALUE_RE;
|
|
48
|
+
var init_secretPatterns = __esm({
|
|
49
|
+
"packages/shared/dist/secretPatterns.js"() {
|
|
50
|
+
"use strict";
|
|
51
|
+
SECRET_LABEL = String.raw`[\w$-]*(?:api[_-]?key|secret|token|password|credential|auth)|aws_secret_access_key`;
|
|
52
|
+
SECRET_LABEL_RE = new RegExp(`^(?:${SECRET_LABEL}|MYSQL_PWD|SSHPASS)$`, "i");
|
|
53
|
+
LABELED_VALUE_RE = new RegExp(String.raw`(?<![\w$-])((["']?)(?:${SECRET_LABEL})\2\s*[:=]\s*)(?=\S)`, "gi");
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
|
|
46
57
|
// node_modules/ignore/index.js
|
|
47
58
|
var require_ignore = __commonJS({
|
|
48
59
|
"node_modules/ignore/index.js"(exports, module2) {
|
|
@@ -885,17 +896,6 @@ var require_ignore = __commonJS({
|
|
|
885
896
|
}
|
|
886
897
|
});
|
|
887
898
|
|
|
888
|
-
// packages/shared/dist/secretPatterns.js
|
|
889
|
-
var SECRET_LABEL, SECRET_LABEL_RE, LABELED_VALUE_RE;
|
|
890
|
-
var init_secretPatterns = __esm({
|
|
891
|
-
"packages/shared/dist/secretPatterns.js"() {
|
|
892
|
-
"use strict";
|
|
893
|
-
SECRET_LABEL = String.raw`[\w$-]*(?:api[_-]?key|secret|token|password|credential|auth)|aws_secret_access_key`;
|
|
894
|
-
SECRET_LABEL_RE = new RegExp(`^(?:${SECRET_LABEL}|MYSQL_PWD|SSHPASS)$`, "i");
|
|
895
|
-
LABELED_VALUE_RE = new RegExp(String.raw`(?<![\w$-])((["']?)(?:${SECRET_LABEL})\2\s*[:=]\s*)(?=\S)`, "gi");
|
|
896
|
-
}
|
|
897
|
-
});
|
|
898
|
-
|
|
899
899
|
// packages/shared/dist/protectedPaths.js
|
|
900
900
|
var init_protectedPaths = __esm({
|
|
901
901
|
"packages/shared/dist/protectedPaths.js"() {
|
|
@@ -1016,7 +1016,7 @@ var init_repositoryRoot = __esm({
|
|
|
1016
1016
|
});
|
|
1017
1017
|
|
|
1018
1018
|
// packages/shared/dist/hookTrace.js
|
|
1019
|
-
var HOOK_TRACE_MAX_BYTES;
|
|
1019
|
+
var HOOK_TRACE_MAX_BYTES, HOOK_MISS_WINDOW_MS, HOOK_MISS_TAIL_BYTES;
|
|
1020
1020
|
var init_hookTrace = __esm({
|
|
1021
1021
|
"packages/shared/dist/hookTrace.js"() {
|
|
1022
1022
|
"use strict";
|
|
@@ -1024,6 +1024,8 @@ var init_hookTrace = __esm({
|
|
|
1024
1024
|
init_runtimeSigners();
|
|
1025
1025
|
init_secretPatterns();
|
|
1026
1026
|
HOOK_TRACE_MAX_BYTES = 2 * 1024 * 1024;
|
|
1027
|
+
HOOK_MISS_WINDOW_MS = 30 * 60 * 1e3;
|
|
1028
|
+
HOOK_MISS_TAIL_BYTES = 64 * 1024;
|
|
1027
1029
|
}
|
|
1028
1030
|
});
|
|
1029
1031
|
|
|
@@ -2736,9 +2738,6 @@ function getMcpInstructions() {
|
|
|
2736
2738
|
}
|
|
2737
2739
|
var MCP_INSTRUCTIONS = getMcpInstructions();
|
|
2738
2740
|
|
|
2739
|
-
// packages/shared/dist/codeScanner.js
|
|
2740
|
-
var import_ignore = __toESM(require_ignore(), 1);
|
|
2741
|
-
|
|
2742
2741
|
// node_modules/web-tree-sitter/web-tree-sitter.js
|
|
2743
2742
|
var __defProp2 = Object.defineProperty;
|
|
2744
2743
|
var __name = (target, value) => __defProp2(target, "name", { value, configurable: true });
|
|
@@ -6787,9 +6786,6 @@ import { dirname, extname, join } from "node:path";
|
|
|
6787
6786
|
import { fileURLToPath } from "node:url";
|
|
6788
6787
|
var WASM_DIR = join(dirname(fileURLToPath(import.meta.url)), "..", "..", "wasm");
|
|
6789
6788
|
|
|
6790
|
-
// packages/shared/dist/ast/astChunker.js
|
|
6791
|
-
var MAX_AST_PARSE_BYTES = 2 * 1024 * 1024;
|
|
6792
|
-
|
|
6793
6789
|
// packages/shared/dist/redactCredentials.js
|
|
6794
6790
|
var REDACTED = "<redacted credential>";
|
|
6795
6791
|
var MAX_PEM_BODY_LENGTH = 8 * 1024;
|
|
@@ -7049,11 +7045,15 @@ var PATTERNS = [
|
|
|
7049
7045
|
|
|
7050
7046
|
// packages/shared/dist/sourceRedaction.js
|
|
7051
7047
|
init_secretPatterns();
|
|
7048
|
+
var MAX_SOURCE_REDACTION_BYTES = 10 * 1024 * 1024;
|
|
7052
7049
|
|
|
7053
|
-
// packages/shared/dist/
|
|
7050
|
+
// packages/shared/dist/ast/astChunker.js
|
|
7051
|
+
var MAX_AST_PARSE_BYTES = 2 * 1024 * 1024;
|
|
7052
|
+
|
|
7053
|
+
// packages/shared/dist/fileSelection.js
|
|
7054
|
+
var import_ignore = __toESM(require_ignore(), 1);
|
|
7054
7055
|
init_protectedPaths();
|
|
7055
7056
|
init_projectIdentityFile();
|
|
7056
|
-
var MAX_SCANNED_FILE_BYTES = 10 * 1024 * 1024;
|
|
7057
7057
|
var BUILT_IN_IGNORE_DIRS = [
|
|
7058
7058
|
// JS / web
|
|
7059
7059
|
"node_modules",
|
|
@@ -7210,22 +7210,35 @@ var DEFAULT_INCLUDE_EXTENSIONS = [
|
|
|
7210
7210
|
".nix",
|
|
7211
7211
|
".bzl"
|
|
7212
7212
|
];
|
|
7213
|
+
var BUILT_IN_IGNORE_DIR_SET = new Set(BUILT_IN_IGNORE_DIRS);
|
|
7214
|
+
var DEFAULT_IGNORE_PATTERNS = [
|
|
7215
|
+
...BUILT_IN_IGNORE_DIRS,
|
|
7216
|
+
...BUILT_IN_IGNORE_FILE_PATTERNS
|
|
7217
|
+
];
|
|
7218
|
+
|
|
7219
|
+
// packages/shared/dist/codeScanner.js
|
|
7220
|
+
var MAX_SCANNED_FILE_BYTES = 10 * 1024 * 1024;
|
|
7213
7221
|
var DEFAULT_OPTIONS = {
|
|
7214
7222
|
maxChunkSize: 8e3,
|
|
7215
7223
|
// ~2000 tokens
|
|
7216
7224
|
minChunkSize: 100,
|
|
7217
|
-
ignorePatterns: [...
|
|
7225
|
+
ignorePatterns: [...DEFAULT_IGNORE_PATTERNS],
|
|
7218
7226
|
includeExtensions: [...DEFAULT_INCLUDE_EXTENSIONS],
|
|
7219
7227
|
maxAstParseBytes: MAX_AST_PARSE_BYTES,
|
|
7220
7228
|
protectedPaths: []
|
|
7221
7229
|
};
|
|
7222
|
-
var BUILT_IN_IGNORE_DIR_SET = new Set(BUILT_IN_IGNORE_DIRS);
|
|
7223
7230
|
|
|
7224
7231
|
// packages/shared/dist/indexJudge.js
|
|
7225
7232
|
var import_ignore2 = __toESM(require_ignore(), 1);
|
|
7226
7233
|
|
|
7227
7234
|
// packages/shared/dist/index.js
|
|
7228
7235
|
init_secretPatterns();
|
|
7236
|
+
|
|
7237
|
+
// packages/shared/dist/sourceRedactionPool.js
|
|
7238
|
+
var MB = 1024 * 1024;
|
|
7239
|
+
var LARGE_FILE_BYTES = 1 * MB;
|
|
7240
|
+
|
|
7241
|
+
// packages/shared/dist/index.js
|
|
7229
7242
|
init_hookTimeouts();
|
|
7230
7243
|
|
|
7231
7244
|
// packages/shared/dist/jitDeliveryAck.js
|