@node9/proxy 2.13.1 → 2.14.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.js +262 -26
- package/dist/cli.mjs +262 -26
- package/dist/dashboard.mjs +246 -24
- package/dist/index.js +219 -21
- package/dist/index.mjs +219 -21
- package/dist/scan-ink.mjs +44 -1
- package/package.json +1 -1
package/dist/dashboard.mjs
CHANGED
|
@@ -343,6 +343,28 @@ function codexSessionCost(model, tokens, request) {
|
|
|
343
343
|
const tierMultiplier = request?.serviceTier === "flex" ? 0.5 : codexModel(model) === "gpt-6-astra" && (request?.serviceTier === "fast" || request?.serviceTier === "priority") ? 2 : 1;
|
|
344
344
|
return (((input - cached - written) * pin + cached * pcr + written * (pcw || pin)) * inputMultiplier + tokenNumber(tokens.output) * pout * outputMultiplier) * tierMultiplier;
|
|
345
345
|
}
|
|
346
|
+
function statAndFirstLine(file) {
|
|
347
|
+
const CAP = 4 * 1024 * 1024;
|
|
348
|
+
const CHUNK = 64 * 1024;
|
|
349
|
+
const fd = fs2.openSync(file, "r");
|
|
350
|
+
try {
|
|
351
|
+
const stat = fs2.fstatSync(fd);
|
|
352
|
+
const limit = Math.min(stat.size, CAP);
|
|
353
|
+
const parts = [];
|
|
354
|
+
for (let pos = 0; pos < limit; pos += CHUNK) {
|
|
355
|
+
const buf = Buffer.alloc(Math.min(CHUNK, limit - pos));
|
|
356
|
+
const read = fs2.readSync(fd, buf, 0, buf.length, pos);
|
|
357
|
+
if (read <= 0) break;
|
|
358
|
+
const slice = buf.subarray(0, read);
|
|
359
|
+
const nl = slice.indexOf(10);
|
|
360
|
+
parts.push(nl >= 0 ? slice.subarray(0, nl) : slice);
|
|
361
|
+
if (nl >= 0) break;
|
|
362
|
+
}
|
|
363
|
+
return { stat, first: Buffer.concat(parts).toString("utf8") };
|
|
364
|
+
} finally {
|
|
365
|
+
fs2.closeSync(fd);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
346
368
|
function listCodexSessionFiles(base = codexSessionsDir()) {
|
|
347
369
|
const files = [];
|
|
348
370
|
const walk = (dir) => {
|
|
@@ -360,10 +382,10 @@ function listCodexSessionFiles(base = codexSessionsDir()) {
|
|
|
360
382
|
const sessions = /* @__PURE__ */ new Map();
|
|
361
383
|
for (const file of files.sort()) {
|
|
362
384
|
try {
|
|
363
|
-
const stat =
|
|
385
|
+
const { stat, first: head } = statAndFirstLine(file);
|
|
364
386
|
let id = "";
|
|
365
387
|
try {
|
|
366
|
-
const first = JSON.parse(
|
|
388
|
+
const first = JSON.parse(head);
|
|
367
389
|
if (first?.type === "session_meta" && typeof first.payload?.id === "string")
|
|
368
390
|
id = first.payload.id;
|
|
369
391
|
} catch {
|
|
@@ -1067,20 +1089,32 @@ function isProtectedHomePath(rawPath) {
|
|
|
1067
1089
|
}
|
|
1068
1090
|
return true;
|
|
1069
1091
|
}
|
|
1070
|
-
function
|
|
1071
|
-
const
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
const name = (words[0] ?? "").toLowerCase();
|
|
1075
|
-
const flags = [];
|
|
1076
|
-
const paths = [];
|
|
1077
|
-
for (let i = 1; i < words.length; i++) {
|
|
1092
|
+
function positionedArgs(words, from = 1, to = words.length) {
|
|
1093
|
+
const out = [];
|
|
1094
|
+
let afterFlag = null;
|
|
1095
|
+
for (let i = from; i < to; i++) {
|
|
1078
1096
|
const v = words[i];
|
|
1079
|
-
if (v === null)
|
|
1080
|
-
|
|
1081
|
-
|
|
1097
|
+
if (v === null) {
|
|
1098
|
+
afterFlag = null;
|
|
1099
|
+
continue;
|
|
1100
|
+
}
|
|
1101
|
+
if (v.startsWith("-")) {
|
|
1102
|
+
afterFlag = v;
|
|
1103
|
+
continue;
|
|
1104
|
+
}
|
|
1105
|
+
out.push({ value: v, index: out.length, argv: i, afterFlag });
|
|
1106
|
+
afterFlag = null;
|
|
1082
1107
|
}
|
|
1083
|
-
return
|
|
1108
|
+
return out;
|
|
1109
|
+
}
|
|
1110
|
+
function extractLiteralArgs(callExpr) {
|
|
1111
|
+
const rawArgs = callExpr.Args || [];
|
|
1112
|
+
if (rawArgs.length === 0) return { name: "", flags: [], paths: [], words: [], args: [] };
|
|
1113
|
+
const words = rawArgs.map((a) => resolveWordLiteral(a));
|
|
1114
|
+
const name = baseWord(words[0]);
|
|
1115
|
+
const flags = words.slice(1).filter((w) => w !== null && w.startsWith("-"));
|
|
1116
|
+
const args = positionedArgs(words);
|
|
1117
|
+
return { name, flags, paths: args.map((a) => a.value), words, args };
|
|
1084
1118
|
}
|
|
1085
1119
|
function resolveWordLiteral(w) {
|
|
1086
1120
|
const parts = w?.Parts || [];
|
|
@@ -1191,6 +1225,9 @@ function analyzeFsOperationImpl(command, depth = 0) {
|
|
|
1191
1225
|
if (result?.verdict === "block") return false;
|
|
1192
1226
|
}
|
|
1193
1227
|
}
|
|
1228
|
+
for (const p of copySourcePaths(words)) {
|
|
1229
|
+
result = stricter(result, copyVerdictOf(matchSensitivePath2(p)));
|
|
1230
|
+
}
|
|
1194
1231
|
return true;
|
|
1195
1232
|
});
|
|
1196
1233
|
return result;
|
|
@@ -1203,6 +1240,133 @@ function stricter(a, b) {
|
|
|
1203
1240
|
if (!b) return a;
|
|
1204
1241
|
return b.verdict === "block" && a.verdict !== "block" ? b : a;
|
|
1205
1242
|
}
|
|
1243
|
+
function flagInfo(w) {
|
|
1244
|
+
if (w.startsWith("--")) {
|
|
1245
|
+
const eq = w.indexOf("=");
|
|
1246
|
+
return eq < 0 ? { letter: null, long: w, attached: null } : { letter: null, long: w.slice(0, eq), attached: w.slice(eq + 1) };
|
|
1247
|
+
}
|
|
1248
|
+
const m = /^-([a-zA-Z]+)(.*)$/.exec(w);
|
|
1249
|
+
if (!m) return { letter: null, long: null, attached: null };
|
|
1250
|
+
return { letter: m[1][m[1].length - 1], long: null, attached: m[2] === "" ? null : m[2] };
|
|
1251
|
+
}
|
|
1252
|
+
function flagIs(w, names) {
|
|
1253
|
+
if (w === null) return false;
|
|
1254
|
+
const f = flagInfo(w);
|
|
1255
|
+
return names.some((n) => n.startsWith("--") ? f.long === n : f.letter === n);
|
|
1256
|
+
}
|
|
1257
|
+
function operandOf(a, names) {
|
|
1258
|
+
if (!names || a.afterFlag === null) return false;
|
|
1259
|
+
return flagIs(a.afterFlag, names) && flagInfo(a.afterFlag).attached === null;
|
|
1260
|
+
}
|
|
1261
|
+
function resolveCopyShape(words, h) {
|
|
1262
|
+
const verb = baseWord(words[h]);
|
|
1263
|
+
if (!verb) return null;
|
|
1264
|
+
const direct = COPY_VERBS[verb];
|
|
1265
|
+
if (direct) return { shape: direct, last: h };
|
|
1266
|
+
const slots = positionedArgs(words, h + 1);
|
|
1267
|
+
for (let i = 0; i < slots.length; i++) {
|
|
1268
|
+
for (let n = 3; n >= 1; n--) {
|
|
1269
|
+
const part = slots.slice(i, i + n);
|
|
1270
|
+
if (part.length < n) continue;
|
|
1271
|
+
const key = [verb, ...part.map((a) => a.value.toLowerCase())].join(" ");
|
|
1272
|
+
const shape = COPY_VERBS[key];
|
|
1273
|
+
if (shape) return { shape, last: part[n - 1].argv };
|
|
1274
|
+
}
|
|
1275
|
+
if (slots[i].afterFlag === null) return null;
|
|
1276
|
+
}
|
|
1277
|
+
return null;
|
|
1278
|
+
}
|
|
1279
|
+
function findStartPoints(words, h) {
|
|
1280
|
+
const k = words.findIndex((w, i) => i > h && w !== null && FIND_EXEC_FLAGS.has(w));
|
|
1281
|
+
if (k < 0) return { k, starts: [] };
|
|
1282
|
+
const firstPredicate = words.findIndex(
|
|
1283
|
+
(w, i) => i > h && w !== null && w.startsWith("-") && !FIND_OPTIONS.has(w)
|
|
1284
|
+
);
|
|
1285
|
+
const end = firstPredicate > h ? firstPredicate : k;
|
|
1286
|
+
return { k, starts: positionalAfter(words, h + 1, end) };
|
|
1287
|
+
}
|
|
1288
|
+
function copySourcePaths(words) {
|
|
1289
|
+
const h = unwrapCommandHead(words);
|
|
1290
|
+
const fi = words.findIndex((w, i) => i <= h && baseWord(w) === "find");
|
|
1291
|
+
if (fi >= 0) {
|
|
1292
|
+
const { k, starts } = findStartPoints(words, fi);
|
|
1293
|
+
if (k < 0) return [];
|
|
1294
|
+
const action = unwrapCommandHead(words.slice(k + 1));
|
|
1295
|
+
return resolveCopyShape(words.slice(k + 1), action) ? starts : [];
|
|
1296
|
+
}
|
|
1297
|
+
if (!COPY_VERB_HEADS.has(baseWord(words[h]))) return [];
|
|
1298
|
+
const r = resolveCopyShape(words, h);
|
|
1299
|
+
if (!r) return [];
|
|
1300
|
+
const { shape, last } = r;
|
|
1301
|
+
const args = positionedArgs(words, last + 1);
|
|
1302
|
+
const tail = words.slice(last + 1);
|
|
1303
|
+
const skipped = (a) => operandOf(a, shape.skipFlags);
|
|
1304
|
+
const targetDir = shape.targetDirFlag === true && tail.some((w) => w !== null && w.startsWith("-") && flagIs(w, ["t", "--target-directory"]));
|
|
1305
|
+
const targetOperand = (a) => targetDir && operandOf(a, ["t", "--target-directory"]);
|
|
1306
|
+
const lastOperand = [...tail].reverse().find((w) => w === null || !w.startsWith("-"));
|
|
1307
|
+
const dynamicDest = lastOperand === null;
|
|
1308
|
+
const destIsLastOperand = (shape.source === "allButLast" || shape.source === "first") && !targetDir && !dynamicDest;
|
|
1309
|
+
if (destIsLastOperand && typeof lastOperand === "string" && matchSensitivePath2(lastOperand))
|
|
1310
|
+
return [];
|
|
1311
|
+
let src;
|
|
1312
|
+
switch (shape.source) {
|
|
1313
|
+
case "all":
|
|
1314
|
+
src = args;
|
|
1315
|
+
break;
|
|
1316
|
+
case "first":
|
|
1317
|
+
src = targetDir ? args : args.slice(0, 1);
|
|
1318
|
+
break;
|
|
1319
|
+
case "flagOperand": {
|
|
1320
|
+
const inline = tail.filter((w) => w !== null && w.startsWith("--")).map((w) => flagInfo(w)).filter((f) => f.attached !== null && (shape.sourceFlags ?? []).includes(f.long ?? "")).map((f) => f.attached);
|
|
1321
|
+
return [
|
|
1322
|
+
...args.filter(
|
|
1323
|
+
(a) => flagIs(a.afterFlag, shape.sourceFlags ?? []) && flagInfo(a.afterFlag).attached === null
|
|
1324
|
+
).map((a) => a.value),
|
|
1325
|
+
...inline
|
|
1326
|
+
];
|
|
1327
|
+
}
|
|
1328
|
+
case "archive":
|
|
1329
|
+
src = archiveInputs(shape.archive, args, tail);
|
|
1330
|
+
break;
|
|
1331
|
+
case "allButLast":
|
|
1332
|
+
src = targetDir || dynamicDest ? args : args.slice(0, -1);
|
|
1333
|
+
break;
|
|
1334
|
+
}
|
|
1335
|
+
return src.filter((a) => !skipped(a) && !targetOperand(a)).map((a) => a.value);
|
|
1336
|
+
}
|
|
1337
|
+
function archiveInputs(kind, args, tail) {
|
|
1338
|
+
const first = args[0];
|
|
1339
|
+
const bareKey = first && first.afterFlag === null && TAR_MODE_WORD.test(first.value);
|
|
1340
|
+
if (kind === "tar") {
|
|
1341
|
+
const flagsText = tail.filter((w) => w !== null && w.startsWith("-")).join(" ");
|
|
1342
|
+
const mode = (bareKey ? first.value : "") + flagsText;
|
|
1343
|
+
const extracting = /x|t/.test(bareKey ? first.value.replace(/f/g, "") : "") || /(^|\s)-[a-zA-Z]*[xt]|--extract|--list|--get/.test(flagsText);
|
|
1344
|
+
const writing = /[cruA]/.test(bareKey ? first.value : "") || /(^|\s)-[a-zA-Z]*[cruA]|--create|--append|--update|--concatenate/.test(flagsText);
|
|
1345
|
+
if (extracting && !writing) return [];
|
|
1346
|
+
void mode;
|
|
1347
|
+
let i = 0;
|
|
1348
|
+
if (bareKey) {
|
|
1349
|
+
i = 1;
|
|
1350
|
+
const next = args[1];
|
|
1351
|
+
if (first.value.includes("f") && next && next.afterFlag === null) i = 2;
|
|
1352
|
+
}
|
|
1353
|
+
return args.slice(i);
|
|
1354
|
+
}
|
|
1355
|
+
if (kind === "zip") return first && first.afterFlag === "-" ? args : args.slice(1);
|
|
1356
|
+
if (kind === "ar") return bareKey ? args.slice(2) : args.slice(1);
|
|
1357
|
+
return args.slice(2);
|
|
1358
|
+
}
|
|
1359
|
+
function copyVerdictOf(hit) {
|
|
1360
|
+
if (!hit) return null;
|
|
1361
|
+
const ruleName = COPY_RULE_OF[hit.ruleName];
|
|
1362
|
+
if (!ruleName) return null;
|
|
1363
|
+
return {
|
|
1364
|
+
ruleName,
|
|
1365
|
+
verdict: "review",
|
|
1366
|
+
reason: `Copying ${hit.path} moves a credential out of its jail (project-jail shield)`,
|
|
1367
|
+
path: hit.path
|
|
1368
|
+
};
|
|
1369
|
+
}
|
|
1206
1370
|
function matchSensitivePath2(p) {
|
|
1207
1371
|
for (const sp of SENSITIVE_PATH_RULES) {
|
|
1208
1372
|
if (sp.match(p))
|
|
@@ -1210,12 +1374,13 @@ function matchSensitivePath2(p) {
|
|
|
1210
1374
|
}
|
|
1211
1375
|
return null;
|
|
1212
1376
|
}
|
|
1377
|
+
function baseWord(w) {
|
|
1378
|
+
return (w ?? "").split("/").pop()?.toLowerCase() ?? "";
|
|
1379
|
+
}
|
|
1213
1380
|
function wrappedReadPaths(words, name) {
|
|
1214
1381
|
if (name === "find") {
|
|
1215
|
-
const k = words
|
|
1216
|
-
|
|
1217
|
-
const firstPredicate = words.findIndex((w, i) => i > 0 && w !== null && w.startsWith("-"));
|
|
1218
|
-
return positionalAfter(words, 1, firstPredicate > 0 ? firstPredicate : k);
|
|
1382
|
+
const { k, starts } = findStartPoints(words, 0);
|
|
1383
|
+
return k > 0 && isReaderWord(words[k + 1] ?? null) ? starts : null;
|
|
1219
1384
|
}
|
|
1220
1385
|
if (!COMMAND_WRAPPERS.has(name) && !RUNNER_WRAPPERS.has(name)) return null;
|
|
1221
1386
|
const h = unwrapCommandHead(words);
|
|
@@ -1564,7 +1729,7 @@ function matchCanaryArgs(args, values) {
|
|
|
1564
1729
|
return null;
|
|
1565
1730
|
}
|
|
1566
1731
|
}
|
|
1567
|
-
var B58, B58_INDEX, XPRV_VERSIONS, ASSIGNMENT_CONTEXT_RE, DLP_STOPWORDS, DLP_PATTERNS, DLP_PATTERNS_GLOBAL, SENSITIVE_PATH_PATTERNS, MAX_DEPTH, MAX_STRING_BYTES, MAX_JSON_PARSE_BYTES, MAX_REGEX_LENGTH, REGEX_CACHE_MAX, regexCache, FORBIDDEN_PATH_SEGMENTS, syntax, sharedParser, MESSAGE_FLAGS, SHELL_INTERPRETERS, DOWNLOAD_CMDS, NORMALIZE_CACHE_MAX, normalizeCache, AST_CACHE_MAX, astCache, PARSE_FAIL, FS_READ_TOOLS, FS_OP_PRESCREEN_RE, HOME_CACHE_ALLOWLIST, SENSITIVE_PATH_RULES, BASH_TOOL_NAMES, AST_FS_REGEX_RULES, COMMAND_WRAPPERS, INLINE_INTERPRETER, RUNNER_WRAPPERS, WRAPPER_TAKES_TARGET, FIND_EXEC_FLAGS, FS_OP_CACHE_MAX, fsOpCache, REDIR_TRUNCATE_OPS, REDIR_FILE_IN_OPS, REDIR_HEREDOC_OPS, isReaderWord, positionalAfter, SOURCE_COMMANDS, SSRF_MAX_HOST, METADATA_ADDRESSES, METADATA_HOSTNAMES, v4Octets, aws_default, bash_safe_default, docker_default, filesystem_default, github_default, k8s_default, mongodb_default, postgres_default, project_jail_default, redis_default, BUILTIN_SHIELDS, CANARY_MIN_LENGTH, MAX_TEXT, MAX_DEPTH2, MAX_JSON_PARSE, URL_DEPTH, B64_DEPTH, MIN_SEGMENT, SEPARATORS, stripSeparators, looksText, CANARY_DECODERS, VIEWS, LONG_OUTPUT_THRESHOLD_BYTES;
|
|
1732
|
+
var B58, B58_INDEX, XPRV_VERSIONS, ASSIGNMENT_CONTEXT_RE, DLP_STOPWORDS, DLP_PATTERNS, DLP_PATTERNS_GLOBAL, SENSITIVE_PATH_PATTERNS, MAX_DEPTH, MAX_STRING_BYTES, MAX_JSON_PARSE_BYTES, MAX_REGEX_LENGTH, REGEX_CACHE_MAX, regexCache, FORBIDDEN_PATH_SEGMENTS, syntax, sharedParser, MESSAGE_FLAGS, SHELL_INTERPRETERS, DOWNLOAD_CMDS, NORMALIZE_CACHE_MAX, normalizeCache, AST_CACHE_MAX, astCache, PARSE_FAIL, FS_READ_TOOLS, SCP_VALUE_FLAGS, RSYNC_SKIP, COPY_VERBS, TAR_MODE_WORD, COPY_VERB_HEADS, FS_OP_PRESCREEN_RE, HOME_CACHE_ALLOWLIST, SENSITIVE_PATH_RULES, BASH_TOOL_NAMES, AST_FS_REGEX_RULES, COMMAND_WRAPPERS, INLINE_INTERPRETER, RUNNER_WRAPPERS, WRAPPER_TAKES_TARGET, FIND_EXEC_FLAGS, FS_OP_CACHE_MAX, fsOpCache, REDIR_TRUNCATE_OPS, REDIR_FILE_IN_OPS, REDIR_HEREDOC_OPS, FIND_OPTIONS, COPY_RULE_OF, isReaderWord, positionalAfter, SOURCE_COMMANDS, SSRF_MAX_HOST, METADATA_ADDRESSES, METADATA_HOSTNAMES, v4Octets, aws_default, bash_safe_default, docker_default, filesystem_default, github_default, k8s_default, mongodb_default, postgres_default, project_jail_default, redis_default, BUILTIN_SHIELDS, CANARY_MIN_LENGTH, MAX_TEXT, MAX_DEPTH2, MAX_JSON_PARSE, URL_DEPTH, B64_DEPTH, MIN_SEGMENT, SEPARATORS, stripSeparators, looksText, CANARY_DECODERS, VIEWS, LONG_OUTPUT_THRESHOLD_BYTES;
|
|
1568
1733
|
var init_dist = __esm({
|
|
1569
1734
|
"packages/policy-engine/dist/index.mjs"() {
|
|
1570
1735
|
"use strict";
|
|
@@ -2165,12 +2330,56 @@ var init_dist = __esm({
|
|
|
2165
2330
|
"nl",
|
|
2166
2331
|
"dd"
|
|
2167
2332
|
]);
|
|
2333
|
+
SCP_VALUE_FLAGS = ["i", "F", "o", "c", "S", "P", "J", "D", "W", "l"];
|
|
2334
|
+
RSYNC_SKIP = [
|
|
2335
|
+
"e",
|
|
2336
|
+
"--rsh",
|
|
2337
|
+
"--exclude",
|
|
2338
|
+
"--exclude-from",
|
|
2339
|
+
"--include",
|
|
2340
|
+
"--include-from",
|
|
2341
|
+
"--files-from",
|
|
2342
|
+
"f",
|
|
2343
|
+
"--filter"
|
|
2344
|
+
];
|
|
2345
|
+
COPY_VERBS = {
|
|
2346
|
+
cp: { source: "allButLast", targetDirFlag: true },
|
|
2347
|
+
mv: { source: "allButLast", targetDirFlag: true },
|
|
2348
|
+
install: { source: "allButLast", targetDirFlag: true },
|
|
2349
|
+
ln: { source: "first", targetDirFlag: true },
|
|
2350
|
+
scp: { source: "allButLast", skipFlags: SCP_VALUE_FLAGS },
|
|
2351
|
+
rsync: { source: "allButLast", skipFlags: RSYNC_SKIP },
|
|
2352
|
+
tar: {
|
|
2353
|
+
source: "archive",
|
|
2354
|
+
archive: "tar",
|
|
2355
|
+
skipFlags: ["f", "X", "T", "--file", "--exclude", "--exclude-from", "--files-from"]
|
|
2356
|
+
},
|
|
2357
|
+
zip: { source: "archive", archive: "zip", skipFlags: ["x", "i", "--exclude", "--include"] },
|
|
2358
|
+
ar: { source: "archive", archive: "ar" },
|
|
2359
|
+
"7z": { source: "archive", archive: "7z", skipFlags: ["x", "--exclude"] },
|
|
2360
|
+
gzip: { source: "all" },
|
|
2361
|
+
bzip2: { source: "all" },
|
|
2362
|
+
xz: { source: "all" },
|
|
2363
|
+
"docker cp": { source: "allButLast" },
|
|
2364
|
+
"kubectl cp": { source: "allButLast" },
|
|
2365
|
+
"gsutil cp": { source: "allButLast" },
|
|
2366
|
+
"gsutil rsync": { source: "allButLast" },
|
|
2367
|
+
"rclone copy": { source: "allButLast" },
|
|
2368
|
+
"rclone sync": { source: "allButLast" },
|
|
2369
|
+
"aws s3 cp": { source: "allButLast" },
|
|
2370
|
+
"aws s3 mv": { source: "allButLast" },
|
|
2371
|
+
"aws s3 sync": { source: "allButLast" },
|
|
2372
|
+
"gcloud storage cp": { source: "allButLast" },
|
|
2373
|
+
"az storage blob upload": { source: "flagOperand", sourceFlags: ["f", "--file"] }
|
|
2374
|
+
};
|
|
2375
|
+
TAR_MODE_WORD = /^[a-zA-Z]+$/;
|
|
2376
|
+
COPY_VERB_HEADS = new Set(Object.keys(COPY_VERBS).map((k) => k.split(" ")[0]));
|
|
2168
2377
|
FS_OP_PRESCREEN_RE = new RegExp(
|
|
2169
2378
|
// A quote is a separator too: `eval "cat X"` and `sh -c 'cat X'` put the
|
|
2170
2379
|
// reader right after `"` / `'`, and without these two characters the
|
|
2171
2380
|
// prescreen rejected every string-wrapped read before the parser ran.
|
|
2172
2381
|
// Found 2026-09-11 by instrumenting the walk -- no CallExpr was ever visited.
|
|
2173
|
-
`(?:^|[\\s|;&("'\`\\n])(?:rm|${[...FS_READ_TOOLS].map((t) => t.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|")})\\b|(?<!<)<(?!<)`
|
|
2382
|
+
`(?:^|[\\s|;&("'\`\\n/])(?:rm|${[...FS_READ_TOOLS, ...COPY_VERB_HEADS].map((t) => t.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|")})\\b|(?<!<)<(?!<)`
|
|
2174
2383
|
);
|
|
2175
2384
|
HOME_CACHE_ALLOWLIST = [
|
|
2176
2385
|
".cache",
|
|
@@ -2349,8 +2558,15 @@ var init_dist = __esm({
|
|
|
2349
2558
|
deriveRedirOp("cat <<X\nX"),
|
|
2350
2559
|
deriveRedirOp("cat <<-X\nX")
|
|
2351
2560
|
]);
|
|
2352
|
-
|
|
2353
|
-
|
|
2561
|
+
FIND_OPTIONS = /* @__PURE__ */ new Set(["-H", "-L", "-P"]);
|
|
2562
|
+
COPY_RULE_OF = {
|
|
2563
|
+
"shield:project-jail:block-read-ssh": "shield:project-jail:review-copy-ssh",
|
|
2564
|
+
"shield:project-jail:block-read-aws": "shield:project-jail:review-copy-aws",
|
|
2565
|
+
"shield:project-jail:block-read-env": "shield:project-jail:review-copy-env",
|
|
2566
|
+
"shield:project-jail:review-read-credentials": "shield:project-jail:review-copy-credentials"
|
|
2567
|
+
};
|
|
2568
|
+
isReaderWord = (w) => w !== null && FS_READ_TOOLS.has(baseWord(w));
|
|
2569
|
+
positionalAfter = (words, from, to = words.length) => positionedArgs(words, from, to).map((a) => a.value);
|
|
2354
2570
|
SOURCE_COMMANDS = /* @__PURE__ */ new Set([...FS_READ_TOOLS, "tee"]);
|
|
2355
2571
|
SSRF_MAX_HOST = 253;
|
|
2356
2572
|
METADATA_ADDRESSES = /* @__PURE__ */ new Set([
|
|
@@ -7278,10 +7494,16 @@ function buildRuleToShieldMap() {
|
|
|
7278
7494
|
}
|
|
7279
7495
|
return map;
|
|
7280
7496
|
}
|
|
7497
|
+
function shieldOfRule(map, rule) {
|
|
7498
|
+
const exact = map.get(rule);
|
|
7499
|
+
if (exact) return exact;
|
|
7500
|
+
const m = /^shield:([^:]+):/.exec(rule);
|
|
7501
|
+
return m && SHIELDS[m[1]] ? m[1] : void 0;
|
|
7502
|
+
}
|
|
7281
7503
|
function applyActivityToShields(agg, e, ruleToShield) {
|
|
7282
7504
|
if (e.kind !== "tool" || !e.checkedBy) return agg;
|
|
7283
7505
|
if (e.verdict !== "block" && e.verdict !== "review") return agg;
|
|
7284
|
-
const shieldName = ruleToShield
|
|
7506
|
+
const shieldName = shieldOfRule(ruleToShield, e.checkedBy);
|
|
7285
7507
|
if (!shieldName) return agg;
|
|
7286
7508
|
const current = agg.byShield[shieldName] ?? { blocks: 0, reviews: 0 };
|
|
7287
7509
|
const updated = {
|
|
@@ -8277,7 +8499,7 @@ function PeriodShields({
|
|
|
8277
8499
|
const byShield = /* @__PURE__ */ new Map();
|
|
8278
8500
|
if (data) {
|
|
8279
8501
|
for (const [rule, count] of data.ruleMap) {
|
|
8280
|
-
const shield = ruleToShield
|
|
8502
|
+
const shield = shieldOfRule(ruleToShield, rule);
|
|
8281
8503
|
if (!shield) continue;
|
|
8282
8504
|
byShield.set(shield, (byShield.get(shield) ?? 0) + count);
|
|
8283
8505
|
}
|