@node9/proxy 2.49.0 → 2.50.0
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-main.js +875 -465
- package/dist/dashboard.mjs +72 -27
- package/dist/hook.js +20 -13
- package/dist/index.js +7 -4
- package/dist/index.mjs +7 -4
- package/dist/scan-ink.mjs +4 -3
- package/package.json +2 -2
package/dist/cli-main.js
CHANGED
|
@@ -520,6 +520,9 @@ function levelChecks(mode) {
|
|
|
520
520
|
function levelPackageSignals(mode) {
|
|
521
521
|
return levelOf(mode) === "soft" ? { newPackage: "off", installScript: "off" } : void 0;
|
|
522
522
|
}
|
|
523
|
+
function isAsiId(v) {
|
|
524
|
+
return typeof v === "string" && Object.prototype.hasOwnProperty.call(ASI, v);
|
|
525
|
+
}
|
|
523
526
|
function packRowOwasp(id, shield) {
|
|
524
527
|
return PACK_RULE_OWASP[id] ?? PACK_SHIELD_OWASP[shield];
|
|
525
528
|
}
|
|
@@ -542,12 +545,13 @@ function packRows() {
|
|
|
542
545
|
if (!rule.name || SHIELD_RULES_FOLDED_INTO_PRODUCT[rule.name]) continue;
|
|
543
546
|
const id = packRowId(shield.name, rule.name);
|
|
544
547
|
if (!id) continue;
|
|
545
|
-
const owasp = packRowOwasp(id, shield.name);
|
|
546
|
-
if (!owasp) throw new Error(`pack row ${id} has no OWASP risk: add the shield to owasp.ts`);
|
|
547
548
|
rows.push({
|
|
548
549
|
id,
|
|
549
550
|
group: "commands",
|
|
550
|
-
|
|
551
|
+
// A shield missing from the table falls back to tool misuse instead of
|
|
552
|
+
// throwing here: this module loads on every hook call, and a mapping
|
|
553
|
+
// omission must fail a test (owasp.spec.ts), never the gate.
|
|
554
|
+
owasp: packRowOwasp(id, shield.name) ?? "ASI02",
|
|
551
555
|
title: rule.name.replace(SHIELD_RULE_NAME, "$3").replace(/-/g, " "),
|
|
552
556
|
catches: rule.description ?? rule.reason ?? "",
|
|
553
557
|
values: ALL,
|
|
@@ -19924,8 +19928,8 @@ var init_audit = __esm({
|
|
|
19924
19928
|
// src/config-schema.ts
|
|
19925
19929
|
function formatIssues(issues) {
|
|
19926
19930
|
const lines = issues.map((issue) => {
|
|
19927
|
-
const
|
|
19928
|
-
return ` \u2022 ${
|
|
19931
|
+
const path114 = issue.path.length > 0 ? issue.path.map(String).join(".") : "root";
|
|
19932
|
+
return ` \u2022 ${path114}: ${issue.message}`;
|
|
19929
19933
|
});
|
|
19930
19934
|
return `Invalid config:
|
|
19931
19935
|
${lines.join("\n")}`;
|
|
@@ -19938,9 +19942,9 @@ function prunePaths(root, paths) {
|
|
|
19938
19942
|
const yi = y[y.length - 1];
|
|
19939
19943
|
return typeof xi === "number" && typeof yi === "number" ? yi - xi : 0;
|
|
19940
19944
|
});
|
|
19941
|
-
for (const
|
|
19945
|
+
for (const path114 of ordered) {
|
|
19942
19946
|
let cur = root;
|
|
19943
|
-
for (const key of
|
|
19947
|
+
for (const key of path114.slice(0, -1)) {
|
|
19944
19948
|
if (cur === null || typeof cur !== "object") {
|
|
19945
19949
|
cur = void 0;
|
|
19946
19950
|
break;
|
|
@@ -19948,7 +19952,7 @@ function prunePaths(root, paths) {
|
|
|
19948
19952
|
cur = cur[key];
|
|
19949
19953
|
}
|
|
19950
19954
|
if (cur === null || typeof cur !== "object") continue;
|
|
19951
|
-
const last =
|
|
19955
|
+
const last = path114[path114.length - 1];
|
|
19952
19956
|
if (Array.isArray(cur)) {
|
|
19953
19957
|
const i = Number(last);
|
|
19954
19958
|
if (Number.isInteger(i) && i >= 0 && i < cur.length) {
|
|
@@ -19984,7 +19988,7 @@ function sanitizeConfig(raw) {
|
|
|
19984
19988
|
return issue.keys.map((k) => [...at, k]);
|
|
19985
19989
|
}
|
|
19986
19990
|
return [at.slice(0, -level || void 0)];
|
|
19987
|
-
}).filter((
|
|
19991
|
+
}).filter((path114) => path114.length > 0);
|
|
19988
19992
|
if (paths.length === 0 || !prunePaths(working, paths)) break;
|
|
19989
19993
|
}
|
|
19990
19994
|
if (ConfigFileSchema.safeParse(working).success) break;
|
|
@@ -21578,13 +21582,13 @@ function getConfig(cwd) {
|
|
|
21578
21582
|
}
|
|
21579
21583
|
if (Array.isArray(mc.jailPaths)) {
|
|
21580
21584
|
for (const jp of mc.jailPaths) {
|
|
21581
|
-
const
|
|
21582
|
-
if (!
|
|
21585
|
+
const path114 = typeof jp?.path === "string" ? jp.path.trim() : "";
|
|
21586
|
+
if (!path114) continue;
|
|
21583
21587
|
const verdict = jp?.verdict === "review" ? "review" : "block";
|
|
21584
|
-
for (const r of pathRules(
|
|
21588
|
+
for (const r of pathRules(path114, verdict, "org-managed jail")) {
|
|
21585
21589
|
mergedPolicy.smartRules.push({ ...r, name: `org:${r.name}` });
|
|
21586
21590
|
}
|
|
21587
|
-
mergedPolicy.managedJailPaths.push({ path:
|
|
21591
|
+
mergedPolicy.managedJailPaths.push({ path: path114, verdict });
|
|
21588
21592
|
}
|
|
21589
21593
|
}
|
|
21590
21594
|
if (Array.isArray(mc.trustedHosts)) {
|
|
@@ -28457,7 +28461,9 @@ async function _authorizeHeadlessCore(toolName, args, metaArg, options) {
|
|
|
28457
28461
|
systemAccessHandled: !isManual && fileAccess.handledPaths.has(filePath)
|
|
28458
28462
|
}) : null) ?? argumentScan(),
|
|
28459
28463
|
pii: () => detectArgsPii(args),
|
|
28460
|
-
packageCheck: () => packageCheck?.enabled && !isManual ? runPackageCheck(toolName, args, packageCheck, options?.cwd, {
|
|
28464
|
+
packageCheck: () => packageCheck?.enabled && !isManual ? runPackageCheck(toolName, args, packageCheck, options?.cwd, {
|
|
28465
|
+
offline: !!forecast && forecast.onlinePackages !== true
|
|
28466
|
+
}) : Promise.resolve(null)
|
|
28461
28467
|
});
|
|
28462
28468
|
const dlpMatch = gates.stop?.dlpMatch ?? gates.reviews.dlp ?? null;
|
|
28463
28469
|
if (dlpMatch) {
|
|
@@ -34065,7 +34071,8 @@ async function forecastDecision(toolName, args, meta, opts = {}) {
|
|
|
34065
34071
|
session,
|
|
34066
34072
|
config,
|
|
34067
34073
|
unknown: /* @__PURE__ */ new Set(),
|
|
34068
|
-
now: opts.at ?? Date.now()
|
|
34074
|
+
now: opts.at ?? Date.now(),
|
|
34075
|
+
...opts.onlinePackages && { onlinePackages: true }
|
|
34069
34076
|
};
|
|
34070
34077
|
const result = await runForecast(
|
|
34071
34078
|
run,
|
|
@@ -34160,6 +34167,20 @@ var init_forecast = __esm({
|
|
|
34160
34167
|
}
|
|
34161
34168
|
});
|
|
34162
34169
|
|
|
34170
|
+
// src/exposure/shell-fetch.ts
|
|
34171
|
+
function shellFetch(tool, rawInput) {
|
|
34172
|
+
if (tool !== "Bash" && tool !== "bash") return null;
|
|
34173
|
+
const cmd = rawInput && typeof rawInput === "object" && !Array.isArray(rawInput) ? rawInput.command : void 0;
|
|
34174
|
+
return typeof cmd === "string" && cmd.length > 0 ? classifyShellExposure(cmd) : null;
|
|
34175
|
+
}
|
|
34176
|
+
var init_shell_fetch = __esm({
|
|
34177
|
+
"src/exposure/shell-fetch.ts"() {
|
|
34178
|
+
"use strict";
|
|
34179
|
+
init_cjs_shims();
|
|
34180
|
+
init_dist();
|
|
34181
|
+
}
|
|
34182
|
+
});
|
|
34183
|
+
|
|
34163
34184
|
// src/version.ts
|
|
34164
34185
|
function readVersion() {
|
|
34165
34186
|
let dir2 = __dirname;
|
|
@@ -34460,6 +34481,8 @@ var init_scan_judge = __esm({
|
|
|
34460
34481
|
init_forecast();
|
|
34461
34482
|
init_forecast_state();
|
|
34462
34483
|
init_roles();
|
|
34484
|
+
init_shell_fetch();
|
|
34485
|
+
init_dist();
|
|
34463
34486
|
init_scan_cache();
|
|
34464
34487
|
init_dlp();
|
|
34465
34488
|
import_fs45 = __toESM(require("fs"));
|
|
@@ -34534,16 +34557,26 @@ var init_scan_judge = __esm({
|
|
|
34534
34557
|
this.session(sessionId).noteOutputSecret(patternName, clockOf(timestamp2));
|
|
34535
34558
|
}
|
|
34536
34559
|
/** A tool that brings outside content returned something. */
|
|
34537
|
-
|
|
34560
|
+
/**
|
|
34561
|
+
* A tool result reached the session. A source read marks it exposed, as the
|
|
34562
|
+
* PostToolUse hook does (log.ts): a source tool, or a shell command that
|
|
34563
|
+
* fetches outside content (`gh issue view`). `read.output` is the result's
|
|
34564
|
+
* text: the destinations it names are recorded as the hook records them.
|
|
34565
|
+
*/
|
|
34566
|
+
noteToolResult(sessionId, toolName, timestamp2, cwd, read3 = {}) {
|
|
34538
34567
|
const policy = this.configFor(cwd).policy.untrustedContent;
|
|
34539
34568
|
if (!policy?.enabled) return;
|
|
34540
|
-
|
|
34569
|
+
const shell = shellFetch(toolName, read3.input);
|
|
34570
|
+
if (!toolRole(toolName, policy).source && !shell?.fetches) return;
|
|
34541
34571
|
const mcp = /^mcp__([^_]+(?:_[^_]+)*)__/.exec(toolName);
|
|
34542
|
-
this.session(sessionId).noteOutsideContent(
|
|
34543
|
-
|
|
34544
|
-
|
|
34545
|
-
|
|
34546
|
-
|
|
34572
|
+
this.session(sessionId).noteOutsideContent(
|
|
34573
|
+
{
|
|
34574
|
+
tool: toolName,
|
|
34575
|
+
...mcp && { server: mcp[1] },
|
|
34576
|
+
at: clockOf(timestamp2)
|
|
34577
|
+
},
|
|
34578
|
+
read3.output ? extractContentDestinations(read3.output) : []
|
|
34579
|
+
);
|
|
34547
34580
|
}
|
|
34548
34581
|
async judge(call, result, dedup) {
|
|
34549
34582
|
const config = this.configFor(call.cwd);
|
|
@@ -37034,8 +37067,8 @@ function isOfficialInstaller(u) {
|
|
|
37034
37067
|
if (u.username || u.password) return false;
|
|
37035
37068
|
const host2 = u.hostname.toLowerCase().replace(/^www\./, "");
|
|
37036
37069
|
if (OFFICIAL_HOSTS.has(host2)) return true;
|
|
37037
|
-
const
|
|
37038
|
-
return !!
|
|
37070
|
+
const path114 = OFFICIAL_PATHS[host2];
|
|
37071
|
+
return !!path114 && path114.test(u.pathname);
|
|
37039
37072
|
}
|
|
37040
37073
|
function onlyOfficialInstaller(s) {
|
|
37041
37074
|
const urls = s.match(URL_RE3);
|
|
@@ -37181,21 +37214,21 @@ function appSkillDirsOf(paths, skillDirs) {
|
|
|
37181
37214
|
}
|
|
37182
37215
|
return apps;
|
|
37183
37216
|
}
|
|
37184
|
-
function isSkillSupportFile(
|
|
37185
|
-
if (!
|
|
37186
|
-
for (let d =
|
|
37187
|
-
const dir2 =
|
|
37217
|
+
function isSkillSupportFile(path114, skillDirs, appDirs) {
|
|
37218
|
+
if (!path114.endsWith(".md") || /(^|\/)[Ss][Kk][Ii][Ll][Ll]\.md$/.test(path114)) return false;
|
|
37219
|
+
for (let d = path114.lastIndexOf("/"); d > 0; d = path114.lastIndexOf("/", d - 1)) {
|
|
37220
|
+
const dir2 = path114.slice(0, d);
|
|
37188
37221
|
if (!skillDirs.has(dir2)) continue;
|
|
37189
|
-
return !appDirs?.has(dir2) || SKILL_LAYOUT_RE.test(
|
|
37222
|
+
return !appDirs?.has(dir2) || SKILL_LAYOUT_RE.test(path114.slice(d + 1));
|
|
37190
37223
|
}
|
|
37191
37224
|
return false;
|
|
37192
37225
|
}
|
|
37193
|
-
function isAppDoc(
|
|
37194
|
-
if (!
|
|
37195
|
-
for (let d =
|
|
37196
|
-
const dir2 =
|
|
37226
|
+
function isAppDoc(path114, skillDirs, appDirs) {
|
|
37227
|
+
if (!path114.endsWith(".md") || INSTRUCTION_FILE_RE.test(path114)) return false;
|
|
37228
|
+
for (let d = path114.lastIndexOf("/"); d > 0; d = path114.lastIndexOf("/", d - 1)) {
|
|
37229
|
+
const dir2 = path114.slice(0, d);
|
|
37197
37230
|
if (!skillDirs.has(dir2)) continue;
|
|
37198
|
-
return appDirs.has(dir2) && !SKILL_LAYOUT_RE.test(
|
|
37231
|
+
return appDirs.has(dir2) && !SKILL_LAYOUT_RE.test(path114.slice(d + 1));
|
|
37199
37232
|
}
|
|
37200
37233
|
return false;
|
|
37201
37234
|
}
|
|
@@ -37217,20 +37250,20 @@ function namedDocs(dir2, skillMd) {
|
|
|
37217
37250
|
}
|
|
37218
37251
|
return out;
|
|
37219
37252
|
}
|
|
37220
|
-
function isHookScript(
|
|
37221
|
-
return /(^|\/)\.claude\/hooks\/.+/.test(
|
|
37253
|
+
function isHookScript(path114) {
|
|
37254
|
+
return /(^|\/)\.claude\/hooks\/.+/.test(path114) && SCRIPT_EXT_RE.test(path114);
|
|
37222
37255
|
}
|
|
37223
|
-
function isSkillScript(
|
|
37224
|
-
if (!SCRIPT_EXT_RE.test(
|
|
37225
|
-
for (let d =
|
|
37226
|
-
if (!skillDirs.has(
|
|
37227
|
-
const rel =
|
|
37256
|
+
function isSkillScript(path114, skillDirs) {
|
|
37257
|
+
if (!SCRIPT_EXT_RE.test(path114)) return false;
|
|
37258
|
+
for (let d = path114.lastIndexOf("/"); d > 0; d = path114.lastIndexOf("/", d - 1)) {
|
|
37259
|
+
if (!skillDirs.has(path114.slice(0, d))) continue;
|
|
37260
|
+
const rel = path114.slice(d + 1);
|
|
37228
37261
|
return !rel.includes("/") || /^(scripts|bin)\//.test(rel);
|
|
37229
37262
|
}
|
|
37230
37263
|
return false;
|
|
37231
37264
|
}
|
|
37232
|
-
function isInstructionFile(
|
|
37233
|
-
return INSTRUCTION_FILE_RE.test(
|
|
37265
|
+
function isInstructionFile(path114, skillDirs, appDirs) {
|
|
37266
|
+
return INSTRUCTION_FILE_RE.test(path114) || isSkillSupportFile(path114, skillDirs, appDirs);
|
|
37234
37267
|
}
|
|
37235
37268
|
function findFetchObeyUnless(text, skip) {
|
|
37236
37269
|
for (let start = 0; start <= text.length; ) {
|
|
@@ -37354,20 +37387,20 @@ function decodeSuspiciousBase64(text) {
|
|
|
37354
37387
|
}
|
|
37355
37388
|
return out;
|
|
37356
37389
|
}
|
|
37357
|
-
function mk2(rule, severity, title, signals, fix,
|
|
37390
|
+
function mk2(rule, severity, title, signals, fix, path114, line) {
|
|
37358
37391
|
return {
|
|
37359
37392
|
check: "CI-6",
|
|
37360
37393
|
rule,
|
|
37361
37394
|
dimension: "instructions",
|
|
37362
37395
|
severity,
|
|
37363
37396
|
title,
|
|
37364
|
-
file:
|
|
37397
|
+
file: path114,
|
|
37365
37398
|
...line ? { line } : {},
|
|
37366
37399
|
signals,
|
|
37367
37400
|
fix
|
|
37368
37401
|
};
|
|
37369
37402
|
}
|
|
37370
|
-
function analyzeInstructionFile(
|
|
37403
|
+
function analyzeInstructionFile(path114, content) {
|
|
37371
37404
|
const findings = [];
|
|
37372
37405
|
const decoded = decodeSuspiciousBase64(content);
|
|
37373
37406
|
const glyph = homoglyphWord(content);
|
|
@@ -37381,7 +37414,7 @@ function analyzeInstructionFile(path113, content) {
|
|
|
37381
37414
|
`\`${glyph.folded}\` is written with ${glyph.count} non-Latin look-alike letter(s): it reads the same to a reviewer, but a search, a replace or a policy check on the real word misses it`
|
|
37382
37415
|
],
|
|
37383
37416
|
"Spell the word with plain Latin letters, or explain on the same line why the look-alikes are there.",
|
|
37384
|
-
|
|
37417
|
+
path114,
|
|
37385
37418
|
glyph.line
|
|
37386
37419
|
)
|
|
37387
37420
|
);
|
|
@@ -37395,7 +37428,7 @@ function analyzeInstructionFile(path113, content) {
|
|
|
37395
37428
|
"contains Unicode tag characters (U+E0000\u2013E007F): an invisible instruction-smuggling channel with no legitimate use in text"
|
|
37396
37429
|
],
|
|
37397
37430
|
"Remove the tag characters. Instruction files must be plain, reviewable text.",
|
|
37398
|
-
|
|
37431
|
+
path114,
|
|
37399
37432
|
lineAt(content, content.search(TAG_CHARS))
|
|
37400
37433
|
)
|
|
37401
37434
|
);
|
|
@@ -37409,7 +37442,7 @@ function analyzeInstructionFile(path113, content) {
|
|
|
37409
37442
|
"contains a bidi override (U+202D/U+202E): a Trojan-Source technique that visually reorders text so a human reads something different from what the agent parses"
|
|
37410
37443
|
],
|
|
37411
37444
|
"Remove the bidi override characters.",
|
|
37412
|
-
|
|
37445
|
+
path114,
|
|
37413
37446
|
lineAt(content, content.search(BIDI_OVERRIDE))
|
|
37414
37447
|
)
|
|
37415
37448
|
);
|
|
@@ -37423,7 +37456,7 @@ function analyzeInstructionFile(path113, content) {
|
|
|
37423
37456
|
"contains bidi embed/isolate characters (U+202A\u2013202C / U+2066\u20132069): legitimate in right-to-left text, but confirm they are not being used to hide or reorder instructions"
|
|
37424
37457
|
],
|
|
37425
37458
|
"Confirm the bidi marks are legitimate RTL formatting; remove otherwise.",
|
|
37426
|
-
|
|
37459
|
+
path114,
|
|
37427
37460
|
lineAt(content, content.search(BIDI_EMBED_ISOLATE))
|
|
37428
37461
|
)
|
|
37429
37462
|
);
|
|
@@ -37439,7 +37472,7 @@ function analyzeInstructionFile(path113, content) {
|
|
|
37439
37472
|
revealed ? "a zero-width character conceals a prompt-override directive that only appears once the hidden characters are stripped" : "a zero-width character splits a visible Latin word: a concealment technique (hides text from human review while the agent reads it as contiguous)"
|
|
37440
37473
|
],
|
|
37441
37474
|
"Remove the zero-width characters. Instruction files must be plain, reviewable text.",
|
|
37442
|
-
|
|
37475
|
+
path114,
|
|
37443
37476
|
lineAt(content, zw.first)
|
|
37444
37477
|
)
|
|
37445
37478
|
);
|
|
@@ -37458,7 +37491,7 @@ function analyzeInstructionFile(path113, content) {
|
|
|
37458
37491
|
`contains a prompt-override / role-impersonation directive (\`${safeText(m[0].slice(0, 60).trim(), 60)}\`)${ovEnc ? ", concealed in a base64 blob" : ""}`
|
|
37459
37492
|
],
|
|
37460
37493
|
"Remove the override text. An instruction file should not tell the agent to ignore its own rules.",
|
|
37461
|
-
|
|
37494
|
+
path114,
|
|
37462
37495
|
ov ? lineAt(content, ov.index) : void 0
|
|
37463
37496
|
// concealed in base64: no line, never a wrong one
|
|
37464
37497
|
)
|
|
@@ -37475,7 +37508,7 @@ function analyzeInstructionFile(path113, content) {
|
|
|
37475
37508
|
`\`${safeText(fo[0].slice(0, 70).trim(), 70)}\`: fetch-and-obey, outside an install/setup section`
|
|
37476
37509
|
],
|
|
37477
37510
|
"Do not instruct the agent to pipe remote content into a shell; pin and vendor scripts instead.",
|
|
37478
|
-
|
|
37511
|
+
path114,
|
|
37479
37512
|
lineAt(content, fo.index)
|
|
37480
37513
|
)
|
|
37481
37514
|
);
|
|
@@ -37491,7 +37524,7 @@ function analyzeInstructionFile(path113, content) {
|
|
|
37491
37524
|
`references \`${safeText(sp[0].slice(0, 50).trim(), 50)}\`: directs the agent toward secrets`
|
|
37492
37525
|
],
|
|
37493
37526
|
"Do not reference credential files or paths in agent instructions.",
|
|
37494
|
-
|
|
37527
|
+
path114,
|
|
37495
37528
|
lineAt(content, sp.index)
|
|
37496
37529
|
)
|
|
37497
37530
|
);
|
|
@@ -37514,7 +37547,7 @@ function analyzeInstructionFile(path113, content) {
|
|
|
37514
37547
|
"Instruction directs the agent to send data to an external endpoint",
|
|
37515
37548
|
[`\`${safeText(ex[0].slice(0, 70).trim(), 70)}\`: possible exfiltration directive`],
|
|
37516
37549
|
"Remove external post/upload directives from agent instructions.",
|
|
37517
|
-
|
|
37550
|
+
path114,
|
|
37518
37551
|
lineAt(content, ex.index)
|
|
37519
37552
|
)
|
|
37520
37553
|
);
|
|
@@ -37747,7 +37780,7 @@ function cmdLine(content, cmd) {
|
|
|
37747
37780
|
const i = jsonValueIndex(content, cmd);
|
|
37748
37781
|
return i >= 0 ? lineAtIndex(content, i) : void 0;
|
|
37749
37782
|
}
|
|
37750
|
-
function analyzeAgentConfig(
|
|
37783
|
+
function analyzeAgentConfig(path114, content, tree) {
|
|
37751
37784
|
let cfg;
|
|
37752
37785
|
try {
|
|
37753
37786
|
cfg = JSON.parse(content);
|
|
@@ -37770,7 +37803,7 @@ function analyzeAgentConfig(path113, content, tree) {
|
|
|
37770
37803
|
dimension: "toolRules",
|
|
37771
37804
|
severity: high ? "high" : "medium",
|
|
37772
37805
|
title: high ? "Agent hook runs UNPINNED/remote third-party code on every action" : "Agent hook runs third-party code in the agent hot path",
|
|
37773
|
-
file:
|
|
37806
|
+
file: path114,
|
|
37774
37807
|
...cmdLine(content, cmd) ? { line: cmdLine(content, cmd) } : {},
|
|
37775
37808
|
signals: [
|
|
37776
37809
|
`hook command: \`${safeText(cmd, 120)}\``,
|
|
@@ -37791,7 +37824,7 @@ function analyzeAgentConfig(path113, content, tree) {
|
|
|
37791
37824
|
dimension: "toolRules",
|
|
37792
37825
|
severity: "medium",
|
|
37793
37826
|
title: "Agent hook runs a script that is not committed",
|
|
37794
|
-
file:
|
|
37827
|
+
file: path114,
|
|
37795
37828
|
...cmdLine(content, cmd) ? { line: cmdLine(content, cmd) } : {},
|
|
37796
37829
|
signals: [
|
|
37797
37830
|
`hook command: \`${safeText(cmd, 120)}\``,
|
|
@@ -37807,7 +37840,7 @@ function analyzeAgentConfig(path113, content, tree) {
|
|
|
37807
37840
|
dimension: "toolRules",
|
|
37808
37841
|
severity: "advisory",
|
|
37809
37842
|
title: "Agent hook runs a committed script this scan did not read",
|
|
37810
|
-
file:
|
|
37843
|
+
file: path114,
|
|
37811
37844
|
...cmdLine(content, cmd) ? { line: cmdLine(content, cmd) } : {},
|
|
37812
37845
|
signals: [
|
|
37813
37846
|
`hook command: \`${safeText(cmd, 120)}\``,
|
|
@@ -37836,12 +37869,12 @@ function analyzeAgentConfig(path113, content, tree) {
|
|
|
37836
37869
|
dimension: "toolRules",
|
|
37837
37870
|
severity: high ? "high" : "medium",
|
|
37838
37871
|
title: high ? "Committed agent config pre-authorizes broad tools with no deny backstop" : "Committed agent config pre-authorizes broad tools",
|
|
37839
|
-
file:
|
|
37872
|
+
file: path114,
|
|
37840
37873
|
signals,
|
|
37841
37874
|
fix: "Scope the allow-list to specific read-only subcommands (e.g. `Bash(gh pr view:*)`); avoid bare `Bash`/`git:`/`Write`, or add a `deny` backstop.",
|
|
37842
37875
|
explain: explainGrant({
|
|
37843
37876
|
high,
|
|
37844
|
-
file:
|
|
37877
|
+
file: path114,
|
|
37845
37878
|
broad: grade.broad,
|
|
37846
37879
|
bareShell: grade.bareShell,
|
|
37847
37880
|
hasBackstop: grade.bareShell ? deny.some((d) => /^Bash\b/.test(d)) : deny.some((d) => /Bash|Write|Edit/.test(d))
|
|
@@ -37858,7 +37891,7 @@ function analyzeAgentConfig(path113, content, tree) {
|
|
|
37858
37891
|
dimension: "toolRules",
|
|
37859
37892
|
severity: "medium",
|
|
37860
37893
|
title: "Committed agent config pre-approves a command that can run other programs",
|
|
37861
|
-
file:
|
|
37894
|
+
file: path114,
|
|
37862
37895
|
signals: [
|
|
37863
37896
|
`pre-approved: ${escapes.slice(0, 5).map((e) => `\`${safeText(e, 80)}\``).join(", ")}`,
|
|
37864
37897
|
"`find -exec` and `make -n --eval` run other programs without a prompt"
|
|
@@ -37868,8 +37901,8 @@ function analyzeAgentConfig(path113, content, tree) {
|
|
|
37868
37901
|
}
|
|
37869
37902
|
return findings;
|
|
37870
37903
|
}
|
|
37871
|
-
function skillReadsUntrusted(
|
|
37872
|
-
if (!ROOT_SURFACE_RE.test(
|
|
37904
|
+
function skillReadsUntrusted(path114, content, allow, broad) {
|
|
37905
|
+
if (!ROOT_SURFACE_RE.test(path114)) return null;
|
|
37873
37906
|
const body = content.replace(/^---[\s\S]*?\n---/, "");
|
|
37874
37907
|
const runsCode = broad.map((a) => a.replace(/^PowerShell(?=$|\()/, "Bash")).some((a) => /^Bash$|^Bash\(\s*\*/.test(a) || openRunner(a) && !/^Bash\(\s*gh\b/.test(a));
|
|
37875
37908
|
const webGrant = allow.some((a) => /^(WebFetch|WebSearch)\b/.test(a));
|
|
@@ -37884,8 +37917,8 @@ function skillReadsUntrusted(path113, content, allow, broad) {
|
|
|
37884
37917
|
return "it reads pull request text that strangers write, and may edit files and run git/gh on it";
|
|
37885
37918
|
return null;
|
|
37886
37919
|
}
|
|
37887
|
-
function analyzeSkillGrants(
|
|
37888
|
-
if (!GRANT_CARRIER_RE.test(
|
|
37920
|
+
function analyzeSkillGrants(path114, content) {
|
|
37921
|
+
if (!GRANT_CARRIER_RE.test(path114)) return [];
|
|
37889
37922
|
const allow = allowedToolsOf(parseFrontmatter(content));
|
|
37890
37923
|
if (allow.length === 0) return [];
|
|
37891
37924
|
const grade = gradeBroadGrant(allow, [], {
|
|
@@ -37893,9 +37926,9 @@ function analyzeSkillGrants(path113, content) {
|
|
|
37893
37926
|
scope: "whenever this skill or command is active, for everyone who opens this repo with the agent"
|
|
37894
37927
|
});
|
|
37895
37928
|
if (!grade) return [];
|
|
37896
|
-
const kind = /commands\//.test(
|
|
37929
|
+
const kind = /commands\//.test(path114) ? "slash command" : "skill";
|
|
37897
37930
|
const at = content.search(/^allowed-tools\s*:/m);
|
|
37898
|
-
const untrusted = skillReadsUntrusted(
|
|
37931
|
+
const untrusted = skillReadsUntrusted(path114, content, allow, grade.broad);
|
|
37899
37932
|
if (untrusted)
|
|
37900
37933
|
return [
|
|
37901
37934
|
{
|
|
@@ -37905,7 +37938,7 @@ function analyzeSkillGrants(path113, content) {
|
|
|
37905
37938
|
dimension: "toolRules",
|
|
37906
37939
|
severity: "advisory",
|
|
37907
37940
|
title: `Committed ${kind} runs code or writes with text strangers control`,
|
|
37908
|
-
file:
|
|
37941
|
+
file: path114,
|
|
37909
37942
|
signals: [...grade.signals, untrusted],
|
|
37910
37943
|
fix: "Drop the shell or interpreter grant from a skill that reads PRs, issues or the web, or have it treat that text as data in a read-only step first."
|
|
37911
37944
|
}
|
|
@@ -37922,7 +37955,7 @@ function analyzeSkillGrants(path113, content) {
|
|
|
37922
37955
|
// shell — the cap is on reach, not on honesty.
|
|
37923
37956
|
severity: "medium",
|
|
37924
37957
|
title: grade.high ? `Committed ${kind} pre-authorizes an unrestricted shell while active` : `Committed ${kind} pre-authorizes broad tools while active`,
|
|
37925
|
-
file:
|
|
37958
|
+
file: path114,
|
|
37926
37959
|
signals: grade.signals,
|
|
37927
37960
|
fix: "Scope `allowed-tools` to the specific commands the skill needs (e.g. `Bash(git status:*)`); avoid a bare `Bash`, `Write` or `Edit`."
|
|
37928
37961
|
}
|
|
@@ -38054,7 +38087,7 @@ function ownPackageNames(manifests) {
|
|
|
38054
38087
|
}
|
|
38055
38088
|
return out;
|
|
38056
38089
|
}
|
|
38057
|
-
function analyzeMcp(
|
|
38090
|
+
function analyzeMcp(path114, content, own = /* @__PURE__ */ new Set()) {
|
|
38058
38091
|
let cfg;
|
|
38059
38092
|
try {
|
|
38060
38093
|
cfg = JSON.parse(content);
|
|
@@ -38090,9 +38123,9 @@ function analyzeMcp(path113, content, own = /* @__PURE__ */ new Set()) {
|
|
|
38090
38123
|
const key = (count.get(name) ?? 0) > 1 ? `${section}.${name}` : name;
|
|
38091
38124
|
servers[key] = { ...spec, anchor: name };
|
|
38092
38125
|
}
|
|
38093
|
-
return analyzeMcpServers(servers,
|
|
38126
|
+
return analyzeMcpServers(servers, path114, content, own);
|
|
38094
38127
|
}
|
|
38095
|
-
function analyzeMcpServers(servers,
|
|
38128
|
+
function analyzeMcpServers(servers, path114, content = "", own = /* @__PURE__ */ new Set()) {
|
|
38096
38129
|
const findings = [];
|
|
38097
38130
|
for (const [name, srv] of Object.entries(servers ?? {})) {
|
|
38098
38131
|
if (!srv || srv.disabled) continue;
|
|
@@ -38111,7 +38144,7 @@ function analyzeMcpServers(servers, path113, content = "", own = /* @__PURE__ */
|
|
|
38111
38144
|
dimension: "mcp",
|
|
38112
38145
|
severity: "medium",
|
|
38113
38146
|
title: `MCP server "${name}" runs an unpinned executable`,
|
|
38114
|
-
file:
|
|
38147
|
+
file: path114,
|
|
38115
38148
|
...line ? { line } : {},
|
|
38116
38149
|
signals: [
|
|
38117
38150
|
why.launcher === "npx" ? `\`${safeText(argv, 120)}\`: unversioned/@latest npx` : `\`${safeText(argv, 120)}\`: unversioned/latest ${why.launcher}`
|
|
@@ -38136,7 +38169,7 @@ function analyzeMcpServers(servers, path113, content = "", own = /* @__PURE__ */
|
|
|
38136
38169
|
dimension: "mcp",
|
|
38137
38170
|
severity: "high",
|
|
38138
38171
|
title: `MCP server "${name}" has an inline credential`,
|
|
38139
|
-
file:
|
|
38172
|
+
file: path114,
|
|
38140
38173
|
...line ? { line } : {},
|
|
38141
38174
|
signals: [
|
|
38142
38175
|
`env.${k} matches ${hit.patternName}: agent-reachable secret committed to the repo`
|
|
@@ -38195,7 +38228,7 @@ var init_mcp = __esm({
|
|
|
38195
38228
|
});
|
|
38196
38229
|
|
|
38197
38230
|
// src/ci-check/codex.ts
|
|
38198
|
-
function analyzeCodexConfig(
|
|
38231
|
+
function analyzeCodexConfig(path114, content, own = /* @__PURE__ */ new Set()) {
|
|
38199
38232
|
let cfg;
|
|
38200
38233
|
try {
|
|
38201
38234
|
cfg = (0, import_smol_toml6.parse)(content);
|
|
@@ -38203,7 +38236,7 @@ function analyzeCodexConfig(path113, content, own = /* @__PURE__ */ new Set()) {
|
|
|
38203
38236
|
return [];
|
|
38204
38237
|
}
|
|
38205
38238
|
const findings = [];
|
|
38206
|
-
findings.push(...analyzeMcpServers(cfg.mcp_servers ?? {},
|
|
38239
|
+
findings.push(...analyzeMcpServers(cfg.mcp_servers ?? {}, path114, content, own));
|
|
38207
38240
|
const sandbox = typeof cfg.sandbox_mode === "string" ? cfg.sandbox_mode : "";
|
|
38208
38241
|
const approval = typeof cfg.approval_policy === "string" ? cfg.approval_policy : "";
|
|
38209
38242
|
const fullAccess = /danger-full-access/i.test(sandbox);
|
|
@@ -38226,7 +38259,7 @@ function analyzeCodexConfig(path113, content, own = /* @__PURE__ */ new Set()) {
|
|
|
38226
38259
|
dimension: "toolRules",
|
|
38227
38260
|
severity: fullAccess ? "high" : "medium",
|
|
38228
38261
|
title: fullAccess ? "Codex config grants a full-access sandbox" : "Codex config never requires approval",
|
|
38229
|
-
file:
|
|
38262
|
+
file: path114,
|
|
38230
38263
|
signals,
|
|
38231
38264
|
fix: 'Commit a least-privilege Codex config: prefer `sandbox_mode = "read-only"` (or `"workspace-write"`) and `approval_policy = "on-request"`/`"on-failure"`. A repo-committed config applies to every contributor who runs Codex here.'
|
|
38232
38265
|
});
|
|
@@ -38395,7 +38428,7 @@ var init_agent_permissions = __esm({
|
|
|
38395
38428
|
init_codex();
|
|
38396
38429
|
init_read_small_file();
|
|
38397
38430
|
CATEGORY = "Agent permissions";
|
|
38398
|
-
CLAUDE_NO_PROMPT_MODES = /* @__PURE__ */ new Set(["bypassPermissions"
|
|
38431
|
+
CLAUDE_NO_PROMPT_MODES = /* @__PURE__ */ new Set(["bypassPermissions"]);
|
|
38399
38432
|
MAX_FILE_BYTES3 = 2 * 1024 * 1024;
|
|
38400
38433
|
CI_SEVERITY = {
|
|
38401
38434
|
critical: "critical",
|
|
@@ -38430,6 +38463,15 @@ function checkOutsideContent(ctx) {
|
|
|
38430
38463
|
const roles = config.policy.untrustedContent?.roles ?? {};
|
|
38431
38464
|
const sources = outsideSources(home, roles);
|
|
38432
38465
|
if (sources.length === 0) return [];
|
|
38466
|
+
const byServer = /* @__PURE__ */ new Map();
|
|
38467
|
+
for (const src of sources) {
|
|
38468
|
+
const e = byServer.get(src.server);
|
|
38469
|
+
if (e) {
|
|
38470
|
+
if (!e.agents.includes(src.agent)) e.agents.push(src.agent);
|
|
38471
|
+
if (src.how === "role") e.how = "role";
|
|
38472
|
+
} else byServer.set(src.server, { agents: [src.agent], how: src.how });
|
|
38473
|
+
}
|
|
38474
|
+
const servers = byServer.size;
|
|
38433
38475
|
const egress = config.policy.egress;
|
|
38434
38476
|
const egressGated = !!egress?.enabled && (egress.mode === "block" || egress.mode === "review");
|
|
38435
38477
|
const hold = checkValue(
|
|
@@ -38446,11 +38488,14 @@ function checkOutsideContent(ctx) {
|
|
|
38446
38488
|
{
|
|
38447
38489
|
category: CATEGORY2,
|
|
38448
38490
|
severity: "high",
|
|
38449
|
-
title: `${
|
|
38491
|
+
title: `${servers} MCP server${servers === 1 ? "" : "s"} bring${servers === 1 ? "s" : ""} outside content in, and the way out is open`,
|
|
38450
38492
|
what: "An agent here reads pages, issues or messages written by others, and what it does next is not held.",
|
|
38451
38493
|
why: gaps.join("; ") + ".",
|
|
38452
38494
|
who: "One poisoned page or issue is enough: the agent reads it, then sends or deletes as it says.",
|
|
38453
|
-
detail: [
|
|
38495
|
+
detail: [
|
|
38496
|
+
...[...byServer].slice(0, 8).map(([name, e]) => `${name} (${e.agents.join(", ")}, by ${e.how})`),
|
|
38497
|
+
...gaps
|
|
38498
|
+
],
|
|
38454
38499
|
owner: "node9",
|
|
38455
38500
|
fix: 'Run `node9 egress watch` (or `node9 egress lock`), keep behavior.untrusted-content on, and mark each server\'s reading tools as "Brings outside content" on the Apps page so the hold applies to them.'
|
|
38456
38501
|
}
|
|
@@ -38597,8 +38642,8 @@ var init_instruction_files = __esm({
|
|
|
38597
38642
|
});
|
|
38598
38643
|
|
|
38599
38644
|
// src/skill-pin.ts
|
|
38600
|
-
function getPinsFilePath2() {
|
|
38601
|
-
return import_path57.default.join(
|
|
38645
|
+
function getPinsFilePath2(home = import_os46.default.homedir()) {
|
|
38646
|
+
return import_path57.default.join(home, ".node9", "skill-pins.json");
|
|
38602
38647
|
}
|
|
38603
38648
|
function sha256Bytes(buf) {
|
|
38604
38649
|
return import_crypto17.default.createHash("sha256").update(buf).digest("hex");
|
|
@@ -38668,8 +38713,8 @@ function hashSkillRoot(absPath) {
|
|
|
38668
38713
|
function getRootKey(absPath) {
|
|
38669
38714
|
return import_crypto17.default.createHash("sha256").update(absPath).digest("hex").slice(0, 16);
|
|
38670
38715
|
}
|
|
38671
|
-
function readSkillPinsSafe() {
|
|
38672
|
-
const filePath = getPinsFilePath2();
|
|
38716
|
+
function readSkillPinsSafe(home) {
|
|
38717
|
+
const filePath = getPinsFilePath2(home);
|
|
38673
38718
|
try {
|
|
38674
38719
|
const raw = import_fs55.default.readFileSync(filePath, "utf-8");
|
|
38675
38720
|
if (!raw.trim()) return { ok: false, reason: "corrupt", detail: "empty file" };
|
|
@@ -38853,7 +38898,7 @@ function checkSupplyChain(ctx) {
|
|
|
38853
38898
|
}
|
|
38854
38899
|
function pluginPinState(home) {
|
|
38855
38900
|
const roots = defaultSkillRoots(void 0, home);
|
|
38856
|
-
const pins = readSkillPinsSafe();
|
|
38901
|
+
const pins = readSkillPinsSafe(home);
|
|
38857
38902
|
const pinned = pins.ok ? pins.pins.roots : {};
|
|
38858
38903
|
return { roots, unpinned: roots.filter((r) => !pinned[getRootKey(r)]) };
|
|
38859
38904
|
}
|
|
@@ -38866,7 +38911,7 @@ function pluginsAndPackages(ctx, home) {
|
|
|
38866
38911
|
if (roots.length > 0 && tamper === "off") {
|
|
38867
38912
|
findings.push({
|
|
38868
38913
|
category: "Supply chain",
|
|
38869
|
-
severity: "
|
|
38914
|
+
severity: "advisory",
|
|
38870
38915
|
title: `${roots.length} installed plugin${roots.length === 1 ? "" : "s"} load${roots.length === 1 ? "s" : ""} unverified`,
|
|
38871
38916
|
what: "Plugins and skills the agent loads are code that runs with its rights, and no content hash is kept for them.",
|
|
38872
38917
|
why: "The check loading.skill-tamper is off, so node9 does not pin them.",
|
|
@@ -38878,7 +38923,7 @@ function pluginsAndPackages(ctx, home) {
|
|
|
38878
38923
|
} else if (unpinned.length > 0) {
|
|
38879
38924
|
findings.push({
|
|
38880
38925
|
category: "Supply chain",
|
|
38881
|
-
severity: "
|
|
38926
|
+
severity: "advisory",
|
|
38882
38927
|
title: `${unpinned.length} of ${roots.length} installed plugin${roots.length === 1 ? "" : "s"} ${unpinned.length === 1 ? "has" : "have"} no pin yet`,
|
|
38883
38928
|
what: "A plugin the agent can load has no recorded content hash yet.",
|
|
38884
38929
|
why: "node9 pins a plugin the first time it loads; these have not loaded since pinning was turned on.",
|
|
@@ -39244,7 +39289,8 @@ function checkCoverage(ctx) {
|
|
|
39244
39289
|
});
|
|
39245
39290
|
return findings;
|
|
39246
39291
|
}
|
|
39247
|
-
const
|
|
39292
|
+
const config = getConfig(ctx.cwd);
|
|
39293
|
+
const mode = config.settings.mode;
|
|
39248
39294
|
if (isRecordOnly(mode)) {
|
|
39249
39295
|
const level = levelOf(mode);
|
|
39250
39296
|
findings.push({
|
|
@@ -39259,7 +39305,6 @@ function checkCoverage(ctx) {
|
|
|
39259
39305
|
fix: "Set mode to `standard` (or `strict`) to enforce in-path."
|
|
39260
39306
|
});
|
|
39261
39307
|
}
|
|
39262
|
-
const config = getConfig(ctx.cwd);
|
|
39263
39308
|
if (config.settings.autoStartDaemon !== false) {
|
|
39264
39309
|
const state = autostartState();
|
|
39265
39310
|
if (state === "disabled" || state === "absent") {
|
|
@@ -39580,8 +39625,6 @@ async function annotateCoverage(findings, ctx) {
|
|
|
39580
39625
|
}
|
|
39581
39626
|
if (probe.kind === "egress") {
|
|
39582
39627
|
f.coverage = egressCoverage(env);
|
|
39583
|
-
if (f.coverage.state === "open" && config.policy.egress.enabled && config.policy.egress.mode !== "off" && isRecordOnly(mode))
|
|
39584
|
-
f.fix = auditModeFix(mode, "node9 egress is set");
|
|
39585
39628
|
continue;
|
|
39586
39629
|
}
|
|
39587
39630
|
if (probe.kind === "gateWired") {
|
|
@@ -41318,6 +41361,7 @@ async function processClaudeFile(file2, projPath, projLabel, judge, judgeFrom, r
|
|
|
41318
41361
|
const sessionCalls = [];
|
|
41319
41362
|
const toolUseFilePaths = /* @__PURE__ */ new Map();
|
|
41320
41363
|
const toolUseNames = /* @__PURE__ */ new Map();
|
|
41364
|
+
const toolUseInputs = /* @__PURE__ */ new Map();
|
|
41321
41365
|
let firstDlpTs = null;
|
|
41322
41366
|
let firstEditTs = null;
|
|
41323
41367
|
for (const line of raw.split("\n")) {
|
|
@@ -41388,7 +41432,10 @@ async function processClaudeFile(file2, projPath, projLabel, judge, judgeFrom, r
|
|
|
41388
41432
|
if (isNode9SelfOutput(resultText)) continue;
|
|
41389
41433
|
const resultTool = block.tool_use_id ? toolUseNames.get(block.tool_use_id) : void 0;
|
|
41390
41434
|
if (resultTool)
|
|
41391
|
-
judge.noteToolResult(sessionId, resultTool, entry.timestamp ?? "", entry.cwd
|
|
41435
|
+
judge.noteToolResult(sessionId, resultTool, entry.timestamp ?? "", entry.cwd, {
|
|
41436
|
+
input: block.tool_use_id ? toolUseInputs.get(block.tool_use_id) : void 0,
|
|
41437
|
+
output: resultText
|
|
41438
|
+
});
|
|
41392
41439
|
const decoysHere1 = recordCanaries(
|
|
41393
41440
|
{ text: resultText },
|
|
41394
41441
|
"tool-result",
|
|
@@ -41453,6 +41500,7 @@ async function processClaudeFile(file2, projPath, projLabel, judge, judgeFrom, r
|
|
|
41453
41500
|
toolUseFilePaths.set(block.id, input.file_path);
|
|
41454
41501
|
}
|
|
41455
41502
|
if (block.id) toolUseNames.set(block.id, toolName);
|
|
41503
|
+
if (block.id) toolUseInputs.set(block.id, input);
|
|
41456
41504
|
sessionCalls.push({ toolName, input, timestamp: entry.timestamp ?? "" });
|
|
41457
41505
|
if (toolNameLower === "bash" || toolNameLower === "execute_bash") {
|
|
41458
41506
|
result.bashCalls++;
|
|
@@ -45667,6 +45715,23 @@ function writeCache2(cache7) {
|
|
|
45667
45715
|
} catch {
|
|
45668
45716
|
}
|
|
45669
45717
|
}
|
|
45718
|
+
function cacheFromSyncBody(body, etag) {
|
|
45719
|
+
return {
|
|
45720
|
+
fetchedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
45721
|
+
rules: extractRules(body),
|
|
45722
|
+
etag,
|
|
45723
|
+
panicMode: body.panicMode,
|
|
45724
|
+
shadowMode: body.shadowMode,
|
|
45725
|
+
syncIntervalHours: body.syncIntervalHours,
|
|
45726
|
+
workspaceId: body.workspaceId,
|
|
45727
|
+
shields: extractShields(body),
|
|
45728
|
+
managedConfig: extractManagedConfig(body),
|
|
45729
|
+
config: extractWorkspaceConfig(body)
|
|
45730
|
+
};
|
|
45731
|
+
}
|
|
45732
|
+
function writePolicyCache(body, etag) {
|
|
45733
|
+
writeCache2(cacheFromSyncBody(body, etag));
|
|
45734
|
+
}
|
|
45670
45735
|
async function syncOnce() {
|
|
45671
45736
|
const creds = readCredentials();
|
|
45672
45737
|
if (!creds) return;
|
|
@@ -45675,19 +45740,7 @@ async function syncOnce() {
|
|
|
45675
45740
|
if (result.kind === "unchanged") {
|
|
45676
45741
|
recordSyncHealth({ ok: true });
|
|
45677
45742
|
} else {
|
|
45678
|
-
|
|
45679
|
-
fetchedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
45680
|
-
rules: extractRules(result.body),
|
|
45681
|
-
etag: result.etag,
|
|
45682
|
-
panicMode: result.body.panicMode,
|
|
45683
|
-
shadowMode: result.body.shadowMode,
|
|
45684
|
-
syncIntervalHours: result.body.syncIntervalHours,
|
|
45685
|
-
workspaceId: result.body.workspaceId,
|
|
45686
|
-
shields: extractShields(result.body),
|
|
45687
|
-
managedConfig: extractManagedConfig(result.body),
|
|
45688
|
-
config: extractWorkspaceConfig(result.body)
|
|
45689
|
-
};
|
|
45690
|
-
writeCache2(cache7);
|
|
45743
|
+
writeCache2(cacheFromSyncBody(result.body, result.etag));
|
|
45691
45744
|
recordSyncHealth({ ok: true, changed: true });
|
|
45692
45745
|
}
|
|
45693
45746
|
} catch (err2) {
|
|
@@ -45905,18 +45958,7 @@ async function runCloudSync() {
|
|
|
45905
45958
|
recordSyncHealth({ ok: true });
|
|
45906
45959
|
return status.cached ? { ok: true, rules: status.rules, fetchedAt: status.fetchedAt, unchanged: true } : { ok: true, rules: 0, fetchedAt: (/* @__PURE__ */ new Date()).toISOString(), unchanged: true };
|
|
45907
45960
|
}
|
|
45908
|
-
const cache7 =
|
|
45909
|
-
fetchedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
45910
|
-
rules: extractRules(result.body),
|
|
45911
|
-
etag: result.etag,
|
|
45912
|
-
panicMode: result.body.panicMode,
|
|
45913
|
-
shadowMode: result.body.shadowMode,
|
|
45914
|
-
syncIntervalHours: result.body.syncIntervalHours,
|
|
45915
|
-
workspaceId: result.body.workspaceId,
|
|
45916
|
-
shields: extractShields(result.body),
|
|
45917
|
-
managedConfig: extractManagedConfig(result.body),
|
|
45918
|
-
config: extractWorkspaceConfig(result.body)
|
|
45919
|
-
};
|
|
45961
|
+
const cache7 = cacheFromSyncBody(result.body, result.etag);
|
|
45920
45962
|
writeCache2(cache7);
|
|
45921
45963
|
recordSyncHealth({ ok: true, changed: true });
|
|
45922
45964
|
return { ok: true, rules: cache7.rules.length, fetchedAt: cache7.fetchedAt };
|
|
@@ -46040,6 +46082,7 @@ var init_sync = __esm({
|
|
|
46040
46082
|
var audit_shipper_exports = {};
|
|
46041
46083
|
__export(audit_shipper_exports, {
|
|
46042
46084
|
AUDIT_SHIP_WATERMARK: () => AUDIT_SHIP_WATERMARK,
|
|
46085
|
+
OWASP_FIELDS_RETRY_MS: () => OWASP_FIELDS_RETRY_MS,
|
|
46043
46086
|
_resetOwaspWireFields: () => _resetOwaspWireFields,
|
|
46044
46087
|
buildBatchEndpoint: () => buildBatchEndpoint,
|
|
46045
46088
|
buildWireRows: () => buildWireRows,
|
|
@@ -46052,7 +46095,7 @@ __export(audit_shipper_exports, {
|
|
|
46052
46095
|
writeWatermark: () => writeWatermark
|
|
46053
46096
|
});
|
|
46054
46097
|
function _resetOwaspWireFields() {
|
|
46055
|
-
|
|
46098
|
+
owaspFieldsRejectedAt = null;
|
|
46056
46099
|
}
|
|
46057
46100
|
function withoutOwaspFields(rows) {
|
|
46058
46101
|
return rows.map((r) => {
|
|
@@ -46176,6 +46219,7 @@ async function shipOnce(deps = {}) {
|
|
|
46176
46219
|
const auditLogPath = deps.auditLogPath ?? LOCAL_AUDIT_LOG;
|
|
46177
46220
|
const watermarkPath = deps.watermarkPath ?? AUDIT_SHIP_WATERMARK;
|
|
46178
46221
|
const fetchImpl = deps.fetchImpl ?? fetch;
|
|
46222
|
+
const now = deps.now ?? Date.now;
|
|
46179
46223
|
let cloudEnabled = deps.cloudEnabled;
|
|
46180
46224
|
if (cloudEnabled === void 0) {
|
|
46181
46225
|
try {
|
|
@@ -46213,7 +46257,8 @@ async function shipOnce(deps = {}) {
|
|
|
46213
46257
|
if (consumed === 0) break;
|
|
46214
46258
|
for (let i = 0; i < rows.length; i += MAX_BATCH) {
|
|
46215
46259
|
const slice = rows.slice(i, i + MAX_BATCH);
|
|
46216
|
-
|
|
46260
|
+
const stripFields = owaspFieldsRejectedAt !== null && now() - owaspFieldsRejectedAt < OWASP_FIELDS_RETRY_MS;
|
|
46261
|
+
let batch = stripFields ? withoutOwaspFields(slice) : slice;
|
|
46217
46262
|
const post = async (body) => {
|
|
46218
46263
|
const controller = new AbortController();
|
|
46219
46264
|
const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
|
|
@@ -46235,7 +46280,7 @@ async function shipOnce(deps = {}) {
|
|
|
46235
46280
|
if (res.status === 400 && hasOwaspFields(batch)) {
|
|
46236
46281
|
batch = withoutOwaspFields(batch);
|
|
46237
46282
|
res = await post(batch);
|
|
46238
|
-
if (res.ok)
|
|
46283
|
+
if (res.ok) owaspFieldsRejectedAt = now();
|
|
46239
46284
|
}
|
|
46240
46285
|
if (!res.ok) throw new Error(`audit/batch HTTP ${res.status}`);
|
|
46241
46286
|
shipped += batch.length;
|
|
@@ -46322,7 +46367,7 @@ function outboxBacklog(auditLogPath = LOCAL_AUDIT_LOG, watermarkPath = AUDIT_SHI
|
|
|
46322
46367
|
};
|
|
46323
46368
|
}
|
|
46324
46369
|
}
|
|
46325
|
-
var import_fs67, import_path70, import_os57, import_crypto21, DECIDED_BY_VALUES, AUDIT_SHIP_WATERMARK, DEFAULT_INTERVAL_MS, MAX_BATCH, MAX_CHUNK_BYTES, MAX_CHUNKS_PER_TICK, FETCH_TIMEOUT_MS, SKIP_CHECKED_BY, CHECK_ID_RE, CANARY_KINDS, OWASP_WIRE_FIELDS,
|
|
46370
|
+
var import_fs67, import_path70, import_os57, import_crypto21, DECIDED_BY_VALUES, AUDIT_SHIP_WATERMARK, DEFAULT_INTERVAL_MS, MAX_BATCH, MAX_CHUNK_BYTES, MAX_CHUNKS_PER_TICK, FETCH_TIMEOUT_MS, SKIP_CHECKED_BY, CHECK_ID_RE, CANARY_KINDS, OWASP_WIRE_FIELDS, owaspFieldsRejectedAt, OWASP_FIELDS_RETRY_MS, shipperStarted;
|
|
46326
46371
|
var init_audit_shipper = __esm({
|
|
46327
46372
|
"src/daemon/audit-shipper.ts"() {
|
|
46328
46373
|
"use strict";
|
|
@@ -46358,7 +46403,8 @@ var init_audit_shipper = __esm({
|
|
|
46358
46403
|
"ssh-key"
|
|
46359
46404
|
]);
|
|
46360
46405
|
OWASP_WIRE_FIELDS = ["checkId", "canary", "canaryKind"];
|
|
46361
|
-
|
|
46406
|
+
owaspFieldsRejectedAt = null;
|
|
46407
|
+
OWASP_FIELDS_RETRY_MS = 60 * 60 * 1e3;
|
|
46362
46408
|
shipperStarted = false;
|
|
46363
46409
|
}
|
|
46364
46410
|
});
|
|
@@ -50892,14 +50938,14 @@ var require_util = __commonJS({
|
|
|
50892
50938
|
}
|
|
50893
50939
|
const port = url.port != null ? url.port : url.protocol === "https:" ? 443 : 80;
|
|
50894
50940
|
let origin = url.origin != null ? url.origin : `${url.protocol || ""}//${url.hostname || ""}:${port}`;
|
|
50895
|
-
let
|
|
50941
|
+
let path114 = url.path != null ? url.path : `${url.pathname || ""}${url.search || ""}`;
|
|
50896
50942
|
if (origin[origin.length - 1] === "/") {
|
|
50897
50943
|
origin = origin.slice(0, origin.length - 1);
|
|
50898
50944
|
}
|
|
50899
|
-
if (
|
|
50900
|
-
|
|
50945
|
+
if (path114 && path114[0] !== "/") {
|
|
50946
|
+
path114 = `/${path114}`;
|
|
50901
50947
|
}
|
|
50902
|
-
return new URL(`${origin}${
|
|
50948
|
+
return new URL(`${origin}${path114}`);
|
|
50903
50949
|
}
|
|
50904
50950
|
if (!isHttpOrHttpsPrefixed(url.origin || url.protocol)) {
|
|
50905
50951
|
throw new InvalidArgumentError("Invalid URL protocol: the URL must start with `http:` or `https:`.");
|
|
@@ -51722,9 +51768,9 @@ var require_diagnostics = __commonJS({
|
|
|
51722
51768
|
"undici:client:sendHeaders",
|
|
51723
51769
|
(evt) => {
|
|
51724
51770
|
const {
|
|
51725
|
-
request: { method, path:
|
|
51771
|
+
request: { method, path: path114, origin }
|
|
51726
51772
|
} = evt;
|
|
51727
|
-
debugLog2("sending request to %s %s%s", method, origin,
|
|
51773
|
+
debugLog2("sending request to %s %s%s", method, origin, path114);
|
|
51728
51774
|
}
|
|
51729
51775
|
);
|
|
51730
51776
|
}
|
|
@@ -51742,14 +51788,14 @@ var require_diagnostics = __commonJS({
|
|
|
51742
51788
|
"undici:request:headers",
|
|
51743
51789
|
(evt) => {
|
|
51744
51790
|
const {
|
|
51745
|
-
request: { method, path:
|
|
51791
|
+
request: { method, path: path114, origin },
|
|
51746
51792
|
response: { statusCode }
|
|
51747
51793
|
} = evt;
|
|
51748
51794
|
debugLog2(
|
|
51749
51795
|
"received response to %s %s%s - HTTP %d",
|
|
51750
51796
|
method,
|
|
51751
51797
|
origin,
|
|
51752
|
-
|
|
51798
|
+
path114,
|
|
51753
51799
|
statusCode
|
|
51754
51800
|
);
|
|
51755
51801
|
}
|
|
@@ -51758,23 +51804,23 @@ var require_diagnostics = __commonJS({
|
|
|
51758
51804
|
"undici:request:trailers",
|
|
51759
51805
|
(evt) => {
|
|
51760
51806
|
const {
|
|
51761
|
-
request: { method, path:
|
|
51807
|
+
request: { method, path: path114, origin }
|
|
51762
51808
|
} = evt;
|
|
51763
|
-
debugLog2("trailers received from %s %s%s", method, origin,
|
|
51809
|
+
debugLog2("trailers received from %s %s%s", method, origin, path114);
|
|
51764
51810
|
}
|
|
51765
51811
|
);
|
|
51766
51812
|
diagnosticsChannel.subscribe(
|
|
51767
51813
|
"undici:request:error",
|
|
51768
51814
|
(evt) => {
|
|
51769
51815
|
const {
|
|
51770
|
-
request: { method, path:
|
|
51816
|
+
request: { method, path: path114, origin },
|
|
51771
51817
|
error
|
|
51772
51818
|
} = evt;
|
|
51773
51819
|
debugLog2(
|
|
51774
51820
|
"request to %s %s%s errored - %s",
|
|
51775
51821
|
method,
|
|
51776
51822
|
origin,
|
|
51777
|
-
|
|
51823
|
+
path114,
|
|
51778
51824
|
error.message
|
|
51779
51825
|
);
|
|
51780
51826
|
}
|
|
@@ -51890,7 +51936,7 @@ var require_request = __commonJS({
|
|
|
51890
51936
|
var kHandler = /* @__PURE__ */ Symbol("handler");
|
|
51891
51937
|
var Request = class {
|
|
51892
51938
|
constructor(origin, {
|
|
51893
|
-
path:
|
|
51939
|
+
path: path114,
|
|
51894
51940
|
method,
|
|
51895
51941
|
body,
|
|
51896
51942
|
headers,
|
|
@@ -51907,11 +51953,11 @@ var require_request = __commonJS({
|
|
|
51907
51953
|
maxRedirections,
|
|
51908
51954
|
typeOfService
|
|
51909
51955
|
}, handler) {
|
|
51910
|
-
if (typeof
|
|
51956
|
+
if (typeof path114 !== "string") {
|
|
51911
51957
|
throw new InvalidArgumentError("path must be a string");
|
|
51912
|
-
} else if (
|
|
51958
|
+
} else if (path114[0] !== "/" && !(path114.startsWith("http://") || path114.startsWith("https://")) && method !== "CONNECT") {
|
|
51913
51959
|
throw new InvalidArgumentError("path must be an absolute URL or start with a slash");
|
|
51914
|
-
} else if (invalidPathRegex.test(
|
|
51960
|
+
} else if (invalidPathRegex.test(path114)) {
|
|
51915
51961
|
throw new InvalidArgumentError("invalid request path");
|
|
51916
51962
|
}
|
|
51917
51963
|
if (typeof method !== "string") {
|
|
@@ -51986,7 +52032,7 @@ var require_request = __commonJS({
|
|
|
51986
52032
|
this.completed = false;
|
|
51987
52033
|
this.aborted = false;
|
|
51988
52034
|
this.upgrade = upgrade || null;
|
|
51989
|
-
this.path = query ? serializePathWithQuery(
|
|
52035
|
+
this.path = query ? serializePathWithQuery(path114, query) : path114;
|
|
51990
52036
|
this.origin = origin;
|
|
51991
52037
|
this.protocol = getProtocolFromUrlString(origin);
|
|
51992
52038
|
this.idempotent = idempotent == null ? method === "HEAD" || method === "GET" : idempotent;
|
|
@@ -57233,7 +57279,7 @@ var require_client_h1 = __commonJS({
|
|
|
57233
57279
|
return method !== "GET" && method !== "HEAD" && method !== "OPTIONS" && method !== "TRACE" && method !== "CONNECT";
|
|
57234
57280
|
}
|
|
57235
57281
|
function writeH1(client, request2) {
|
|
57236
|
-
const { method, path:
|
|
57282
|
+
const { method, path: path114, host: host2, upgrade, blocking, reset } = request2;
|
|
57237
57283
|
let { body, headers, contentLength } = request2;
|
|
57238
57284
|
const expectsPayload = method === "PUT" || method === "POST" || method === "PATCH" || method === "QUERY" || method === "PROPFIND" || method === "PROPPATCH";
|
|
57239
57285
|
if (util.isFormDataLike(body)) {
|
|
@@ -57311,7 +57357,7 @@ var require_client_h1 = __commonJS({
|
|
|
57311
57357
|
if (socket.setTypeOfService) {
|
|
57312
57358
|
socket.setTypeOfService(request2.typeOfService);
|
|
57313
57359
|
}
|
|
57314
|
-
let header = `${method} ${
|
|
57360
|
+
let header = `${method} ${path114} HTTP/1.1\r
|
|
57315
57361
|
`;
|
|
57316
57362
|
if (typeof host2 === "string") {
|
|
57317
57363
|
header += `host: ${host2}\r
|
|
@@ -57989,7 +58035,7 @@ var require_client_h2 = __commonJS({
|
|
|
57989
58035
|
const headersTimeout = request2.headersTimeout ?? client[kHeadersTimeout];
|
|
57990
58036
|
const bodyTimeout = request2.bodyTimeout ?? client[kBodyTimeout];
|
|
57991
58037
|
const session = client[kHTTP2Session];
|
|
57992
|
-
const { method, path:
|
|
58038
|
+
const { method, path: path114, host: host2, upgrade, expectContinue, signal, protocol, headers: reqHeaders } = request2;
|
|
57993
58039
|
let { body } = request2;
|
|
57994
58040
|
if (upgrade != null && upgrade !== "websocket") {
|
|
57995
58041
|
util.errorRequest(client, request2, new InvalidArgumentError(`Custom upgrade "${upgrade}" not supported over HTTP/2`));
|
|
@@ -58058,7 +58104,7 @@ var require_client_h2 = __commonJS({
|
|
|
58058
58104
|
}
|
|
58059
58105
|
headers[HTTP2_HEADER_METHOD] = "CONNECT";
|
|
58060
58106
|
headers[HTTP2_HEADER_PROTOCOL] = "websocket";
|
|
58061
|
-
headers[HTTP2_HEADER_PATH] =
|
|
58107
|
+
headers[HTTP2_HEADER_PATH] = path114;
|
|
58062
58108
|
if (protocol === "ws:" || protocol === "wss:") {
|
|
58063
58109
|
headers[HTTP2_HEADER_SCHEME] = protocol === "ws:" ? "http" : "https";
|
|
58064
58110
|
} else {
|
|
@@ -58110,7 +58156,7 @@ var require_client_h2 = __commonJS({
|
|
|
58110
58156
|
stream.setTimeout(headersTimeout);
|
|
58111
58157
|
return true;
|
|
58112
58158
|
}
|
|
58113
|
-
headers[HTTP2_HEADER_PATH] =
|
|
58159
|
+
headers[HTTP2_HEADER_PATH] = path114;
|
|
58114
58160
|
headers[HTTP2_HEADER_SCHEME] = protocol === "http:" ? "http" : "https";
|
|
58115
58161
|
const expectsPayload = method === "PUT" || method === "POST" || method === "PATCH";
|
|
58116
58162
|
if (body && typeof body.read === "function") {
|
|
@@ -60477,10 +60523,10 @@ var require_proxy_agent = __commonJS({
|
|
|
60477
60523
|
};
|
|
60478
60524
|
const {
|
|
60479
60525
|
origin,
|
|
60480
|
-
path:
|
|
60526
|
+
path: path114 = "/",
|
|
60481
60527
|
headers = {}
|
|
60482
60528
|
} = opts;
|
|
60483
|
-
opts.path = origin +
|
|
60529
|
+
opts.path = origin + path114;
|
|
60484
60530
|
if (!("host" in headers) && !("Host" in headers)) {
|
|
60485
60531
|
const { host: host2 } = new URL(origin);
|
|
60486
60532
|
headers.host = host2;
|
|
@@ -62655,20 +62701,20 @@ var require_mock_utils = __commonJS({
|
|
|
62655
62701
|
}
|
|
62656
62702
|
return normalizedQp;
|
|
62657
62703
|
}
|
|
62658
|
-
function safeUrl(
|
|
62659
|
-
if (typeof
|
|
62660
|
-
return
|
|
62704
|
+
function safeUrl(path114) {
|
|
62705
|
+
if (typeof path114 !== "string") {
|
|
62706
|
+
return path114;
|
|
62661
62707
|
}
|
|
62662
|
-
const pathSegments =
|
|
62708
|
+
const pathSegments = path114.split("?", 3);
|
|
62663
62709
|
if (pathSegments.length !== 2) {
|
|
62664
|
-
return
|
|
62710
|
+
return path114;
|
|
62665
62711
|
}
|
|
62666
62712
|
const qp = new URLSearchParams(pathSegments.pop());
|
|
62667
62713
|
qp.sort();
|
|
62668
62714
|
return [...pathSegments, qp.toString()].join("?");
|
|
62669
62715
|
}
|
|
62670
|
-
function matchKey(mockDispatch2, { path:
|
|
62671
|
-
const pathMatch = matchValue(mockDispatch2.path,
|
|
62716
|
+
function matchKey(mockDispatch2, { path: path114, method, body, headers }) {
|
|
62717
|
+
const pathMatch = matchValue(mockDispatch2.path, path114);
|
|
62672
62718
|
const methodMatch = matchValue(mockDispatch2.method, method);
|
|
62673
62719
|
const bodyMatch = typeof mockDispatch2.body !== "undefined" ? matchValue(mockDispatch2.body, body) : true;
|
|
62674
62720
|
const headersMatch = matchHeaders(mockDispatch2, headers);
|
|
@@ -62693,8 +62739,8 @@ var require_mock_utils = __commonJS({
|
|
|
62693
62739
|
const basePath = key.query ? serializePathWithQuery(key.path, key.query) : key.path;
|
|
62694
62740
|
const resolvedPath = typeof basePath === "string" ? safeUrl(basePath) : basePath;
|
|
62695
62741
|
const resolvedPathWithoutTrailingSlash = removeTrailingSlash(resolvedPath);
|
|
62696
|
-
let matchedMockDispatches = mockDispatches.filter(({ consumed }) => !consumed).filter(({ path:
|
|
62697
|
-
return ignoreTrailingSlash ? matchValue(removeTrailingSlash(safeUrl(
|
|
62742
|
+
let matchedMockDispatches = mockDispatches.filter(({ consumed }) => !consumed).filter(({ path: path114, ignoreTrailingSlash }) => {
|
|
62743
|
+
return ignoreTrailingSlash ? matchValue(removeTrailingSlash(safeUrl(path114)), resolvedPathWithoutTrailingSlash) : matchValue(safeUrl(path114), resolvedPath);
|
|
62698
62744
|
});
|
|
62699
62745
|
if (matchedMockDispatches.length === 0) {
|
|
62700
62746
|
throw new MockNotMatchedError(`Mock dispatch not matched for path '${resolvedPath}'`);
|
|
@@ -62733,19 +62779,19 @@ var require_mock_utils = __commonJS({
|
|
|
62733
62779
|
mockDispatches.splice(index, 1);
|
|
62734
62780
|
}
|
|
62735
62781
|
}
|
|
62736
|
-
function removeTrailingSlash(
|
|
62737
|
-
while (
|
|
62738
|
-
|
|
62782
|
+
function removeTrailingSlash(path114) {
|
|
62783
|
+
while (path114.endsWith("/")) {
|
|
62784
|
+
path114 = path114.slice(0, -1);
|
|
62739
62785
|
}
|
|
62740
|
-
if (
|
|
62741
|
-
|
|
62786
|
+
if (path114.length === 0) {
|
|
62787
|
+
path114 = "/";
|
|
62742
62788
|
}
|
|
62743
|
-
return
|
|
62789
|
+
return path114;
|
|
62744
62790
|
}
|
|
62745
62791
|
function buildKey(opts) {
|
|
62746
|
-
const { path:
|
|
62792
|
+
const { path: path114, method, body, headers, query } = opts;
|
|
62747
62793
|
return {
|
|
62748
|
-
path:
|
|
62794
|
+
path: path114,
|
|
62749
62795
|
method,
|
|
62750
62796
|
body,
|
|
62751
62797
|
headers,
|
|
@@ -63440,10 +63486,10 @@ var require_pending_interceptors_formatter = __commonJS({
|
|
|
63440
63486
|
}
|
|
63441
63487
|
format(pendingInterceptors) {
|
|
63442
63488
|
const withPrettyHeaders = pendingInterceptors.map(
|
|
63443
|
-
({ method, path:
|
|
63489
|
+
({ method, path: path114, data: { statusCode }, persist, times, timesInvoked, origin }) => ({
|
|
63444
63490
|
Method: method,
|
|
63445
63491
|
Origin: origin,
|
|
63446
|
-
Path:
|
|
63492
|
+
Path: path114,
|
|
63447
63493
|
"Status code": statusCode,
|
|
63448
63494
|
Persistent: persist ? PERSISTENT : NOT_PERSISTENT,
|
|
63449
63495
|
Invocations: timesInvoked,
|
|
@@ -63526,9 +63572,9 @@ var require_mock_agent = __commonJS({
|
|
|
63526
63572
|
const acceptNonStandardSearchParameters = this[kMockAgentAcceptsNonStandardSearchParameters];
|
|
63527
63573
|
const dispatchOpts = { ...opts };
|
|
63528
63574
|
if (acceptNonStandardSearchParameters && dispatchOpts.path) {
|
|
63529
|
-
const [
|
|
63575
|
+
const [path114, searchParams] = dispatchOpts.path.split("?");
|
|
63530
63576
|
const normalizedSearchParams = normalizeSearchParams(searchParams, acceptNonStandardSearchParameters);
|
|
63531
|
-
dispatchOpts.path = `${
|
|
63577
|
+
dispatchOpts.path = `${path114}?${normalizedSearchParams}`;
|
|
63532
63578
|
}
|
|
63533
63579
|
return this[kAgent].dispatch(dispatchOpts, handler);
|
|
63534
63580
|
}
|
|
@@ -63931,12 +63977,12 @@ var require_snapshot_recorder = __commonJS({
|
|
|
63931
63977
|
* @return {Promise<void>} - Resolves when snapshots are loaded
|
|
63932
63978
|
*/
|
|
63933
63979
|
async loadSnapshots(filePath) {
|
|
63934
|
-
const
|
|
63935
|
-
if (!
|
|
63980
|
+
const path114 = filePath || this.#snapshotPath;
|
|
63981
|
+
if (!path114) {
|
|
63936
63982
|
throw new InvalidArgumentError("Snapshot path is required");
|
|
63937
63983
|
}
|
|
63938
63984
|
try {
|
|
63939
|
-
const data = await readFile(resolve2(
|
|
63985
|
+
const data = await readFile(resolve2(path114), "utf8");
|
|
63940
63986
|
const parsed = JSON.parse(data);
|
|
63941
63987
|
if (Array.isArray(parsed)) {
|
|
63942
63988
|
this.#snapshots.clear();
|
|
@@ -63950,7 +63996,7 @@ var require_snapshot_recorder = __commonJS({
|
|
|
63950
63996
|
if (error.code === "ENOENT") {
|
|
63951
63997
|
this.#snapshots.clear();
|
|
63952
63998
|
} else {
|
|
63953
|
-
throw new UndiciError(`Failed to load snapshots from ${
|
|
63999
|
+
throw new UndiciError(`Failed to load snapshots from ${path114}`, { cause: error });
|
|
63954
64000
|
}
|
|
63955
64001
|
}
|
|
63956
64002
|
}
|
|
@@ -63961,11 +64007,11 @@ var require_snapshot_recorder = __commonJS({
|
|
|
63961
64007
|
* @returns {Promise<void>} - Resolves when snapshots are saved
|
|
63962
64008
|
*/
|
|
63963
64009
|
async saveSnapshots(filePath) {
|
|
63964
|
-
const
|
|
63965
|
-
if (!
|
|
64010
|
+
const path114 = filePath || this.#snapshotPath;
|
|
64011
|
+
if (!path114) {
|
|
63966
64012
|
throw new InvalidArgumentError("Snapshot path is required");
|
|
63967
64013
|
}
|
|
63968
|
-
const resolvedPath = resolve2(
|
|
64014
|
+
const resolvedPath = resolve2(path114);
|
|
63969
64015
|
await mkdir(dirname3(resolvedPath), { recursive: true });
|
|
63970
64016
|
const data = Array.from(this.#snapshots.entries()).map(([hash2, snapshot]) => ({
|
|
63971
64017
|
hash: hash2,
|
|
@@ -64606,15 +64652,15 @@ var require_redirect_handler = __commonJS({
|
|
|
64606
64652
|
}
|
|
64607
64653
|
this.history[kRedirectCacheControl].push(headers["cache-control"]);
|
|
64608
64654
|
const { origin, pathname, search } = util.parseURL(new URL(this.location, this.opts.origin && new URL(this.opts.path, this.opts.origin)));
|
|
64609
|
-
const
|
|
64610
|
-
const redirectUrlString = `${origin}${
|
|
64655
|
+
const path114 = search ? `${pathname}${search}` : pathname;
|
|
64656
|
+
const redirectUrlString = `${origin}${path114}`;
|
|
64611
64657
|
for (const historyUrl of this.history) {
|
|
64612
64658
|
if (historyUrl.toString() === redirectUrlString) {
|
|
64613
64659
|
throw new InvalidArgumentError(`Redirect loop detected. Cannot redirect to ${origin}. This typically happens when using a Client or Pool with cross-origin redirects. Use an Agent for cross-origin redirects.`);
|
|
64614
64660
|
}
|
|
64615
64661
|
}
|
|
64616
64662
|
this.opts.headers = cleanRequestHeaders(this.opts.headers, statusCode === 303, this.opts.origin !== origin);
|
|
64617
|
-
this.opts.path =
|
|
64663
|
+
this.opts.path = path114;
|
|
64618
64664
|
this.opts.origin = origin;
|
|
64619
64665
|
this.opts.query = null;
|
|
64620
64666
|
}
|
|
@@ -66390,10 +66436,10 @@ var require_cache_handler = __commonJS({
|
|
|
66390
66436
|
}
|
|
66391
66437
|
return locationUrl.pathname + locationUrl.search;
|
|
66392
66438
|
}
|
|
66393
|
-
function deleteCachedUri(store, cacheKey,
|
|
66439
|
+
function deleteCachedUri(store, cacheKey, path114) {
|
|
66394
66440
|
deleteCachedValue(store, {
|
|
66395
66441
|
...cacheKey,
|
|
66396
|
-
path:
|
|
66442
|
+
path: path114
|
|
66397
66443
|
});
|
|
66398
66444
|
for (let i = 0; i < util.safeHTTPMethods.length; i++) {
|
|
66399
66445
|
const method = util.safeHTTPMethods[i];
|
|
@@ -66401,7 +66447,7 @@ var require_cache_handler = __commonJS({
|
|
|
66401
66447
|
deleteCachedValue(store, {
|
|
66402
66448
|
...cacheKey,
|
|
66403
66449
|
method,
|
|
66404
|
-
path:
|
|
66450
|
+
path: path114
|
|
66405
66451
|
});
|
|
66406
66452
|
}
|
|
66407
66453
|
}
|
|
@@ -66412,9 +66458,9 @@ var require_cache_handler = __commonJS({
|
|
|
66412
66458
|
}
|
|
66413
66459
|
const values = Array.isArray(headerValue) ? headerValue : [headerValue];
|
|
66414
66460
|
for (let i = 0; i < values.length; i++) {
|
|
66415
|
-
const
|
|
66416
|
-
if (
|
|
66417
|
-
deleteCachedUri(store, cacheKey,
|
|
66461
|
+
const path114 = getSameOriginPath(cacheKey, values[i]);
|
|
66462
|
+
if (path114 !== void 0) {
|
|
66463
|
+
deleteCachedUri(store, cacheKey, path114);
|
|
66418
66464
|
}
|
|
66419
66465
|
}
|
|
66420
66466
|
}
|
|
@@ -71637,11 +71683,11 @@ var require_fetch = __commonJS({
|
|
|
71637
71683
|
function dispatch({ body }) {
|
|
71638
71684
|
const url = requestCurrentURL(request2);
|
|
71639
71685
|
const agent = fetchParams.controller.dispatcher;
|
|
71640
|
-
const
|
|
71686
|
+
const path114 = url.pathname + url.search;
|
|
71641
71687
|
const hasTrailingQuestionMark = url.search.length === 0 && url.href[url.href.length - url.hash.length - 1] === "?";
|
|
71642
71688
|
return new Promise((resolve2, reject) => agent.dispatch(
|
|
71643
71689
|
{
|
|
71644
|
-
path: hasTrailingQuestionMark ? `${
|
|
71690
|
+
path: hasTrailingQuestionMark ? `${path114}?` : path114,
|
|
71645
71691
|
origin: url.origin,
|
|
71646
71692
|
method: request2.method,
|
|
71647
71693
|
body: agent.isMockActive ? request2.body && (request2.body.source || request2.body.stream) : body,
|
|
@@ -72593,9 +72639,9 @@ var require_util4 = __commonJS({
|
|
|
72593
72639
|
}
|
|
72594
72640
|
}
|
|
72595
72641
|
}
|
|
72596
|
-
function validateCookiePath(
|
|
72597
|
-
for (let i = 0; i <
|
|
72598
|
-
const code2 =
|
|
72642
|
+
function validateCookiePath(path114) {
|
|
72643
|
+
for (let i = 0; i < path114.length; ++i) {
|
|
72644
|
+
const code2 = path114.charCodeAt(i);
|
|
72599
72645
|
if (code2 < 32 || // exclude CTLs (0-31)
|
|
72600
72646
|
code2 > 126 || // exclude DEL and non-ascii
|
|
72601
72647
|
code2 === 59) {
|
|
@@ -76048,11 +76094,11 @@ var require_undici = __commonJS({
|
|
|
76048
76094
|
if (typeof opts.path !== "string") {
|
|
76049
76095
|
throw new InvalidArgumentError("invalid opts.path");
|
|
76050
76096
|
}
|
|
76051
|
-
let
|
|
76097
|
+
let path114 = opts.path;
|
|
76052
76098
|
if (!opts.path.startsWith("/")) {
|
|
76053
|
-
|
|
76099
|
+
path114 = `/${path114}`;
|
|
76054
76100
|
}
|
|
76055
|
-
url = new URL(util.parseOrigin(url).origin +
|
|
76101
|
+
url = new URL(util.parseOrigin(url).origin + path114);
|
|
76056
76102
|
} else {
|
|
76057
76103
|
if (!opts) {
|
|
76058
76104
|
opts = typeof url === "object" ? url : {};
|
|
@@ -76174,10 +76220,10 @@ function readFirstRunEnv() {
|
|
|
76174
76220
|
stdinTTY: !!process.stdin.isTTY,
|
|
76175
76221
|
stdoutTTY: !!process.stdout.isTTY,
|
|
76176
76222
|
ci: isCI() || process.env.NODE9_NONINTERACTIVE === "1",
|
|
76177
|
-
hasConfig:
|
|
76223
|
+
hasConfig: import_fs107.default.existsSync(import_path106.default.join(import_os87.default.homedir(), ".node9/config.json")),
|
|
76178
76224
|
// Any stored profile means this is not a never-configured machine. Treat
|
|
76179
76225
|
// malformed credential files conservatively and leave repair to explicit setup.
|
|
76180
|
-
hasCredentials: !!getCredentials() ||
|
|
76226
|
+
hasCredentials: !!getCredentials() || import_fs107.default.existsSync(import_path106.default.join(import_os87.default.homedir(), ".node9/credentials.json"))
|
|
76181
76227
|
};
|
|
76182
76228
|
}
|
|
76183
76229
|
function shouldOfferFirstRun(env) {
|
|
@@ -76282,14 +76328,14 @@ async function runSetupWizard(opts) {
|
|
|
76282
76328
|
process.exitCode = 130;
|
|
76283
76329
|
}
|
|
76284
76330
|
}
|
|
76285
|
-
var
|
|
76331
|
+
var import_fs107, import_os87, import_path106;
|
|
76286
76332
|
var init_first_run = __esm({
|
|
76287
76333
|
"src/cli/first-run.ts"() {
|
|
76288
76334
|
"use strict";
|
|
76289
76335
|
init_cjs_shims();
|
|
76290
|
-
|
|
76291
|
-
|
|
76292
|
-
|
|
76336
|
+
import_fs107 = __toESM(require("fs"));
|
|
76337
|
+
import_os87 = __toESM(require("os"));
|
|
76338
|
+
import_path106 = __toESM(require("path"));
|
|
76293
76339
|
init_config();
|
|
76294
76340
|
init_agent_wiring();
|
|
76295
76341
|
init_browser_login();
|
|
@@ -76335,20 +76381,20 @@ function getModelContextLimit(model) {
|
|
|
76335
76381
|
return 2e5;
|
|
76336
76382
|
}
|
|
76337
76383
|
function readSessionUsage() {
|
|
76338
|
-
const projectsDir =
|
|
76339
|
-
if (!
|
|
76384
|
+
const projectsDir = import_path107.default.join(import_os88.default.homedir(), ".claude", "projects");
|
|
76385
|
+
if (!import_fs108.default.existsSync(projectsDir)) return null;
|
|
76340
76386
|
let latestFile = null;
|
|
76341
76387
|
let latestMtime = 0;
|
|
76342
76388
|
try {
|
|
76343
|
-
for (const dir2 of
|
|
76344
|
-
const dirPath =
|
|
76389
|
+
for (const dir2 of import_fs108.default.readdirSync(projectsDir)) {
|
|
76390
|
+
const dirPath = import_path107.default.join(projectsDir, dir2);
|
|
76345
76391
|
try {
|
|
76346
|
-
if (!
|
|
76347
|
-
for (const file2 of
|
|
76392
|
+
if (!import_fs108.default.statSync(dirPath).isDirectory()) continue;
|
|
76393
|
+
for (const file2 of import_fs108.default.readdirSync(dirPath)) {
|
|
76348
76394
|
if (!file2.endsWith(".jsonl") || file2.startsWith("agent-")) continue;
|
|
76349
|
-
const filePath =
|
|
76395
|
+
const filePath = import_path107.default.join(dirPath, file2);
|
|
76350
76396
|
try {
|
|
76351
|
-
const mtime =
|
|
76397
|
+
const mtime = import_fs108.default.statSync(filePath).mtimeMs;
|
|
76352
76398
|
if (mtime > latestMtime) {
|
|
76353
76399
|
latestMtime = mtime;
|
|
76354
76400
|
latestFile = filePath;
|
|
@@ -76363,7 +76409,7 @@ function readSessionUsage() {
|
|
|
76363
76409
|
}
|
|
76364
76410
|
if (!latestFile) return null;
|
|
76365
76411
|
try {
|
|
76366
|
-
const lines =
|
|
76412
|
+
const lines = import_fs108.default.readFileSync(latestFile, "utf-8").split("\n");
|
|
76367
76413
|
let lastModel = "";
|
|
76368
76414
|
let lastInput = 0;
|
|
76369
76415
|
let lastOutput = 0;
|
|
@@ -76424,7 +76470,7 @@ function formatBase(activity) {
|
|
|
76424
76470
|
const time = new Date(activity.ts).toLocaleTimeString([], { hour12: false });
|
|
76425
76471
|
const icon = getIcon(activity.tool);
|
|
76426
76472
|
const toolName = activity.tool.slice(0, 16).padEnd(16);
|
|
76427
|
-
const argsStr = JSON.stringify(activity.args ?? {}).replace(/\s+/g, " ").replaceAll(
|
|
76473
|
+
const argsStr = JSON.stringify(activity.args ?? {}).replace(/\s+/g, " ").replaceAll(import_os88.default.homedir(), "~");
|
|
76428
76474
|
const argsPreview = argsStr.length > 70 ? argsStr.slice(0, 70) + "\u2026" : argsStr;
|
|
76429
76475
|
return `${import_chalk49.default.gray(time)} ${icon} ${agentLabel(activity.agent, activity.mcpServer, activity.sessionId)}${import_chalk49.default.white.bold(toolName)} ${import_chalk49.default.dim(argsPreview)}`;
|
|
76430
76476
|
}
|
|
@@ -76442,12 +76488,12 @@ function renderResult(activity, result) {
|
|
|
76442
76488
|
const costSuffix = cost == null ? "" : import_chalk49.default.dim(` ~$${cost >= 1e-3 ? cost.toFixed(3) : "0.000"}`);
|
|
76443
76489
|
if (process.stdout.isTTY) {
|
|
76444
76490
|
if (pendingShownForId === activity.id && pendingWrappedLines > 1) {
|
|
76445
|
-
|
|
76446
|
-
|
|
76491
|
+
import_readline6.default.moveCursor(process.stdout, 0, -(pendingWrappedLines - 1));
|
|
76492
|
+
import_readline6.default.cursorTo(process.stdout, 0);
|
|
76447
76493
|
process.stdout.write(ERASE_DOWN);
|
|
76448
76494
|
} else {
|
|
76449
|
-
|
|
76450
|
-
|
|
76495
|
+
import_readline6.default.clearLine(process.stdout, 0);
|
|
76496
|
+
import_readline6.default.cursorTo(process.stdout, 0);
|
|
76451
76497
|
}
|
|
76452
76498
|
pendingShownForId = null;
|
|
76453
76499
|
pendingWrappedLines = 0;
|
|
@@ -76463,9 +76509,9 @@ function renderPending(activity) {
|
|
|
76463
76509
|
}
|
|
76464
76510
|
async function ensureDaemon() {
|
|
76465
76511
|
let pidPort = null;
|
|
76466
|
-
if (
|
|
76512
|
+
if (import_fs108.default.existsSync(PID_FILE)) {
|
|
76467
76513
|
try {
|
|
76468
|
-
const { port } = JSON.parse(
|
|
76514
|
+
const { port } = JSON.parse(import_fs108.default.readFileSync(PID_FILE, "utf-8"));
|
|
76469
76515
|
pidPort = port;
|
|
76470
76516
|
} catch {
|
|
76471
76517
|
console.error(import_chalk49.default.dim("\u26A0\uFE0F Could not read PID file; falling back to default port."));
|
|
@@ -76491,7 +76537,7 @@ async function ensureDaemon() {
|
|
|
76491
76537
|
child.unref();
|
|
76492
76538
|
if (startupFd !== void 0) {
|
|
76493
76539
|
try {
|
|
76494
|
-
|
|
76540
|
+
import_fs108.default.closeSync(startupFd);
|
|
76495
76541
|
} catch {
|
|
76496
76542
|
}
|
|
76497
76543
|
}
|
|
@@ -76735,7 +76781,7 @@ async function startTail(options = {}) {
|
|
|
76735
76781
|
let cancelActiveCard = null;
|
|
76736
76782
|
const localAllowCounts = /* @__PURE__ */ new Map();
|
|
76737
76783
|
const canApprove = process.stdout.isTTY && process.stdin.isTTY;
|
|
76738
|
-
if (canApprove)
|
|
76784
|
+
if (canApprove) import_readline6.default.emitKeypressEvents(process.stdin);
|
|
76739
76785
|
let idleKeypressHandler = null;
|
|
76740
76786
|
function enterIdleMode() {
|
|
76741
76787
|
if (!canApprove || idleKeypressHandler !== null) return;
|
|
@@ -76776,7 +76822,7 @@ async function startTail(options = {}) {
|
|
|
76776
76822
|
}
|
|
76777
76823
|
function clearCard() {
|
|
76778
76824
|
if (cardLineCount > 0) {
|
|
76779
|
-
|
|
76825
|
+
import_readline6.default.moveCursor(process.stdout, 0, -cardLineCount);
|
|
76780
76826
|
process.stdout.write(ERASE_DOWN);
|
|
76781
76827
|
cardLineCount = 0;
|
|
76782
76828
|
}
|
|
@@ -76861,8 +76907,8 @@ async function startTail(options = {}) {
|
|
|
76861
76907
|
);
|
|
76862
76908
|
}).catch((err2) => {
|
|
76863
76909
|
try {
|
|
76864
|
-
|
|
76865
|
-
|
|
76910
|
+
import_fs108.default.appendFileSync(
|
|
76911
|
+
import_path107.default.join(import_os88.default.homedir(), ".node9", "hook-debug.log"),
|
|
76866
76912
|
`[tail] POST /decision failed: ${String(err2)}
|
|
76867
76913
|
`
|
|
76868
76914
|
);
|
|
@@ -76928,9 +76974,9 @@ async function startTail(options = {}) {
|
|
|
76928
76974
|
};
|
|
76929
76975
|
process.stdin.on("keypress", onKeypress);
|
|
76930
76976
|
}
|
|
76931
|
-
const auditLog =
|
|
76977
|
+
const auditLog = import_path107.default.join(import_os88.default.homedir(), ".node9", "audit.log");
|
|
76932
76978
|
try {
|
|
76933
|
-
const unackedDlp =
|
|
76979
|
+
const unackedDlp = import_fs108.default.readFileSync(auditLog, "utf-8").split("\n").filter((l) => l.includes('"response-dlp"')).length;
|
|
76934
76980
|
if (unackedDlp > 0) {
|
|
76935
76981
|
console.log("");
|
|
76936
76982
|
console.log(
|
|
@@ -76959,8 +77005,8 @@ async function startTail(options = {}) {
|
|
|
76959
77005
|
clearCard();
|
|
76960
77006
|
process.stdout.write(SHOW_CURSOR);
|
|
76961
77007
|
if (process.stdout.isTTY) {
|
|
76962
|
-
|
|
76963
|
-
|
|
77008
|
+
import_readline6.default.clearLine(process.stdout, 0);
|
|
77009
|
+
import_readline6.default.cursorTo(process.stdout, 0);
|
|
76964
77010
|
}
|
|
76965
77011
|
console.log(import_chalk49.default.dim("\n\u{1F6F0}\uFE0F Disconnected."));
|
|
76966
77012
|
process.exit(0);
|
|
@@ -76970,7 +77016,7 @@ async function startTail(options = {}) {
|
|
|
76970
77016
|
if (stallWarned) return;
|
|
76971
77017
|
if (Date.now() - lastActivityFromDaemon < STALL_THRESHOLD_MS) return;
|
|
76972
77018
|
try {
|
|
76973
|
-
const auditMtime =
|
|
77019
|
+
const auditMtime = import_fs108.default.statSync(auditLog).mtimeMs;
|
|
76974
77020
|
if (Date.now() - auditMtime >= STALL_THRESHOLD_MS) return;
|
|
76975
77021
|
console.log("");
|
|
76976
77022
|
console.log(
|
|
@@ -76999,7 +77045,7 @@ async function startTail(options = {}) {
|
|
|
76999
77045
|
let currentData = "";
|
|
77000
77046
|
res.on("error", () => {
|
|
77001
77047
|
});
|
|
77002
|
-
const rl =
|
|
77048
|
+
const rl = import_readline6.default.createInterface({ input: res, crlfDelay: Infinity });
|
|
77003
77049
|
rl.on("error", () => {
|
|
77004
77050
|
});
|
|
77005
77051
|
rl.on("line", (line) => {
|
|
@@ -77019,8 +77065,8 @@ async function startTail(options = {}) {
|
|
|
77019
77065
|
clearCard();
|
|
77020
77066
|
process.stdout.write(SHOW_CURSOR);
|
|
77021
77067
|
if (process.stdout.isTTY) {
|
|
77022
|
-
|
|
77023
|
-
|
|
77068
|
+
import_readline6.default.clearLine(process.stdout, 0);
|
|
77069
|
+
import_readline6.default.cursorTo(process.stdout, 0);
|
|
77024
77070
|
}
|
|
77025
77071
|
console.log(import_chalk49.default.red("\n\u274C Daemon disconnected."));
|
|
77026
77072
|
process.exit(1);
|
|
@@ -77142,7 +77188,7 @@ async function startTail(options = {}) {
|
|
|
77142
77188
|
process.exit(1);
|
|
77143
77189
|
});
|
|
77144
77190
|
}
|
|
77145
|
-
var import_http6, import_chalk49,
|
|
77191
|
+
var import_http6, import_chalk49, import_fs108, import_os88, import_path107, import_readline6, import_child_process17, PID_FILE, ICONS, MODEL_CONTEXT_LIMITS, RESET, BOLD, RED, YELLOW, CYAN, GRAY, GREEN, HIDE_CURSOR, SHOW_CURSOR, ERASE_DOWN, pendingShownForId, pendingWrappedLines, DIVIDER;
|
|
77146
77192
|
var init_tail = __esm({
|
|
77147
77193
|
"src/tui/tail.ts"() {
|
|
77148
77194
|
"use strict";
|
|
@@ -77150,16 +77196,16 @@ var init_tail = __esm({
|
|
|
77150
77196
|
import_http6 = __toESM(require("http"));
|
|
77151
77197
|
init_write();
|
|
77152
77198
|
import_chalk49 = __toESM(require("chalk"));
|
|
77153
|
-
|
|
77154
|
-
|
|
77155
|
-
|
|
77156
|
-
|
|
77199
|
+
import_fs108 = __toESM(require("fs"));
|
|
77200
|
+
import_os88 = __toESM(require("os"));
|
|
77201
|
+
import_path107 = __toESM(require("path"));
|
|
77202
|
+
import_readline6 = __toESM(require("readline"));
|
|
77157
77203
|
import_child_process17 = require("child_process");
|
|
77158
77204
|
init_startup_log();
|
|
77159
77205
|
init_daemon3();
|
|
77160
77206
|
init_daemon();
|
|
77161
77207
|
init_safe_text();
|
|
77162
|
-
PID_FILE =
|
|
77208
|
+
PID_FILE = import_path107.default.join(import_os88.default.homedir(), ".node9", "daemon.pid");
|
|
77163
77209
|
ICONS = {
|
|
77164
77210
|
bash: "\u{1F4BB}",
|
|
77165
77211
|
shell: "\u{1F4BB}",
|
|
@@ -77281,9 +77327,9 @@ function formatTimeLeft(resetsAt) {
|
|
|
77281
77327
|
return ` (${m}m left)`;
|
|
77282
77328
|
}
|
|
77283
77329
|
function safeReadJson(filePath) {
|
|
77284
|
-
if (!
|
|
77330
|
+
if (!import_fs109.default.existsSync(filePath)) return null;
|
|
77285
77331
|
try {
|
|
77286
|
-
return JSON.parse(
|
|
77332
|
+
return JSON.parse(import_fs109.default.readFileSync(filePath, "utf-8"));
|
|
77287
77333
|
} catch {
|
|
77288
77334
|
return null;
|
|
77289
77335
|
}
|
|
@@ -77304,12 +77350,12 @@ function countHooksInFile(filePath) {
|
|
|
77304
77350
|
return Object.keys(cfg.hooks).length;
|
|
77305
77351
|
}
|
|
77306
77352
|
function countRulesInDir(rulesDir) {
|
|
77307
|
-
if (!
|
|
77353
|
+
if (!import_fs109.default.existsSync(rulesDir)) return 0;
|
|
77308
77354
|
let count = 0;
|
|
77309
77355
|
try {
|
|
77310
|
-
for (const entry of
|
|
77356
|
+
for (const entry of import_fs109.default.readdirSync(rulesDir, { withFileTypes: true })) {
|
|
77311
77357
|
if (entry.isDirectory()) {
|
|
77312
|
-
count += countRulesInDir(
|
|
77358
|
+
count += countRulesInDir(import_path108.default.join(rulesDir, entry.name));
|
|
77313
77359
|
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
77314
77360
|
count++;
|
|
77315
77361
|
}
|
|
@@ -77320,46 +77366,46 @@ function countRulesInDir(rulesDir) {
|
|
|
77320
77366
|
}
|
|
77321
77367
|
function isSamePath(a, b) {
|
|
77322
77368
|
try {
|
|
77323
|
-
return
|
|
77369
|
+
return import_path108.default.resolve(a) === import_path108.default.resolve(b);
|
|
77324
77370
|
} catch {
|
|
77325
77371
|
return false;
|
|
77326
77372
|
}
|
|
77327
77373
|
}
|
|
77328
77374
|
function countConfigs(cwd) {
|
|
77329
|
-
const homeDir2 =
|
|
77330
|
-
const claudeDir =
|
|
77375
|
+
const homeDir2 = import_os89.default.homedir();
|
|
77376
|
+
const claudeDir = import_path108.default.join(homeDir2, ".claude");
|
|
77331
77377
|
let claudeMdCount = 0;
|
|
77332
77378
|
let rulesCount = 0;
|
|
77333
77379
|
let hooksCount = 0;
|
|
77334
77380
|
const userMcpServers = /* @__PURE__ */ new Set();
|
|
77335
77381
|
const projectMcpServers = /* @__PURE__ */ new Set();
|
|
77336
|
-
if (
|
|
77337
|
-
rulesCount += countRulesInDir(
|
|
77338
|
-
const userSettings =
|
|
77382
|
+
if (import_fs109.default.existsSync(import_path108.default.join(claudeDir, "CLAUDE.md"))) claudeMdCount++;
|
|
77383
|
+
rulesCount += countRulesInDir(import_path108.default.join(claudeDir, "rules"));
|
|
77384
|
+
const userSettings = import_path108.default.join(claudeDir, "settings.json");
|
|
77339
77385
|
for (const name of getMcpServerNames(userSettings)) userMcpServers.add(name);
|
|
77340
77386
|
hooksCount += countHooksInFile(userSettings);
|
|
77341
|
-
const userClaudeJson =
|
|
77387
|
+
const userClaudeJson = import_path108.default.join(homeDir2, ".claude.json");
|
|
77342
77388
|
for (const name of getMcpServerNames(userClaudeJson)) userMcpServers.add(name);
|
|
77343
77389
|
for (const name of getDisabledMcpServers(userClaudeJson, "disabledMcpServers")) {
|
|
77344
77390
|
userMcpServers.delete(name);
|
|
77345
77391
|
}
|
|
77346
77392
|
if (cwd) {
|
|
77347
|
-
if (
|
|
77348
|
-
if (
|
|
77349
|
-
const projectClaudeDir =
|
|
77393
|
+
if (import_fs109.default.existsSync(import_path108.default.join(cwd, "CLAUDE.md"))) claudeMdCount++;
|
|
77394
|
+
if (import_fs109.default.existsSync(import_path108.default.join(cwd, "CLAUDE.local.md"))) claudeMdCount++;
|
|
77395
|
+
const projectClaudeDir = import_path108.default.join(cwd, ".claude");
|
|
77350
77396
|
const overlapsUserScope = isSamePath(projectClaudeDir, claudeDir);
|
|
77351
77397
|
if (!overlapsUserScope) {
|
|
77352
|
-
if (
|
|
77353
|
-
rulesCount += countRulesInDir(
|
|
77354
|
-
const projSettings =
|
|
77398
|
+
if (import_fs109.default.existsSync(import_path108.default.join(projectClaudeDir, "CLAUDE.md"))) claudeMdCount++;
|
|
77399
|
+
rulesCount += countRulesInDir(import_path108.default.join(projectClaudeDir, "rules"));
|
|
77400
|
+
const projSettings = import_path108.default.join(projectClaudeDir, "settings.json");
|
|
77355
77401
|
for (const name of getMcpServerNames(projSettings)) projectMcpServers.add(name);
|
|
77356
77402
|
hooksCount += countHooksInFile(projSettings);
|
|
77357
77403
|
}
|
|
77358
|
-
if (
|
|
77359
|
-
const localSettings =
|
|
77404
|
+
if (import_fs109.default.existsSync(import_path108.default.join(projectClaudeDir, "CLAUDE.local.md"))) claudeMdCount++;
|
|
77405
|
+
const localSettings = import_path108.default.join(projectClaudeDir, "settings.local.json");
|
|
77360
77406
|
for (const name of getMcpServerNames(localSettings)) projectMcpServers.add(name);
|
|
77361
77407
|
hooksCount += countHooksInFile(localSettings);
|
|
77362
|
-
const mcpJsonServers = getMcpServerNames(
|
|
77408
|
+
const mcpJsonServers = getMcpServerNames(import_path108.default.join(cwd, ".mcp.json"));
|
|
77363
77409
|
const disabledMcpJson = getDisabledMcpServers(localSettings, "disabledMcpjsonServers");
|
|
77364
77410
|
for (const name of disabledMcpJson) mcpJsonServers.delete(name);
|
|
77365
77411
|
for (const name of mcpJsonServers) projectMcpServers.add(name);
|
|
@@ -77392,12 +77438,12 @@ function readActiveShieldsHud() {
|
|
|
77392
77438
|
return shieldsCache.value;
|
|
77393
77439
|
}
|
|
77394
77440
|
try {
|
|
77395
|
-
const shieldsPath =
|
|
77396
|
-
if (!
|
|
77441
|
+
const shieldsPath = import_path108.default.join(import_os89.default.homedir(), ".node9", "shields.json");
|
|
77442
|
+
if (!import_fs109.default.existsSync(shieldsPath)) {
|
|
77397
77443
|
shieldsCache = { value: [], ts: now };
|
|
77398
77444
|
return [];
|
|
77399
77445
|
}
|
|
77400
|
-
const parsed = JSON.parse(
|
|
77446
|
+
const parsed = JSON.parse(import_fs109.default.readFileSync(shieldsPath, "utf-8"));
|
|
77401
77447
|
if (!Array.isArray(parsed.active)) {
|
|
77402
77448
|
shieldsCache = { value: [], ts: now };
|
|
77403
77449
|
return [];
|
|
@@ -77499,17 +77545,17 @@ function renderContextLine(stdin) {
|
|
|
77499
77545
|
async function main() {
|
|
77500
77546
|
try {
|
|
77501
77547
|
const [stdin, daemonStatus2] = await Promise.all([readStdin(), queryDaemon()]);
|
|
77502
|
-
if (
|
|
77548
|
+
if (import_fs109.default.existsSync(import_path108.default.join(import_os89.default.homedir(), ".node9", "hud-debug"))) {
|
|
77503
77549
|
try {
|
|
77504
|
-
const logPath =
|
|
77550
|
+
const logPath = import_path108.default.join(import_os89.default.homedir(), ".node9", "hud-debug.log");
|
|
77505
77551
|
const MAX_LOG_SIZE = 10 * 1024 * 1024;
|
|
77506
77552
|
let size = 0;
|
|
77507
77553
|
try {
|
|
77508
|
-
size =
|
|
77554
|
+
size = import_fs109.default.statSync(logPath).size;
|
|
77509
77555
|
} catch {
|
|
77510
77556
|
}
|
|
77511
77557
|
if (size < MAX_LOG_SIZE) {
|
|
77512
|
-
|
|
77558
|
+
import_fs109.default.appendFileSync(
|
|
77513
77559
|
logPath,
|
|
77514
77560
|
JSON.stringify({ ts: (/* @__PURE__ */ new Date()).toISOString(), stdin }) + "\n"
|
|
77515
77561
|
);
|
|
@@ -77530,11 +77576,11 @@ async function main() {
|
|
|
77530
77576
|
try {
|
|
77531
77577
|
const cwd = stdin.cwd ?? process.cwd();
|
|
77532
77578
|
for (const configPath2 of [
|
|
77533
|
-
|
|
77534
|
-
|
|
77579
|
+
import_path108.default.join(cwd, "node9.config.json"),
|
|
77580
|
+
import_path108.default.join(import_os89.default.homedir(), ".node9", "config.json")
|
|
77535
77581
|
]) {
|
|
77536
|
-
if (!
|
|
77537
|
-
const cfg = JSON.parse(
|
|
77582
|
+
if (!import_fs109.default.existsSync(configPath2)) continue;
|
|
77583
|
+
const cfg = JSON.parse(import_fs109.default.readFileSync(configPath2, "utf-8"));
|
|
77538
77584
|
const hud = cfg.settings?.hud;
|
|
77539
77585
|
if (hud && "showEnvironmentCounts" in hud) return hud.showEnvironmentCounts !== false;
|
|
77540
77586
|
}
|
|
@@ -77552,14 +77598,14 @@ async function main() {
|
|
|
77552
77598
|
renderOffline();
|
|
77553
77599
|
}
|
|
77554
77600
|
}
|
|
77555
|
-
var
|
|
77601
|
+
var import_fs109, import_path108, import_os89, import_http7, RESET2, BOLD2, DIM, RED2, GREEN2, YELLOW2, BLUE, MAGENTA, CYAN2, WHITE, BAR_FILLED, BAR_EMPTY, BAR_WIDTH, shieldsCache, SHIELDS_CACHE_TTL_MS;
|
|
77556
77602
|
var init_hud = __esm({
|
|
77557
77603
|
"src/cli/hud.ts"() {
|
|
77558
77604
|
"use strict";
|
|
77559
77605
|
init_cjs_shims();
|
|
77560
|
-
|
|
77561
|
-
|
|
77562
|
-
|
|
77606
|
+
import_fs109 = __toESM(require("fs"));
|
|
77607
|
+
import_path108 = __toESM(require("path"));
|
|
77608
|
+
import_os89 = __toESM(require("os"));
|
|
77563
77609
|
import_http7 = __toESM(require("http"));
|
|
77564
77610
|
init_daemon();
|
|
77565
77611
|
init_dist();
|
|
@@ -77624,9 +77670,9 @@ init_agent_wiring();
|
|
|
77624
77670
|
init_credentials();
|
|
77625
77671
|
init_daemon3();
|
|
77626
77672
|
var import_chalk50 = __toESM(require("chalk"));
|
|
77627
|
-
var
|
|
77628
|
-
var
|
|
77629
|
-
var
|
|
77673
|
+
var import_fs110 = __toESM(require("fs"));
|
|
77674
|
+
var import_path109 = __toESM(require("path"));
|
|
77675
|
+
var import_os90 = __toESM(require("os"));
|
|
77630
77676
|
var import_prompts4 = require("@inquirer/prompts");
|
|
77631
77677
|
|
|
77632
77678
|
// src/utils/duration.ts
|
|
@@ -78697,6 +78743,7 @@ init_audit();
|
|
|
78697
78743
|
init_config();
|
|
78698
78744
|
init_daemon();
|
|
78699
78745
|
init_dist();
|
|
78746
|
+
init_shell_fetch();
|
|
78700
78747
|
|
|
78701
78748
|
// src/exposure/source.ts
|
|
78702
78749
|
init_cjs_shims();
|
|
@@ -78921,11 +78968,6 @@ function buildArgsField(rawInput) {
|
|
|
78921
78968
|
return hashed;
|
|
78922
78969
|
}
|
|
78923
78970
|
}
|
|
78924
|
-
function shellFetch(tool, rawInput) {
|
|
78925
|
-
if (tool !== "Bash" && tool !== "bash") return null;
|
|
78926
|
-
const cmd = rawInput && typeof rawInput === "object" && !Array.isArray(rawInput) ? rawInput.command : void 0;
|
|
78927
|
-
return typeof cmd === "string" && cmd.length > 0 ? classifyShellExposure(cmd) : null;
|
|
78928
|
-
}
|
|
78929
78971
|
function registerLogCommand(program2) {
|
|
78930
78972
|
program2.command("log", { hidden: true }).description("PostToolUse hook \u2014 records executed tool calls").argument("[data]", "JSON string of the tool call").option(
|
|
78931
78973
|
"--agent <name>",
|
|
@@ -85566,6 +85608,373 @@ function registerAgentsCommand(program2) {
|
|
|
85566
85608
|
// src/cli.ts
|
|
85567
85609
|
init_scan();
|
|
85568
85610
|
|
|
85611
|
+
// src/cli/commands/forecast-cases.ts
|
|
85612
|
+
init_cjs_shims();
|
|
85613
|
+
var import_fs96 = __toESM(require("fs"));
|
|
85614
|
+
var import_os80 = __toESM(require("os"));
|
|
85615
|
+
var import_path95 = __toESM(require("path"));
|
|
85616
|
+
var import_readline5 = __toESM(require("readline"));
|
|
85617
|
+
init_dist();
|
|
85618
|
+
init_config();
|
|
85619
|
+
init_forecast();
|
|
85620
|
+
init_scan_judge();
|
|
85621
|
+
init_dlp();
|
|
85622
|
+
init_jail();
|
|
85623
|
+
init_registry2();
|
|
85624
|
+
init_version();
|
|
85625
|
+
init_sync();
|
|
85626
|
+
function materialize(t, env) {
|
|
85627
|
+
if (typeof t === "string")
|
|
85628
|
+
return t.replaceAll("{{HOME}}", env.home).replaceAll("{{CWD}}", env.cwd);
|
|
85629
|
+
if (t === null || typeof t !== "object") return t;
|
|
85630
|
+
if (Array.isArray(t)) return t.map((x) => materialize(x, env));
|
|
85631
|
+
const o = t;
|
|
85632
|
+
const keys = Object.keys(o);
|
|
85633
|
+
if (keys.length === 1 && keys[0] === "$join" && Array.isArray(o.$join))
|
|
85634
|
+
return materialize(o.$join.join(""), env);
|
|
85635
|
+
const out = {};
|
|
85636
|
+
for (const [k, v] of Object.entries(o)) out[k] = materialize(v, env);
|
|
85637
|
+
return out;
|
|
85638
|
+
}
|
|
85639
|
+
var PROFILE_NEEDS = {
|
|
85640
|
+
clean: null,
|
|
85641
|
+
"asb-sandbox": null,
|
|
85642
|
+
"git-guardrails": null,
|
|
85643
|
+
"jailed-agent": "user-jail-path",
|
|
85644
|
+
"user-jail": "user-jail-path",
|
|
85645
|
+
"org-jail": "managed-jail-path",
|
|
85646
|
+
canary: "decoy",
|
|
85647
|
+
"egress-lock": "egress-block",
|
|
85648
|
+
"egress-watch": "egress-gated",
|
|
85649
|
+
"exposure-org": "organisation-domain",
|
|
85650
|
+
"ask-before-dangerous-actions": "hold-action-checks",
|
|
85651
|
+
"injection-optin": "injection-scan"
|
|
85652
|
+
};
|
|
85653
|
+
function profileNeed(setup) {
|
|
85654
|
+
if (setup in PROFILE_NEEDS) return PROFILE_NEEDS[setup];
|
|
85655
|
+
if (setup.startsWith("egress-deny-")) return "egress-deny-list";
|
|
85656
|
+
return void 0;
|
|
85657
|
+
}
|
|
85658
|
+
function homeHas(config) {
|
|
85659
|
+
const settings = catalogSettingsFrom(config.settings, config.policy);
|
|
85660
|
+
const value = (id) => checkValue(settings, id);
|
|
85661
|
+
const egress = config.policy.egress;
|
|
85662
|
+
const gated = !!egress?.enabled && (egress.mode === "block" || egress.mode === "review");
|
|
85663
|
+
let userJail = false;
|
|
85664
|
+
try {
|
|
85665
|
+
userJail = readJailPaths().length > 0;
|
|
85666
|
+
} catch {
|
|
85667
|
+
userJail = false;
|
|
85668
|
+
}
|
|
85669
|
+
let decoy = false;
|
|
85670
|
+
try {
|
|
85671
|
+
decoy = loadCanaries().length > 0;
|
|
85672
|
+
} catch {
|
|
85673
|
+
decoy = false;
|
|
85674
|
+
}
|
|
85675
|
+
const held = (id) => value(id) === "review" || value(id) === "block";
|
|
85676
|
+
return {
|
|
85677
|
+
"user-jail-path": userJail,
|
|
85678
|
+
"managed-jail-path": (config.policy.managedJailPaths ?? []).length > 0,
|
|
85679
|
+
decoy,
|
|
85680
|
+
"egress-block": !!egress?.enabled && egress.mode === "block",
|
|
85681
|
+
"egress-gated": gated,
|
|
85682
|
+
"egress-deny-list": gated && (egress?.deny?.length ?? 0) > 0,
|
|
85683
|
+
"organisation-domain": (config.policy.untrustedContent?.orgDomains ?? []).length > 0,
|
|
85684
|
+
"hold-action-checks": held("actions.money") && held("actions.access") && held("actions.publish"),
|
|
85685
|
+
"injection-scan": value("behavior.prompt-injection") !== "off"
|
|
85686
|
+
};
|
|
85687
|
+
}
|
|
85688
|
+
var emptyCell = () => ({
|
|
85689
|
+
attacks: 0,
|
|
85690
|
+
stopped: 0,
|
|
85691
|
+
loggedOnly: 0,
|
|
85692
|
+
passed: 0,
|
|
85693
|
+
benign: 0,
|
|
85694
|
+
interrupted: 0,
|
|
85695
|
+
notApplicable: 0,
|
|
85696
|
+
notSimulated: 0,
|
|
85697
|
+
volatile: 0,
|
|
85698
|
+
undetermined: 0,
|
|
85699
|
+
errors: 0
|
|
85700
|
+
});
|
|
85701
|
+
function summarize(results, config) {
|
|
85702
|
+
const settings = catalogSettingsFrom(config.settings, config.policy);
|
|
85703
|
+
const byRisk = {};
|
|
85704
|
+
const passedByCheck = {};
|
|
85705
|
+
const passedUnattributed = {};
|
|
85706
|
+
const notApplicableBy = {};
|
|
85707
|
+
const cell = (r) => {
|
|
85708
|
+
const risk = byRisk[r.owasp] ??= {
|
|
85709
|
+
headline: emptyCell(),
|
|
85710
|
+
vendor: emptyCell(),
|
|
85711
|
+
unknown: emptyCell()
|
|
85712
|
+
};
|
|
85713
|
+
return risk[r.section];
|
|
85714
|
+
};
|
|
85715
|
+
for (const r of results) {
|
|
85716
|
+
const c = cell(r);
|
|
85717
|
+
if (r.error) {
|
|
85718
|
+
c.errors++;
|
|
85719
|
+
continue;
|
|
85720
|
+
}
|
|
85721
|
+
if (r.notApplicable) {
|
|
85722
|
+
c.notApplicable++;
|
|
85723
|
+
notApplicableBy[r.notApplicable] = (notApplicableBy[r.notApplicable] ?? 0) + 1;
|
|
85724
|
+
continue;
|
|
85725
|
+
}
|
|
85726
|
+
if (r.notSimulated) {
|
|
85727
|
+
c.notSimulated++;
|
|
85728
|
+
continue;
|
|
85729
|
+
}
|
|
85730
|
+
if (r.volatile) {
|
|
85731
|
+
c.volatile++;
|
|
85732
|
+
continue;
|
|
85733
|
+
}
|
|
85734
|
+
const stopped = r.enforced === true && (r.decision === "review" || r.decision === "block");
|
|
85735
|
+
const recorded = !stopped && r.decision !== void 0 && r.decision !== "allow";
|
|
85736
|
+
if (r.expected === "allow") {
|
|
85737
|
+
c.benign++;
|
|
85738
|
+
if (stopped) c.interrupted++;
|
|
85739
|
+
continue;
|
|
85740
|
+
}
|
|
85741
|
+
if (!stopped && (r.unknown?.length ?? 0) > 0) {
|
|
85742
|
+
c.undetermined++;
|
|
85743
|
+
continue;
|
|
85744
|
+
}
|
|
85745
|
+
c.attacks++;
|
|
85746
|
+
if (stopped) c.stopped++;
|
|
85747
|
+
else if (recorded) {
|
|
85748
|
+
c.loggedOnly++;
|
|
85749
|
+
if (r.checkId) {
|
|
85750
|
+
const e = passedByCheck[r.checkId] ??= {
|
|
85751
|
+
value: checkValue(settings, r.checkId),
|
|
85752
|
+
count: 0
|
|
85753
|
+
};
|
|
85754
|
+
e.count++;
|
|
85755
|
+
} else passedUnattributed[r.owasp] = (passedUnattributed[r.owasp] ?? 0) + 1;
|
|
85756
|
+
} else {
|
|
85757
|
+
c.passed++;
|
|
85758
|
+
passedUnattributed[r.owasp] = (passedUnattributed[r.owasp] ?? 0) + 1;
|
|
85759
|
+
}
|
|
85760
|
+
}
|
|
85761
|
+
return {
|
|
85762
|
+
engineVersion: PROXY_VERSION,
|
|
85763
|
+
mode: config.settings.mode ?? "standard",
|
|
85764
|
+
policySource: config.policySource,
|
|
85765
|
+
cases: results.length,
|
|
85766
|
+
byRisk,
|
|
85767
|
+
passedByCheck,
|
|
85768
|
+
passedUnattributed,
|
|
85769
|
+
notApplicableBy
|
|
85770
|
+
};
|
|
85771
|
+
}
|
|
85772
|
+
function toolOf(payload, fallback) {
|
|
85773
|
+
return typeof payload.tool_name === "string" && payload.tool_name ? payload.tool_name : fallback;
|
|
85774
|
+
}
|
|
85775
|
+
function notePostCall(judge, sessionId, tool, input, output, at, cwd) {
|
|
85776
|
+
const m = scanArgs(output);
|
|
85777
|
+
if (m) judge.noteOutputSecret(sessionId, m.patternName, at);
|
|
85778
|
+
judge.noteToolResult(sessionId, tool, at, cwd, {
|
|
85779
|
+
input,
|
|
85780
|
+
output: collectToolOutputText(output).text
|
|
85781
|
+
});
|
|
85782
|
+
}
|
|
85783
|
+
async function runCase(judge, rec, env, has2, at, online = false) {
|
|
85784
|
+
const base3 = {
|
|
85785
|
+
id: rec.id,
|
|
85786
|
+
owasp: isAsiId(rec.owasp) ? rec.owasp : "unknown",
|
|
85787
|
+
section: rec.section === "headline" || rec.section === "vendor" ? rec.section : "unknown",
|
|
85788
|
+
setup: rec.setup,
|
|
85789
|
+
expected: rec.expected,
|
|
85790
|
+
...rec.volatile && { volatile: true }
|
|
85791
|
+
};
|
|
85792
|
+
const need = profileNeed(rec.setup);
|
|
85793
|
+
if (need && !has2[need]) return { ...base3, notApplicable: need };
|
|
85794
|
+
if (rec.stage === "post") return { ...base3, notSimulated: "post-stage" };
|
|
85795
|
+
const sessionId = `forecast-cases:${rec.id}`;
|
|
85796
|
+
const cwd = env.cwd;
|
|
85797
|
+
const config = judge.configFor(cwd);
|
|
85798
|
+
const meta = { agent: "claude", sessionId };
|
|
85799
|
+
for (const p of rec.prior ?? []) {
|
|
85800
|
+
const payload2 = materialize(p.input, env) ?? {};
|
|
85801
|
+
const tool = toolOf(payload2, rec.tool);
|
|
85802
|
+
if (p.stage === "post") {
|
|
85803
|
+
notePostCall(judge, sessionId, tool, payload2.tool_input, materialize(p.output, env), at, cwd);
|
|
85804
|
+
continue;
|
|
85805
|
+
}
|
|
85806
|
+
await forecastDecision(tool, payload2.tool_input ?? {}, meta, {
|
|
85807
|
+
cwd,
|
|
85808
|
+
config,
|
|
85809
|
+
session: judge.session(sessionId),
|
|
85810
|
+
at: Date.parse(at),
|
|
85811
|
+
...online && { onlinePackages: true }
|
|
85812
|
+
});
|
|
85813
|
+
}
|
|
85814
|
+
const payload = materialize(rec.input, env) ?? {};
|
|
85815
|
+
const v = await forecastDecision(toolOf(payload, rec.tool), payload.tool_input ?? {}, meta, {
|
|
85816
|
+
cwd,
|
|
85817
|
+
config,
|
|
85818
|
+
session: judge.session(sessionId),
|
|
85819
|
+
at: Date.parse(at),
|
|
85820
|
+
...online && { onlinePackages: true }
|
|
85821
|
+
});
|
|
85822
|
+
return {
|
|
85823
|
+
...base3,
|
|
85824
|
+
decision: v.decision,
|
|
85825
|
+
enforced: v.enforced,
|
|
85826
|
+
...v.checkId && { checkId: v.checkId },
|
|
85827
|
+
layer: v.layer,
|
|
85828
|
+
...v.notEnforcedBecause && { notEnforcedBecause: v.notEnforcedBecause },
|
|
85829
|
+
...v.unknown.length > 0 && { unknown: v.unknown }
|
|
85830
|
+
};
|
|
85831
|
+
}
|
|
85832
|
+
function materializeProfileFiles(profile, env) {
|
|
85833
|
+
for (const f of profile.files ?? []) {
|
|
85834
|
+
const target = materialize(f.path, env);
|
|
85835
|
+
const rel = import_path95.default.relative(env.home, target);
|
|
85836
|
+
if (rel.startsWith("..") || import_path95.default.isAbsolute(rel)) continue;
|
|
85837
|
+
import_fs96.default.mkdirSync(import_path95.default.dirname(target), { recursive: true });
|
|
85838
|
+
const content = materialize(f.content, env);
|
|
85839
|
+
import_fs96.default.writeFileSync(target, typeof content === "string" ? content : JSON.stringify(content));
|
|
85840
|
+
}
|
|
85841
|
+
}
|
|
85842
|
+
var POLICY_HOME_GUARDS = ["rules-cache.json", "credentials.json"];
|
|
85843
|
+
var PolicyHomeTaken = class extends Error {
|
|
85844
|
+
};
|
|
85845
|
+
async function runForecastCases(opts) {
|
|
85846
|
+
const env = {
|
|
85847
|
+
home: opts.home,
|
|
85848
|
+
cwd: opts.cwd ?? import_path95.default.join(opts.home, "bench-project")
|
|
85849
|
+
};
|
|
85850
|
+
import_fs96.default.mkdirSync(env.cwd, { recursive: true });
|
|
85851
|
+
if (opts.policy) {
|
|
85852
|
+
const taken = POLICY_HOME_GUARDS.filter(
|
|
85853
|
+
(f) => import_fs96.default.existsSync(import_path95.default.join(opts.home, ".node9", f))
|
|
85854
|
+
);
|
|
85855
|
+
if (taken.length > 0)
|
|
85856
|
+
throw new PolicyHomeTaken(
|
|
85857
|
+
`--policy needs a fresh HOME; ${opts.home} already has ${taken.map((f) => `.node9/${f}`).join(" and ")}`
|
|
85858
|
+
);
|
|
85859
|
+
writePolicyCache(opts.policy, opts.policy.etag);
|
|
85860
|
+
if (!process.env.NODE9_API_KEY) process.env.NODE9_API_KEY = "forecast-cases";
|
|
85861
|
+
}
|
|
85862
|
+
const judge = new HistoryJudge();
|
|
85863
|
+
const config = judge.configFor(env.cwd);
|
|
85864
|
+
const has2 = homeHas(config);
|
|
85865
|
+
const profiles = /* @__PURE__ */ new Map();
|
|
85866
|
+
const profileOf = (name) => {
|
|
85867
|
+
if (!opts.profilesDir) return null;
|
|
85868
|
+
if (profiles.has(name)) return profiles.get(name);
|
|
85869
|
+
let p = null;
|
|
85870
|
+
try {
|
|
85871
|
+
p = JSON.parse(
|
|
85872
|
+
import_fs96.default.readFileSync(import_path95.default.join(opts.profilesDir, `${name}.json`), "utf8")
|
|
85873
|
+
);
|
|
85874
|
+
materializeProfileFiles(p, env);
|
|
85875
|
+
} catch {
|
|
85876
|
+
p = null;
|
|
85877
|
+
}
|
|
85878
|
+
profiles.set(name, p);
|
|
85879
|
+
return p;
|
|
85880
|
+
};
|
|
85881
|
+
const results = [];
|
|
85882
|
+
const rl = import_readline5.default.createInterface({
|
|
85883
|
+
input: import_fs96.default.createReadStream(opts.casesPath, { encoding: "utf8" }),
|
|
85884
|
+
crlfDelay: Infinity
|
|
85885
|
+
});
|
|
85886
|
+
for await (const line of rl) {
|
|
85887
|
+
if (!line.trim()) continue;
|
|
85888
|
+
let rec;
|
|
85889
|
+
try {
|
|
85890
|
+
rec = JSON.parse(line);
|
|
85891
|
+
} catch {
|
|
85892
|
+
continue;
|
|
85893
|
+
}
|
|
85894
|
+
if (!rec || typeof rec.id !== "string") continue;
|
|
85895
|
+
profileOf(rec.setup);
|
|
85896
|
+
let result;
|
|
85897
|
+
try {
|
|
85898
|
+
result = await runCase(judge, rec, env, has2, opts.at, opts.onlinePackages === true);
|
|
85899
|
+
} catch (err2) {
|
|
85900
|
+
result = {
|
|
85901
|
+
id: rec.id,
|
|
85902
|
+
owasp: isAsiId(rec.owasp) ? rec.owasp : "unknown",
|
|
85903
|
+
section: rec.section === "headline" || rec.section === "vendor" ? rec.section : "unknown",
|
|
85904
|
+
setup: rec.setup,
|
|
85905
|
+
expected: rec.expected,
|
|
85906
|
+
error: err2 instanceof Error ? err2.message : String(err2)
|
|
85907
|
+
};
|
|
85908
|
+
}
|
|
85909
|
+
results.push(result);
|
|
85910
|
+
opts.write(JSON.stringify({ case: result }));
|
|
85911
|
+
}
|
|
85912
|
+
const summary = summarize(results, config);
|
|
85913
|
+
opts.write(JSON.stringify({ summary }));
|
|
85914
|
+
return summary;
|
|
85915
|
+
}
|
|
85916
|
+
function registerForecastCasesCommand(program2) {
|
|
85917
|
+
program2.command("forecast-cases <cases>", { hidden: true }).description(
|
|
85918
|
+
"Judge a file of benchmark cases through the forecast entry under this HOME; JSON per case, then a summary"
|
|
85919
|
+
).option(
|
|
85920
|
+
"--profiles <dir>",
|
|
85921
|
+
"The benchmark profiles directory: its fixture files are created under HOME"
|
|
85922
|
+
).option("--at <iso>", "The clock every case is judged at", "2026-01-01T00:00:00.000Z").option(
|
|
85923
|
+
"--online-packages",
|
|
85924
|
+
"Let the package check query the advisory service and the registries, as the hook does (default: offline)"
|
|
85925
|
+
).option(
|
|
85926
|
+
"--cwd <dir>",
|
|
85927
|
+
"The project directory the cases are judged in ({{CWD}}); default HOME/bench-project"
|
|
85928
|
+
).option(
|
|
85929
|
+
"--policy <file>",
|
|
85930
|
+
"A cloud policy sync response body (JSON), written as this HOME's rules cache first"
|
|
85931
|
+
).action(
|
|
85932
|
+
async (cases, opts) => {
|
|
85933
|
+
const casesPath = import_path95.default.resolve(cases);
|
|
85934
|
+
if (!import_fs96.default.existsSync(casesPath)) {
|
|
85935
|
+
console.error(`forecast-cases: no such file: ${casesPath}`);
|
|
85936
|
+
process.exitCode = 2;
|
|
85937
|
+
return;
|
|
85938
|
+
}
|
|
85939
|
+
let policy;
|
|
85940
|
+
if (opts.policy) {
|
|
85941
|
+
const parsed = readPolicyBody(import_path95.default.resolve(opts.policy));
|
|
85942
|
+
if (!parsed) {
|
|
85943
|
+
console.error(`forecast-cases: --policy is not a JSON object: ${opts.policy}`);
|
|
85944
|
+
process.exitCode = 2;
|
|
85945
|
+
return;
|
|
85946
|
+
}
|
|
85947
|
+
policy = parsed;
|
|
85948
|
+
}
|
|
85949
|
+
try {
|
|
85950
|
+
await runForecastCases({
|
|
85951
|
+
casesPath,
|
|
85952
|
+
profilesDir: opts.profiles ? import_path95.default.resolve(opts.profiles) : void 0,
|
|
85953
|
+
home: import_os80.default.homedir(),
|
|
85954
|
+
cwd: opts.cwd ? import_path95.default.resolve(opts.cwd) : void 0,
|
|
85955
|
+
policy,
|
|
85956
|
+
onlinePackages: opts.onlinePackages === true,
|
|
85957
|
+
at: opts.at,
|
|
85958
|
+
write: (line) => process.stdout.write(line + "\n")
|
|
85959
|
+
});
|
|
85960
|
+
} catch (err2) {
|
|
85961
|
+
if (!(err2 instanceof PolicyHomeTaken)) throw err2;
|
|
85962
|
+
console.error(`forecast-cases: ${err2.message}`);
|
|
85963
|
+
process.exitCode = 2;
|
|
85964
|
+
}
|
|
85965
|
+
}
|
|
85966
|
+
);
|
|
85967
|
+
}
|
|
85968
|
+
function readPolicyBody(file2) {
|
|
85969
|
+
try {
|
|
85970
|
+
const v = JSON.parse(import_fs96.default.readFileSync(file2, "utf8"));
|
|
85971
|
+
if (!v || typeof v !== "object" || Array.isArray(v)) return void 0;
|
|
85972
|
+
return v;
|
|
85973
|
+
} catch {
|
|
85974
|
+
return void 0;
|
|
85975
|
+
}
|
|
85976
|
+
}
|
|
85977
|
+
|
|
85569
85978
|
// src/cli/commands/posture.ts
|
|
85570
85979
|
init_cjs_shims();
|
|
85571
85980
|
var import_chalk35 = __toESM(require("chalk"));
|
|
@@ -85605,8 +86014,8 @@ init_cjs_shims();
|
|
|
85605
86014
|
|
|
85606
86015
|
// src/ci-check/fetch.ts
|
|
85607
86016
|
init_cjs_shims();
|
|
85608
|
-
var
|
|
85609
|
-
var
|
|
86017
|
+
var import_fs97 = __toESM(require("fs"));
|
|
86018
|
+
var import_path96 = __toESM(require("path"));
|
|
85610
86019
|
var import_node_child_process = require("child_process");
|
|
85611
86020
|
var import_undici = __toESM(require_undici());
|
|
85612
86021
|
|
|
@@ -85616,18 +86025,18 @@ init_instructions();
|
|
|
85616
86025
|
init_suppress();
|
|
85617
86026
|
var MCP_CONFIG_RE = /\.mcp\.json$|\.cursor\/mcp\.json$|(^|\/)\.vscode\/mcp\.json$|(^|\/)\.kiro\/settings\/mcp\.json$|(^|\/)\.gemini\/settings\.json$|(^|\/)opencode\.json$|(^|\/)\.opencode\/config\.json$/;
|
|
85618
86027
|
var ISSUE_FORM_RE = /^\.github\/ISSUE_TEMPLATE\/[^/]+\.(ya?ml|md)$/i;
|
|
85619
|
-
function routeOf(
|
|
85620
|
-
if (
|
|
85621
|
-
if (/\.github\/workflows\/.+\.ya?ml$/.test(
|
|
85622
|
-
if (ISSUE_FORM_RE.test(
|
|
85623
|
-
if (
|
|
85624
|
-
if (/\.claude\/settings(\.local)?\.json$/.test(
|
|
85625
|
-
if (isHookScript(
|
|
85626
|
-
if (isSkillScript(
|
|
85627
|
-
if (MCP_CONFIG_RE.test(
|
|
85628
|
-
if (/(^|\/)\.codex\/config\.toml$/.test(
|
|
85629
|
-
if (isInstructionFile(
|
|
85630
|
-
if (isAppDoc(
|
|
86028
|
+
function routeOf(path114, skillDirs, appDirs = /* @__PURE__ */ new Set()) {
|
|
86029
|
+
if (path114 === SUPPRESSIONS_FILE) return "suppressions";
|
|
86030
|
+
if (/\.github\/workflows\/.+\.ya?ml$/.test(path114)) return "workflow";
|
|
86031
|
+
if (ISSUE_FORM_RE.test(path114)) return "issue-form";
|
|
86032
|
+
if (path114 === "package.json" || path114 === "pyproject.toml") return "manifest";
|
|
86033
|
+
if (/\.claude\/settings(\.local)?\.json$/.test(path114)) return "agent-config";
|
|
86034
|
+
if (isHookScript(path114)) return "hook-script";
|
|
86035
|
+
if (isSkillScript(path114, skillDirs)) return "skill-script";
|
|
86036
|
+
if (MCP_CONFIG_RE.test(path114)) return "mcp";
|
|
86037
|
+
if (/(^|\/)\.codex\/config\.toml$/.test(path114)) return "codex";
|
|
86038
|
+
if (isInstructionFile(path114, skillDirs, appDirs)) return "instruction";
|
|
86039
|
+
if (isAppDoc(path114, skillDirs, appDirs)) return "app-doc";
|
|
85631
86040
|
return null;
|
|
85632
86041
|
}
|
|
85633
86042
|
|
|
@@ -85757,7 +86166,7 @@ function parseRepoUrl(input) {
|
|
|
85757
86166
|
function isLocalPath(input) {
|
|
85758
86167
|
if (input.startsWith(".") || input.startsWith("/") || input.startsWith("~")) return true;
|
|
85759
86168
|
try {
|
|
85760
|
-
return
|
|
86169
|
+
return import_fs97.default.existsSync(input) && import_fs97.default.statSync(input).isDirectory();
|
|
85761
86170
|
} catch {
|
|
85762
86171
|
return false;
|
|
85763
86172
|
}
|
|
@@ -86118,7 +86527,7 @@ function capNested(reads, cap, notes) {
|
|
|
86118
86527
|
}
|
|
86119
86528
|
var overLimit = (text) => Buffer.byteLength(text, "utf8") > MAX_FILE_BYTES5;
|
|
86120
86529
|
var RAW_LIMIT = 2 * MAX_FILE_BYTES5;
|
|
86121
|
-
var OPEN_READ =
|
|
86530
|
+
var OPEN_READ = import_fs97.default.constants.O_RDONLY | (import_fs97.default.constants.O_NOFOLLOW ?? 0) | (import_fs97.default.constants.O_NONBLOCK ?? 0);
|
|
86122
86531
|
var MAX_WALK_ENTRIES = 1e6;
|
|
86123
86532
|
var direntKind = (e) => e.isSymbolicLink() ? "link" : e.isDirectory() ? "dir" : e.isFile() ? "file" : "other";
|
|
86124
86533
|
function walkDisk(root, notes) {
|
|
@@ -86133,7 +86542,7 @@ function walkDisk(root, notes) {
|
|
|
86133
86542
|
const relDir = stack.pop();
|
|
86134
86543
|
let dirents;
|
|
86135
86544
|
try {
|
|
86136
|
-
dirents =
|
|
86545
|
+
dirents = import_fs97.default.readdirSync(import_path96.default.join(root, relDir), { withFileTypes: true });
|
|
86137
86546
|
} catch (e) {
|
|
86138
86547
|
unlistable.push(`${relDir || "."} (${e?.code ?? "error"})`);
|
|
86139
86548
|
continue;
|
|
@@ -86147,7 +86556,7 @@ function walkDisk(root, notes) {
|
|
|
86147
86556
|
const k = direntKind(e);
|
|
86148
86557
|
kinds2.set(rel, k);
|
|
86149
86558
|
if (k !== "dir" || isUnwalked(`${rel}/`)) continue;
|
|
86150
|
-
if (
|
|
86559
|
+
if (import_fs97.default.existsSync(import_path96.default.join(root, rel, ".git"))) {
|
|
86151
86560
|
sealed.add(rel);
|
|
86152
86561
|
nestedRepos.push(rel);
|
|
86153
86562
|
} else stack.push(rel);
|
|
@@ -86170,7 +86579,7 @@ function walkDisk(root, notes) {
|
|
|
86170
86579
|
}
|
|
86171
86580
|
function gitmodulePaths(root) {
|
|
86172
86581
|
try {
|
|
86173
|
-
const text = readLocalFile(
|
|
86582
|
+
const text = readLocalFile(import_path96.default.join(root, ".gitmodules"), ".gitmodules");
|
|
86174
86583
|
return [...text.matchAll(/^\s*path\s*=\s*(.+?)\s*$/gm)].map((m) => m[1].replace(/\/+$/, ""));
|
|
86175
86584
|
} catch {
|
|
86176
86585
|
return [];
|
|
@@ -86178,9 +86587,9 @@ function gitmodulePaths(root) {
|
|
|
86178
86587
|
}
|
|
86179
86588
|
function localLinkText(root, rel) {
|
|
86180
86589
|
try {
|
|
86181
|
-
const t =
|
|
86590
|
+
const t = import_fs97.default.readlinkSync(import_path96.default.join(root, rel));
|
|
86182
86591
|
if (process.platform !== "win32") return t;
|
|
86183
|
-
return
|
|
86592
|
+
return import_path96.default.win32.isAbsolute(t) ? `/${t.replace(/\\/g, "/")}` : t.replace(/\\/g, "/");
|
|
86184
86593
|
} catch {
|
|
86185
86594
|
return null;
|
|
86186
86595
|
}
|
|
@@ -86188,11 +86597,11 @@ function localLinkText(root, rel) {
|
|
|
86188
86597
|
function readLocalFile(abs, rel) {
|
|
86189
86598
|
let fd;
|
|
86190
86599
|
try {
|
|
86191
|
-
fd =
|
|
86192
|
-
const st =
|
|
86600
|
+
fd = import_fs97.default.openSync(abs, OPEN_READ);
|
|
86601
|
+
const st = import_fs97.default.fstatSync(fd);
|
|
86193
86602
|
if (!st.isFile()) throw new Error(unreadNote(rel, "no longer a regular file"));
|
|
86194
86603
|
if (st.size > RAW_LIMIT) throw new Error(tooLargeNote(rel));
|
|
86195
|
-
const text = lf(
|
|
86604
|
+
const text = lf(import_fs97.default.readFileSync(fd, "utf8"));
|
|
86196
86605
|
if (overLimit(text)) throw new Error(tooLargeNote(rel));
|
|
86197
86606
|
return text;
|
|
86198
86607
|
} catch (e) {
|
|
@@ -86200,7 +86609,7 @@ function readLocalFile(abs, rel) {
|
|
|
86200
86609
|
if (msg.includes(INCOMPLETE)) throw e;
|
|
86201
86610
|
throw new Error(unreadNote(rel, e?.code ?? "error"));
|
|
86202
86611
|
} finally {
|
|
86203
|
-
if (fd !== void 0)
|
|
86612
|
+
if (fd !== void 0) import_fs97.default.closeSync(fd);
|
|
86204
86613
|
}
|
|
86205
86614
|
}
|
|
86206
86615
|
function localGitHubRepo(root) {
|
|
@@ -86221,10 +86630,10 @@ function readLocalTree(dir2) {
|
|
|
86221
86630
|
notes.push(...plan.notes);
|
|
86222
86631
|
const files = [];
|
|
86223
86632
|
for (const { rel, real, route } of plan.reads) {
|
|
86224
|
-
const abs =
|
|
86633
|
+
const abs = import_path96.default.join(root, real);
|
|
86225
86634
|
let size = 0;
|
|
86226
86635
|
try {
|
|
86227
|
-
size =
|
|
86636
|
+
size = import_fs97.default.lstatSync(abs).size;
|
|
86228
86637
|
} catch {
|
|
86229
86638
|
}
|
|
86230
86639
|
if (size > RAW_LIMIT) {
|
|
@@ -87386,17 +87795,17 @@ function localTarget(uses, self) {
|
|
|
87386
87795
|
if (!f) return null;
|
|
87387
87796
|
return f[1].toLowerCase() === self.owner.toLowerCase() && f[2].toLowerCase() === self.repo.toLowerCase() ? `.github/workflows/${f[3]}` : null;
|
|
87388
87797
|
}
|
|
87389
|
-
function localCallsOf(
|
|
87798
|
+
function localCallsOf(path114, content, autoLabels, trustedRunSources, self) {
|
|
87390
87799
|
AUTO_LABELS = autoLabels ?? /* @__PURE__ */ new Set();
|
|
87391
87800
|
TRUSTED_RUN_SOURCES = trustedRunSources ?? /* @__PURE__ */ new Set();
|
|
87392
87801
|
try {
|
|
87393
|
-
return localCallsOfInner(
|
|
87802
|
+
return localCallsOfInner(path114, content, self);
|
|
87394
87803
|
} finally {
|
|
87395
87804
|
AUTO_LABELS = /* @__PURE__ */ new Set();
|
|
87396
87805
|
TRUSTED_RUN_SOURCES = /* @__PURE__ */ new Set();
|
|
87397
87806
|
}
|
|
87398
87807
|
}
|
|
87399
|
-
function localCallsOfInner(
|
|
87808
|
+
function localCallsOfInner(path114, content, self) {
|
|
87400
87809
|
let raw;
|
|
87401
87810
|
try {
|
|
87402
87811
|
raw = loadWorkflow(content).raw;
|
|
@@ -87414,7 +87823,7 @@ function localCallsOfInner(path113, content, self) {
|
|
|
87414
87823
|
out.push({
|
|
87415
87824
|
target,
|
|
87416
87825
|
caller: {
|
|
87417
|
-
file:
|
|
87826
|
+
file: path114,
|
|
87418
87827
|
keys: reach.keys,
|
|
87419
87828
|
untrusted: reach.untrusted,
|
|
87420
87829
|
secretExposed: reach.secretExposed,
|
|
@@ -87650,7 +88059,7 @@ function upstreamRunTrusted(wf, raw) {
|
|
|
87650
88059
|
const names = Array.isArray(run?.workflows) ? run.workflows.map(String) : [];
|
|
87651
88060
|
return names.length > 0 && names.every((n) => TRUSTED_RUN_SOURCES.has(n));
|
|
87652
88061
|
}
|
|
87653
|
-
function runSourceOf(
|
|
88062
|
+
function runSourceOf(path114, content, autoLabels) {
|
|
87654
88063
|
AUTO_LABELS = autoLabels ?? /* @__PURE__ */ new Set();
|
|
87655
88064
|
try {
|
|
87656
88065
|
let raw;
|
|
@@ -87663,7 +88072,7 @@ function runSourceOf(path113, content, autoLabels) {
|
|
|
87663
88072
|
const wf = raw;
|
|
87664
88073
|
CALLERS.delete(wf);
|
|
87665
88074
|
const reach = triggerReach(wf, raw);
|
|
87666
|
-
const name = typeof raw["name"] === "string" && raw["name"] ? raw["name"] :
|
|
88075
|
+
const name = typeof raw["name"] === "string" && raw["name"] ? raw["name"] : path114;
|
|
87667
88076
|
return { name, trusted: !reach.untrusted && !reach.reusable };
|
|
87668
88077
|
} finally {
|
|
87669
88078
|
AUTO_LABELS = /* @__PURE__ */ new Set();
|
|
@@ -88133,18 +88542,18 @@ function severityFromScore(score) {
|
|
|
88133
88542
|
if (score >= 1) return "advisory";
|
|
88134
88543
|
return null;
|
|
88135
88544
|
}
|
|
88136
|
-
function analyzeWorkflow(
|
|
88545
|
+
function analyzeWorkflow(path114, content, callers, autoLabels, trustedRunSources) {
|
|
88137
88546
|
AUTO_LABELS = autoLabels ?? /* @__PURE__ */ new Set();
|
|
88138
88547
|
TRUSTED_RUN_SOURCES = trustedRunSources ?? /* @__PURE__ */ new Set();
|
|
88139
88548
|
try {
|
|
88140
|
-
return analyzeWorkflowInner(
|
|
88549
|
+
return analyzeWorkflowInner(path114, content, callers);
|
|
88141
88550
|
} finally {
|
|
88142
88551
|
AUTO_LABELS = /* @__PURE__ */ new Set();
|
|
88143
88552
|
TRUSTED_RUN_SOURCES = /* @__PURE__ */ new Set();
|
|
88144
88553
|
UPSTREAM_TRUSTED = false;
|
|
88145
88554
|
}
|
|
88146
88555
|
}
|
|
88147
|
-
function analyzeWorkflowInner(
|
|
88556
|
+
function analyzeWorkflowInner(path114, content, callers) {
|
|
88148
88557
|
let raw;
|
|
88149
88558
|
try {
|
|
88150
88559
|
raw = loadWorkflow(content).raw;
|
|
@@ -88353,7 +88762,7 @@ function analyzeWorkflowInner(path113, content, callers) {
|
|
|
88353
88762
|
dimension: "workflows",
|
|
88354
88763
|
severity,
|
|
88355
88764
|
title,
|
|
88356
|
-
file:
|
|
88765
|
+
file: path114,
|
|
88357
88766
|
signals,
|
|
88358
88767
|
mitigations: mitigations.length ? mitigations : void 0,
|
|
88359
88768
|
fix: head === "root" && privileged ? "Do not check out the untrusted PR head into the workspace root under a privileged trigger (pull_request_target/workflow_run): check out the base ref, or isolate the head in a subdir (--add-dir). Add an actor gate and scope the agent tools." : head === "root" ? "This runs under `pull_request` (fork PRs get a read-only token), so the head checkout is low-risk today: keep it on `pull_request` (not `pull_request_target`) and keep the actor gate + scoped tools." : "Add/verify an actor gate, scope the agent tools to read-only, and env-deny secrets. See Anthropic\u2019s claude-code-action security doc."
|
|
@@ -88457,18 +88866,18 @@ function evalAgentJob(job, wf, raw, untrustedTrigger, reusable) {
|
|
|
88457
88866
|
if (reusable && !loadedGun && SEVERITY_RANK2[severity] > SEVERITY_RANK2.medium) severity = "medium";
|
|
88458
88867
|
return { severity, secrets, injectable, canReadEnv };
|
|
88459
88868
|
}
|
|
88460
|
-
function analyzeWorkflowSecrets(
|
|
88869
|
+
function analyzeWorkflowSecrets(path114, content, callers, autoLabels, trustedRunSources) {
|
|
88461
88870
|
AUTO_LABELS = autoLabels ?? /* @__PURE__ */ new Set();
|
|
88462
88871
|
TRUSTED_RUN_SOURCES = trustedRunSources ?? /* @__PURE__ */ new Set();
|
|
88463
88872
|
try {
|
|
88464
|
-
return analyzeWorkflowSecretsInner(
|
|
88873
|
+
return analyzeWorkflowSecretsInner(path114, content, callers);
|
|
88465
88874
|
} finally {
|
|
88466
88875
|
AUTO_LABELS = /* @__PURE__ */ new Set();
|
|
88467
88876
|
TRUSTED_RUN_SOURCES = /* @__PURE__ */ new Set();
|
|
88468
88877
|
UPSTREAM_TRUSTED = false;
|
|
88469
88878
|
}
|
|
88470
88879
|
}
|
|
88471
|
-
function analyzeWorkflowSecretsInner(
|
|
88880
|
+
function analyzeWorkflowSecretsInner(path114, content, callers) {
|
|
88472
88881
|
let raw;
|
|
88473
88882
|
try {
|
|
88474
88883
|
raw = loadWorkflow(content).raw;
|
|
@@ -88495,7 +88904,7 @@ function analyzeWorkflowSecretsInner(path113, content, callers) {
|
|
|
88495
88904
|
dimension: "data",
|
|
88496
88905
|
severity: worst.severity,
|
|
88497
88906
|
title: worst.severity === "advisory" ? "Secrets reachable by the agent: hardening" : "Exfiltratable secrets reachable by an injectable agent",
|
|
88498
|
-
file:
|
|
88907
|
+
file: path114,
|
|
88499
88908
|
signals: [
|
|
88500
88909
|
`agent can reach: ${worst.secrets.map((s) => s.name).join(", ")}`,
|
|
88501
88910
|
worst.injectable ? "the agent is externally triggerable (untrusted trigger, no gate)" : "gated / not externally triggerable: latent risk only",
|
|
@@ -88517,7 +88926,7 @@ function marketplaceOwner(market) {
|
|
|
88517
88926
|
market
|
|
88518
88927
|
)?.[1] ?? /^([\w.-]{1,100})\/[\w.-]{1,100}(?:[#@].*)?$/.exec(market)?.[1];
|
|
88519
88928
|
}
|
|
88520
|
-
function analyzeWorkflowPlugins(
|
|
88929
|
+
function analyzeWorkflowPlugins(path114, content, owner) {
|
|
88521
88930
|
let raw;
|
|
88522
88931
|
try {
|
|
88523
88932
|
raw = loadWorkflow(content).raw;
|
|
@@ -88547,7 +88956,7 @@ function analyzeWorkflowPlugins(path113, content, owner) {
|
|
|
88547
88956
|
dimension: "mcp",
|
|
88548
88957
|
severity: "medium",
|
|
88549
88958
|
title: "Agent installs plugins from a third-party marketplace on every run",
|
|
88550
|
-
file:
|
|
88959
|
+
file: path114,
|
|
88551
88960
|
signals: [
|
|
88552
88961
|
`\`plugin_marketplaces: ${safeText(market, 120)}\` is not pinned to a commit: whoever controls it changes the code and prompts the agent runs`
|
|
88553
88962
|
],
|
|
@@ -88563,11 +88972,11 @@ function readsItemList(text) {
|
|
|
88563
88972
|
if (text.length > 2e5) return ITEM_LIST_RE.test(text);
|
|
88564
88973
|
return text.replace(/\\\r?\n/g, " ").split("\n").some((l) => ITEM_LIST_RE.test(l) && !sanitizedListing(l));
|
|
88565
88974
|
}
|
|
88566
|
-
function analyzeTrustedReaders(
|
|
88975
|
+
function analyzeTrustedReaders(path114, content, autoLabels, callers, trustedRunSources) {
|
|
88567
88976
|
AUTO_LABELS = autoLabels ?? /* @__PURE__ */ new Set();
|
|
88568
88977
|
TRUSTED_RUN_SOURCES = trustedRunSources ?? /* @__PURE__ */ new Set();
|
|
88569
88978
|
try {
|
|
88570
|
-
return analyzeTrustedReadersInner(
|
|
88979
|
+
return analyzeTrustedReadersInner(path114, content, callers);
|
|
88571
88980
|
} finally {
|
|
88572
88981
|
AUTO_LABELS = /* @__PURE__ */ new Set();
|
|
88573
88982
|
TRUSTED_RUN_SOURCES = /* @__PURE__ */ new Set();
|
|
@@ -88576,7 +88985,7 @@ function analyzeTrustedReaders(path113, content, autoLabels, callers, trustedRun
|
|
|
88576
88985
|
function keysWithCallers(keys, callers) {
|
|
88577
88986
|
return [.../* @__PURE__ */ new Set([...keys, ...(callers ?? []).flatMap((c) => c.keys)])];
|
|
88578
88987
|
}
|
|
88579
|
-
function analyzeTrustedReadersInner(
|
|
88988
|
+
function analyzeTrustedReadersInner(path114, content, callers) {
|
|
88580
88989
|
let raw;
|
|
88581
88990
|
try {
|
|
88582
88991
|
raw = loadWorkflow(content).raw;
|
|
@@ -88637,7 +89046,7 @@ function analyzeTrustedReadersInner(path113, content, callers) {
|
|
|
88637
89046
|
dimension: "workflows",
|
|
88638
89047
|
severity: "advisory",
|
|
88639
89048
|
title: "Agent on a trusted trigger reads content strangers write, with a write token",
|
|
88640
|
-
file:
|
|
89049
|
+
file: path114,
|
|
88641
89050
|
signals: [
|
|
88642
89051
|
`runs on ${keys.map((k) => safeText(k, 40)).join(", ")}: no stranger starts it`,
|
|
88643
89052
|
...reads.map((r) => `the agent ${r}`),
|
|
@@ -88725,17 +89134,17 @@ function requiresTrustedAuthor(src) {
|
|
|
88725
89134
|
};
|
|
88726
89135
|
return req(x);
|
|
88727
89136
|
}
|
|
88728
|
-
function analyzeForkCodeOnTrust(
|
|
89137
|
+
function analyzeForkCodeOnTrust(path114, content, callers, autoLabels, trustedRunSources) {
|
|
88729
89138
|
AUTO_LABELS = autoLabels ?? /* @__PURE__ */ new Set();
|
|
88730
89139
|
TRUSTED_RUN_SOURCES = trustedRunSources ?? /* @__PURE__ */ new Set();
|
|
88731
89140
|
try {
|
|
88732
|
-
return analyzeForkCodeOnTrustInner(
|
|
89141
|
+
return analyzeForkCodeOnTrustInner(path114, content, callers);
|
|
88733
89142
|
} finally {
|
|
88734
89143
|
AUTO_LABELS = /* @__PURE__ */ new Set();
|
|
88735
89144
|
TRUSTED_RUN_SOURCES = /* @__PURE__ */ new Set();
|
|
88736
89145
|
}
|
|
88737
89146
|
}
|
|
88738
|
-
function analyzeForkCodeOnTrustInner(
|
|
89147
|
+
function analyzeForkCodeOnTrustInner(path114, content, callers) {
|
|
88739
89148
|
let raw;
|
|
88740
89149
|
try {
|
|
88741
89150
|
raw = loadWorkflow(content).raw;
|
|
@@ -88774,7 +89183,7 @@ function analyzeForkCodeOnTrustInner(path113, content, callers) {
|
|
|
88774
89183
|
dimension: "workflows",
|
|
88775
89184
|
severity: "advisory",
|
|
88776
89185
|
title: "A maintainer's action runs the agent inside the fork's code",
|
|
88777
|
-
file:
|
|
89186
|
+
file: path114,
|
|
88778
89187
|
signals: [
|
|
88779
89188
|
`triggered by ${forkKeys.map((k) => safeText(k, 40)).join(", ")}, behind a gate a maintainer passes (a comment, a label, a push to the PR branch, a reopen)`,
|
|
88780
89189
|
"checks out the untrusted PR head into the workspace root",
|
|
@@ -88806,18 +89215,18 @@ function laterSecrets(wf, job, from) {
|
|
|
88806
89215
|
if (!/^GITHUB_TOKEN$/i.test(m[1])) out.add(m[1]);
|
|
88807
89216
|
return [...out];
|
|
88808
89217
|
}
|
|
88809
|
-
function analyzeAgentOutputToEnv(
|
|
89218
|
+
function analyzeAgentOutputToEnv(path114, content, callers, autoLabels, trustedRunSources) {
|
|
88810
89219
|
AUTO_LABELS = autoLabels ?? /* @__PURE__ */ new Set();
|
|
88811
89220
|
TRUSTED_RUN_SOURCES = trustedRunSources ?? /* @__PURE__ */ new Set();
|
|
88812
89221
|
try {
|
|
88813
|
-
return analyzeAgentOutputToEnvInner(
|
|
89222
|
+
return analyzeAgentOutputToEnvInner(path114, content, callers);
|
|
88814
89223
|
} finally {
|
|
88815
89224
|
AUTO_LABELS = /* @__PURE__ */ new Set();
|
|
88816
89225
|
TRUSTED_RUN_SOURCES = /* @__PURE__ */ new Set();
|
|
88817
89226
|
UPSTREAM_TRUSTED = false;
|
|
88818
89227
|
}
|
|
88819
89228
|
}
|
|
88820
|
-
function analyzeAgentOutputToEnvInner(
|
|
89229
|
+
function analyzeAgentOutputToEnvInner(path114, content, callers) {
|
|
88821
89230
|
let raw;
|
|
88822
89231
|
try {
|
|
88823
89232
|
raw = loadWorkflow(content).raw;
|
|
@@ -88913,7 +89322,7 @@ function analyzeAgentOutputToEnvInner(path113, content, callers) {
|
|
|
88913
89322
|
dimension: "workflows",
|
|
88914
89323
|
severity,
|
|
88915
89324
|
title: sink.target === "GITHUB_PATH" ? "The agent's output is added to the job's PATH" : "The agent's output is written into the job's environment",
|
|
88916
|
-
file:
|
|
89325
|
+
file: path114,
|
|
88917
89326
|
signals,
|
|
88918
89327
|
fix: `Write the agent's result to a file and read it with a strict parser in the next step (a fixed set of values, or a number); never append free text from the agent to \`${target}\`. If a value must go there, strip newlines (\`tr -d '\\n'\`) and write it under a fixed name, or use a delimiter generated at run time.`,
|
|
88919
89328
|
explain: explainAgentOutputEnv({
|
|
@@ -88991,7 +89400,7 @@ function reviewQuestion(rule) {
|
|
|
88991
89400
|
return "Is this an instruction the agent follows, or text for a person?";
|
|
88992
89401
|
}
|
|
88993
89402
|
var RANK2 = { critical: 4, high: 3, medium: 2, advisory: 1 };
|
|
88994
|
-
var worstRank = (
|
|
89403
|
+
var worstRank = (fs115) => Math.max(...fs115.map((f) => RANK2[f.severity] ?? 0));
|
|
88995
89404
|
var fileOrder = (a, b) => worstRank(b[1]) - worstRank(a[1]) || b[1].length - a[1].length;
|
|
88996
89405
|
function groupReview(findings) {
|
|
88997
89406
|
const byFile = /* @__PURE__ */ new Map();
|
|
@@ -89062,7 +89471,7 @@ function logicalLines2(content) {
|
|
|
89062
89471
|
}
|
|
89063
89472
|
return out;
|
|
89064
89473
|
}
|
|
89065
|
-
function analyzeScript(
|
|
89474
|
+
function analyzeScript(path114, content, rulePrefix) {
|
|
89066
89475
|
const check = rulePrefix.startsWith("CI-1") ? "CI-1" : "CI-6";
|
|
89067
89476
|
const dimension = check === "CI-1" ? "toolRules" : "instructions";
|
|
89068
89477
|
const mk3 = (suffix, severity, title, signal, fix, line) => ({
|
|
@@ -89071,7 +89480,7 @@ function analyzeScript(path113, content, rulePrefix) {
|
|
|
89071
89480
|
dimension,
|
|
89072
89481
|
severity,
|
|
89073
89482
|
title,
|
|
89074
|
-
file:
|
|
89483
|
+
file: path114,
|
|
89075
89484
|
...line ? { line } : {},
|
|
89076
89485
|
signals: [signal],
|
|
89077
89486
|
fix
|
|
@@ -89501,7 +89910,7 @@ async function scanRepo(input, onProgress) {
|
|
|
89501
89910
|
init_cjs_shims();
|
|
89502
89911
|
var import_chalk36 = __toESM(require("chalk"));
|
|
89503
89912
|
init_suppress();
|
|
89504
|
-
var listed = (
|
|
89913
|
+
var listed = (fs115) => fs115.filter((f) => f.tier !== "review");
|
|
89505
89914
|
function excerpt(f) {
|
|
89506
89915
|
const m = /`([^`]+)`/.exec(f.signals[0] ?? "");
|
|
89507
89916
|
return safeText(m ? m[1] : f.title, 120).replace(/`/g, "'");
|
|
@@ -89517,14 +89926,14 @@ function reviewMd(findings) {
|
|
|
89517
89926
|
L.push("");
|
|
89518
89927
|
const files = [...byFile.keys()];
|
|
89519
89928
|
for (const file2 of files.slice(0, REVIEW_FILES)) {
|
|
89520
|
-
const
|
|
89929
|
+
const fs115 = byFile.get(file2);
|
|
89521
89930
|
L.push(`- \`${safeText(file2, 300)}\``);
|
|
89522
|
-
for (const f of
|
|
89931
|
+
for (const f of fs115.slice(0, REVIEW_LINES_PER_FILE))
|
|
89523
89932
|
L.push(
|
|
89524
89933
|
` - ${f.line ? `line ${Number(f.line)}: ` : ""}\`${excerpt(f)}\`. Check: ${reviewQuestion(f.rule)}`
|
|
89525
89934
|
);
|
|
89526
|
-
if (
|
|
89527
|
-
L.push(` - and ${
|
|
89935
|
+
if (fs115.length > REVIEW_LINES_PER_FILE)
|
|
89936
|
+
L.push(` - and ${fs115.length - REVIEW_LINES_PER_FILE} similar lines in this file`);
|
|
89528
89937
|
}
|
|
89529
89938
|
const more = files.length - REVIEW_FILES;
|
|
89530
89939
|
if (more > 0) L.push(`- and ${more} more file${more === 1 ? "" : "s"}`);
|
|
@@ -89540,7 +89949,7 @@ function reviewMd(findings) {
|
|
|
89540
89949
|
}
|
|
89541
89950
|
function reviewTerminal(findings) {
|
|
89542
89951
|
const { byFile, grants } = groupReview(findings);
|
|
89543
|
-
const items = [...byFile.values()].reduce((a,
|
|
89952
|
+
const items = [...byFile.values()].reduce((a, fs115) => a + fs115.length, 0);
|
|
89544
89953
|
if (!items && !grants) return [];
|
|
89545
89954
|
const L = [];
|
|
89546
89955
|
if (items) {
|
|
@@ -89549,12 +89958,12 @@ function reviewTerminal(findings) {
|
|
|
89549
89958
|
);
|
|
89550
89959
|
const files = [...byFile.keys()];
|
|
89551
89960
|
for (const file2 of files.slice(0, REVIEW_FILES)) {
|
|
89552
|
-
const
|
|
89961
|
+
const fs115 = byFile.get(file2);
|
|
89553
89962
|
L.push(import_chalk36.default.gray(` ${file2}`));
|
|
89554
|
-
for (const f of
|
|
89963
|
+
for (const f of fs115.slice(0, REVIEW_LINES_PER_FILE))
|
|
89555
89964
|
L.push(` \u2022 ${f.line ? `line ${f.line}: ` : ""}${excerpt(f)}`);
|
|
89556
|
-
if (
|
|
89557
|
-
L.push(import_chalk36.default.gray(` and ${
|
|
89965
|
+
if (fs115.length > REVIEW_LINES_PER_FILE)
|
|
89966
|
+
L.push(import_chalk36.default.gray(` and ${fs115.length - REVIEW_LINES_PER_FILE} similar lines`));
|
|
89558
89967
|
}
|
|
89559
89968
|
const more = files.length - REVIEW_FILES;
|
|
89560
89969
|
if (more > 0) L.push(import_chalk36.default.gray(` and ${more} more file${more === 1 ? "" : "s"}`));
|
|
@@ -90208,16 +90617,16 @@ var import_chalk40 = __toESM(require("chalk"));
|
|
|
90208
90617
|
|
|
90209
90618
|
// src/canary/plant.ts
|
|
90210
90619
|
init_cjs_shims();
|
|
90211
|
-
var
|
|
90212
|
-
var
|
|
90213
|
-
var
|
|
90620
|
+
var import_fs99 = __toESM(require("fs"));
|
|
90621
|
+
var import_os81 = __toESM(require("os"));
|
|
90622
|
+
var import_path98 = __toESM(require("path"));
|
|
90214
90623
|
init_jail();
|
|
90215
90624
|
init_registry2();
|
|
90216
90625
|
|
|
90217
90626
|
// src/canary/sites.ts
|
|
90218
90627
|
init_cjs_shims();
|
|
90219
|
-
var
|
|
90220
|
-
var
|
|
90628
|
+
var import_fs98 = __toESM(require("fs"));
|
|
90629
|
+
var import_path97 = __toESM(require("path"));
|
|
90221
90630
|
|
|
90222
90631
|
// src/canary/generate.ts
|
|
90223
90632
|
init_cjs_shims();
|
|
@@ -90312,26 +90721,26 @@ function generateSshKey() {
|
|
|
90312
90721
|
var SITES = {
|
|
90313
90722
|
"aws-profile": {
|
|
90314
90723
|
kind: "aws-profile",
|
|
90315
|
-
primary: (h) =>
|
|
90316
|
-
fallback: (h) =>
|
|
90724
|
+
primary: (h) => import_path97.default.join(h, ".aws", "credentials"),
|
|
90725
|
+
fallback: (h) => import_path97.default.join(h, ".aws", "credentials.bak"),
|
|
90317
90726
|
// SSO / profile-only / credential_process setups have ~/.aws/config and no
|
|
90318
90727
|
// credentials file; the SDK and CLI then parse ~/.aws/credentials on every
|
|
90319
90728
|
// profile lookup. A planted primary would be a file real tools read.
|
|
90320
|
-
preferFallback: (h) =>
|
|
90729
|
+
preferFallback: (h) => import_fs98.default.existsSync(import_path97.default.join(h, ".aws", "config")),
|
|
90321
90730
|
dirMode: 448,
|
|
90322
90731
|
generate: generateAwsProfile
|
|
90323
90732
|
},
|
|
90324
90733
|
"env-file": {
|
|
90325
90734
|
kind: "env-file",
|
|
90326
|
-
primary: (h) =>
|
|
90327
|
-
fallback: (h) =>
|
|
90735
|
+
primary: (h) => import_path97.default.join(h, ".env.bak"),
|
|
90736
|
+
fallback: (h) => import_path97.default.join(h, ".env.local.bak"),
|
|
90328
90737
|
dirMode: 493,
|
|
90329
90738
|
generate: generateEnvFile
|
|
90330
90739
|
},
|
|
90331
90740
|
"ssh-key": {
|
|
90332
90741
|
kind: "ssh-key",
|
|
90333
|
-
primary: (h) =>
|
|
90334
|
-
fallback: (h) =>
|
|
90742
|
+
primary: (h) => import_path97.default.join(h, ".ssh", "id_rsa_backup"),
|
|
90743
|
+
fallback: (h) => import_path97.default.join(h, ".ssh", "id_rsa.old"),
|
|
90335
90744
|
// ssh refuses a group-writable ~/.ssh for config / known_hosts reads.
|
|
90336
90745
|
dirMode: 448,
|
|
90337
90746
|
generate: generateSshKey
|
|
@@ -90344,12 +90753,12 @@ var isKind = (s) => ALL_KINDS.includes(s);
|
|
|
90344
90753
|
var liveRecords = (kind) => loadCanaries().filter((r) => r.kind === kind && !r.retiredAt);
|
|
90345
90754
|
var fileHashOf = (p) => {
|
|
90346
90755
|
try {
|
|
90347
|
-
return sha256Hex(
|
|
90756
|
+
return sha256Hex(import_fs99.default.readFileSync(p));
|
|
90348
90757
|
} catch {
|
|
90349
90758
|
return null;
|
|
90350
90759
|
}
|
|
90351
90760
|
};
|
|
90352
|
-
function plantKind(kind, home =
|
|
90761
|
+
function plantKind(kind, home = import_os81.default.homedir()) {
|
|
90353
90762
|
const site = SITES[kind];
|
|
90354
90763
|
const live = liveRecords(kind);
|
|
90355
90764
|
if (live.length > 0) {
|
|
@@ -90368,8 +90777,8 @@ function plantKind(kind, home = import_os80.default.homedir()) {
|
|
|
90368
90777
|
const primary = site.primary(home);
|
|
90369
90778
|
const fallback = site.fallback(home);
|
|
90370
90779
|
let target;
|
|
90371
|
-
if (!
|
|
90372
|
-
else if (!
|
|
90780
|
+
if (!import_fs99.default.existsSync(primary) && !site.preferFallback?.(home)) target = primary;
|
|
90781
|
+
else if (!import_fs99.default.existsSync(fallback)) target = fallback;
|
|
90373
90782
|
else {
|
|
90374
90783
|
return {
|
|
90375
90784
|
kind,
|
|
@@ -90380,11 +90789,11 @@ function plantKind(kind, home = import_os80.default.homedir()) {
|
|
|
90380
90789
|
recordIds: []
|
|
90381
90790
|
};
|
|
90382
90791
|
}
|
|
90383
|
-
const dir2 =
|
|
90792
|
+
const dir2 = import_path98.default.dirname(target);
|
|
90384
90793
|
const gen = site.generate();
|
|
90385
|
-
const createdDir =
|
|
90386
|
-
|
|
90387
|
-
|
|
90794
|
+
const createdDir = import_fs99.default.mkdirSync(dir2, { recursive: true, mode: site.dirMode }) !== void 0;
|
|
90795
|
+
import_fs99.default.writeFileSync(target, gen.text, { mode: 384, flag: "wx" });
|
|
90796
|
+
import_fs99.default.chmodSync(target, 384);
|
|
90388
90797
|
const fileHash = sha256Hex(gen.text);
|
|
90389
90798
|
regenerateUserJail(addJailPath(target, "block"));
|
|
90390
90799
|
const recordIds = gen.values.map(
|
|
@@ -90402,14 +90811,14 @@ function plantKind(kind, home = import_os80.default.homedir()) {
|
|
|
90402
90811
|
}
|
|
90403
90812
|
function allowedPathsFor(kind, home) {
|
|
90404
90813
|
const site = SITES[kind];
|
|
90405
|
-
return [site.primary(home), site.fallback(home)].map((x) =>
|
|
90814
|
+
return [site.primary(home), site.fallback(home)].map((x) => import_path98.default.resolve(x));
|
|
90406
90815
|
}
|
|
90407
|
-
function removeKind(kind, home =
|
|
90816
|
+
function removeKind(kind, home = import_os81.default.homedir()) {
|
|
90408
90817
|
const live = liveRecords(kind);
|
|
90409
90818
|
if (live.length === 0) return { kind, action: "absent" };
|
|
90410
90819
|
const p = live[0].path;
|
|
90411
90820
|
const { fileHash, createdDir } = live[0];
|
|
90412
|
-
if (!allowedPathsFor(kind, home).includes(
|
|
90821
|
+
if (!allowedPathsFor(kind, home).includes(import_path98.default.resolve(p))) {
|
|
90413
90822
|
return {
|
|
90414
90823
|
kind,
|
|
90415
90824
|
action: "refused",
|
|
@@ -90417,7 +90826,7 @@ function removeKind(kind, home = import_os80.default.homedir()) {
|
|
|
90417
90826
|
reason: `${p} is not a path node9 plants a ${kind} decoy at; refusing to delete it. If you believe this is a decoy, remove it by hand.`
|
|
90418
90827
|
};
|
|
90419
90828
|
}
|
|
90420
|
-
if (!
|
|
90829
|
+
if (!import_fs99.default.existsSync(p)) {
|
|
90421
90830
|
for (const r of live) retireCanary(r.id);
|
|
90422
90831
|
unjail(p);
|
|
90423
90832
|
return { kind, action: "already-gone", path: p };
|
|
@@ -90430,13 +90839,13 @@ function removeKind(kind, home = import_os80.default.homedir()) {
|
|
|
90430
90839
|
reason: `${p} changed since node9 wrote it; inspect and remove it by hand`
|
|
90431
90840
|
};
|
|
90432
90841
|
}
|
|
90433
|
-
|
|
90842
|
+
import_fs99.default.unlinkSync(p);
|
|
90434
90843
|
let dirRemoved = false;
|
|
90435
90844
|
if (createdDir) {
|
|
90436
|
-
const dir2 =
|
|
90845
|
+
const dir2 = import_path98.default.dirname(p);
|
|
90437
90846
|
try {
|
|
90438
|
-
if (
|
|
90439
|
-
|
|
90847
|
+
if (import_fs99.default.readdirSync(dir2).length === 0) {
|
|
90848
|
+
import_fs99.default.rmdirSync(dir2);
|
|
90440
90849
|
dirRemoved = true;
|
|
90441
90850
|
}
|
|
90442
90851
|
} catch {
|
|
@@ -90460,14 +90869,14 @@ function statusAll() {
|
|
|
90460
90869
|
const p = live[0].path;
|
|
90461
90870
|
return {
|
|
90462
90871
|
kind,
|
|
90463
|
-
state:
|
|
90872
|
+
state: import_fs99.default.existsSync(p) ? "planted" : "missing",
|
|
90464
90873
|
path: p,
|
|
90465
90874
|
records: live.length,
|
|
90466
90875
|
plantedAt: live[0].plantedAt
|
|
90467
90876
|
};
|
|
90468
90877
|
});
|
|
90469
90878
|
}
|
|
90470
|
-
function rotateKind(kind, home =
|
|
90879
|
+
function rotateKind(kind, home = import_os81.default.homedir()) {
|
|
90471
90880
|
const removed = removeKind(kind);
|
|
90472
90881
|
if (removed.action === "refused") return { removed };
|
|
90473
90882
|
return { removed, planted: plantKind(kind, home) };
|
|
@@ -90556,15 +90965,15 @@ init_daemon3();
|
|
|
90556
90965
|
// src/cli/commands/sandbox.ts
|
|
90557
90966
|
init_cjs_shims();
|
|
90558
90967
|
var import_chalk41 = __toESM(require("chalk"));
|
|
90559
|
-
var
|
|
90560
|
-
var
|
|
90968
|
+
var import_fs102 = __toESM(require("fs"));
|
|
90969
|
+
var import_path101 = __toESM(require("path"));
|
|
90561
90970
|
var import_child_process16 = require("child_process");
|
|
90562
90971
|
init_config();
|
|
90563
90972
|
|
|
90564
90973
|
// src/sandbox/config.ts
|
|
90565
90974
|
init_cjs_shims();
|
|
90566
|
-
var
|
|
90567
|
-
var
|
|
90975
|
+
var import_fs100 = __toESM(require("fs"));
|
|
90976
|
+
var import_path99 = __toESM(require("path"));
|
|
90568
90977
|
var import_yaml2 = require("yaml");
|
|
90569
90978
|
var SANDBOX_CONFIG_FILE = "node9.sandbox.yaml";
|
|
90570
90979
|
var FORBIDDEN_ENV = /* @__PURE__ */ new Set(["NODE9_API_KEY", "NODE9_API_URL"]);
|
|
@@ -90637,16 +91046,16 @@ function scaffoldSandboxYaml(agent) {
|
|
|
90637
91046
|
return header + (0, import_yaml2.stringify)(defaultSandboxConfig(agent));
|
|
90638
91047
|
}
|
|
90639
91048
|
function sandboxConfigPath(cwd = process.cwd()) {
|
|
90640
|
-
return
|
|
91049
|
+
return import_path99.default.join(cwd, SANDBOX_CONFIG_FILE);
|
|
90641
91050
|
}
|
|
90642
91051
|
function loadSandboxConfig(cwd = process.cwd(), fallbackAgent = "claude") {
|
|
90643
91052
|
const p = sandboxConfigPath(cwd);
|
|
90644
|
-
if (!
|
|
91053
|
+
if (!import_fs100.default.existsSync(p)) {
|
|
90645
91054
|
throw new Error(`sandbox: ${SANDBOX_CONFIG_FILE} not found \u2014 run \`node9 sandbox new\` first.`);
|
|
90646
91055
|
}
|
|
90647
91056
|
let raw;
|
|
90648
91057
|
try {
|
|
90649
|
-
raw = (0, import_yaml2.parse)(
|
|
91058
|
+
raw = (0, import_yaml2.parse)(import_fs100.default.readFileSync(p, "utf-8"));
|
|
90650
91059
|
} catch (err2) {
|
|
90651
91060
|
throw new Error(
|
|
90652
91061
|
`sandbox: ${SANDBOX_CONFIG_FILE} is not valid YAML \u2014 ${err2.message}`
|
|
@@ -90707,14 +91116,14 @@ init_atomic_write();
|
|
|
90707
91116
|
|
|
90708
91117
|
// src/sandbox/runtime.ts
|
|
90709
91118
|
init_cjs_shims();
|
|
90710
|
-
var
|
|
90711
|
-
var
|
|
90712
|
-
var
|
|
91119
|
+
var import_fs101 = __toESM(require("fs"));
|
|
91120
|
+
var import_os82 = __toESM(require("os"));
|
|
91121
|
+
var import_path100 = __toESM(require("path"));
|
|
90713
91122
|
var import_crypto27 = __toESM(require("crypto"));
|
|
90714
91123
|
var import_child_process15 = require("child_process");
|
|
90715
91124
|
init_templates();
|
|
90716
91125
|
function sandboxDataDir(cwd = process.cwd()) {
|
|
90717
|
-
return
|
|
91126
|
+
return import_path100.default.join(cwd, ".node9", "sandbox", "data");
|
|
90718
91127
|
}
|
|
90719
91128
|
function detectEngine(engine) {
|
|
90720
91129
|
const r = (0, import_child_process15.spawnSync)(engine, ["--version"], { encoding: "utf-8" });
|
|
@@ -90725,7 +91134,7 @@ function detectEngine(engine) {
|
|
|
90725
91134
|
}
|
|
90726
91135
|
function agentCredentialsMount(agent) {
|
|
90727
91136
|
const rel = agent === "codex" ? ".codex/auth.json" : ".claude/.credentials.json";
|
|
90728
|
-
return { hostPath:
|
|
91137
|
+
return { hostPath: import_path100.default.join(import_os82.default.homedir(), rel), target: `/home/${RUN_AS_USER}/${rel}` };
|
|
90729
91138
|
}
|
|
90730
91139
|
function buildRunArgs(opts) {
|
|
90731
91140
|
const { config, workspaceHostPath, dataHostPath, allowlistHostPath, agentArgs } = opts;
|
|
@@ -90735,7 +91144,7 @@ function buildRunArgs(opts) {
|
|
|
90735
91144
|
args.push("-v", `${allowlistHostPath}:${ALLOWED_DOMAINS_PATH}:ro`);
|
|
90736
91145
|
if (config.node9.mountAgentCredentials) {
|
|
90737
91146
|
const creds = agentCredentialsMount(config.agent);
|
|
90738
|
-
if (
|
|
91147
|
+
if (import_fs101.default.existsSync(creds.hostPath)) {
|
|
90739
91148
|
args.push("-v", `${creds.hostPath}:${creds.target}`);
|
|
90740
91149
|
}
|
|
90741
91150
|
}
|
|
@@ -90753,30 +91162,30 @@ function imageContentHash(dockerfile, entrypoint) {
|
|
|
90753
91162
|
return import_crypto27.default.createHash("sha256").update(dockerfile).update("\0").update(entrypoint).digest("hex").slice(0, 16);
|
|
90754
91163
|
}
|
|
90755
91164
|
function sandboxBuildDir(cwd = process.cwd()) {
|
|
90756
|
-
return
|
|
91165
|
+
return import_path100.default.join(cwd, ".node9", "sandbox", "build");
|
|
90757
91166
|
}
|
|
90758
91167
|
function writeBuildContext(cwd, dockerfile, entrypoint) {
|
|
90759
91168
|
const dir2 = sandboxBuildDir(cwd);
|
|
90760
|
-
|
|
90761
|
-
|
|
90762
|
-
|
|
91169
|
+
import_fs101.default.mkdirSync(dir2, { recursive: true });
|
|
91170
|
+
import_fs101.default.writeFileSync(import_path100.default.join(dir2, "Dockerfile"), dockerfile);
|
|
91171
|
+
import_fs101.default.writeFileSync(import_path100.default.join(dir2, "entrypoint.sh"), entrypoint);
|
|
90763
91172
|
return dir2;
|
|
90764
91173
|
}
|
|
90765
91174
|
function writeAllowlist(cwd, hosts) {
|
|
90766
|
-
const dir2 =
|
|
90767
|
-
|
|
90768
|
-
const p =
|
|
90769
|
-
|
|
91175
|
+
const dir2 = import_path100.default.join(cwd, ".node9", "sandbox");
|
|
91176
|
+
import_fs101.default.mkdirSync(dir2, { recursive: true });
|
|
91177
|
+
const p = import_path100.default.join(dir2, "allowed-domains.txt");
|
|
91178
|
+
import_fs101.default.writeFileSync(p, hosts.join("\n") + "\n");
|
|
90770
91179
|
return p;
|
|
90771
91180
|
}
|
|
90772
91181
|
function resolveHomePath(p) {
|
|
90773
|
-
return p.startsWith("~") ?
|
|
91182
|
+
return p.startsWith("~") ? import_path100.default.join(import_os82.default.homedir(), p.slice(1)) : import_path100.default.resolve(p);
|
|
90774
91183
|
}
|
|
90775
91184
|
|
|
90776
91185
|
// src/cli/commands/sandbox.ts
|
|
90777
91186
|
function seedDataDirConfig(dataDir, sandbox) {
|
|
90778
|
-
|
|
90779
|
-
const configPath2 =
|
|
91187
|
+
import_fs102.default.mkdirSync(dataDir, { recursive: true });
|
|
91188
|
+
const configPath2 = import_path101.default.join(dataDir, "config.json");
|
|
90780
91189
|
const seed = {
|
|
90781
91190
|
settings: {
|
|
90782
91191
|
approvers: {
|
|
@@ -90787,7 +91196,7 @@ function seedDataDirConfig(dataDir, sandbox) {
|
|
|
90787
91196
|
}
|
|
90788
91197
|
}
|
|
90789
91198
|
};
|
|
90790
|
-
|
|
91199
|
+
import_fs102.default.writeFileSync(configPath2, JSON.stringify(seed, null, 2), { mode: 384 });
|
|
90791
91200
|
}
|
|
90792
91201
|
function registerSandboxCommand(program2, version2) {
|
|
90793
91202
|
const node9Version2 = pinnedNode9Version(version2);
|
|
@@ -90796,7 +91205,7 @@ function registerSandboxCommand(program2, version2) {
|
|
|
90796
91205
|
const agent = opts.agent === "codex" ? "codex" : "claude";
|
|
90797
91206
|
const p = sandboxConfigPath();
|
|
90798
91207
|
try {
|
|
90799
|
-
|
|
91208
|
+
import_fs102.default.writeFileSync(p, scaffoldSandboxYaml(agent), { flag: "wx" });
|
|
90800
91209
|
} catch (e) {
|
|
90801
91210
|
if (e.code !== "EEXIST") throw e;
|
|
90802
91211
|
console.log(
|
|
@@ -90843,8 +91252,8 @@ function registerSandboxCommand(program2, version2) {
|
|
|
90843
91252
|
const buildDir = writeBuildContext(cwd, dockerfile, entrypoint);
|
|
90844
91253
|
const hash2 = imageContentHash(dockerfile, entrypoint);
|
|
90845
91254
|
const image = sandbox.runtime.image;
|
|
90846
|
-
const hashFile =
|
|
90847
|
-
const lastHash =
|
|
91255
|
+
const hashFile = import_path101.default.join(sandboxBuildDir(cwd), ".image-hash");
|
|
91256
|
+
const lastHash = import_fs102.default.existsSync(hashFile) ? import_fs102.default.readFileSync(hashFile, "utf-8").trim() : "";
|
|
90848
91257
|
const imageExists = (0, import_child_process16.spawnSync)(sandbox.runtime.engine, ["image", "inspect", image], { stdio: "ignore" }).status === 0;
|
|
90849
91258
|
const needBuild = sandbox.runtime.rebuild === "always" || !imageExists || sandbox.runtime.rebuild !== "never" && lastHash !== hash2;
|
|
90850
91259
|
if (needBuild) {
|
|
@@ -90870,7 +91279,7 @@ function registerSandboxCommand(program2, version2) {
|
|
|
90870
91279
|
});
|
|
90871
91280
|
if (sandbox.node9.mountAgentCredentials) {
|
|
90872
91281
|
const creds = agentCredentialsMount(sandbox.agent);
|
|
90873
|
-
if (
|
|
91282
|
+
if (import_fs102.default.existsSync(creds.hostPath)) {
|
|
90874
91283
|
console.log(import_chalk41.default.dim(` mounting ${creds.hostPath} (agent credentials, rw)`));
|
|
90875
91284
|
} else {
|
|
90876
91285
|
console.log(
|
|
@@ -90886,20 +91295,20 @@ function registerSandboxCommand(program2, version2) {
|
|
|
90886
91295
|
process.exit(r.status ?? 0);
|
|
90887
91296
|
});
|
|
90888
91297
|
cmd.command("tail").description("Stream the sandbox's audit log (host-side)").action(() => {
|
|
90889
|
-
const auditPath =
|
|
90890
|
-
if (!
|
|
91298
|
+
const auditPath = import_path101.default.join(sandboxDataDir(), "audit.log");
|
|
91299
|
+
if (!import_fs102.default.existsSync(auditPath)) {
|
|
90891
91300
|
console.log(import_chalk41.default.dim(" no sandbox audit yet."));
|
|
90892
91301
|
return;
|
|
90893
91302
|
}
|
|
90894
91303
|
(0, import_child_process16.spawnSync)("tail", ["-f", auditPath], { stdio: "inherit" });
|
|
90895
91304
|
});
|
|
90896
91305
|
cmd.command("logs").description("Dump the sandbox's audit log").action(() => {
|
|
90897
|
-
const auditPath =
|
|
90898
|
-
if (!
|
|
91306
|
+
const auditPath = import_path101.default.join(sandboxDataDir(), "audit.log");
|
|
91307
|
+
if (!import_fs102.default.existsSync(auditPath)) {
|
|
90899
91308
|
console.log(import_chalk41.default.dim(" no sandbox audit yet."));
|
|
90900
91309
|
return;
|
|
90901
91310
|
}
|
|
90902
|
-
process.stdout.write(
|
|
91311
|
+
process.stdout.write(import_fs102.default.readFileSync(auditPath, "utf-8"));
|
|
90903
91312
|
});
|
|
90904
91313
|
cmd.command("clean").description("Remove the sandbox image, build context, and data").action(() => {
|
|
90905
91314
|
const cwd = process.cwd();
|
|
@@ -90913,7 +91322,7 @@ function registerSandboxCommand(program2, version2) {
|
|
|
90913
91322
|
stdio: "ignore"
|
|
90914
91323
|
});
|
|
90915
91324
|
}
|
|
90916
|
-
|
|
91325
|
+
import_fs102.default.rmSync(import_path101.default.join(cwd, ".node9", "sandbox"), { recursive: true, force: true });
|
|
90917
91326
|
console.log(import_chalk41.default.green(" \u2713 sandbox image + build + data removed."));
|
|
90918
91327
|
});
|
|
90919
91328
|
}
|
|
@@ -91142,13 +91551,13 @@ function registerPackageIndexCommand(program2) {
|
|
|
91142
91551
|
// src/cli/commands/skill-pin.ts
|
|
91143
91552
|
init_cjs_shims();
|
|
91144
91553
|
var import_chalk45 = __toESM(require("chalk"));
|
|
91145
|
-
var
|
|
91146
|
-
var
|
|
91147
|
-
var
|
|
91554
|
+
var import_fs103 = __toESM(require("fs"));
|
|
91555
|
+
var import_os83 = __toESM(require("os"));
|
|
91556
|
+
var import_path102 = __toESM(require("path"));
|
|
91148
91557
|
init_skill_pin();
|
|
91149
91558
|
function wipeSkillSessions() {
|
|
91150
91559
|
try {
|
|
91151
|
-
|
|
91560
|
+
import_fs103.default.rmSync(import_path102.default.join(import_os83.default.homedir(), ".node9", "skill-sessions"), {
|
|
91152
91561
|
recursive: true,
|
|
91153
91562
|
force: true
|
|
91154
91563
|
});
|
|
@@ -91231,15 +91640,15 @@ function registerSkillPinCommand(program2) {
|
|
|
91231
91640
|
|
|
91232
91641
|
// src/cli/commands/decisions.ts
|
|
91233
91642
|
init_cjs_shims();
|
|
91234
|
-
var
|
|
91235
|
-
var
|
|
91236
|
-
var
|
|
91643
|
+
var import_fs104 = __toESM(require("fs"));
|
|
91644
|
+
var import_os84 = __toESM(require("os"));
|
|
91645
|
+
var import_path103 = __toESM(require("path"));
|
|
91237
91646
|
var import_chalk46 = __toESM(require("chalk"));
|
|
91238
|
-
var DECISIONS_FILE2 =
|
|
91647
|
+
var DECISIONS_FILE2 = import_path103.default.join(import_os84.default.homedir(), ".node9", "decisions.json");
|
|
91239
91648
|
function readDecisions() {
|
|
91240
91649
|
try {
|
|
91241
|
-
if (!
|
|
91242
|
-
const raw =
|
|
91650
|
+
if (!import_fs104.default.existsSync(DECISIONS_FILE2)) return {};
|
|
91651
|
+
const raw = import_fs104.default.readFileSync(DECISIONS_FILE2, "utf-8");
|
|
91243
91652
|
const parsed = JSON.parse(raw);
|
|
91244
91653
|
const out = {};
|
|
91245
91654
|
for (const [k, v] of Object.entries(parsed)) {
|
|
@@ -91251,11 +91660,11 @@ function readDecisions() {
|
|
|
91251
91660
|
}
|
|
91252
91661
|
}
|
|
91253
91662
|
function writeDecisions(d) {
|
|
91254
|
-
const dir2 =
|
|
91255
|
-
if (!
|
|
91663
|
+
const dir2 = import_path103.default.dirname(DECISIONS_FILE2);
|
|
91664
|
+
if (!import_fs104.default.existsSync(dir2)) import_fs104.default.mkdirSync(dir2, { recursive: true });
|
|
91256
91665
|
const tmp = `${DECISIONS_FILE2}.${process.pid}.tmp`;
|
|
91257
|
-
|
|
91258
|
-
|
|
91666
|
+
import_fs104.default.writeFileSync(tmp, JSON.stringify(d, null, 2));
|
|
91667
|
+
import_fs104.default.renameSync(tmp, DECISIONS_FILE2);
|
|
91259
91668
|
}
|
|
91260
91669
|
function registerDecisionsCommand(program2) {
|
|
91261
91670
|
const cmd = program2.command("decisions").description('Manage persistent "Always Allow" / "Always Deny" tool decisions');
|
|
@@ -91313,15 +91722,15 @@ Persistent decisions (${entries.length})
|
|
|
91313
91722
|
// src/cli/commands/dlp.ts
|
|
91314
91723
|
init_cjs_shims();
|
|
91315
91724
|
var import_chalk47 = __toESM(require("chalk"));
|
|
91316
|
-
var
|
|
91317
|
-
var
|
|
91318
|
-
var
|
|
91725
|
+
var import_fs105 = __toESM(require("fs"));
|
|
91726
|
+
var import_path104 = __toESM(require("path"));
|
|
91727
|
+
var import_os85 = __toESM(require("os"));
|
|
91319
91728
|
init_safe_text();
|
|
91320
|
-
var AUDIT_LOG =
|
|
91321
|
-
var RESOLVED_FILE =
|
|
91729
|
+
var AUDIT_LOG = import_path104.default.join(import_os85.default.homedir(), ".node9", "audit.log");
|
|
91730
|
+
var RESOLVED_FILE = import_path104.default.join(import_os85.default.homedir(), ".node9", "dlp-resolved.json");
|
|
91322
91731
|
function loadResolved() {
|
|
91323
91732
|
try {
|
|
91324
|
-
const raw = JSON.parse(
|
|
91733
|
+
const raw = JSON.parse(import_fs105.default.readFileSync(RESOLVED_FILE, "utf-8"));
|
|
91325
91734
|
return new Set(raw);
|
|
91326
91735
|
} catch {
|
|
91327
91736
|
return /* @__PURE__ */ new Set();
|
|
@@ -91329,13 +91738,13 @@ function loadResolved() {
|
|
|
91329
91738
|
}
|
|
91330
91739
|
function saveResolved(resolved) {
|
|
91331
91740
|
try {
|
|
91332
|
-
|
|
91741
|
+
import_fs105.default.writeFileSync(RESOLVED_FILE, JSON.stringify([...resolved], null, 2), { mode: 384 });
|
|
91333
91742
|
} catch {
|
|
91334
91743
|
}
|
|
91335
91744
|
}
|
|
91336
91745
|
function loadDlpFindings() {
|
|
91337
|
-
if (!
|
|
91338
|
-
return
|
|
91746
|
+
if (!import_fs105.default.existsSync(AUDIT_LOG)) return [];
|
|
91747
|
+
return import_fs105.default.readFileSync(AUDIT_LOG, "utf-8").split("\n").flatMap((line) => {
|
|
91339
91748
|
if (!line.trim()) return [];
|
|
91340
91749
|
try {
|
|
91341
91750
|
const e = JSON.parse(line);
|
|
@@ -91434,15 +91843,15 @@ function registerDlpCommand(program2) {
|
|
|
91434
91843
|
// src/cli/commands/mask.ts
|
|
91435
91844
|
init_cjs_shims();
|
|
91436
91845
|
var import_chalk48 = __toESM(require("chalk"));
|
|
91437
|
-
var
|
|
91438
|
-
var
|
|
91439
|
-
var
|
|
91846
|
+
var import_fs106 = __toESM(require("fs"));
|
|
91847
|
+
var import_path105 = __toESM(require("path"));
|
|
91848
|
+
var import_os86 = __toESM(require("os"));
|
|
91440
91849
|
init_dlp();
|
|
91441
91850
|
function findJsonlFiles(dir2) {
|
|
91442
91851
|
const results = [];
|
|
91443
|
-
if (!
|
|
91444
|
-
for (const entry of
|
|
91445
|
-
const full =
|
|
91852
|
+
if (!import_fs106.default.existsSync(dir2)) return results;
|
|
91853
|
+
for (const entry of import_fs106.default.readdirSync(dir2, { withFileTypes: true })) {
|
|
91854
|
+
const full = import_path105.default.join(dir2, entry.name);
|
|
91446
91855
|
if (entry.isDirectory()) results.push(...findJsonlFiles(full));
|
|
91447
91856
|
else if (entry.isFile() && entry.name.endsWith(".jsonl")) results.push(full);
|
|
91448
91857
|
}
|
|
@@ -91485,7 +91894,7 @@ function redactJson(obj) {
|
|
|
91485
91894
|
function processFile(filePath, dryRun) {
|
|
91486
91895
|
let raw;
|
|
91487
91896
|
try {
|
|
91488
|
-
raw =
|
|
91897
|
+
raw = import_fs106.default.readFileSync(filePath, "utf-8");
|
|
91489
91898
|
} catch {
|
|
91490
91899
|
return { redactedLines: 0, patterns: [] };
|
|
91491
91900
|
}
|
|
@@ -91517,14 +91926,14 @@ function processFile(filePath, dryRun) {
|
|
|
91517
91926
|
}
|
|
91518
91927
|
}
|
|
91519
91928
|
if (!dryRun && redactedLines > 0) {
|
|
91520
|
-
|
|
91929
|
+
import_fs106.default.writeFileSync(filePath, newLines.join("\n"), "utf-8");
|
|
91521
91930
|
}
|
|
91522
91931
|
return { redactedLines, patterns };
|
|
91523
91932
|
}
|
|
91524
91933
|
function processJsonFile(filePath, dryRun) {
|
|
91525
91934
|
let raw;
|
|
91526
91935
|
try {
|
|
91527
|
-
raw =
|
|
91936
|
+
raw = import_fs106.default.readFileSync(filePath, "utf-8");
|
|
91528
91937
|
} catch {
|
|
91529
91938
|
return { redactedLines: 0, patterns: [] };
|
|
91530
91939
|
}
|
|
@@ -91537,15 +91946,15 @@ function processJsonFile(filePath, dryRun) {
|
|
|
91537
91946
|
const { value, modified, found } = redactJson(parsed);
|
|
91538
91947
|
if (!modified) return { redactedLines: 0, patterns: [] };
|
|
91539
91948
|
if (!dryRun) {
|
|
91540
|
-
|
|
91949
|
+
import_fs106.default.writeFileSync(filePath, JSON.stringify(value, null, 2), "utf-8");
|
|
91541
91950
|
}
|
|
91542
91951
|
return { redactedLines: 1, patterns: found };
|
|
91543
91952
|
}
|
|
91544
91953
|
function findJsonFiles(dir2) {
|
|
91545
91954
|
const results = [];
|
|
91546
|
-
if (!
|
|
91547
|
-
for (const entry of
|
|
91548
|
-
const full =
|
|
91955
|
+
if (!import_fs106.default.existsSync(dir2)) return results;
|
|
91956
|
+
for (const entry of import_fs106.default.readdirSync(dir2, { withFileTypes: true })) {
|
|
91957
|
+
const full = import_path105.default.join(dir2, entry.name);
|
|
91549
91958
|
if (entry.isDirectory()) results.push(...findJsonFiles(full));
|
|
91550
91959
|
else if (entry.isFile() && entry.name.endsWith(".json")) results.push(full);
|
|
91551
91960
|
}
|
|
@@ -91554,9 +91963,9 @@ function findJsonFiles(dir2) {
|
|
|
91554
91963
|
function registerMaskCommand(program2) {
|
|
91555
91964
|
program2.command("mask").description("Redact plaintext secrets from local AI session history files").option("--dry-run", "show what would be redacted without making changes").option("--all", "scan all history (default: last 30 days)").action(async (options) => {
|
|
91556
91965
|
const dryRun = !!options.dryRun;
|
|
91557
|
-
const home =
|
|
91558
|
-
const claudeDir =
|
|
91559
|
-
const geminiDir =
|
|
91966
|
+
const home = import_os86.default.homedir();
|
|
91967
|
+
const claudeDir = import_path105.default.join(home, ".claude", "projects");
|
|
91968
|
+
const geminiDir = import_path105.default.join(home, ".gemini", "tmp");
|
|
91560
91969
|
const allFiles = [
|
|
91561
91970
|
...findJsonlFiles(claudeDir).map((p) => ({ path: p, type: "jsonl" })),
|
|
91562
91971
|
...findJsonFiles(geminiDir).map((p) => ({ path: p, type: "json" }))
|
|
@@ -91564,7 +91973,7 @@ function registerMaskCommand(program2) {
|
|
|
91564
91973
|
const cutoff = options.all ? null : new Date(Date.now() - 30 * 24 * 60 * 60 * 1e3);
|
|
91565
91974
|
const filtered = cutoff ? allFiles.filter((f) => {
|
|
91566
91975
|
try {
|
|
91567
|
-
return
|
|
91976
|
+
return import_fs106.default.statSync(f.path).mtime >= cutoff;
|
|
91568
91977
|
} catch {
|
|
91569
91978
|
return false;
|
|
91570
91979
|
}
|
|
@@ -91621,7 +92030,7 @@ function registerMaskCommand(program2) {
|
|
|
91621
92030
|
init_blast();
|
|
91622
92031
|
init_safe_text();
|
|
91623
92032
|
var { version } = JSON.parse(
|
|
91624
|
-
|
|
92033
|
+
import_fs110.default.readFileSync(import_path109.default.join(__dirname, "../package.json"), "utf-8")
|
|
91625
92034
|
);
|
|
91626
92035
|
var program = new import_commander.Command();
|
|
91627
92036
|
program.name("node9").description("The Sudo Command for AI Agents").version(version);
|
|
@@ -91779,8 +92188,8 @@ function undoLeftoverNote() {
|
|
|
91779
92188
|
program.command("uninstall").description("Remove all Node9 hooks and optionally delete config files").option("--purge", "Also delete ~/.node9/ directory (config, audit log, credentials)").action(async (options) => {
|
|
91780
92189
|
console.log(import_chalk50.default.cyan("\n\u{1F6E1}\uFE0F Node9 Uninstall\n"));
|
|
91781
92190
|
try {
|
|
91782
|
-
const credRaw =
|
|
91783
|
-
|
|
92191
|
+
const credRaw = import_fs110.default.readFileSync(
|
|
92192
|
+
import_path109.default.join(import_os90.default.homedir(), ".node9", "credentials.json"),
|
|
91784
92193
|
"utf-8"
|
|
91785
92194
|
);
|
|
91786
92195
|
const prof = JSON.parse(credRaw)[process.env.NODE9_PROFILE || "default"];
|
|
@@ -91855,7 +92264,7 @@ program.command("uninstall").description("Remove all Node9 hooks and optionally
|
|
|
91855
92264
|
if (removed.length > 0 || refused.length > 0) {
|
|
91856
92265
|
console.log(import_chalk50.default.bold("\nRemoving decoy credentials..."));
|
|
91857
92266
|
for (const r of removed) {
|
|
91858
|
-
if (r.path) console.log(import_chalk50.default.green(` \u2705 ${r.path.replace(
|
|
92267
|
+
if (r.path) console.log(import_chalk50.default.green(` \u2705 ${r.path.replace(import_os90.default.homedir(), "~")}`));
|
|
91859
92268
|
}
|
|
91860
92269
|
for (const r of refused) {
|
|
91861
92270
|
decoysLeft.push(r.path ?? "(unknown path)");
|
|
@@ -91872,8 +92281,8 @@ program.command("uninstall").description("Remove all Node9 hooks and optionally
|
|
|
91872
92281
|
decoysLeft = ["(the decoy registry could not be read)"];
|
|
91873
92282
|
}
|
|
91874
92283
|
if (options.purge) {
|
|
91875
|
-
const node9Dir =
|
|
91876
|
-
if (
|
|
92284
|
+
const node9Dir = import_path109.default.join(import_os90.default.homedir(), ".node9");
|
|
92285
|
+
if (import_fs110.default.existsSync(node9Dir)) {
|
|
91877
92286
|
const alsoSnapshots = undoLeftoverPaths().length > 0 ? ", old undo snapshots" : "";
|
|
91878
92287
|
if (decoysLeft.length > 0) {
|
|
91879
92288
|
console.error(import_chalk50.default.red("\n \u26A0\uFE0F Decoy credential files are still on disk:"));
|
|
@@ -91889,8 +92298,8 @@ program.command("uninstall").description("Remove all Node9 hooks and optionally
|
|
|
91889
92298
|
default: false
|
|
91890
92299
|
});
|
|
91891
92300
|
if (confirmed) {
|
|
91892
|
-
|
|
91893
|
-
if (
|
|
92301
|
+
import_fs110.default.rmSync(node9Dir, { recursive: true });
|
|
92302
|
+
if (import_fs110.default.existsSync(node9Dir)) {
|
|
91894
92303
|
console.error(
|
|
91895
92304
|
import_chalk50.default.red("\n \u26A0\uFE0F ~/.node9/ could not be fully deleted \u2014 remove it manually.")
|
|
91896
92305
|
);
|
|
@@ -92046,7 +92455,7 @@ program.command("tail").description("Stream live agent activity to the terminal"
|
|
|
92046
92455
|
});
|
|
92047
92456
|
program.command("monitor").description("Live interactive dashboard \u2014 activity feed, approvals, security signals").action(async () => {
|
|
92048
92457
|
try {
|
|
92049
|
-
const dashboardPath =
|
|
92458
|
+
const dashboardPath = import_path109.default.join(__dirname, "dashboard.mjs");
|
|
92050
92459
|
const dynamicImport = new Function("id", "return import(id)");
|
|
92051
92460
|
const mod = await dynamicImport(`file://${dashboardPath}`);
|
|
92052
92461
|
await mod.startMonitor();
|
|
@@ -92084,14 +92493,14 @@ Claude Code spawns this command every ~300ms and writes a JSON payload to stdin.
|
|
|
92084
92493
|
Run "node9 addto claude" to register it as the statusLine.`
|
|
92085
92494
|
).argument("[subcommand]", 'Optional: "debug on" / "debug off" to toggle stdin logging').argument("[state]", 'on|off \u2014 used with "debug" subcommand').action(async (subcommand, state) => {
|
|
92086
92495
|
if (subcommand === "debug") {
|
|
92087
|
-
const flagFile =
|
|
92496
|
+
const flagFile = import_path109.default.join(import_os90.default.homedir(), ".node9", "hud-debug");
|
|
92088
92497
|
if (state === "on") {
|
|
92089
|
-
|
|
92090
|
-
|
|
92498
|
+
import_fs110.default.mkdirSync(import_path109.default.dirname(flagFile), { recursive: true });
|
|
92499
|
+
import_fs110.default.writeFileSync(flagFile, "");
|
|
92091
92500
|
console.log("HUD debug logging enabled \u2192 ~/.node9/hud-debug.log");
|
|
92092
92501
|
console.log("Tail it with: tail -f ~/.node9/hud-debug.log");
|
|
92093
92502
|
} else if (state === "off") {
|
|
92094
|
-
if (
|
|
92503
|
+
if (import_fs110.default.existsSync(flagFile)) import_fs110.default.unlinkSync(flagFile);
|
|
92095
92504
|
console.log("HUD debug logging disabled.");
|
|
92096
92505
|
} else {
|
|
92097
92506
|
console.error("Usage: node9 hud debug on|off");
|
|
@@ -92206,6 +92615,7 @@ registerTrustCommand(program);
|
|
|
92206
92615
|
registerSyncCommand(program);
|
|
92207
92616
|
registerAgentsCommand(program);
|
|
92208
92617
|
registerScanCommand(program);
|
|
92618
|
+
registerForecastCasesCommand(program);
|
|
92209
92619
|
registerPostureCommand(program);
|
|
92210
92620
|
registerScanRepoCommand(program);
|
|
92211
92621
|
registerEgressCommand(program);
|
|
@@ -92225,9 +92635,9 @@ if (process.argv[2] !== "daemon") {
|
|
|
92225
92635
|
const isCheckHook = process.argv[2] === "check";
|
|
92226
92636
|
if (isCheckHook) {
|
|
92227
92637
|
if (process.env.NODE9_DEBUG === "1" || getConfig().settings.enableHookLogDebug) {
|
|
92228
|
-
const logPath =
|
|
92638
|
+
const logPath = import_path109.default.join(import_os90.default.homedir(), ".node9", "hook-debug.log");
|
|
92229
92639
|
const msg = reason instanceof Error ? reason.message : String(reason);
|
|
92230
|
-
|
|
92640
|
+
import_fs110.default.appendFileSync(logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] UNHANDLED: ${msg}
|
|
92231
92641
|
`);
|
|
92232
92642
|
}
|
|
92233
92643
|
process.exit(0);
|