@node9/proxy 2.14.0 → 2.14.1
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 +599 -38
- package/dist/cli.mjs +599 -38
- package/dist/dashboard.mjs +598 -37
- package/dist/index.js +597 -36
- package/dist/index.mjs +597 -36
- 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;
|
|
@@ -1729,7 +1936,7 @@ function matchCanaryArgs(args, values) {
|
|
|
1729
1936
|
return null;
|
|
1730
1937
|
}
|
|
1731
1938
|
}
|
|
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;
|
|
1939
|
+
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, 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
1940
|
var init_dist = __esm({
|
|
1734
1941
|
"packages/policy-engine/dist/index.mjs"() {
|
|
1735
1942
|
"use strict";
|
|
@@ -2330,7 +2537,345 @@ var init_dist = __esm({
|
|
|
2330
2537
|
"nl",
|
|
2331
2538
|
"dd"
|
|
2332
2539
|
]);
|
|
2540
|
+
GREP_SHAPE = {
|
|
2541
|
+
takesValue: /* @__PURE__ */ new Set([
|
|
2542
|
+
"-A",
|
|
2543
|
+
"-B",
|
|
2544
|
+
"-C",
|
|
2545
|
+
"-D",
|
|
2546
|
+
"-d",
|
|
2547
|
+
"-e",
|
|
2548
|
+
"-f",
|
|
2549
|
+
"-m",
|
|
2550
|
+
"--after-context",
|
|
2551
|
+
"--before-context",
|
|
2552
|
+
"--binary-files",
|
|
2553
|
+
"--context",
|
|
2554
|
+
"--devices",
|
|
2555
|
+
"--directories",
|
|
2556
|
+
"--exclude",
|
|
2557
|
+
"--exclude-dir",
|
|
2558
|
+
"--exclude-from",
|
|
2559
|
+
"--file",
|
|
2560
|
+
"--include",
|
|
2561
|
+
"--label",
|
|
2562
|
+
"--max-count",
|
|
2563
|
+
"--regexp"
|
|
2564
|
+
]),
|
|
2565
|
+
noValue: /* @__PURE__ */ new Set([
|
|
2566
|
+
"-E",
|
|
2567
|
+
"-F",
|
|
2568
|
+
"-G",
|
|
2569
|
+
"-P",
|
|
2570
|
+
"-i",
|
|
2571
|
+
"-y",
|
|
2572
|
+
"-v",
|
|
2573
|
+
"-V",
|
|
2574
|
+
"-w",
|
|
2575
|
+
"-x",
|
|
2576
|
+
"-c",
|
|
2577
|
+
"-l",
|
|
2578
|
+
"-L",
|
|
2579
|
+
"-o",
|
|
2580
|
+
"-q",
|
|
2581
|
+
"-s",
|
|
2582
|
+
"-b",
|
|
2583
|
+
"-H",
|
|
2584
|
+
"-h",
|
|
2585
|
+
"-n",
|
|
2586
|
+
"-T",
|
|
2587
|
+
"-Z",
|
|
2588
|
+
"-z",
|
|
2589
|
+
"-R",
|
|
2590
|
+
"-r",
|
|
2591
|
+
"-U",
|
|
2592
|
+
"-u",
|
|
2593
|
+
"-I",
|
|
2594
|
+
"-a",
|
|
2595
|
+
"--basic-regexp",
|
|
2596
|
+
"--binary",
|
|
2597
|
+
"--byte-offset",
|
|
2598
|
+
"--color",
|
|
2599
|
+
"--colour",
|
|
2600
|
+
"--count",
|
|
2601
|
+
"--dereference-recursive",
|
|
2602
|
+
"--extended-regexp",
|
|
2603
|
+
"--files-with-matches",
|
|
2604
|
+
"--files-without-match",
|
|
2605
|
+
"--fixed-strings",
|
|
2606
|
+
"--help",
|
|
2607
|
+
"--ignore-case",
|
|
2608
|
+
"--initial-tab",
|
|
2609
|
+
"--invert-match",
|
|
2610
|
+
"--line-buffered",
|
|
2611
|
+
"--line-number",
|
|
2612
|
+
"--line-regexp",
|
|
2613
|
+
"--no-filename",
|
|
2614
|
+
"--no-group-separator",
|
|
2615
|
+
"--no-ignore-case",
|
|
2616
|
+
"--no-messages",
|
|
2617
|
+
"--null",
|
|
2618
|
+
"--null-data",
|
|
2619
|
+
"--only-matching",
|
|
2620
|
+
"--perl-regexp",
|
|
2621
|
+
"--quiet",
|
|
2622
|
+
"--recursive",
|
|
2623
|
+
"--silent",
|
|
2624
|
+
"--text",
|
|
2625
|
+
"--version",
|
|
2626
|
+
"--with-filename",
|
|
2627
|
+
"--word-regexp"
|
|
2628
|
+
]),
|
|
2629
|
+
patternFlags: /* @__PURE__ */ new Set(["-e", "--regexp"]),
|
|
2630
|
+
noPatternFlags: /* @__PURE__ */ new Set(["-f", "--file"])
|
|
2631
|
+
};
|
|
2632
|
+
PATTERN_VERBS = {
|
|
2633
|
+
grep: GREP_SHAPE,
|
|
2634
|
+
// /usr/bin/egrep and /usr/bin/fgrep are 41-byte shell wrappers that exec
|
|
2635
|
+
// `grep -E` and `grep -F`. Read in full, not assumed.
|
|
2636
|
+
egrep: GREP_SHAPE,
|
|
2637
|
+
fgrep: GREP_SHAPE,
|
|
2638
|
+
// ripgrep 14.1.1, complete from its own --help. An earlier comment here said rg
|
|
2639
|
+
// was not installed on the measuring machine; it is, and that stale claim is why
|
|
2640
|
+
// this table shipped incomplete for two rounds, blocking ordinary searches like
|
|
2641
|
+
// `rg --sort-files .env src` (/code-review round 4).
|
|
2642
|
+
rg: {
|
|
2643
|
+
takesValue: /* @__PURE__ */ new Set([
|
|
2644
|
+
"-A",
|
|
2645
|
+
"-B",
|
|
2646
|
+
"-C",
|
|
2647
|
+
"-d",
|
|
2648
|
+
"-E",
|
|
2649
|
+
"-e",
|
|
2650
|
+
"-f",
|
|
2651
|
+
"-g",
|
|
2652
|
+
"-j",
|
|
2653
|
+
"-M",
|
|
2654
|
+
"-m",
|
|
2655
|
+
"-r",
|
|
2656
|
+
"-t",
|
|
2657
|
+
"-T",
|
|
2658
|
+
"--after-context",
|
|
2659
|
+
"--before-context",
|
|
2660
|
+
"--color",
|
|
2661
|
+
"--colors",
|
|
2662
|
+
"--context",
|
|
2663
|
+
"--context-separator",
|
|
2664
|
+
"--dfa-size-limit",
|
|
2665
|
+
"--encoding",
|
|
2666
|
+
"--engine",
|
|
2667
|
+
"--field-context-separator",
|
|
2668
|
+
"--field-match-separator",
|
|
2669
|
+
"--file",
|
|
2670
|
+
"--generate",
|
|
2671
|
+
"--glob",
|
|
2672
|
+
"--hostname-bin",
|
|
2673
|
+
"--hyperlink-format",
|
|
2674
|
+
"--iglob",
|
|
2675
|
+
"--ignore-file",
|
|
2676
|
+
"--max-columns",
|
|
2677
|
+
"--max-count",
|
|
2678
|
+
"--max-depth",
|
|
2679
|
+
// An ALIAS of --max-depth, and it takes a value. The round-5 extraction read
|
|
2680
|
+
// alias lines as plain switches and swept it into noValue, which hard-blocked
|
|
2681
|
+
// `rg --maxdepth 2 .env src` while `--max-depth 2` ran (/code-review round 7).
|
|
2682
|
+
"--maxdepth",
|
|
2683
|
+
"--max-filesize",
|
|
2684
|
+
"--path-separator",
|
|
2685
|
+
"--pre",
|
|
2686
|
+
"--pre-glob",
|
|
2687
|
+
"--regexp",
|
|
2688
|
+
"--regex-size-limit",
|
|
2689
|
+
"--replace",
|
|
2690
|
+
"--sort",
|
|
2691
|
+
"--sortr",
|
|
2692
|
+
"--threads",
|
|
2693
|
+
"--type",
|
|
2694
|
+
"--type-add",
|
|
2695
|
+
"--type-clear",
|
|
2696
|
+
"--type-not"
|
|
2697
|
+
]),
|
|
2698
|
+
noValue: /* @__PURE__ */ new Set([
|
|
2699
|
+
"-.",
|
|
2700
|
+
"-0",
|
|
2701
|
+
"-a",
|
|
2702
|
+
"-b",
|
|
2703
|
+
"-c",
|
|
2704
|
+
"-F",
|
|
2705
|
+
"-h",
|
|
2706
|
+
"-H",
|
|
2707
|
+
"-i",
|
|
2708
|
+
"-I",
|
|
2709
|
+
"-l",
|
|
2710
|
+
"-L",
|
|
2711
|
+
"-n",
|
|
2712
|
+
"-N",
|
|
2713
|
+
"-o",
|
|
2714
|
+
"-p",
|
|
2715
|
+
"-P",
|
|
2716
|
+
"-q",
|
|
2717
|
+
"-s",
|
|
2718
|
+
"-S",
|
|
2719
|
+
"-u",
|
|
2720
|
+
"-U",
|
|
2721
|
+
"-v",
|
|
2722
|
+
"-V",
|
|
2723
|
+
"-w",
|
|
2724
|
+
"-x",
|
|
2725
|
+
"-z",
|
|
2726
|
+
"--auto-hybrid-regex",
|
|
2727
|
+
"--binary",
|
|
2728
|
+
"--block-buffered",
|
|
2729
|
+
"--byte-offset",
|
|
2730
|
+
"--case-sensitive",
|
|
2731
|
+
"--column",
|
|
2732
|
+
"--count",
|
|
2733
|
+
"--count-matches",
|
|
2734
|
+
"--crlf",
|
|
2735
|
+
"--debug",
|
|
2736
|
+
"--files",
|
|
2737
|
+
"--files-with-matches",
|
|
2738
|
+
"--files-without-match",
|
|
2739
|
+
"--fixed-strings",
|
|
2740
|
+
"--follow",
|
|
2741
|
+
"--glob-case-insensitive",
|
|
2742
|
+
"--heading",
|
|
2743
|
+
"--help",
|
|
2744
|
+
"--hidden",
|
|
2745
|
+
"--ignore-case",
|
|
2746
|
+
"--ignore-file-case-insensitive",
|
|
2747
|
+
"--include-zero",
|
|
2748
|
+
"--invert-match",
|
|
2749
|
+
"--json",
|
|
2750
|
+
"--line-buffered",
|
|
2751
|
+
"--line-number",
|
|
2752
|
+
"--line-regexp",
|
|
2753
|
+
"--max-columns-preview",
|
|
2754
|
+
"--mmap",
|
|
2755
|
+
"--multiline",
|
|
2756
|
+
"--multiline-dotall",
|
|
2757
|
+
"--no-column",
|
|
2758
|
+
"--no-config",
|
|
2759
|
+
"--no-context-separator",
|
|
2760
|
+
"--no-encoding",
|
|
2761
|
+
"--no-filename",
|
|
2762
|
+
"--no-ignore",
|
|
2763
|
+
"--no-ignore-dot",
|
|
2764
|
+
"--no-ignore-exclude",
|
|
2765
|
+
"--no-ignore-files",
|
|
2766
|
+
"--no-ignore-global",
|
|
2767
|
+
"--no-ignore-messages",
|
|
2768
|
+
"--no-ignore-parent",
|
|
2769
|
+
"--no-ignore-vcs",
|
|
2770
|
+
"--no-line-number",
|
|
2771
|
+
"--no-messages",
|
|
2772
|
+
"--no-pcre2-unicode",
|
|
2773
|
+
"--no-pre",
|
|
2774
|
+
"--no-require-git",
|
|
2775
|
+
"--no-unicode",
|
|
2776
|
+
"--null",
|
|
2777
|
+
"--null-data",
|
|
2778
|
+
"--one-file-system",
|
|
2779
|
+
"--only-matching",
|
|
2780
|
+
"--passthru",
|
|
2781
|
+
"--pcre2",
|
|
2782
|
+
"--pcre2-version",
|
|
2783
|
+
"--pretty",
|
|
2784
|
+
"--print0",
|
|
2785
|
+
"--quiet",
|
|
2786
|
+
"--search-zip",
|
|
2787
|
+
"--smart-case",
|
|
2788
|
+
"--sort-files",
|
|
2789
|
+
"--stats",
|
|
2790
|
+
"--stop-on-nonmatch",
|
|
2791
|
+
"--text",
|
|
2792
|
+
"--trace",
|
|
2793
|
+
"--trim",
|
|
2794
|
+
"--type-list",
|
|
2795
|
+
"--unrestricted",
|
|
2796
|
+
"--version",
|
|
2797
|
+
"--vimgrep",
|
|
2798
|
+
"--with-filename",
|
|
2799
|
+
"--word-regexp",
|
|
2800
|
+
// The COMPLETE remainder of `rg --help`, added after /code-review round 5
|
|
2801
|
+
// found 40 documented switches in neither set. The table is now the whole
|
|
2802
|
+
// option list: `rg --help` yields 149 long options, 35 of them value-taking.
|
|
2803
|
+
"--ignore",
|
|
2804
|
+
"--ignore-dot",
|
|
2805
|
+
"--ignore-exclude",
|
|
2806
|
+
"--ignore-files",
|
|
2807
|
+
"--ignore-global",
|
|
2808
|
+
"--ignore-messages",
|
|
2809
|
+
"--ignore-parent",
|
|
2810
|
+
"--ignore-vcs",
|
|
2811
|
+
"--messages",
|
|
2812
|
+
"--no-auto-hybrid-regex",
|
|
2813
|
+
"--no-binary",
|
|
2814
|
+
"--no-block-buffered",
|
|
2815
|
+
"--no-byte-offset",
|
|
2816
|
+
"--no-crlf",
|
|
2817
|
+
"--no-fixed-strings",
|
|
2818
|
+
"--no-follow",
|
|
2819
|
+
"--no-glob-case-insensitive",
|
|
2820
|
+
"--no-heading",
|
|
2821
|
+
"--no-hidden",
|
|
2822
|
+
"--no-ignore-file-case-insensitive",
|
|
2823
|
+
"--no-include-zero",
|
|
2824
|
+
"--no-invert-match",
|
|
2825
|
+
"--no-json",
|
|
2826
|
+
"--no-line-buffered",
|
|
2827
|
+
"--no-max-columns-preview",
|
|
2828
|
+
"--no-mmap",
|
|
2829
|
+
"--no-multiline",
|
|
2830
|
+
"--no-multiline-dotall",
|
|
2831
|
+
"--no-one-file-system",
|
|
2832
|
+
"--no-pcre2",
|
|
2833
|
+
"--no-search-zip",
|
|
2834
|
+
"--no-sort-files",
|
|
2835
|
+
"--no-stats",
|
|
2836
|
+
"--no-text",
|
|
2837
|
+
"--no-trim",
|
|
2838
|
+
"--passthrough",
|
|
2839
|
+
"--pcre2-unicode",
|
|
2840
|
+
"--require-git",
|
|
2841
|
+
"--unicode"
|
|
2842
|
+
]),
|
|
2843
|
+
patternFlags: /* @__PURE__ */ new Set(["-e", "--regexp"]),
|
|
2844
|
+
// `--files` and `--type-list` list or enumerate without a pattern. Founder
|
|
2845
|
+
// decision 2026-09-13: `rg --files ~/.ssh` stays BLOCKED, which this achieves
|
|
2846
|
+
// by leaving the directory in the judged list.
|
|
2847
|
+
noPatternFlags: /* @__PURE__ */ new Set(["-f", "--file", "--files", "--type-list", "--pcre2-version"])
|
|
2848
|
+
}
|
|
2849
|
+
};
|
|
2850
|
+
PATTERN_VERB_NAMES = Object.keys(PATTERN_VERBS);
|
|
2851
|
+
GREP_FILE_OPERANDS = /* @__PURE__ */ new Set(["-f", "--file", "--exclude-from", "--include"]);
|
|
2852
|
+
READER_VALUE_LETTERS = {
|
|
2853
|
+
awk: ["F", "v", "f"],
|
|
2854
|
+
gawk: ["F", "v", "f", "e", "E", "i", "l", "o", "p", "D"],
|
|
2855
|
+
sed: ["e", "f", "i", "l"],
|
|
2856
|
+
sort: ["C", "k", "o", "S", "t", "T"]
|
|
2857
|
+
};
|
|
2858
|
+
FILE_OPERAND_FLAGS = {
|
|
2859
|
+
grep: GREP_FILE_OPERANDS,
|
|
2860
|
+
egrep: GREP_FILE_OPERANDS,
|
|
2861
|
+
fgrep: GREP_FILE_OPERANDS,
|
|
2862
|
+
// rg and gawk are NOT installed on the measuring machine: these two rows are
|
|
2863
|
+
// from the shipped documentation (ripgrep `-f/--file`, `--ignore-file`; gawk
|
|
2864
|
+
// `-f/--file`) and are marked as such in the spec.
|
|
2865
|
+
// `-g/--glob/--iglob` name which files ripgrep SEARCHES, so an operand naming
|
|
2866
|
+
// a credential makes rg open it -- the same reason grep's `--include` is here.
|
|
2867
|
+
// Measured (/code-review round 3): `rg --hidden -g .env AWS tree` opened .env
|
|
2868
|
+
// and printed its contents.
|
|
2869
|
+
rg: /* @__PURE__ */ new Set(["-f", "--file", "--ignore-file", "-g", "--glob", "--iglob"]),
|
|
2870
|
+
sed: /* @__PURE__ */ new Set(["-f", "--file"]),
|
|
2871
|
+
awk: /* @__PURE__ */ new Set(["-f", "--file"]),
|
|
2872
|
+
gawk: /* @__PURE__ */ new Set(["-f", "--file"]),
|
|
2873
|
+
sort: /* @__PURE__ */ new Set(["--files0-from"])
|
|
2874
|
+
};
|
|
2333
2875
|
SCP_VALUE_FLAGS = ["i", "F", "o", "c", "S", "P", "J", "D", "W", "l"];
|
|
2876
|
+
TAR_VALUE_LETTERS = ["b", "C", "f", "F", "g", "H", "I", "K", "L", "N", "T", "V", "X"];
|
|
2877
|
+
ZIP_VALUE_LETTERS = ["b", "n", "P", "t", "s", "O", "x", "i"];
|
|
2878
|
+
RSYNC_VALUE_LETTERS = ["e", "f", "T", "B", "M"];
|
|
2334
2879
|
RSYNC_SKIP = [
|
|
2335
2880
|
"e",
|
|
2336
2881
|
"--rsh",
|
|
@@ -2342,21 +2887,35 @@ var init_dist = __esm({
|
|
|
2342
2887
|
"f",
|
|
2343
2888
|
"--filter"
|
|
2344
2889
|
];
|
|
2890
|
+
CP_VALUE_LETTERS = ["S", "t"];
|
|
2891
|
+
INSTALL_VALUE_LETTERS = ["S", "t", "g", "m", "o"];
|
|
2345
2892
|
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 },
|
|
2893
|
+
cp: { source: "allButLast", targetDirFlag: true, valueLetters: CP_VALUE_LETTERS },
|
|
2894
|
+
mv: { source: "allButLast", targetDirFlag: true, valueLetters: CP_VALUE_LETTERS },
|
|
2895
|
+
install: { source: "allButLast", targetDirFlag: true, valueLetters: INSTALL_VALUE_LETTERS },
|
|
2896
|
+
ln: { source: "first", targetDirFlag: true, valueLetters: CP_VALUE_LETTERS },
|
|
2897
|
+
scp: { source: "allButLast", skipFlags: SCP_VALUE_FLAGS, valueLetters: SCP_VALUE_FLAGS },
|
|
2898
|
+
rsync: { source: "allButLast", skipFlags: RSYNC_SKIP, valueLetters: RSYNC_VALUE_LETTERS },
|
|
2352
2899
|
tar: {
|
|
2353
2900
|
source: "archive",
|
|
2354
2901
|
archive: "tar",
|
|
2355
|
-
skipFlags: ["f", "X", "T", "--file", "--exclude", "--exclude-from", "--files-from"]
|
|
2902
|
+
skipFlags: ["f", "X", "T", "--file", "--exclude", "--exclude-from", "--files-from"],
|
|
2903
|
+
valueLetters: TAR_VALUE_LETTERS
|
|
2904
|
+
},
|
|
2905
|
+
zip: {
|
|
2906
|
+
source: "archive",
|
|
2907
|
+
archive: "zip",
|
|
2908
|
+
skipFlags: ["x", "i", "--exclude", "--include"],
|
|
2909
|
+
valueLetters: ZIP_VALUE_LETTERS
|
|
2356
2910
|
},
|
|
2357
|
-
zip: { source: "archive", archive: "zip", skipFlags: ["x", "i", "--exclude", "--include"] },
|
|
2358
2911
|
ar: { source: "archive", archive: "ar" },
|
|
2359
|
-
|
|
2912
|
+
// 7z switches are INLINE only (`-mx9`, `-px`, `-x!pat`), so no following word is
|
|
2913
|
+
// ever a switch's operand -- which is why the short `x` is NOT a skipFlag here
|
|
2914
|
+
// and valueLetters is empty. Keeping the short `x` made `7z a out.7z -mx KEY`
|
|
2915
|
+
// drop the credential as an exclusion operand (/code-review round 8), and the
|
|
2916
|
+
// derived "every skipped letter is a value letter" row in jail-copy.spec.ts is
|
|
2917
|
+
// what keeps the two tables honest about it.
|
|
2918
|
+
"7z": { source: "archive", archive: "7z", skipFlags: ["--exclude"], valueLetters: [] },
|
|
2360
2919
|
gzip: { source: "all" },
|
|
2361
2920
|
bzip2: { source: "all" },
|
|
2362
2921
|
xz: { source: "all" },
|
|
@@ -2567,6 +3126,8 @@ var init_dist = __esm({
|
|
|
2567
3126
|
};
|
|
2568
3127
|
isReaderWord = (w) => w !== null && FS_READ_TOOLS.has(baseWord(w));
|
|
2569
3128
|
positionalAfter = (words, from, to = words.length) => positionedArgs(words, from, to).map((a) => a.value);
|
|
3129
|
+
NONE = { kind: "none" };
|
|
3130
|
+
UNKNOWN = { kind: "unknown" };
|
|
2570
3131
|
SOURCE_COMMANDS = /* @__PURE__ */ new Set([...FS_READ_TOOLS, "tee"]);
|
|
2571
3132
|
SSRF_MAX_HOST = 253;
|
|
2572
3133
|
METADATA_ADDRESSES = /* @__PURE__ */ new Set([
|