@node9/proxy 2.14.0 → 2.14.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +685 -92
- package/dist/cli.mjs +685 -92
- package/dist/dashboard.mjs +613 -42
- package/dist/index.js +611 -42
- package/dist/index.mjs +611 -42
- package/dist/scan-ink.mjs +337 -9
- package/package.json +1 -1
package/dist/dashboard.mjs
CHANGED
|
@@ -848,6 +848,19 @@ function parseShared(command) {
|
|
|
848
848
|
astCache.set(command, parsed);
|
|
849
849
|
return parsed;
|
|
850
850
|
}
|
|
851
|
+
function byteOffsetToCharIndex(command) {
|
|
852
|
+
if (!/[^\u0000-\u007F]/.test(command)) return null;
|
|
853
|
+
const map = /* @__PURE__ */ new Map();
|
|
854
|
+
let byte = 0;
|
|
855
|
+
for (let i = 0; i < command.length; ) {
|
|
856
|
+
map.set(byte, i);
|
|
857
|
+
const cp = command.codePointAt(i);
|
|
858
|
+
byte += cp < 128 ? 1 : cp < 2048 ? 2 : cp < 65536 ? 3 : 4;
|
|
859
|
+
i += cp > 65535 ? 2 : 1;
|
|
860
|
+
}
|
|
861
|
+
map.set(byte, command.length);
|
|
862
|
+
return (b) => map.get(b) ?? -1;
|
|
863
|
+
}
|
|
851
864
|
function cachedNormalize(command, compute) {
|
|
852
865
|
const hit = normalizeCache.get(command);
|
|
853
866
|
if (hit !== void 0) {
|
|
@@ -877,6 +890,8 @@ function normalizeCommandForPolicyImpl(command) {
|
|
|
877
890
|
const f = parseShared(command);
|
|
878
891
|
if (f === PARSE_FAIL) return { posix: command, separator: command };
|
|
879
892
|
try {
|
|
893
|
+
const toCharIndex = byteOffsetToCharIndex(command);
|
|
894
|
+
const at = (byteOffset) => toCharIndex === null ? byteOffset : toCharIndex(byteOffset);
|
|
880
895
|
const strips = [];
|
|
881
896
|
const rewrites = [];
|
|
882
897
|
const quoteOnlyRewrites = [];
|
|
@@ -897,8 +912,9 @@ function normalizeCommandForPolicyImpl(command) {
|
|
|
897
912
|
const quotedNode = nextParts[0];
|
|
898
913
|
const nt = syntax.NodeType(quotedNode);
|
|
899
914
|
const markStrip = () => {
|
|
900
|
-
const s = next.Pos().Offset();
|
|
901
|
-
const e = next.End().Offset();
|
|
915
|
+
const s = at(next.Pos().Offset());
|
|
916
|
+
const e = at(next.End().Offset());
|
|
917
|
+
if (s < 0 || e < 0) return;
|
|
902
918
|
strips.push([s, e]);
|
|
903
919
|
msgSpans.add(`${s}:${e}`);
|
|
904
920
|
};
|
|
@@ -915,8 +931,9 @@ function normalizeCommandForPolicyImpl(command) {
|
|
|
915
931
|
}
|
|
916
932
|
}
|
|
917
933
|
for (const arg of args) {
|
|
918
|
-
const s = arg.Pos().Offset();
|
|
919
|
-
const e = arg.End().Offset();
|
|
934
|
+
const s = at(arg.Pos().Offset());
|
|
935
|
+
const e = at(arg.End().Offset());
|
|
936
|
+
if (s < 0 || e < 0) continue;
|
|
920
937
|
if (msgSpans.has(`${s}:${e}`)) continue;
|
|
921
938
|
const resolved = resolveWordLiteral(arg);
|
|
922
939
|
if (resolved === null) continue;
|
|
@@ -1178,7 +1195,7 @@ function analyzeFsOperationImpl(command, depth = 0) {
|
|
|
1178
1195
|
return result?.verdict !== "block";
|
|
1179
1196
|
}
|
|
1180
1197
|
if (nodeType !== "CallExpr") return true;
|
|
1181
|
-
const { name, flags, paths, words } = extractLiteralArgs(n);
|
|
1198
|
+
const { name, flags, paths, words, args } = extractLiteralArgs(n);
|
|
1182
1199
|
if (!name) return true;
|
|
1183
1200
|
if (name === "rm") {
|
|
1184
1201
|
const flagStr = flags.join("").toLowerCase();
|
|
@@ -1218,7 +1235,7 @@ function analyzeFsOperationImpl(command, depth = 0) {
|
|
|
1218
1235
|
return true;
|
|
1219
1236
|
}
|
|
1220
1237
|
}
|
|
1221
|
-
const readPaths = FS_READ_TOOLS.has(name) ?
|
|
1238
|
+
const readPaths = FS_READ_TOOLS.has(name) ? [...readTargets(name, args, flags, words, 1), ...flagOperandFiles(name, words, 1)] : wrappedReadPaths(words, name);
|
|
1222
1239
|
if (readPaths) {
|
|
1223
1240
|
for (const p of readPaths) {
|
|
1224
1241
|
result = stricter(result, matchSensitivePath2(p));
|
|
@@ -1254,9 +1271,22 @@ function flagIs(w, names) {
|
|
|
1254
1271
|
const f = flagInfo(w);
|
|
1255
1272
|
return names.some((n) => n.startsWith("--") ? f.long === n : f.letter === n);
|
|
1256
1273
|
}
|
|
1257
|
-
function operandOf(a, names) {
|
|
1274
|
+
function operandOf(a, names, valueLetters) {
|
|
1258
1275
|
if (!names || a.afterFlag === null) return false;
|
|
1259
|
-
|
|
1276
|
+
const w = a.afterFlag;
|
|
1277
|
+
if (!w.startsWith("--") && valueLetters) {
|
|
1278
|
+
const letters = w.slice(1);
|
|
1279
|
+
for (let i = 0; i < letters.length; i++) {
|
|
1280
|
+
if (!valueLetters.includes(letters[i])) continue;
|
|
1281
|
+
return i === letters.length - 1 && names.includes(letters[i]);
|
|
1282
|
+
}
|
|
1283
|
+
return false;
|
|
1284
|
+
}
|
|
1285
|
+
if (w.startsWith("--") && !w.includes("=")) {
|
|
1286
|
+
const longs = names.filter((n) => n.startsWith("--"));
|
|
1287
|
+
if (longs.some((n) => n === w || w.length >= 3 && n.startsWith(w))) return true;
|
|
1288
|
+
}
|
|
1289
|
+
return flagIs(w, names) && flagInfo(w).attached === null;
|
|
1260
1290
|
}
|
|
1261
1291
|
function resolveCopyShape(words, h) {
|
|
1262
1292
|
const verb = baseWord(words[h]);
|
|
@@ -1280,7 +1310,7 @@ function findStartPoints(words, h) {
|
|
|
1280
1310
|
const k = words.findIndex((w, i) => i > h && w !== null && FIND_EXEC_FLAGS.has(w));
|
|
1281
1311
|
if (k < 0) return { k, starts: [] };
|
|
1282
1312
|
const firstPredicate = words.findIndex(
|
|
1283
|
-
(w, i) => i > h && w !== null && w.startsWith("-") && !FIND_OPTIONS.has(w)
|
|
1313
|
+
(w, i) => i > h && w !== null && w !== "--" && w.startsWith("-") && !FIND_OPTIONS.has(w)
|
|
1284
1314
|
);
|
|
1285
1315
|
const end = firstPredicate > h ? firstPredicate : k;
|
|
1286
1316
|
return { k, starts: positionalAfter(words, h + 1, end) };
|
|
@@ -1300,14 +1330,35 @@ function copySourcePaths(words) {
|
|
|
1300
1330
|
const { shape, last } = r;
|
|
1301
1331
|
const args = positionedArgs(words, last + 1);
|
|
1302
1332
|
const tail = words.slice(last + 1);
|
|
1303
|
-
const
|
|
1304
|
-
const
|
|
1305
|
-
const
|
|
1333
|
+
const copyOptionsEnd = tail.findIndex((w) => w === "--");
|
|
1334
|
+
const copyPastOptions = (a) => copyOptionsEnd >= 0 && a.argv > last + 1 + copyOptionsEnd;
|
|
1335
|
+
const skipped = (a) => !copyPastOptions(a) && operandOf(a, shape.skipFlags, shape.valueLetters);
|
|
1336
|
+
const firstValueLetter = (w) => {
|
|
1337
|
+
const letters = w.slice(1);
|
|
1338
|
+
for (let i = 0; i < letters.length; i++) {
|
|
1339
|
+
if ((shape.valueLetters ?? []).includes(letters[i]))
|
|
1340
|
+
return { letter: letters[i], last: i === letters.length - 1 };
|
|
1341
|
+
}
|
|
1342
|
+
return null;
|
|
1343
|
+
};
|
|
1344
|
+
const isTargetDirFlag = (w) => {
|
|
1345
|
+
if (w.startsWith("--")) {
|
|
1346
|
+
const name = w.includes("=") ? w.slice(0, w.indexOf("=")) : w;
|
|
1347
|
+
return name.length >= 3 && "--target-directory".startsWith(name);
|
|
1348
|
+
}
|
|
1349
|
+
return firstValueLetter(w)?.letter === "t";
|
|
1350
|
+
};
|
|
1351
|
+
const targetDir = shape.targetDirFlag === true && tail.some((w) => w !== null && w.startsWith("-") && isTargetDirFlag(w));
|
|
1352
|
+
const targetTakesNextWord = (w) => {
|
|
1353
|
+
if (w.startsWith("--"))
|
|
1354
|
+
return !w.includes("=") && w.length >= 3 && "--target-directory".startsWith(w);
|
|
1355
|
+
const f = firstValueLetter(w);
|
|
1356
|
+
return f !== null && f.letter === "t" && f.last;
|
|
1357
|
+
};
|
|
1358
|
+
const targetOperand = (a) => targetDir && a.afterFlag !== null && !copyPastOptions(a) && targetTakesNextWord(a.afterFlag);
|
|
1306
1359
|
const lastOperand = [...tail].reverse().find((w) => w === null || !w.startsWith("-"));
|
|
1307
1360
|
const dynamicDest = lastOperand === null;
|
|
1308
1361
|
const destIsLastOperand = (shape.source === "allButLast" || shape.source === "first") && !targetDir && !dynamicDest;
|
|
1309
|
-
if (destIsLastOperand && typeof lastOperand === "string" && matchSensitivePath2(lastOperand))
|
|
1310
|
-
return [];
|
|
1311
1362
|
let src;
|
|
1312
1363
|
switch (shape.source) {
|
|
1313
1364
|
case "all":
|
|
@@ -1317,11 +1368,17 @@ function copySourcePaths(words) {
|
|
|
1317
1368
|
src = targetDir ? args : args.slice(0, 1);
|
|
1318
1369
|
break;
|
|
1319
1370
|
case "flagOperand": {
|
|
1320
|
-
const
|
|
1371
|
+
const namesSource = (f) => {
|
|
1372
|
+
const names = shape.sourceFlags ?? [];
|
|
1373
|
+
if (f.long !== null)
|
|
1374
|
+
return names.some(
|
|
1375
|
+
(n) => n.startsWith("--") && (n === f.long || f.long.length >= 3 && n.startsWith(f.long))
|
|
1376
|
+
);
|
|
1377
|
+
return f.letter !== null && names.includes(f.letter);
|
|
1378
|
+
};
|
|
1379
|
+
const inline = tail.filter((w) => w !== null && w.startsWith("-")).map((w) => flagInfo(w)).filter((f) => f.attached !== null && namesSource(f)).map((f) => f.attached);
|
|
1321
1380
|
return [
|
|
1322
|
-
...args.filter(
|
|
1323
|
-
(a) => flagIs(a.afterFlag, shape.sourceFlags ?? []) && flagInfo(a.afterFlag).attached === null
|
|
1324
|
-
).map((a) => a.value),
|
|
1381
|
+
...args.filter((a) => !copyPastOptions(a) && operandOf(a, shape.sourceFlags, shape.valueLetters)).map((a) => a.value),
|
|
1325
1382
|
...inline
|
|
1326
1383
|
];
|
|
1327
1384
|
}
|
|
@@ -1332,7 +1389,14 @@ function copySourcePaths(words) {
|
|
|
1332
1389
|
src = targetDir || dynamicDest ? args : args.slice(0, -1);
|
|
1333
1390
|
break;
|
|
1334
1391
|
}
|
|
1335
|
-
|
|
1392
|
+
const sources = src.filter((a) => !skipped(a) && !targetOperand(a)).map((a) => a.value);
|
|
1393
|
+
if (destIsLastOperand && typeof lastOperand === "string" && matchSensitivePath2(lastOperand)) {
|
|
1394
|
+
const jailedSources = sources.filter((p) => matchSensitivePath2(p));
|
|
1395
|
+
const dirOf = (p) => /[\\/]/.test(p) ? p.replace(/[\\/][^\\/]*$/, "") : "";
|
|
1396
|
+
if (jailedSources.length === 0) return [];
|
|
1397
|
+
if (jailedSources.every((p) => dirOf(p) === dirOf(lastOperand))) return [];
|
|
1398
|
+
}
|
|
1399
|
+
return sources;
|
|
1336
1400
|
}
|
|
1337
1401
|
function archiveInputs(kind, args, tail) {
|
|
1338
1402
|
const first = args[0];
|
|
@@ -1344,13 +1408,17 @@ function archiveInputs(kind, args, tail) {
|
|
|
1344
1408
|
const writing = /[cruA]/.test(bareKey ? first.value : "") || /(^|\s)-[a-zA-Z]*[cruA]|--create|--append|--update|--concatenate/.test(flagsText);
|
|
1345
1409
|
if (extracting && !writing) return [];
|
|
1346
1410
|
void mode;
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
if (
|
|
1352
|
-
|
|
1353
|
-
|
|
1411
|
+
if (!bareKey) return args;
|
|
1412
|
+
let i = 1;
|
|
1413
|
+
const fromDirs = [];
|
|
1414
|
+
for (const ch of first.value) {
|
|
1415
|
+
if (!TAR_VALUE_LETTERS.includes(ch)) continue;
|
|
1416
|
+
const operand = args[i];
|
|
1417
|
+
if (!operand || operand.afterFlag !== null) break;
|
|
1418
|
+
i += 1;
|
|
1419
|
+
if (ch === "C") fromDirs.push(operand);
|
|
1420
|
+
}
|
|
1421
|
+
return [...fromDirs, ...args.slice(i)];
|
|
1354
1422
|
}
|
|
1355
1423
|
if (kind === "zip") return first && first.afterFlag === "-" ? args : args.slice(1);
|
|
1356
1424
|
if (kind === "ar") return bareKey ? args.slice(2) : args.slice(1);
|
|
@@ -1377,6 +1445,138 @@ function matchSensitivePath2(p) {
|
|
|
1377
1445
|
function baseWord(w) {
|
|
1378
1446
|
return (w ?? "").split("/").pop()?.toLowerCase() ?? "";
|
|
1379
1447
|
}
|
|
1448
|
+
function namesFlag(name, candidates, known) {
|
|
1449
|
+
if (candidates.has(name)) return true;
|
|
1450
|
+
if (!name.startsWith("--") || name.length < 3) return false;
|
|
1451
|
+
if (known?.has(name)) return false;
|
|
1452
|
+
for (const c of candidates) if (c.startsWith(name)) return true;
|
|
1453
|
+
return false;
|
|
1454
|
+
}
|
|
1455
|
+
function knownLongFlags(verb) {
|
|
1456
|
+
const out = /* @__PURE__ */ new Set();
|
|
1457
|
+
const shape = PATTERN_VERBS[verb];
|
|
1458
|
+
if (shape) {
|
|
1459
|
+
for (const set of [shape.takesValue, shape.noValue, shape.patternFlags, shape.noPatternFlags])
|
|
1460
|
+
for (const f of set) if (f.startsWith("--")) out.add(f);
|
|
1461
|
+
}
|
|
1462
|
+
for (const f of FILE_OPERAND_FLAGS[verb] ?? []) if (f.startsWith("--")) out.add(f);
|
|
1463
|
+
return out;
|
|
1464
|
+
}
|
|
1465
|
+
function flagNamesOf(token, shape) {
|
|
1466
|
+
if (token.startsWith("--")) {
|
|
1467
|
+
const eq = token.indexOf("=");
|
|
1468
|
+
return [eq > 0 ? token.slice(0, eq) : token];
|
|
1469
|
+
}
|
|
1470
|
+
const out = [];
|
|
1471
|
+
for (const c of token.slice(1)) {
|
|
1472
|
+
const name = `-${c}`;
|
|
1473
|
+
out.push(name);
|
|
1474
|
+
if (shape?.takesValue.has(name)) break;
|
|
1475
|
+
}
|
|
1476
|
+
return out;
|
|
1477
|
+
}
|
|
1478
|
+
function flagEffect(token, shape, known) {
|
|
1479
|
+
if (token === "--") return NONE;
|
|
1480
|
+
if (/^-+$/.test(token)) return UNKNOWN;
|
|
1481
|
+
if (/^-\d+$/.test(token)) return NONE;
|
|
1482
|
+
if (token.startsWith("--")) {
|
|
1483
|
+
if (token.includes("=")) return NONE;
|
|
1484
|
+
const takes = namesFlag(token, shape.takesValue, known);
|
|
1485
|
+
const none = namesFlag(token, shape.noValue, known);
|
|
1486
|
+
if (takes && none) return UNKNOWN;
|
|
1487
|
+
if (takes) return { kind: "takes", flag: token };
|
|
1488
|
+
if (none) return NONE;
|
|
1489
|
+
return UNKNOWN;
|
|
1490
|
+
}
|
|
1491
|
+
const letters = token.slice(1);
|
|
1492
|
+
if (!letters) return NONE;
|
|
1493
|
+
for (let i = 0; i < letters.length; i++) {
|
|
1494
|
+
const name = `-${letters[i]}`;
|
|
1495
|
+
if (shape.takesValue.has(name)) {
|
|
1496
|
+
return i === letters.length - 1 ? { kind: "takes", flag: name } : NONE;
|
|
1497
|
+
}
|
|
1498
|
+
if (!shape.noValue.has(name)) return UNKNOWN;
|
|
1499
|
+
}
|
|
1500
|
+
return NONE;
|
|
1501
|
+
}
|
|
1502
|
+
function readTargets(verb, args, flags, words = [], from = 1) {
|
|
1503
|
+
const shape = PATTERN_VERBS[verb];
|
|
1504
|
+
if (!shape) return args.map((a) => a.value);
|
|
1505
|
+
const known = knownLongFlags(verb);
|
|
1506
|
+
const names = flags.flatMap((f) => flagNamesOf(f, shape));
|
|
1507
|
+
const patternElsewhere = names.some(
|
|
1508
|
+
(n) => namesFlag(n, shape.patternFlags, known) || namesFlag(n, shape.noPatternFlags, known)
|
|
1509
|
+
);
|
|
1510
|
+
const excused = /* @__PURE__ */ new Set();
|
|
1511
|
+
const fileFlags = FILE_OPERAND_FLAGS[verb];
|
|
1512
|
+
const optionsEnd = words.findIndex((w, i) => i >= from && w === "--");
|
|
1513
|
+
const pastOptions = (a) => optionsEnd >= 0 && a.argv > optionsEnd;
|
|
1514
|
+
for (const a of args) {
|
|
1515
|
+
if (a.afterFlag === null || pastOptions(a)) continue;
|
|
1516
|
+
const e = flagEffect(a.afterFlag, shape, known);
|
|
1517
|
+
if (e.kind !== "takes") continue;
|
|
1518
|
+
if (fileFlags && namesFlag(e.flag, fileFlags, known)) continue;
|
|
1519
|
+
excused.add(a);
|
|
1520
|
+
}
|
|
1521
|
+
const patternArgv = (() => {
|
|
1522
|
+
for (let i = from; i < words.length; i++) {
|
|
1523
|
+
const w = words[i];
|
|
1524
|
+
if (w === null) return -1;
|
|
1525
|
+
if (w === "--") return i + 1;
|
|
1526
|
+
if (w.startsWith("-")) {
|
|
1527
|
+
const e = flagEffect(w, shape, known);
|
|
1528
|
+
if (e.kind === "takes") i += 1;
|
|
1529
|
+
else if (e.kind === "unknown") return -1;
|
|
1530
|
+
continue;
|
|
1531
|
+
}
|
|
1532
|
+
return i;
|
|
1533
|
+
}
|
|
1534
|
+
return -1;
|
|
1535
|
+
})();
|
|
1536
|
+
if (!patternElsewhere && patternArgv >= 0) {
|
|
1537
|
+
const a = args.find((x) => x.argv === patternArgv);
|
|
1538
|
+
if (a) excused.add(a);
|
|
1539
|
+
}
|
|
1540
|
+
return args.filter((a) => !excused.has(a)).map((a) => a.value);
|
|
1541
|
+
}
|
|
1542
|
+
function flagOperandFiles(verb, words, from) {
|
|
1543
|
+
const flags = FILE_OPERAND_FLAGS[verb];
|
|
1544
|
+
if (!flags) return [];
|
|
1545
|
+
const known = knownLongFlags(verb);
|
|
1546
|
+
const out = [];
|
|
1547
|
+
for (let i = from; i < words.length; i++) {
|
|
1548
|
+
const w = words[i];
|
|
1549
|
+
if (w === null || !w.startsWith("-") || w === "--") continue;
|
|
1550
|
+
if (w.startsWith("--")) {
|
|
1551
|
+
const eq = w.indexOf("=");
|
|
1552
|
+
if (eq <= 0) continue;
|
|
1553
|
+
const name = w.slice(0, eq);
|
|
1554
|
+
const value = w.slice(eq + 1);
|
|
1555
|
+
if (!value) continue;
|
|
1556
|
+
if (namesFlag(name, flags, known)) {
|
|
1557
|
+
out.push(value);
|
|
1558
|
+
continue;
|
|
1559
|
+
}
|
|
1560
|
+
const shape2 = PATTERN_VERBS[verb];
|
|
1561
|
+
if (!shape2) continue;
|
|
1562
|
+
const recognised = namesFlag(name, shape2.takesValue, known) || namesFlag(name, shape2.noValue, known) || namesFlag(name, shape2.patternFlags, known) || namesFlag(name, shape2.noPatternFlags, known);
|
|
1563
|
+
if (!recognised) out.push(value);
|
|
1564
|
+
continue;
|
|
1565
|
+
}
|
|
1566
|
+
const shape = PATTERN_VERBS[verb];
|
|
1567
|
+
const letters = w.slice(1);
|
|
1568
|
+
for (let j = 0; j < letters.length; j++) {
|
|
1569
|
+
const name = `-${letters[j]}`;
|
|
1570
|
+
const isFileFlag = flags.has(name);
|
|
1571
|
+
const argTaking = isFileFlag || (shape?.takesValue.has(name) ?? false) || (READER_VALUE_LETTERS[verb] ?? []).includes(letters[j]);
|
|
1572
|
+
if (!argTaking) continue;
|
|
1573
|
+
const attached = letters.slice(j + 1);
|
|
1574
|
+
if (isFileFlag && attached) out.push(attached);
|
|
1575
|
+
break;
|
|
1576
|
+
}
|
|
1577
|
+
}
|
|
1578
|
+
return out;
|
|
1579
|
+
}
|
|
1380
1580
|
function wrappedReadPaths(words, name) {
|
|
1381
1581
|
if (name === "find") {
|
|
1382
1582
|
const { k, starts } = findStartPoints(words, 0);
|
|
@@ -1384,7 +1584,14 @@ function wrappedReadPaths(words, name) {
|
|
|
1384
1584
|
}
|
|
1385
1585
|
if (!COMMAND_WRAPPERS.has(name) && !RUNNER_WRAPPERS.has(name)) return null;
|
|
1386
1586
|
const h = unwrapCommandHead(words);
|
|
1387
|
-
|
|
1587
|
+
if (h <= 0 || !isReaderWord(words[h] ?? null)) return null;
|
|
1588
|
+
const head = baseWord(words[h]);
|
|
1589
|
+
const rest = words.slice(h + 1);
|
|
1590
|
+
const restFlags = rest.filter((w) => w !== null && w.startsWith("-"));
|
|
1591
|
+
return [
|
|
1592
|
+
...readTargets(head, positionedArgs(words, h + 1), restFlags, words, h + 1),
|
|
1593
|
+
...flagOperandFiles(head, words, h + 1)
|
|
1594
|
+
];
|
|
1388
1595
|
}
|
|
1389
1596
|
function literalShellPayload(words, name) {
|
|
1390
1597
|
const h = COMMAND_WRAPPERS.has(name) || RUNNER_WRAPPERS.has(name) ? unwrapCommandHead(words) : 0;
|
|
@@ -1568,6 +1775,9 @@ function classifySsrf(host) {
|
|
|
1568
1775
|
return null;
|
|
1569
1776
|
}
|
|
1570
1777
|
}
|
|
1778
|
+
function stripTerminalEscapes(s) {
|
|
1779
|
+
return s.replace(TERMINAL_ESCAPE_RE, "");
|
|
1780
|
+
}
|
|
1571
1781
|
function isShieldVerdict(v) {
|
|
1572
1782
|
return v === "allow" || v === "review" || v === "block";
|
|
1573
1783
|
}
|
|
@@ -1729,7 +1939,7 @@ function matchCanaryArgs(args, values) {
|
|
|
1729
1939
|
return null;
|
|
1730
1940
|
}
|
|
1731
1941
|
}
|
|
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;
|
|
1942
|
+
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, GREP_SHAPE, PATTERN_VERBS, PATTERN_VERB_NAMES, GREP_FILE_OPERANDS, READER_VALUE_LETTERS, FILE_OPERAND_FLAGS, SCP_VALUE_FLAGS, 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, 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, NONE, UNKNOWN, SOURCE_COMMANDS, SSRF_MAX_HOST, METADATA_ADDRESSES, METADATA_HOSTNAMES, v4Octets, TERMINAL_ESCAPE_RE, 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;
|
|
1733
1943
|
var init_dist = __esm({
|
|
1734
1944
|
"packages/policy-engine/dist/index.mjs"() {
|
|
1735
1945
|
"use strict";
|
|
@@ -2330,7 +2540,345 @@ var init_dist = __esm({
|
|
|
2330
2540
|
"nl",
|
|
2331
2541
|
"dd"
|
|
2332
2542
|
]);
|
|
2543
|
+
GREP_SHAPE = {
|
|
2544
|
+
takesValue: /* @__PURE__ */ new Set([
|
|
2545
|
+
"-A",
|
|
2546
|
+
"-B",
|
|
2547
|
+
"-C",
|
|
2548
|
+
"-D",
|
|
2549
|
+
"-d",
|
|
2550
|
+
"-e",
|
|
2551
|
+
"-f",
|
|
2552
|
+
"-m",
|
|
2553
|
+
"--after-context",
|
|
2554
|
+
"--before-context",
|
|
2555
|
+
"--binary-files",
|
|
2556
|
+
"--context",
|
|
2557
|
+
"--devices",
|
|
2558
|
+
"--directories",
|
|
2559
|
+
"--exclude",
|
|
2560
|
+
"--exclude-dir",
|
|
2561
|
+
"--exclude-from",
|
|
2562
|
+
"--file",
|
|
2563
|
+
"--include",
|
|
2564
|
+
"--label",
|
|
2565
|
+
"--max-count",
|
|
2566
|
+
"--regexp"
|
|
2567
|
+
]),
|
|
2568
|
+
noValue: /* @__PURE__ */ new Set([
|
|
2569
|
+
"-E",
|
|
2570
|
+
"-F",
|
|
2571
|
+
"-G",
|
|
2572
|
+
"-P",
|
|
2573
|
+
"-i",
|
|
2574
|
+
"-y",
|
|
2575
|
+
"-v",
|
|
2576
|
+
"-V",
|
|
2577
|
+
"-w",
|
|
2578
|
+
"-x",
|
|
2579
|
+
"-c",
|
|
2580
|
+
"-l",
|
|
2581
|
+
"-L",
|
|
2582
|
+
"-o",
|
|
2583
|
+
"-q",
|
|
2584
|
+
"-s",
|
|
2585
|
+
"-b",
|
|
2586
|
+
"-H",
|
|
2587
|
+
"-h",
|
|
2588
|
+
"-n",
|
|
2589
|
+
"-T",
|
|
2590
|
+
"-Z",
|
|
2591
|
+
"-z",
|
|
2592
|
+
"-R",
|
|
2593
|
+
"-r",
|
|
2594
|
+
"-U",
|
|
2595
|
+
"-u",
|
|
2596
|
+
"-I",
|
|
2597
|
+
"-a",
|
|
2598
|
+
"--basic-regexp",
|
|
2599
|
+
"--binary",
|
|
2600
|
+
"--byte-offset",
|
|
2601
|
+
"--color",
|
|
2602
|
+
"--colour",
|
|
2603
|
+
"--count",
|
|
2604
|
+
"--dereference-recursive",
|
|
2605
|
+
"--extended-regexp",
|
|
2606
|
+
"--files-with-matches",
|
|
2607
|
+
"--files-without-match",
|
|
2608
|
+
"--fixed-strings",
|
|
2609
|
+
"--help",
|
|
2610
|
+
"--ignore-case",
|
|
2611
|
+
"--initial-tab",
|
|
2612
|
+
"--invert-match",
|
|
2613
|
+
"--line-buffered",
|
|
2614
|
+
"--line-number",
|
|
2615
|
+
"--line-regexp",
|
|
2616
|
+
"--no-filename",
|
|
2617
|
+
"--no-group-separator",
|
|
2618
|
+
"--no-ignore-case",
|
|
2619
|
+
"--no-messages",
|
|
2620
|
+
"--null",
|
|
2621
|
+
"--null-data",
|
|
2622
|
+
"--only-matching",
|
|
2623
|
+
"--perl-regexp",
|
|
2624
|
+
"--quiet",
|
|
2625
|
+
"--recursive",
|
|
2626
|
+
"--silent",
|
|
2627
|
+
"--text",
|
|
2628
|
+
"--version",
|
|
2629
|
+
"--with-filename",
|
|
2630
|
+
"--word-regexp"
|
|
2631
|
+
]),
|
|
2632
|
+
patternFlags: /* @__PURE__ */ new Set(["-e", "--regexp"]),
|
|
2633
|
+
noPatternFlags: /* @__PURE__ */ new Set(["-f", "--file"])
|
|
2634
|
+
};
|
|
2635
|
+
PATTERN_VERBS = {
|
|
2636
|
+
grep: GREP_SHAPE,
|
|
2637
|
+
// /usr/bin/egrep and /usr/bin/fgrep are 41-byte shell wrappers that exec
|
|
2638
|
+
// `grep -E` and `grep -F`. Read in full, not assumed.
|
|
2639
|
+
egrep: GREP_SHAPE,
|
|
2640
|
+
fgrep: GREP_SHAPE,
|
|
2641
|
+
// ripgrep 14.1.1, complete from its own --help. An earlier comment here said rg
|
|
2642
|
+
// was not installed on the measuring machine; it is, and that stale claim is why
|
|
2643
|
+
// this table shipped incomplete for two rounds, blocking ordinary searches like
|
|
2644
|
+
// `rg --sort-files .env src` (/code-review round 4).
|
|
2645
|
+
rg: {
|
|
2646
|
+
takesValue: /* @__PURE__ */ new Set([
|
|
2647
|
+
"-A",
|
|
2648
|
+
"-B",
|
|
2649
|
+
"-C",
|
|
2650
|
+
"-d",
|
|
2651
|
+
"-E",
|
|
2652
|
+
"-e",
|
|
2653
|
+
"-f",
|
|
2654
|
+
"-g",
|
|
2655
|
+
"-j",
|
|
2656
|
+
"-M",
|
|
2657
|
+
"-m",
|
|
2658
|
+
"-r",
|
|
2659
|
+
"-t",
|
|
2660
|
+
"-T",
|
|
2661
|
+
"--after-context",
|
|
2662
|
+
"--before-context",
|
|
2663
|
+
"--color",
|
|
2664
|
+
"--colors",
|
|
2665
|
+
"--context",
|
|
2666
|
+
"--context-separator",
|
|
2667
|
+
"--dfa-size-limit",
|
|
2668
|
+
"--encoding",
|
|
2669
|
+
"--engine",
|
|
2670
|
+
"--field-context-separator",
|
|
2671
|
+
"--field-match-separator",
|
|
2672
|
+
"--file",
|
|
2673
|
+
"--generate",
|
|
2674
|
+
"--glob",
|
|
2675
|
+
"--hostname-bin",
|
|
2676
|
+
"--hyperlink-format",
|
|
2677
|
+
"--iglob",
|
|
2678
|
+
"--ignore-file",
|
|
2679
|
+
"--max-columns",
|
|
2680
|
+
"--max-count",
|
|
2681
|
+
"--max-depth",
|
|
2682
|
+
// An ALIAS of --max-depth, and it takes a value. The round-5 extraction read
|
|
2683
|
+
// alias lines as plain switches and swept it into noValue, which hard-blocked
|
|
2684
|
+
// `rg --maxdepth 2 .env src` while `--max-depth 2` ran (/code-review round 7).
|
|
2685
|
+
"--maxdepth",
|
|
2686
|
+
"--max-filesize",
|
|
2687
|
+
"--path-separator",
|
|
2688
|
+
"--pre",
|
|
2689
|
+
"--pre-glob",
|
|
2690
|
+
"--regexp",
|
|
2691
|
+
"--regex-size-limit",
|
|
2692
|
+
"--replace",
|
|
2693
|
+
"--sort",
|
|
2694
|
+
"--sortr",
|
|
2695
|
+
"--threads",
|
|
2696
|
+
"--type",
|
|
2697
|
+
"--type-add",
|
|
2698
|
+
"--type-clear",
|
|
2699
|
+
"--type-not"
|
|
2700
|
+
]),
|
|
2701
|
+
noValue: /* @__PURE__ */ new Set([
|
|
2702
|
+
"-.",
|
|
2703
|
+
"-0",
|
|
2704
|
+
"-a",
|
|
2705
|
+
"-b",
|
|
2706
|
+
"-c",
|
|
2707
|
+
"-F",
|
|
2708
|
+
"-h",
|
|
2709
|
+
"-H",
|
|
2710
|
+
"-i",
|
|
2711
|
+
"-I",
|
|
2712
|
+
"-l",
|
|
2713
|
+
"-L",
|
|
2714
|
+
"-n",
|
|
2715
|
+
"-N",
|
|
2716
|
+
"-o",
|
|
2717
|
+
"-p",
|
|
2718
|
+
"-P",
|
|
2719
|
+
"-q",
|
|
2720
|
+
"-s",
|
|
2721
|
+
"-S",
|
|
2722
|
+
"-u",
|
|
2723
|
+
"-U",
|
|
2724
|
+
"-v",
|
|
2725
|
+
"-V",
|
|
2726
|
+
"-w",
|
|
2727
|
+
"-x",
|
|
2728
|
+
"-z",
|
|
2729
|
+
"--auto-hybrid-regex",
|
|
2730
|
+
"--binary",
|
|
2731
|
+
"--block-buffered",
|
|
2732
|
+
"--byte-offset",
|
|
2733
|
+
"--case-sensitive",
|
|
2734
|
+
"--column",
|
|
2735
|
+
"--count",
|
|
2736
|
+
"--count-matches",
|
|
2737
|
+
"--crlf",
|
|
2738
|
+
"--debug",
|
|
2739
|
+
"--files",
|
|
2740
|
+
"--files-with-matches",
|
|
2741
|
+
"--files-without-match",
|
|
2742
|
+
"--fixed-strings",
|
|
2743
|
+
"--follow",
|
|
2744
|
+
"--glob-case-insensitive",
|
|
2745
|
+
"--heading",
|
|
2746
|
+
"--help",
|
|
2747
|
+
"--hidden",
|
|
2748
|
+
"--ignore-case",
|
|
2749
|
+
"--ignore-file-case-insensitive",
|
|
2750
|
+
"--include-zero",
|
|
2751
|
+
"--invert-match",
|
|
2752
|
+
"--json",
|
|
2753
|
+
"--line-buffered",
|
|
2754
|
+
"--line-number",
|
|
2755
|
+
"--line-regexp",
|
|
2756
|
+
"--max-columns-preview",
|
|
2757
|
+
"--mmap",
|
|
2758
|
+
"--multiline",
|
|
2759
|
+
"--multiline-dotall",
|
|
2760
|
+
"--no-column",
|
|
2761
|
+
"--no-config",
|
|
2762
|
+
"--no-context-separator",
|
|
2763
|
+
"--no-encoding",
|
|
2764
|
+
"--no-filename",
|
|
2765
|
+
"--no-ignore",
|
|
2766
|
+
"--no-ignore-dot",
|
|
2767
|
+
"--no-ignore-exclude",
|
|
2768
|
+
"--no-ignore-files",
|
|
2769
|
+
"--no-ignore-global",
|
|
2770
|
+
"--no-ignore-messages",
|
|
2771
|
+
"--no-ignore-parent",
|
|
2772
|
+
"--no-ignore-vcs",
|
|
2773
|
+
"--no-line-number",
|
|
2774
|
+
"--no-messages",
|
|
2775
|
+
"--no-pcre2-unicode",
|
|
2776
|
+
"--no-pre",
|
|
2777
|
+
"--no-require-git",
|
|
2778
|
+
"--no-unicode",
|
|
2779
|
+
"--null",
|
|
2780
|
+
"--null-data",
|
|
2781
|
+
"--one-file-system",
|
|
2782
|
+
"--only-matching",
|
|
2783
|
+
"--passthru",
|
|
2784
|
+
"--pcre2",
|
|
2785
|
+
"--pcre2-version",
|
|
2786
|
+
"--pretty",
|
|
2787
|
+
"--print0",
|
|
2788
|
+
"--quiet",
|
|
2789
|
+
"--search-zip",
|
|
2790
|
+
"--smart-case",
|
|
2791
|
+
"--sort-files",
|
|
2792
|
+
"--stats",
|
|
2793
|
+
"--stop-on-nonmatch",
|
|
2794
|
+
"--text",
|
|
2795
|
+
"--trace",
|
|
2796
|
+
"--trim",
|
|
2797
|
+
"--type-list",
|
|
2798
|
+
"--unrestricted",
|
|
2799
|
+
"--version",
|
|
2800
|
+
"--vimgrep",
|
|
2801
|
+
"--with-filename",
|
|
2802
|
+
"--word-regexp",
|
|
2803
|
+
// The COMPLETE remainder of `rg --help`, added after /code-review round 5
|
|
2804
|
+
// found 40 documented switches in neither set. The table is now the whole
|
|
2805
|
+
// option list: `rg --help` yields 149 long options, 35 of them value-taking.
|
|
2806
|
+
"--ignore",
|
|
2807
|
+
"--ignore-dot",
|
|
2808
|
+
"--ignore-exclude",
|
|
2809
|
+
"--ignore-files",
|
|
2810
|
+
"--ignore-global",
|
|
2811
|
+
"--ignore-messages",
|
|
2812
|
+
"--ignore-parent",
|
|
2813
|
+
"--ignore-vcs",
|
|
2814
|
+
"--messages",
|
|
2815
|
+
"--no-auto-hybrid-regex",
|
|
2816
|
+
"--no-binary",
|
|
2817
|
+
"--no-block-buffered",
|
|
2818
|
+
"--no-byte-offset",
|
|
2819
|
+
"--no-crlf",
|
|
2820
|
+
"--no-fixed-strings",
|
|
2821
|
+
"--no-follow",
|
|
2822
|
+
"--no-glob-case-insensitive",
|
|
2823
|
+
"--no-heading",
|
|
2824
|
+
"--no-hidden",
|
|
2825
|
+
"--no-ignore-file-case-insensitive",
|
|
2826
|
+
"--no-include-zero",
|
|
2827
|
+
"--no-invert-match",
|
|
2828
|
+
"--no-json",
|
|
2829
|
+
"--no-line-buffered",
|
|
2830
|
+
"--no-max-columns-preview",
|
|
2831
|
+
"--no-mmap",
|
|
2832
|
+
"--no-multiline",
|
|
2833
|
+
"--no-multiline-dotall",
|
|
2834
|
+
"--no-one-file-system",
|
|
2835
|
+
"--no-pcre2",
|
|
2836
|
+
"--no-search-zip",
|
|
2837
|
+
"--no-sort-files",
|
|
2838
|
+
"--no-stats",
|
|
2839
|
+
"--no-text",
|
|
2840
|
+
"--no-trim",
|
|
2841
|
+
"--passthrough",
|
|
2842
|
+
"--pcre2-unicode",
|
|
2843
|
+
"--require-git",
|
|
2844
|
+
"--unicode"
|
|
2845
|
+
]),
|
|
2846
|
+
patternFlags: /* @__PURE__ */ new Set(["-e", "--regexp"]),
|
|
2847
|
+
// `--files` and `--type-list` list or enumerate without a pattern. Founder
|
|
2848
|
+
// decision 2026-09-13: `rg --files ~/.ssh` stays BLOCKED, which this achieves
|
|
2849
|
+
// by leaving the directory in the judged list.
|
|
2850
|
+
noPatternFlags: /* @__PURE__ */ new Set(["-f", "--file", "--files", "--type-list", "--pcre2-version"])
|
|
2851
|
+
}
|
|
2852
|
+
};
|
|
2853
|
+
PATTERN_VERB_NAMES = Object.keys(PATTERN_VERBS);
|
|
2854
|
+
GREP_FILE_OPERANDS = /* @__PURE__ */ new Set(["-f", "--file", "--exclude-from", "--include"]);
|
|
2855
|
+
READER_VALUE_LETTERS = {
|
|
2856
|
+
awk: ["F", "v", "f"],
|
|
2857
|
+
gawk: ["F", "v", "f", "e", "E", "i", "l", "o", "p", "D"],
|
|
2858
|
+
sed: ["e", "f", "i", "l"],
|
|
2859
|
+
sort: ["C", "k", "o", "S", "t", "T"]
|
|
2860
|
+
};
|
|
2861
|
+
FILE_OPERAND_FLAGS = {
|
|
2862
|
+
grep: GREP_FILE_OPERANDS,
|
|
2863
|
+
egrep: GREP_FILE_OPERANDS,
|
|
2864
|
+
fgrep: GREP_FILE_OPERANDS,
|
|
2865
|
+
// rg and gawk are NOT installed on the measuring machine: these two rows are
|
|
2866
|
+
// from the shipped documentation (ripgrep `-f/--file`, `--ignore-file`; gawk
|
|
2867
|
+
// `-f/--file`) and are marked as such in the spec.
|
|
2868
|
+
// `-g/--glob/--iglob` name which files ripgrep SEARCHES, so an operand naming
|
|
2869
|
+
// a credential makes rg open it -- the same reason grep's `--include` is here.
|
|
2870
|
+
// Measured (/code-review round 3): `rg --hidden -g .env AWS tree` opened .env
|
|
2871
|
+
// and printed its contents.
|
|
2872
|
+
rg: /* @__PURE__ */ new Set(["-f", "--file", "--ignore-file", "-g", "--glob", "--iglob"]),
|
|
2873
|
+
sed: /* @__PURE__ */ new Set(["-f", "--file"]),
|
|
2874
|
+
awk: /* @__PURE__ */ new Set(["-f", "--file"]),
|
|
2875
|
+
gawk: /* @__PURE__ */ new Set(["-f", "--file"]),
|
|
2876
|
+
sort: /* @__PURE__ */ new Set(["--files0-from"])
|
|
2877
|
+
};
|
|
2333
2878
|
SCP_VALUE_FLAGS = ["i", "F", "o", "c", "S", "P", "J", "D", "W", "l"];
|
|
2879
|
+
TAR_VALUE_LETTERS = ["b", "C", "f", "F", "g", "H", "I", "K", "L", "N", "T", "V", "X"];
|
|
2880
|
+
ZIP_VALUE_LETTERS = ["b", "n", "P", "t", "s", "O", "x", "i"];
|
|
2881
|
+
RSYNC_VALUE_LETTERS = ["e", "f", "T", "B", "M"];
|
|
2334
2882
|
RSYNC_SKIP = [
|
|
2335
2883
|
"e",
|
|
2336
2884
|
"--rsh",
|
|
@@ -2342,21 +2890,35 @@ var init_dist = __esm({
|
|
|
2342
2890
|
"f",
|
|
2343
2891
|
"--filter"
|
|
2344
2892
|
];
|
|
2893
|
+
CP_VALUE_LETTERS = ["S", "t"];
|
|
2894
|
+
INSTALL_VALUE_LETTERS = ["S", "t", "g", "m", "o"];
|
|
2345
2895
|
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 },
|
|
2896
|
+
cp: { source: "allButLast", targetDirFlag: true, valueLetters: CP_VALUE_LETTERS },
|
|
2897
|
+
mv: { source: "allButLast", targetDirFlag: true, valueLetters: CP_VALUE_LETTERS },
|
|
2898
|
+
install: { source: "allButLast", targetDirFlag: true, valueLetters: INSTALL_VALUE_LETTERS },
|
|
2899
|
+
ln: { source: "first", targetDirFlag: true, valueLetters: CP_VALUE_LETTERS },
|
|
2900
|
+
scp: { source: "allButLast", skipFlags: SCP_VALUE_FLAGS, valueLetters: SCP_VALUE_FLAGS },
|
|
2901
|
+
rsync: { source: "allButLast", skipFlags: RSYNC_SKIP, valueLetters: RSYNC_VALUE_LETTERS },
|
|
2352
2902
|
tar: {
|
|
2353
2903
|
source: "archive",
|
|
2354
2904
|
archive: "tar",
|
|
2355
|
-
skipFlags: ["f", "X", "T", "--file", "--exclude", "--exclude-from", "--files-from"]
|
|
2905
|
+
skipFlags: ["f", "X", "T", "--file", "--exclude", "--exclude-from", "--files-from"],
|
|
2906
|
+
valueLetters: TAR_VALUE_LETTERS
|
|
2907
|
+
},
|
|
2908
|
+
zip: {
|
|
2909
|
+
source: "archive",
|
|
2910
|
+
archive: "zip",
|
|
2911
|
+
skipFlags: ["x", "i", "--exclude", "--include"],
|
|
2912
|
+
valueLetters: ZIP_VALUE_LETTERS
|
|
2356
2913
|
},
|
|
2357
|
-
zip: { source: "archive", archive: "zip", skipFlags: ["x", "i", "--exclude", "--include"] },
|
|
2358
2914
|
ar: { source: "archive", archive: "ar" },
|
|
2359
|
-
|
|
2915
|
+
// 7z switches are INLINE only (`-mx9`, `-px`, `-x!pat`), so no following word is
|
|
2916
|
+
// ever a switch's operand -- which is why the short `x` is NOT a skipFlag here
|
|
2917
|
+
// and valueLetters is empty. Keeping the short `x` made `7z a out.7z -mx KEY`
|
|
2918
|
+
// drop the credential as an exclusion operand (/code-review round 8), and the
|
|
2919
|
+
// derived "every skipped letter is a value letter" row in jail-copy.spec.ts is
|
|
2920
|
+
// what keeps the two tables honest about it.
|
|
2921
|
+
"7z": { source: "archive", archive: "7z", skipFlags: ["--exclude"], valueLetters: [] },
|
|
2360
2922
|
gzip: { source: "all" },
|
|
2361
2923
|
bzip2: { source: "all" },
|
|
2362
2924
|
xz: { source: "all" },
|
|
@@ -2567,6 +3129,8 @@ var init_dist = __esm({
|
|
|
2567
3129
|
};
|
|
2568
3130
|
isReaderWord = (w) => w !== null && FS_READ_TOOLS.has(baseWord(w));
|
|
2569
3131
|
positionalAfter = (words, from, to = words.length) => positionedArgs(words, from, to).map((a) => a.value);
|
|
3132
|
+
NONE = { kind: "none" };
|
|
3133
|
+
UNKNOWN = { kind: "unknown" };
|
|
2570
3134
|
SOURCE_COMMANDS = /* @__PURE__ */ new Set([...FS_READ_TOOLS, "tee"]);
|
|
2571
3135
|
SSRF_MAX_HOST = 253;
|
|
2572
3136
|
METADATA_ADDRESSES = /* @__PURE__ */ new Set([
|
|
@@ -2589,6 +3153,7 @@ var init_dist = __esm({
|
|
|
2589
3153
|
const p = a.split(".");
|
|
2590
3154
|
return p.length === 4 ? p.map(Number) : null;
|
|
2591
3155
|
};
|
|
3156
|
+
TERMINAL_ESCAPE_RE = /\x1b\[[0-9;?]*[A-Za-z]|\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)|\x1b[@-_]|[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g;
|
|
2592
3157
|
aws_default = {
|
|
2593
3158
|
name: "aws",
|
|
2594
3159
|
description: "Protects AWS infrastructure from destructive AI operations",
|
|
@@ -5117,6 +5682,14 @@ var init_session_files = __esm({
|
|
|
5117
5682
|
}
|
|
5118
5683
|
});
|
|
5119
5684
|
|
|
5685
|
+
// src/utils/safe-text.ts
|
|
5686
|
+
var init_safe_text = __esm({
|
|
5687
|
+
"src/utils/safe-text.ts"() {
|
|
5688
|
+
"use strict";
|
|
5689
|
+
init_dist();
|
|
5690
|
+
}
|
|
5691
|
+
});
|
|
5692
|
+
|
|
5120
5693
|
// src/costSync.ts
|
|
5121
5694
|
function decodeProjectDirName(dirName) {
|
|
5122
5695
|
return dirName.replace(/-/g, "/");
|
|
@@ -5132,6 +5705,7 @@ var init_costSync = __esm({
|
|
|
5132
5705
|
init_cost_gemini();
|
|
5133
5706
|
init_cost_copilot();
|
|
5134
5707
|
init_session_files();
|
|
5708
|
+
init_safe_text();
|
|
5135
5709
|
SYNC_INTERVAL_MS = 10 * 60 * 1e3;
|
|
5136
5710
|
}
|
|
5137
5711
|
});
|
|
@@ -6105,9 +6679,6 @@ function isNode9SelfOutput(text) {
|
|
|
6105
6679
|
}
|
|
6106
6680
|
return false;
|
|
6107
6681
|
}
|
|
6108
|
-
function stripTerminalEscapes(s) {
|
|
6109
|
-
return s.replace(TERMINAL_ESCAPE_RE, "");
|
|
6110
|
-
}
|
|
6111
6682
|
function preview(input, max) {
|
|
6112
6683
|
const cmd = input.command ?? input.query ?? input.file_path ?? JSON.stringify(input);
|
|
6113
6684
|
const s = stripTerminalEscapes(String(cmd)).replace(/\s+/g, " ").trim();
|
|
@@ -7083,7 +7654,7 @@ function scanCodexHistory(startDate, onProgress, onLine) {
|
|
|
7083
7654
|
}
|
|
7084
7655
|
return result;
|
|
7085
7656
|
}
|
|
7086
|
-
var toolInspectionMap, CODE_EXTENSIONS, SELF_OUTPUT_MARKERS,
|
|
7657
|
+
var toolInspectionMap, CODE_EXTENSIONS, SELF_OUTPUT_MARKERS, LOOP_TOOLS, LOOP_THRESHOLD, LOOP_TIMESPAN_THRESHOLD_MS;
|
|
7087
7658
|
var init_scan = __esm({
|
|
7088
7659
|
"src/cli/commands/scan.ts"() {
|
|
7089
7660
|
"use strict";
|
|
@@ -7109,6 +7680,7 @@ var init_scan = __esm({
|
|
|
7109
7680
|
init_scan_json();
|
|
7110
7681
|
init_session_files();
|
|
7111
7682
|
init_scan_history();
|
|
7683
|
+
init_safe_text();
|
|
7112
7684
|
toolInspectionMap = DEFAULT_CONFIG.policy.toolInspection;
|
|
7113
7685
|
CODE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
7114
7686
|
".ts",
|
|
@@ -7143,7 +7715,6 @@ var init_scan = __esm({
|
|
|
7143
7715
|
/\bseverity:\s*['"](?:block|review|allow)['"]/,
|
|
7144
7716
|
/NODE9 SECURITY ALERT/
|
|
7145
7717
|
];
|
|
7146
|
-
TERMINAL_ESCAPE_RE = /\x1b\[[0-9;?]*[A-Za-z]|\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)|\x1b[@-_]|[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g;
|
|
7147
7718
|
LOOP_TOOLS = /* @__PURE__ */ new Set([
|
|
7148
7719
|
"bash",
|
|
7149
7720
|
"execute_bash",
|