@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.mjs
CHANGED
|
@@ -905,6 +905,19 @@ function parseShared(command) {
|
|
|
905
905
|
astCache.set(command, parsed);
|
|
906
906
|
return parsed;
|
|
907
907
|
}
|
|
908
|
+
function byteOffsetToCharIndex(command) {
|
|
909
|
+
if (!/[^\u0000-\u007F]/.test(command)) return null;
|
|
910
|
+
const map = /* @__PURE__ */ new Map();
|
|
911
|
+
let byte = 0;
|
|
912
|
+
for (let i = 0; i < command.length; ) {
|
|
913
|
+
map.set(byte, i);
|
|
914
|
+
const cp = command.codePointAt(i);
|
|
915
|
+
byte += cp < 128 ? 1 : cp < 2048 ? 2 : cp < 65536 ? 3 : 4;
|
|
916
|
+
i += cp > 65535 ? 2 : 1;
|
|
917
|
+
}
|
|
918
|
+
map.set(byte, command.length);
|
|
919
|
+
return (b) => map.get(b) ?? -1;
|
|
920
|
+
}
|
|
908
921
|
function cachedNormalize(command, compute) {
|
|
909
922
|
const hit = normalizeCache.get(command);
|
|
910
923
|
if (hit !== void 0) {
|
|
@@ -934,6 +947,8 @@ function normalizeCommandForPolicyImpl(command) {
|
|
|
934
947
|
const f = parseShared(command);
|
|
935
948
|
if (f === PARSE_FAIL) return { posix: command, separator: command };
|
|
936
949
|
try {
|
|
950
|
+
const toCharIndex = byteOffsetToCharIndex(command);
|
|
951
|
+
const at = (byteOffset) => toCharIndex === null ? byteOffset : toCharIndex(byteOffset);
|
|
937
952
|
const strips = [];
|
|
938
953
|
const rewrites = [];
|
|
939
954
|
const quoteOnlyRewrites = [];
|
|
@@ -954,8 +969,9 @@ function normalizeCommandForPolicyImpl(command) {
|
|
|
954
969
|
const quotedNode = nextParts[0];
|
|
955
970
|
const nt = syntax.NodeType(quotedNode);
|
|
956
971
|
const markStrip = () => {
|
|
957
|
-
const s = next.Pos().Offset();
|
|
958
|
-
const e = next.End().Offset();
|
|
972
|
+
const s = at(next.Pos().Offset());
|
|
973
|
+
const e = at(next.End().Offset());
|
|
974
|
+
if (s < 0 || e < 0) return;
|
|
959
975
|
strips.push([s, e]);
|
|
960
976
|
msgSpans.add(`${s}:${e}`);
|
|
961
977
|
};
|
|
@@ -972,8 +988,9 @@ function normalizeCommandForPolicyImpl(command) {
|
|
|
972
988
|
}
|
|
973
989
|
}
|
|
974
990
|
for (const arg of args) {
|
|
975
|
-
const s = arg.Pos().Offset();
|
|
976
|
-
const e = arg.End().Offset();
|
|
991
|
+
const s = at(arg.Pos().Offset());
|
|
992
|
+
const e = at(arg.End().Offset());
|
|
993
|
+
if (s < 0 || e < 0) continue;
|
|
977
994
|
if (msgSpans.has(`${s}:${e}`)) continue;
|
|
978
995
|
const resolved = resolveWordLiteral(arg);
|
|
979
996
|
if (resolved === null) continue;
|
|
@@ -1599,7 +1616,7 @@ function analyzeFsOperationImpl(command, depth = 0) {
|
|
|
1599
1616
|
return result?.verdict !== "block";
|
|
1600
1617
|
}
|
|
1601
1618
|
if (nodeType !== "CallExpr") return true;
|
|
1602
|
-
const { name, flags, paths, words } = extractLiteralArgs(n);
|
|
1619
|
+
const { name, flags, paths, words, args } = extractLiteralArgs(n);
|
|
1603
1620
|
if (!name) return true;
|
|
1604
1621
|
if (name === "rm") {
|
|
1605
1622
|
const flagStr = flags.join("").toLowerCase();
|
|
@@ -1639,7 +1656,7 @@ function analyzeFsOperationImpl(command, depth = 0) {
|
|
|
1639
1656
|
return true;
|
|
1640
1657
|
}
|
|
1641
1658
|
}
|
|
1642
|
-
const readPaths = FS_READ_TOOLS.has(name) ?
|
|
1659
|
+
const readPaths = FS_READ_TOOLS.has(name) ? [...readTargets(name, args, flags, words, 1), ...flagOperandFiles(name, words, 1)] : wrappedReadPaths(words, name);
|
|
1643
1660
|
if (readPaths) {
|
|
1644
1661
|
for (const p of readPaths) {
|
|
1645
1662
|
result = stricter(result, matchSensitivePath2(p));
|
|
@@ -1675,9 +1692,22 @@ function flagIs(w, names) {
|
|
|
1675
1692
|
const f = flagInfo(w);
|
|
1676
1693
|
return names.some((n) => n.startsWith("--") ? f.long === n : f.letter === n);
|
|
1677
1694
|
}
|
|
1678
|
-
function operandOf(a, names) {
|
|
1695
|
+
function operandOf(a, names, valueLetters) {
|
|
1679
1696
|
if (!names || a.afterFlag === null) return false;
|
|
1680
|
-
|
|
1697
|
+
const w = a.afterFlag;
|
|
1698
|
+
if (!w.startsWith("--") && valueLetters) {
|
|
1699
|
+
const letters = w.slice(1);
|
|
1700
|
+
for (let i = 0; i < letters.length; i++) {
|
|
1701
|
+
if (!valueLetters.includes(letters[i])) continue;
|
|
1702
|
+
return i === letters.length - 1 && names.includes(letters[i]);
|
|
1703
|
+
}
|
|
1704
|
+
return false;
|
|
1705
|
+
}
|
|
1706
|
+
if (w.startsWith("--") && !w.includes("=")) {
|
|
1707
|
+
const longs = names.filter((n) => n.startsWith("--"));
|
|
1708
|
+
if (longs.some((n) => n === w || w.length >= 3 && n.startsWith(w))) return true;
|
|
1709
|
+
}
|
|
1710
|
+
return flagIs(w, names) && flagInfo(w).attached === null;
|
|
1681
1711
|
}
|
|
1682
1712
|
function resolveCopyShape(words, h) {
|
|
1683
1713
|
const verb = baseWord(words[h]);
|
|
@@ -1701,7 +1731,7 @@ function findStartPoints(words, h) {
|
|
|
1701
1731
|
const k = words.findIndex((w, i) => i > h && w !== null && FIND_EXEC_FLAGS.has(w));
|
|
1702
1732
|
if (k < 0) return { k, starts: [] };
|
|
1703
1733
|
const firstPredicate = words.findIndex(
|
|
1704
|
-
(w, i) => i > h && w !== null && w.startsWith("-") && !FIND_OPTIONS.has(w)
|
|
1734
|
+
(w, i) => i > h && w !== null && w !== "--" && w.startsWith("-") && !FIND_OPTIONS.has(w)
|
|
1705
1735
|
);
|
|
1706
1736
|
const end = firstPredicate > h ? firstPredicate : k;
|
|
1707
1737
|
return { k, starts: positionalAfter(words, h + 1, end) };
|
|
@@ -1721,14 +1751,35 @@ function copySourcePaths(words) {
|
|
|
1721
1751
|
const { shape, last } = r;
|
|
1722
1752
|
const args = positionedArgs(words, last + 1);
|
|
1723
1753
|
const tail = words.slice(last + 1);
|
|
1724
|
-
const
|
|
1725
|
-
const
|
|
1726
|
-
const
|
|
1754
|
+
const copyOptionsEnd = tail.findIndex((w) => w === "--");
|
|
1755
|
+
const copyPastOptions = (a) => copyOptionsEnd >= 0 && a.argv > last + 1 + copyOptionsEnd;
|
|
1756
|
+
const skipped = (a) => !copyPastOptions(a) && operandOf(a, shape.skipFlags, shape.valueLetters);
|
|
1757
|
+
const firstValueLetter = (w) => {
|
|
1758
|
+
const letters = w.slice(1);
|
|
1759
|
+
for (let i = 0; i < letters.length; i++) {
|
|
1760
|
+
if ((shape.valueLetters ?? []).includes(letters[i]))
|
|
1761
|
+
return { letter: letters[i], last: i === letters.length - 1 };
|
|
1762
|
+
}
|
|
1763
|
+
return null;
|
|
1764
|
+
};
|
|
1765
|
+
const isTargetDirFlag = (w) => {
|
|
1766
|
+
if (w.startsWith("--")) {
|
|
1767
|
+
const name = w.includes("=") ? w.slice(0, w.indexOf("=")) : w;
|
|
1768
|
+
return name.length >= 3 && "--target-directory".startsWith(name);
|
|
1769
|
+
}
|
|
1770
|
+
return firstValueLetter(w)?.letter === "t";
|
|
1771
|
+
};
|
|
1772
|
+
const targetDir = shape.targetDirFlag === true && tail.some((w) => w !== null && w.startsWith("-") && isTargetDirFlag(w));
|
|
1773
|
+
const targetTakesNextWord = (w) => {
|
|
1774
|
+
if (w.startsWith("--"))
|
|
1775
|
+
return !w.includes("=") && w.length >= 3 && "--target-directory".startsWith(w);
|
|
1776
|
+
const f = firstValueLetter(w);
|
|
1777
|
+
return f !== null && f.letter === "t" && f.last;
|
|
1778
|
+
};
|
|
1779
|
+
const targetOperand = (a) => targetDir && a.afterFlag !== null && !copyPastOptions(a) && targetTakesNextWord(a.afterFlag);
|
|
1727
1780
|
const lastOperand = [...tail].reverse().find((w) => w === null || !w.startsWith("-"));
|
|
1728
1781
|
const dynamicDest = lastOperand === null;
|
|
1729
1782
|
const destIsLastOperand = (shape.source === "allButLast" || shape.source === "first") && !targetDir && !dynamicDest;
|
|
1730
|
-
if (destIsLastOperand && typeof lastOperand === "string" && matchSensitivePath2(lastOperand))
|
|
1731
|
-
return [];
|
|
1732
1783
|
let src;
|
|
1733
1784
|
switch (shape.source) {
|
|
1734
1785
|
case "all":
|
|
@@ -1738,11 +1789,17 @@ function copySourcePaths(words) {
|
|
|
1738
1789
|
src = targetDir ? args : args.slice(0, 1);
|
|
1739
1790
|
break;
|
|
1740
1791
|
case "flagOperand": {
|
|
1741
|
-
const
|
|
1792
|
+
const namesSource = (f) => {
|
|
1793
|
+
const names = shape.sourceFlags ?? [];
|
|
1794
|
+
if (f.long !== null)
|
|
1795
|
+
return names.some(
|
|
1796
|
+
(n) => n.startsWith("--") && (n === f.long || f.long.length >= 3 && n.startsWith(f.long))
|
|
1797
|
+
);
|
|
1798
|
+
return f.letter !== null && names.includes(f.letter);
|
|
1799
|
+
};
|
|
1800
|
+
const inline = tail.filter((w) => w !== null && w.startsWith("-")).map((w) => flagInfo(w)).filter((f) => f.attached !== null && namesSource(f)).map((f) => f.attached);
|
|
1742
1801
|
return [
|
|
1743
|
-
...args.filter(
|
|
1744
|
-
(a) => flagIs(a.afterFlag, shape.sourceFlags ?? []) && flagInfo(a.afterFlag).attached === null
|
|
1745
|
-
).map((a) => a.value),
|
|
1802
|
+
...args.filter((a) => !copyPastOptions(a) && operandOf(a, shape.sourceFlags, shape.valueLetters)).map((a) => a.value),
|
|
1746
1803
|
...inline
|
|
1747
1804
|
];
|
|
1748
1805
|
}
|
|
@@ -1753,7 +1810,14 @@ function copySourcePaths(words) {
|
|
|
1753
1810
|
src = targetDir || dynamicDest ? args : args.slice(0, -1);
|
|
1754
1811
|
break;
|
|
1755
1812
|
}
|
|
1756
|
-
|
|
1813
|
+
const sources = src.filter((a) => !skipped(a) && !targetOperand(a)).map((a) => a.value);
|
|
1814
|
+
if (destIsLastOperand && typeof lastOperand === "string" && matchSensitivePath2(lastOperand)) {
|
|
1815
|
+
const jailedSources = sources.filter((p) => matchSensitivePath2(p));
|
|
1816
|
+
const dirOf = (p) => /[\\/]/.test(p) ? p.replace(/[\\/][^\\/]*$/, "") : "";
|
|
1817
|
+
if (jailedSources.length === 0) return [];
|
|
1818
|
+
if (jailedSources.every((p) => dirOf(p) === dirOf(lastOperand))) return [];
|
|
1819
|
+
}
|
|
1820
|
+
return sources;
|
|
1757
1821
|
}
|
|
1758
1822
|
function archiveInputs(kind, args, tail) {
|
|
1759
1823
|
const first = args[0];
|
|
@@ -1765,13 +1829,17 @@ function archiveInputs(kind, args, tail) {
|
|
|
1765
1829
|
const writing = /[cruA]/.test(bareKey ? first.value : "") || /(^|\s)-[a-zA-Z]*[cruA]|--create|--append|--update|--concatenate/.test(flagsText);
|
|
1766
1830
|
if (extracting && !writing) return [];
|
|
1767
1831
|
void mode;
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
if (
|
|
1773
|
-
|
|
1774
|
-
|
|
1832
|
+
if (!bareKey) return args;
|
|
1833
|
+
let i = 1;
|
|
1834
|
+
const fromDirs = [];
|
|
1835
|
+
for (const ch of first.value) {
|
|
1836
|
+
if (!TAR_VALUE_LETTERS.includes(ch)) continue;
|
|
1837
|
+
const operand = args[i];
|
|
1838
|
+
if (!operand || operand.afterFlag !== null) break;
|
|
1839
|
+
i += 1;
|
|
1840
|
+
if (ch === "C") fromDirs.push(operand);
|
|
1841
|
+
}
|
|
1842
|
+
return [...fromDirs, ...args.slice(i)];
|
|
1775
1843
|
}
|
|
1776
1844
|
if (kind === "zip") return first && first.afterFlag === "-" ? args : args.slice(1);
|
|
1777
1845
|
if (kind === "ar") return bareKey ? args.slice(2) : args.slice(1);
|
|
@@ -1798,6 +1866,138 @@ function matchSensitivePath2(p) {
|
|
|
1798
1866
|
function baseWord(w) {
|
|
1799
1867
|
return (w ?? "").split("/").pop()?.toLowerCase() ?? "";
|
|
1800
1868
|
}
|
|
1869
|
+
function namesFlag(name, candidates2, known) {
|
|
1870
|
+
if (candidates2.has(name)) return true;
|
|
1871
|
+
if (!name.startsWith("--") || name.length < 3) return false;
|
|
1872
|
+
if (known?.has(name)) return false;
|
|
1873
|
+
for (const c of candidates2) if (c.startsWith(name)) return true;
|
|
1874
|
+
return false;
|
|
1875
|
+
}
|
|
1876
|
+
function knownLongFlags(verb) {
|
|
1877
|
+
const out = /* @__PURE__ */ new Set();
|
|
1878
|
+
const shape = PATTERN_VERBS[verb];
|
|
1879
|
+
if (shape) {
|
|
1880
|
+
for (const set of [shape.takesValue, shape.noValue, shape.patternFlags, shape.noPatternFlags])
|
|
1881
|
+
for (const f of set) if (f.startsWith("--")) out.add(f);
|
|
1882
|
+
}
|
|
1883
|
+
for (const f of FILE_OPERAND_FLAGS[verb] ?? []) if (f.startsWith("--")) out.add(f);
|
|
1884
|
+
return out;
|
|
1885
|
+
}
|
|
1886
|
+
function flagNamesOf(token, shape) {
|
|
1887
|
+
if (token.startsWith("--")) {
|
|
1888
|
+
const eq = token.indexOf("=");
|
|
1889
|
+
return [eq > 0 ? token.slice(0, eq) : token];
|
|
1890
|
+
}
|
|
1891
|
+
const out = [];
|
|
1892
|
+
for (const c of token.slice(1)) {
|
|
1893
|
+
const name = `-${c}`;
|
|
1894
|
+
out.push(name);
|
|
1895
|
+
if (shape?.takesValue.has(name)) break;
|
|
1896
|
+
}
|
|
1897
|
+
return out;
|
|
1898
|
+
}
|
|
1899
|
+
function flagEffect(token, shape, known) {
|
|
1900
|
+
if (token === "--") return NONE;
|
|
1901
|
+
if (/^-+$/.test(token)) return UNKNOWN;
|
|
1902
|
+
if (/^-\d+$/.test(token)) return NONE;
|
|
1903
|
+
if (token.startsWith("--")) {
|
|
1904
|
+
if (token.includes("=")) return NONE;
|
|
1905
|
+
const takes = namesFlag(token, shape.takesValue, known);
|
|
1906
|
+
const none = namesFlag(token, shape.noValue, known);
|
|
1907
|
+
if (takes && none) return UNKNOWN;
|
|
1908
|
+
if (takes) return { kind: "takes", flag: token };
|
|
1909
|
+
if (none) return NONE;
|
|
1910
|
+
return UNKNOWN;
|
|
1911
|
+
}
|
|
1912
|
+
const letters = token.slice(1);
|
|
1913
|
+
if (!letters) return NONE;
|
|
1914
|
+
for (let i = 0; i < letters.length; i++) {
|
|
1915
|
+
const name = `-${letters[i]}`;
|
|
1916
|
+
if (shape.takesValue.has(name)) {
|
|
1917
|
+
return i === letters.length - 1 ? { kind: "takes", flag: name } : NONE;
|
|
1918
|
+
}
|
|
1919
|
+
if (!shape.noValue.has(name)) return UNKNOWN;
|
|
1920
|
+
}
|
|
1921
|
+
return NONE;
|
|
1922
|
+
}
|
|
1923
|
+
function readTargets(verb, args, flags, words = [], from = 1) {
|
|
1924
|
+
const shape = PATTERN_VERBS[verb];
|
|
1925
|
+
if (!shape) return args.map((a) => a.value);
|
|
1926
|
+
const known = knownLongFlags(verb);
|
|
1927
|
+
const names = flags.flatMap((f) => flagNamesOf(f, shape));
|
|
1928
|
+
const patternElsewhere = names.some(
|
|
1929
|
+
(n) => namesFlag(n, shape.patternFlags, known) || namesFlag(n, shape.noPatternFlags, known)
|
|
1930
|
+
);
|
|
1931
|
+
const excused = /* @__PURE__ */ new Set();
|
|
1932
|
+
const fileFlags = FILE_OPERAND_FLAGS[verb];
|
|
1933
|
+
const optionsEnd = words.findIndex((w, i) => i >= from && w === "--");
|
|
1934
|
+
const pastOptions = (a) => optionsEnd >= 0 && a.argv > optionsEnd;
|
|
1935
|
+
for (const a of args) {
|
|
1936
|
+
if (a.afterFlag === null || pastOptions(a)) continue;
|
|
1937
|
+
const e = flagEffect(a.afterFlag, shape, known);
|
|
1938
|
+
if (e.kind !== "takes") continue;
|
|
1939
|
+
if (fileFlags && namesFlag(e.flag, fileFlags, known)) continue;
|
|
1940
|
+
excused.add(a);
|
|
1941
|
+
}
|
|
1942
|
+
const patternArgv = (() => {
|
|
1943
|
+
for (let i = from; i < words.length; i++) {
|
|
1944
|
+
const w = words[i];
|
|
1945
|
+
if (w === null) return -1;
|
|
1946
|
+
if (w === "--") return i + 1;
|
|
1947
|
+
if (w.startsWith("-")) {
|
|
1948
|
+
const e = flagEffect(w, shape, known);
|
|
1949
|
+
if (e.kind === "takes") i += 1;
|
|
1950
|
+
else if (e.kind === "unknown") return -1;
|
|
1951
|
+
continue;
|
|
1952
|
+
}
|
|
1953
|
+
return i;
|
|
1954
|
+
}
|
|
1955
|
+
return -1;
|
|
1956
|
+
})();
|
|
1957
|
+
if (!patternElsewhere && patternArgv >= 0) {
|
|
1958
|
+
const a = args.find((x) => x.argv === patternArgv);
|
|
1959
|
+
if (a) excused.add(a);
|
|
1960
|
+
}
|
|
1961
|
+
return args.filter((a) => !excused.has(a)).map((a) => a.value);
|
|
1962
|
+
}
|
|
1963
|
+
function flagOperandFiles(verb, words, from) {
|
|
1964
|
+
const flags = FILE_OPERAND_FLAGS[verb];
|
|
1965
|
+
if (!flags) return [];
|
|
1966
|
+
const known = knownLongFlags(verb);
|
|
1967
|
+
const out = [];
|
|
1968
|
+
for (let i = from; i < words.length; i++) {
|
|
1969
|
+
const w = words[i];
|
|
1970
|
+
if (w === null || !w.startsWith("-") || w === "--") continue;
|
|
1971
|
+
if (w.startsWith("--")) {
|
|
1972
|
+
const eq = w.indexOf("=");
|
|
1973
|
+
if (eq <= 0) continue;
|
|
1974
|
+
const name = w.slice(0, eq);
|
|
1975
|
+
const value = w.slice(eq + 1);
|
|
1976
|
+
if (!value) continue;
|
|
1977
|
+
if (namesFlag(name, flags, known)) {
|
|
1978
|
+
out.push(value);
|
|
1979
|
+
continue;
|
|
1980
|
+
}
|
|
1981
|
+
const shape2 = PATTERN_VERBS[verb];
|
|
1982
|
+
if (!shape2) continue;
|
|
1983
|
+
const recognised = namesFlag(name, shape2.takesValue, known) || namesFlag(name, shape2.noValue, known) || namesFlag(name, shape2.patternFlags, known) || namesFlag(name, shape2.noPatternFlags, known);
|
|
1984
|
+
if (!recognised) out.push(value);
|
|
1985
|
+
continue;
|
|
1986
|
+
}
|
|
1987
|
+
const shape = PATTERN_VERBS[verb];
|
|
1988
|
+
const letters = w.slice(1);
|
|
1989
|
+
for (let j = 0; j < letters.length; j++) {
|
|
1990
|
+
const name = `-${letters[j]}`;
|
|
1991
|
+
const isFileFlag = flags.has(name);
|
|
1992
|
+
const argTaking = isFileFlag || (shape?.takesValue.has(name) ?? false) || (READER_VALUE_LETTERS[verb] ?? []).includes(letters[j]);
|
|
1993
|
+
if (!argTaking) continue;
|
|
1994
|
+
const attached = letters.slice(j + 1);
|
|
1995
|
+
if (isFileFlag && attached) out.push(attached);
|
|
1996
|
+
break;
|
|
1997
|
+
}
|
|
1998
|
+
}
|
|
1999
|
+
return out;
|
|
2000
|
+
}
|
|
1801
2001
|
function wrappedReadPaths(words, name) {
|
|
1802
2002
|
if (name === "find") {
|
|
1803
2003
|
const { k, starts } = findStartPoints(words, 0);
|
|
@@ -1805,7 +2005,14 @@ function wrappedReadPaths(words, name) {
|
|
|
1805
2005
|
}
|
|
1806
2006
|
if (!COMMAND_WRAPPERS.has(name) && !RUNNER_WRAPPERS.has(name)) return null;
|
|
1807
2007
|
const h = unwrapCommandHead(words);
|
|
1808
|
-
|
|
2008
|
+
if (h <= 0 || !isReaderWord(words[h] ?? null)) return null;
|
|
2009
|
+
const head = baseWord(words[h]);
|
|
2010
|
+
const rest = words.slice(h + 1);
|
|
2011
|
+
const restFlags = rest.filter((w) => w !== null && w.startsWith("-"));
|
|
2012
|
+
return [
|
|
2013
|
+
...readTargets(head, positionedArgs(words, h + 1), restFlags, words, h + 1),
|
|
2014
|
+
...flagOperandFiles(head, words, h + 1)
|
|
2015
|
+
];
|
|
1809
2016
|
}
|
|
1810
2017
|
function literalShellPayload(words, name) {
|
|
1811
2018
|
const h = COMMAND_WRAPPERS.has(name) || RUNNER_WRAPPERS.has(name) ? unwrapCommandHead(words) : 0;
|
|
@@ -2738,6 +2945,17 @@ async function evaluatePolicy(config, toolName, args, context = {}, hooks = {})
|
|
|
2738
2945
|
function isIgnoredTool(toolName, config) {
|
|
2739
2946
|
return matchesPattern(toolName, config.policy.ignoredTools);
|
|
2740
2947
|
}
|
|
2948
|
+
function stripTerminalEscapes(s) {
|
|
2949
|
+
return s.replace(TERMINAL_ESCAPE_RE, "");
|
|
2950
|
+
}
|
|
2951
|
+
function stripControlChars(s) {
|
|
2952
|
+
return s.replace(CONTROL_CHAR_RE, "");
|
|
2953
|
+
}
|
|
2954
|
+
function safeMessage(value, max = 300) {
|
|
2955
|
+
const raw = typeof value === "string" ? value : value instanceof Error ? value.message : String(value ?? "");
|
|
2956
|
+
const s = stripTerminalEscapes(raw).replace(/\s+/g, " ").trim();
|
|
2957
|
+
return s.length > max ? s.slice(0, max - 1) + "\u2026" : s;
|
|
2958
|
+
}
|
|
2741
2959
|
function isShieldVerdict(v) {
|
|
2742
2960
|
return v === "allow" || v === "review" || v === "block";
|
|
2743
2961
|
}
|
|
@@ -2955,7 +3173,10 @@ function computeSecurityScore(opts) {
|
|
|
2955
3173
|
}
|
|
2956
3174
|
function truncateBlastPath(full) {
|
|
2957
3175
|
if (!full) return "";
|
|
2958
|
-
|
|
3176
|
+
if (full.length > MAX_BLAST_PATH) full = full.slice(-MAX_BLAST_PATH);
|
|
3177
|
+
let end = full.length;
|
|
3178
|
+
while (end > 0 && (full[end - 1] === "/" || full[end - 1] === "\\")) end--;
|
|
3179
|
+
const cleaned = full.slice(0, end);
|
|
2959
3180
|
const parts = cleaned.split(/[/\\]+/).filter((p) => p.length > 0);
|
|
2960
3181
|
if (parts.length <= 2) {
|
|
2961
3182
|
return cleaned.startsWith("~") && !cleaned.startsWith("~/") ? cleaned : cleaned.startsWith("~/") ? cleaned : parts.join("/");
|
|
@@ -3451,7 +3672,7 @@ function toScanFinding(c) {
|
|
|
3451
3672
|
}
|
|
3452
3673
|
function previewArgs(input, max) {
|
|
3453
3674
|
const cmd = input.command ?? input.query ?? input.file_path ?? JSON.stringify(input);
|
|
3454
|
-
const s = String(cmd)
|
|
3675
|
+
const s = stripTerminalEscapes(String(cmd)).replace(/\s+/g, " ").trim();
|
|
3455
3676
|
return s.length > max ? s.slice(0, max - 1) + "\u2026" : s;
|
|
3456
3677
|
}
|
|
3457
3678
|
function makeFinding(args) {
|
|
@@ -3491,7 +3712,7 @@ function* stringValues(obj, depth = 0) {
|
|
|
3491
3712
|
}
|
|
3492
3713
|
for (const v of Object.values(obj)) yield* stringValues(v, depth + 1);
|
|
3493
3714
|
}
|
|
3494
|
-
var 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,
|
|
3715
|
+
var 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;
|
|
3495
3716
|
var init_dist = __esm({
|
|
3496
3717
|
"packages/policy-engine/dist/index.mjs"() {
|
|
3497
3718
|
"use strict";
|
|
@@ -4227,7 +4448,345 @@ var init_dist = __esm({
|
|
|
4227
4448
|
"nl",
|
|
4228
4449
|
"dd"
|
|
4229
4450
|
]);
|
|
4451
|
+
GREP_SHAPE = {
|
|
4452
|
+
takesValue: /* @__PURE__ */ new Set([
|
|
4453
|
+
"-A",
|
|
4454
|
+
"-B",
|
|
4455
|
+
"-C",
|
|
4456
|
+
"-D",
|
|
4457
|
+
"-d",
|
|
4458
|
+
"-e",
|
|
4459
|
+
"-f",
|
|
4460
|
+
"-m",
|
|
4461
|
+
"--after-context",
|
|
4462
|
+
"--before-context",
|
|
4463
|
+
"--binary-files",
|
|
4464
|
+
"--context",
|
|
4465
|
+
"--devices",
|
|
4466
|
+
"--directories",
|
|
4467
|
+
"--exclude",
|
|
4468
|
+
"--exclude-dir",
|
|
4469
|
+
"--exclude-from",
|
|
4470
|
+
"--file",
|
|
4471
|
+
"--include",
|
|
4472
|
+
"--label",
|
|
4473
|
+
"--max-count",
|
|
4474
|
+
"--regexp"
|
|
4475
|
+
]),
|
|
4476
|
+
noValue: /* @__PURE__ */ new Set([
|
|
4477
|
+
"-E",
|
|
4478
|
+
"-F",
|
|
4479
|
+
"-G",
|
|
4480
|
+
"-P",
|
|
4481
|
+
"-i",
|
|
4482
|
+
"-y",
|
|
4483
|
+
"-v",
|
|
4484
|
+
"-V",
|
|
4485
|
+
"-w",
|
|
4486
|
+
"-x",
|
|
4487
|
+
"-c",
|
|
4488
|
+
"-l",
|
|
4489
|
+
"-L",
|
|
4490
|
+
"-o",
|
|
4491
|
+
"-q",
|
|
4492
|
+
"-s",
|
|
4493
|
+
"-b",
|
|
4494
|
+
"-H",
|
|
4495
|
+
"-h",
|
|
4496
|
+
"-n",
|
|
4497
|
+
"-T",
|
|
4498
|
+
"-Z",
|
|
4499
|
+
"-z",
|
|
4500
|
+
"-R",
|
|
4501
|
+
"-r",
|
|
4502
|
+
"-U",
|
|
4503
|
+
"-u",
|
|
4504
|
+
"-I",
|
|
4505
|
+
"-a",
|
|
4506
|
+
"--basic-regexp",
|
|
4507
|
+
"--binary",
|
|
4508
|
+
"--byte-offset",
|
|
4509
|
+
"--color",
|
|
4510
|
+
"--colour",
|
|
4511
|
+
"--count",
|
|
4512
|
+
"--dereference-recursive",
|
|
4513
|
+
"--extended-regexp",
|
|
4514
|
+
"--files-with-matches",
|
|
4515
|
+
"--files-without-match",
|
|
4516
|
+
"--fixed-strings",
|
|
4517
|
+
"--help",
|
|
4518
|
+
"--ignore-case",
|
|
4519
|
+
"--initial-tab",
|
|
4520
|
+
"--invert-match",
|
|
4521
|
+
"--line-buffered",
|
|
4522
|
+
"--line-number",
|
|
4523
|
+
"--line-regexp",
|
|
4524
|
+
"--no-filename",
|
|
4525
|
+
"--no-group-separator",
|
|
4526
|
+
"--no-ignore-case",
|
|
4527
|
+
"--no-messages",
|
|
4528
|
+
"--null",
|
|
4529
|
+
"--null-data",
|
|
4530
|
+
"--only-matching",
|
|
4531
|
+
"--perl-regexp",
|
|
4532
|
+
"--quiet",
|
|
4533
|
+
"--recursive",
|
|
4534
|
+
"--silent",
|
|
4535
|
+
"--text",
|
|
4536
|
+
"--version",
|
|
4537
|
+
"--with-filename",
|
|
4538
|
+
"--word-regexp"
|
|
4539
|
+
]),
|
|
4540
|
+
patternFlags: /* @__PURE__ */ new Set(["-e", "--regexp"]),
|
|
4541
|
+
noPatternFlags: /* @__PURE__ */ new Set(["-f", "--file"])
|
|
4542
|
+
};
|
|
4543
|
+
PATTERN_VERBS = {
|
|
4544
|
+
grep: GREP_SHAPE,
|
|
4545
|
+
// /usr/bin/egrep and /usr/bin/fgrep are 41-byte shell wrappers that exec
|
|
4546
|
+
// `grep -E` and `grep -F`. Read in full, not assumed.
|
|
4547
|
+
egrep: GREP_SHAPE,
|
|
4548
|
+
fgrep: GREP_SHAPE,
|
|
4549
|
+
// ripgrep 14.1.1, complete from its own --help. An earlier comment here said rg
|
|
4550
|
+
// was not installed on the measuring machine; it is, and that stale claim is why
|
|
4551
|
+
// this table shipped incomplete for two rounds, blocking ordinary searches like
|
|
4552
|
+
// `rg --sort-files .env src` (/code-review round 4).
|
|
4553
|
+
rg: {
|
|
4554
|
+
takesValue: /* @__PURE__ */ new Set([
|
|
4555
|
+
"-A",
|
|
4556
|
+
"-B",
|
|
4557
|
+
"-C",
|
|
4558
|
+
"-d",
|
|
4559
|
+
"-E",
|
|
4560
|
+
"-e",
|
|
4561
|
+
"-f",
|
|
4562
|
+
"-g",
|
|
4563
|
+
"-j",
|
|
4564
|
+
"-M",
|
|
4565
|
+
"-m",
|
|
4566
|
+
"-r",
|
|
4567
|
+
"-t",
|
|
4568
|
+
"-T",
|
|
4569
|
+
"--after-context",
|
|
4570
|
+
"--before-context",
|
|
4571
|
+
"--color",
|
|
4572
|
+
"--colors",
|
|
4573
|
+
"--context",
|
|
4574
|
+
"--context-separator",
|
|
4575
|
+
"--dfa-size-limit",
|
|
4576
|
+
"--encoding",
|
|
4577
|
+
"--engine",
|
|
4578
|
+
"--field-context-separator",
|
|
4579
|
+
"--field-match-separator",
|
|
4580
|
+
"--file",
|
|
4581
|
+
"--generate",
|
|
4582
|
+
"--glob",
|
|
4583
|
+
"--hostname-bin",
|
|
4584
|
+
"--hyperlink-format",
|
|
4585
|
+
"--iglob",
|
|
4586
|
+
"--ignore-file",
|
|
4587
|
+
"--max-columns",
|
|
4588
|
+
"--max-count",
|
|
4589
|
+
"--max-depth",
|
|
4590
|
+
// An ALIAS of --max-depth, and it takes a value. The round-5 extraction read
|
|
4591
|
+
// alias lines as plain switches and swept it into noValue, which hard-blocked
|
|
4592
|
+
// `rg --maxdepth 2 .env src` while `--max-depth 2` ran (/code-review round 7).
|
|
4593
|
+
"--maxdepth",
|
|
4594
|
+
"--max-filesize",
|
|
4595
|
+
"--path-separator",
|
|
4596
|
+
"--pre",
|
|
4597
|
+
"--pre-glob",
|
|
4598
|
+
"--regexp",
|
|
4599
|
+
"--regex-size-limit",
|
|
4600
|
+
"--replace",
|
|
4601
|
+
"--sort",
|
|
4602
|
+
"--sortr",
|
|
4603
|
+
"--threads",
|
|
4604
|
+
"--type",
|
|
4605
|
+
"--type-add",
|
|
4606
|
+
"--type-clear",
|
|
4607
|
+
"--type-not"
|
|
4608
|
+
]),
|
|
4609
|
+
noValue: /* @__PURE__ */ new Set([
|
|
4610
|
+
"-.",
|
|
4611
|
+
"-0",
|
|
4612
|
+
"-a",
|
|
4613
|
+
"-b",
|
|
4614
|
+
"-c",
|
|
4615
|
+
"-F",
|
|
4616
|
+
"-h",
|
|
4617
|
+
"-H",
|
|
4618
|
+
"-i",
|
|
4619
|
+
"-I",
|
|
4620
|
+
"-l",
|
|
4621
|
+
"-L",
|
|
4622
|
+
"-n",
|
|
4623
|
+
"-N",
|
|
4624
|
+
"-o",
|
|
4625
|
+
"-p",
|
|
4626
|
+
"-P",
|
|
4627
|
+
"-q",
|
|
4628
|
+
"-s",
|
|
4629
|
+
"-S",
|
|
4630
|
+
"-u",
|
|
4631
|
+
"-U",
|
|
4632
|
+
"-v",
|
|
4633
|
+
"-V",
|
|
4634
|
+
"-w",
|
|
4635
|
+
"-x",
|
|
4636
|
+
"-z",
|
|
4637
|
+
"--auto-hybrid-regex",
|
|
4638
|
+
"--binary",
|
|
4639
|
+
"--block-buffered",
|
|
4640
|
+
"--byte-offset",
|
|
4641
|
+
"--case-sensitive",
|
|
4642
|
+
"--column",
|
|
4643
|
+
"--count",
|
|
4644
|
+
"--count-matches",
|
|
4645
|
+
"--crlf",
|
|
4646
|
+
"--debug",
|
|
4647
|
+
"--files",
|
|
4648
|
+
"--files-with-matches",
|
|
4649
|
+
"--files-without-match",
|
|
4650
|
+
"--fixed-strings",
|
|
4651
|
+
"--follow",
|
|
4652
|
+
"--glob-case-insensitive",
|
|
4653
|
+
"--heading",
|
|
4654
|
+
"--help",
|
|
4655
|
+
"--hidden",
|
|
4656
|
+
"--ignore-case",
|
|
4657
|
+
"--ignore-file-case-insensitive",
|
|
4658
|
+
"--include-zero",
|
|
4659
|
+
"--invert-match",
|
|
4660
|
+
"--json",
|
|
4661
|
+
"--line-buffered",
|
|
4662
|
+
"--line-number",
|
|
4663
|
+
"--line-regexp",
|
|
4664
|
+
"--max-columns-preview",
|
|
4665
|
+
"--mmap",
|
|
4666
|
+
"--multiline",
|
|
4667
|
+
"--multiline-dotall",
|
|
4668
|
+
"--no-column",
|
|
4669
|
+
"--no-config",
|
|
4670
|
+
"--no-context-separator",
|
|
4671
|
+
"--no-encoding",
|
|
4672
|
+
"--no-filename",
|
|
4673
|
+
"--no-ignore",
|
|
4674
|
+
"--no-ignore-dot",
|
|
4675
|
+
"--no-ignore-exclude",
|
|
4676
|
+
"--no-ignore-files",
|
|
4677
|
+
"--no-ignore-global",
|
|
4678
|
+
"--no-ignore-messages",
|
|
4679
|
+
"--no-ignore-parent",
|
|
4680
|
+
"--no-ignore-vcs",
|
|
4681
|
+
"--no-line-number",
|
|
4682
|
+
"--no-messages",
|
|
4683
|
+
"--no-pcre2-unicode",
|
|
4684
|
+
"--no-pre",
|
|
4685
|
+
"--no-require-git",
|
|
4686
|
+
"--no-unicode",
|
|
4687
|
+
"--null",
|
|
4688
|
+
"--null-data",
|
|
4689
|
+
"--one-file-system",
|
|
4690
|
+
"--only-matching",
|
|
4691
|
+
"--passthru",
|
|
4692
|
+
"--pcre2",
|
|
4693
|
+
"--pcre2-version",
|
|
4694
|
+
"--pretty",
|
|
4695
|
+
"--print0",
|
|
4696
|
+
"--quiet",
|
|
4697
|
+
"--search-zip",
|
|
4698
|
+
"--smart-case",
|
|
4699
|
+
"--sort-files",
|
|
4700
|
+
"--stats",
|
|
4701
|
+
"--stop-on-nonmatch",
|
|
4702
|
+
"--text",
|
|
4703
|
+
"--trace",
|
|
4704
|
+
"--trim",
|
|
4705
|
+
"--type-list",
|
|
4706
|
+
"--unrestricted",
|
|
4707
|
+
"--version",
|
|
4708
|
+
"--vimgrep",
|
|
4709
|
+
"--with-filename",
|
|
4710
|
+
"--word-regexp",
|
|
4711
|
+
// The COMPLETE remainder of `rg --help`, added after /code-review round 5
|
|
4712
|
+
// found 40 documented switches in neither set. The table is now the whole
|
|
4713
|
+
// option list: `rg --help` yields 149 long options, 35 of them value-taking.
|
|
4714
|
+
"--ignore",
|
|
4715
|
+
"--ignore-dot",
|
|
4716
|
+
"--ignore-exclude",
|
|
4717
|
+
"--ignore-files",
|
|
4718
|
+
"--ignore-global",
|
|
4719
|
+
"--ignore-messages",
|
|
4720
|
+
"--ignore-parent",
|
|
4721
|
+
"--ignore-vcs",
|
|
4722
|
+
"--messages",
|
|
4723
|
+
"--no-auto-hybrid-regex",
|
|
4724
|
+
"--no-binary",
|
|
4725
|
+
"--no-block-buffered",
|
|
4726
|
+
"--no-byte-offset",
|
|
4727
|
+
"--no-crlf",
|
|
4728
|
+
"--no-fixed-strings",
|
|
4729
|
+
"--no-follow",
|
|
4730
|
+
"--no-glob-case-insensitive",
|
|
4731
|
+
"--no-heading",
|
|
4732
|
+
"--no-hidden",
|
|
4733
|
+
"--no-ignore-file-case-insensitive",
|
|
4734
|
+
"--no-include-zero",
|
|
4735
|
+
"--no-invert-match",
|
|
4736
|
+
"--no-json",
|
|
4737
|
+
"--no-line-buffered",
|
|
4738
|
+
"--no-max-columns-preview",
|
|
4739
|
+
"--no-mmap",
|
|
4740
|
+
"--no-multiline",
|
|
4741
|
+
"--no-multiline-dotall",
|
|
4742
|
+
"--no-one-file-system",
|
|
4743
|
+
"--no-pcre2",
|
|
4744
|
+
"--no-search-zip",
|
|
4745
|
+
"--no-sort-files",
|
|
4746
|
+
"--no-stats",
|
|
4747
|
+
"--no-text",
|
|
4748
|
+
"--no-trim",
|
|
4749
|
+
"--passthrough",
|
|
4750
|
+
"--pcre2-unicode",
|
|
4751
|
+
"--require-git",
|
|
4752
|
+
"--unicode"
|
|
4753
|
+
]),
|
|
4754
|
+
patternFlags: /* @__PURE__ */ new Set(["-e", "--regexp"]),
|
|
4755
|
+
// `--files` and `--type-list` list or enumerate without a pattern. Founder
|
|
4756
|
+
// decision 2026-09-13: `rg --files ~/.ssh` stays BLOCKED, which this achieves
|
|
4757
|
+
// by leaving the directory in the judged list.
|
|
4758
|
+
noPatternFlags: /* @__PURE__ */ new Set(["-f", "--file", "--files", "--type-list", "--pcre2-version"])
|
|
4759
|
+
}
|
|
4760
|
+
};
|
|
4761
|
+
PATTERN_VERB_NAMES = Object.keys(PATTERN_VERBS);
|
|
4762
|
+
GREP_FILE_OPERANDS = /* @__PURE__ */ new Set(["-f", "--file", "--exclude-from", "--include"]);
|
|
4763
|
+
READER_VALUE_LETTERS = {
|
|
4764
|
+
awk: ["F", "v", "f"],
|
|
4765
|
+
gawk: ["F", "v", "f", "e", "E", "i", "l", "o", "p", "D"],
|
|
4766
|
+
sed: ["e", "f", "i", "l"],
|
|
4767
|
+
sort: ["C", "k", "o", "S", "t", "T"]
|
|
4768
|
+
};
|
|
4769
|
+
FILE_OPERAND_FLAGS = {
|
|
4770
|
+
grep: GREP_FILE_OPERANDS,
|
|
4771
|
+
egrep: GREP_FILE_OPERANDS,
|
|
4772
|
+
fgrep: GREP_FILE_OPERANDS,
|
|
4773
|
+
// rg and gawk are NOT installed on the measuring machine: these two rows are
|
|
4774
|
+
// from the shipped documentation (ripgrep `-f/--file`, `--ignore-file`; gawk
|
|
4775
|
+
// `-f/--file`) and are marked as such in the spec.
|
|
4776
|
+
// `-g/--glob/--iglob` name which files ripgrep SEARCHES, so an operand naming
|
|
4777
|
+
// a credential makes rg open it -- the same reason grep's `--include` is here.
|
|
4778
|
+
// Measured (/code-review round 3): `rg --hidden -g .env AWS tree` opened .env
|
|
4779
|
+
// and printed its contents.
|
|
4780
|
+
rg: /* @__PURE__ */ new Set(["-f", "--file", "--ignore-file", "-g", "--glob", "--iglob"]),
|
|
4781
|
+
sed: /* @__PURE__ */ new Set(["-f", "--file"]),
|
|
4782
|
+
awk: /* @__PURE__ */ new Set(["-f", "--file"]),
|
|
4783
|
+
gawk: /* @__PURE__ */ new Set(["-f", "--file"]),
|
|
4784
|
+
sort: /* @__PURE__ */ new Set(["--files0-from"])
|
|
4785
|
+
};
|
|
4230
4786
|
SCP_VALUE_FLAGS = ["i", "F", "o", "c", "S", "P", "J", "D", "W", "l"];
|
|
4787
|
+
TAR_VALUE_LETTERS = ["b", "C", "f", "F", "g", "H", "I", "K", "L", "N", "T", "V", "X"];
|
|
4788
|
+
ZIP_VALUE_LETTERS = ["b", "n", "P", "t", "s", "O", "x", "i"];
|
|
4789
|
+
RSYNC_VALUE_LETTERS = ["e", "f", "T", "B", "M"];
|
|
4231
4790
|
RSYNC_SKIP = [
|
|
4232
4791
|
"e",
|
|
4233
4792
|
"--rsh",
|
|
@@ -4239,21 +4798,35 @@ var init_dist = __esm({
|
|
|
4239
4798
|
"f",
|
|
4240
4799
|
"--filter"
|
|
4241
4800
|
];
|
|
4801
|
+
CP_VALUE_LETTERS = ["S", "t"];
|
|
4802
|
+
INSTALL_VALUE_LETTERS = ["S", "t", "g", "m", "o"];
|
|
4242
4803
|
COPY_VERBS = {
|
|
4243
|
-
cp: { source: "allButLast", targetDirFlag: true },
|
|
4244
|
-
mv: { source: "allButLast", targetDirFlag: true },
|
|
4245
|
-
install: { source: "allButLast", targetDirFlag: true },
|
|
4246
|
-
ln: { source: "first", targetDirFlag: true },
|
|
4247
|
-
scp: { source: "allButLast", skipFlags: SCP_VALUE_FLAGS },
|
|
4248
|
-
rsync: { source: "allButLast", skipFlags: RSYNC_SKIP },
|
|
4804
|
+
cp: { source: "allButLast", targetDirFlag: true, valueLetters: CP_VALUE_LETTERS },
|
|
4805
|
+
mv: { source: "allButLast", targetDirFlag: true, valueLetters: CP_VALUE_LETTERS },
|
|
4806
|
+
install: { source: "allButLast", targetDirFlag: true, valueLetters: INSTALL_VALUE_LETTERS },
|
|
4807
|
+
ln: { source: "first", targetDirFlag: true, valueLetters: CP_VALUE_LETTERS },
|
|
4808
|
+
scp: { source: "allButLast", skipFlags: SCP_VALUE_FLAGS, valueLetters: SCP_VALUE_FLAGS },
|
|
4809
|
+
rsync: { source: "allButLast", skipFlags: RSYNC_SKIP, valueLetters: RSYNC_VALUE_LETTERS },
|
|
4249
4810
|
tar: {
|
|
4250
4811
|
source: "archive",
|
|
4251
4812
|
archive: "tar",
|
|
4252
|
-
skipFlags: ["f", "X", "T", "--file", "--exclude", "--exclude-from", "--files-from"]
|
|
4813
|
+
skipFlags: ["f", "X", "T", "--file", "--exclude", "--exclude-from", "--files-from"],
|
|
4814
|
+
valueLetters: TAR_VALUE_LETTERS
|
|
4815
|
+
},
|
|
4816
|
+
zip: {
|
|
4817
|
+
source: "archive",
|
|
4818
|
+
archive: "zip",
|
|
4819
|
+
skipFlags: ["x", "i", "--exclude", "--include"],
|
|
4820
|
+
valueLetters: ZIP_VALUE_LETTERS
|
|
4253
4821
|
},
|
|
4254
|
-
zip: { source: "archive", archive: "zip", skipFlags: ["x", "i", "--exclude", "--include"] },
|
|
4255
4822
|
ar: { source: "archive", archive: "ar" },
|
|
4256
|
-
|
|
4823
|
+
// 7z switches are INLINE only (`-mx9`, `-px`, `-x!pat`), so no following word is
|
|
4824
|
+
// ever a switch's operand -- which is why the short `x` is NOT a skipFlag here
|
|
4825
|
+
// and valueLetters is empty. Keeping the short `x` made `7z a out.7z -mx KEY`
|
|
4826
|
+
// drop the credential as an exclusion operand (/code-review round 8), and the
|
|
4827
|
+
// derived "every skipped letter is a value letter" row in jail-copy.spec.ts is
|
|
4828
|
+
// what keeps the two tables honest about it.
|
|
4829
|
+
"7z": { source: "archive", archive: "7z", skipFlags: ["--exclude"], valueLetters: [] },
|
|
4257
4830
|
gzip: { source: "all" },
|
|
4258
4831
|
bzip2: { source: "all" },
|
|
4259
4832
|
xz: { source: "all" },
|
|
@@ -4575,6 +5148,8 @@ var init_dist = __esm({
|
|
|
4575
5148
|
};
|
|
4576
5149
|
isReaderWord = (w) => w !== null && FS_READ_TOOLS.has(baseWord(w));
|
|
4577
5150
|
positionalAfter = (words, from, to = words.length) => positionedArgs(words, from, to).map((a) => a.value);
|
|
5151
|
+
NONE = { kind: "none" };
|
|
5152
|
+
UNKNOWN = { kind: "unknown" };
|
|
4578
5153
|
DEFAULT_EGRESS_ALLOWLIST = [
|
|
4579
5154
|
// node9's own control plane (api, app, dev-api, staging and the apex).
|
|
4580
5155
|
// Without it, turning egress on asks the user to approve node9 itself.
|
|
@@ -4764,6 +5339,8 @@ var init_dist = __esm({
|
|
|
4764
5339
|
block: 2
|
|
4765
5340
|
};
|
|
4766
5341
|
SQL_DML_KEYWORDS = /* @__PURE__ */ new Set(["select", "insert", "update", "delete", "merge", "upsert"]);
|
|
5342
|
+
TERMINAL_ESCAPE_RE = /\x1b\[[0-9;?]*[A-Za-z]|\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)|\x1b[@-_]|[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g;
|
|
5343
|
+
CONTROL_CHAR_RE = /[\x00-\x1F\x7F]/g;
|
|
4767
5344
|
aws_default = {
|
|
4768
5345
|
name: "aws",
|
|
4769
5346
|
description: "Protects AWS infrastructure from destructive AI operations",
|
|
@@ -5541,6 +6118,7 @@ var init_dist = __esm({
|
|
|
5541
6118
|
longOutputRedactions: 1
|
|
5542
6119
|
};
|
|
5543
6120
|
LOOP_THRESHOLD_FOR_WASTE = 3;
|
|
6121
|
+
MAX_BLAST_PATH = 4096;
|
|
5544
6122
|
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;
|
|
5545
6123
|
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;
|
|
5546
6124
|
FILE_TOOLS = /* @__PURE__ */ new Set([
|
|
@@ -5619,10 +6197,8 @@ var init_dist = __esm({
|
|
|
5619
6197
|
{ view: "separators-stripped", decoder: "separators", stripped: true }
|
|
5620
6198
|
];
|
|
5621
6199
|
LONG_OUTPUT_THRESHOLD_BYTES = 100 * 1024;
|
|
5622
|
-
CANONICAL_EXTRACTOR_VERSION = "canonical-
|
|
6200
|
+
CANONICAL_EXTRACTOR_VERSION = "canonical-v15";
|
|
5623
6201
|
DEDUPE_PREVIEW_LEN = 120;
|
|
5624
|
-
TERMINAL_ESCAPE_RE = // eslint-disable-next-line no-control-regex
|
|
5625
|
-
/\x1b\[[0-9;?]*[A-Za-z]|\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)|\x1b[@-_]|[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g;
|
|
5626
6202
|
ENGINE_VERSION = "1.4.0";
|
|
5627
6203
|
}
|
|
5628
6204
|
});
|
|
@@ -8170,6 +8746,14 @@ var init_context_sniper = __esm({
|
|
|
8170
8746
|
}
|
|
8171
8747
|
});
|
|
8172
8748
|
|
|
8749
|
+
// src/utils/safe-text.ts
|
|
8750
|
+
var init_safe_text = __esm({
|
|
8751
|
+
"src/utils/safe-text.ts"() {
|
|
8752
|
+
"use strict";
|
|
8753
|
+
init_dist();
|
|
8754
|
+
}
|
|
8755
|
+
});
|
|
8756
|
+
|
|
8173
8757
|
// src/ui/native.ts
|
|
8174
8758
|
import { spawn } from "child_process";
|
|
8175
8759
|
import path11 from "path";
|
|
@@ -8281,7 +8865,7 @@ function escapePango(text) {
|
|
|
8281
8865
|
function buildPlainMessage(toolName, formattedArgs, agent, explainableLabel, locked, allowCount = 1, ruleDescription) {
|
|
8282
8866
|
const lines = [];
|
|
8283
8867
|
if (locked) lines.push("\u26A0\uFE0F LOCKED BY ADMIN POLICY\n");
|
|
8284
|
-
const safeAgent = (agent ?? "AI Agent"
|
|
8868
|
+
const safeAgent = safeMessage(agent ?? "AI Agent", 80);
|
|
8285
8869
|
lines.push(`\u{1F916} ${safeAgent} | \u{1F527} ${toolName}`);
|
|
8286
8870
|
lines.push(`\u{1F6E1}\uFE0F ${explainableLabel || "Security Policy"}`);
|
|
8287
8871
|
if (ruleDescription) lines.push(`\u2139 ${ruleDescription}`);
|
|
@@ -8416,6 +9000,7 @@ var init_native = __esm({
|
|
|
8416
9000
|
"src/ui/native.ts"() {
|
|
8417
9001
|
"use strict";
|
|
8418
9002
|
init_context_sniper();
|
|
9003
|
+
init_safe_text();
|
|
8419
9004
|
isTestEnv = () => {
|
|
8420
9005
|
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";
|
|
8421
9006
|
};
|
|
@@ -8805,14 +9390,14 @@ async function resolveNode9SaaS(requestId, creds, approved, decidedBy) {
|
|
|
8805
9390
|
if (!res.ok) {
|
|
8806
9391
|
fs12.appendFileSync(
|
|
8807
9392
|
HOOK_DEBUG_LOG,
|
|
8808
|
-
`[resolve-cloud] PATCH ${resolveUrl} \u2192 HTTP ${res.status}
|
|
9393
|
+
`[resolve-cloud] PATCH ${safeMessage(resolveUrl, 200)} \u2192 HTTP ${res.status}
|
|
8809
9394
|
`
|
|
8810
9395
|
);
|
|
8811
9396
|
}
|
|
8812
9397
|
} catch (err2) {
|
|
8813
9398
|
fs12.appendFileSync(
|
|
8814
9399
|
HOOK_DEBUG_LOG,
|
|
8815
|
-
`[resolve-cloud] PATCH failed for ${requestId}: ${err2
|
|
9400
|
+
`[resolve-cloud] PATCH failed for ${safeMessage(requestId, 64)}: ${safeMessage(err2)}
|
|
8816
9401
|
`
|
|
8817
9402
|
);
|
|
8818
9403
|
}
|
|
@@ -8822,6 +9407,7 @@ var init_cloud = __esm({
|
|
|
8822
9407
|
"src/auth/cloud.ts"() {
|
|
8823
9408
|
"use strict";
|
|
8824
9409
|
init_audit();
|
|
9410
|
+
init_safe_text();
|
|
8825
9411
|
DLP_SAMPLE_MAX_LEN = 200;
|
|
8826
9412
|
DLP_PATTERN_MAX_LEN = 100;
|
|
8827
9413
|
KNOWN_CHECKED_BY = /* @__PURE__ */ new Set([
|
|
@@ -8954,9 +9540,8 @@ async function authorizeHeadless(toolName, args, meta, options) {
|
|
|
8954
9540
|
if (!options?.calledFromDaemon) {
|
|
8955
9541
|
const actId = randomUUID2();
|
|
8956
9542
|
const actTs = Date.now();
|
|
8957
|
-
const
|
|
8958
|
-
const
|
|
8959
|
-
const sanitizedMcpServer = meta?.mcpServer ? stripAnsi2(meta.mcpServer).slice(0, 40) : void 0;
|
|
9543
|
+
const sanitizedAgent = meta?.agent ? safeMessage(meta.agent, 80) : void 0;
|
|
9544
|
+
const sanitizedMcpServer = meta?.mcpServer ? safeMessage(meta.mcpServer, 40) : void 0;
|
|
8960
9545
|
const socketOk = await notifyActivity({
|
|
8961
9546
|
id: actId,
|
|
8962
9547
|
ts: actTs,
|
|
@@ -9831,6 +10416,7 @@ var init_orchestrator = __esm({
|
|
|
9831
10416
|
init_loop_detector();
|
|
9832
10417
|
init_shields();
|
|
9833
10418
|
init_jail();
|
|
10419
|
+
init_safe_text();
|
|
9834
10420
|
WRITE_TOOLS = /* @__PURE__ */ new Set([
|
|
9835
10421
|
"write",
|
|
9836
10422
|
"write_file",
|
|
@@ -14436,7 +15022,7 @@ async function postCostBatches(apiUrl, apiKey, machineId, entries) {
|
|
|
14436
15022
|
}
|
|
14437
15023
|
}
|
|
14438
15024
|
} catch (err2) {
|
|
14439
|
-
fs26.appendFileSync(HOOK_DEBUG_LOG, `[cost-sync] ${err2
|
|
15025
|
+
fs26.appendFileSync(HOOK_DEBUG_LOG, `[cost-sync] ${safeMessage(err2)}
|
|
14440
15026
|
`);
|
|
14441
15027
|
}
|
|
14442
15028
|
}
|
|
@@ -14475,6 +15061,7 @@ var init_costSync = __esm({
|
|
|
14475
15061
|
init_cost_gemini();
|
|
14476
15062
|
init_cost_copilot();
|
|
14477
15063
|
init_session_files();
|
|
15064
|
+
init_safe_text();
|
|
14478
15065
|
SYNC_INTERVAL_MS = 10 * 60 * 1e3;
|
|
14479
15066
|
claudeSource = {
|
|
14480
15067
|
id: "claude",
|
|
@@ -15310,9 +15897,6 @@ function fmtTs(ts) {
|
|
|
15310
15897
|
return ts.slice(0, 10);
|
|
15311
15898
|
}
|
|
15312
15899
|
}
|
|
15313
|
-
function stripTerminalEscapes(s) {
|
|
15314
|
-
return s.replace(TERMINAL_ESCAPE_RE2, "");
|
|
15315
|
-
}
|
|
15316
15900
|
function preview(input, max) {
|
|
15317
15901
|
const cmd = input.command ?? input.query ?? input.file_path ?? JSON.stringify(input);
|
|
15318
15902
|
const s = stripTerminalEscapes(String(cmd)).replace(/\s+/g, " ").trim();
|
|
@@ -18027,7 +18611,7 @@ function registerScanCommand(program2) {
|
|
|
18027
18611
|
}
|
|
18028
18612
|
);
|
|
18029
18613
|
}
|
|
18030
|
-
var toolInspectionMap, CODE_EXTENSIONS, SELF_OUTPUT_MARKERS,
|
|
18614
|
+
var 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;
|
|
18031
18615
|
var init_scan = __esm({
|
|
18032
18616
|
"src/cli/commands/scan.ts"() {
|
|
18033
18617
|
"use strict";
|
|
@@ -18053,6 +18637,7 @@ var init_scan = __esm({
|
|
|
18053
18637
|
init_scan_json();
|
|
18054
18638
|
init_session_files();
|
|
18055
18639
|
init_scan_history();
|
|
18640
|
+
init_safe_text();
|
|
18056
18641
|
toolInspectionMap = DEFAULT_CONFIG.policy.toolInspection;
|
|
18057
18642
|
CODE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
18058
18643
|
".ts",
|
|
@@ -18087,7 +18672,6 @@ var init_scan = __esm({
|
|
|
18087
18672
|
/\bseverity:\s*['"](?:block|review|allow)['"]/,
|
|
18088
18673
|
/NODE9 SECURITY ALERT/
|
|
18089
18674
|
];
|
|
18090
|
-
TERMINAL_ESCAPE_RE2 = /\x1b\[[0-9;?]*[A-Za-z]|\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)|\x1b[@-_]|[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g;
|
|
18091
18675
|
LOOP_TOOLS = /* @__PURE__ */ new Set([
|
|
18092
18676
|
"bash",
|
|
18093
18677
|
"execute_bash",
|
|
@@ -18578,7 +19162,7 @@ function atomicWriteSync2(filePath, data, options) {
|
|
|
18578
19162
|
function redactArgs(value) {
|
|
18579
19163
|
if (!value || typeof value !== "object") return value;
|
|
18580
19164
|
if (Array.isArray(value)) return value.map(redactArgs);
|
|
18581
|
-
const result =
|
|
19165
|
+
const result = /* @__PURE__ */ Object.create(null);
|
|
18582
19166
|
for (const [k, v] of Object.entries(value)) {
|
|
18583
19167
|
result[k] = SECRET_KEY_RE.test(k) ? "[REDACTED]" : redactArgs(v);
|
|
18584
19168
|
}
|
|
@@ -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
|
}
|
|
@@ -50665,7 +51249,7 @@ async function startTail(options = {}) {
|
|
|
50665
51249
|
req.on("error", (err2) => {
|
|
50666
51250
|
const msg = err2.code === "ECONNREFUSED" ? "Daemon is not running. Start it with: node9 daemon start" : err2.message;
|
|
50667
51251
|
console.error(chalk44.red(`
|
|
50668
|
-
\u274C ${msg}`));
|
|
51252
|
+
\u274C ${safeMessage(msg)}`));
|
|
50669
51253
|
process.exit(1);
|
|
50670
51254
|
});
|
|
50671
51255
|
}
|
|
@@ -50676,6 +51260,7 @@ var init_tail = __esm({
|
|
|
50676
51260
|
init_startup_log();
|
|
50677
51261
|
init_daemon2();
|
|
50678
51262
|
init_daemon();
|
|
51263
|
+
init_safe_text();
|
|
50679
51264
|
PID_FILE = path74.join(os66.homedir(), ".node9", "daemon.pid");
|
|
50680
51265
|
ICONS = {
|
|
50681
51266
|
bash: "\u{1F4BB}",
|
|
@@ -51322,9 +51907,7 @@ function shellInvocation(command) {
|
|
|
51322
51907
|
}
|
|
51323
51908
|
|
|
51324
51909
|
// src/proxy/index.ts
|
|
51325
|
-
|
|
51326
|
-
return value.replace(/[\x00-\x1F\x7F]/g, "");
|
|
51327
|
-
}
|
|
51910
|
+
init_safe_text();
|
|
51328
51911
|
async function runProxy(targetCommand) {
|
|
51329
51912
|
const commandParts = parseCommandString(targetCommand);
|
|
51330
51913
|
const cmd = commandParts[0];
|
|
@@ -51360,7 +51943,7 @@ async function runProxy(targetCommand) {
|
|
|
51360
51943
|
try {
|
|
51361
51944
|
const name = message.params?.name || message.params?.tool_name || "unknown";
|
|
51362
51945
|
const toolArgs = message.params?.arguments || message.params?.tool_input || {};
|
|
51363
|
-
const result = await authorizeHeadless(
|
|
51946
|
+
const result = await authorizeHeadless(stripControlChars(name), toolArgs, {
|
|
51364
51947
|
agent: "Proxy/MCP"
|
|
51365
51948
|
});
|
|
51366
51949
|
if (!result.approved) {
|
|
@@ -51608,17 +52191,27 @@ init_machine_id();
|
|
|
51608
52191
|
|
|
51609
52192
|
// src/utils/open-browser.ts
|
|
51610
52193
|
import { spawn as spawn4 } from "child_process";
|
|
52194
|
+
function isOpenableUrl(url) {
|
|
52195
|
+
let u;
|
|
52196
|
+
try {
|
|
52197
|
+
u = new URL(url);
|
|
52198
|
+
} catch {
|
|
52199
|
+
return false;
|
|
52200
|
+
}
|
|
52201
|
+
if (u.protocol !== "https:" && u.protocol !== "http:") return false;
|
|
52202
|
+
return !/[\x00-\x20\x7F"'`]/.test(url);
|
|
52203
|
+
}
|
|
51611
52204
|
function openBrowser(url) {
|
|
52205
|
+
if (!isOpenableUrl(url)) return false;
|
|
51612
52206
|
if (process.env.SSH_CONNECTION || process.env.SSH_TTY) return false;
|
|
51613
52207
|
if (process.platform === "linux" && !process.env.DISPLAY && !process.env.WAYLAND_DISPLAY) {
|
|
51614
52208
|
return false;
|
|
51615
52209
|
}
|
|
51616
|
-
const
|
|
52210
|
+
const [cmd, args] = process.platform === "darwin" ? ["open", [url]] : process.platform === "win32" ? ["rundll32.exe", ["url.dll,FileProtocolHandler", url]] : ["xdg-open", [url]];
|
|
51617
52211
|
try {
|
|
51618
|
-
const child = spawn4(
|
|
52212
|
+
const child = spawn4(cmd, args, {
|
|
51619
52213
|
stdio: "ignore",
|
|
51620
|
-
detached: true
|
|
51621
|
-
shell: process.platform === "win32"
|
|
52214
|
+
detached: true
|
|
51622
52215
|
});
|
|
51623
52216
|
child.on("error", () => {
|
|
51624
52217
|
});
|
|
@@ -51679,6 +52272,7 @@ function postJson2(url, body, bearer) {
|
|
|
51679
52272
|
}
|
|
51680
52273
|
|
|
51681
52274
|
// src/auth/device-login.ts
|
|
52275
|
+
init_safe_text();
|
|
51682
52276
|
var sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
51683
52277
|
async function runDeviceLogin(opts = {}) {
|
|
51684
52278
|
const startUrl = resolveCloudEndpoint("/device/start", opts.apiUrl);
|
|
@@ -51694,14 +52288,16 @@ async function runDeviceLogin(opts = {}) {
|
|
|
51694
52288
|
} catch (e) {
|
|
51695
52289
|
return {
|
|
51696
52290
|
ok: false,
|
|
51697
|
-
reason: `Could not reach the node9 cloud: ${
|
|
52291
|
+
reason: `Could not reach the node9 cloud: ${safeMessage(e)}`
|
|
51698
52292
|
};
|
|
51699
52293
|
}
|
|
51700
52294
|
console.log("");
|
|
51701
52295
|
console.log(` Open this link to approve the connection:`);
|
|
51702
|
-
console.log(` ${chalk11.cyan.underline(start.verificationUrl)}`);
|
|
52296
|
+
console.log(` ${chalk11.cyan.underline(safeMessage(start.verificationUrl, 200))}`);
|
|
51703
52297
|
console.log("");
|
|
51704
|
-
console.log(
|
|
52298
|
+
console.log(
|
|
52299
|
+
` Code: ${chalk11.bold(safeMessage(start.userCode, 40))} ${chalk11.gray("(match it in the browser)")}`
|
|
52300
|
+
);
|
|
51705
52301
|
console.log("");
|
|
51706
52302
|
const opened = opts.noBrowser ? false : openBrowser(start.verificationUrl);
|
|
51707
52303
|
console.log(
|
|
@@ -51747,6 +52343,7 @@ import * as fs50 from "fs";
|
|
|
51747
52343
|
import * as os45 from "os";
|
|
51748
52344
|
import * as path48 from "path";
|
|
51749
52345
|
import chalk12 from "chalk";
|
|
52346
|
+
init_safe_text();
|
|
51750
52347
|
async function revokeSelf(creds) {
|
|
51751
52348
|
const url = creds.apiUrl.replace(/\/$/, "") + "/machines/self/disconnect";
|
|
51752
52349
|
try {
|
|
@@ -51787,7 +52384,7 @@ function registerLogoutCommand(program2) {
|
|
|
51787
52384
|
} else if (res.outcome === "already") {
|
|
51788
52385
|
console.log(chalk12.gray("\u2713 Cloud: this machine was already disconnected."));
|
|
51789
52386
|
} else {
|
|
51790
|
-
console.log(chalk12.yellow(`\u26A0 Could not reach the cloud (${res.detail}).`));
|
|
52387
|
+
console.log(chalk12.yellow(`\u26A0 Could not reach the cloud (${safeMessage(res.detail)}).`));
|
|
51791
52388
|
console.log(
|
|
51792
52389
|
chalk12.yellow(" The key was removed locally, but is still listed in the dashboard \u2014")
|
|
51793
52390
|
);
|
|
@@ -52094,9 +52691,7 @@ function discardPendingReview(key, now = Date.now()) {
|
|
|
52094
52691
|
|
|
52095
52692
|
// src/cli/commands/check.ts
|
|
52096
52693
|
init_hook_payload();
|
|
52097
|
-
|
|
52098
|
-
return value.replace(/[\x00-\x1F\x7F]/g, "");
|
|
52099
|
-
}
|
|
52694
|
+
init_safe_text();
|
|
52100
52695
|
function detectAiAgent(payload) {
|
|
52101
52696
|
const meta = payload.meta;
|
|
52102
52697
|
if (meta && typeof meta === "object") {
|
|
@@ -52342,10 +52937,13 @@ RAW: ${raw}
|
|
|
52342
52937
|
const logPath = path51.join(os48.homedir(), ".node9", "hook-debug.log");
|
|
52343
52938
|
if (!fs53.existsSync(path51.dirname(logPath)))
|
|
52344
52939
|
fs53.mkdirSync(path51.dirname(logPath), { recursive: true });
|
|
52345
|
-
fs53.appendFileSync(
|
|
52346
|
-
|
|
52940
|
+
fs53.appendFileSync(
|
|
52941
|
+
logPath,
|
|
52942
|
+
`[${(/* @__PURE__ */ new Date()).toISOString()}] STDIN: ${JSON.stringify(raw)}
|
|
52943
|
+
`
|
|
52944
|
+
);
|
|
52347
52945
|
}
|
|
52348
|
-
const rawToolName =
|
|
52946
|
+
const rawToolName = stripControlChars(extractToolName(payload));
|
|
52349
52947
|
const toolName = canonicalToolName(rawToolName);
|
|
52350
52948
|
const toolInput = canonicalToolInput(rawToolName, extractToolInput(payload));
|
|
52351
52949
|
const agent = agentOverride ?? detectAiAgent(payload);
|
|
@@ -52735,6 +53333,7 @@ function containsShellMetachar(token) {
|
|
|
52735
53333
|
|
|
52736
53334
|
// src/cli/commands/log.ts
|
|
52737
53335
|
init_hook_payload();
|
|
53336
|
+
init_safe_text();
|
|
52738
53337
|
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;
|
|
52739
53338
|
function detectTestResult(command, output) {
|
|
52740
53339
|
if (!TEST_COMMAND_RE2.test(command)) return null;
|
|
@@ -52753,9 +53352,6 @@ var CONFIDENCE_RANK = { low: 0, medium: 1, high: 2 };
|
|
|
52753
53352
|
function atLeastConfidence(c, min) {
|
|
52754
53353
|
return CONFIDENCE_RANK[c] >= CONFIDENCE_RANK[min];
|
|
52755
53354
|
}
|
|
52756
|
-
function sanitize3(value) {
|
|
52757
|
-
return value.replace(/[\x00-\x1F\x7F]/g, "");
|
|
52758
|
-
}
|
|
52759
53355
|
function scanCoveredEverything(value, depth = 0) {
|
|
52760
53356
|
if (value === null || value === void 0) return true;
|
|
52761
53357
|
if (typeof value === "string") return value.length <= DLP_SCAN_LIMITS.maxStringBytes;
|
|
@@ -52794,7 +53390,7 @@ function registerLogCommand(program2) {
|
|
|
52794
53390
|
if (!raw || raw.trim() === "") process.exit(0);
|
|
52795
53391
|
const payload = JSON.parse(raw);
|
|
52796
53392
|
if (payload.toolCall === null) process.exit(0);
|
|
52797
|
-
const rawToolName =
|
|
53393
|
+
const rawToolName = stripControlChars(extractToolName(payload, "unknown"));
|
|
52798
53394
|
const tool = canonicalToolName(rawToolName);
|
|
52799
53395
|
const rawInput = canonicalToolInput(rawToolName, extractToolInput(payload));
|
|
52800
53396
|
const metaTag = (() => {
|
|
@@ -55626,6 +56222,7 @@ import http5 from "http";
|
|
|
55626
56222
|
import https8 from "https";
|
|
55627
56223
|
import { URL as URL5 } from "url";
|
|
55628
56224
|
import chalk22 from "chalk";
|
|
56225
|
+
init_safe_text();
|
|
55629
56226
|
function resolveConnectUrl(apiUrl) {
|
|
55630
56227
|
return resolveCloudEndpoint("/cli/connect", apiUrl);
|
|
55631
56228
|
}
|
|
@@ -55684,7 +56281,7 @@ function registerConnectCommand(program2) {
|
|
|
55684
56281
|
try {
|
|
55685
56282
|
resp = await postConnect(resolveConnectUrl(options.apiUrl), token);
|
|
55686
56283
|
} catch (e) {
|
|
55687
|
-
console.error(chalk22.red(`\u2717 ${e
|
|
56284
|
+
console.error(chalk22.red(`\u2717 ${safeMessage(e) || "Connect failed."}`));
|
|
55688
56285
|
process.exitCode = 1;
|
|
55689
56286
|
return;
|
|
55690
56287
|
}
|
|
@@ -55771,9 +56368,7 @@ init_mcp_pin();
|
|
|
55771
56368
|
init_mcp_cmd();
|
|
55772
56369
|
init_mcp_tools();
|
|
55773
56370
|
init_daemon();
|
|
55774
|
-
|
|
55775
|
-
return value.replace(/[\x00-\x1F\x7F]/g, "");
|
|
55776
|
-
}
|
|
56371
|
+
init_safe_text();
|
|
55777
56372
|
var RPC_INVALID_REQUEST = -32600;
|
|
55778
56373
|
var RPC_SERVER_ERROR = -32e3;
|
|
55779
56374
|
function isValidId(id) {
|
|
@@ -55797,7 +56392,7 @@ function normalizeClientName(name) {
|
|
|
55797
56392
|
if (lower.includes("gemini")) return "Gemini";
|
|
55798
56393
|
if (lower.includes("cline")) return "Cline";
|
|
55799
56394
|
if (lower.includes("continue")) return "Continue";
|
|
55800
|
-
const sanitized =
|
|
56395
|
+
const sanitized = stripControlChars(name).slice(0, 40);
|
|
55801
56396
|
return sanitized.length > 0 ? sanitized : void 0;
|
|
55802
56397
|
}
|
|
55803
56398
|
function reportPinMismatchToCloud(serverKey, serverLabel, agent) {
|
|
@@ -55977,7 +56572,7 @@ async function runMcpGateway(upstreamCommand, configName) {
|
|
|
55977
56572
|
if (!deferredStdinEnd) agentIn.pause();
|
|
55978
56573
|
authPending = true;
|
|
55979
56574
|
try {
|
|
55980
|
-
const toolName =
|
|
56575
|
+
const toolName = stripControlChars(
|
|
55981
56576
|
String(message.params?.name ?? message.params?.tool_name ?? "unknown")
|
|
55982
56577
|
);
|
|
55983
56578
|
const toolArgs = message.params?.arguments ?? message.params?.tool_input ?? {};
|
|
@@ -61417,16 +62012,13 @@ Persistent decisions (${entries.length})
|
|
|
61417
62012
|
}
|
|
61418
62013
|
|
|
61419
62014
|
// src/cli/commands/dlp.ts
|
|
62015
|
+
init_safe_text();
|
|
61420
62016
|
import chalk42 from "chalk";
|
|
61421
62017
|
import fs77 from "fs";
|
|
61422
62018
|
import path72 from "path";
|
|
61423
62019
|
import os64 from "os";
|
|
61424
62020
|
var AUDIT_LOG = path72.join(os64.homedir(), ".node9", "audit.log");
|
|
61425
62021
|
var RESOLVED_FILE = path72.join(os64.homedir(), ".node9", "dlp-resolved.json");
|
|
61426
|
-
var ANSI_RE = /\x1b(?:\[[0-9;?]*[a-zA-Z]|\][^\x07\x1b]*(?:\x07|\x1b\\)|[@-_])/g;
|
|
61427
|
-
function stripAnsi(s) {
|
|
61428
|
-
return s.replace(ANSI_RE, "");
|
|
61429
|
-
}
|
|
61430
62022
|
function loadResolved() {
|
|
61431
62023
|
try {
|
|
61432
62024
|
const raw = JSON.parse(fs77.readFileSync(RESOLVED_FILE, "utf-8"));
|
|
@@ -61520,10 +62112,10 @@ function registerDlpCommand(program2) {
|
|
|
61520
62112
|
" " + chalk42.red("\u25CF") + " " + chalk42.white(e.dlpPattern ?? "Secret") + chalk42.dim(" " + fmtDate3(e.ts))
|
|
61521
62113
|
);
|
|
61522
62114
|
if (e.dlpSample) {
|
|
61523
|
-
console.log(" " + chalk42.dim("Sample: ") + chalk42.yellow(
|
|
62115
|
+
console.log(" " + chalk42.dim("Sample: ") + chalk42.yellow(safeMessage(e.dlpSample)));
|
|
61524
62116
|
}
|
|
61525
62117
|
if (e.project) {
|
|
61526
|
-
console.log(" " + chalk42.dim("Project: ") + chalk42.dim(
|
|
62118
|
+
console.log(" " + chalk42.dim("Project: ") + chalk42.dim(safeMessage(e.project)));
|
|
61527
62119
|
}
|
|
61528
62120
|
console.log("");
|
|
61529
62121
|
}
|
|
@@ -61726,6 +62318,7 @@ function registerMaskCommand(program2) {
|
|
|
61726
62318
|
|
|
61727
62319
|
// src/cli.ts
|
|
61728
62320
|
init_blast();
|
|
62321
|
+
init_safe_text();
|
|
61729
62322
|
var { version } = JSON.parse(
|
|
61730
62323
|
fs81.readFileSync(path76.join(__dirname, "../package.json"), "utf-8")
|
|
61731
62324
|
);
|
|
@@ -61758,7 +62351,7 @@ program.command("login").argument("[apiKey]", "Service/legacy key. Omit to log i
|
|
|
61758
62351
|
cliVersion: version
|
|
61759
62352
|
});
|
|
61760
62353
|
if (!res.ok) {
|
|
61761
|
-
console.error(chalk45.red(`\u2717 ${res.reason}`));
|
|
62354
|
+
console.error(chalk45.red(`\u2717 ${safeMessage(res.reason)}`));
|
|
61762
62355
|
process.exitCode = 1;
|
|
61763
62356
|
return;
|
|
61764
62357
|
}
|