@node9/proxy 2.51.0 → 2.53.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 +2220 -1625
- package/dist/dashboard.mjs +599 -229
- package/dist/hook.js +814 -287
- package/dist/index.js +615 -216
- package/dist/index.mjs +615 -216
- package/dist/scan-ink.mjs +42 -2
- package/package.json +1 -1
package/dist/dashboard.mjs
CHANGED
|
@@ -470,15 +470,15 @@ function ssrfExemptMatches(entries, normalized) {
|
|
|
470
470
|
continue;
|
|
471
471
|
}
|
|
472
472
|
if (!target) continue;
|
|
473
|
-
const
|
|
473
|
+
const base32 = bitsOf(normalizeIpLiteral(entry.slice(0, slash)) ?? "");
|
|
474
474
|
const prefixText = entry.slice(slash + 1);
|
|
475
475
|
const prefix = /^\d+$/.test(prefixText) ? Number(prefixText) : NaN;
|
|
476
|
-
if (!
|
|
476
|
+
if (!base32 || !Number.isInteger(prefix) || prefix < 0 || // A v4 range never matches a v6 address, and the reverse: the widths
|
|
477
477
|
// differ, so `0.0.0.0/0` does not release `::1`.
|
|
478
|
-
|
|
478
|
+
base32.length !== target.length || prefix > base32.length) {
|
|
479
479
|
continue;
|
|
480
480
|
}
|
|
481
|
-
if (
|
|
481
|
+
if (base32.slice(0, prefix) === target.slice(0, prefix)) return true;
|
|
482
482
|
}
|
|
483
483
|
return false;
|
|
484
484
|
}
|
|
@@ -532,6 +532,10 @@ function reviewsEveryAgentFileWrite(mode) {
|
|
|
532
532
|
const level = levelOf(mode);
|
|
533
533
|
return level === "strict" || level === "block-all";
|
|
534
534
|
}
|
|
535
|
+
function holdsSendsWithoutDaemon(mode) {
|
|
536
|
+
const level = levelOf(mode);
|
|
537
|
+
return level === "strict" || level === "block-all";
|
|
538
|
+
}
|
|
535
539
|
function isBlockAll(mode) {
|
|
536
540
|
return levelOf(mode) === "block-all";
|
|
537
541
|
}
|
|
@@ -1739,6 +1743,39 @@ function protectedLiteral(code2, isProtected) {
|
|
|
1739
1743
|
}
|
|
1740
1744
|
return null;
|
|
1741
1745
|
}
|
|
1746
|
+
function inlineReadPaths(language, code2, preload = {}) {
|
|
1747
|
+
const out = [];
|
|
1748
|
+
const before = READ_BEFORE[language];
|
|
1749
|
+
const after = READ_AFTER[language];
|
|
1750
|
+
const assigned = /* @__PURE__ */ new Map();
|
|
1751
|
+
for (const m of code2.matchAll(STRING_LITERAL)) {
|
|
1752
|
+
const raw = m[2].trim();
|
|
1753
|
+
const value = raw.replace(/^[<+]\s*/, "");
|
|
1754
|
+
if (!value) continue;
|
|
1755
|
+
const head = code2.slice(Math.max(0, m.index - 160), m.index);
|
|
1756
|
+
const tail = code2.slice(m.index + m[0].length, m.index + m[0].length + 40);
|
|
1757
|
+
if (/^[>|]/.test(raw) || WRITE_MODE_AFTER.test(tail) || PERL_WRITE_BEFORE.test(head)) continue;
|
|
1758
|
+
if (before.test(head) || after?.test(tail) || language === "node" && DOTENV_PATH_OPTION.test(head)) {
|
|
1759
|
+
out.push(value);
|
|
1760
|
+
continue;
|
|
1761
|
+
}
|
|
1762
|
+
const name = ASSIGNED.exec(head)?.[1];
|
|
1763
|
+
if (name) assigned.set(name, [...assigned.get(name) ?? [], value]);
|
|
1764
|
+
}
|
|
1765
|
+
if (assigned.size > 0) {
|
|
1766
|
+
const opened = /* @__PURE__ */ new Set();
|
|
1767
|
+
for (const m of code2.matchAll(OPENED_NAME[language])) opened.add(m[1] ?? m[2]);
|
|
1768
|
+
for (const [name, values] of assigned) if (opened.has(name)) out.push(...values);
|
|
1769
|
+
}
|
|
1770
|
+
if (language === "python" || language === "node") {
|
|
1771
|
+
const d = DOTENV[language];
|
|
1772
|
+
const readsEnv = d.env.test(code2);
|
|
1773
|
+
const loads = /dotenv/.test(code2) && d.load.test(code2) && !d.literalPath.test(code2);
|
|
1774
|
+
if ((loads || preload.dotenv) && (readsEnv || d.values.test(code2))) out.push(".env");
|
|
1775
|
+
if (readsEnv) out.push(...preload.envFiles ?? []);
|
|
1776
|
+
}
|
|
1777
|
+
return out;
|
|
1778
|
+
}
|
|
1742
1779
|
function amplifies(language, code2) {
|
|
1743
1780
|
const loop = language === "python" ? /\bwhile\s+(?:True|1)\s*:/ : language === "node" ? /\bwhile\s*\(\s*(?:true|1)\s*\)|\bfor\s*\(\s*;\s*;\s*\)|\bsetInterval\s*\(/ : /\bwhile\s*\(?\s*(?:1|true)\s*\)?|\bloop\s+do\b|\bfor\s*\(\s*;\s*;\s*\)/;
|
|
1744
1781
|
const m = loop.exec(code2);
|
|
@@ -2593,15 +2630,28 @@ function inlineExecCall(stmt, pipeFed) {
|
|
|
2593
2630
|
const fromStdin = () => {
|
|
2594
2631
|
if (stdinFed) {
|
|
2595
2632
|
const { code: code2, source } = stdinCodeOf(redirs);
|
|
2596
|
-
return { interp, code: [code2], source };
|
|
2633
|
+
return { interp, code: [code2], source, preload };
|
|
2597
2634
|
}
|
|
2598
2635
|
return { interp, code: [null], source: "pipe" };
|
|
2599
2636
|
};
|
|
2600
2637
|
let positionals2 = 0;
|
|
2601
2638
|
let selectedProgram = false;
|
|
2602
2639
|
const codes2 = [];
|
|
2640
|
+
const preload = {};
|
|
2641
|
+
const nodeFamily = inlineLanguageOf(interp) === "node";
|
|
2603
2642
|
for (let i = 0; i < args.length; i++) {
|
|
2604
2643
|
const a = args[i];
|
|
2644
|
+
if (nodeFamily && !selectedProgram && codes2.length === 0 && a != null) {
|
|
2645
|
+
const flag = NODE_VALUE_FLAG.exec(a);
|
|
2646
|
+
if (flag) {
|
|
2647
|
+
const value = flag[2] ?? args[++i];
|
|
2648
|
+
if (value != null) {
|
|
2649
|
+
if (/^--env-file/.test(flag[1])) (preload.envFiles ??= []).push(value);
|
|
2650
|
+
else if (/^dotenv\/config(?:\.js)?$/.test(value)) preload.dotenv = true;
|
|
2651
|
+
}
|
|
2652
|
+
continue;
|
|
2653
|
+
}
|
|
2654
|
+
}
|
|
2605
2655
|
if (a == null) {
|
|
2606
2656
|
if (codes2.length > 0) break;
|
|
2607
2657
|
positionals2++;
|
|
@@ -2638,7 +2688,12 @@ function inlineExecCall(stmt, pipeFed) {
|
|
|
2638
2688
|
}
|
|
2639
2689
|
}
|
|
2640
2690
|
if (codes2.length > 0) {
|
|
2641
|
-
return {
|
|
2691
|
+
return {
|
|
2692
|
+
interp,
|
|
2693
|
+
code: codes2,
|
|
2694
|
+
source: codes2.includes(null) ? "variable" : void 0,
|
|
2695
|
+
preload
|
|
2696
|
+
};
|
|
2642
2697
|
}
|
|
2643
2698
|
if (positionals2 === 0 && (stdinFed || pipeFed)) {
|
|
2644
2699
|
if (!/^(bash|sh|zsh)$/i.test(interp)) return fromStdin();
|
|
@@ -3461,7 +3516,7 @@ function extractShellDestTokens(command) {
|
|
|
3461
3516
|
}
|
|
3462
3517
|
function analyzeFsOperation(command) {
|
|
3463
3518
|
const normalized = normalizeCommandForPolicy(command);
|
|
3464
|
-
if (!FS_OP_PRESCREEN_RE.test(normalized) && !FS_OP_PRESCREEN_RE.test(command) && !SOURCES_FILE_RE.test(command))
|
|
3519
|
+
if (!FS_OP_PRESCREEN_RE.test(normalized) && !FS_OP_PRESCREEN_RE.test(command) && !SOURCES_FILE_RE.test(command) && !runsInlineInterpreter(command, normalized))
|
|
3465
3520
|
return null;
|
|
3466
3521
|
if (fsOpCache.has(command)) {
|
|
3467
3522
|
const hit = fsOpCache.get(command) ?? null;
|
|
@@ -3469,7 +3524,8 @@ function analyzeFsOperation(command) {
|
|
|
3469
3524
|
fsOpCache.set(command, hit);
|
|
3470
3525
|
return hit;
|
|
3471
3526
|
}
|
|
3472
|
-
const
|
|
3527
|
+
const direct = analyzeFsOperationImpl(command) ?? (INDIRECT_SHAPE_RE.test(command) ? structuralJailRead(command) : null);
|
|
3528
|
+
const computed = direct?.verdict === "block" || !runsInlineInterpreter(command, normalized) ? direct : stricter(direct, inlineCodeJailRead(command));
|
|
3473
3529
|
if (fsOpCache.size >= FS_OP_CACHE_MAX) {
|
|
3474
3530
|
const oldest = fsOpCache.keys().next().value;
|
|
3475
3531
|
if (oldest !== void 0) fsOpCache.delete(oldest);
|
|
@@ -3478,8 +3534,8 @@ function analyzeFsOperation(command) {
|
|
|
3478
3534
|
return computed;
|
|
3479
3535
|
}
|
|
3480
3536
|
function isSensitiveCleanupName(p) {
|
|
3481
|
-
const
|
|
3482
|
-
return /^\.env(\.|$)/i.test(
|
|
3537
|
+
const base32 = p.replace(/^.*[\\/]/, "");
|
|
3538
|
+
return /^\.env(\.|$)/i.test(base32) || /(?:^|[\\/])\.(?:ssh|aws|gnupg|git)(?:[\\/]|$)/i.test(p) || /\.(?:pem|key|p12|pfx|crt)$/i.test(base32) || /^\.?(?:netrc|npmrc|pgpass|htpasswd)$/i.test(base32) || /^id_(?:rsa|dsa|ecdsa|ed25519)/i.test(base32) || /credential/i.test(p) || /secret/i.test(base32);
|
|
3483
3539
|
}
|
|
3484
3540
|
function isWaivableCleanupTarget(p) {
|
|
3485
3541
|
if (/^[/~]/.test(p) || /^\$/.test(p)) return false;
|
|
@@ -4208,6 +4264,24 @@ function structuralJailRead(command) {
|
|
|
4208
4264
|
}
|
|
4209
4265
|
return review;
|
|
4210
4266
|
}
|
|
4267
|
+
function inlineCodeJailRead(command) {
|
|
4268
|
+
const calls = inlineExecCalls(command);
|
|
4269
|
+
if (calls === PARSE_FAIL) return null;
|
|
4270
|
+
let review = null;
|
|
4271
|
+
for (const call of calls) {
|
|
4272
|
+
const language = inlineLanguageOf(call.interp);
|
|
4273
|
+
if (language === null) continue;
|
|
4274
|
+
for (const code2 of call.code) {
|
|
4275
|
+
if (code2 === null) continue;
|
|
4276
|
+
for (const p of inlineReadPaths(language, code2, call.preload)) {
|
|
4277
|
+
const hit = matchSensitivePath(p);
|
|
4278
|
+
if (hit?.verdict === "block") return hit;
|
|
4279
|
+
review ??= hit;
|
|
4280
|
+
}
|
|
4281
|
+
}
|
|
4282
|
+
}
|
|
4283
|
+
return review;
|
|
4284
|
+
}
|
|
4211
4285
|
function baseWord(w) {
|
|
4212
4286
|
return (w ?? "").split("/").pop()?.toLowerCase() ?? "";
|
|
4213
4287
|
}
|
|
@@ -4765,6 +4839,21 @@ function hits(access, paths, directories, context) {
|
|
|
4765
4839
|
}
|
|
4766
4840
|
return false;
|
|
4767
4841
|
}
|
|
4842
|
+
function hitsNode9Dir(access, dirs, context) {
|
|
4843
|
+
const home = context.homeDirs?.[0] ?? "~";
|
|
4844
|
+
if (access.glob) {
|
|
4845
|
+
const pattern = normalizeFilePath(access.glob, access.cwd ?? context.cwd, home);
|
|
4846
|
+
const magic = pattern.search(/[*?[{]/);
|
|
4847
|
+
const literal = magic < 0 ? pattern : pattern.slice(0, pattern.lastIndexOf("/", magic));
|
|
4848
|
+
return dirs.some((d) => within(literal, d));
|
|
4849
|
+
}
|
|
4850
|
+
const candidates = access.candidates ?? [
|
|
4851
|
+
normalizeFilePath(access.path, access.cwd ?? context.cwd, home)
|
|
4852
|
+
];
|
|
4853
|
+
return candidates.some(
|
|
4854
|
+
(p) => dirs.some((d) => within(p, d)) || access.recursive === true && dirs.some((d) => within(d, p))
|
|
4855
|
+
);
|
|
4856
|
+
}
|
|
4768
4857
|
function hitsSystemDir(access, context, dirs = SYSTEM_DIRS) {
|
|
4769
4858
|
const home = context.homeDirs?.[0] ?? "~";
|
|
4770
4859
|
const candidates = access.candidates ?? [
|
|
@@ -4805,6 +4894,7 @@ function evaluateProtectedFileAccess(accesses, context, settings) {
|
|
|
4805
4894
|
const consider = (result) => {
|
|
4806
4895
|
if (!best || RANK[result.decision] > RANK[best.decision]) best = result;
|
|
4807
4896
|
};
|
|
4897
|
+
const node9Dirs = homes.map((home) => `${home.replace(/\/$/, "")}/.node9`);
|
|
4808
4898
|
for (const access of accesses) {
|
|
4809
4899
|
const mutation = access.operation !== "read";
|
|
4810
4900
|
let kind;
|
|
@@ -4833,6 +4923,10 @@ function evaluateProtectedFileAccess(accesses, context, settings) {
|
|
|
4833
4923
|
"files.system-dirs",
|
|
4834
4924
|
"review-root-home-read",
|
|
4835
4925
|
"Reading the root account's home requires approval"
|
|
4926
|
+
] : mutation && hitsNode9Dir(access, node9Dirs, context) ? [
|
|
4927
|
+
"commands.node9-disarm",
|
|
4928
|
+
"review-node9-disarm",
|
|
4929
|
+
"Changing node9's own files requires approval"
|
|
4836
4930
|
] : null;
|
|
4837
4931
|
} catch {
|
|
4838
4932
|
consider(incompleteFileVerdict(access.operation));
|
|
@@ -5438,9 +5532,9 @@ function validateBelgianNationalNumber(raw) {
|
|
|
5438
5532
|
if (!/^\d{11}$/.test(d)) return false;
|
|
5439
5533
|
const month = Number(d.slice(2, 4)) % 20;
|
|
5440
5534
|
if (month !== 0 && !plausibleDate(String(month).padStart(2, "0"), d.slice(4, 6))) return false;
|
|
5441
|
-
const
|
|
5535
|
+
const base32 = Number(d.slice(0, 9));
|
|
5442
5536
|
const check = Number(d.slice(9, 11));
|
|
5443
|
-
return 97 -
|
|
5537
|
+
return 97 - base32 % 97 === check || 97 - (2e9 + base32) % 97 === check;
|
|
5444
5538
|
}
|
|
5445
5539
|
function validateCuit(raw) {
|
|
5446
5540
|
const d = raw.replace(/-/g, "");
|
|
@@ -6574,9 +6668,9 @@ function evaluateGitHooksFileAccess(args, accesses, context, settings, shell) {
|
|
|
6574
6668
|
}
|
|
6575
6669
|
function agentFileKind(p) {
|
|
6576
6670
|
const lower2 = p.toLowerCase();
|
|
6577
|
-
const
|
|
6578
|
-
if (INSTRUCTION_NAMES.has(
|
|
6579
|
-
if (
|
|
6671
|
+
const base32 = lower2.slice(lower2.lastIndexOf("/") + 1);
|
|
6672
|
+
if (INSTRUCTION_NAMES.has(base32)) return "instructions";
|
|
6673
|
+
if (base32 === "copilot-instructions.md" && lower2.endsWith("/.github/" + base32))
|
|
6580
6674
|
return "instructions";
|
|
6581
6675
|
if (/\/\.cursor\/rules(?:\/|$)/.test(lower2)) return "instructions";
|
|
6582
6676
|
if (/\/\.claude\/projects\/[^/]+\/memory(?:\/|$)/.test(lower2)) return "memory";
|
|
@@ -6745,7 +6839,7 @@ function evaluateAgentFileWrite(args, accesses, context, settings, shell, hooks
|
|
|
6745
6839
|
skills: "agent skill",
|
|
6746
6840
|
settings: "agent settings"
|
|
6747
6841
|
};
|
|
6748
|
-
const
|
|
6842
|
+
const base32 = `${kindLabel[kind]} written: ${access.path}`;
|
|
6749
6843
|
if (!signal && !every) {
|
|
6750
6844
|
return {
|
|
6751
6845
|
decision: "allow",
|
|
@@ -6755,14 +6849,14 @@ function evaluateAgentFileWrite(args, accesses, context, settings, shell, hooks
|
|
|
6755
6849
|
path: access.path,
|
|
6756
6850
|
operation: access.operation,
|
|
6757
6851
|
kind,
|
|
6758
|
-
reason:
|
|
6852
|
+
reason: base32,
|
|
6759
6853
|
ruleDescription: "The AI writes to a file every later agent session loads as instructions.",
|
|
6760
|
-
blockedByLabel: `Node9 Files: ${
|
|
6854
|
+
blockedByLabel: `Node9 Files: ${base32}`,
|
|
6761
6855
|
tier: 2
|
|
6762
6856
|
};
|
|
6763
6857
|
}
|
|
6764
6858
|
const ruleName = signal === "content" ? "review-agent-file-content" : signal === "hooks" ? "review-agent-hooks-change" : "review-agent-file-write";
|
|
6765
|
-
const reason = signal ? `${
|
|
6859
|
+
const reason = signal ? `${base32} (${detail})` : base32;
|
|
6766
6860
|
const description = signal === "content" ? "The AI writes an instruction into a file every later agent session loads: to hide something from you, to skip approvals or the guard, or to read or send a secret. It would persist past this session; confirm it is yours." : signal === "hooks" ? "The AI changes the hooks in the agent's settings. Hooks are how node9 and your other checks run before each tool call; a change here can disarm them." : "The AI writes to a file every later agent session loads as instructions (CLAUDE.md, AGENTS.md, memory, agents, commands). Confirm the change is yours.";
|
|
6767
6861
|
return {
|
|
6768
6862
|
decision: value === "log" ? "allow" : value,
|
|
@@ -8370,6 +8464,139 @@ function scanArgumentSecrets(args) {
|
|
|
8370
8464
|
severity: "review"
|
|
8371
8465
|
} : null;
|
|
8372
8466
|
}
|
|
8467
|
+
function patternSelects(pattern, targets) {
|
|
8468
|
+
const pieces = pattern.toLowerCase().split(/[\\^$.*+?()[\]{}|]+/).filter(Boolean);
|
|
8469
|
+
if (pieces.length === 0) return false;
|
|
8470
|
+
return targets.some((t) => pieces.every((p) => t.includes(p)));
|
|
8471
|
+
}
|
|
8472
|
+
function sourceText(bytes, pos, end) {
|
|
8473
|
+
if (typeof pos !== "number" || typeof end !== "number" || pos < 0 || end < pos) return "";
|
|
8474
|
+
return new TextDecoder().decode(bytes.subarray(pos, end));
|
|
8475
|
+
}
|
|
8476
|
+
function nextOperand(words, from) {
|
|
8477
|
+
for (let i = from; i < words.length; i++) {
|
|
8478
|
+
const w = words[i];
|
|
8479
|
+
if (w !== null && w.startsWith("-")) continue;
|
|
8480
|
+
return i;
|
|
8481
|
+
}
|
|
8482
|
+
return -1;
|
|
8483
|
+
}
|
|
8484
|
+
function node9Command(words, h) {
|
|
8485
|
+
const head = base2(words[h]);
|
|
8486
|
+
if (head !== "node9" && head !== "node9.cmd" && words[h] !== "@node9/proxy") return null;
|
|
8487
|
+
const s = nextOperand(words, h + 1);
|
|
8488
|
+
const sub = s < 0 ? "" : (words[s] ?? "").toLowerCase();
|
|
8489
|
+
if (sub === "uninstall") return "node9 uninstall";
|
|
8490
|
+
if (sub !== "daemon") return null;
|
|
8491
|
+
const a = nextOperand(words, s + 1);
|
|
8492
|
+
const action = a < 0 ? "" : (words[a] ?? "").toLowerCase();
|
|
8493
|
+
return action === "stop" || action === "uninstall" ? `node9 daemon ${action}` : null;
|
|
8494
|
+
}
|
|
8495
|
+
function killsDaemon(words, texts, h, daemonPid) {
|
|
8496
|
+
const head = base2(words[h]);
|
|
8497
|
+
const args = words.slice(h + 1);
|
|
8498
|
+
if (head === "kill") {
|
|
8499
|
+
for (let i = 0; i < args.length; i++) {
|
|
8500
|
+
const w = args[i];
|
|
8501
|
+
if (w === "-s" || w === "-n") {
|
|
8502
|
+
i++;
|
|
8503
|
+
continue;
|
|
8504
|
+
}
|
|
8505
|
+
if (w !== null && w.startsWith("-")) continue;
|
|
8506
|
+
if (w === null) {
|
|
8507
|
+
if (HOME_PID_FILE_RE.test(texts[h + 1 + i] ?? "")) return "kill of the pid in daemon.pid";
|
|
8508
|
+
continue;
|
|
8509
|
+
}
|
|
8510
|
+
if (daemonPid !== null && w === String(daemonPid)) return `kill ${w} (the node9 daemon)`;
|
|
8511
|
+
}
|
|
8512
|
+
return null;
|
|
8513
|
+
}
|
|
8514
|
+
if (head === "pkill") {
|
|
8515
|
+
let full = false;
|
|
8516
|
+
let pattern = null;
|
|
8517
|
+
for (let i = 0; i < args.length; i++) {
|
|
8518
|
+
const w = args[i];
|
|
8519
|
+
if (w === null) continue;
|
|
8520
|
+
if (PKILL_VALUE_FLAGS.has(w)) {
|
|
8521
|
+
i++;
|
|
8522
|
+
continue;
|
|
8523
|
+
}
|
|
8524
|
+
if (w === "--full") full = true;
|
|
8525
|
+
else if (/^-[a-zA-Z]+$/.test(w) && w.includes("f")) full = true;
|
|
8526
|
+
if (w.startsWith("-")) continue;
|
|
8527
|
+
pattern = w;
|
|
8528
|
+
}
|
|
8529
|
+
if (pattern === null) return null;
|
|
8530
|
+
return patternSelects(pattern, full ? DAEMON_CMDLINES : DAEMON_NAMES) ? `pkill ${full ? "-f " : ""}${pattern}` : null;
|
|
8531
|
+
}
|
|
8532
|
+
if (head === "killall") {
|
|
8533
|
+
const regex = args.some((w) => w === "-r" || w === "--regexp");
|
|
8534
|
+
for (const w of args) {
|
|
8535
|
+
if (w === null || w.startsWith("-")) continue;
|
|
8536
|
+
if (regex ? patternSelects(w, DAEMON_NAMES) : KILLALL_NAMES.has(w.toLowerCase()))
|
|
8537
|
+
return `killall ${w}`;
|
|
8538
|
+
}
|
|
8539
|
+
return null;
|
|
8540
|
+
}
|
|
8541
|
+
if (head === "taskkill" || head === "taskkill.exe") {
|
|
8542
|
+
for (let i = 0; i < args.length - 1; i++) {
|
|
8543
|
+
const flag = (args[i] ?? "").toLowerCase();
|
|
8544
|
+
const value = (args[i + 1] ?? "").toLowerCase();
|
|
8545
|
+
if ((flag === "/im" || flag === "-im") && KILLALL_NAMES.has(value))
|
|
8546
|
+
return `taskkill /IM ${value}`;
|
|
8547
|
+
if ((flag === "/pid" || flag === "-pid") && daemonPid !== null && value === String(daemonPid))
|
|
8548
|
+
return `taskkill /PID ${value} (the node9 daemon)`;
|
|
8549
|
+
}
|
|
8550
|
+
}
|
|
8551
|
+
return null;
|
|
8552
|
+
}
|
|
8553
|
+
function stopsService(words, h) {
|
|
8554
|
+
const head = base2(words[h]);
|
|
8555
|
+
const args = words.slice(h + 1).map((w) => (w ?? "").toLowerCase());
|
|
8556
|
+
if (head === "systemctl") {
|
|
8557
|
+
const action = args.find((w) => STOP_SYSTEMCTL.has(w));
|
|
8558
|
+
if (action && args.some((w) => /^node9-daemon(\.service)?$/.test(w)))
|
|
8559
|
+
return `systemctl ${action} node9-daemon`;
|
|
8560
|
+
}
|
|
8561
|
+
if (head === "launchctl") {
|
|
8562
|
+
const action = args.find((w) => STOP_LAUNCHCTL.has(w));
|
|
8563
|
+
if (action && args.some((w) => w.includes("ai.node9.daemon")))
|
|
8564
|
+
return `launchctl ${action} ai.node9.daemon`;
|
|
8565
|
+
}
|
|
8566
|
+
return null;
|
|
8567
|
+
}
|
|
8568
|
+
function analyzeNode9Disarm(command, daemonPid = null, depth = 0) {
|
|
8569
|
+
if (depth > 3 || !NAME_PRESCREEN_RE.test(command.replace(/[\\'"]/g, ""))) return null;
|
|
8570
|
+
let shown = null;
|
|
8571
|
+
const bytes = new TextEncoder().encode(command);
|
|
8572
|
+
try {
|
|
8573
|
+
walkCommandScope(command, (node) => {
|
|
8574
|
+
if (shown !== null) return false;
|
|
8575
|
+
const n = node;
|
|
8576
|
+
if (!n || n.kind !== "CallExpr") return true;
|
|
8577
|
+
const words = (n.Args || []).map((a) => resolveWordLiteral(a));
|
|
8578
|
+
if (words.length === 0) return true;
|
|
8579
|
+
const texts = (n.Args || []).map((a) => sourceText(bytes, a.pos, a.end));
|
|
8580
|
+
const h = unwrapCommandHead(words);
|
|
8581
|
+
shown = node9Command(words, h) ?? killsDaemon(words, texts, h, daemonPid) ?? stopsService(words, h);
|
|
8582
|
+
if (shown === null) {
|
|
8583
|
+
const payload = literalShellPayload(words, base2(words[0]));
|
|
8584
|
+
if (payload) {
|
|
8585
|
+
const inner = analyzeNode9Disarm(payload, daemonPid, depth + 1);
|
|
8586
|
+
if (inner) shown = inner.reason.replace(/^node9 switched off by the agent: /, "");
|
|
8587
|
+
}
|
|
8588
|
+
}
|
|
8589
|
+
return true;
|
|
8590
|
+
});
|
|
8591
|
+
} catch {
|
|
8592
|
+
}
|
|
8593
|
+
if (shown === null) return null;
|
|
8594
|
+
return {
|
|
8595
|
+
ruleName: RULE_NAME2,
|
|
8596
|
+
reason: `node9 switched off by the agent: ${shown}`,
|
|
8597
|
+
description: DESCRIPTION
|
|
8598
|
+
};
|
|
8599
|
+
}
|
|
8373
8600
|
function catalogSettings(config) {
|
|
8374
8601
|
return catalogSettingsFromConfig(config.settings, config.policy);
|
|
8375
8602
|
}
|
|
@@ -8463,6 +8690,10 @@ function egressPolicyVerdict(eg) {
|
|
|
8463
8690
|
};
|
|
8464
8691
|
}
|
|
8465
8692
|
async function evaluatePolicy(config, toolName, args, context = {}, hostHooks = {}) {
|
|
8693
|
+
const v = await evaluatePolicyVerdict(config, toolName, args, context, hostHooks);
|
|
8694
|
+
return v.decision === "block" && v.checkId !== void 0 && NOT_OVERRIDABLE_CHECKS.has(v.checkId) ? { ...v, overridable: false } : v;
|
|
8695
|
+
}
|
|
8696
|
+
async function evaluatePolicyVerdict(config, toolName, args, context = {}, hostHooks = {}) {
|
|
8466
8697
|
let protectedVerdict = null;
|
|
8467
8698
|
const layers = inspectionLayers(config.policy);
|
|
8468
8699
|
if (context.agent !== "Terminal") {
|
|
@@ -8520,7 +8751,7 @@ async function evaluatePolicy(config, toolName, args, context = {}, hostHooks =
|
|
|
8520
8751
|
}
|
|
8521
8752
|
async function evaluatePolicyCore(config, toolName, args, context = {}, hooks = {}) {
|
|
8522
8753
|
const { agent, cwd, activeEnvironment } = context;
|
|
8523
|
-
const { checkProvenance: checkProvenance2, isTrustedHost: isTrustedHost2, isConfiguredRegistry, isGitWorkTreeTop: isGitWorkTreeTop2 } = hooks;
|
|
8754
|
+
const { checkProvenance: checkProvenance2, isTrustedHost: isTrustedHost2, isConfiguredRegistry, isGitWorkTreeTop: isGitWorkTreeTop2, daemonPid } = hooks;
|
|
8524
8755
|
const settingsView = catalogSettings(config);
|
|
8525
8756
|
const layers = inspectionLayers(config.policy);
|
|
8526
8757
|
const cv = (id) => checkValue(settingsView, id);
|
|
@@ -8705,6 +8936,23 @@ async function evaluatePolicyCore(config, toolName, args, context = {}, hooks =
|
|
|
8705
8936
|
else if (v && !pendingAstReview) pendingAstReview = v;
|
|
8706
8937
|
}
|
|
8707
8938
|
}
|
|
8939
|
+
if (cv("commands.node9-disarm") !== "off") {
|
|
8940
|
+
const finding = analyzeNode9Disarm(bashCommand, daemonPid?.() ?? null);
|
|
8941
|
+
if (finding) {
|
|
8942
|
+
const v = applyCheckValue(cv("commands.node9-disarm"), {
|
|
8943
|
+
decision: "review",
|
|
8944
|
+
blockedByLabel: `Node9 (AST): ${finding.ruleName}`,
|
|
8945
|
+
reason: finding.reason,
|
|
8946
|
+
tier: 2,
|
|
8947
|
+
ruleName: finding.ruleName,
|
|
8948
|
+
ruleDescription: finding.description,
|
|
8949
|
+
checkId: "commands.node9-disarm"
|
|
8950
|
+
});
|
|
8951
|
+
if (v?.logged) noteLogged(v);
|
|
8952
|
+
else if (v?.decision === "block") return v;
|
|
8953
|
+
else if (v && !pendingAstReview) pendingAstReview = v;
|
|
8954
|
+
}
|
|
8955
|
+
}
|
|
8708
8956
|
}
|
|
8709
8957
|
if (config.policy.smartRules.length > 0) {
|
|
8710
8958
|
const rmCleanupWaiver = bashCommand !== null && isRmCreatedInCommandCleanup(bashCommand);
|
|
@@ -9152,8 +9400,8 @@ function hasRoutingNumber(text) {
|
|
|
9152
9400
|
}
|
|
9153
9401
|
return false;
|
|
9154
9402
|
}
|
|
9155
|
-
function* validCardRuns(text,
|
|
9156
|
-
const re = new RegExp(
|
|
9403
|
+
function* validCardRuns(text, base32, exemptFractions = true) {
|
|
9404
|
+
const re = new RegExp(base32.source, "g");
|
|
9157
9405
|
let m;
|
|
9158
9406
|
while ((m = re.exec(text)) !== null) {
|
|
9159
9407
|
const digits = m[0].replace(/\D/g, "");
|
|
@@ -9166,17 +9414,17 @@ function* validCardRuns(text, base22, exemptFractions = true) {
|
|
|
9166
9414
|
}
|
|
9167
9415
|
}
|
|
9168
9416
|
function hasValidCard(text) {
|
|
9169
|
-
for (const
|
|
9170
|
-
if (!validCardRuns(text,
|
|
9417
|
+
for (const base32 of CARD_PATTERNS) {
|
|
9418
|
+
if (!validCardRuns(text, base32).next().done) return true;
|
|
9171
9419
|
}
|
|
9172
9420
|
return false;
|
|
9173
9421
|
}
|
|
9174
9422
|
function replaceValidCards(text, replace, { exemptFractions = true } = {}) {
|
|
9175
9423
|
let out = text;
|
|
9176
|
-
for (const
|
|
9424
|
+
for (const base32 of CARD_PATTERNS) {
|
|
9177
9425
|
let res = "";
|
|
9178
9426
|
let last = 0;
|
|
9179
|
-
for (const run of validCardRuns(out,
|
|
9427
|
+
for (const run of validCardRuns(out, base32, exemptFractions)) {
|
|
9180
9428
|
res += out.slice(last, run.index) + replace(run.digits);
|
|
9181
9429
|
last = run.index + run.length;
|
|
9182
9430
|
}
|
|
@@ -9417,9 +9665,9 @@ function maskLeaf(value, key, depth) {
|
|
|
9417
9665
|
const used = /* @__PURE__ */ new Set();
|
|
9418
9666
|
return Object.fromEntries(
|
|
9419
9667
|
Object.entries(value).map(([k, v]) => {
|
|
9420
|
-
const
|
|
9421
|
-
let name =
|
|
9422
|
-
for (let n = 2; used.has(name); n++) name = `${
|
|
9668
|
+
const base32 = maskPersonalData(k);
|
|
9669
|
+
let name = base32;
|
|
9670
|
+
for (let n = 2; used.has(name); n++) name = `${base32}#${n}`;
|
|
9423
9671
|
used.add(name);
|
|
9424
9672
|
return [name, maskLeaf(v, k, depth + 1)];
|
|
9425
9673
|
})
|
|
@@ -9924,7 +10172,7 @@ function matchCanaryArgs(args, values) {
|
|
|
9924
10172
|
return null;
|
|
9925
10173
|
}
|
|
9926
10174
|
}
|
|
9927
|
-
var getFilename2, __filename2, MAX_REGEX_LENGTH, REGEX_CACHE_MAX, regexCache, aws_default, bash_safe_default, docker_default, filesystem_default, github_default, k8s_default, mongodb_default, postgres_default, project_jail_default, redis_default, finance_default, identity_default, publishing_default, settings_default, branches_default, ACTION_TEMPLATES, ACTION_CHECKS, GAP, prog, httpTo, httpWrite, HTTP_WRITE, HTTP_WRITE_ANY, NOT_STRIPE_TEST, postTo, STRIPE_OBJECTS, APP_SHIELD_SPECS, APP_SHIELDS, APP_SHIELD_NAMES, APP_SERVER_GLOB, GENERAL_ACTION_RULES, BUILTIN_SHIELDS, SSRF_MAX_HOST, METADATA_ADDRESSES, STRICT_TIERS, METADATA_HOSTNAMES, v4Octets, TIER_REASON, CHECK_TEXT, LEVELS, MODE_VALUES, SOFT, STRICT, BLOCK_ALL, LEVEL_CHECKS, ASI, ASI_IDS, PACK_SHIELD_OWASP, PACK_RULE_OWASP, POSTURE_CATEGORY_OWASP, VERDICTS, CHECK_VERDICT_RANK, ALL, BUILTIN_DANGEROUS_WORDS, PRODUCT_CHECKS, SHIELD_RULE_NAME, SHIELD_RULES_FOLDED_INTO_PRODUCT, CHECKS, CHECK_BY_ID, LEGACY_TO_ID, PROJECT_JAIL_BLOCK_READ, OVERRIDE_PREFIX, LABEL_WRAPPERS, LEGACY_READERS, syntax, KINDS, STRUCTS, unknownKinds, INVISIBLE_RE, INVISIBLE_ONE, HOMOGLYPHS, HOMOGLYPH_RE, MAX_BLOBS, MIN_DECODED, BASE64_RUN_RE, HEX_RUN_RE, HEX_ESCAPE_RUN_RE, SYSTEM_AUTH_FILES, SYSTEM_AUTH_DIRS, PASSWORD_HASH_FILES, STARTUP_NAMES, SYSTEM_DIRS, SYSTEM_DIRS_EXEMPT, UPLOAD_SYSTEM_DIRS, AGENT_INSTRUCTION_FILES, AGENT_INSTRUCTION_DIRS, LEGACY_SYSTEM_PATH_RE, MAX_ALTERNATIVES, MAX_CALL_DEPTH, MAX_CALL_WALKS, MAX_XARGS_PAYLOAD, POSITIONAL, MAX_DEPTH, MAX_PAYLOAD_DEPTH, unique, clone, SENDING_STDIN, DOWNLOAD_SHORT_VALUE, DOWNLOAD_LONG_VALUE, DOWNLOAD_OUTPUT_FLAGS, DOWNLOAD_DIR_FLAGS, base, quoteGlob, asWord, ops, MAX_INLINE_CODE, WHAT, OUTSIDE, pyImport, either, PYTHON, NODE, PERL, RUBY, PHP, TABLES, STRING_LITERAL, sharedParser, MESSAGE_FLAGS, SHELL_INTERPRETERS, DOWNLOAD_CMDS, NORMALIZE_CACHE_MAX, normalizeCache, codeBodiesCache, AST_CACHE_MAX, astCache, PARSE_FAIL, INTERPRETER_LINE, PROGRAM_DIR, ACCESS_VIEW_CACHE_MAX, accessViewCache, MAX_READING_PAYLOADS, STDIN_CODE_INTERPRETERS, RUNS_TEXT_ELSEWHERE, defaultExpansionOps, EMPTY_NAMES, VARIABLE_READERS, PLAIN_PROGRAM_NAME, FS_READ_TOOLS, GREP_SHAPE, PATTERN_VERBS, PATTERN_VERB_NAMES, GREP_FILE_OPERANDS, READER_VALUE_LETTERS, FILE_OPERAND_FLAGS, SCP_VALUE_FLAGS, CURL_SOURCE_FLAGS, CURL_VALUE_LETTERS, WGET_VALUE_LETTERS, TAR_VALUE_LETTERS, ZIP_VALUE_LETTERS, RSYNC_VALUE_LETTERS, RSYNC_SKIP, CP_VALUE_LETTERS, INSTALL_VALUE_LETTERS, COPY_VERBS, TAR_MODE_WORD, COPY_VERB_HEADS, FS_OP_PRESCREEN_RE, HOME_CACHE_ALLOWLIST, SENSITIVE_PATH_RULES, AST_FS_REGEX_RULES, SQL_DB_CLIS, SQL_DDL_RE, CHMOD_OPEN_PERM_TOKENS, COMMAND_WRAPPERS, INLINE_INTERPRETER, RUNNER_WRAPPERS, _redirStdinOps, _listOps, WRAPPER_TAKES_TARGET, FIND_EXEC_FLAGS, FS_MUTATION_TOOLS, INTERP_LEADING_TARGET, MAX_PAYLOAD_NESTING, payloadNesting, MAX_INLINE_CALLS, INLINE_EXEC_FALLBACK, UNREADABLE_SOURCE, SCRIPT_RUNNERS, SCRIPT_RUNNER_VALUE_FLAGS, MAX_SCRIPT_OPERANDS, NET_BINARIES, VALUE_FLAGS, HOME_VARIABLES, assignmentTable, currentStmtOffset, PAYLOAD_BUDGET, payloadBudget, seenPayloads, UNANALYSABLE_NESTING, ASSIGNMENT_HEADS, andOrOps, ARRAY_MARK, ARRAY_SEP, MAX_CALL_DEPTH2, MAX_CALL_WALKS2, callDepth, callWalks, FS_OP_CACHE_MAX, fsOpCache, stripDotSlash, REDIR_TRUNCATE_OPS, REDIR_FILE_IN_OPS, REDIR_HEREDOC_OPS, FIND_OPTIONS, COPY_RULE_OF, INDIRECT_SHAPE_RE, SOURCES_FILE_RE, SHELL_SET_VARS, pipeOps, callWords, JAILED_GLOB_NAMES, JAILED_DIR_NAMES, shellGlob, GLOB_META, isReaderWord, positionalAfter, NONE, UNKNOWN, FORBIDDEN_PATH_SEGMENTS, BASH_TOOL_NAMES, MCP_EXECUTORS, BUILTIN_FIELDS, ARGV_FIELDS, BARE_WORD, MAX_ARGV_CHARACTERS, exempt, RANK, SEQUENCE_OPS, BIP39_ENGLISH, BIP39_PUBLIC_VECTORS, indices, lengths, hash, MAX_MNEMONIC_HASHES, SECRET_VIEW_LIMITS, IBAN_LENGTH, IBAN_BBAN_SHAPE, B58, B58_INDEX, XPRV_VERSIONS, B62, CRC32_TABLE, GITHUB_TOKEN_RE, B64URL, B64URL_INDEX, CASK_TWO_ZERO_SUFFIX, CASK_FOUR_ZERO_SUFFIX, CF_ODD, CF_EVEN, SPANISH_LETTERS, HETU_CHARS, VERHOEFF_D, VERHOEFF_P, MAX, UNTRUSTED_TOOLS, INJECTION_SIGNALS, MENTION_QUOTE_RE, MENTION_WORD_RE, ASSIGNMENT_CONTEXT_RE, DLP_STOPWORDS, REFERENCE_VALUE_RE, IDENTIFIER_VALUE_RE, PATH_VALUE_RE, DOTTED_REFERENCE_RE, CONCATENATION_RE, EMAIL_VALUE_RE, FIXTURE_NAME_RE, DERIVATIVE_NAME_RE, QUERY_CREDENTIAL_VALUE_RE, OTP_SECRET_RE, OTP_DOC_SECRETS, ASSIGNED_SECRET_VALUE_RE, ASSIGNED_SECRET_NAME_RE, NAME_KEYWORD_RE, ARN_CONTEXT_RE, CIPHER_KEY_NAME_RE, CIPHER_NAME_PARTS, CIPHER_KEY_VALUE_RE, LARAVEL_KEY_VALUE_RE, SQL_PASSWORD_VALUE_RE, GRAFANA_KEY_VALUE_RE, BASIC_VALUE_RE, BASIC_PAIR_RE, BASIC_HEADER_RE, BASIC_HEADER_PAIR_RE, BASIC_PLACEHOLDER_RE, BASIC_TEMPLATE_MARKERS, DROPBOX_SECRET_RE, OTP_CAPTURE_RE, DB_URL_PASSWORD_RE, DLP_PATTERNS, DLP_PATTERNS_GLOBAL, SENSITIVE_PATH_PATTERNS, SENSITIVE_PATH_REGEXES, MAX_DEPTH2, MAX_STRING_BYTES, MAX_JSON_PARSE_BYTES, BATCH_SEPARATOR, ENCODED_RUN_RE, IMPERATIVE, SECRET_TARGET, GUARD, SIGNALS, DESTINATION_RE, REUSED_SIGNALS, NEVER_NEGATED, NEGATION_BEFORE, RDR_IN, COPY_VERBS2, LITERAL_VERBS, GIT_PRESCREEN_RE, MAX_PAYLOAD_DEPTH2, MAX_ALIAS_DEPTH, CACHE_MAX, cache, PAYLOAD_SHELLS, CONFIG_SCOPE_FLAGS, CONFIG_VALUE_FLAGS, GLOBAL_VALUE_OPTIONS, GLOBAL_FLAG_OPTIONS, MAX_LOOP_ITEMS, GitWalk, POSITIONAL2, NO_VARS, NO_APPENDS, FORCE_PUSH, DESTRUCTIVE, UNREADABLE, PUSH_LONG_VALUE, BRANCH_LONG_VALUE, TAG_LONG_VALUE, CLEAN_LONG_VALUE, RESTORE_LONG_VALUE, CHECKOUT_LONG_VALUE, HOOKS_BYPASS, NO_VERIFY_SUBS, HOOK_KILL_SWITCHES, COMMIT_LONG_VALUE, CHMOD_OPTION_RE, _appendOp, STAGE_ALL, ADD_LONG_VALUE, CHECK_ID, RULE_NAME, INERT_LINE_RE, CHECK_ID2, INSTRUCTION_NAMES, SETTINGS_RE, HOOK_WORDS_RE, SHELLS, NETCATS, NET_CLIENTS, SENDERS, NETCAT_EXEC_LONG, DECL_DUMPS, PROC_ENVIRON_RE, DEV_NET_RE, SOCAT_PROGRAM_RE, SOCAT_NET_RE, PRESCREEN_RE, MAX_PAYLOAD_DEPTH3, CACHE_MAX2, cache2, dupInOp, REVERSE_SHELL_DESCRIPTION, ENV_EXFIL_DESCRIPTION, DYNAMIC_WORD, MULTICALL, SHELL_VALUE_OPTIONS, INTERPRETERS, OutboundWalk, NPM_INSTALL_VERBS, NPM_EXEC_VERBS, PNPM_INSTALL_VERBS, YARN_INSTALL_VERBS, BUN_INSTALL_VERBS, DLX_VERBS, NON_REGISTRY_RE, NPM_NAME_RE, EXACT_SEMVER_RE, NPM_VALUE_FLAGS, PNPM_VALUE_FLAGS, YARN_VALUE_FLAGS, BUN_VALUE_FLAGS, PIP_VALUE_FLAGS, UV_VALUE_FLAGS, POETRY_VALUE_FLAGS, PIPENV_VALUE_FLAGS, PIPX_VALUE_FLAGS, PY_SPEC_RE, PY_EXACT_RE, EXACT_VERSION_RE, GEM_NAME_RE, GEM_VALUE_FLAGS, BUNDLE_VALUE_FLAGS, CRATE_NAME_RE, CARGO_ADD_VALUE_FLAGS, CARGO_INSTALL_VALUE_FLAGS, GO_VALUE_FLAGS, GO_PATH_RE, NUGET_NAME_RE, DOTNET_ADD_VALUE_FLAGS, DOTNET_TOOL_VALUE_FLAGS, NUGET_VALUE_FLAGS, MAVEN_COORD_RE, COMPOSER_NAME_RE, COMPOSER_VALUE_FLAGS, EDITOR_HEADS, EXTENSION_ID_RE, MANAGER_HEADS, SHELLS2, MAX_NESTING, SHELL_VALUE_FLAGS, NPM_FAMILY, PIP_FAMILY, NPM_FETCH_VERBS, PIP_FETCH_VERBS, NPM_FLAGS, PIP_FLAGS, NPM_VARS, PIP_VARS, PRESCREEN_RE2, PIP_ATTACHED_RE, MAX_PAYLOAD_DEPTH4, PUBLIC_REGISTRY_HOSTS, TUNING_FIELDS, MAP_GOVERNED, KNOB_GOVERNED, CONFIGURABLE_CHECK_IDS, DEFAULT_EGRESS_ALLOWLIST, PRIVATE_HOST_SUFFIXES, SOURCE_COMMANDS, SINK_COMMANDS, OBFUSCATORS, SENSITIVE_PATTERNS, FLAGS_WITH_VALUES, DESTINATION_ARGS, MCP_DESTINATION_KEYS, ARGUMENT_SCAN_LIMITS, RUN_CHAR, runChar, VERDICT_RANK, SQL_DML_KEYWORDS, MAX_DESTINATIONS, MAX_SCAN_CHARS, EMAIL_RE, URL_RE, IBAN_RE, RECIPIENT_KEYS, DESTRUCTIVE_VERB_RE, PII_EMAIL_RE, PII_SSN_RE, PII_PHONE_RE, PII_CC16_RE, PII_CC15_RE, PII_CC14_RE, PII_CC13_RE, PII_CC19_RE, CARD_PATTERNS, PII_ROUTING_RE, ROUTING_LABEL_RE, ROUTING_LABEL_WINDOW, NATIONAL_ID_SHAPES, NATIONAL_ID_LABEL_RE, NATIONAL_ID_LABEL_CS_RE, idLabelIn, NATIONAL_ID_LABEL_WINDOW, NATIONAL_ID_GUARD_RE, PII_IBAN_RE, REALTIME_PII_PATTERNS, MAX_PII_SCAN_BYTES, IBAN_DESTINATION_KEYS, WHOLE_IBAN_RE, JSON_ESCAPE_RE, JSON_ESCAPES, MASKED_KINDS, ENTRY_RE, IBAN_TEXT_RE, EMAIL_TEXT_RE, ACCOUNT_KEY_RE, ACCOUNT_VALUE_RE, MAX_MASK_DEPTH, EMPTY, CURL_SEND_FLAGS, WGET_SEND_FLAGS, IWR_SEND_FLAGS, WRITE_METHODS, GH_READ, GH_WRITE, GH_HOSTNAME_FLAGS, GH_REPO_VALUE_FLAGS, GH_API_VALUE_FLAGS, GIT_FETCH, PUBLISH, SHELLS3, OWN_HEADS, MAX_DEPTH3, CWD_CHANGERS, TERMINAL_ESCAPE_RE, LOOP_MAX_RECORDS, CANARY_MIN_LENGTH, MAX_TEXT, MAX_DEPTH4, MAX_JSON_PARSE, URL_DEPTH, B64_DEPTH, MIN_SEGMENT, SEPARATORS, stripSeparators, looksText, CANARY_DECODERS, VIEWS, LONG_OUTPUT_THRESHOLD_BYTES, CANONICAL_EXTRACTOR_VERSION;
|
|
10175
|
+
var getFilename2, __filename2, MAX_REGEX_LENGTH, REGEX_CACHE_MAX, regexCache, aws_default, bash_safe_default, docker_default, filesystem_default, github_default, k8s_default, mongodb_default, postgres_default, project_jail_default, redis_default, finance_default, identity_default, publishing_default, settings_default, branches_default, ACTION_TEMPLATES, ACTION_CHECKS, GAP, prog, httpTo, httpWrite, HTTP_WRITE, HTTP_WRITE_ANY, NOT_STRIPE_TEST, postTo, STRIPE_OBJECTS, APP_SHIELD_SPECS, APP_SHIELDS, APP_SHIELD_NAMES, APP_SERVER_GLOB, GENERAL_ACTION_RULES, BUILTIN_SHIELDS, SSRF_MAX_HOST, METADATA_ADDRESSES, STRICT_TIERS, METADATA_HOSTNAMES, v4Octets, TIER_REASON, CHECK_TEXT, LEVELS, MODE_VALUES, SOFT, STRICT, BLOCK_ALL, LEVEL_CHECKS, ASI, ASI_IDS, PACK_SHIELD_OWASP, PACK_RULE_OWASP, POSTURE_CATEGORY_OWASP, VERDICTS, CHECK_VERDICT_RANK, ALL, BUILTIN_DANGEROUS_WORDS, PRODUCT_CHECKS, SHIELD_RULE_NAME, SHIELD_RULES_FOLDED_INTO_PRODUCT, CHECKS, CHECK_BY_ID, LEGACY_TO_ID, PROJECT_JAIL_BLOCK_READ, OVERRIDE_PREFIX, LABEL_WRAPPERS, LEGACY_READERS, syntax, KINDS, STRUCTS, unknownKinds, INVISIBLE_RE, INVISIBLE_ONE, HOMOGLYPHS, HOMOGLYPH_RE, MAX_BLOBS, MIN_DECODED, BASE64_RUN_RE, HEX_RUN_RE, HEX_ESCAPE_RUN_RE, SYSTEM_AUTH_FILES, SYSTEM_AUTH_DIRS, PASSWORD_HASH_FILES, STARTUP_NAMES, SYSTEM_DIRS, SYSTEM_DIRS_EXEMPT, UPLOAD_SYSTEM_DIRS, AGENT_INSTRUCTION_FILES, AGENT_INSTRUCTION_DIRS, LEGACY_SYSTEM_PATH_RE, MAX_ALTERNATIVES, MAX_CALL_DEPTH, MAX_CALL_WALKS, MAX_XARGS_PAYLOAD, POSITIONAL, MAX_DEPTH, MAX_PAYLOAD_DEPTH, unique, clone, SENDING_STDIN, DOWNLOAD_SHORT_VALUE, DOWNLOAD_LONG_VALUE, DOWNLOAD_OUTPUT_FLAGS, DOWNLOAD_DIR_FLAGS, base, quoteGlob, asWord, ops, MAX_INLINE_CODE, WHAT, OUTSIDE, pyImport, either, PYTHON, NODE, PERL, RUBY, PHP, TABLES, STRING_LITERAL, READ_CALL, ARG, WRAP, STR_PREFIX, WRITE_MODE_LITERAL, WRITE_MODE, WRITE_MODE_AFTER, PERL_WRITE_BEFORE, readCallBefore, READ_BEFORE, READ_AFTER, ASSIGNED, openedName, OPENED_NAME, DOTENV, DOTENV_PATH_OPTION, sharedParser, MESSAGE_FLAGS, SHELL_INTERPRETERS, DOWNLOAD_CMDS, NORMALIZE_CACHE_MAX, normalizeCache, codeBodiesCache, AST_CACHE_MAX, astCache, PARSE_FAIL, INTERPRETER_LINE, PROGRAM_DIR, ACCESS_VIEW_CACHE_MAX, accessViewCache, MAX_READING_PAYLOADS, STDIN_CODE_INTERPRETERS, RUNS_TEXT_ELSEWHERE, defaultExpansionOps, EMPTY_NAMES, VARIABLE_READERS, PLAIN_PROGRAM_NAME, FS_READ_TOOLS, GREP_SHAPE, PATTERN_VERBS, PATTERN_VERB_NAMES, GREP_FILE_OPERANDS, READER_VALUE_LETTERS, FILE_OPERAND_FLAGS, SCP_VALUE_FLAGS, CURL_SOURCE_FLAGS, CURL_VALUE_LETTERS, WGET_VALUE_LETTERS, TAR_VALUE_LETTERS, ZIP_VALUE_LETTERS, RSYNC_VALUE_LETTERS, RSYNC_SKIP, CP_VALUE_LETTERS, INSTALL_VALUE_LETTERS, COPY_VERBS, TAR_MODE_WORD, COPY_VERB_HEADS, FS_OP_PRESCREEN_RE, HOME_CACHE_ALLOWLIST, SENSITIVE_PATH_RULES, AST_FS_REGEX_RULES, SQL_DB_CLIS, SQL_DDL_RE, CHMOD_OPEN_PERM_TOKENS, COMMAND_WRAPPERS, INLINE_INTERPRETER, RUNNER_WRAPPERS, _redirStdinOps, _listOps, WRAPPER_TAKES_TARGET, FIND_EXEC_FLAGS, FS_MUTATION_TOOLS, INTERP_LEADING_TARGET, NODE_VALUE_FLAG, MAX_PAYLOAD_NESTING, payloadNesting, MAX_INLINE_CALLS, INLINE_EXEC_FALLBACK, UNREADABLE_SOURCE, SCRIPT_RUNNERS, SCRIPT_RUNNER_VALUE_FLAGS, MAX_SCRIPT_OPERANDS, NET_BINARIES, VALUE_FLAGS, HOME_VARIABLES, assignmentTable, currentStmtOffset, PAYLOAD_BUDGET, payloadBudget, seenPayloads, UNANALYSABLE_NESTING, ASSIGNMENT_HEADS, andOrOps, ARRAY_MARK, ARRAY_SEP, MAX_CALL_DEPTH2, MAX_CALL_WALKS2, callDepth, callWalks, FS_OP_CACHE_MAX, fsOpCache, stripDotSlash, REDIR_TRUNCATE_OPS, REDIR_FILE_IN_OPS, REDIR_HEREDOC_OPS, FIND_OPTIONS, COPY_RULE_OF, INDIRECT_SHAPE_RE, SOURCES_FILE_RE, SHELL_SET_VARS, pipeOps, callWords, JAILED_GLOB_NAMES, JAILED_DIR_NAMES, shellGlob, GLOB_META, INLINE_INTERP_PRESCREEN_RE, runsInlineInterpreter, isReaderWord, positionalAfter, NONE, UNKNOWN, FORBIDDEN_PATH_SEGMENTS, BASH_TOOL_NAMES, MCP_EXECUTORS, BUILTIN_FIELDS, ARGV_FIELDS, BARE_WORD, MAX_ARGV_CHARACTERS, exempt, RANK, SEQUENCE_OPS, BIP39_ENGLISH, BIP39_PUBLIC_VECTORS, indices, lengths, hash, MAX_MNEMONIC_HASHES, SECRET_VIEW_LIMITS, IBAN_LENGTH, IBAN_BBAN_SHAPE, B58, B58_INDEX, XPRV_VERSIONS, B62, CRC32_TABLE, GITHUB_TOKEN_RE, B64URL, B64URL_INDEX, CASK_TWO_ZERO_SUFFIX, CASK_FOUR_ZERO_SUFFIX, CF_ODD, CF_EVEN, SPANISH_LETTERS, HETU_CHARS, VERHOEFF_D, VERHOEFF_P, MAX, UNTRUSTED_TOOLS, INJECTION_SIGNALS, MENTION_QUOTE_RE, MENTION_WORD_RE, ASSIGNMENT_CONTEXT_RE, DLP_STOPWORDS, REFERENCE_VALUE_RE, IDENTIFIER_VALUE_RE, PATH_VALUE_RE, DOTTED_REFERENCE_RE, CONCATENATION_RE, EMAIL_VALUE_RE, FIXTURE_NAME_RE, DERIVATIVE_NAME_RE, QUERY_CREDENTIAL_VALUE_RE, OTP_SECRET_RE, OTP_DOC_SECRETS, ASSIGNED_SECRET_VALUE_RE, ASSIGNED_SECRET_NAME_RE, NAME_KEYWORD_RE, ARN_CONTEXT_RE, CIPHER_KEY_NAME_RE, CIPHER_NAME_PARTS, CIPHER_KEY_VALUE_RE, LARAVEL_KEY_VALUE_RE, SQL_PASSWORD_VALUE_RE, GRAFANA_KEY_VALUE_RE, BASIC_VALUE_RE, BASIC_PAIR_RE, BASIC_HEADER_RE, BASIC_HEADER_PAIR_RE, BASIC_PLACEHOLDER_RE, BASIC_TEMPLATE_MARKERS, DROPBOX_SECRET_RE, OTP_CAPTURE_RE, DB_URL_PASSWORD_RE, DLP_PATTERNS, DLP_PATTERNS_GLOBAL, SENSITIVE_PATH_PATTERNS, SENSITIVE_PATH_REGEXES, MAX_DEPTH2, MAX_STRING_BYTES, MAX_JSON_PARSE_BYTES, BATCH_SEPARATOR, ENCODED_RUN_RE, IMPERATIVE, SECRET_TARGET, GUARD, SIGNALS, DESTINATION_RE, REUSED_SIGNALS, NEVER_NEGATED, NEGATION_BEFORE, RDR_IN, COPY_VERBS2, LITERAL_VERBS, GIT_PRESCREEN_RE, MAX_PAYLOAD_DEPTH2, MAX_ALIAS_DEPTH, CACHE_MAX, cache, PAYLOAD_SHELLS, CONFIG_SCOPE_FLAGS, CONFIG_VALUE_FLAGS, GLOBAL_VALUE_OPTIONS, GLOBAL_FLAG_OPTIONS, MAX_LOOP_ITEMS, GitWalk, POSITIONAL2, NO_VARS, NO_APPENDS, FORCE_PUSH, DESTRUCTIVE, UNREADABLE, PUSH_LONG_VALUE, BRANCH_LONG_VALUE, TAG_LONG_VALUE, CLEAN_LONG_VALUE, RESTORE_LONG_VALUE, CHECKOUT_LONG_VALUE, HOOKS_BYPASS, NO_VERIFY_SUBS, HOOK_KILL_SWITCHES, COMMIT_LONG_VALUE, CHMOD_OPTION_RE, _appendOp, STAGE_ALL, ADD_LONG_VALUE, CHECK_ID, RULE_NAME, INERT_LINE_RE, CHECK_ID2, INSTRUCTION_NAMES, SETTINGS_RE, HOOK_WORDS_RE, SHELLS, NETCATS, NET_CLIENTS, SENDERS, NETCAT_EXEC_LONG, DECL_DUMPS, PROC_ENVIRON_RE, DEV_NET_RE, SOCAT_PROGRAM_RE, SOCAT_NET_RE, PRESCREEN_RE, MAX_PAYLOAD_DEPTH3, CACHE_MAX2, cache2, dupInOp, REVERSE_SHELL_DESCRIPTION, ENV_EXFIL_DESCRIPTION, DYNAMIC_WORD, MULTICALL, SHELL_VALUE_OPTIONS, INTERPRETERS, OutboundWalk, NPM_INSTALL_VERBS, NPM_EXEC_VERBS, PNPM_INSTALL_VERBS, YARN_INSTALL_VERBS, BUN_INSTALL_VERBS, DLX_VERBS, NON_REGISTRY_RE, NPM_NAME_RE, EXACT_SEMVER_RE, NPM_VALUE_FLAGS, PNPM_VALUE_FLAGS, YARN_VALUE_FLAGS, BUN_VALUE_FLAGS, PIP_VALUE_FLAGS, UV_VALUE_FLAGS, POETRY_VALUE_FLAGS, PIPENV_VALUE_FLAGS, PIPX_VALUE_FLAGS, PY_SPEC_RE, PY_EXACT_RE, EXACT_VERSION_RE, GEM_NAME_RE, GEM_VALUE_FLAGS, BUNDLE_VALUE_FLAGS, CRATE_NAME_RE, CARGO_ADD_VALUE_FLAGS, CARGO_INSTALL_VALUE_FLAGS, GO_VALUE_FLAGS, GO_PATH_RE, NUGET_NAME_RE, DOTNET_ADD_VALUE_FLAGS, DOTNET_TOOL_VALUE_FLAGS, NUGET_VALUE_FLAGS, MAVEN_COORD_RE, COMPOSER_NAME_RE, COMPOSER_VALUE_FLAGS, EDITOR_HEADS, EXTENSION_ID_RE, MANAGER_HEADS, SHELLS2, MAX_NESTING, SHELL_VALUE_FLAGS, NPM_FAMILY, PIP_FAMILY, NPM_FETCH_VERBS, PIP_FETCH_VERBS, NPM_FLAGS, PIP_FLAGS, NPM_VARS, PIP_VARS, PRESCREEN_RE2, PIP_ATTACHED_RE, MAX_PAYLOAD_DEPTH4, PUBLIC_REGISTRY_HOSTS, TUNING_FIELDS, MAP_GOVERNED, KNOB_GOVERNED, CONFIGURABLE_CHECK_IDS, DEFAULT_EGRESS_ALLOWLIST, PRIVATE_HOST_SUFFIXES, SOURCE_COMMANDS, SINK_COMMANDS, OBFUSCATORS, SENSITIVE_PATTERNS, FLAGS_WITH_VALUES, DESTINATION_ARGS, MCP_DESTINATION_KEYS, ARGUMENT_SCAN_LIMITS, RUN_CHAR, runChar, RULE_NAME2, DESCRIPTION, DAEMON_CMDLINES, DAEMON_NAMES, KILLALL_NAMES, STOP_SYSTEMCTL, STOP_LAUNCHCTL, PKILL_VALUE_FLAGS, NAME_PRESCREEN_RE, base2, HOME_PID_FILE_RE, VERDICT_RANK, SQL_DML_KEYWORDS, NOT_OVERRIDABLE_CHECKS, MAX_DESTINATIONS, MAX_SCAN_CHARS, EMAIL_RE, URL_RE, IBAN_RE, RECIPIENT_KEYS, DESTRUCTIVE_VERB_RE, PII_EMAIL_RE, PII_SSN_RE, PII_PHONE_RE, PII_CC16_RE, PII_CC15_RE, PII_CC14_RE, PII_CC13_RE, PII_CC19_RE, CARD_PATTERNS, PII_ROUTING_RE, ROUTING_LABEL_RE, ROUTING_LABEL_WINDOW, NATIONAL_ID_SHAPES, NATIONAL_ID_LABEL_RE, NATIONAL_ID_LABEL_CS_RE, idLabelIn, NATIONAL_ID_LABEL_WINDOW, NATIONAL_ID_GUARD_RE, PII_IBAN_RE, REALTIME_PII_PATTERNS, MAX_PII_SCAN_BYTES, IBAN_DESTINATION_KEYS, WHOLE_IBAN_RE, JSON_ESCAPE_RE, JSON_ESCAPES, MASKED_KINDS, ENTRY_RE, IBAN_TEXT_RE, EMAIL_TEXT_RE, ACCOUNT_KEY_RE, ACCOUNT_VALUE_RE, MAX_MASK_DEPTH, EMPTY, CURL_SEND_FLAGS, WGET_SEND_FLAGS, IWR_SEND_FLAGS, WRITE_METHODS, GH_READ, GH_WRITE, GH_HOSTNAME_FLAGS, GH_REPO_VALUE_FLAGS, GH_API_VALUE_FLAGS, GIT_FETCH, PUBLISH, SHELLS3, OWN_HEADS, MAX_DEPTH3, CWD_CHANGERS, TERMINAL_ESCAPE_RE, LOOP_MAX_RECORDS, CANARY_MIN_LENGTH, MAX_TEXT, MAX_DEPTH4, MAX_JSON_PARSE, URL_DEPTH, B64_DEPTH, MIN_SEGMENT, SEPARATORS, stripSeparators, looksText, CANARY_DECODERS, VIEWS, LONG_OUTPUT_THRESHOLD_BYTES, CANONICAL_EXTRACTOR_VERSION;
|
|
9928
10176
|
var init_dist = __esm({
|
|
9929
10177
|
"packages/policy-engine/dist/index.mjs"() {
|
|
9930
10178
|
"use strict";
|
|
@@ -11923,7 +12171,7 @@ var init_dist = __esm({
|
|
|
11923
12171
|
advice: "Fixed at Review for now."
|
|
11924
12172
|
},
|
|
11925
12173
|
"commands.node9-disarm": {
|
|
11926
|
-
plain: "The agent
|
|
12174
|
+
plain: "The agent switches node9 off or weakens it: stops or kills the daemon, stops its service, uninstalls node9, changes files in ~/.node9, clears a session flag, trusts an address, pauses the gate, weakens a shield.",
|
|
11927
12175
|
example: "After reading a web page, the agent runs node9 session-exposure clear --all",
|
|
11928
12176
|
advice: "Keep Review: these are your commands to run. Block if the agent should never touch node9."
|
|
11929
12177
|
},
|
|
@@ -12256,7 +12504,7 @@ var init_dist = __esm({
|
|
|
12256
12504
|
group: "commands",
|
|
12257
12505
|
owasp: "ASI10",
|
|
12258
12506
|
title: "node9 disarmed from the shell",
|
|
12259
|
-
catches: "a node9 command that clears a session flag, trusts a destination, pauses the gate or weakens a shield
|
|
12507
|
+
catches: "the agent stopping or killing the node9 daemon, stopping its service, uninstalling node9, changing files in ~/.node9, or running a node9 command that clears a session flag, trusts a destination, pauses the gate or weakens a shield",
|
|
12260
12508
|
values: ALL,
|
|
12261
12509
|
defaultValue: "review",
|
|
12262
12510
|
legacy: ["review-node9-disarm"]
|
|
@@ -13137,6 +13385,62 @@ var init_dist = __esm({
|
|
|
13137
13385
|
php: PHP
|
|
13138
13386
|
};
|
|
13139
13387
|
STRING_LITERAL = /(['"`])((?:\\.|(?!\1)[^\\\n]){1,4096})\1/g;
|
|
13388
|
+
READ_CALL = {
|
|
13389
|
+
python: String.raw`(?:\b(?:io|codecs)\.)?\bopen|\b(?:dotenv_values|load_dotenv|get_key|read_file|loadtxt|read_csv)`,
|
|
13390
|
+
node: String.raw`\b(?:readFileSync|readFile|createReadStream|readTextFile(?:Sync)?|readFileStr|openSync|file)`,
|
|
13391
|
+
perl: String.raw`\b(?:open|sysopen|read_file|slurp)`,
|
|
13392
|
+
ruby: String.raw`\b(?:File|IO)\.(?:read|binread|readlines|foreach|open)|\bDotenv\.(?:load|parse|overload)`,
|
|
13393
|
+
php: String.raw`\b(?:file_get_contents|fopen|file|readfile|parse_ini_file|highlight_file|show_source)`
|
|
13394
|
+
};
|
|
13395
|
+
ARG = String.raw`(?:(?:(?:my|our|local)\s+)?[\w.$]+(?:\s*\(\s*\))?|'[^'\n]{0,8}'|"[^"\n]{0,8}")\s*,\s*`;
|
|
13396
|
+
WRAP = String.raw`(?:(?:new\s+)?[\w.$]+\s*\(\s*(?:${ARG}){0,3}){0,3}`;
|
|
13397
|
+
STR_PREFIX = String.raw`[rRbBuUfF]{0,2}`;
|
|
13398
|
+
WRITE_MODE_LITERAL = String.raw`['"](?=[rbtU+]*w|(?![^'"]*\+)[rbtU]*[ax])[rwaxbtU+]{1,4}['"]`;
|
|
13399
|
+
WRITE_MODE = String.raw`\s*,\s*(?:mode\s*=\s*)?${WRITE_MODE_LITERAL}`;
|
|
13400
|
+
WRITE_MODE_AFTER = new RegExp(`^(?:\\s*\\)){0,3}${WRITE_MODE}`);
|
|
13401
|
+
PERL_WRITE_BEFORE = /['"]\s*(?:\+?[>|]|>>)\s*['"]\s*,\s*$/;
|
|
13402
|
+
readCallBefore = (language) => new RegExp(
|
|
13403
|
+
String.raw`(?:${READ_CALL[language]})(?![\w$])\s*\(?\s*(?:${ARG}){0,3}${WRAP}${STR_PREFIX}$`
|
|
13404
|
+
);
|
|
13405
|
+
READ_BEFORE = {
|
|
13406
|
+
python: readCallBefore("python"),
|
|
13407
|
+
node: readCallBefore("node"),
|
|
13408
|
+
perl: readCallBefore("perl"),
|
|
13409
|
+
ruby: readCallBefore("ruby"),
|
|
13410
|
+
php: readCallBefore("php")
|
|
13411
|
+
};
|
|
13412
|
+
READ_AFTER = {
|
|
13413
|
+
python: new RegExp(
|
|
13414
|
+
String.raw`^\s*\)\s*\.\s*(?:read_text|read_bytes|open)\s*\((?!\s*(?:mode\s*=\s*)?${WRITE_MODE_LITERAL})`
|
|
13415
|
+
)
|
|
13416
|
+
};
|
|
13417
|
+
ASSIGNED = new RegExp(String.raw`([$\w]+)\s*=\s*${WRAP}${STR_PREFIX}$`);
|
|
13418
|
+
openedName = (language) => new RegExp(
|
|
13419
|
+
String.raw`(?:${READ_CALL[language]})(?![\w$])\s*\(?\s*(?:${ARG}){0,3}${WRAP}([$\w]+)(?!${WRITE_MODE})\s*[),]` + (language === "python" ? String.raw`|\bPath\s*\(\s*([$\w]+)\s*\)\s*\.\s*(?:read_text|read_bytes|open)\s*\(` : ""),
|
|
13420
|
+
"g"
|
|
13421
|
+
);
|
|
13422
|
+
OPENED_NAME = {
|
|
13423
|
+
python: openedName("python"),
|
|
13424
|
+
node: openedName("node"),
|
|
13425
|
+
perl: openedName("perl"),
|
|
13426
|
+
ruby: openedName("ruby"),
|
|
13427
|
+
php: openedName("php")
|
|
13428
|
+
};
|
|
13429
|
+
DOTENV = {
|
|
13430
|
+
node: {
|
|
13431
|
+
load: /\brequire\s*\(\s*['"`]dotenv(?:\/config)?['"`]\s*\)|\bimport\s*(?:[\w${}\s,*]+\s+from\s*)?['"`]dotenv(?:\/config)?['"`]|\bimport\s*\(\s*['"`]dotenv(?:\/config)?['"`]\s*\)/,
|
|
13432
|
+
values: /\.parsed\b|[(,]\s*(?:require\s*\(\s*['"`]dotenv['"`]\s*\)|dotenv)\s*\.\s*config\s*\(/,
|
|
13433
|
+
env: /\b(?:process|Deno|Bun)\s*\.\s*env\b/,
|
|
13434
|
+
literalPath: /\bconfig\s*\(\s*\{[^)]*\bpath\s*:\s*['"`]/
|
|
13435
|
+
},
|
|
13436
|
+
python: {
|
|
13437
|
+
load: /\b(?:load_dotenv|dotenv_values|get_key)\s*\(/,
|
|
13438
|
+
values: /\b(?:dotenv_values|get_key)\s*\(/,
|
|
13439
|
+
env: /\b(?:environ|getenv)\b/,
|
|
13440
|
+
literalPath: /\b(?:load_dotenv|dotenv_values)\s*\(\s*(?:dotenv_path\s*=\s*)?[rRbBuU]?['"]/
|
|
13441
|
+
}
|
|
13442
|
+
};
|
|
13443
|
+
DOTENV_PATH_OPTION = /\bconfig\s*\(\s*\{[^)]*\bpath\s*:\s*$/;
|
|
13140
13444
|
sharedParser = lazy(() => getSyntax().NewParser());
|
|
13141
13445
|
MESSAGE_FLAGS = /* @__PURE__ */ new Set([
|
|
13142
13446
|
"-m",
|
|
@@ -13931,6 +14235,7 @@ var init_dist = __esm({
|
|
|
13931
14235
|
"rmdir"
|
|
13932
14236
|
]);
|
|
13933
14237
|
INTERP_LEADING_TARGET = /* @__PURE__ */ new Set(["su"]);
|
|
14238
|
+
NODE_VALUE_FLAG = /^(-r|--require|--import|--loader|--experimental-loader|--env-file|--env-file-if-exists|--input-type|-C|--conditions)(?:=(.*))?$/;
|
|
13934
14239
|
MAX_PAYLOAD_NESTING = 8;
|
|
13935
14240
|
payloadNesting = 0;
|
|
13936
14241
|
MAX_INLINE_CALLS = 16;
|
|
@@ -14179,6 +14484,8 @@ var init_dist = __esm({
|
|
|
14179
14484
|
JAILED_DIR_NAMES = [".ssh", ".aws"];
|
|
14180
14485
|
shellGlob = (p) => p.replace(/\[!/g, "[^");
|
|
14181
14486
|
GLOB_META = /(?<!\\)[*?[]/;
|
|
14487
|
+
INLINE_INTERP_PRESCREEN_RE = /(?:^|[^\w-])(?:python|node|tsx|ts-node|deno|bun|perl|ruby|irb|php)(?![A-Za-z_])/i;
|
|
14488
|
+
runsInlineInterpreter = (command, normalized) => INLINE_INTERP_PRESCREEN_RE.test(command) || INLINE_INTERP_PRESCREEN_RE.test(normalized);
|
|
14182
14489
|
isReaderWord = (w) => w !== null && FS_READ_TOOLS.has(baseWord(w));
|
|
14183
14490
|
positionalAfter = (words, from, to = words.length) => positionedArgs(words, from, to).map((a) => a.value);
|
|
14184
14491
|
NONE = { kind: "none" };
|
|
@@ -17495,9 +17802,9 @@ zoo`.split("\n");
|
|
|
17495
17802
|
const name = n.Name.Value;
|
|
17496
17803
|
if (n.Append) {
|
|
17497
17804
|
const prev = this.appended.has(name) ? this.appended.get(name) : resolveWordLiteral(n.Value) === null ? null : void 0;
|
|
17498
|
-
const
|
|
17805
|
+
const base32 = prev === void 0 ? recordedExpansion(name) : prev;
|
|
17499
17806
|
const piece = resolveWordLiteral(n.Value);
|
|
17500
|
-
this.appended.set(name, typeof
|
|
17807
|
+
this.appended.set(name, typeof base32 === "string" && piece !== null ? base32 + piece : null);
|
|
17501
17808
|
this.treeTopVars.delete(name);
|
|
17502
17809
|
return true;
|
|
17503
17810
|
}
|
|
@@ -19013,12 +19320,50 @@ ${text}` : text);
|
|
|
19013
19320
|
const char = value[index] ?? "";
|
|
19014
19321
|
return RUN_CHAR.test(char) || char !== "" && isInvisibleChar(char);
|
|
19015
19322
|
};
|
|
19323
|
+
RULE_NAME2 = "review-node9-disarm";
|
|
19324
|
+
DESCRIPTION = "The AI wants to stop node9, remove it, or change its own files. These are your commands to run, not the agent's: with the daemon stopped the outside-content and taint checks are off.";
|
|
19325
|
+
DAEMON_CMDLINES = [
|
|
19326
|
+
"node /usr/lib/node_modules/@node9/proxy/dist/cli.js daemon start",
|
|
19327
|
+
"node9 daemon start"
|
|
19328
|
+
];
|
|
19329
|
+
DAEMON_NAMES = ["node", "node9"];
|
|
19330
|
+
KILLALL_NAMES = /* @__PURE__ */ new Set(["node", "node9", "node.exe", "node9.exe"]);
|
|
19331
|
+
STOP_SYSTEMCTL = /* @__PURE__ */ new Set(["stop", "disable", "mask", "kill"]);
|
|
19332
|
+
STOP_LAUNCHCTL = /* @__PURE__ */ new Set(["unload", "bootout", "remove", "stop", "kill", "disable"]);
|
|
19333
|
+
PKILL_VALUE_FLAGS = /* @__PURE__ */ new Set([
|
|
19334
|
+
"-u",
|
|
19335
|
+
"-U",
|
|
19336
|
+
"-g",
|
|
19337
|
+
"-G",
|
|
19338
|
+
"-P",
|
|
19339
|
+
"-s",
|
|
19340
|
+
"-t",
|
|
19341
|
+
"-F",
|
|
19342
|
+
"--signal",
|
|
19343
|
+
"--euid",
|
|
19344
|
+
"--uid",
|
|
19345
|
+
"--pgroup",
|
|
19346
|
+
"--group",
|
|
19347
|
+
"--parent",
|
|
19348
|
+
"--session",
|
|
19349
|
+
"--terminal",
|
|
19350
|
+
"--pidfile",
|
|
19351
|
+
"--ns",
|
|
19352
|
+
"--nslist"
|
|
19353
|
+
]);
|
|
19354
|
+
NAME_PRESCREEN_RE = /node9|kill|systemctl|launchctl|daemon/i;
|
|
19355
|
+
base2 = (w) => (w ?? "").split(/[\\/]/).pop()?.toLowerCase() ?? "";
|
|
19356
|
+
HOME_PID_FILE_RE = /(?:^|[\s"'(=`])(?:~|\$HOME|\$\{HOME\}|\/home\/[^/\s]+|\/Users\/[^/\s]+|\/root)\/\.node9\/daemon\.pid/;
|
|
19016
19357
|
VERDICT_RANK = {
|
|
19017
19358
|
allow: 0,
|
|
19018
19359
|
review: 1,
|
|
19019
19360
|
block: 2
|
|
19020
19361
|
};
|
|
19021
19362
|
SQL_DML_KEYWORDS = /* @__PURE__ */ new Set(["select", "insert", "update", "delete", "merge", "upsert"]);
|
|
19363
|
+
NOT_OVERRIDABLE_CHECKS = /* @__PURE__ */ new Set([
|
|
19364
|
+
"data.credential-files",
|
|
19365
|
+
"data.credential-files-other"
|
|
19366
|
+
]);
|
|
19022
19367
|
MAX_DESTINATIONS = 200;
|
|
19023
19368
|
MAX_SCAN_CHARS = 1e5;
|
|
19024
19369
|
EMAIL_RE = /[\p{L}\p{N}._%+-]+@[\p{L}\p{N}](?:[\p{L}\p{N}-]*[\p{L}\p{N}])?(?:\.[\p{L}\p{N}](?:[\p{L}\p{N}-]*[\p{L}\p{N}])?)*\.\p{L}{2,}/gu;
|
|
@@ -19362,7 +19707,7 @@ ${text}` : text);
|
|
|
19362
19707
|
{ view: "separators-stripped", decoder: "separators", stripped: true }
|
|
19363
19708
|
];
|
|
19364
19709
|
LONG_OUTPUT_THRESHOLD_BYTES = 100 * 1024;
|
|
19365
|
-
CANONICAL_EXTRACTOR_VERSION = "canonical-
|
|
19710
|
+
CANONICAL_EXTRACTOR_VERSION = "canonical-v39";
|
|
19366
19711
|
}
|
|
19367
19712
|
});
|
|
19368
19713
|
|
|
@@ -19839,7 +20184,7 @@ function statAndFirstLine(file2) {
|
|
|
19839
20184
|
fs3.closeSync(fd);
|
|
19840
20185
|
}
|
|
19841
20186
|
}
|
|
19842
|
-
function listCodexSessionFiles(
|
|
20187
|
+
function listCodexSessionFiles(base4 = codexSessionsDir()) {
|
|
19843
20188
|
const files = [];
|
|
19844
20189
|
const walk3 = (dir2) => {
|
|
19845
20190
|
try {
|
|
@@ -19851,8 +20196,8 @@ function listCodexSessionFiles(base3 = codexSessionsDir()) {
|
|
|
19851
20196
|
} catch {
|
|
19852
20197
|
}
|
|
19853
20198
|
};
|
|
19854
|
-
walk3(
|
|
19855
|
-
if (path4.basename(
|
|
20199
|
+
walk3(base4);
|
|
20200
|
+
if (path4.basename(base4) === "sessions") walk3(path4.join(path4.dirname(base4), "archived_sessions"));
|
|
19856
20201
|
const sessions = /* @__PURE__ */ new Map();
|
|
19857
20202
|
for (const file2 of files.sort()) {
|
|
19858
20203
|
try {
|
|
@@ -20263,8 +20608,8 @@ function claudeDesktopConfigPath(homeDir = os6.homedir()) {
|
|
|
20263
20608
|
}
|
|
20264
20609
|
function opencodeConfigDir(home = os6.homedir()) {
|
|
20265
20610
|
const xdg = process.env.XDG_CONFIG_HOME;
|
|
20266
|
-
const
|
|
20267
|
-
return path9.join(
|
|
20611
|
+
const base4 = xdg && path9.isAbsolute(xdg) ? xdg : path9.join(home, ".config");
|
|
20612
|
+
return path9.join(base4, "opencode");
|
|
20268
20613
|
}
|
|
20269
20614
|
function commonBinDirs(home) {
|
|
20270
20615
|
return [
|
|
@@ -21779,8 +22124,8 @@ import os13 from "os";
|
|
|
21779
22124
|
function sanitizeSsrfAllow(entries, source) {
|
|
21780
22125
|
const kept = [];
|
|
21781
22126
|
for (const entry of entries) {
|
|
21782
|
-
const
|
|
21783
|
-
const m = classifySsrf(
|
|
22127
|
+
const base4 = entry.includes("/") ? entry.slice(0, entry.indexOf("/")).trim() : entry;
|
|
22128
|
+
const m = classifySsrf(base4);
|
|
21784
22129
|
if (m && !m.overridable) {
|
|
21785
22130
|
const what = entry.includes("/") ? "covers only protected addresses" : "is a protected address";
|
|
21786
22131
|
process.emitWarning(
|
|
@@ -22542,12 +22887,12 @@ function getConfig(cwd) {
|
|
|
22542
22887
|
continue;
|
|
22543
22888
|
explicit[id] = v;
|
|
22544
22889
|
}
|
|
22545
|
-
const
|
|
22890
|
+
const base4 = resolveCheckMap({
|
|
22546
22891
|
...catalogSettingsFrom(mergedSettings, mergedPolicy),
|
|
22547
22892
|
checks: explicit
|
|
22548
22893
|
});
|
|
22549
22894
|
for (const [id, v] of Object.entries(v2ChecksByPath.get(projectPath)?.checks ?? {})) {
|
|
22550
|
-
if (CHECK_VERDICT_RANK[v] > CHECK_VERDICT_RANK[
|
|
22895
|
+
if (CHECK_VERDICT_RANK[v] > CHECK_VERDICT_RANK[base4[id] ?? "off"]) {
|
|
22551
22896
|
explicit[id] = v;
|
|
22552
22897
|
checkSources[id] = "project";
|
|
22553
22898
|
}
|
|
@@ -23193,6 +23538,39 @@ var init_egress = __esm({
|
|
|
23193
23538
|
}
|
|
23194
23539
|
});
|
|
23195
23540
|
|
|
23541
|
+
// src/utils/read-small-file.ts
|
|
23542
|
+
import fs16 from "fs";
|
|
23543
|
+
function readSmallFile(file2, maxBytes) {
|
|
23544
|
+
let fd;
|
|
23545
|
+
try {
|
|
23546
|
+
fd = fs16.openSync(file2, fs16.constants.O_RDONLY | (fs16.constants.O_NONBLOCK ?? 0));
|
|
23547
|
+
} catch {
|
|
23548
|
+
return null;
|
|
23549
|
+
}
|
|
23550
|
+
try {
|
|
23551
|
+
const st = fs16.fstatSync(fd);
|
|
23552
|
+
if (!st.isFile() || st.size > maxBytes) return null;
|
|
23553
|
+
const buf = Buffer.alloc(Math.min(st.size, maxBytes));
|
|
23554
|
+
let read2 = 0;
|
|
23555
|
+
while (read2 < buf.length) {
|
|
23556
|
+
const n = fs16.readSync(fd, buf, read2, buf.length - read2, read2);
|
|
23557
|
+
if (n === 0) break;
|
|
23558
|
+
read2 += n;
|
|
23559
|
+
}
|
|
23560
|
+
return buf.toString("utf8", 0, read2);
|
|
23561
|
+
} catch {
|
|
23562
|
+
return null;
|
|
23563
|
+
} finally {
|
|
23564
|
+
fs16.closeSync(fd);
|
|
23565
|
+
}
|
|
23566
|
+
}
|
|
23567
|
+
var init_read_small_file = __esm({
|
|
23568
|
+
"src/utils/read-small-file.ts"() {
|
|
23569
|
+
"use strict";
|
|
23570
|
+
init_esm_shims();
|
|
23571
|
+
}
|
|
23572
|
+
});
|
|
23573
|
+
|
|
23196
23574
|
// src/policy/gate-order.ts
|
|
23197
23575
|
function fileGateOutcome(file2, panicMode) {
|
|
23198
23576
|
if (!file2) return null;
|
|
@@ -23412,7 +23790,7 @@ var init_gate_order = __esm({
|
|
|
23412
23790
|
});
|
|
23413
23791
|
|
|
23414
23792
|
// src/policy/file-access.ts
|
|
23415
|
-
import
|
|
23793
|
+
import fs17 from "fs";
|
|
23416
23794
|
import os14 from "os";
|
|
23417
23795
|
import path17 from "path";
|
|
23418
23796
|
function absoluteSpelling(p, cwd, home) {
|
|
@@ -23426,13 +23804,13 @@ function physical(p, followFinal, links = 0) {
|
|
|
23426
23804
|
return { path: `${parent.path}/${path17.basename(p)}`, missing: parent.missing };
|
|
23427
23805
|
}
|
|
23428
23806
|
try {
|
|
23429
|
-
return { path:
|
|
23807
|
+
return { path: fs17.realpathSync.native(p), missing: false };
|
|
23430
23808
|
} catch (error) {
|
|
23431
23809
|
const code2 = error.code;
|
|
23432
23810
|
if (!["ENOENT", "ENOTDIR"].includes(code2 ?? "")) throw error;
|
|
23433
23811
|
try {
|
|
23434
|
-
if (
|
|
23435
|
-
const target =
|
|
23812
|
+
if (fs17.lstatSync(p).isSymbolicLink()) {
|
|
23813
|
+
const target = fs17.readlinkSync(p);
|
|
23436
23814
|
return physical(
|
|
23437
23815
|
path17.isAbsolute(target) ? target : `${path17.dirname(p)}/${target}`,
|
|
23438
23816
|
true,
|
|
@@ -23472,14 +23850,14 @@ function prepareFileAccesses(tool, args, cwd = process.cwd(), inspection = {}, h
|
|
|
23472
23850
|
const raw = absoluteSpelling(access.path, access.cwd ?? cwd, home);
|
|
23473
23851
|
if (access.directoryTarget) {
|
|
23474
23852
|
try {
|
|
23475
|
-
if (!
|
|
23853
|
+
if (!fs17.statSync(absoluteSpelling(access.directoryTarget, access.cwd ?? cwd, home)).isDirectory())
|
|
23476
23854
|
continue;
|
|
23477
23855
|
} catch {
|
|
23478
23856
|
}
|
|
23479
23857
|
}
|
|
23480
23858
|
if (access.operation === "create") {
|
|
23481
23859
|
try {
|
|
23482
|
-
|
|
23860
|
+
fs17.statSync(raw);
|
|
23483
23861
|
continue;
|
|
23484
23862
|
} catch {
|
|
23485
23863
|
}
|
|
@@ -23535,7 +23913,7 @@ var init_file_access = __esm({
|
|
|
23535
23913
|
});
|
|
23536
23914
|
|
|
23537
23915
|
// src/supply-chain/osv-index.ts
|
|
23538
|
-
import
|
|
23916
|
+
import fs18 from "fs";
|
|
23539
23917
|
import os15 from "os";
|
|
23540
23918
|
import path18 from "path";
|
|
23541
23919
|
import { createHash as createHash4 } from "crypto";
|
|
@@ -23566,7 +23944,7 @@ function shardPath(eco, shard) {
|
|
|
23566
23944
|
}
|
|
23567
23945
|
function readMeta(eco) {
|
|
23568
23946
|
try {
|
|
23569
|
-
const m = JSON.parse(
|
|
23947
|
+
const m = JSON.parse(fs18.readFileSync(path18.join(ecoDir(eco), "meta.json"), "utf8"));
|
|
23570
23948
|
if (typeof m?.syncedAt !== "string" || typeof m?.lastModifiedMs !== "number") return null;
|
|
23571
23949
|
return m;
|
|
23572
23950
|
} catch {
|
|
@@ -23575,7 +23953,7 @@ function readMeta(eco) {
|
|
|
23575
23953
|
}
|
|
23576
23954
|
function readShard(eco, shard) {
|
|
23577
23955
|
try {
|
|
23578
|
-
const s = JSON.parse(
|
|
23956
|
+
const s = JSON.parse(fs18.readFileSync(shardPath(eco, shard), "utf8"));
|
|
23579
23957
|
return s && typeof s === "object" && !Array.isArray(s) ? s : {};
|
|
23580
23958
|
} catch {
|
|
23581
23959
|
return {};
|
|
@@ -23697,15 +24075,15 @@ var init_net = __esm({
|
|
|
23697
24075
|
|
|
23698
24076
|
// src/supply-chain/osv-online.ts
|
|
23699
24077
|
async function queryOsvMalicious(queries) {
|
|
23700
|
-
const
|
|
23701
|
-
if (!
|
|
24078
|
+
const base4 = endpoints().osvApi;
|
|
24079
|
+
if (!base4 || queries.length === 0) return null;
|
|
23702
24080
|
const body = JSON.stringify({
|
|
23703
24081
|
queries: queries.map((q) => ({
|
|
23704
24082
|
package: { name: q.name, ecosystem: q.ecosystem },
|
|
23705
24083
|
...q.version ? { version: q.version } : {}
|
|
23706
24084
|
}))
|
|
23707
24085
|
});
|
|
23708
|
-
const res = await fetchJson(`${
|
|
24086
|
+
const res = await fetchJson(`${base4}/v1/querybatch`, {
|
|
23709
24087
|
timeoutMs: TIMEOUT_MS,
|
|
23710
24088
|
maxBytes: 1024 * 1024,
|
|
23711
24089
|
body
|
|
@@ -23768,9 +24146,9 @@ function pypiRepoOf(doc) {
|
|
|
23768
24146
|
return null;
|
|
23769
24147
|
}
|
|
23770
24148
|
async function npmSourceRepo(name, version) {
|
|
23771
|
-
const
|
|
23772
|
-
if (!
|
|
23773
|
-
const url = `${
|
|
24149
|
+
const base4 = endpoints().npmRegistry;
|
|
24150
|
+
if (!base4) return "unknown";
|
|
24151
|
+
const url = `${base4}/-/npm/v1/attestations/${name.replaceAll("/", "%2F")}@${encodeURIComponent(version)}`;
|
|
23774
24152
|
return read(url, npmRepoOf);
|
|
23775
24153
|
}
|
|
23776
24154
|
async function read(url, repoOf) {
|
|
@@ -23783,9 +24161,9 @@ async function read(url, repoOf) {
|
|
|
23783
24161
|
}
|
|
23784
24162
|
}
|
|
23785
24163
|
async function pypiSourceRepo(name, version, filename) {
|
|
23786
|
-
const
|
|
23787
|
-
if (!
|
|
23788
|
-
const url = `${
|
|
24164
|
+
const base4 = endpoints().pypi;
|
|
24165
|
+
if (!base4) return "unknown";
|
|
24166
|
+
const url = `${base4}/integrity/${encodeURIComponent(name)}/${encodeURIComponent(version)}/${encodeURIComponent(filename)}/provenance`;
|
|
23789
24167
|
return read(url, pypiRepoOf);
|
|
23790
24168
|
}
|
|
23791
24169
|
function comparePypi(a, b) {
|
|
@@ -23837,9 +24215,9 @@ async function npmVersionDocument(url, selector) {
|
|
|
23837
24215
|
};
|
|
23838
24216
|
}
|
|
23839
24217
|
async function npmInfo(name, version, freshWindowMs, raw) {
|
|
23840
|
-
const
|
|
23841
|
-
if (!
|
|
23842
|
-
const url = `${
|
|
24218
|
+
const base4 = endpoints().npmRegistry;
|
|
24219
|
+
if (!base4) return null;
|
|
24220
|
+
const url = `${base4}/${name.replaceAll("/", "%2F")}`;
|
|
23843
24221
|
const aliasStart = raw?.indexOf("@npm:") ?? -1;
|
|
23844
24222
|
const target = aliasStart > 0 ? raw.slice(aliasStart + 5) : raw?.replace(/^npm:/, "");
|
|
23845
24223
|
const specStart = target?.indexOf("@", 1) ?? -1;
|
|
@@ -23907,9 +24285,9 @@ async function npmInfo(name, version, freshWindowMs, raw) {
|
|
|
23907
24285
|
return info;
|
|
23908
24286
|
}
|
|
23909
24287
|
async function pypiInfo(name, version) {
|
|
23910
|
-
const
|
|
23911
|
-
if (!
|
|
23912
|
-
const url = version ? `${
|
|
24288
|
+
const base4 = endpoints().pypi;
|
|
24289
|
+
if (!base4) return null;
|
|
24290
|
+
const url = version ? `${base4}/pypi/${encodeURIComponent(name)}/${encodeURIComponent(version)}/json` : `${base4}/pypi/${encodeURIComponent(name)}/json`;
|
|
23913
24291
|
const doc = await fetchJson(url, { timeoutMs: TIMEOUT_MS3, maxBytes: MAX_BYTES2 });
|
|
23914
24292
|
if (!doc?.info?.version) return null;
|
|
23915
24293
|
const times = (doc.urls ?? []).map((u) => u.upload_time_iso_8601 ? Date.parse(u.upload_time_iso_8601) : NaN).filter((t) => Number.isFinite(t));
|
|
@@ -23933,9 +24311,9 @@ function pypiHistoryOf(releases, version) {
|
|
|
23933
24311
|
};
|
|
23934
24312
|
}
|
|
23935
24313
|
async function pypiHistory(name, version) {
|
|
23936
|
-
const
|
|
23937
|
-
if (!
|
|
23938
|
-
const doc = await fetchJson(`${
|
|
24314
|
+
const base4 = endpoints().pypi;
|
|
24315
|
+
if (!base4) return null;
|
|
24316
|
+
const doc = await fetchJson(`${base4}/pypi/${encodeURIComponent(name)}/json`, {
|
|
23939
24317
|
timeoutMs: TIMEOUT_MS3,
|
|
23940
24318
|
maxBytes: MAX_BYTES2
|
|
23941
24319
|
});
|
|
@@ -23962,7 +24340,7 @@ var init_registry2 = __esm({
|
|
|
23962
24340
|
});
|
|
23963
24341
|
|
|
23964
24342
|
// src/supply-chain/local-resolve.ts
|
|
23965
|
-
import
|
|
24343
|
+
import fs19 from "fs";
|
|
23966
24344
|
import path19 from "path";
|
|
23967
24345
|
function resolveInstalled(name, cwd) {
|
|
23968
24346
|
if (!cwd || !path19.isAbsolute(cwd)) return null;
|
|
@@ -23972,7 +24350,7 @@ function resolveInstalled(name, cwd) {
|
|
|
23972
24350
|
const pkgDir = path19.join(dir2, "node_modules", ...name.split("/"));
|
|
23973
24351
|
const manifest = path19.join(pkgDir, "package.json");
|
|
23974
24352
|
try {
|
|
23975
|
-
const raw =
|
|
24353
|
+
const raw = fs19.readFileSync(manifest, "utf8");
|
|
23976
24354
|
const parsed = JSON.parse(raw);
|
|
23977
24355
|
if (typeof parsed.version === "string" && parsed.version.length > 0) {
|
|
23978
24356
|
return { version: parsed.version, dir: pkgDir };
|
|
@@ -24272,7 +24650,7 @@ var init_check = __esm({
|
|
|
24272
24650
|
// src/supply-chain/registries.ts
|
|
24273
24651
|
import os16 from "os";
|
|
24274
24652
|
import path21 from "path";
|
|
24275
|
-
import
|
|
24653
|
+
import fs20 from "fs";
|
|
24276
24654
|
function userFiles(home, env) {
|
|
24277
24655
|
const xdg = env.XDG_CONFIG_HOME || path21.join(home, ".config");
|
|
24278
24656
|
return [
|
|
@@ -24357,7 +24735,7 @@ function configuredRegistryHosts(cwd, env = process.env, home = os16.homedir())
|
|
|
24357
24735
|
const r = readCappedText(
|
|
24358
24736
|
file2,
|
|
24359
24737
|
MAX_CONFIG_BYTES,
|
|
24360
|
-
|
|
24738
|
+
fs20.constants.O_RDONLY | (fs20.constants.O_NONBLOCK ?? 0)
|
|
24361
24739
|
);
|
|
24362
24740
|
if (r) hostsInText(r.text, hosts);
|
|
24363
24741
|
}
|
|
@@ -24415,7 +24793,7 @@ var init_registries = __esm({
|
|
|
24415
24793
|
});
|
|
24416
24794
|
|
|
24417
24795
|
// src/utils/provenance.ts
|
|
24418
|
-
import
|
|
24796
|
+
import fs21 from "fs";
|
|
24419
24797
|
import path22 from "path";
|
|
24420
24798
|
import os17 from "os";
|
|
24421
24799
|
function findInPath(cmd) {
|
|
@@ -24425,7 +24803,7 @@ function findInPath(cmd) {
|
|
|
24425
24803
|
if (!dir2) continue;
|
|
24426
24804
|
const full = path22.join(dir2, cmd);
|
|
24427
24805
|
try {
|
|
24428
|
-
|
|
24806
|
+
fs21.accessSync(full, fs21.constants.X_OK);
|
|
24429
24807
|
return full;
|
|
24430
24808
|
} catch {
|
|
24431
24809
|
}
|
|
@@ -24470,7 +24848,7 @@ function checkProvenance(cmd, cwd) {
|
|
|
24470
24848
|
reason: "binary not found in PATH"
|
|
24471
24849
|
};
|
|
24472
24850
|
}
|
|
24473
|
-
resolved =
|
|
24851
|
+
resolved = fs21.realpathSync(found);
|
|
24474
24852
|
} catch {
|
|
24475
24853
|
return {
|
|
24476
24854
|
resolvedPath: cmd,
|
|
@@ -24479,7 +24857,7 @@ function checkProvenance(cmd, cwd) {
|
|
|
24479
24857
|
};
|
|
24480
24858
|
}
|
|
24481
24859
|
try {
|
|
24482
|
-
const stat =
|
|
24860
|
+
const stat = fs21.statSync(resolved);
|
|
24483
24861
|
if (stat.mode & 2) {
|
|
24484
24862
|
return {
|
|
24485
24863
|
resolvedPath: resolved,
|
|
@@ -24516,8 +24894,9 @@ var init_provenance2 = __esm({
|
|
|
24516
24894
|
});
|
|
24517
24895
|
|
|
24518
24896
|
// src/policy/index.ts
|
|
24519
|
-
import
|
|
24897
|
+
import fs22 from "fs";
|
|
24520
24898
|
import path23 from "path";
|
|
24899
|
+
import os18 from "os";
|
|
24521
24900
|
async function evaluatePolicy2(toolName, args, agent, cwd, opts) {
|
|
24522
24901
|
const config = opts?.config ?? getConfig(cwd);
|
|
24523
24902
|
const prepared = opts?.fileAccess ?? prepareFileAccesses(toolName, args, cwd, inspectionLayers(config.policy));
|
|
@@ -24544,14 +24923,26 @@ async function evaluatePolicy2(toolName, args, agent, cwd, opts) {
|
|
|
24544
24923
|
isTrustedHost: config.policy.trustedHostsManaged ? (host2) => matchesTrustedHost(host2, config.policy.trustedHosts) : isTrustedHost,
|
|
24545
24924
|
readAgentSettings,
|
|
24546
24925
|
isConfiguredRegistry: (host2, at) => configuredRegistryHosts(at).has(host2),
|
|
24547
|
-
isGitWorkTreeTop
|
|
24926
|
+
isGitWorkTreeTop,
|
|
24927
|
+
daemonPid: daemonPidFromFile
|
|
24548
24928
|
}
|
|
24549
24929
|
);
|
|
24550
24930
|
}
|
|
24931
|
+
function daemonPidFromFile() {
|
|
24932
|
+
if (forecastRun()) return null;
|
|
24933
|
+
const text = readSmallFile(path23.join(os18.homedir(), ".node9", "daemon.pid"), 4096);
|
|
24934
|
+
if (text === null) return null;
|
|
24935
|
+
try {
|
|
24936
|
+
const pid = JSON.parse(text).pid;
|
|
24937
|
+
return typeof pid === "number" && Number.isInteger(pid) && pid > 0 && pid <= 4194304 ? pid : null;
|
|
24938
|
+
} catch {
|
|
24939
|
+
return null;
|
|
24940
|
+
}
|
|
24941
|
+
}
|
|
24551
24942
|
function isGitWorkTreeTop(dir2, cwd) {
|
|
24552
24943
|
if (!path23.isAbsolute(cwd)) return true;
|
|
24553
24944
|
try {
|
|
24554
|
-
return
|
|
24945
|
+
return fs22.existsSync(path23.join(path23.resolve(cwd, dir2), ".git"));
|
|
24555
24946
|
} catch {
|
|
24556
24947
|
return true;
|
|
24557
24948
|
}
|
|
@@ -24560,7 +24951,7 @@ function readAgentSettings(absPath) {
|
|
|
24560
24951
|
const r = readCappedText(
|
|
24561
24952
|
absPath,
|
|
24562
24953
|
MAX_AGENT_SETTINGS_BYTES,
|
|
24563
|
-
|
|
24954
|
+
fs22.constants.O_RDONLY | (fs22.constants.O_NONBLOCK ?? 0)
|
|
24564
24955
|
);
|
|
24565
24956
|
return r && !r.truncated ? r.text : null;
|
|
24566
24957
|
}
|
|
@@ -24574,6 +24965,8 @@ var init_policy = __esm({
|
|
|
24574
24965
|
init_esm_shims();
|
|
24575
24966
|
init_dist();
|
|
24576
24967
|
init_read_capped();
|
|
24968
|
+
init_read_small_file();
|
|
24969
|
+
init_forecast_context();
|
|
24577
24970
|
init_dlp();
|
|
24578
24971
|
init_gate_order();
|
|
24579
24972
|
init_file_access();
|
|
@@ -25743,46 +26136,13 @@ var init_codex = __esm({
|
|
|
25743
26136
|
}
|
|
25744
26137
|
});
|
|
25745
26138
|
|
|
25746
|
-
// src/utils/read-small-file.ts
|
|
25747
|
-
import fs22 from "fs";
|
|
25748
|
-
function readSmallFile(file2, maxBytes) {
|
|
25749
|
-
let fd;
|
|
25750
|
-
try {
|
|
25751
|
-
fd = fs22.openSync(file2, fs22.constants.O_RDONLY | (fs22.constants.O_NONBLOCK ?? 0));
|
|
25752
|
-
} catch {
|
|
25753
|
-
return null;
|
|
25754
|
-
}
|
|
25755
|
-
try {
|
|
25756
|
-
const st = fs22.fstatSync(fd);
|
|
25757
|
-
if (!st.isFile() || st.size > maxBytes) return null;
|
|
25758
|
-
const buf = Buffer.alloc(Math.min(st.size, maxBytes));
|
|
25759
|
-
let read2 = 0;
|
|
25760
|
-
while (read2 < buf.length) {
|
|
25761
|
-
const n = fs22.readSync(fd, buf, read2, buf.length - read2, read2);
|
|
25762
|
-
if (n === 0) break;
|
|
25763
|
-
read2 += n;
|
|
25764
|
-
}
|
|
25765
|
-
return buf.toString("utf8", 0, read2);
|
|
25766
|
-
} catch {
|
|
25767
|
-
return null;
|
|
25768
|
-
} finally {
|
|
25769
|
-
fs22.closeSync(fd);
|
|
25770
|
-
}
|
|
25771
|
-
}
|
|
25772
|
-
var init_read_small_file = __esm({
|
|
25773
|
-
"src/utils/read-small-file.ts"() {
|
|
25774
|
-
"use strict";
|
|
25775
|
-
init_esm_shims();
|
|
25776
|
-
}
|
|
25777
|
-
});
|
|
25778
|
-
|
|
25779
26139
|
// src/posture/agent-permissions.ts
|
|
25780
|
-
import
|
|
26140
|
+
import os19 from "os";
|
|
25781
26141
|
import path25 from "path";
|
|
25782
26142
|
function readSmall(file2) {
|
|
25783
26143
|
return readSmallFile(file2, MAX_FILE_BYTES2);
|
|
25784
26144
|
}
|
|
25785
|
-
function
|
|
26145
|
+
function base3(agent, severity, title) {
|
|
25786
26146
|
return {
|
|
25787
26147
|
category: CATEGORY,
|
|
25788
26148
|
severity,
|
|
@@ -25809,7 +26169,7 @@ function claudeCode(home) {
|
|
|
25809
26169
|
const findings = [];
|
|
25810
26170
|
const mode = typeof cfg.permissions?.defaultMode === "string" ? cfg.permissions.defaultMode : "";
|
|
25811
26171
|
if (CLAUDE_NO_PROMPT_MODES.has(mode) || cfg.dangerouslySkipPermissions === true) {
|
|
25812
|
-
const f =
|
|
26172
|
+
const f = base3("Claude Code", "high", "Claude Code runs without asking");
|
|
25813
26173
|
f.what = "Claude Code's own permission prompt is switched off for every session.";
|
|
25814
26174
|
f.why = CLAUDE_NO_PROMPT_MODES.has(mode) ? `~/.claude/settings.json sets permissions.defaultMode to ${mode}.` : "~/.claude/settings.json sets dangerouslySkipPermissions.";
|
|
25815
26175
|
f.detail = [
|
|
@@ -25820,7 +26180,7 @@ function claudeCode(home) {
|
|
|
25820
26180
|
}
|
|
25821
26181
|
for (const ci of analyzeAgentConfig(".claude/settings.json", text)) {
|
|
25822
26182
|
if (ci.rule !== "CI-1.broad-allow" && ci.rule !== "CI-1.exec-escape-grant") continue;
|
|
25823
|
-
const f =
|
|
26183
|
+
const f = base3(
|
|
25824
26184
|
"Claude Code",
|
|
25825
26185
|
CI_SEVERITY[ci.severity],
|
|
25826
26186
|
ci.rule === "CI-1.broad-allow" ? "Claude Code pre-approves broad tools for every session" : "Claude Code pre-approves a command that can run other programs"
|
|
@@ -25840,7 +26200,7 @@ function codex(home) {
|
|
|
25840
26200
|
const findings = [];
|
|
25841
26201
|
for (const ci of analyzeCodexConfig(".codex/config.toml", text)) {
|
|
25842
26202
|
if (ci.rule !== "CI-1.codex-unsafe-defaults") continue;
|
|
25843
|
-
const f =
|
|
26203
|
+
const f = base3("Codex", "high", "Codex runs without approval or without a sandbox");
|
|
25844
26204
|
f.what = "Codex's own approval or sandbox is switched off for every session.";
|
|
25845
26205
|
f.why = "~/.codex/config.toml sets it for every project.";
|
|
25846
26206
|
f.detail = ci.signals.slice(0, 6);
|
|
@@ -25873,7 +26233,7 @@ function gemini(home) {
|
|
|
25873
26233
|
};
|
|
25874
26234
|
visit2(cfg, "", 0);
|
|
25875
26235
|
if (hits2.length === 0) return [];
|
|
25876
|
-
const f =
|
|
26236
|
+
const f = base3("Gemini CLI", "high", "Gemini CLI accepts every tool call on its own");
|
|
25877
26237
|
f.what = "Gemini CLI's own confirmation is switched off for every session.";
|
|
25878
26238
|
f.why = "~/.gemini/settings.json sets it.";
|
|
25879
26239
|
f.detail = hits2.slice(0, 4);
|
|
@@ -25881,7 +26241,7 @@ function gemini(home) {
|
|
|
25881
26241
|
return [f];
|
|
25882
26242
|
}
|
|
25883
26243
|
function checkAgentPermissions(ctx) {
|
|
25884
|
-
const home = ctx.home ||
|
|
26244
|
+
const home = ctx.home || os19.homedir();
|
|
25885
26245
|
return [...claudeCode(home), ...codex(home), ...gemini(home)];
|
|
25886
26246
|
}
|
|
25887
26247
|
var CATEGORY, CLAUDE_NO_PROMPT_MODES, MAX_FILE_BYTES2, CI_SEVERITY;
|
|
@@ -25905,7 +26265,7 @@ var init_agent_permissions = __esm({
|
|
|
25905
26265
|
});
|
|
25906
26266
|
|
|
25907
26267
|
// src/posture/outside-content.ts
|
|
25908
|
-
import
|
|
26268
|
+
import os20 from "os";
|
|
25909
26269
|
function outsideSources(home, roles) {
|
|
25910
26270
|
const out = [];
|
|
25911
26271
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -25924,7 +26284,7 @@ function outsideSources(home, roles) {
|
|
|
25924
26284
|
return out;
|
|
25925
26285
|
}
|
|
25926
26286
|
function checkOutsideContent(ctx) {
|
|
25927
|
-
const home = ctx.home ||
|
|
26287
|
+
const home = ctx.home || os20.homedir();
|
|
25928
26288
|
const config = getConfig(ctx.cwd);
|
|
25929
26289
|
const roles = config.policy.untrustedContent?.roles ?? {};
|
|
25930
26290
|
const sources = outsideSources(home, roles);
|
|
@@ -25982,7 +26342,7 @@ var init_outside_content = __esm({
|
|
|
25982
26342
|
|
|
25983
26343
|
// src/posture/instruction-files.ts
|
|
25984
26344
|
import fs23 from "fs";
|
|
25985
|
-
import
|
|
26345
|
+
import os21 from "os";
|
|
25986
26346
|
import path26 from "path";
|
|
25987
26347
|
function listMd(dir2, depth, out) {
|
|
25988
26348
|
if (out.length >= MAX_FILES || depth < 0) return;
|
|
@@ -26041,7 +26401,7 @@ function counts(ci, memory) {
|
|
|
26041
26401
|
return memory ? ci.severity === "high" || ci.severity === "critical" : true;
|
|
26042
26402
|
}
|
|
26043
26403
|
function checkInstructionFiles(ctx) {
|
|
26044
|
-
const home = ctx.home ||
|
|
26404
|
+
const home = ctx.home || os21.homedir();
|
|
26045
26405
|
const findings = [];
|
|
26046
26406
|
const detail = [];
|
|
26047
26407
|
let worst = "medium";
|
|
@@ -26109,9 +26469,9 @@ var init_instruction_files = __esm({
|
|
|
26109
26469
|
// src/skill-pin.ts
|
|
26110
26470
|
import fs24 from "fs";
|
|
26111
26471
|
import path27 from "path";
|
|
26112
|
-
import
|
|
26472
|
+
import os22 from "os";
|
|
26113
26473
|
import crypto3 from "crypto";
|
|
26114
|
-
function getPinsFilePath(home =
|
|
26474
|
+
function getPinsFilePath(home = os22.homedir()) {
|
|
26115
26475
|
return path27.join(home, ".node9", "skill-pins.json");
|
|
26116
26476
|
}
|
|
26117
26477
|
function getRootKey(absPath) {
|
|
@@ -26132,7 +26492,7 @@ function readSkillPinsSafe(home) {
|
|
|
26132
26492
|
return { ok: false, reason: "corrupt", detail: String(err) };
|
|
26133
26493
|
}
|
|
26134
26494
|
}
|
|
26135
|
-
function defaultSkillRoots(_cwd, home =
|
|
26495
|
+
function defaultSkillRoots(_cwd, home = os22.homedir()) {
|
|
26136
26496
|
const marketplaces = path27.join(home, ".claude", "plugins", "marketplaces");
|
|
26137
26497
|
const roots = [];
|
|
26138
26498
|
let registries;
|
|
@@ -26168,7 +26528,7 @@ var init_skill_pin = __esm({
|
|
|
26168
26528
|
});
|
|
26169
26529
|
|
|
26170
26530
|
// src/posture/supply-chain.ts
|
|
26171
|
-
import
|
|
26531
|
+
import os23 from "os";
|
|
26172
26532
|
import path28 from "path";
|
|
26173
26533
|
import { parse as parseToml7 } from "smol-toml";
|
|
26174
26534
|
function isNode9Managed(command, args = []) {
|
|
@@ -26197,7 +26557,7 @@ function readServers(file2, format, agent) {
|
|
|
26197
26557
|
}
|
|
26198
26558
|
}
|
|
26199
26559
|
function checkSupplyChain(ctx) {
|
|
26200
|
-
const home = ctx.home ||
|
|
26560
|
+
const home = ctx.home || os23.homedir();
|
|
26201
26561
|
const servers = [];
|
|
26202
26562
|
for (const spec of AGENT_SPECS) {
|
|
26203
26563
|
if (!spec.mcpFile || spec.mcpInventory === false) continue;
|
|
@@ -26622,7 +26982,7 @@ var init_startup_log = __esm({
|
|
|
26622
26982
|
// src/daemon/service.ts
|
|
26623
26983
|
import fs27 from "fs";
|
|
26624
26984
|
import path29 from "path";
|
|
26625
|
-
import
|
|
26985
|
+
import os24 from "os";
|
|
26626
26986
|
import { spawnSync, execFileSync } from "child_process";
|
|
26627
26987
|
function isLaunchdInstalled() {
|
|
26628
26988
|
return fs27.existsSync(LAUNCHD_PLIST);
|
|
@@ -26630,7 +26990,7 @@ function isLaunchdInstalled() {
|
|
|
26630
26990
|
function isSystemdInstalled() {
|
|
26631
26991
|
return fs27.existsSync(SYSTEMD_UNIT);
|
|
26632
26992
|
}
|
|
26633
|
-
function windowsStartupDir(homeDir =
|
|
26993
|
+
function windowsStartupDir(homeDir = os24.homedir()) {
|
|
26634
26994
|
const appData = process.env.APPDATA || path29.join(homeDir, "AppData", "Roaming");
|
|
26635
26995
|
return path29.join(appData, "Microsoft", "Windows", "Start Menu", "Programs", "Startup");
|
|
26636
26996
|
}
|
|
@@ -26679,8 +27039,8 @@ var init_service = __esm({
|
|
|
26679
27039
|
init_startup_log();
|
|
26680
27040
|
init_api_url();
|
|
26681
27041
|
LAUNCHD_LABEL = "ai.node9.daemon";
|
|
26682
|
-
LAUNCHD_PLIST = path29.join(
|
|
26683
|
-
SYSTEMD_UNIT_DIR = path29.join(
|
|
27042
|
+
LAUNCHD_PLIST = path29.join(os24.homedir(), "Library", "LaunchAgents", `${LAUNCHD_LABEL}.plist`);
|
|
27043
|
+
SYSTEMD_UNIT_DIR = path29.join(os24.homedir(), ".config", "systemd", "user");
|
|
26684
27044
|
SYSTEMD_UNIT = path29.join(SYSTEMD_UNIT_DIR, "node9-daemon.service");
|
|
26685
27045
|
STARTUP_FILE = "node9-daemon.vbs";
|
|
26686
27046
|
WIN_LAUNCHER = () => path29.join(windowsStartupDir(), STARTUP_FILE);
|
|
@@ -26690,9 +27050,9 @@ var init_service = __esm({
|
|
|
26690
27050
|
});
|
|
26691
27051
|
|
|
26692
27052
|
// src/posture/coverage.ts
|
|
26693
|
-
import
|
|
27053
|
+
import os25 from "os";
|
|
26694
27054
|
function checkCoverage(ctx) {
|
|
26695
|
-
const home = ctx.home ||
|
|
27055
|
+
const home = ctx.home || os25.homedir();
|
|
26696
27056
|
const findings = [];
|
|
26697
27057
|
const protectedAgents = getAgentWiring(home).filter((r) => r.isProtected);
|
|
26698
27058
|
if (protectedAgents.length === 0) {
|
|
@@ -26910,14 +27270,14 @@ function scorePosture(findings, checksRun) {
|
|
|
26910
27270
|
(f) => f.coverage?.state !== "covered" && f.coverage?.state !== "cant-fix"
|
|
26911
27271
|
);
|
|
26912
27272
|
const count = (sev) => open.filter((f) => f.severity === sev && !f.scoreWeight).length;
|
|
26913
|
-
const
|
|
27273
|
+
const base4 = computeSecurityScore({
|
|
26914
27274
|
critical: count("critical"),
|
|
26915
27275
|
high: count("high"),
|
|
26916
27276
|
medium: count("medium"),
|
|
26917
27277
|
total: Math.max(checksRun, 1)
|
|
26918
27278
|
});
|
|
26919
27279
|
const headroom = open.reduce((sum, f) => sum + (f.scoreWeight ?? 0), 0);
|
|
26920
|
-
const score = Math.max(0,
|
|
27280
|
+
const score = Math.max(0, base4.score - headroom);
|
|
26921
27281
|
const tier = score >= 80 ? "good" : score >= 50 ? "at-risk" : "critical";
|
|
26922
27282
|
return { score, tier };
|
|
26923
27283
|
}
|
|
@@ -27091,7 +27451,7 @@ var init_enforcement = __esm({
|
|
|
27091
27451
|
});
|
|
27092
27452
|
|
|
27093
27453
|
// src/posture/index.ts
|
|
27094
|
-
import
|
|
27454
|
+
import os26 from "os";
|
|
27095
27455
|
function dropEnforcementRedundant(findings) {
|
|
27096
27456
|
const coveragePresent = findings.some((f) => f.category === "Coverage");
|
|
27097
27457
|
if (!coveragePresent) return findings;
|
|
@@ -27117,7 +27477,7 @@ async function runChecks(checks, ctx) {
|
|
|
27117
27477
|
}
|
|
27118
27478
|
async function runPosture(opts = {}) {
|
|
27119
27479
|
const ctx = {
|
|
27120
|
-
home: opts.home ??
|
|
27480
|
+
home: opts.home ?? os26.homedir(),
|
|
27121
27481
|
cwd: opts.cwd ?? process.cwd(),
|
|
27122
27482
|
agent: opts.agent,
|
|
27123
27483
|
env: opts.env
|
|
@@ -27215,7 +27575,7 @@ var init_render = __esm({
|
|
|
27215
27575
|
import chalk3 from "chalk";
|
|
27216
27576
|
import fs28 from "fs";
|
|
27217
27577
|
import path31 from "path";
|
|
27218
|
-
import
|
|
27578
|
+
import os27 from "os";
|
|
27219
27579
|
function buildSensitivePaths(home, cwd) {
|
|
27220
27580
|
const homeFiles = homeCredentialFiles(home).map(({ full, label: label2, description, score }) => ({
|
|
27221
27581
|
full,
|
|
@@ -27254,7 +27614,7 @@ function isReadable(filePath) {
|
|
|
27254
27614
|
}
|
|
27255
27615
|
}
|
|
27256
27616
|
function runBlast() {
|
|
27257
|
-
const home =
|
|
27617
|
+
const home = os27.homedir();
|
|
27258
27618
|
const cwd = process.cwd();
|
|
27259
27619
|
const paths = buildSensitivePaths(home, cwd);
|
|
27260
27620
|
let scoreDeduction = 0;
|
|
@@ -27462,7 +27822,7 @@ var init_decision_record = __esm({
|
|
|
27462
27822
|
import fs29 from "fs";
|
|
27463
27823
|
import http from "http";
|
|
27464
27824
|
import path32 from "path";
|
|
27465
|
-
import
|
|
27825
|
+
import os28 from "os";
|
|
27466
27826
|
async function checkStatePredicates(predicates) {
|
|
27467
27827
|
if (predicates.length === 0) return {};
|
|
27468
27828
|
if (forecastRun()) return null;
|
|
@@ -27488,7 +27848,7 @@ function resolveDaemonPort(env = process.env) {
|
|
|
27488
27848
|
function getInternalToken() {
|
|
27489
27849
|
if (forecastRun()) return null;
|
|
27490
27850
|
try {
|
|
27491
|
-
const pidFile = path32.join(
|
|
27851
|
+
const pidFile = path32.join(os28.homedir(), ".node9", "daemon.pid");
|
|
27492
27852
|
if (!fs29.existsSync(pidFile)) return null;
|
|
27493
27853
|
const data = JSON.parse(fs29.readFileSync(pidFile, "utf-8"));
|
|
27494
27854
|
process.kill(data.pid, 0);
|
|
@@ -27499,7 +27859,7 @@ function getInternalToken() {
|
|
|
27499
27859
|
}
|
|
27500
27860
|
function isDaemonRunning() {
|
|
27501
27861
|
if (forecastRun()) return false;
|
|
27502
|
-
const pidFile = path32.join(
|
|
27862
|
+
const pidFile = path32.join(os28.homedir(), ".node9", "daemon.pid");
|
|
27503
27863
|
if (fs29.existsSync(pidFile)) {
|
|
27504
27864
|
let pid;
|
|
27505
27865
|
let port;
|
|
@@ -27546,11 +27906,11 @@ async function daemonHasInteractiveApprover(timeoutMs = 400) {
|
|
|
27546
27906
|
}
|
|
27547
27907
|
}
|
|
27548
27908
|
async function registerDaemonEntry(toolName, args, meta, riskMetadata, activityId, cwd, recoveryCommand, skipBackgroundAuth, viewOnly, localSmartRuleMatched, socketActivitySent, sessionId, card) {
|
|
27549
|
-
const
|
|
27909
|
+
const base4 = `http://${DAEMON_HOST}:${DAEMON_PORT}`;
|
|
27550
27910
|
const ctrl = new AbortController();
|
|
27551
27911
|
const timer = setTimeout(() => ctrl.abort(), 5e3);
|
|
27552
27912
|
try {
|
|
27553
|
-
const res = await fetch(`${
|
|
27913
|
+
const res = await fetch(`${base4}/check`, {
|
|
27554
27914
|
method: "POST",
|
|
27555
27915
|
headers: { "Content-Type": "application/json" },
|
|
27556
27916
|
body: JSON.stringify({
|
|
@@ -27660,8 +28020,8 @@ function daemonGet(urlPath, signal, token = getInternalToken()) {
|
|
|
27660
28020
|
});
|
|
27661
28021
|
}
|
|
27662
28022
|
async function notifyDaemonViewer(toolName, args, meta, riskMetadata, activityId, socketActivitySent, extra) {
|
|
27663
|
-
const
|
|
27664
|
-
const res = await fetch(`${
|
|
28023
|
+
const base4 = `http://${DAEMON_HOST}:${DAEMON_PORT}`;
|
|
28024
|
+
const res = await fetch(`${base4}/check`, {
|
|
27665
28025
|
method: "POST",
|
|
27666
28026
|
headers: { "Content-Type": "application/json" },
|
|
27667
28027
|
body: JSON.stringify({
|
|
@@ -27693,9 +28053,9 @@ async function notifyTaint(filePath, source, fromEid) {
|
|
|
27693
28053
|
return;
|
|
27694
28054
|
}
|
|
27695
28055
|
if (!isDaemonRunning()) return;
|
|
27696
|
-
const
|
|
28056
|
+
const base4 = `http://${DAEMON_HOST}:${DAEMON_PORT}`;
|
|
27697
28057
|
try {
|
|
27698
|
-
await fetch(`${
|
|
28058
|
+
await fetch(`${base4}/taint`, {
|
|
27699
28059
|
method: "POST",
|
|
27700
28060
|
headers: { "Content-Type": "application/json" },
|
|
27701
28061
|
// Phase D2 — fromEid is the audit eid that created this taint (edge source).
|
|
@@ -27713,9 +28073,9 @@ async function checkTaint(paths) {
|
|
|
27713
28073
|
return record2 ? { tainted: true, record: record2 } : { tainted: false };
|
|
27714
28074
|
}
|
|
27715
28075
|
if (!isDaemonRunning()) return { tainted: false, daemonUnavailable: true };
|
|
27716
|
-
const
|
|
28076
|
+
const base4 = `http://${DAEMON_HOST}:${DAEMON_PORT}`;
|
|
27717
28077
|
try {
|
|
27718
|
-
const res = await fetch(`${
|
|
28078
|
+
const res = await fetch(`${base4}/taint/check`, {
|
|
27719
28079
|
method: "POST",
|
|
27720
28080
|
headers: { "Content-Type": "application/json" },
|
|
27721
28081
|
body: JSON.stringify({ paths }),
|
|
@@ -27743,9 +28103,9 @@ async function notifyWritten(paths) {
|
|
|
27743
28103
|
return;
|
|
27744
28104
|
}
|
|
27745
28105
|
if (paths.length === 0 || !isDaemonRunning()) return;
|
|
27746
|
-
const
|
|
28106
|
+
const base4 = `http://${DAEMON_HOST}:${DAEMON_PORT}`;
|
|
27747
28107
|
try {
|
|
27748
|
-
await fetch(`${
|
|
28108
|
+
await fetch(`${base4}/written`, {
|
|
27749
28109
|
method: "POST",
|
|
27750
28110
|
headers: exposureHeaders(),
|
|
27751
28111
|
body: JSON.stringify({ paths: paths.slice(0, 64) }),
|
|
@@ -27759,9 +28119,9 @@ async function checkWritten(paths) {
|
|
|
27759
28119
|
const forecast = forecastRun();
|
|
27760
28120
|
if (forecast) return { written: forecast.session.written(paths) };
|
|
27761
28121
|
if (!isDaemonRunning()) return { written: [], daemonUnavailable: true };
|
|
27762
|
-
const
|
|
28122
|
+
const base4 = `http://${DAEMON_HOST}:${DAEMON_PORT}`;
|
|
27763
28123
|
try {
|
|
27764
|
-
const res = await fetch(`${
|
|
28124
|
+
const res = await fetch(`${base4}/written/check`, {
|
|
27765
28125
|
method: "POST",
|
|
27766
28126
|
headers: exposureHeaders(),
|
|
27767
28127
|
body: JSON.stringify({ paths: paths.slice(0, 64) }),
|
|
@@ -27783,9 +28143,9 @@ async function checkSessionTaint(sessionId) {
|
|
|
27783
28143
|
return record2 ? { tainted: true, record: record2, exposed } : { tainted: false, exposed };
|
|
27784
28144
|
}
|
|
27785
28145
|
if (!sessionId || !isDaemonRunning()) return { tainted: false };
|
|
27786
|
-
const
|
|
28146
|
+
const base4 = `http://${DAEMON_HOST}:${DAEMON_PORT}`;
|
|
27787
28147
|
try {
|
|
27788
|
-
const res = await fetch(`${
|
|
28148
|
+
const res = await fetch(`${base4}/session-taint/check`, {
|
|
27789
28149
|
method: "POST",
|
|
27790
28150
|
headers: exposureHeaders(),
|
|
27791
28151
|
body: JSON.stringify({ sessionId }),
|
|
@@ -27803,8 +28163,8 @@ function exposureHeaders() {
|
|
|
27803
28163
|
};
|
|
27804
28164
|
}
|
|
27805
28165
|
async function exposurePost(route, body, timeoutMs) {
|
|
27806
|
-
const
|
|
27807
|
-
const res = await fetch(`${
|
|
28166
|
+
const base4 = `http://${DAEMON_HOST}:${DAEMON_PORT}`;
|
|
28167
|
+
const res = await fetch(`${base4}${route}`, {
|
|
27808
28168
|
method: "POST",
|
|
27809
28169
|
headers: exposureHeaders(),
|
|
27810
28170
|
body: JSON.stringify(body),
|
|
@@ -27819,7 +28179,8 @@ async function checkSessionExposure(sessionId) {
|
|
|
27819
28179
|
const record2 = forecast.session.checkExposure(forecast.now);
|
|
27820
28180
|
return record2 ? { exposed: true, record: record2 } : { exposed: false };
|
|
27821
28181
|
}
|
|
27822
|
-
if (!sessionId
|
|
28182
|
+
if (!sessionId) return { exposed: false };
|
|
28183
|
+
if (!isDaemonRunning()) return { exposed: false, daemonUnavailable: true };
|
|
27823
28184
|
try {
|
|
27824
28185
|
return await exposurePost(
|
|
27825
28186
|
"/session-exposure/check",
|
|
@@ -27843,8 +28204,8 @@ async function approveSessionExposure(sessionId, keys) {
|
|
|
27843
28204
|
}
|
|
27844
28205
|
}
|
|
27845
28206
|
async function resolveViaDaemon(id, decision, internalToken, source, record2) {
|
|
27846
|
-
const
|
|
27847
|
-
const res = await fetch(`${
|
|
28207
|
+
const base4 = `http://${DAEMON_HOST}:${DAEMON_PORT}`;
|
|
28208
|
+
const res = await fetch(`${base4}/resolve/${id}`, {
|
|
27848
28209
|
method: "POST",
|
|
27849
28210
|
headers: { "Content-Type": "application/json", "X-Node9-Internal": internalToken },
|
|
27850
28211
|
body: JSON.stringify({ decision, ...source && { source }, ...record2 && { record: record2 } }),
|
|
@@ -28108,7 +28469,7 @@ var init_scan_watermark = __esm({
|
|
|
28108
28469
|
|
|
28109
28470
|
// src/cli/aggregate/report-audit.ts
|
|
28110
28471
|
import fs31 from "fs";
|
|
28111
|
-
import
|
|
28472
|
+
import os29 from "os";
|
|
28112
28473
|
import path34 from "path";
|
|
28113
28474
|
function buildTestTimestamps(allEntries) {
|
|
28114
28475
|
const testTs = /* @__PURE__ */ new Set();
|
|
@@ -28546,10 +28907,10 @@ function dimensionOfBlock(checkedBy, ruleName) {
|
|
|
28546
28907
|
}
|
|
28547
28908
|
function aggregateReportFromAudit(period, opts = {}) {
|
|
28548
28909
|
const now = opts.now ?? /* @__PURE__ */ new Date();
|
|
28549
|
-
const auditLogPath2 = opts.auditLogPath ?? path34.join(
|
|
28550
|
-
const claudeProjectsDir = opts.claudeProjectsDir ?? path34.join(
|
|
28910
|
+
const auditLogPath2 = opts.auditLogPath ?? path34.join(os29.homedir(), ".node9", "audit.log");
|
|
28911
|
+
const claudeProjectsDir = opts.claudeProjectsDir ?? path34.join(os29.homedir(), ".claude", "projects");
|
|
28551
28912
|
const codexSessionsDir2 = opts.codexSessionsDir ?? codexSessionsDir();
|
|
28552
|
-
const geminiTmpDir = opts.geminiTmpDir ?? path34.join(
|
|
28913
|
+
const geminiTmpDir = opts.geminiTmpDir ?? path34.join(os29.homedir(), ".gemini", "tmp");
|
|
28553
28914
|
const hasAuditFile = fs31.existsSync(auditLogPath2);
|
|
28554
28915
|
const allEntries = opts.preloadedAuditEntries ?? parseAuditLog(auditLogPath2);
|
|
28555
28916
|
const unackedDlp = allEntries.filter((e) => e.source === "response-dlp");
|
|
@@ -28946,9 +29307,9 @@ var init_catalog = __esm({
|
|
|
28946
29307
|
// src/daemon/mcp-tools.ts
|
|
28947
29308
|
import fs32 from "fs";
|
|
28948
29309
|
import path35 from "path";
|
|
28949
|
-
import
|
|
29310
|
+
import os30 from "os";
|
|
28950
29311
|
function getMcpToolsFile() {
|
|
28951
|
-
return path35.join(
|
|
29312
|
+
return path35.join(os30.homedir(), ".node9", "mcp-tools.json");
|
|
28952
29313
|
}
|
|
28953
29314
|
function readMcpToolsConfig() {
|
|
28954
29315
|
try {
|
|
@@ -28970,9 +29331,9 @@ var init_mcp_tools = __esm({
|
|
|
28970
29331
|
|
|
28971
29332
|
// src/apps/state.ts
|
|
28972
29333
|
import fs33 from "fs";
|
|
28973
|
-
import
|
|
29334
|
+
import os31 from "os";
|
|
28974
29335
|
import path36 from "path";
|
|
28975
|
-
function appsFilePath(home =
|
|
29336
|
+
function appsFilePath(home = os31.homedir()) {
|
|
28976
29337
|
return path36.join(home, ".node9", "apps.json");
|
|
28977
29338
|
}
|
|
28978
29339
|
function emptyFile() {
|
|
@@ -29442,7 +29803,7 @@ var init_native = __esm({
|
|
|
29442
29803
|
|
|
29443
29804
|
// src/auth/session-script.ts
|
|
29444
29805
|
import fs34 from "fs";
|
|
29445
|
-
import
|
|
29806
|
+
import os32 from "os";
|
|
29446
29807
|
import path39 from "path";
|
|
29447
29808
|
function readScriptFile(resolved) {
|
|
29448
29809
|
let fd;
|
|
@@ -29474,16 +29835,16 @@ function absolute(p, cwd, home) {
|
|
|
29474
29835
|
const spelled = p === "~" || p.startsWith("~/") ? home + p.slice(1) : p;
|
|
29475
29836
|
return path39.resolve(cwd, spelled);
|
|
29476
29837
|
}
|
|
29477
|
-
async function resolveSessionScript(toolName, args, cwd, layers, deps, home =
|
|
29838
|
+
async function resolveSessionScript(toolName, args, cwd, layers, deps, home = os32.homedir()) {
|
|
29478
29839
|
try {
|
|
29479
29840
|
const d = deps ?? { checkWritten, readScript: readScriptFile };
|
|
29480
29841
|
const shell = resolveShellInput(toolName, args, layers);
|
|
29481
29842
|
if (shell.kind !== "shell") return null;
|
|
29482
29843
|
const operands2 = shellScriptOperands(shell.command);
|
|
29483
29844
|
if (operands2.length === 0) return null;
|
|
29484
|
-
const
|
|
29845
|
+
const base4 = cwd ?? process.cwd();
|
|
29485
29846
|
const byResolved = /* @__PURE__ */ new Map();
|
|
29486
|
-
for (const op of operands2) byResolved.set(absolute(op,
|
|
29847
|
+
for (const op of operands2) byResolved.set(absolute(op, base4, home), op);
|
|
29487
29848
|
const { written } = await d.checkWritten([...byResolved.keys()]);
|
|
29488
29849
|
for (const resolved of written) {
|
|
29489
29850
|
const spelled = byResolved.get(resolved);
|
|
@@ -29495,7 +29856,7 @@ async function resolveSessionScript(toolName, args, cwd, layers, deps, home = os
|
|
|
29495
29856
|
path: spelled,
|
|
29496
29857
|
resolved,
|
|
29497
29858
|
args: scriptArgs,
|
|
29498
|
-
fileAccess: prepareFileAccesses("Bash", scriptArgs,
|
|
29859
|
+
fileAccess: prepareFileAccesses("Bash", scriptArgs, base4, layers, home)
|
|
29499
29860
|
};
|
|
29500
29861
|
}
|
|
29501
29862
|
return null;
|
|
@@ -29503,17 +29864,17 @@ async function resolveSessionScript(toolName, args, cwd, layers, deps, home = os
|
|
|
29503
29864
|
return null;
|
|
29504
29865
|
}
|
|
29505
29866
|
}
|
|
29506
|
-
function sessionWriteTargets(toolName, args, fileAccess, cwd, home =
|
|
29507
|
-
const
|
|
29867
|
+
function sessionWriteTargets(toolName, args, fileAccess, cwd, home = os32.homedir()) {
|
|
29868
|
+
const base4 = cwd ?? process.cwd();
|
|
29508
29869
|
const out = /* @__PURE__ */ new Set();
|
|
29509
29870
|
const argsObj = args && typeof args === "object" ? args : {};
|
|
29510
29871
|
const named = argsObj.file_path ?? argsObj.path ?? argsObj.filename;
|
|
29511
29872
|
if (typeof named === "string" && named && /write|edit|create|save|append/i.test(toolName))
|
|
29512
|
-
out.add(absolute(named,
|
|
29873
|
+
out.add(absolute(named, base4, home));
|
|
29513
29874
|
for (const a of fileAccess?.accesses ?? []) {
|
|
29514
29875
|
if (a.operation !== "write" && a.operation !== "create") continue;
|
|
29515
29876
|
if (a.glob || a.recursive) continue;
|
|
29516
|
-
out.add(absolute(a.path, a.cwd ??
|
|
29877
|
+
out.add(absolute(a.path, a.cwd ?? base4, home));
|
|
29517
29878
|
if (out.size >= MAX_RECORDED_WRITES) break;
|
|
29518
29879
|
}
|
|
29519
29880
|
return [...out];
|
|
@@ -29700,7 +30061,7 @@ var init_known_hosts = __esm({
|
|
|
29700
30061
|
|
|
29701
30062
|
// src/exposure/writes.ts
|
|
29702
30063
|
import fs37 from "fs";
|
|
29703
|
-
import
|
|
30064
|
+
import os33 from "os";
|
|
29704
30065
|
import path42 from "path";
|
|
29705
30066
|
function writtenContent(args) {
|
|
29706
30067
|
if (!args || typeof args !== "object" || Array.isArray(args)) return [];
|
|
@@ -29738,8 +30099,8 @@ function packageScriptsTouched(args, absPath, shellCommand) {
|
|
|
29738
30099
|
}
|
|
29739
30100
|
function judgeWritesAfterExposure(opts) {
|
|
29740
30101
|
const holds = [];
|
|
29741
|
-
const home = opts.home ??
|
|
29742
|
-
const tmp = normalizeFilePath(
|
|
30102
|
+
const home = opts.home ?? os33.homedir();
|
|
30103
|
+
const tmp = normalizeFilePath(os33.tmpdir());
|
|
29743
30104
|
const root = opts.cwd ? normalizeFilePath(opts.cwd, "", home) : null;
|
|
29744
30105
|
const seen = /* @__PURE__ */ new Set();
|
|
29745
30106
|
for (const access of opts.accesses) {
|
|
@@ -29792,10 +30153,10 @@ var init_exposure_store = __esm({
|
|
|
29792
30153
|
// src/exposure/marker.ts
|
|
29793
30154
|
import crypto4 from "crypto";
|
|
29794
30155
|
import fs38 from "fs";
|
|
29795
|
-
import
|
|
30156
|
+
import os34 from "os";
|
|
29796
30157
|
import path43 from "path";
|
|
29797
30158
|
function dir() {
|
|
29798
|
-
return path43.join(
|
|
30159
|
+
return path43.join(os34.homedir(), ".node9", "exposure-sessions");
|
|
29799
30160
|
}
|
|
29800
30161
|
function file(sessionId) {
|
|
29801
30162
|
const id = crypto4.createHash("sha256").update(sessionId).digest("hex").slice(0, 32);
|
|
@@ -29926,9 +30287,9 @@ var init_roles = __esm({
|
|
|
29926
30287
|
// src/auth/trusted-recipients.ts
|
|
29927
30288
|
import fs40 from "fs";
|
|
29928
30289
|
import path44 from "path";
|
|
29929
|
-
import
|
|
30290
|
+
import os35 from "os";
|
|
29930
30291
|
function getTrustedRecipientsPath() {
|
|
29931
|
-
return path44.join(
|
|
30292
|
+
return path44.join(os35.homedir(), ".node9", "trusted-recipients.json");
|
|
29932
30293
|
}
|
|
29933
30294
|
function readTrustedRecipients() {
|
|
29934
30295
|
try {
|
|
@@ -29983,7 +30344,7 @@ var init_trusted_recipients = __esm({
|
|
|
29983
30344
|
// src/auth/state.ts
|
|
29984
30345
|
import fs41 from "fs";
|
|
29985
30346
|
import path45 from "path";
|
|
29986
|
-
import
|
|
30347
|
+
import os36 from "os";
|
|
29987
30348
|
function extractCommandPattern(toolName, args) {
|
|
29988
30349
|
const lower2 = toolName.toLowerCase();
|
|
29989
30350
|
if (lower2 !== "bash" && lower2 !== "execute_bash" && lower2 !== "shell") return void 0;
|
|
@@ -30060,7 +30421,7 @@ function writeTrustSession(toolName, durationMs, args) {
|
|
|
30060
30421
|
}
|
|
30061
30422
|
function getPersistentDecision(toolName) {
|
|
30062
30423
|
try {
|
|
30063
|
-
const file2 = path45.join(
|
|
30424
|
+
const file2 = path45.join(os36.homedir(), ".node9", "decisions.json");
|
|
30064
30425
|
if (!fs41.existsSync(file2)) return null;
|
|
30065
30426
|
const decisions = JSON.parse(fs41.readFileSync(file2, "utf-8"));
|
|
30066
30427
|
const d = decisions[toolName];
|
|
@@ -30077,14 +30438,14 @@ var init_state2 = __esm({
|
|
|
30077
30438
|
init_policy();
|
|
30078
30439
|
init_atomic_write();
|
|
30079
30440
|
init_forecast_context();
|
|
30080
|
-
PAUSED_FILE = path45.join(
|
|
30081
|
-
TRUST_FILE = path45.join(
|
|
30441
|
+
PAUSED_FILE = path45.join(os36.homedir(), ".node9", "PAUSED");
|
|
30442
|
+
TRUST_FILE = path45.join(os36.homedir(), ".node9", "trust.json");
|
|
30082
30443
|
}
|
|
30083
30444
|
});
|
|
30084
30445
|
|
|
30085
30446
|
// src/auth/cloud.ts
|
|
30086
30447
|
import fs42 from "fs";
|
|
30087
|
-
import
|
|
30448
|
+
import os37 from "os";
|
|
30088
30449
|
import path46 from "path";
|
|
30089
30450
|
function maskArgsForCloud(args) {
|
|
30090
30451
|
if (args === void 0 || args === null) return args;
|
|
@@ -30118,7 +30479,7 @@ async function initNode9SaaS(toolName, args, creds, meta, riskMetadata, agentPol
|
|
|
30118
30479
|
let ciContext;
|
|
30119
30480
|
if (process.env.CI) {
|
|
30120
30481
|
try {
|
|
30121
|
-
const ciContextPath = path46.join(
|
|
30482
|
+
const ciContextPath = path46.join(os37.homedir(), ".node9", "ci-context.json");
|
|
30122
30483
|
const ci = readCappedText(ciContextPath, 1e4);
|
|
30123
30484
|
if (!ci) throw new Error("ci-context.json unreadable");
|
|
30124
30485
|
if (ci.truncated) throw new Error("ci-context.json exceeds 10 KB");
|
|
@@ -30160,9 +30521,9 @@ async function initNode9SaaS(toolName, args, creds, meta, riskMetadata, agentPol
|
|
|
30160
30521
|
context: {
|
|
30161
30522
|
agent: meta?.agent,
|
|
30162
30523
|
mcpServer: meta?.mcpServer,
|
|
30163
|
-
hostname:
|
|
30524
|
+
hostname: os37.hostname(),
|
|
30164
30525
|
cwd: process.cwd(),
|
|
30165
|
-
platform:
|
|
30526
|
+
platform: os37.platform()
|
|
30166
30527
|
},
|
|
30167
30528
|
// The SaaS validates riskMetadata strictly and would drop it whole on
|
|
30168
30529
|
// an unknown key, so only fields its schema declares go on the wire.
|
|
@@ -30267,9 +30628,9 @@ var init_cloud = __esm({
|
|
|
30267
30628
|
// src/loop-detector.ts
|
|
30268
30629
|
import fs43 from "fs";
|
|
30269
30630
|
import path47 from "path";
|
|
30270
|
-
import
|
|
30631
|
+
import os38 from "os";
|
|
30271
30632
|
function loopStateFile() {
|
|
30272
|
-
return path47.join(
|
|
30633
|
+
return path47.join(os38.homedir(), ".node9", "loop-state.json");
|
|
30273
30634
|
}
|
|
30274
30635
|
function readState() {
|
|
30275
30636
|
try {
|
|
@@ -30285,7 +30646,7 @@ function readState() {
|
|
|
30285
30646
|
function writeState(records) {
|
|
30286
30647
|
const dir2 = path47.dirname(loopStateFile());
|
|
30287
30648
|
if (!fs43.existsSync(dir2)) fs43.mkdirSync(dir2, { recursive: true });
|
|
30288
|
-
const tmpPath = `${loopStateFile()}.${
|
|
30649
|
+
const tmpPath = `${loopStateFile()}.${os38.hostname()}.${process.pid}.tmp`;
|
|
30289
30650
|
fs43.writeFileSync(tmpPath, JSON.stringify(records));
|
|
30290
30651
|
fs43.renameSync(tmpPath, loopStateFile());
|
|
30291
30652
|
}
|
|
@@ -30449,7 +30810,7 @@ var init_card_result = __esm({
|
|
|
30449
30810
|
});
|
|
30450
30811
|
|
|
30451
30812
|
// src/auth/orchestrator.ts
|
|
30452
|
-
import
|
|
30813
|
+
import os39 from "os";
|
|
30453
30814
|
import path48 from "path";
|
|
30454
30815
|
function isProtectedPathRule(ruleName) {
|
|
30455
30816
|
if (!ruleName) return false;
|
|
@@ -30497,7 +30858,7 @@ function isMcpToolName(toolName) {
|
|
|
30497
30858
|
return /^mcp__[^_](?:[^_]|_(?!_))*?__/i.test(toolName);
|
|
30498
30859
|
}
|
|
30499
30860
|
function absoluteUploadPath(spelled, cwd) {
|
|
30500
|
-
const expanded = spelled === "~" || spelled.startsWith("~/") ? path48.join(
|
|
30861
|
+
const expanded = spelled === "~" || spelled.startsWith("~/") ? path48.join(os39.homedir(), spelled.slice(1)) : spelled;
|
|
30501
30862
|
if (path48.isAbsolute(expanded)) return expanded;
|
|
30502
30863
|
return cwd && path48.isAbsolute(cwd) ? path48.resolve(cwd, expanded) : expanded;
|
|
30503
30864
|
}
|
|
@@ -30777,8 +31138,17 @@ async function _authorizeHeadlessCore(toolName, args, metaArg, options) {
|
|
|
30777
31138
|
const judged = sendsSomething || (!!shellExp?.fetches || writes.length > 0) && mayBeExposed;
|
|
30778
31139
|
if (judged) {
|
|
30779
31140
|
const exposure = await checkSessionExposure(meta.sessionId);
|
|
30780
|
-
|
|
30781
|
-
|
|
31141
|
+
const unknownRead = exposure.daemonUnavailable === true && holdsSendsWithoutDaemon(config.settings.mode);
|
|
31142
|
+
const rec = exposure.exposed && exposure.record ? exposure.record : unknownRead ? {
|
|
31143
|
+
sessionId: meta.sessionId,
|
|
31144
|
+
sources: [],
|
|
31145
|
+
destinations: [],
|
|
31146
|
+
userMentioned: [],
|
|
31147
|
+
approved: [],
|
|
31148
|
+
createdAt: 0,
|
|
31149
|
+
expiresAt: 0
|
|
31150
|
+
} : null;
|
|
31151
|
+
if (rec) {
|
|
30782
31152
|
const dests = new Set(
|
|
30783
31153
|
acts && !shellExp && !mcpFileWrite ? extractArgDestinations(args) : []
|
|
30784
31154
|
);
|
|
@@ -30837,7 +31207,7 @@ async function _authorizeHeadlessCore(toolName, args, metaArg, options) {
|
|
|
30837
31207
|
if (dests.size === 0 && acts && !mcpFileWrite && (role.destructive === true || isDestructiveToolName(bare))) {
|
|
30838
31208
|
held.push({ dest: "", why: "destructive" });
|
|
30839
31209
|
}
|
|
30840
|
-
const writeHolds = writes.length > 0 ? judgeWritesAfterExposure({
|
|
31210
|
+
const writeHolds = writes.length > 0 && !(unknownRead && !exposure.exposed) ? judgeWritesAfterExposure({
|
|
30841
31211
|
accesses: writes,
|
|
30842
31212
|
args,
|
|
30843
31213
|
shellCommand: shellInput.kind === "shell" ? shellInput.command : null,
|
|
@@ -30864,14 +31234,14 @@ async function _authorizeHeadlessCore(toolName, args, metaArg, options) {
|
|
|
30864
31234
|
const parts = held.map(
|
|
30865
31235
|
(h) => h.dest ? `sends to ${destinationValue(h.dest)}, ${h.why === "appeared in what was read" ? `${noun(h.dest)} that appeared in that ${last ? readWord : "content"}` : `${noun(h.dest)} this session did not know`}` : h.why === "repository" ? h.repo.endsWith("/*") ? `sends to a repository on ${h.repo.slice(0, -2)} it does not name (a gist, a new repository or an API call)` : `sends to ${h.repo}, a repository that is not one of this project's remotes` : h.why === "unresolved" ? "sends to a destination this session cannot see (built at run time, or a remote of another repository)" : `is ${bare}, a destructive call, with no known destination`
|
|
30866
31236
|
);
|
|
30867
|
-
const home =
|
|
31237
|
+
const home = os39.homedir();
|
|
30868
31238
|
const short = (p) => p.startsWith(home + "/") ? "~" + p.slice(home.length) : p;
|
|
30869
31239
|
for (const w of writeHolds) {
|
|
30870
31240
|
parts.push(
|
|
30871
31241
|
w.why === "outside-project" ? `writes outside the project, to ${short(w.path)}` : w.why === "agent-instruction" ? `writes to ${short(w.path)}, a file that runs code or instructs the agent` : `writes content carrying ${destinationValue(w.destination ?? "")}, ${noun(w.destination ?? "host:x")} that appeared in that ${readWord}`
|
|
30872
31242
|
);
|
|
30873
31243
|
}
|
|
30874
|
-
exposureReview = `\u{1F6E1}\uFE0F Node9: this session read ${read2}. This call ${parts.join("; and ")}.`;
|
|
31244
|
+
exposureReview = unknownRead && !exposure.exposed ? `\u{1F6E1}\uFE0F Node9: the node9 daemon is not running, so node9 cannot tell what this session read. This call ${parts.join("; and ")}. Start it with: node9 daemon start.` : `\u{1F6E1}\uFE0F Node9: this session read ${read2}. This call ${parts.join("; and ")}.`;
|
|
30875
31245
|
exposureFromEid = last?.eid;
|
|
30876
31246
|
if (exposureFromEid) exposureMeta = { exposureFromEid };
|
|
30877
31247
|
exposureKeys = [
|
|
@@ -32163,11 +32533,11 @@ var init_version = __esm({
|
|
|
32163
32533
|
|
|
32164
32534
|
// src/cli/commands/scan-cache.ts
|
|
32165
32535
|
import fs45 from "fs";
|
|
32166
|
-
import
|
|
32536
|
+
import os40 from "os";
|
|
32167
32537
|
import path50 from "path";
|
|
32168
32538
|
import { createHash as createHash5 } from "crypto";
|
|
32169
32539
|
function scanCacheRoot() {
|
|
32170
|
-
return path50.join(
|
|
32540
|
+
return path50.join(os40.homedir(), ".node9", "scan-cache");
|
|
32171
32541
|
}
|
|
32172
32542
|
function configHashOf(config) {
|
|
32173
32543
|
const h = createHash5("sha256");
|
|
@@ -32175,7 +32545,7 @@ function configHashOf(config) {
|
|
|
32175
32545
|
h.update(JSON.stringify(config.policySource));
|
|
32176
32546
|
h.update(JSON.stringify(config.policy));
|
|
32177
32547
|
for (const name of SIDECAR_FILES) {
|
|
32178
|
-
const st = fileStamp(path50.join(
|
|
32548
|
+
const st = fileStamp(path50.join(os40.homedir(), ".node9", name));
|
|
32179
32549
|
h.update(`|${name}:${st ? `${st.size}:${st.mtimeMs}` : "absent"}`);
|
|
32180
32550
|
}
|
|
32181
32551
|
return h.digest("hex").slice(0, 16);
|
|
@@ -32356,7 +32726,7 @@ var init_scan_cache = __esm({
|
|
|
32356
32726
|
|
|
32357
32727
|
// src/cli/commands/scan-judge.ts
|
|
32358
32728
|
import fs46 from "fs";
|
|
32359
|
-
import
|
|
32729
|
+
import os41 from "os";
|
|
32360
32730
|
import path51 from "path";
|
|
32361
32731
|
function findingDedupKey(f) {
|
|
32362
32732
|
return `${f.source.rule.name ?? "<unnamed>"}|${preview(f.input)}|${f.project}|${f.repo ?? ""}`;
|
|
@@ -32476,7 +32846,7 @@ var init_scan_judge = __esm({
|
|
|
32476
32846
|
if (parent === dir2) break;
|
|
32477
32847
|
dir2 = parent;
|
|
32478
32848
|
}
|
|
32479
|
-
const home =
|
|
32849
|
+
const home = os41.homedir();
|
|
32480
32850
|
const label2 = found && found.startsWith(home) ? "~" + found.slice(home.length) : found;
|
|
32481
32851
|
this.repos.set(cwd, label2);
|
|
32482
32852
|
return label2;
|
|
@@ -32698,7 +33068,7 @@ var init_scan_history = __esm({
|
|
|
32698
33068
|
import chalk6 from "chalk";
|
|
32699
33069
|
import fs47 from "fs";
|
|
32700
33070
|
import path52 from "path";
|
|
32701
|
-
import
|
|
33071
|
+
import os42 from "os";
|
|
32702
33072
|
import stringWidth2 from "string-width";
|
|
32703
33073
|
function dayKey(ts) {
|
|
32704
33074
|
if (!ts) return "unknown";
|
|
@@ -33151,7 +33521,7 @@ async function processClaudeProjectAsync(proj, projectsDir, judge, cache7, start
|
|
|
33151
33521
|
}
|
|
33152
33522
|
function claudeProjectLabel(dirName) {
|
|
33153
33523
|
const name = decodeURIComponent(dirName);
|
|
33154
|
-
const homeDashed =
|
|
33524
|
+
const homeDashed = os42.homedir().replace(/\//g, "-");
|
|
33155
33525
|
const label2 = name.startsWith(homeDashed) ? "~" + decodeProjectDirName(name.slice(homeDashed.length)) : decodeProjectDirName(name);
|
|
33156
33526
|
return stripTerminalEscapes(label2).slice(0, 40);
|
|
33157
33527
|
}
|
|
@@ -33262,7 +33632,7 @@ function mergeFileScan(result, file2, dedup, startDate = null) {
|
|
|
33262
33632
|
}
|
|
33263
33633
|
}
|
|
33264
33634
|
async function scanClaudeHistoryAsync(startDate, onProgress, onLine, opts = {}) {
|
|
33265
|
-
const projectsDir = path52.join(
|
|
33635
|
+
const projectsDir = path52.join(os42.homedir(), ".claude", "projects");
|
|
33266
33636
|
const result = emptyClaudeScan();
|
|
33267
33637
|
if (!fs47.existsSync(projectsDir)) return result;
|
|
33268
33638
|
let projDirs;
|
|
@@ -33295,7 +33665,7 @@ async function scanClaudeHistoryAsync(startDate, onProgress, onLine, opts = {})
|
|
|
33295
33665
|
}
|
|
33296
33666
|
async function scanGeminiHistory(startDate, onProgress, onLine, opts = {}) {
|
|
33297
33667
|
const canaryVals = safeCanaryScanValues();
|
|
33298
|
-
const tmpDir = path52.join(
|
|
33668
|
+
const tmpDir = path52.join(os42.homedir(), ".gemini", "tmp");
|
|
33299
33669
|
const result = {
|
|
33300
33670
|
filesScanned: 0,
|
|
33301
33671
|
sessions: 0,
|
|
@@ -33332,7 +33702,7 @@ async function scanGeminiHistory(startDate, onProgress, onLine, opts = {}) {
|
|
|
33332
33702
|
try {
|
|
33333
33703
|
projLabel = stripTerminalEscapes(
|
|
33334
33704
|
fs47.readFileSync(path52.join(slugPath, ".project_root"), "utf-8").trim()
|
|
33335
|
-
).replace(
|
|
33705
|
+
).replace(os42.homedir(), "~").slice(0, 40);
|
|
33336
33706
|
} catch {
|
|
33337
33707
|
}
|
|
33338
33708
|
const chatsDir = path52.join(slugPath, "chats");
|
|
@@ -33496,7 +33866,7 @@ async function scanGeminiHistory(startDate, onProgress, onLine, opts = {}) {
|
|
|
33496
33866
|
return result;
|
|
33497
33867
|
}
|
|
33498
33868
|
function antigravityBrainDirs() {
|
|
33499
|
-
return ["antigravity-cli", "antigravity-ide"].map((surface) => path52.join(
|
|
33869
|
+
return ["antigravity-cli", "antigravity-ide"].map((surface) => path52.join(os42.homedir(), ".gemini", surface, "brain")).filter((p) => fs47.existsSync(p));
|
|
33500
33870
|
}
|
|
33501
33871
|
function antigravityTranscriptPath(convPath) {
|
|
33502
33872
|
const logsDir = path52.join(convPath, ".system_generated", "logs");
|
|
@@ -33633,7 +34003,7 @@ async function scanAntigravityHistory(startDate, onProgress, onLine, opts = {})
|
|
|
33633
34003
|
day.bashCalls++;
|
|
33634
34004
|
const cwd = String(input.cwd ?? "");
|
|
33635
34005
|
if (cwd && projLabel === conv.slice(0, 8)) {
|
|
33636
|
-
projLabel = stripTerminalEscapes(cwd).replace(
|
|
34006
|
+
projLabel = stripTerminalEscapes(cwd).replace(os42.homedir(), "~").slice(0, 40);
|
|
33637
34007
|
}
|
|
33638
34008
|
}
|
|
33639
34009
|
const rawCmd = String(input.command ?? "").trimStart();
|
|
@@ -33682,7 +34052,7 @@ async function scanAntigravityHistory(startDate, onProgress, onLine, opts = {})
|
|
|
33682
34052
|
}
|
|
33683
34053
|
async function scanCopilotHistory(startDate, onProgress, onLine, opts = {}) {
|
|
33684
34054
|
const canaryVals = safeCanaryScanValues();
|
|
33685
|
-
const sessionDir = path52.join(
|
|
34055
|
+
const sessionDir = path52.join(os42.homedir(), ".copilot", "session-state");
|
|
33686
34056
|
const result = {
|
|
33687
34057
|
filesScanned: 0,
|
|
33688
34058
|
sessions: 0,
|
|
@@ -33750,7 +34120,7 @@ async function scanCopilotHistory(startDate, onProgress, onLine, opts = {}) {
|
|
|
33750
34120
|
if (ev.type === "session.start") {
|
|
33751
34121
|
const cwd = ev.data?.context?.cwd;
|
|
33752
34122
|
if (typeof cwd === "string" && cwd) {
|
|
33753
|
-
projLabel = stripTerminalEscapes(cwd).replace(
|
|
34123
|
+
projLabel = stripTerminalEscapes(cwd).replace(os42.homedir(), "~").slice(0, 40);
|
|
33754
34124
|
if (path52.isAbsolute(cwd)) sessionCwd = cwd;
|
|
33755
34125
|
}
|
|
33756
34126
|
continue;
|
|
@@ -33907,7 +34277,7 @@ async function scanCodexHistory(startDate, onProgress, onLine, opts = {}) {
|
|
|
33907
34277
|
sessionId = String(payload["id"] ?? filePath);
|
|
33908
34278
|
startTime = String(payload["timestamp"] ?? "");
|
|
33909
34279
|
const cwd = String(payload["cwd"] ?? "");
|
|
33910
|
-
projLabel = stripTerminalEscapes(cwd.replace(
|
|
34280
|
+
projLabel = stripTerminalEscapes(cwd.replace(os42.homedir(), "~")).slice(0, 40);
|
|
33911
34281
|
if (path52.isAbsolute(cwd)) sessionCwd = cwd;
|
|
33912
34282
|
continue;
|
|
33913
34283
|
}
|
|
@@ -34108,12 +34478,12 @@ var init_scan = __esm({
|
|
|
34108
34478
|
|
|
34109
34479
|
// src/tui/dashboard/data.ts
|
|
34110
34480
|
import fs48 from "fs";
|
|
34111
|
-
import
|
|
34481
|
+
import os43 from "os";
|
|
34112
34482
|
import path53 from "path";
|
|
34113
34483
|
import http2 from "http";
|
|
34114
34484
|
import { execFile } from "child_process";
|
|
34115
34485
|
function auditLogPath() {
|
|
34116
|
-
return path53.join(
|
|
34486
|
+
return path53.join(os43.homedir(), ".node9", "audit.log");
|
|
34117
34487
|
}
|
|
34118
34488
|
function readAuditEntriesAsync(chunkSize = 1e3, customPath) {
|
|
34119
34489
|
return new Promise((resolve) => {
|
|
@@ -34274,7 +34644,7 @@ async function runPostureDetached() {
|
|
|
34274
34644
|
} catch {
|
|
34275
34645
|
}
|
|
34276
34646
|
}
|
|
34277
|
-
return runPosture({ home:
|
|
34647
|
+
return runPosture({ home: os43.homedir(), cwd: process.cwd() });
|
|
34278
34648
|
}
|
|
34279
34649
|
async function loadPosture(run = runPostureDetached) {
|
|
34280
34650
|
try {
|
|
@@ -34291,13 +34661,13 @@ async function loadPosture(run = runPostureDetached) {
|
|
|
34291
34661
|
}
|
|
34292
34662
|
}
|
|
34293
34663
|
function shortenPath(p) {
|
|
34294
|
-
const home =
|
|
34664
|
+
const home = os43.homedir();
|
|
34295
34665
|
return p.startsWith(home) ? p.replace(home, "~") : p;
|
|
34296
34666
|
}
|
|
34297
34667
|
async function loadReportAuditAsync(period) {
|
|
34298
|
-
const claudeProjectsDir = path53.join(
|
|
34668
|
+
const claudeProjectsDir = path53.join(os43.homedir(), ".claude", "projects");
|
|
34299
34669
|
const codexSessionsDir2 = codexSessionsDir();
|
|
34300
|
-
const geminiTmpDir = path53.join(
|
|
34670
|
+
const geminiTmpDir = path53.join(os43.homedir(), ".gemini", "tmp");
|
|
34301
34671
|
const { start, end } = getDateRange(period, /* @__PURE__ */ new Date());
|
|
34302
34672
|
const entries = await readAuditEntriesAsync();
|
|
34303
34673
|
void ensurePricingLoaded();
|