@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/cli.js
CHANGED
|
@@ -894,6 +894,19 @@ function parseShared(command) {
|
|
|
894
894
|
astCache.set(command, parsed);
|
|
895
895
|
return parsed;
|
|
896
896
|
}
|
|
897
|
+
function byteOffsetToCharIndex(command) {
|
|
898
|
+
if (!/[^\u0000-\u007F]/.test(command)) return null;
|
|
899
|
+
const map = /* @__PURE__ */ new Map();
|
|
900
|
+
let byte = 0;
|
|
901
|
+
for (let i = 0; i < command.length; ) {
|
|
902
|
+
map.set(byte, i);
|
|
903
|
+
const cp = command.codePointAt(i);
|
|
904
|
+
byte += cp < 128 ? 1 : cp < 2048 ? 2 : cp < 65536 ? 3 : 4;
|
|
905
|
+
i += cp > 65535 ? 2 : 1;
|
|
906
|
+
}
|
|
907
|
+
map.set(byte, command.length);
|
|
908
|
+
return (b) => map.get(b) ?? -1;
|
|
909
|
+
}
|
|
897
910
|
function cachedNormalize(command, compute) {
|
|
898
911
|
const hit = normalizeCache.get(command);
|
|
899
912
|
if (hit !== void 0) {
|
|
@@ -923,6 +936,8 @@ function normalizeCommandForPolicyImpl(command) {
|
|
|
923
936
|
const f = parseShared(command);
|
|
924
937
|
if (f === PARSE_FAIL) return { posix: command, separator: command };
|
|
925
938
|
try {
|
|
939
|
+
const toCharIndex = byteOffsetToCharIndex(command);
|
|
940
|
+
const at = (byteOffset) => toCharIndex === null ? byteOffset : toCharIndex(byteOffset);
|
|
926
941
|
const strips = [];
|
|
927
942
|
const rewrites = [];
|
|
928
943
|
const quoteOnlyRewrites = [];
|
|
@@ -943,8 +958,9 @@ function normalizeCommandForPolicyImpl(command) {
|
|
|
943
958
|
const quotedNode = nextParts[0];
|
|
944
959
|
const nt = syntax.NodeType(quotedNode);
|
|
945
960
|
const markStrip = () => {
|
|
946
|
-
const s = next.Pos().Offset();
|
|
947
|
-
const e = next.End().Offset();
|
|
961
|
+
const s = at(next.Pos().Offset());
|
|
962
|
+
const e = at(next.End().Offset());
|
|
963
|
+
if (s < 0 || e < 0) return;
|
|
948
964
|
strips.push([s, e]);
|
|
949
965
|
msgSpans.add(`${s}:${e}`);
|
|
950
966
|
};
|
|
@@ -961,8 +977,9 @@ function normalizeCommandForPolicyImpl(command) {
|
|
|
961
977
|
}
|
|
962
978
|
}
|
|
963
979
|
for (const arg of args) {
|
|
964
|
-
const s = arg.Pos().Offset();
|
|
965
|
-
const e = arg.End().Offset();
|
|
980
|
+
const s = at(arg.Pos().Offset());
|
|
981
|
+
const e = at(arg.End().Offset());
|
|
982
|
+
if (s < 0 || e < 0) continue;
|
|
966
983
|
if (msgSpans.has(`${s}:${e}`)) continue;
|
|
967
984
|
const resolved = resolveWordLiteral(arg);
|
|
968
985
|
if (resolved === null) continue;
|
|
@@ -1588,7 +1605,7 @@ function analyzeFsOperationImpl(command, depth = 0) {
|
|
|
1588
1605
|
return result?.verdict !== "block";
|
|
1589
1606
|
}
|
|
1590
1607
|
if (nodeType !== "CallExpr") return true;
|
|
1591
|
-
const { name, flags, paths, words } = extractLiteralArgs(n);
|
|
1608
|
+
const { name, flags, paths, words, args } = extractLiteralArgs(n);
|
|
1592
1609
|
if (!name) return true;
|
|
1593
1610
|
if (name === "rm") {
|
|
1594
1611
|
const flagStr = flags.join("").toLowerCase();
|
|
@@ -1628,7 +1645,7 @@ function analyzeFsOperationImpl(command, depth = 0) {
|
|
|
1628
1645
|
return true;
|
|
1629
1646
|
}
|
|
1630
1647
|
}
|
|
1631
|
-
const readPaths = FS_READ_TOOLS.has(name) ?
|
|
1648
|
+
const readPaths = FS_READ_TOOLS.has(name) ? [...readTargets(name, args, flags, words, 1), ...flagOperandFiles(name, words, 1)] : wrappedReadPaths(words, name);
|
|
1632
1649
|
if (readPaths) {
|
|
1633
1650
|
for (const p of readPaths) {
|
|
1634
1651
|
result = stricter(result, matchSensitivePath2(p));
|
|
@@ -1664,9 +1681,22 @@ function flagIs(w, names) {
|
|
|
1664
1681
|
const f = flagInfo(w);
|
|
1665
1682
|
return names.some((n) => n.startsWith("--") ? f.long === n : f.letter === n);
|
|
1666
1683
|
}
|
|
1667
|
-
function operandOf(a, names) {
|
|
1684
|
+
function operandOf(a, names, valueLetters) {
|
|
1668
1685
|
if (!names || a.afterFlag === null) return false;
|
|
1669
|
-
|
|
1686
|
+
const w = a.afterFlag;
|
|
1687
|
+
if (!w.startsWith("--") && valueLetters) {
|
|
1688
|
+
const letters = w.slice(1);
|
|
1689
|
+
for (let i = 0; i < letters.length; i++) {
|
|
1690
|
+
if (!valueLetters.includes(letters[i])) continue;
|
|
1691
|
+
return i === letters.length - 1 && names.includes(letters[i]);
|
|
1692
|
+
}
|
|
1693
|
+
return false;
|
|
1694
|
+
}
|
|
1695
|
+
if (w.startsWith("--") && !w.includes("=")) {
|
|
1696
|
+
const longs = names.filter((n) => n.startsWith("--"));
|
|
1697
|
+
if (longs.some((n) => n === w || w.length >= 3 && n.startsWith(w))) return true;
|
|
1698
|
+
}
|
|
1699
|
+
return flagIs(w, names) && flagInfo(w).attached === null;
|
|
1670
1700
|
}
|
|
1671
1701
|
function resolveCopyShape(words, h) {
|
|
1672
1702
|
const verb = baseWord(words[h]);
|
|
@@ -1690,7 +1720,7 @@ function findStartPoints(words, h) {
|
|
|
1690
1720
|
const k = words.findIndex((w, i) => i > h && w !== null && FIND_EXEC_FLAGS.has(w));
|
|
1691
1721
|
if (k < 0) return { k, starts: [] };
|
|
1692
1722
|
const firstPredicate = words.findIndex(
|
|
1693
|
-
(w, i) => i > h && w !== null && w.startsWith("-") && !FIND_OPTIONS.has(w)
|
|
1723
|
+
(w, i) => i > h && w !== null && w !== "--" && w.startsWith("-") && !FIND_OPTIONS.has(w)
|
|
1694
1724
|
);
|
|
1695
1725
|
const end = firstPredicate > h ? firstPredicate : k;
|
|
1696
1726
|
return { k, starts: positionalAfter(words, h + 1, end) };
|
|
@@ -1710,14 +1740,35 @@ function copySourcePaths(words) {
|
|
|
1710
1740
|
const { shape, last } = r;
|
|
1711
1741
|
const args = positionedArgs(words, last + 1);
|
|
1712
1742
|
const tail = words.slice(last + 1);
|
|
1713
|
-
const
|
|
1714
|
-
const
|
|
1715
|
-
const
|
|
1743
|
+
const copyOptionsEnd = tail.findIndex((w) => w === "--");
|
|
1744
|
+
const copyPastOptions = (a) => copyOptionsEnd >= 0 && a.argv > last + 1 + copyOptionsEnd;
|
|
1745
|
+
const skipped = (a) => !copyPastOptions(a) && operandOf(a, shape.skipFlags, shape.valueLetters);
|
|
1746
|
+
const firstValueLetter = (w) => {
|
|
1747
|
+
const letters = w.slice(1);
|
|
1748
|
+
for (let i = 0; i < letters.length; i++) {
|
|
1749
|
+
if ((shape.valueLetters ?? []).includes(letters[i]))
|
|
1750
|
+
return { letter: letters[i], last: i === letters.length - 1 };
|
|
1751
|
+
}
|
|
1752
|
+
return null;
|
|
1753
|
+
};
|
|
1754
|
+
const isTargetDirFlag = (w) => {
|
|
1755
|
+
if (w.startsWith("--")) {
|
|
1756
|
+
const name = w.includes("=") ? w.slice(0, w.indexOf("=")) : w;
|
|
1757
|
+
return name.length >= 3 && "--target-directory".startsWith(name);
|
|
1758
|
+
}
|
|
1759
|
+
return firstValueLetter(w)?.letter === "t";
|
|
1760
|
+
};
|
|
1761
|
+
const targetDir = shape.targetDirFlag === true && tail.some((w) => w !== null && w.startsWith("-") && isTargetDirFlag(w));
|
|
1762
|
+
const targetTakesNextWord = (w) => {
|
|
1763
|
+
if (w.startsWith("--"))
|
|
1764
|
+
return !w.includes("=") && w.length >= 3 && "--target-directory".startsWith(w);
|
|
1765
|
+
const f = firstValueLetter(w);
|
|
1766
|
+
return f !== null && f.letter === "t" && f.last;
|
|
1767
|
+
};
|
|
1768
|
+
const targetOperand = (a) => targetDir && a.afterFlag !== null && !copyPastOptions(a) && targetTakesNextWord(a.afterFlag);
|
|
1716
1769
|
const lastOperand = [...tail].reverse().find((w) => w === null || !w.startsWith("-"));
|
|
1717
1770
|
const dynamicDest = lastOperand === null;
|
|
1718
1771
|
const destIsLastOperand = (shape.source === "allButLast" || shape.source === "first") && !targetDir && !dynamicDest;
|
|
1719
|
-
if (destIsLastOperand && typeof lastOperand === "string" && matchSensitivePath2(lastOperand))
|
|
1720
|
-
return [];
|
|
1721
1772
|
let src;
|
|
1722
1773
|
switch (shape.source) {
|
|
1723
1774
|
case "all":
|
|
@@ -1727,11 +1778,17 @@ function copySourcePaths(words) {
|
|
|
1727
1778
|
src = targetDir ? args : args.slice(0, 1);
|
|
1728
1779
|
break;
|
|
1729
1780
|
case "flagOperand": {
|
|
1730
|
-
const
|
|
1781
|
+
const namesSource = (f) => {
|
|
1782
|
+
const names = shape.sourceFlags ?? [];
|
|
1783
|
+
if (f.long !== null)
|
|
1784
|
+
return names.some(
|
|
1785
|
+
(n) => n.startsWith("--") && (n === f.long || f.long.length >= 3 && n.startsWith(f.long))
|
|
1786
|
+
);
|
|
1787
|
+
return f.letter !== null && names.includes(f.letter);
|
|
1788
|
+
};
|
|
1789
|
+
const inline = tail.filter((w) => w !== null && w.startsWith("-")).map((w) => flagInfo(w)).filter((f) => f.attached !== null && namesSource(f)).map((f) => f.attached);
|
|
1731
1790
|
return [
|
|
1732
|
-
...args.filter(
|
|
1733
|
-
(a) => flagIs(a.afterFlag, shape.sourceFlags ?? []) && flagInfo(a.afterFlag).attached === null
|
|
1734
|
-
).map((a) => a.value),
|
|
1791
|
+
...args.filter((a) => !copyPastOptions(a) && operandOf(a, shape.sourceFlags, shape.valueLetters)).map((a) => a.value),
|
|
1735
1792
|
...inline
|
|
1736
1793
|
];
|
|
1737
1794
|
}
|
|
@@ -1742,7 +1799,14 @@ function copySourcePaths(words) {
|
|
|
1742
1799
|
src = targetDir || dynamicDest ? args : args.slice(0, -1);
|
|
1743
1800
|
break;
|
|
1744
1801
|
}
|
|
1745
|
-
|
|
1802
|
+
const sources = src.filter((a) => !skipped(a) && !targetOperand(a)).map((a) => a.value);
|
|
1803
|
+
if (destIsLastOperand && typeof lastOperand === "string" && matchSensitivePath2(lastOperand)) {
|
|
1804
|
+
const jailedSources = sources.filter((p) => matchSensitivePath2(p));
|
|
1805
|
+
const dirOf = (p) => /[\\/]/.test(p) ? p.replace(/[\\/][^\\/]*$/, "") : "";
|
|
1806
|
+
if (jailedSources.length === 0) return [];
|
|
1807
|
+
if (jailedSources.every((p) => dirOf(p) === dirOf(lastOperand))) return [];
|
|
1808
|
+
}
|
|
1809
|
+
return sources;
|
|
1746
1810
|
}
|
|
1747
1811
|
function archiveInputs(kind, args, tail) {
|
|
1748
1812
|
const first = args[0];
|
|
@@ -1754,13 +1818,17 @@ function archiveInputs(kind, args, tail) {
|
|
|
1754
1818
|
const writing = /[cruA]/.test(bareKey ? first.value : "") || /(^|\s)-[a-zA-Z]*[cruA]|--create|--append|--update|--concatenate/.test(flagsText);
|
|
1755
1819
|
if (extracting && !writing) return [];
|
|
1756
1820
|
void mode;
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
if (
|
|
1762
|
-
|
|
1763
|
-
|
|
1821
|
+
if (!bareKey) return args;
|
|
1822
|
+
let i = 1;
|
|
1823
|
+
const fromDirs = [];
|
|
1824
|
+
for (const ch of first.value) {
|
|
1825
|
+
if (!TAR_VALUE_LETTERS.includes(ch)) continue;
|
|
1826
|
+
const operand = args[i];
|
|
1827
|
+
if (!operand || operand.afterFlag !== null) break;
|
|
1828
|
+
i += 1;
|
|
1829
|
+
if (ch === "C") fromDirs.push(operand);
|
|
1830
|
+
}
|
|
1831
|
+
return [...fromDirs, ...args.slice(i)];
|
|
1764
1832
|
}
|
|
1765
1833
|
if (kind === "zip") return first && first.afterFlag === "-" ? args : args.slice(1);
|
|
1766
1834
|
if (kind === "ar") return bareKey ? args.slice(2) : args.slice(1);
|
|
@@ -1787,6 +1855,138 @@ function matchSensitivePath2(p) {
|
|
|
1787
1855
|
function baseWord(w) {
|
|
1788
1856
|
return (w ?? "").split("/").pop()?.toLowerCase() ?? "";
|
|
1789
1857
|
}
|
|
1858
|
+
function namesFlag(name, candidates2, known) {
|
|
1859
|
+
if (candidates2.has(name)) return true;
|
|
1860
|
+
if (!name.startsWith("--") || name.length < 3) return false;
|
|
1861
|
+
if (known?.has(name)) return false;
|
|
1862
|
+
for (const c of candidates2) if (c.startsWith(name)) return true;
|
|
1863
|
+
return false;
|
|
1864
|
+
}
|
|
1865
|
+
function knownLongFlags(verb) {
|
|
1866
|
+
const out = /* @__PURE__ */ new Set();
|
|
1867
|
+
const shape = PATTERN_VERBS[verb];
|
|
1868
|
+
if (shape) {
|
|
1869
|
+
for (const set of [shape.takesValue, shape.noValue, shape.patternFlags, shape.noPatternFlags])
|
|
1870
|
+
for (const f of set) if (f.startsWith("--")) out.add(f);
|
|
1871
|
+
}
|
|
1872
|
+
for (const f of FILE_OPERAND_FLAGS[verb] ?? []) if (f.startsWith("--")) out.add(f);
|
|
1873
|
+
return out;
|
|
1874
|
+
}
|
|
1875
|
+
function flagNamesOf(token, shape) {
|
|
1876
|
+
if (token.startsWith("--")) {
|
|
1877
|
+
const eq = token.indexOf("=");
|
|
1878
|
+
return [eq > 0 ? token.slice(0, eq) : token];
|
|
1879
|
+
}
|
|
1880
|
+
const out = [];
|
|
1881
|
+
for (const c of token.slice(1)) {
|
|
1882
|
+
const name = `-${c}`;
|
|
1883
|
+
out.push(name);
|
|
1884
|
+
if (shape?.takesValue.has(name)) break;
|
|
1885
|
+
}
|
|
1886
|
+
return out;
|
|
1887
|
+
}
|
|
1888
|
+
function flagEffect(token, shape, known) {
|
|
1889
|
+
if (token === "--") return NONE;
|
|
1890
|
+
if (/^-+$/.test(token)) return UNKNOWN;
|
|
1891
|
+
if (/^-\d+$/.test(token)) return NONE;
|
|
1892
|
+
if (token.startsWith("--")) {
|
|
1893
|
+
if (token.includes("=")) return NONE;
|
|
1894
|
+
const takes = namesFlag(token, shape.takesValue, known);
|
|
1895
|
+
const none = namesFlag(token, shape.noValue, known);
|
|
1896
|
+
if (takes && none) return UNKNOWN;
|
|
1897
|
+
if (takes) return { kind: "takes", flag: token };
|
|
1898
|
+
if (none) return NONE;
|
|
1899
|
+
return UNKNOWN;
|
|
1900
|
+
}
|
|
1901
|
+
const letters = token.slice(1);
|
|
1902
|
+
if (!letters) return NONE;
|
|
1903
|
+
for (let i = 0; i < letters.length; i++) {
|
|
1904
|
+
const name = `-${letters[i]}`;
|
|
1905
|
+
if (shape.takesValue.has(name)) {
|
|
1906
|
+
return i === letters.length - 1 ? { kind: "takes", flag: name } : NONE;
|
|
1907
|
+
}
|
|
1908
|
+
if (!shape.noValue.has(name)) return UNKNOWN;
|
|
1909
|
+
}
|
|
1910
|
+
return NONE;
|
|
1911
|
+
}
|
|
1912
|
+
function readTargets(verb, args, flags, words = [], from = 1) {
|
|
1913
|
+
const shape = PATTERN_VERBS[verb];
|
|
1914
|
+
if (!shape) return args.map((a) => a.value);
|
|
1915
|
+
const known = knownLongFlags(verb);
|
|
1916
|
+
const names = flags.flatMap((f) => flagNamesOf(f, shape));
|
|
1917
|
+
const patternElsewhere = names.some(
|
|
1918
|
+
(n) => namesFlag(n, shape.patternFlags, known) || namesFlag(n, shape.noPatternFlags, known)
|
|
1919
|
+
);
|
|
1920
|
+
const excused = /* @__PURE__ */ new Set();
|
|
1921
|
+
const fileFlags = FILE_OPERAND_FLAGS[verb];
|
|
1922
|
+
const optionsEnd = words.findIndex((w, i) => i >= from && w === "--");
|
|
1923
|
+
const pastOptions = (a) => optionsEnd >= 0 && a.argv > optionsEnd;
|
|
1924
|
+
for (const a of args) {
|
|
1925
|
+
if (a.afterFlag === null || pastOptions(a)) continue;
|
|
1926
|
+
const e = flagEffect(a.afterFlag, shape, known);
|
|
1927
|
+
if (e.kind !== "takes") continue;
|
|
1928
|
+
if (fileFlags && namesFlag(e.flag, fileFlags, known)) continue;
|
|
1929
|
+
excused.add(a);
|
|
1930
|
+
}
|
|
1931
|
+
const patternArgv = (() => {
|
|
1932
|
+
for (let i = from; i < words.length; i++) {
|
|
1933
|
+
const w = words[i];
|
|
1934
|
+
if (w === null) return -1;
|
|
1935
|
+
if (w === "--") return i + 1;
|
|
1936
|
+
if (w.startsWith("-")) {
|
|
1937
|
+
const e = flagEffect(w, shape, known);
|
|
1938
|
+
if (e.kind === "takes") i += 1;
|
|
1939
|
+
else if (e.kind === "unknown") return -1;
|
|
1940
|
+
continue;
|
|
1941
|
+
}
|
|
1942
|
+
return i;
|
|
1943
|
+
}
|
|
1944
|
+
return -1;
|
|
1945
|
+
})();
|
|
1946
|
+
if (!patternElsewhere && patternArgv >= 0) {
|
|
1947
|
+
const a = args.find((x) => x.argv === patternArgv);
|
|
1948
|
+
if (a) excused.add(a);
|
|
1949
|
+
}
|
|
1950
|
+
return args.filter((a) => !excused.has(a)).map((a) => a.value);
|
|
1951
|
+
}
|
|
1952
|
+
function flagOperandFiles(verb, words, from) {
|
|
1953
|
+
const flags = FILE_OPERAND_FLAGS[verb];
|
|
1954
|
+
if (!flags) return [];
|
|
1955
|
+
const known = knownLongFlags(verb);
|
|
1956
|
+
const out = [];
|
|
1957
|
+
for (let i = from; i < words.length; i++) {
|
|
1958
|
+
const w = words[i];
|
|
1959
|
+
if (w === null || !w.startsWith("-") || w === "--") continue;
|
|
1960
|
+
if (w.startsWith("--")) {
|
|
1961
|
+
const eq = w.indexOf("=");
|
|
1962
|
+
if (eq <= 0) continue;
|
|
1963
|
+
const name = w.slice(0, eq);
|
|
1964
|
+
const value = w.slice(eq + 1);
|
|
1965
|
+
if (!value) continue;
|
|
1966
|
+
if (namesFlag(name, flags, known)) {
|
|
1967
|
+
out.push(value);
|
|
1968
|
+
continue;
|
|
1969
|
+
}
|
|
1970
|
+
const shape2 = PATTERN_VERBS[verb];
|
|
1971
|
+
if (!shape2) continue;
|
|
1972
|
+
const recognised = namesFlag(name, shape2.takesValue, known) || namesFlag(name, shape2.noValue, known) || namesFlag(name, shape2.patternFlags, known) || namesFlag(name, shape2.noPatternFlags, known);
|
|
1973
|
+
if (!recognised) out.push(value);
|
|
1974
|
+
continue;
|
|
1975
|
+
}
|
|
1976
|
+
const shape = PATTERN_VERBS[verb];
|
|
1977
|
+
const letters = w.slice(1);
|
|
1978
|
+
for (let j = 0; j < letters.length; j++) {
|
|
1979
|
+
const name = `-${letters[j]}`;
|
|
1980
|
+
const isFileFlag = flags.has(name);
|
|
1981
|
+
const argTaking = isFileFlag || (shape?.takesValue.has(name) ?? false) || (READER_VALUE_LETTERS[verb] ?? []).includes(letters[j]);
|
|
1982
|
+
if (!argTaking) continue;
|
|
1983
|
+
const attached = letters.slice(j + 1);
|
|
1984
|
+
if (isFileFlag && attached) out.push(attached);
|
|
1985
|
+
break;
|
|
1986
|
+
}
|
|
1987
|
+
}
|
|
1988
|
+
return out;
|
|
1989
|
+
}
|
|
1790
1990
|
function wrappedReadPaths(words, name) {
|
|
1791
1991
|
if (name === "find") {
|
|
1792
1992
|
const { k, starts } = findStartPoints(words, 0);
|
|
@@ -1794,7 +1994,14 @@ function wrappedReadPaths(words, name) {
|
|
|
1794
1994
|
}
|
|
1795
1995
|
if (!COMMAND_WRAPPERS.has(name) && !RUNNER_WRAPPERS.has(name)) return null;
|
|
1796
1996
|
const h = unwrapCommandHead(words);
|
|
1797
|
-
|
|
1997
|
+
if (h <= 0 || !isReaderWord(words[h] ?? null)) return null;
|
|
1998
|
+
const head = baseWord(words[h]);
|
|
1999
|
+
const rest = words.slice(h + 1);
|
|
2000
|
+
const restFlags = rest.filter((w) => w !== null && w.startsWith("-"));
|
|
2001
|
+
return [
|
|
2002
|
+
...readTargets(head, positionedArgs(words, h + 1), restFlags, words, h + 1),
|
|
2003
|
+
...flagOperandFiles(head, words, h + 1)
|
|
2004
|
+
];
|
|
1798
2005
|
}
|
|
1799
2006
|
function literalShellPayload(words, name) {
|
|
1800
2007
|
const h = COMMAND_WRAPPERS.has(name) || RUNNER_WRAPPERS.has(name) ? unwrapCommandHead(words) : 0;
|
|
@@ -2727,6 +2934,17 @@ async function evaluatePolicy(config, toolName, args, context = {}, hooks = {})
|
|
|
2727
2934
|
function isIgnoredTool(toolName, config) {
|
|
2728
2935
|
return matchesPattern(toolName, config.policy.ignoredTools);
|
|
2729
2936
|
}
|
|
2937
|
+
function stripTerminalEscapes(s) {
|
|
2938
|
+
return s.replace(TERMINAL_ESCAPE_RE, "");
|
|
2939
|
+
}
|
|
2940
|
+
function stripControlChars(s) {
|
|
2941
|
+
return s.replace(CONTROL_CHAR_RE, "");
|
|
2942
|
+
}
|
|
2943
|
+
function safeMessage(value, max = 300) {
|
|
2944
|
+
const raw = typeof value === "string" ? value : value instanceof Error ? value.message : String(value ?? "");
|
|
2945
|
+
const s = stripTerminalEscapes(raw).replace(/\s+/g, " ").trim();
|
|
2946
|
+
return s.length > max ? s.slice(0, max - 1) + "\u2026" : s;
|
|
2947
|
+
}
|
|
2730
2948
|
function isShieldVerdict(v) {
|
|
2731
2949
|
return v === "allow" || v === "review" || v === "block";
|
|
2732
2950
|
}
|
|
@@ -2944,7 +3162,10 @@ function computeSecurityScore(opts) {
|
|
|
2944
3162
|
}
|
|
2945
3163
|
function truncateBlastPath(full) {
|
|
2946
3164
|
if (!full) return "";
|
|
2947
|
-
|
|
3165
|
+
if (full.length > MAX_BLAST_PATH) full = full.slice(-MAX_BLAST_PATH);
|
|
3166
|
+
let end = full.length;
|
|
3167
|
+
while (end > 0 && (full[end - 1] === "/" || full[end - 1] === "\\")) end--;
|
|
3168
|
+
const cleaned = full.slice(0, end);
|
|
2948
3169
|
const parts = cleaned.split(/[/\\]+/).filter((p) => p.length > 0);
|
|
2949
3170
|
if (parts.length <= 2) {
|
|
2950
3171
|
return cleaned.startsWith("~") && !cleaned.startsWith("~/") ? cleaned : cleaned.startsWith("~/") ? cleaned : parts.join("/");
|
|
@@ -3440,7 +3661,7 @@ function toScanFinding(c) {
|
|
|
3440
3661
|
}
|
|
3441
3662
|
function previewArgs(input, max) {
|
|
3442
3663
|
const cmd = input.command ?? input.query ?? input.file_path ?? JSON.stringify(input);
|
|
3443
|
-
const s = String(cmd)
|
|
3664
|
+
const s = stripTerminalEscapes(String(cmd)).replace(/\s+/g, " ").trim();
|
|
3444
3665
|
return s.length > max ? s.slice(0, max - 1) + "\u2026" : s;
|
|
3445
3666
|
}
|
|
3446
3667
|
function makeFinding(args) {
|
|
@@ -3480,7 +3701,7 @@ function* stringValues(obj, depth = 0) {
|
|
|
3480
3701
|
}
|
|
3481
3702
|
for (const v of Object.values(obj)) yield* stringValues(v, depth + 1);
|
|
3482
3703
|
}
|
|
3483
|
-
var import_safe_regex2, import_crypto3, import_mvdan_sh, import_picomatch, import_safe_regex22, import_safe_regex23, import_crypto4, IBAN_LENGTH, B58, B58_INDEX, XPRV_VERSIONS, MAX, UNTRUSTED_TOOLS, SIGNALS, ASSIGNMENT_CONTEXT_RE, DLP_STOPWORDS, DLP_PATTERNS, DLP_PATTERNS_GLOBAL, SENSITIVE_PATH_PATTERNS, MAX_DEPTH, MAX_STRING_BYTES, MAX_JSON_PARSE_BYTES, DLP_SCAN_LIMITS, 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, SQL_DB_CLIS, SQL_DDL_RE, CHMOD_OPEN_PERM_TOKENS, COMMAND_WRAPPERS, INLINE_INTERPRETER, RUNNER_WRAPPERS, _redirStdinOps, _listOps, WRAPPER_TAKES_TARGET, FIND_EXEC_FLAGS, INTERP_LEADING_TARGET, NET_BINARIES, VALUE_FLAGS, FS_OP_CACHE_MAX, fsOpCache, stripDotSlash, REDIR_TRUNCATE_OPS, REDIR_FILE_IN_OPS, REDIR_HEREDOC_OPS, FIND_OPTIONS, COPY_RULE_OF, isReaderWord, positionalAfter, DEFAULT_EGRESS_ALLOWLIST, SOURCE_COMMANDS, SINK_COMMANDS, OBFUSCATORS, SENSITIVE_PATTERNS, FLAGS_WITH_VALUES, SSRF_MAX_HOST, METADATA_ADDRESSES, STRICT_TIERS, METADATA_HOSTNAMES, v4Octets, TIER_REASON, DESTINATION_ARGS, VERDICT_RANK, SQL_DML_KEYWORDS, aws_default, bash_safe_default, docker_default, filesystem_default, github_default, k8s_default, mongodb_default, postgres_default, project_jail_default, redis_default, BUILTIN_SHIELDS, LOOP_MAX_RECORDS, FINDING_TO_SIGNAL, SCAN_SIGNAL_WEIGHTS, LOOP_THRESHOLD_FOR_WASTE, DESTRUCTIVE_OP_RE, SENSITIVE_PATH_RE, FILE_TOOLS, PII_EMAIL_RE, PII_SSN_RE, PII_PHONE_RE, PII_CC16_RE, PII_CC15_RE, PII_IBAN_RE, REALTIME_PII_PATTERNS, MAX_PII_SCAN_BYTES, 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, CANONICAL_EXTRACTOR_VERSION, DEDUPE_PREVIEW_LEN,
|
|
3704
|
+
var import_safe_regex2, import_crypto3, import_mvdan_sh, import_picomatch, import_safe_regex22, import_safe_regex23, import_crypto4, IBAN_LENGTH, B58, B58_INDEX, XPRV_VERSIONS, MAX, UNTRUSTED_TOOLS, SIGNALS, ASSIGNMENT_CONTEXT_RE, DLP_STOPWORDS, DLP_PATTERNS, DLP_PATTERNS_GLOBAL, SENSITIVE_PATH_PATTERNS, MAX_DEPTH, MAX_STRING_BYTES, MAX_JSON_PARSE_BYTES, DLP_SCAN_LIMITS, 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, SQL_DB_CLIS, SQL_DDL_RE, CHMOD_OPEN_PERM_TOKENS, COMMAND_WRAPPERS, INLINE_INTERPRETER, RUNNER_WRAPPERS, _redirStdinOps, _listOps, WRAPPER_TAKES_TARGET, FIND_EXEC_FLAGS, INTERP_LEADING_TARGET, NET_BINARIES, VALUE_FLAGS, FS_OP_CACHE_MAX, fsOpCache, stripDotSlash, REDIR_TRUNCATE_OPS, REDIR_FILE_IN_OPS, REDIR_HEREDOC_OPS, FIND_OPTIONS, COPY_RULE_OF, isReaderWord, positionalAfter, NONE, UNKNOWN, DEFAULT_EGRESS_ALLOWLIST, SOURCE_COMMANDS, SINK_COMMANDS, OBFUSCATORS, SENSITIVE_PATTERNS, FLAGS_WITH_VALUES, SSRF_MAX_HOST, METADATA_ADDRESSES, STRICT_TIERS, METADATA_HOSTNAMES, v4Octets, TIER_REASON, DESTINATION_ARGS, VERDICT_RANK, SQL_DML_KEYWORDS, TERMINAL_ESCAPE_RE, CONTROL_CHAR_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, LOOP_MAX_RECORDS, FINDING_TO_SIGNAL, SCAN_SIGNAL_WEIGHTS, LOOP_THRESHOLD_FOR_WASTE, MAX_BLAST_PATH, DESTRUCTIVE_OP_RE, SENSITIVE_PATH_RE, FILE_TOOLS, PII_EMAIL_RE, PII_SSN_RE, PII_PHONE_RE, PII_CC16_RE, PII_CC15_RE, PII_IBAN_RE, REALTIME_PII_PATTERNS, MAX_PII_SCAN_BYTES, 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, CANONICAL_EXTRACTOR_VERSION, DEDUPE_PREVIEW_LEN, ENGINE_VERSION;
|
|
3484
3705
|
var init_dist = __esm({
|
|
3485
3706
|
"packages/policy-engine/dist/index.mjs"() {
|
|
3486
3707
|
"use strict";
|
|
@@ -4223,7 +4444,345 @@ var init_dist = __esm({
|
|
|
4223
4444
|
"nl",
|
|
4224
4445
|
"dd"
|
|
4225
4446
|
]);
|
|
4447
|
+
GREP_SHAPE = {
|
|
4448
|
+
takesValue: /* @__PURE__ */ new Set([
|
|
4449
|
+
"-A",
|
|
4450
|
+
"-B",
|
|
4451
|
+
"-C",
|
|
4452
|
+
"-D",
|
|
4453
|
+
"-d",
|
|
4454
|
+
"-e",
|
|
4455
|
+
"-f",
|
|
4456
|
+
"-m",
|
|
4457
|
+
"--after-context",
|
|
4458
|
+
"--before-context",
|
|
4459
|
+
"--binary-files",
|
|
4460
|
+
"--context",
|
|
4461
|
+
"--devices",
|
|
4462
|
+
"--directories",
|
|
4463
|
+
"--exclude",
|
|
4464
|
+
"--exclude-dir",
|
|
4465
|
+
"--exclude-from",
|
|
4466
|
+
"--file",
|
|
4467
|
+
"--include",
|
|
4468
|
+
"--label",
|
|
4469
|
+
"--max-count",
|
|
4470
|
+
"--regexp"
|
|
4471
|
+
]),
|
|
4472
|
+
noValue: /* @__PURE__ */ new Set([
|
|
4473
|
+
"-E",
|
|
4474
|
+
"-F",
|
|
4475
|
+
"-G",
|
|
4476
|
+
"-P",
|
|
4477
|
+
"-i",
|
|
4478
|
+
"-y",
|
|
4479
|
+
"-v",
|
|
4480
|
+
"-V",
|
|
4481
|
+
"-w",
|
|
4482
|
+
"-x",
|
|
4483
|
+
"-c",
|
|
4484
|
+
"-l",
|
|
4485
|
+
"-L",
|
|
4486
|
+
"-o",
|
|
4487
|
+
"-q",
|
|
4488
|
+
"-s",
|
|
4489
|
+
"-b",
|
|
4490
|
+
"-H",
|
|
4491
|
+
"-h",
|
|
4492
|
+
"-n",
|
|
4493
|
+
"-T",
|
|
4494
|
+
"-Z",
|
|
4495
|
+
"-z",
|
|
4496
|
+
"-R",
|
|
4497
|
+
"-r",
|
|
4498
|
+
"-U",
|
|
4499
|
+
"-u",
|
|
4500
|
+
"-I",
|
|
4501
|
+
"-a",
|
|
4502
|
+
"--basic-regexp",
|
|
4503
|
+
"--binary",
|
|
4504
|
+
"--byte-offset",
|
|
4505
|
+
"--color",
|
|
4506
|
+
"--colour",
|
|
4507
|
+
"--count",
|
|
4508
|
+
"--dereference-recursive",
|
|
4509
|
+
"--extended-regexp",
|
|
4510
|
+
"--files-with-matches",
|
|
4511
|
+
"--files-without-match",
|
|
4512
|
+
"--fixed-strings",
|
|
4513
|
+
"--help",
|
|
4514
|
+
"--ignore-case",
|
|
4515
|
+
"--initial-tab",
|
|
4516
|
+
"--invert-match",
|
|
4517
|
+
"--line-buffered",
|
|
4518
|
+
"--line-number",
|
|
4519
|
+
"--line-regexp",
|
|
4520
|
+
"--no-filename",
|
|
4521
|
+
"--no-group-separator",
|
|
4522
|
+
"--no-ignore-case",
|
|
4523
|
+
"--no-messages",
|
|
4524
|
+
"--null",
|
|
4525
|
+
"--null-data",
|
|
4526
|
+
"--only-matching",
|
|
4527
|
+
"--perl-regexp",
|
|
4528
|
+
"--quiet",
|
|
4529
|
+
"--recursive",
|
|
4530
|
+
"--silent",
|
|
4531
|
+
"--text",
|
|
4532
|
+
"--version",
|
|
4533
|
+
"--with-filename",
|
|
4534
|
+
"--word-regexp"
|
|
4535
|
+
]),
|
|
4536
|
+
patternFlags: /* @__PURE__ */ new Set(["-e", "--regexp"]),
|
|
4537
|
+
noPatternFlags: /* @__PURE__ */ new Set(["-f", "--file"])
|
|
4538
|
+
};
|
|
4539
|
+
PATTERN_VERBS = {
|
|
4540
|
+
grep: GREP_SHAPE,
|
|
4541
|
+
// /usr/bin/egrep and /usr/bin/fgrep are 41-byte shell wrappers that exec
|
|
4542
|
+
// `grep -E` and `grep -F`. Read in full, not assumed.
|
|
4543
|
+
egrep: GREP_SHAPE,
|
|
4544
|
+
fgrep: GREP_SHAPE,
|
|
4545
|
+
// ripgrep 14.1.1, complete from its own --help. An earlier comment here said rg
|
|
4546
|
+
// was not installed on the measuring machine; it is, and that stale claim is why
|
|
4547
|
+
// this table shipped incomplete for two rounds, blocking ordinary searches like
|
|
4548
|
+
// `rg --sort-files .env src` (/code-review round 4).
|
|
4549
|
+
rg: {
|
|
4550
|
+
takesValue: /* @__PURE__ */ new Set([
|
|
4551
|
+
"-A",
|
|
4552
|
+
"-B",
|
|
4553
|
+
"-C",
|
|
4554
|
+
"-d",
|
|
4555
|
+
"-E",
|
|
4556
|
+
"-e",
|
|
4557
|
+
"-f",
|
|
4558
|
+
"-g",
|
|
4559
|
+
"-j",
|
|
4560
|
+
"-M",
|
|
4561
|
+
"-m",
|
|
4562
|
+
"-r",
|
|
4563
|
+
"-t",
|
|
4564
|
+
"-T",
|
|
4565
|
+
"--after-context",
|
|
4566
|
+
"--before-context",
|
|
4567
|
+
"--color",
|
|
4568
|
+
"--colors",
|
|
4569
|
+
"--context",
|
|
4570
|
+
"--context-separator",
|
|
4571
|
+
"--dfa-size-limit",
|
|
4572
|
+
"--encoding",
|
|
4573
|
+
"--engine",
|
|
4574
|
+
"--field-context-separator",
|
|
4575
|
+
"--field-match-separator",
|
|
4576
|
+
"--file",
|
|
4577
|
+
"--generate",
|
|
4578
|
+
"--glob",
|
|
4579
|
+
"--hostname-bin",
|
|
4580
|
+
"--hyperlink-format",
|
|
4581
|
+
"--iglob",
|
|
4582
|
+
"--ignore-file",
|
|
4583
|
+
"--max-columns",
|
|
4584
|
+
"--max-count",
|
|
4585
|
+
"--max-depth",
|
|
4586
|
+
// An ALIAS of --max-depth, and it takes a value. The round-5 extraction read
|
|
4587
|
+
// alias lines as plain switches and swept it into noValue, which hard-blocked
|
|
4588
|
+
// `rg --maxdepth 2 .env src` while `--max-depth 2` ran (/code-review round 7).
|
|
4589
|
+
"--maxdepth",
|
|
4590
|
+
"--max-filesize",
|
|
4591
|
+
"--path-separator",
|
|
4592
|
+
"--pre",
|
|
4593
|
+
"--pre-glob",
|
|
4594
|
+
"--regexp",
|
|
4595
|
+
"--regex-size-limit",
|
|
4596
|
+
"--replace",
|
|
4597
|
+
"--sort",
|
|
4598
|
+
"--sortr",
|
|
4599
|
+
"--threads",
|
|
4600
|
+
"--type",
|
|
4601
|
+
"--type-add",
|
|
4602
|
+
"--type-clear",
|
|
4603
|
+
"--type-not"
|
|
4604
|
+
]),
|
|
4605
|
+
noValue: /* @__PURE__ */ new Set([
|
|
4606
|
+
"-.",
|
|
4607
|
+
"-0",
|
|
4608
|
+
"-a",
|
|
4609
|
+
"-b",
|
|
4610
|
+
"-c",
|
|
4611
|
+
"-F",
|
|
4612
|
+
"-h",
|
|
4613
|
+
"-H",
|
|
4614
|
+
"-i",
|
|
4615
|
+
"-I",
|
|
4616
|
+
"-l",
|
|
4617
|
+
"-L",
|
|
4618
|
+
"-n",
|
|
4619
|
+
"-N",
|
|
4620
|
+
"-o",
|
|
4621
|
+
"-p",
|
|
4622
|
+
"-P",
|
|
4623
|
+
"-q",
|
|
4624
|
+
"-s",
|
|
4625
|
+
"-S",
|
|
4626
|
+
"-u",
|
|
4627
|
+
"-U",
|
|
4628
|
+
"-v",
|
|
4629
|
+
"-V",
|
|
4630
|
+
"-w",
|
|
4631
|
+
"-x",
|
|
4632
|
+
"-z",
|
|
4633
|
+
"--auto-hybrid-regex",
|
|
4634
|
+
"--binary",
|
|
4635
|
+
"--block-buffered",
|
|
4636
|
+
"--byte-offset",
|
|
4637
|
+
"--case-sensitive",
|
|
4638
|
+
"--column",
|
|
4639
|
+
"--count",
|
|
4640
|
+
"--count-matches",
|
|
4641
|
+
"--crlf",
|
|
4642
|
+
"--debug",
|
|
4643
|
+
"--files",
|
|
4644
|
+
"--files-with-matches",
|
|
4645
|
+
"--files-without-match",
|
|
4646
|
+
"--fixed-strings",
|
|
4647
|
+
"--follow",
|
|
4648
|
+
"--glob-case-insensitive",
|
|
4649
|
+
"--heading",
|
|
4650
|
+
"--help",
|
|
4651
|
+
"--hidden",
|
|
4652
|
+
"--ignore-case",
|
|
4653
|
+
"--ignore-file-case-insensitive",
|
|
4654
|
+
"--include-zero",
|
|
4655
|
+
"--invert-match",
|
|
4656
|
+
"--json",
|
|
4657
|
+
"--line-buffered",
|
|
4658
|
+
"--line-number",
|
|
4659
|
+
"--line-regexp",
|
|
4660
|
+
"--max-columns-preview",
|
|
4661
|
+
"--mmap",
|
|
4662
|
+
"--multiline",
|
|
4663
|
+
"--multiline-dotall",
|
|
4664
|
+
"--no-column",
|
|
4665
|
+
"--no-config",
|
|
4666
|
+
"--no-context-separator",
|
|
4667
|
+
"--no-encoding",
|
|
4668
|
+
"--no-filename",
|
|
4669
|
+
"--no-ignore",
|
|
4670
|
+
"--no-ignore-dot",
|
|
4671
|
+
"--no-ignore-exclude",
|
|
4672
|
+
"--no-ignore-files",
|
|
4673
|
+
"--no-ignore-global",
|
|
4674
|
+
"--no-ignore-messages",
|
|
4675
|
+
"--no-ignore-parent",
|
|
4676
|
+
"--no-ignore-vcs",
|
|
4677
|
+
"--no-line-number",
|
|
4678
|
+
"--no-messages",
|
|
4679
|
+
"--no-pcre2-unicode",
|
|
4680
|
+
"--no-pre",
|
|
4681
|
+
"--no-require-git",
|
|
4682
|
+
"--no-unicode",
|
|
4683
|
+
"--null",
|
|
4684
|
+
"--null-data",
|
|
4685
|
+
"--one-file-system",
|
|
4686
|
+
"--only-matching",
|
|
4687
|
+
"--passthru",
|
|
4688
|
+
"--pcre2",
|
|
4689
|
+
"--pcre2-version",
|
|
4690
|
+
"--pretty",
|
|
4691
|
+
"--print0",
|
|
4692
|
+
"--quiet",
|
|
4693
|
+
"--search-zip",
|
|
4694
|
+
"--smart-case",
|
|
4695
|
+
"--sort-files",
|
|
4696
|
+
"--stats",
|
|
4697
|
+
"--stop-on-nonmatch",
|
|
4698
|
+
"--text",
|
|
4699
|
+
"--trace",
|
|
4700
|
+
"--trim",
|
|
4701
|
+
"--type-list",
|
|
4702
|
+
"--unrestricted",
|
|
4703
|
+
"--version",
|
|
4704
|
+
"--vimgrep",
|
|
4705
|
+
"--with-filename",
|
|
4706
|
+
"--word-regexp",
|
|
4707
|
+
// The COMPLETE remainder of `rg --help`, added after /code-review round 5
|
|
4708
|
+
// found 40 documented switches in neither set. The table is now the whole
|
|
4709
|
+
// option list: `rg --help` yields 149 long options, 35 of them value-taking.
|
|
4710
|
+
"--ignore",
|
|
4711
|
+
"--ignore-dot",
|
|
4712
|
+
"--ignore-exclude",
|
|
4713
|
+
"--ignore-files",
|
|
4714
|
+
"--ignore-global",
|
|
4715
|
+
"--ignore-messages",
|
|
4716
|
+
"--ignore-parent",
|
|
4717
|
+
"--ignore-vcs",
|
|
4718
|
+
"--messages",
|
|
4719
|
+
"--no-auto-hybrid-regex",
|
|
4720
|
+
"--no-binary",
|
|
4721
|
+
"--no-block-buffered",
|
|
4722
|
+
"--no-byte-offset",
|
|
4723
|
+
"--no-crlf",
|
|
4724
|
+
"--no-fixed-strings",
|
|
4725
|
+
"--no-follow",
|
|
4726
|
+
"--no-glob-case-insensitive",
|
|
4727
|
+
"--no-heading",
|
|
4728
|
+
"--no-hidden",
|
|
4729
|
+
"--no-ignore-file-case-insensitive",
|
|
4730
|
+
"--no-include-zero",
|
|
4731
|
+
"--no-invert-match",
|
|
4732
|
+
"--no-json",
|
|
4733
|
+
"--no-line-buffered",
|
|
4734
|
+
"--no-max-columns-preview",
|
|
4735
|
+
"--no-mmap",
|
|
4736
|
+
"--no-multiline",
|
|
4737
|
+
"--no-multiline-dotall",
|
|
4738
|
+
"--no-one-file-system",
|
|
4739
|
+
"--no-pcre2",
|
|
4740
|
+
"--no-search-zip",
|
|
4741
|
+
"--no-sort-files",
|
|
4742
|
+
"--no-stats",
|
|
4743
|
+
"--no-text",
|
|
4744
|
+
"--no-trim",
|
|
4745
|
+
"--passthrough",
|
|
4746
|
+
"--pcre2-unicode",
|
|
4747
|
+
"--require-git",
|
|
4748
|
+
"--unicode"
|
|
4749
|
+
]),
|
|
4750
|
+
patternFlags: /* @__PURE__ */ new Set(["-e", "--regexp"]),
|
|
4751
|
+
// `--files` and `--type-list` list or enumerate without a pattern. Founder
|
|
4752
|
+
// decision 2026-09-13: `rg --files ~/.ssh` stays BLOCKED, which this achieves
|
|
4753
|
+
// by leaving the directory in the judged list.
|
|
4754
|
+
noPatternFlags: /* @__PURE__ */ new Set(["-f", "--file", "--files", "--type-list", "--pcre2-version"])
|
|
4755
|
+
}
|
|
4756
|
+
};
|
|
4757
|
+
PATTERN_VERB_NAMES = Object.keys(PATTERN_VERBS);
|
|
4758
|
+
GREP_FILE_OPERANDS = /* @__PURE__ */ new Set(["-f", "--file", "--exclude-from", "--include"]);
|
|
4759
|
+
READER_VALUE_LETTERS = {
|
|
4760
|
+
awk: ["F", "v", "f"],
|
|
4761
|
+
gawk: ["F", "v", "f", "e", "E", "i", "l", "o", "p", "D"],
|
|
4762
|
+
sed: ["e", "f", "i", "l"],
|
|
4763
|
+
sort: ["C", "k", "o", "S", "t", "T"]
|
|
4764
|
+
};
|
|
4765
|
+
FILE_OPERAND_FLAGS = {
|
|
4766
|
+
grep: GREP_FILE_OPERANDS,
|
|
4767
|
+
egrep: GREP_FILE_OPERANDS,
|
|
4768
|
+
fgrep: GREP_FILE_OPERANDS,
|
|
4769
|
+
// rg and gawk are NOT installed on the measuring machine: these two rows are
|
|
4770
|
+
// from the shipped documentation (ripgrep `-f/--file`, `--ignore-file`; gawk
|
|
4771
|
+
// `-f/--file`) and are marked as such in the spec.
|
|
4772
|
+
// `-g/--glob/--iglob` name which files ripgrep SEARCHES, so an operand naming
|
|
4773
|
+
// a credential makes rg open it -- the same reason grep's `--include` is here.
|
|
4774
|
+
// Measured (/code-review round 3): `rg --hidden -g .env AWS tree` opened .env
|
|
4775
|
+
// and printed its contents.
|
|
4776
|
+
rg: /* @__PURE__ */ new Set(["-f", "--file", "--ignore-file", "-g", "--glob", "--iglob"]),
|
|
4777
|
+
sed: /* @__PURE__ */ new Set(["-f", "--file"]),
|
|
4778
|
+
awk: /* @__PURE__ */ new Set(["-f", "--file"]),
|
|
4779
|
+
gawk: /* @__PURE__ */ new Set(["-f", "--file"]),
|
|
4780
|
+
sort: /* @__PURE__ */ new Set(["--files0-from"])
|
|
4781
|
+
};
|
|
4226
4782
|
SCP_VALUE_FLAGS = ["i", "F", "o", "c", "S", "P", "J", "D", "W", "l"];
|
|
4783
|
+
TAR_VALUE_LETTERS = ["b", "C", "f", "F", "g", "H", "I", "K", "L", "N", "T", "V", "X"];
|
|
4784
|
+
ZIP_VALUE_LETTERS = ["b", "n", "P", "t", "s", "O", "x", "i"];
|
|
4785
|
+
RSYNC_VALUE_LETTERS = ["e", "f", "T", "B", "M"];
|
|
4227
4786
|
RSYNC_SKIP = [
|
|
4228
4787
|
"e",
|
|
4229
4788
|
"--rsh",
|
|
@@ -4235,21 +4794,35 @@ var init_dist = __esm({
|
|
|
4235
4794
|
"f",
|
|
4236
4795
|
"--filter"
|
|
4237
4796
|
];
|
|
4797
|
+
CP_VALUE_LETTERS = ["S", "t"];
|
|
4798
|
+
INSTALL_VALUE_LETTERS = ["S", "t", "g", "m", "o"];
|
|
4238
4799
|
COPY_VERBS = {
|
|
4239
|
-
cp: { source: "allButLast", targetDirFlag: true },
|
|
4240
|
-
mv: { source: "allButLast", targetDirFlag: true },
|
|
4241
|
-
install: { source: "allButLast", targetDirFlag: true },
|
|
4242
|
-
ln: { source: "first", targetDirFlag: true },
|
|
4243
|
-
scp: { source: "allButLast", skipFlags: SCP_VALUE_FLAGS },
|
|
4244
|
-
rsync: { source: "allButLast", skipFlags: RSYNC_SKIP },
|
|
4800
|
+
cp: { source: "allButLast", targetDirFlag: true, valueLetters: CP_VALUE_LETTERS },
|
|
4801
|
+
mv: { source: "allButLast", targetDirFlag: true, valueLetters: CP_VALUE_LETTERS },
|
|
4802
|
+
install: { source: "allButLast", targetDirFlag: true, valueLetters: INSTALL_VALUE_LETTERS },
|
|
4803
|
+
ln: { source: "first", targetDirFlag: true, valueLetters: CP_VALUE_LETTERS },
|
|
4804
|
+
scp: { source: "allButLast", skipFlags: SCP_VALUE_FLAGS, valueLetters: SCP_VALUE_FLAGS },
|
|
4805
|
+
rsync: { source: "allButLast", skipFlags: RSYNC_SKIP, valueLetters: RSYNC_VALUE_LETTERS },
|
|
4245
4806
|
tar: {
|
|
4246
4807
|
source: "archive",
|
|
4247
4808
|
archive: "tar",
|
|
4248
|
-
skipFlags: ["f", "X", "T", "--file", "--exclude", "--exclude-from", "--files-from"]
|
|
4809
|
+
skipFlags: ["f", "X", "T", "--file", "--exclude", "--exclude-from", "--files-from"],
|
|
4810
|
+
valueLetters: TAR_VALUE_LETTERS
|
|
4811
|
+
},
|
|
4812
|
+
zip: {
|
|
4813
|
+
source: "archive",
|
|
4814
|
+
archive: "zip",
|
|
4815
|
+
skipFlags: ["x", "i", "--exclude", "--include"],
|
|
4816
|
+
valueLetters: ZIP_VALUE_LETTERS
|
|
4249
4817
|
},
|
|
4250
|
-
zip: { source: "archive", archive: "zip", skipFlags: ["x", "i", "--exclude", "--include"] },
|
|
4251
4818
|
ar: { source: "archive", archive: "ar" },
|
|
4252
|
-
|
|
4819
|
+
// 7z switches are INLINE only (`-mx9`, `-px`, `-x!pat`), so no following word is
|
|
4820
|
+
// ever a switch's operand -- which is why the short `x` is NOT a skipFlag here
|
|
4821
|
+
// and valueLetters is empty. Keeping the short `x` made `7z a out.7z -mx KEY`
|
|
4822
|
+
// drop the credential as an exclusion operand (/code-review round 8), and the
|
|
4823
|
+
// derived "every skipped letter is a value letter" row in jail-copy.spec.ts is
|
|
4824
|
+
// what keeps the two tables honest about it.
|
|
4825
|
+
"7z": { source: "archive", archive: "7z", skipFlags: ["--exclude"], valueLetters: [] },
|
|
4253
4826
|
gzip: { source: "all" },
|
|
4254
4827
|
bzip2: { source: "all" },
|
|
4255
4828
|
xz: { source: "all" },
|
|
@@ -4571,6 +5144,8 @@ var init_dist = __esm({
|
|
|
4571
5144
|
};
|
|
4572
5145
|
isReaderWord = (w) => w !== null && FS_READ_TOOLS.has(baseWord(w));
|
|
4573
5146
|
positionalAfter = (words, from, to = words.length) => positionedArgs(words, from, to).map((a) => a.value);
|
|
5147
|
+
NONE = { kind: "none" };
|
|
5148
|
+
UNKNOWN = { kind: "unknown" };
|
|
4574
5149
|
DEFAULT_EGRESS_ALLOWLIST = [
|
|
4575
5150
|
// node9's own control plane (api, app, dev-api, staging and the apex).
|
|
4576
5151
|
// Without it, turning egress on asks the user to approve node9 itself.
|
|
@@ -4760,6 +5335,8 @@ var init_dist = __esm({
|
|
|
4760
5335
|
block: 2
|
|
4761
5336
|
};
|
|
4762
5337
|
SQL_DML_KEYWORDS = /* @__PURE__ */ new Set(["select", "insert", "update", "delete", "merge", "upsert"]);
|
|
5338
|
+
TERMINAL_ESCAPE_RE = /\x1b\[[0-9;?]*[A-Za-z]|\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)|\x1b[@-_]|[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g;
|
|
5339
|
+
CONTROL_CHAR_RE = /[\x00-\x1F\x7F]/g;
|
|
4763
5340
|
aws_default = {
|
|
4764
5341
|
name: "aws",
|
|
4765
5342
|
description: "Protects AWS infrastructure from destructive AI operations",
|
|
@@ -5537,6 +6114,7 @@ var init_dist = __esm({
|
|
|
5537
6114
|
longOutputRedactions: 1
|
|
5538
6115
|
};
|
|
5539
6116
|
LOOP_THRESHOLD_FOR_WASTE = 3;
|
|
6117
|
+
MAX_BLAST_PATH = 4096;
|
|
5540
6118
|
DESTRUCTIVE_OP_RE = /\brm\s+-[rRf]+\b|\bDROP\s+(TABLE|DATABASE|COLLECTION|SCHEMA)\b|\bTRUNCATE\s+TABLE\b|\bgit\s+push\s+(--force|-f)\b|\bFLUSHALL\b|\bFLUSHDB\b|\bkubectl\s+delete\b|\bhelm\s+uninstall\b/i;
|
|
5541
6119
|
SENSITIVE_PATH_RE = /[\\/]\.aws(?:[\\/]|$)|^\.aws[\\/]|[\\/]\.ssh(?:[\\/]|$)|^\.ssh[\\/]|(?:^|[\\/])\.env(?![\w-])(?:[\w.-]*\.local$|(?!\.(?:example|sample|template)\b)(?!\.test$)[\w.-]*$)|\.config\/gcloud\/credentials\.db\b|\.docker\/config\.json\b|\.netrc\b|\.npmrc\b|\.node9\/credentials\.json\b/i;
|
|
5542
6120
|
FILE_TOOLS = /* @__PURE__ */ new Set([
|
|
@@ -5615,10 +6193,8 @@ var init_dist = __esm({
|
|
|
5615
6193
|
{ view: "separators-stripped", decoder: "separators", stripped: true }
|
|
5616
6194
|
];
|
|
5617
6195
|
LONG_OUTPUT_THRESHOLD_BYTES = 100 * 1024;
|
|
5618
|
-
CANONICAL_EXTRACTOR_VERSION = "canonical-
|
|
6196
|
+
CANONICAL_EXTRACTOR_VERSION = "canonical-v15";
|
|
5619
6197
|
DEDUPE_PREVIEW_LEN = 120;
|
|
5620
|
-
TERMINAL_ESCAPE_RE = // eslint-disable-next-line no-control-regex
|
|
5621
|
-
/\x1b\[[0-9;?]*[A-Za-z]|\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)|\x1b[@-_]|[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g;
|
|
5622
6198
|
ENGINE_VERSION = "1.4.0";
|
|
5623
6199
|
}
|
|
5624
6200
|
});
|
|
@@ -8167,6 +8743,14 @@ var init_context_sniper = __esm({
|
|
|
8167
8743
|
}
|
|
8168
8744
|
});
|
|
8169
8745
|
|
|
8746
|
+
// src/utils/safe-text.ts
|
|
8747
|
+
var init_safe_text = __esm({
|
|
8748
|
+
"src/utils/safe-text.ts"() {
|
|
8749
|
+
"use strict";
|
|
8750
|
+
init_dist();
|
|
8751
|
+
}
|
|
8752
|
+
});
|
|
8753
|
+
|
|
8170
8754
|
// src/ui/native.ts
|
|
8171
8755
|
function resolveNativeDecision(opts) {
|
|
8172
8756
|
const { code, output, elapsedMs, locked } = opts;
|
|
@@ -8276,7 +8860,7 @@ function escapePango(text) {
|
|
|
8276
8860
|
function buildPlainMessage(toolName, formattedArgs, agent, explainableLabel, locked, allowCount = 1, ruleDescription) {
|
|
8277
8861
|
const lines = [];
|
|
8278
8862
|
if (locked) lines.push("\u26A0\uFE0F LOCKED BY ADMIN POLICY\n");
|
|
8279
|
-
const safeAgent = (agent ?? "AI Agent"
|
|
8863
|
+
const safeAgent = safeMessage(agent ?? "AI Agent", 80);
|
|
8280
8864
|
lines.push(`\u{1F916} ${safeAgent} | \u{1F527} ${toolName}`);
|
|
8281
8865
|
lines.push(`\u{1F6E1}\uFE0F ${explainableLabel || "Security Policy"}`);
|
|
8282
8866
|
if (ruleDescription) lines.push(`\u2139 ${ruleDescription}`);
|
|
@@ -8413,6 +8997,7 @@ var init_native = __esm({
|
|
|
8413
8997
|
import_child_process = require("child_process");
|
|
8414
8998
|
import_path11 = __toESM(require("path"));
|
|
8415
8999
|
init_context_sniper();
|
|
9000
|
+
init_safe_text();
|
|
8416
9001
|
isTestEnv = () => {
|
|
8417
9002
|
return process.env.NODE_ENV === "test" || process.env.VITEST === "true" || !!process.env.VITEST || process.env.CI === "true" || !!process.env.CI || process.env.NODE9_TESTING === "1";
|
|
8418
9003
|
};
|
|
@@ -8799,14 +9384,14 @@ async function resolveNode9SaaS(requestId, creds, approved, decidedBy) {
|
|
|
8799
9384
|
if (!res.ok) {
|
|
8800
9385
|
import_fs12.default.appendFileSync(
|
|
8801
9386
|
HOOK_DEBUG_LOG,
|
|
8802
|
-
`[resolve-cloud] PATCH ${resolveUrl} \u2192 HTTP ${res.status}
|
|
9387
|
+
`[resolve-cloud] PATCH ${safeMessage(resolveUrl, 200)} \u2192 HTTP ${res.status}
|
|
8803
9388
|
`
|
|
8804
9389
|
);
|
|
8805
9390
|
}
|
|
8806
9391
|
} catch (err2) {
|
|
8807
9392
|
import_fs12.default.appendFileSync(
|
|
8808
9393
|
HOOK_DEBUG_LOG,
|
|
8809
|
-
`[resolve-cloud] PATCH failed for ${requestId}: ${err2
|
|
9394
|
+
`[resolve-cloud] PATCH failed for ${safeMessage(requestId, 64)}: ${safeMessage(err2)}
|
|
8810
9395
|
`
|
|
8811
9396
|
);
|
|
8812
9397
|
}
|
|
@@ -8819,6 +9404,7 @@ var init_cloud = __esm({
|
|
|
8819
9404
|
import_os11 = __toESM(require("os"));
|
|
8820
9405
|
import_path14 = __toESM(require("path"));
|
|
8821
9406
|
init_audit();
|
|
9407
|
+
init_safe_text();
|
|
8822
9408
|
DLP_SAMPLE_MAX_LEN = 200;
|
|
8823
9409
|
DLP_PATTERN_MAX_LEN = 100;
|
|
8824
9410
|
KNOWN_CHECKED_BY = /* @__PURE__ */ new Set([
|
|
@@ -8951,9 +9537,8 @@ async function authorizeHeadless(toolName, args, meta, options) {
|
|
|
8951
9537
|
if (!options?.calledFromDaemon) {
|
|
8952
9538
|
const actId = (0, import_crypto7.randomUUID)();
|
|
8953
9539
|
const actTs = Date.now();
|
|
8954
|
-
const
|
|
8955
|
-
const
|
|
8956
|
-
const sanitizedMcpServer = meta?.mcpServer ? stripAnsi2(meta.mcpServer).slice(0, 40) : void 0;
|
|
9540
|
+
const sanitizedAgent = meta?.agent ? safeMessage(meta.agent, 80) : void 0;
|
|
9541
|
+
const sanitizedMcpServer = meta?.mcpServer ? safeMessage(meta.mcpServer, 40) : void 0;
|
|
8957
9542
|
const socketOk = await notifyActivity({
|
|
8958
9543
|
id: actId,
|
|
8959
9544
|
ts: actTs,
|
|
@@ -9829,6 +10414,7 @@ var init_orchestrator = __esm({
|
|
|
9829
10414
|
init_loop_detector();
|
|
9830
10415
|
init_shields();
|
|
9831
10416
|
init_jail();
|
|
10417
|
+
init_safe_text();
|
|
9832
10418
|
WRITE_TOOLS = /* @__PURE__ */ new Set([
|
|
9833
10419
|
"write",
|
|
9834
10420
|
"write_file",
|
|
@@ -14434,7 +15020,7 @@ async function postCostBatches(apiUrl, apiKey, machineId, entries) {
|
|
|
14434
15020
|
}
|
|
14435
15021
|
}
|
|
14436
15022
|
} catch (err2) {
|
|
14437
|
-
import_fs24.default.appendFileSync(HOOK_DEBUG_LOG, `[cost-sync] ${err2
|
|
15023
|
+
import_fs24.default.appendFileSync(HOOK_DEBUG_LOG, `[cost-sync] ${safeMessage(err2)}
|
|
14438
15024
|
`);
|
|
14439
15025
|
}
|
|
14440
15026
|
}
|
|
@@ -14476,6 +15062,7 @@ var init_costSync = __esm({
|
|
|
14476
15062
|
init_cost_gemini();
|
|
14477
15063
|
init_cost_copilot();
|
|
14478
15064
|
init_session_files();
|
|
15065
|
+
init_safe_text();
|
|
14479
15066
|
SYNC_INTERVAL_MS = 10 * 60 * 1e3;
|
|
14480
15067
|
claudeSource = {
|
|
14481
15068
|
id: "claude",
|
|
@@ -15306,9 +15893,6 @@ function fmtTs(ts) {
|
|
|
15306
15893
|
return ts.slice(0, 10);
|
|
15307
15894
|
}
|
|
15308
15895
|
}
|
|
15309
|
-
function stripTerminalEscapes(s) {
|
|
15310
|
-
return s.replace(TERMINAL_ESCAPE_RE2, "");
|
|
15311
|
-
}
|
|
15312
15896
|
function preview(input, max) {
|
|
15313
15897
|
const cmd = input.command ?? input.query ?? input.file_path ?? JSON.stringify(input);
|
|
15314
15898
|
const s = stripTerminalEscapes(String(cmd)).replace(/\s+/g, " ").trim();
|
|
@@ -18023,7 +18607,7 @@ function registerScanCommand(program2) {
|
|
|
18023
18607
|
}
|
|
18024
18608
|
);
|
|
18025
18609
|
}
|
|
18026
|
-
var import_chalk6, import_fs27, import_path29, import_os26, import_string_width2, toolInspectionMap, CODE_EXTENSIONS, SELF_OUTPUT_MARKERS,
|
|
18610
|
+
var import_chalk6, import_fs27, import_path29, import_os26, import_string_width2, toolInspectionMap, CODE_EXTENSIONS, SELF_OUTPUT_MARKERS, LOOP_TOOLS, LOOP_THRESHOLD, LOOP_TIMESPAN_THRESHOLD_MS, STUCK_TOOLS_MIN_WASTE, STUCK_TOOLS_LIMIT, RECURRING_SESSION_THRESHOLD, STALE_AGE_DAYS, classifyRuleSeverity2, narrativeRuleLabel2;
|
|
18027
18611
|
var init_scan = __esm({
|
|
18028
18612
|
"src/cli/commands/scan.ts"() {
|
|
18029
18613
|
"use strict";
|
|
@@ -18054,6 +18638,7 @@ var init_scan = __esm({
|
|
|
18054
18638
|
init_scan_json();
|
|
18055
18639
|
init_session_files();
|
|
18056
18640
|
init_scan_history();
|
|
18641
|
+
init_safe_text();
|
|
18057
18642
|
toolInspectionMap = DEFAULT_CONFIG.policy.toolInspection;
|
|
18058
18643
|
CODE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
18059
18644
|
".ts",
|
|
@@ -18088,7 +18673,6 @@ var init_scan = __esm({
|
|
|
18088
18673
|
/\bseverity:\s*['"](?:block|review|allow)['"]/,
|
|
18089
18674
|
/NODE9 SECURITY ALERT/
|
|
18090
18675
|
];
|
|
18091
|
-
TERMINAL_ESCAPE_RE2 = /\x1b\[[0-9;?]*[A-Za-z]|\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)|\x1b[@-_]|[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g;
|
|
18092
18676
|
LOOP_TOOLS = /* @__PURE__ */ new Set([
|
|
18093
18677
|
"bash",
|
|
18094
18678
|
"execute_bash",
|
|
@@ -18574,7 +19158,7 @@ function atomicWriteSync2(filePath, data, options) {
|
|
|
18574
19158
|
function redactArgs(value) {
|
|
18575
19159
|
if (!value || typeof value !== "object") return value;
|
|
18576
19160
|
if (Array.isArray(value)) return value.map(redactArgs);
|
|
18577
|
-
const result =
|
|
19161
|
+
const result = /* @__PURE__ */ Object.create(null);
|
|
18578
19162
|
for (const [k, v] of Object.entries(value)) {
|
|
18579
19163
|
result[k] = SECRET_KEY_RE.test(k) ? "[REDACTED]" : redactArgs(v);
|
|
18580
19164
|
}
|
|
@@ -22930,7 +23514,7 @@ data: ${JSON.stringify(item.data)}
|
|
|
22930
23514
|
if (req.method === "GET" && pathname === "/state/check") {
|
|
22931
23515
|
const predicatesParam = reqUrl.searchParams.get("predicates") ?? "";
|
|
22932
23516
|
const predicates = predicatesParam.split(",").filter(Boolean);
|
|
22933
|
-
const results =
|
|
23517
|
+
const results = /* @__PURE__ */ Object.create(null);
|
|
22934
23518
|
for (const p of predicates) {
|
|
22935
23519
|
results[p] = sessionHistory.checkPredicate(p);
|
|
22936
23520
|
}
|
|
@@ -50666,7 +51250,7 @@ async function startTail(options = {}) {
|
|
|
50666
51250
|
req.on("error", (err2) => {
|
|
50667
51251
|
const msg = err2.code === "ECONNREFUSED" ? "Daemon is not running. Start it with: node9 daemon start" : err2.message;
|
|
50668
51252
|
console.error(import_chalk44.default.red(`
|
|
50669
|
-
\u274C ${msg}`));
|
|
51253
|
+
\u274C ${safeMessage(msg)}`));
|
|
50670
51254
|
process.exit(1);
|
|
50671
51255
|
});
|
|
50672
51256
|
}
|
|
@@ -50684,6 +51268,7 @@ var init_tail = __esm({
|
|
|
50684
51268
|
init_startup_log();
|
|
50685
51269
|
init_daemon2();
|
|
50686
51270
|
init_daemon();
|
|
51271
|
+
init_safe_text();
|
|
50687
51272
|
PID_FILE = import_path70.default.join(import_os62.default.homedir(), ".node9", "daemon.pid");
|
|
50688
51273
|
ICONS = {
|
|
50689
51274
|
bash: "\u{1F4BB}",
|
|
@@ -51330,9 +51915,7 @@ function shellInvocation(command) {
|
|
|
51330
51915
|
}
|
|
51331
51916
|
|
|
51332
51917
|
// src/proxy/index.ts
|
|
51333
|
-
|
|
51334
|
-
return value.replace(/[\x00-\x1F\x7F]/g, "");
|
|
51335
|
-
}
|
|
51918
|
+
init_safe_text();
|
|
51336
51919
|
async function runProxy(targetCommand) {
|
|
51337
51920
|
const commandParts = (0, import_execa2.parseCommandString)(targetCommand);
|
|
51338
51921
|
const cmd = commandParts[0];
|
|
@@ -51368,7 +51951,7 @@ async function runProxy(targetCommand) {
|
|
|
51368
51951
|
try {
|
|
51369
51952
|
const name = message.params?.name || message.params?.tool_name || "unknown";
|
|
51370
51953
|
const toolArgs = message.params?.arguments || message.params?.tool_input || {};
|
|
51371
|
-
const result = await authorizeHeadless(
|
|
51954
|
+
const result = await authorizeHeadless(stripControlChars(name), toolArgs, {
|
|
51372
51955
|
agent: "Proxy/MCP"
|
|
51373
51956
|
});
|
|
51374
51957
|
if (!result.approved) {
|
|
@@ -51616,17 +52199,27 @@ init_machine_id();
|
|
|
51616
52199
|
|
|
51617
52200
|
// src/utils/open-browser.ts
|
|
51618
52201
|
var import_child_process6 = require("child_process");
|
|
52202
|
+
function isOpenableUrl(url) {
|
|
52203
|
+
let u;
|
|
52204
|
+
try {
|
|
52205
|
+
u = new URL(url);
|
|
52206
|
+
} catch {
|
|
52207
|
+
return false;
|
|
52208
|
+
}
|
|
52209
|
+
if (u.protocol !== "https:" && u.protocol !== "http:") return false;
|
|
52210
|
+
return !/[\x00-\x20\x7F"'`]/.test(url);
|
|
52211
|
+
}
|
|
51619
52212
|
function openBrowser(url) {
|
|
52213
|
+
if (!isOpenableUrl(url)) return false;
|
|
51620
52214
|
if (process.env.SSH_CONNECTION || process.env.SSH_TTY) return false;
|
|
51621
52215
|
if (process.platform === "linux" && !process.env.DISPLAY && !process.env.WAYLAND_DISPLAY) {
|
|
51622
52216
|
return false;
|
|
51623
52217
|
}
|
|
51624
|
-
const
|
|
52218
|
+
const [cmd, args] = process.platform === "darwin" ? ["open", [url]] : process.platform === "win32" ? ["rundll32.exe", ["url.dll,FileProtocolHandler", url]] : ["xdg-open", [url]];
|
|
51625
52219
|
try {
|
|
51626
|
-
const child = (0, import_child_process6.spawn)(
|
|
52220
|
+
const child = (0, import_child_process6.spawn)(cmd, args, {
|
|
51627
52221
|
stdio: "ignore",
|
|
51628
|
-
detached: true
|
|
51629
|
-
shell: process.platform === "win32"
|
|
52222
|
+
detached: true
|
|
51630
52223
|
});
|
|
51631
52224
|
child.on("error", () => {
|
|
51632
52225
|
});
|
|
@@ -51687,6 +52280,7 @@ function postJson2(url, body, bearer) {
|
|
|
51687
52280
|
}
|
|
51688
52281
|
|
|
51689
52282
|
// src/auth/device-login.ts
|
|
52283
|
+
init_safe_text();
|
|
51690
52284
|
var sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
51691
52285
|
async function runDeviceLogin(opts = {}) {
|
|
51692
52286
|
const startUrl = resolveCloudEndpoint("/device/start", opts.apiUrl);
|
|
@@ -51702,14 +52296,16 @@ async function runDeviceLogin(opts = {}) {
|
|
|
51702
52296
|
} catch (e) {
|
|
51703
52297
|
return {
|
|
51704
52298
|
ok: false,
|
|
51705
|
-
reason: `Could not reach the node9 cloud: ${
|
|
52299
|
+
reason: `Could not reach the node9 cloud: ${safeMessage(e)}`
|
|
51706
52300
|
};
|
|
51707
52301
|
}
|
|
51708
52302
|
console.log("");
|
|
51709
52303
|
console.log(` Open this link to approve the connection:`);
|
|
51710
|
-
console.log(` ${import_chalk11.default.cyan.underline(start.verificationUrl)}`);
|
|
52304
|
+
console.log(` ${import_chalk11.default.cyan.underline(safeMessage(start.verificationUrl, 200))}`);
|
|
51711
52305
|
console.log("");
|
|
51712
|
-
console.log(
|
|
52306
|
+
console.log(
|
|
52307
|
+
` Code: ${import_chalk11.default.bold(safeMessage(start.userCode, 40))} ${import_chalk11.default.gray("(match it in the browser)")}`
|
|
52308
|
+
);
|
|
51713
52309
|
console.log("");
|
|
51714
52310
|
const opened = opts.noBrowser ? false : openBrowser(start.verificationUrl);
|
|
51715
52311
|
console.log(
|
|
@@ -51755,6 +52351,7 @@ var fs50 = __toESM(require("fs"));
|
|
|
51755
52351
|
var os45 = __toESM(require("os"));
|
|
51756
52352
|
var path48 = __toESM(require("path"));
|
|
51757
52353
|
var import_chalk12 = __toESM(require("chalk"));
|
|
52354
|
+
init_safe_text();
|
|
51758
52355
|
async function revokeSelf(creds) {
|
|
51759
52356
|
const url = creds.apiUrl.replace(/\/$/, "") + "/machines/self/disconnect";
|
|
51760
52357
|
try {
|
|
@@ -51795,7 +52392,7 @@ function registerLogoutCommand(program2) {
|
|
|
51795
52392
|
} else if (res.outcome === "already") {
|
|
51796
52393
|
console.log(import_chalk12.default.gray("\u2713 Cloud: this machine was already disconnected."));
|
|
51797
52394
|
} else {
|
|
51798
|
-
console.log(import_chalk12.default.yellow(`\u26A0 Could not reach the cloud (${res.detail}).`));
|
|
52395
|
+
console.log(import_chalk12.default.yellow(`\u26A0 Could not reach the cloud (${safeMessage(res.detail)}).`));
|
|
51799
52396
|
console.log(
|
|
51800
52397
|
import_chalk12.default.yellow(" The key was removed locally, but is still listed in the dashboard \u2014")
|
|
51801
52398
|
);
|
|
@@ -52102,9 +52699,7 @@ function discardPendingReview(key, now = Date.now()) {
|
|
|
52102
52699
|
|
|
52103
52700
|
// src/cli/commands/check.ts
|
|
52104
52701
|
init_hook_payload();
|
|
52105
|
-
|
|
52106
|
-
return value.replace(/[\x00-\x1F\x7F]/g, "");
|
|
52107
|
-
}
|
|
52702
|
+
init_safe_text();
|
|
52108
52703
|
function detectAiAgent(payload) {
|
|
52109
52704
|
const meta = payload.meta;
|
|
52110
52705
|
if (meta && typeof meta === "object") {
|
|
@@ -52350,10 +52945,13 @@ RAW: ${raw}
|
|
|
52350
52945
|
const logPath = import_path47.default.join(import_os44.default.homedir(), ".node9", "hook-debug.log");
|
|
52351
52946
|
if (!import_fs49.default.existsSync(import_path47.default.dirname(logPath)))
|
|
52352
52947
|
import_fs49.default.mkdirSync(import_path47.default.dirname(logPath), { recursive: true });
|
|
52353
|
-
import_fs49.default.appendFileSync(
|
|
52354
|
-
|
|
52948
|
+
import_fs49.default.appendFileSync(
|
|
52949
|
+
logPath,
|
|
52950
|
+
`[${(/* @__PURE__ */ new Date()).toISOString()}] STDIN: ${JSON.stringify(raw)}
|
|
52951
|
+
`
|
|
52952
|
+
);
|
|
52355
52953
|
}
|
|
52356
|
-
const rawToolName =
|
|
52954
|
+
const rawToolName = stripControlChars(extractToolName(payload));
|
|
52357
52955
|
const toolName = canonicalToolName(rawToolName);
|
|
52358
52956
|
const toolInput = canonicalToolInput(rawToolName, extractToolInput(payload));
|
|
52359
52957
|
const agent = agentOverride ?? detectAiAgent(payload);
|
|
@@ -52743,6 +53341,7 @@ function containsShellMetachar(token) {
|
|
|
52743
53341
|
|
|
52744
53342
|
// src/cli/commands/log.ts
|
|
52745
53343
|
init_hook_payload();
|
|
53344
|
+
init_safe_text();
|
|
52746
53345
|
var TEST_COMMAND_RE2 = /(?:^|\s)(npm\s+(?:run\s+)?test|npx\s+(?:vitest|jest|mocha)|yarn\s+(?:run\s+)?test|pnpm\s+(?:run\s+)?test|vitest|jest|mocha|pytest|py\.test|cargo\s+test|go\s+test|bundle\s+exec\s+rspec|rspec|phpunit|dotnet\s+test)\b/i;
|
|
52747
53346
|
function detectTestResult(command, output) {
|
|
52748
53347
|
if (!TEST_COMMAND_RE2.test(command)) return null;
|
|
@@ -52761,9 +53360,6 @@ var CONFIDENCE_RANK = { low: 0, medium: 1, high: 2 };
|
|
|
52761
53360
|
function atLeastConfidence(c, min) {
|
|
52762
53361
|
return CONFIDENCE_RANK[c] >= CONFIDENCE_RANK[min];
|
|
52763
53362
|
}
|
|
52764
|
-
function sanitize3(value) {
|
|
52765
|
-
return value.replace(/[\x00-\x1F\x7F]/g, "");
|
|
52766
|
-
}
|
|
52767
53363
|
function scanCoveredEverything(value, depth = 0) {
|
|
52768
53364
|
if (value === null || value === void 0) return true;
|
|
52769
53365
|
if (typeof value === "string") return value.length <= DLP_SCAN_LIMITS.maxStringBytes;
|
|
@@ -52802,7 +53398,7 @@ function registerLogCommand(program2) {
|
|
|
52802
53398
|
if (!raw || raw.trim() === "") process.exit(0);
|
|
52803
53399
|
const payload = JSON.parse(raw);
|
|
52804
53400
|
if (payload.toolCall === null) process.exit(0);
|
|
52805
|
-
const rawToolName =
|
|
53401
|
+
const rawToolName = stripControlChars(extractToolName(payload, "unknown"));
|
|
52806
53402
|
const tool = canonicalToolName(rawToolName);
|
|
52807
53403
|
const rawInput = canonicalToolInput(rawToolName, extractToolInput(payload));
|
|
52808
53404
|
const metaTag = (() => {
|
|
@@ -55634,6 +56230,7 @@ var import_http4 = __toESM(require("http"));
|
|
|
55634
56230
|
var import_https7 = __toESM(require("https"));
|
|
55635
56231
|
var import_url4 = require("url");
|
|
55636
56232
|
var import_chalk22 = __toESM(require("chalk"));
|
|
56233
|
+
init_safe_text();
|
|
55637
56234
|
function resolveConnectUrl(apiUrl) {
|
|
55638
56235
|
return resolveCloudEndpoint("/cli/connect", apiUrl);
|
|
55639
56236
|
}
|
|
@@ -55692,7 +56289,7 @@ function registerConnectCommand(program2) {
|
|
|
55692
56289
|
try {
|
|
55693
56290
|
resp = await postConnect(resolveConnectUrl(options.apiUrl), token);
|
|
55694
56291
|
} catch (e) {
|
|
55695
|
-
console.error(import_chalk22.default.red(`\u2717 ${e
|
|
56292
|
+
console.error(import_chalk22.default.red(`\u2717 ${safeMessage(e) || "Connect failed."}`));
|
|
55696
56293
|
process.exitCode = 1;
|
|
55697
56294
|
return;
|
|
55698
56295
|
}
|
|
@@ -55779,9 +56376,7 @@ init_mcp_pin();
|
|
|
55779
56376
|
init_mcp_cmd();
|
|
55780
56377
|
init_mcp_tools();
|
|
55781
56378
|
init_daemon();
|
|
55782
|
-
|
|
55783
|
-
return value.replace(/[\x00-\x1F\x7F]/g, "");
|
|
55784
|
-
}
|
|
56379
|
+
init_safe_text();
|
|
55785
56380
|
var RPC_INVALID_REQUEST = -32600;
|
|
55786
56381
|
var RPC_SERVER_ERROR = -32e3;
|
|
55787
56382
|
function isValidId(id) {
|
|
@@ -55805,7 +56400,7 @@ function normalizeClientName(name) {
|
|
|
55805
56400
|
if (lower.includes("gemini")) return "Gemini";
|
|
55806
56401
|
if (lower.includes("cline")) return "Cline";
|
|
55807
56402
|
if (lower.includes("continue")) return "Continue";
|
|
55808
|
-
const sanitized =
|
|
56403
|
+
const sanitized = stripControlChars(name).slice(0, 40);
|
|
55809
56404
|
return sanitized.length > 0 ? sanitized : void 0;
|
|
55810
56405
|
}
|
|
55811
56406
|
function reportPinMismatchToCloud(serverKey, serverLabel, agent) {
|
|
@@ -55985,7 +56580,7 @@ async function runMcpGateway(upstreamCommand, configName) {
|
|
|
55985
56580
|
if (!deferredStdinEnd) agentIn.pause();
|
|
55986
56581
|
authPending = true;
|
|
55987
56582
|
try {
|
|
55988
|
-
const toolName =
|
|
56583
|
+
const toolName = stripControlChars(
|
|
55989
56584
|
String(message.params?.name ?? message.params?.tool_name ?? "unknown")
|
|
55990
56585
|
);
|
|
55991
56586
|
const toolArgs = message.params?.arguments ?? message.params?.tool_input ?? {};
|
|
@@ -61429,12 +62024,9 @@ var import_chalk42 = __toESM(require("chalk"));
|
|
|
61429
62024
|
var import_fs73 = __toESM(require("fs"));
|
|
61430
62025
|
var import_path68 = __toESM(require("path"));
|
|
61431
62026
|
var import_os60 = __toESM(require("os"));
|
|
62027
|
+
init_safe_text();
|
|
61432
62028
|
var AUDIT_LOG = import_path68.default.join(import_os60.default.homedir(), ".node9", "audit.log");
|
|
61433
62029
|
var RESOLVED_FILE = import_path68.default.join(import_os60.default.homedir(), ".node9", "dlp-resolved.json");
|
|
61434
|
-
var ANSI_RE = /\x1b(?:\[[0-9;?]*[a-zA-Z]|\][^\x07\x1b]*(?:\x07|\x1b\\)|[@-_])/g;
|
|
61435
|
-
function stripAnsi(s) {
|
|
61436
|
-
return s.replace(ANSI_RE, "");
|
|
61437
|
-
}
|
|
61438
62030
|
function loadResolved() {
|
|
61439
62031
|
try {
|
|
61440
62032
|
const raw = JSON.parse(import_fs73.default.readFileSync(RESOLVED_FILE, "utf-8"));
|
|
@@ -61528,10 +62120,10 @@ function registerDlpCommand(program2) {
|
|
|
61528
62120
|
" " + import_chalk42.default.red("\u25CF") + " " + import_chalk42.default.white(e.dlpPattern ?? "Secret") + import_chalk42.default.dim(" " + fmtDate3(e.ts))
|
|
61529
62121
|
);
|
|
61530
62122
|
if (e.dlpSample) {
|
|
61531
|
-
console.log(" " + import_chalk42.default.dim("Sample: ") + import_chalk42.default.yellow(
|
|
62123
|
+
console.log(" " + import_chalk42.default.dim("Sample: ") + import_chalk42.default.yellow(safeMessage(e.dlpSample)));
|
|
61532
62124
|
}
|
|
61533
62125
|
if (e.project) {
|
|
61534
|
-
console.log(" " + import_chalk42.default.dim("Project: ") + import_chalk42.default.dim(
|
|
62126
|
+
console.log(" " + import_chalk42.default.dim("Project: ") + import_chalk42.default.dim(safeMessage(e.project)));
|
|
61535
62127
|
}
|
|
61536
62128
|
console.log("");
|
|
61537
62129
|
}
|
|
@@ -61734,6 +62326,7 @@ function registerMaskCommand(program2) {
|
|
|
61734
62326
|
|
|
61735
62327
|
// src/cli.ts
|
|
61736
62328
|
init_blast();
|
|
62329
|
+
init_safe_text();
|
|
61737
62330
|
var { version } = JSON.parse(
|
|
61738
62331
|
import_fs77.default.readFileSync(import_path72.default.join(__dirname, "../package.json"), "utf-8")
|
|
61739
62332
|
);
|
|
@@ -61766,7 +62359,7 @@ program.command("login").argument("[apiKey]", "Service/legacy key. Omit to log i
|
|
|
61766
62359
|
cliVersion: version
|
|
61767
62360
|
});
|
|
61768
62361
|
if (!res.ok) {
|
|
61769
|
-
console.error(import_chalk45.default.red(`\u2717 ${res.reason}`));
|
|
62362
|
+
console.error(import_chalk45.default.red(`\u2717 ${safeMessage(res.reason)}`));
|
|
61770
62363
|
process.exitCode = 1;
|
|
61771
62364
|
return;
|
|
61772
62365
|
}
|