@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/index.js
CHANGED
|
@@ -1510,6 +1510,19 @@ function parseShared(command) {
|
|
|
1510
1510
|
astCache.set(command, parsed);
|
|
1511
1511
|
return parsed;
|
|
1512
1512
|
}
|
|
1513
|
+
function byteOffsetToCharIndex(command) {
|
|
1514
|
+
if (!/[^\u0000-\u007F]/.test(command)) return null;
|
|
1515
|
+
const map = /* @__PURE__ */ new Map();
|
|
1516
|
+
let byte = 0;
|
|
1517
|
+
for (let i = 0; i < command.length; ) {
|
|
1518
|
+
map.set(byte, i);
|
|
1519
|
+
const cp = command.codePointAt(i);
|
|
1520
|
+
byte += cp < 128 ? 1 : cp < 2048 ? 2 : cp < 65536 ? 3 : 4;
|
|
1521
|
+
i += cp > 65535 ? 2 : 1;
|
|
1522
|
+
}
|
|
1523
|
+
map.set(byte, command.length);
|
|
1524
|
+
return (b) => map.get(b) ?? -1;
|
|
1525
|
+
}
|
|
1513
1526
|
function cachedNormalize(command, compute) {
|
|
1514
1527
|
const hit = normalizeCache.get(command);
|
|
1515
1528
|
if (hit !== void 0) {
|
|
@@ -1539,6 +1552,8 @@ function normalizeCommandForPolicyImpl(command) {
|
|
|
1539
1552
|
const f = parseShared(command);
|
|
1540
1553
|
if (f === PARSE_FAIL) return { posix: command, separator: command };
|
|
1541
1554
|
try {
|
|
1555
|
+
const toCharIndex = byteOffsetToCharIndex(command);
|
|
1556
|
+
const at = (byteOffset) => toCharIndex === null ? byteOffset : toCharIndex(byteOffset);
|
|
1542
1557
|
const strips = [];
|
|
1543
1558
|
const rewrites = [];
|
|
1544
1559
|
const quoteOnlyRewrites = [];
|
|
@@ -1559,8 +1574,9 @@ function normalizeCommandForPolicyImpl(command) {
|
|
|
1559
1574
|
const quotedNode = nextParts[0];
|
|
1560
1575
|
const nt = syntax.NodeType(quotedNode);
|
|
1561
1576
|
const markStrip = () => {
|
|
1562
|
-
const s = next.Pos().Offset();
|
|
1563
|
-
const e = next.End().Offset();
|
|
1577
|
+
const s = at(next.Pos().Offset());
|
|
1578
|
+
const e = at(next.End().Offset());
|
|
1579
|
+
if (s < 0 || e < 0) return;
|
|
1564
1580
|
strips.push([s, e]);
|
|
1565
1581
|
msgSpans.add(`${s}:${e}`);
|
|
1566
1582
|
};
|
|
@@ -1577,8 +1593,9 @@ function normalizeCommandForPolicyImpl(command) {
|
|
|
1577
1593
|
}
|
|
1578
1594
|
}
|
|
1579
1595
|
for (const arg of args) {
|
|
1580
|
-
const s = arg.Pos().Offset();
|
|
1581
|
-
const e = arg.End().Offset();
|
|
1596
|
+
const s = at(arg.Pos().Offset());
|
|
1597
|
+
const e = at(arg.End().Offset());
|
|
1598
|
+
if (s < 0 || e < 0) continue;
|
|
1582
1599
|
if (msgSpans.has(`${s}:${e}`)) continue;
|
|
1583
1600
|
const resolved = resolveWordLiteral(arg);
|
|
1584
1601
|
if (resolved === null) continue;
|
|
@@ -1700,7 +1717,345 @@ var FS_READ_TOOLS = /* @__PURE__ */ new Set([
|
|
|
1700
1717
|
"nl",
|
|
1701
1718
|
"dd"
|
|
1702
1719
|
]);
|
|
1720
|
+
var GREP_SHAPE = {
|
|
1721
|
+
takesValue: /* @__PURE__ */ new Set([
|
|
1722
|
+
"-A",
|
|
1723
|
+
"-B",
|
|
1724
|
+
"-C",
|
|
1725
|
+
"-D",
|
|
1726
|
+
"-d",
|
|
1727
|
+
"-e",
|
|
1728
|
+
"-f",
|
|
1729
|
+
"-m",
|
|
1730
|
+
"--after-context",
|
|
1731
|
+
"--before-context",
|
|
1732
|
+
"--binary-files",
|
|
1733
|
+
"--context",
|
|
1734
|
+
"--devices",
|
|
1735
|
+
"--directories",
|
|
1736
|
+
"--exclude",
|
|
1737
|
+
"--exclude-dir",
|
|
1738
|
+
"--exclude-from",
|
|
1739
|
+
"--file",
|
|
1740
|
+
"--include",
|
|
1741
|
+
"--label",
|
|
1742
|
+
"--max-count",
|
|
1743
|
+
"--regexp"
|
|
1744
|
+
]),
|
|
1745
|
+
noValue: /* @__PURE__ */ new Set([
|
|
1746
|
+
"-E",
|
|
1747
|
+
"-F",
|
|
1748
|
+
"-G",
|
|
1749
|
+
"-P",
|
|
1750
|
+
"-i",
|
|
1751
|
+
"-y",
|
|
1752
|
+
"-v",
|
|
1753
|
+
"-V",
|
|
1754
|
+
"-w",
|
|
1755
|
+
"-x",
|
|
1756
|
+
"-c",
|
|
1757
|
+
"-l",
|
|
1758
|
+
"-L",
|
|
1759
|
+
"-o",
|
|
1760
|
+
"-q",
|
|
1761
|
+
"-s",
|
|
1762
|
+
"-b",
|
|
1763
|
+
"-H",
|
|
1764
|
+
"-h",
|
|
1765
|
+
"-n",
|
|
1766
|
+
"-T",
|
|
1767
|
+
"-Z",
|
|
1768
|
+
"-z",
|
|
1769
|
+
"-R",
|
|
1770
|
+
"-r",
|
|
1771
|
+
"-U",
|
|
1772
|
+
"-u",
|
|
1773
|
+
"-I",
|
|
1774
|
+
"-a",
|
|
1775
|
+
"--basic-regexp",
|
|
1776
|
+
"--binary",
|
|
1777
|
+
"--byte-offset",
|
|
1778
|
+
"--color",
|
|
1779
|
+
"--colour",
|
|
1780
|
+
"--count",
|
|
1781
|
+
"--dereference-recursive",
|
|
1782
|
+
"--extended-regexp",
|
|
1783
|
+
"--files-with-matches",
|
|
1784
|
+
"--files-without-match",
|
|
1785
|
+
"--fixed-strings",
|
|
1786
|
+
"--help",
|
|
1787
|
+
"--ignore-case",
|
|
1788
|
+
"--initial-tab",
|
|
1789
|
+
"--invert-match",
|
|
1790
|
+
"--line-buffered",
|
|
1791
|
+
"--line-number",
|
|
1792
|
+
"--line-regexp",
|
|
1793
|
+
"--no-filename",
|
|
1794
|
+
"--no-group-separator",
|
|
1795
|
+
"--no-ignore-case",
|
|
1796
|
+
"--no-messages",
|
|
1797
|
+
"--null",
|
|
1798
|
+
"--null-data",
|
|
1799
|
+
"--only-matching",
|
|
1800
|
+
"--perl-regexp",
|
|
1801
|
+
"--quiet",
|
|
1802
|
+
"--recursive",
|
|
1803
|
+
"--silent",
|
|
1804
|
+
"--text",
|
|
1805
|
+
"--version",
|
|
1806
|
+
"--with-filename",
|
|
1807
|
+
"--word-regexp"
|
|
1808
|
+
]),
|
|
1809
|
+
patternFlags: /* @__PURE__ */ new Set(["-e", "--regexp"]),
|
|
1810
|
+
noPatternFlags: /* @__PURE__ */ new Set(["-f", "--file"])
|
|
1811
|
+
};
|
|
1812
|
+
var PATTERN_VERBS = {
|
|
1813
|
+
grep: GREP_SHAPE,
|
|
1814
|
+
// /usr/bin/egrep and /usr/bin/fgrep are 41-byte shell wrappers that exec
|
|
1815
|
+
// `grep -E` and `grep -F`. Read in full, not assumed.
|
|
1816
|
+
egrep: GREP_SHAPE,
|
|
1817
|
+
fgrep: GREP_SHAPE,
|
|
1818
|
+
// ripgrep 14.1.1, complete from its own --help. An earlier comment here said rg
|
|
1819
|
+
// was not installed on the measuring machine; it is, and that stale claim is why
|
|
1820
|
+
// this table shipped incomplete for two rounds, blocking ordinary searches like
|
|
1821
|
+
// `rg --sort-files .env src` (/code-review round 4).
|
|
1822
|
+
rg: {
|
|
1823
|
+
takesValue: /* @__PURE__ */ new Set([
|
|
1824
|
+
"-A",
|
|
1825
|
+
"-B",
|
|
1826
|
+
"-C",
|
|
1827
|
+
"-d",
|
|
1828
|
+
"-E",
|
|
1829
|
+
"-e",
|
|
1830
|
+
"-f",
|
|
1831
|
+
"-g",
|
|
1832
|
+
"-j",
|
|
1833
|
+
"-M",
|
|
1834
|
+
"-m",
|
|
1835
|
+
"-r",
|
|
1836
|
+
"-t",
|
|
1837
|
+
"-T",
|
|
1838
|
+
"--after-context",
|
|
1839
|
+
"--before-context",
|
|
1840
|
+
"--color",
|
|
1841
|
+
"--colors",
|
|
1842
|
+
"--context",
|
|
1843
|
+
"--context-separator",
|
|
1844
|
+
"--dfa-size-limit",
|
|
1845
|
+
"--encoding",
|
|
1846
|
+
"--engine",
|
|
1847
|
+
"--field-context-separator",
|
|
1848
|
+
"--field-match-separator",
|
|
1849
|
+
"--file",
|
|
1850
|
+
"--generate",
|
|
1851
|
+
"--glob",
|
|
1852
|
+
"--hostname-bin",
|
|
1853
|
+
"--hyperlink-format",
|
|
1854
|
+
"--iglob",
|
|
1855
|
+
"--ignore-file",
|
|
1856
|
+
"--max-columns",
|
|
1857
|
+
"--max-count",
|
|
1858
|
+
"--max-depth",
|
|
1859
|
+
// An ALIAS of --max-depth, and it takes a value. The round-5 extraction read
|
|
1860
|
+
// alias lines as plain switches and swept it into noValue, which hard-blocked
|
|
1861
|
+
// `rg --maxdepth 2 .env src` while `--max-depth 2` ran (/code-review round 7).
|
|
1862
|
+
"--maxdepth",
|
|
1863
|
+
"--max-filesize",
|
|
1864
|
+
"--path-separator",
|
|
1865
|
+
"--pre",
|
|
1866
|
+
"--pre-glob",
|
|
1867
|
+
"--regexp",
|
|
1868
|
+
"--regex-size-limit",
|
|
1869
|
+
"--replace",
|
|
1870
|
+
"--sort",
|
|
1871
|
+
"--sortr",
|
|
1872
|
+
"--threads",
|
|
1873
|
+
"--type",
|
|
1874
|
+
"--type-add",
|
|
1875
|
+
"--type-clear",
|
|
1876
|
+
"--type-not"
|
|
1877
|
+
]),
|
|
1878
|
+
noValue: /* @__PURE__ */ new Set([
|
|
1879
|
+
"-.",
|
|
1880
|
+
"-0",
|
|
1881
|
+
"-a",
|
|
1882
|
+
"-b",
|
|
1883
|
+
"-c",
|
|
1884
|
+
"-F",
|
|
1885
|
+
"-h",
|
|
1886
|
+
"-H",
|
|
1887
|
+
"-i",
|
|
1888
|
+
"-I",
|
|
1889
|
+
"-l",
|
|
1890
|
+
"-L",
|
|
1891
|
+
"-n",
|
|
1892
|
+
"-N",
|
|
1893
|
+
"-o",
|
|
1894
|
+
"-p",
|
|
1895
|
+
"-P",
|
|
1896
|
+
"-q",
|
|
1897
|
+
"-s",
|
|
1898
|
+
"-S",
|
|
1899
|
+
"-u",
|
|
1900
|
+
"-U",
|
|
1901
|
+
"-v",
|
|
1902
|
+
"-V",
|
|
1903
|
+
"-w",
|
|
1904
|
+
"-x",
|
|
1905
|
+
"-z",
|
|
1906
|
+
"--auto-hybrid-regex",
|
|
1907
|
+
"--binary",
|
|
1908
|
+
"--block-buffered",
|
|
1909
|
+
"--byte-offset",
|
|
1910
|
+
"--case-sensitive",
|
|
1911
|
+
"--column",
|
|
1912
|
+
"--count",
|
|
1913
|
+
"--count-matches",
|
|
1914
|
+
"--crlf",
|
|
1915
|
+
"--debug",
|
|
1916
|
+
"--files",
|
|
1917
|
+
"--files-with-matches",
|
|
1918
|
+
"--files-without-match",
|
|
1919
|
+
"--fixed-strings",
|
|
1920
|
+
"--follow",
|
|
1921
|
+
"--glob-case-insensitive",
|
|
1922
|
+
"--heading",
|
|
1923
|
+
"--help",
|
|
1924
|
+
"--hidden",
|
|
1925
|
+
"--ignore-case",
|
|
1926
|
+
"--ignore-file-case-insensitive",
|
|
1927
|
+
"--include-zero",
|
|
1928
|
+
"--invert-match",
|
|
1929
|
+
"--json",
|
|
1930
|
+
"--line-buffered",
|
|
1931
|
+
"--line-number",
|
|
1932
|
+
"--line-regexp",
|
|
1933
|
+
"--max-columns-preview",
|
|
1934
|
+
"--mmap",
|
|
1935
|
+
"--multiline",
|
|
1936
|
+
"--multiline-dotall",
|
|
1937
|
+
"--no-column",
|
|
1938
|
+
"--no-config",
|
|
1939
|
+
"--no-context-separator",
|
|
1940
|
+
"--no-encoding",
|
|
1941
|
+
"--no-filename",
|
|
1942
|
+
"--no-ignore",
|
|
1943
|
+
"--no-ignore-dot",
|
|
1944
|
+
"--no-ignore-exclude",
|
|
1945
|
+
"--no-ignore-files",
|
|
1946
|
+
"--no-ignore-global",
|
|
1947
|
+
"--no-ignore-messages",
|
|
1948
|
+
"--no-ignore-parent",
|
|
1949
|
+
"--no-ignore-vcs",
|
|
1950
|
+
"--no-line-number",
|
|
1951
|
+
"--no-messages",
|
|
1952
|
+
"--no-pcre2-unicode",
|
|
1953
|
+
"--no-pre",
|
|
1954
|
+
"--no-require-git",
|
|
1955
|
+
"--no-unicode",
|
|
1956
|
+
"--null",
|
|
1957
|
+
"--null-data",
|
|
1958
|
+
"--one-file-system",
|
|
1959
|
+
"--only-matching",
|
|
1960
|
+
"--passthru",
|
|
1961
|
+
"--pcre2",
|
|
1962
|
+
"--pcre2-version",
|
|
1963
|
+
"--pretty",
|
|
1964
|
+
"--print0",
|
|
1965
|
+
"--quiet",
|
|
1966
|
+
"--search-zip",
|
|
1967
|
+
"--smart-case",
|
|
1968
|
+
"--sort-files",
|
|
1969
|
+
"--stats",
|
|
1970
|
+
"--stop-on-nonmatch",
|
|
1971
|
+
"--text",
|
|
1972
|
+
"--trace",
|
|
1973
|
+
"--trim",
|
|
1974
|
+
"--type-list",
|
|
1975
|
+
"--unrestricted",
|
|
1976
|
+
"--version",
|
|
1977
|
+
"--vimgrep",
|
|
1978
|
+
"--with-filename",
|
|
1979
|
+
"--word-regexp",
|
|
1980
|
+
// The COMPLETE remainder of `rg --help`, added after /code-review round 5
|
|
1981
|
+
// found 40 documented switches in neither set. The table is now the whole
|
|
1982
|
+
// option list: `rg --help` yields 149 long options, 35 of them value-taking.
|
|
1983
|
+
"--ignore",
|
|
1984
|
+
"--ignore-dot",
|
|
1985
|
+
"--ignore-exclude",
|
|
1986
|
+
"--ignore-files",
|
|
1987
|
+
"--ignore-global",
|
|
1988
|
+
"--ignore-messages",
|
|
1989
|
+
"--ignore-parent",
|
|
1990
|
+
"--ignore-vcs",
|
|
1991
|
+
"--messages",
|
|
1992
|
+
"--no-auto-hybrid-regex",
|
|
1993
|
+
"--no-binary",
|
|
1994
|
+
"--no-block-buffered",
|
|
1995
|
+
"--no-byte-offset",
|
|
1996
|
+
"--no-crlf",
|
|
1997
|
+
"--no-fixed-strings",
|
|
1998
|
+
"--no-follow",
|
|
1999
|
+
"--no-glob-case-insensitive",
|
|
2000
|
+
"--no-heading",
|
|
2001
|
+
"--no-hidden",
|
|
2002
|
+
"--no-ignore-file-case-insensitive",
|
|
2003
|
+
"--no-include-zero",
|
|
2004
|
+
"--no-invert-match",
|
|
2005
|
+
"--no-json",
|
|
2006
|
+
"--no-line-buffered",
|
|
2007
|
+
"--no-max-columns-preview",
|
|
2008
|
+
"--no-mmap",
|
|
2009
|
+
"--no-multiline",
|
|
2010
|
+
"--no-multiline-dotall",
|
|
2011
|
+
"--no-one-file-system",
|
|
2012
|
+
"--no-pcre2",
|
|
2013
|
+
"--no-search-zip",
|
|
2014
|
+
"--no-sort-files",
|
|
2015
|
+
"--no-stats",
|
|
2016
|
+
"--no-text",
|
|
2017
|
+
"--no-trim",
|
|
2018
|
+
"--passthrough",
|
|
2019
|
+
"--pcre2-unicode",
|
|
2020
|
+
"--require-git",
|
|
2021
|
+
"--unicode"
|
|
2022
|
+
]),
|
|
2023
|
+
patternFlags: /* @__PURE__ */ new Set(["-e", "--regexp"]),
|
|
2024
|
+
// `--files` and `--type-list` list or enumerate without a pattern. Founder
|
|
2025
|
+
// decision 2026-09-13: `rg --files ~/.ssh` stays BLOCKED, which this achieves
|
|
2026
|
+
// by leaving the directory in the judged list.
|
|
2027
|
+
noPatternFlags: /* @__PURE__ */ new Set(["-f", "--file", "--files", "--type-list", "--pcre2-version"])
|
|
2028
|
+
}
|
|
2029
|
+
};
|
|
2030
|
+
var PATTERN_VERB_NAMES = Object.keys(PATTERN_VERBS);
|
|
2031
|
+
var GREP_FILE_OPERANDS = /* @__PURE__ */ new Set(["-f", "--file", "--exclude-from", "--include"]);
|
|
2032
|
+
var READER_VALUE_LETTERS = {
|
|
2033
|
+
awk: ["F", "v", "f"],
|
|
2034
|
+
gawk: ["F", "v", "f", "e", "E", "i", "l", "o", "p", "D"],
|
|
2035
|
+
sed: ["e", "f", "i", "l"],
|
|
2036
|
+
sort: ["C", "k", "o", "S", "t", "T"]
|
|
2037
|
+
};
|
|
2038
|
+
var FILE_OPERAND_FLAGS = {
|
|
2039
|
+
grep: GREP_FILE_OPERANDS,
|
|
2040
|
+
egrep: GREP_FILE_OPERANDS,
|
|
2041
|
+
fgrep: GREP_FILE_OPERANDS,
|
|
2042
|
+
// rg and gawk are NOT installed on the measuring machine: these two rows are
|
|
2043
|
+
// from the shipped documentation (ripgrep `-f/--file`, `--ignore-file`; gawk
|
|
2044
|
+
// `-f/--file`) and are marked as such in the spec.
|
|
2045
|
+
// `-g/--glob/--iglob` name which files ripgrep SEARCHES, so an operand naming
|
|
2046
|
+
// a credential makes rg open it -- the same reason grep's `--include` is here.
|
|
2047
|
+
// Measured (/code-review round 3): `rg --hidden -g .env AWS tree` opened .env
|
|
2048
|
+
// and printed its contents.
|
|
2049
|
+
rg: /* @__PURE__ */ new Set(["-f", "--file", "--ignore-file", "-g", "--glob", "--iglob"]),
|
|
2050
|
+
sed: /* @__PURE__ */ new Set(["-f", "--file"]),
|
|
2051
|
+
awk: /* @__PURE__ */ new Set(["-f", "--file"]),
|
|
2052
|
+
gawk: /* @__PURE__ */ new Set(["-f", "--file"]),
|
|
2053
|
+
sort: /* @__PURE__ */ new Set(["--files0-from"])
|
|
2054
|
+
};
|
|
1703
2055
|
var SCP_VALUE_FLAGS = ["i", "F", "o", "c", "S", "P", "J", "D", "W", "l"];
|
|
2056
|
+
var TAR_VALUE_LETTERS = ["b", "C", "f", "F", "g", "H", "I", "K", "L", "N", "T", "V", "X"];
|
|
2057
|
+
var ZIP_VALUE_LETTERS = ["b", "n", "P", "t", "s", "O", "x", "i"];
|
|
2058
|
+
var RSYNC_VALUE_LETTERS = ["e", "f", "T", "B", "M"];
|
|
1704
2059
|
var RSYNC_SKIP = [
|
|
1705
2060
|
"e",
|
|
1706
2061
|
"--rsh",
|
|
@@ -1712,21 +2067,35 @@ var RSYNC_SKIP = [
|
|
|
1712
2067
|
"f",
|
|
1713
2068
|
"--filter"
|
|
1714
2069
|
];
|
|
2070
|
+
var CP_VALUE_LETTERS = ["S", "t"];
|
|
2071
|
+
var INSTALL_VALUE_LETTERS = ["S", "t", "g", "m", "o"];
|
|
1715
2072
|
var COPY_VERBS = {
|
|
1716
|
-
cp: { source: "allButLast", targetDirFlag: true },
|
|
1717
|
-
mv: { source: "allButLast", targetDirFlag: true },
|
|
1718
|
-
install: { source: "allButLast", targetDirFlag: true },
|
|
1719
|
-
ln: { source: "first", targetDirFlag: true },
|
|
1720
|
-
scp: { source: "allButLast", skipFlags: SCP_VALUE_FLAGS },
|
|
1721
|
-
rsync: { source: "allButLast", skipFlags: RSYNC_SKIP },
|
|
2073
|
+
cp: { source: "allButLast", targetDirFlag: true, valueLetters: CP_VALUE_LETTERS },
|
|
2074
|
+
mv: { source: "allButLast", targetDirFlag: true, valueLetters: CP_VALUE_LETTERS },
|
|
2075
|
+
install: { source: "allButLast", targetDirFlag: true, valueLetters: INSTALL_VALUE_LETTERS },
|
|
2076
|
+
ln: { source: "first", targetDirFlag: true, valueLetters: CP_VALUE_LETTERS },
|
|
2077
|
+
scp: { source: "allButLast", skipFlags: SCP_VALUE_FLAGS, valueLetters: SCP_VALUE_FLAGS },
|
|
2078
|
+
rsync: { source: "allButLast", skipFlags: RSYNC_SKIP, valueLetters: RSYNC_VALUE_LETTERS },
|
|
1722
2079
|
tar: {
|
|
1723
2080
|
source: "archive",
|
|
1724
2081
|
archive: "tar",
|
|
1725
|
-
skipFlags: ["f", "X", "T", "--file", "--exclude", "--exclude-from", "--files-from"]
|
|
2082
|
+
skipFlags: ["f", "X", "T", "--file", "--exclude", "--exclude-from", "--files-from"],
|
|
2083
|
+
valueLetters: TAR_VALUE_LETTERS
|
|
2084
|
+
},
|
|
2085
|
+
zip: {
|
|
2086
|
+
source: "archive",
|
|
2087
|
+
archive: "zip",
|
|
2088
|
+
skipFlags: ["x", "i", "--exclude", "--include"],
|
|
2089
|
+
valueLetters: ZIP_VALUE_LETTERS
|
|
1726
2090
|
},
|
|
1727
|
-
zip: { source: "archive", archive: "zip", skipFlags: ["x", "i", "--exclude", "--include"] },
|
|
1728
2091
|
ar: { source: "archive", archive: "ar" },
|
|
1729
|
-
|
|
2092
|
+
// 7z switches are INLINE only (`-mx9`, `-px`, `-x!pat`), so no following word is
|
|
2093
|
+
// ever a switch's operand -- which is why the short `x` is NOT a skipFlag here
|
|
2094
|
+
// and valueLetters is empty. Keeping the short `x` made `7z a out.7z -mx KEY`
|
|
2095
|
+
// drop the credential as an exclusion operand (/code-review round 8), and the
|
|
2096
|
+
// derived "every skipped letter is a value letter" row in jail-copy.spec.ts is
|
|
2097
|
+
// what keeps the two tables honest about it.
|
|
2098
|
+
"7z": { source: "archive", archive: "7z", skipFlags: ["--exclude"], valueLetters: [] },
|
|
1730
2099
|
gzip: { source: "all" },
|
|
1731
2100
|
bzip2: { source: "all" },
|
|
1732
2101
|
xz: { source: "all" },
|
|
@@ -2586,7 +2955,7 @@ function analyzeFsOperationImpl(command, depth = 0) {
|
|
|
2586
2955
|
return result?.verdict !== "block";
|
|
2587
2956
|
}
|
|
2588
2957
|
if (nodeType !== "CallExpr") return true;
|
|
2589
|
-
const { name, flags, paths, words } = extractLiteralArgs(n);
|
|
2958
|
+
const { name, flags, paths, words, args } = extractLiteralArgs(n);
|
|
2590
2959
|
if (!name) return true;
|
|
2591
2960
|
if (name === "rm") {
|
|
2592
2961
|
const flagStr = flags.join("").toLowerCase();
|
|
@@ -2626,7 +2995,7 @@ function analyzeFsOperationImpl(command, depth = 0) {
|
|
|
2626
2995
|
return true;
|
|
2627
2996
|
}
|
|
2628
2997
|
}
|
|
2629
|
-
const readPaths = FS_READ_TOOLS.has(name) ?
|
|
2998
|
+
const readPaths = FS_READ_TOOLS.has(name) ? [...readTargets(name, args, flags, words, 1), ...flagOperandFiles(name, words, 1)] : wrappedReadPaths(words, name);
|
|
2630
2999
|
if (readPaths) {
|
|
2631
3000
|
for (const p of readPaths) {
|
|
2632
3001
|
result = stricter(result, matchSensitivePath2(p));
|
|
@@ -2662,9 +3031,22 @@ function flagIs(w, names) {
|
|
|
2662
3031
|
const f = flagInfo(w);
|
|
2663
3032
|
return names.some((n) => n.startsWith("--") ? f.long === n : f.letter === n);
|
|
2664
3033
|
}
|
|
2665
|
-
function operandOf(a, names) {
|
|
3034
|
+
function operandOf(a, names, valueLetters) {
|
|
2666
3035
|
if (!names || a.afterFlag === null) return false;
|
|
2667
|
-
|
|
3036
|
+
const w = a.afterFlag;
|
|
3037
|
+
if (!w.startsWith("--") && valueLetters) {
|
|
3038
|
+
const letters = w.slice(1);
|
|
3039
|
+
for (let i = 0; i < letters.length; i++) {
|
|
3040
|
+
if (!valueLetters.includes(letters[i])) continue;
|
|
3041
|
+
return i === letters.length - 1 && names.includes(letters[i]);
|
|
3042
|
+
}
|
|
3043
|
+
return false;
|
|
3044
|
+
}
|
|
3045
|
+
if (w.startsWith("--") && !w.includes("=")) {
|
|
3046
|
+
const longs = names.filter((n) => n.startsWith("--"));
|
|
3047
|
+
if (longs.some((n) => n === w || w.length >= 3 && n.startsWith(w))) return true;
|
|
3048
|
+
}
|
|
3049
|
+
return flagIs(w, names) && flagInfo(w).attached === null;
|
|
2668
3050
|
}
|
|
2669
3051
|
function resolveCopyShape(words, h) {
|
|
2670
3052
|
const verb = baseWord(words[h]);
|
|
@@ -2689,7 +3071,7 @@ function findStartPoints(words, h) {
|
|
|
2689
3071
|
const k = words.findIndex((w, i) => i > h && w !== null && FIND_EXEC_FLAGS.has(w));
|
|
2690
3072
|
if (k < 0) return { k, starts: [] };
|
|
2691
3073
|
const firstPredicate = words.findIndex(
|
|
2692
|
-
(w, i) => i > h && w !== null && w.startsWith("-") && !FIND_OPTIONS.has(w)
|
|
3074
|
+
(w, i) => i > h && w !== null && w !== "--" && w.startsWith("-") && !FIND_OPTIONS.has(w)
|
|
2693
3075
|
);
|
|
2694
3076
|
const end = firstPredicate > h ? firstPredicate : k;
|
|
2695
3077
|
return { k, starts: positionalAfter(words, h + 1, end) };
|
|
@@ -2709,14 +3091,35 @@ function copySourcePaths(words) {
|
|
|
2709
3091
|
const { shape, last } = r;
|
|
2710
3092
|
const args = positionedArgs(words, last + 1);
|
|
2711
3093
|
const tail = words.slice(last + 1);
|
|
2712
|
-
const
|
|
2713
|
-
const
|
|
2714
|
-
const
|
|
3094
|
+
const copyOptionsEnd = tail.findIndex((w) => w === "--");
|
|
3095
|
+
const copyPastOptions = (a) => copyOptionsEnd >= 0 && a.argv > last + 1 + copyOptionsEnd;
|
|
3096
|
+
const skipped = (a) => !copyPastOptions(a) && operandOf(a, shape.skipFlags, shape.valueLetters);
|
|
3097
|
+
const firstValueLetter = (w) => {
|
|
3098
|
+
const letters = w.slice(1);
|
|
3099
|
+
for (let i = 0; i < letters.length; i++) {
|
|
3100
|
+
if ((shape.valueLetters ?? []).includes(letters[i]))
|
|
3101
|
+
return { letter: letters[i], last: i === letters.length - 1 };
|
|
3102
|
+
}
|
|
3103
|
+
return null;
|
|
3104
|
+
};
|
|
3105
|
+
const isTargetDirFlag = (w) => {
|
|
3106
|
+
if (w.startsWith("--")) {
|
|
3107
|
+
const name = w.includes("=") ? w.slice(0, w.indexOf("=")) : w;
|
|
3108
|
+
return name.length >= 3 && "--target-directory".startsWith(name);
|
|
3109
|
+
}
|
|
3110
|
+
return firstValueLetter(w)?.letter === "t";
|
|
3111
|
+
};
|
|
3112
|
+
const targetDir = shape.targetDirFlag === true && tail.some((w) => w !== null && w.startsWith("-") && isTargetDirFlag(w));
|
|
3113
|
+
const targetTakesNextWord = (w) => {
|
|
3114
|
+
if (w.startsWith("--"))
|
|
3115
|
+
return !w.includes("=") && w.length >= 3 && "--target-directory".startsWith(w);
|
|
3116
|
+
const f = firstValueLetter(w);
|
|
3117
|
+
return f !== null && f.letter === "t" && f.last;
|
|
3118
|
+
};
|
|
3119
|
+
const targetOperand = (a) => targetDir && a.afterFlag !== null && !copyPastOptions(a) && targetTakesNextWord(a.afterFlag);
|
|
2715
3120
|
const lastOperand = [...tail].reverse().find((w) => w === null || !w.startsWith("-"));
|
|
2716
3121
|
const dynamicDest = lastOperand === null;
|
|
2717
3122
|
const destIsLastOperand = (shape.source === "allButLast" || shape.source === "first") && !targetDir && !dynamicDest;
|
|
2718
|
-
if (destIsLastOperand && typeof lastOperand === "string" && matchSensitivePath2(lastOperand))
|
|
2719
|
-
return [];
|
|
2720
3123
|
let src;
|
|
2721
3124
|
switch (shape.source) {
|
|
2722
3125
|
case "all":
|
|
@@ -2726,11 +3129,17 @@ function copySourcePaths(words) {
|
|
|
2726
3129
|
src = targetDir ? args : args.slice(0, 1);
|
|
2727
3130
|
break;
|
|
2728
3131
|
case "flagOperand": {
|
|
2729
|
-
const
|
|
3132
|
+
const namesSource = (f) => {
|
|
3133
|
+
const names = shape.sourceFlags ?? [];
|
|
3134
|
+
if (f.long !== null)
|
|
3135
|
+
return names.some(
|
|
3136
|
+
(n) => n.startsWith("--") && (n === f.long || f.long.length >= 3 && n.startsWith(f.long))
|
|
3137
|
+
);
|
|
3138
|
+
return f.letter !== null && names.includes(f.letter);
|
|
3139
|
+
};
|
|
3140
|
+
const inline = tail.filter((w) => w !== null && w.startsWith("-")).map((w) => flagInfo(w)).filter((f) => f.attached !== null && namesSource(f)).map((f) => f.attached);
|
|
2730
3141
|
return [
|
|
2731
|
-
...args.filter(
|
|
2732
|
-
(a) => flagIs(a.afterFlag, shape.sourceFlags ?? []) && flagInfo(a.afterFlag).attached === null
|
|
2733
|
-
).map((a) => a.value),
|
|
3142
|
+
...args.filter((a) => !copyPastOptions(a) && operandOf(a, shape.sourceFlags, shape.valueLetters)).map((a) => a.value),
|
|
2734
3143
|
...inline
|
|
2735
3144
|
];
|
|
2736
3145
|
}
|
|
@@ -2741,7 +3150,14 @@ function copySourcePaths(words) {
|
|
|
2741
3150
|
src = targetDir || dynamicDest ? args : args.slice(0, -1);
|
|
2742
3151
|
break;
|
|
2743
3152
|
}
|
|
2744
|
-
|
|
3153
|
+
const sources = src.filter((a) => !skipped(a) && !targetOperand(a)).map((a) => a.value);
|
|
3154
|
+
if (destIsLastOperand && typeof lastOperand === "string" && matchSensitivePath2(lastOperand)) {
|
|
3155
|
+
const jailedSources = sources.filter((p) => matchSensitivePath2(p));
|
|
3156
|
+
const dirOf = (p) => /[\\/]/.test(p) ? p.replace(/[\\/][^\\/]*$/, "") : "";
|
|
3157
|
+
if (jailedSources.length === 0) return [];
|
|
3158
|
+
if (jailedSources.every((p) => dirOf(p) === dirOf(lastOperand))) return [];
|
|
3159
|
+
}
|
|
3160
|
+
return sources;
|
|
2745
3161
|
}
|
|
2746
3162
|
function archiveInputs(kind, args, tail) {
|
|
2747
3163
|
const first = args[0];
|
|
@@ -2753,13 +3169,17 @@ function archiveInputs(kind, args, tail) {
|
|
|
2753
3169
|
const writing = /[cruA]/.test(bareKey ? first.value : "") || /(^|\s)-[a-zA-Z]*[cruA]|--create|--append|--update|--concatenate/.test(flagsText);
|
|
2754
3170
|
if (extracting && !writing) return [];
|
|
2755
3171
|
void mode;
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
if (
|
|
2761
|
-
|
|
2762
|
-
|
|
3172
|
+
if (!bareKey) return args;
|
|
3173
|
+
let i = 1;
|
|
3174
|
+
const fromDirs = [];
|
|
3175
|
+
for (const ch of first.value) {
|
|
3176
|
+
if (!TAR_VALUE_LETTERS.includes(ch)) continue;
|
|
3177
|
+
const operand = args[i];
|
|
3178
|
+
if (!operand || operand.afterFlag !== null) break;
|
|
3179
|
+
i += 1;
|
|
3180
|
+
if (ch === "C") fromDirs.push(operand);
|
|
3181
|
+
}
|
|
3182
|
+
return [...fromDirs, ...args.slice(i)];
|
|
2763
3183
|
}
|
|
2764
3184
|
if (kind === "zip") return first && first.afterFlag === "-" ? args : args.slice(1);
|
|
2765
3185
|
if (kind === "ar") return bareKey ? args.slice(2) : args.slice(1);
|
|
@@ -2794,6 +3214,140 @@ function baseWord(w) {
|
|
|
2794
3214
|
}
|
|
2795
3215
|
var isReaderWord = (w) => w !== null && FS_READ_TOOLS.has(baseWord(w));
|
|
2796
3216
|
var positionalAfter = (words, from, to = words.length) => positionedArgs(words, from, to).map((a) => a.value);
|
|
3217
|
+
function namesFlag(name, candidates, known) {
|
|
3218
|
+
if (candidates.has(name)) return true;
|
|
3219
|
+
if (!name.startsWith("--") || name.length < 3) return false;
|
|
3220
|
+
if (known?.has(name)) return false;
|
|
3221
|
+
for (const c of candidates) if (c.startsWith(name)) return true;
|
|
3222
|
+
return false;
|
|
3223
|
+
}
|
|
3224
|
+
function knownLongFlags(verb) {
|
|
3225
|
+
const out = /* @__PURE__ */ new Set();
|
|
3226
|
+
const shape = PATTERN_VERBS[verb];
|
|
3227
|
+
if (shape) {
|
|
3228
|
+
for (const set of [shape.takesValue, shape.noValue, shape.patternFlags, shape.noPatternFlags])
|
|
3229
|
+
for (const f of set) if (f.startsWith("--")) out.add(f);
|
|
3230
|
+
}
|
|
3231
|
+
for (const f of FILE_OPERAND_FLAGS[verb] ?? []) if (f.startsWith("--")) out.add(f);
|
|
3232
|
+
return out;
|
|
3233
|
+
}
|
|
3234
|
+
function flagNamesOf(token, shape) {
|
|
3235
|
+
if (token.startsWith("--")) {
|
|
3236
|
+
const eq = token.indexOf("=");
|
|
3237
|
+
return [eq > 0 ? token.slice(0, eq) : token];
|
|
3238
|
+
}
|
|
3239
|
+
const out = [];
|
|
3240
|
+
for (const c of token.slice(1)) {
|
|
3241
|
+
const name = `-${c}`;
|
|
3242
|
+
out.push(name);
|
|
3243
|
+
if (shape?.takesValue.has(name)) break;
|
|
3244
|
+
}
|
|
3245
|
+
return out;
|
|
3246
|
+
}
|
|
3247
|
+
var NONE = { kind: "none" };
|
|
3248
|
+
var UNKNOWN = { kind: "unknown" };
|
|
3249
|
+
function flagEffect(token, shape, known) {
|
|
3250
|
+
if (token === "--") return NONE;
|
|
3251
|
+
if (/^-+$/.test(token)) return UNKNOWN;
|
|
3252
|
+
if (/^-\d+$/.test(token)) return NONE;
|
|
3253
|
+
if (token.startsWith("--")) {
|
|
3254
|
+
if (token.includes("=")) return NONE;
|
|
3255
|
+
const takes = namesFlag(token, shape.takesValue, known);
|
|
3256
|
+
const none = namesFlag(token, shape.noValue, known);
|
|
3257
|
+
if (takes && none) return UNKNOWN;
|
|
3258
|
+
if (takes) return { kind: "takes", flag: token };
|
|
3259
|
+
if (none) return NONE;
|
|
3260
|
+
return UNKNOWN;
|
|
3261
|
+
}
|
|
3262
|
+
const letters = token.slice(1);
|
|
3263
|
+
if (!letters) return NONE;
|
|
3264
|
+
for (let i = 0; i < letters.length; i++) {
|
|
3265
|
+
const name = `-${letters[i]}`;
|
|
3266
|
+
if (shape.takesValue.has(name)) {
|
|
3267
|
+
return i === letters.length - 1 ? { kind: "takes", flag: name } : NONE;
|
|
3268
|
+
}
|
|
3269
|
+
if (!shape.noValue.has(name)) return UNKNOWN;
|
|
3270
|
+
}
|
|
3271
|
+
return NONE;
|
|
3272
|
+
}
|
|
3273
|
+
function readTargets(verb, args, flags, words = [], from = 1) {
|
|
3274
|
+
const shape = PATTERN_VERBS[verb];
|
|
3275
|
+
if (!shape) return args.map((a) => a.value);
|
|
3276
|
+
const known = knownLongFlags(verb);
|
|
3277
|
+
const names = flags.flatMap((f) => flagNamesOf(f, shape));
|
|
3278
|
+
const patternElsewhere = names.some(
|
|
3279
|
+
(n) => namesFlag(n, shape.patternFlags, known) || namesFlag(n, shape.noPatternFlags, known)
|
|
3280
|
+
);
|
|
3281
|
+
const excused = /* @__PURE__ */ new Set();
|
|
3282
|
+
const fileFlags = FILE_OPERAND_FLAGS[verb];
|
|
3283
|
+
const optionsEnd = words.findIndex((w, i) => i >= from && w === "--");
|
|
3284
|
+
const pastOptions = (a) => optionsEnd >= 0 && a.argv > optionsEnd;
|
|
3285
|
+
for (const a of args) {
|
|
3286
|
+
if (a.afterFlag === null || pastOptions(a)) continue;
|
|
3287
|
+
const e = flagEffect(a.afterFlag, shape, known);
|
|
3288
|
+
if (e.kind !== "takes") continue;
|
|
3289
|
+
if (fileFlags && namesFlag(e.flag, fileFlags, known)) continue;
|
|
3290
|
+
excused.add(a);
|
|
3291
|
+
}
|
|
3292
|
+
const patternArgv = (() => {
|
|
3293
|
+
for (let i = from; i < words.length; i++) {
|
|
3294
|
+
const w = words[i];
|
|
3295
|
+
if (w === null) return -1;
|
|
3296
|
+
if (w === "--") return i + 1;
|
|
3297
|
+
if (w.startsWith("-")) {
|
|
3298
|
+
const e = flagEffect(w, shape, known);
|
|
3299
|
+
if (e.kind === "takes") i += 1;
|
|
3300
|
+
else if (e.kind === "unknown") return -1;
|
|
3301
|
+
continue;
|
|
3302
|
+
}
|
|
3303
|
+
return i;
|
|
3304
|
+
}
|
|
3305
|
+
return -1;
|
|
3306
|
+
})();
|
|
3307
|
+
if (!patternElsewhere && patternArgv >= 0) {
|
|
3308
|
+
const a = args.find((x) => x.argv === patternArgv);
|
|
3309
|
+
if (a) excused.add(a);
|
|
3310
|
+
}
|
|
3311
|
+
return args.filter((a) => !excused.has(a)).map((a) => a.value);
|
|
3312
|
+
}
|
|
3313
|
+
function flagOperandFiles(verb, words, from) {
|
|
3314
|
+
const flags = FILE_OPERAND_FLAGS[verb];
|
|
3315
|
+
if (!flags) return [];
|
|
3316
|
+
const known = knownLongFlags(verb);
|
|
3317
|
+
const out = [];
|
|
3318
|
+
for (let i = from; i < words.length; i++) {
|
|
3319
|
+
const w = words[i];
|
|
3320
|
+
if (w === null || !w.startsWith("-") || w === "--") continue;
|
|
3321
|
+
if (w.startsWith("--")) {
|
|
3322
|
+
const eq = w.indexOf("=");
|
|
3323
|
+
if (eq <= 0) continue;
|
|
3324
|
+
const name = w.slice(0, eq);
|
|
3325
|
+
const value = w.slice(eq + 1);
|
|
3326
|
+
if (!value) continue;
|
|
3327
|
+
if (namesFlag(name, flags, known)) {
|
|
3328
|
+
out.push(value);
|
|
3329
|
+
continue;
|
|
3330
|
+
}
|
|
3331
|
+
const shape2 = PATTERN_VERBS[verb];
|
|
3332
|
+
if (!shape2) continue;
|
|
3333
|
+
const recognised = namesFlag(name, shape2.takesValue, known) || namesFlag(name, shape2.noValue, known) || namesFlag(name, shape2.patternFlags, known) || namesFlag(name, shape2.noPatternFlags, known);
|
|
3334
|
+
if (!recognised) out.push(value);
|
|
3335
|
+
continue;
|
|
3336
|
+
}
|
|
3337
|
+
const shape = PATTERN_VERBS[verb];
|
|
3338
|
+
const letters = w.slice(1);
|
|
3339
|
+
for (let j = 0; j < letters.length; j++) {
|
|
3340
|
+
const name = `-${letters[j]}`;
|
|
3341
|
+
const isFileFlag = flags.has(name);
|
|
3342
|
+
const argTaking = isFileFlag || (shape?.takesValue.has(name) ?? false) || (READER_VALUE_LETTERS[verb] ?? []).includes(letters[j]);
|
|
3343
|
+
if (!argTaking) continue;
|
|
3344
|
+
const attached = letters.slice(j + 1);
|
|
3345
|
+
if (isFileFlag && attached) out.push(attached);
|
|
3346
|
+
break;
|
|
3347
|
+
}
|
|
3348
|
+
}
|
|
3349
|
+
return out;
|
|
3350
|
+
}
|
|
2797
3351
|
function wrappedReadPaths(words, name) {
|
|
2798
3352
|
if (name === "find") {
|
|
2799
3353
|
const { k, starts } = findStartPoints(words, 0);
|
|
@@ -2801,7 +3355,14 @@ function wrappedReadPaths(words, name) {
|
|
|
2801
3355
|
}
|
|
2802
3356
|
if (!COMMAND_WRAPPERS.has(name) && !RUNNER_WRAPPERS.has(name)) return null;
|
|
2803
3357
|
const h = unwrapCommandHead(words);
|
|
2804
|
-
|
|
3358
|
+
if (h <= 0 || !isReaderWord(words[h] ?? null)) return null;
|
|
3359
|
+
const head = baseWord(words[h]);
|
|
3360
|
+
const rest = words.slice(h + 1);
|
|
3361
|
+
const restFlags = rest.filter((w) => w !== null && w.startsWith("-"));
|
|
3362
|
+
return [
|
|
3363
|
+
...readTargets(head, positionedArgs(words, h + 1), restFlags, words, h + 1),
|
|
3364
|
+
...flagOperandFiles(head, words, h + 1)
|
|
3365
|
+
];
|
|
2805
3366
|
}
|
|
2806
3367
|
function literalShellPayload(words, name) {
|
|
2807
3368
|
const h = COMMAND_WRAPPERS.has(name) || RUNNER_WRAPPERS.has(name) ? unwrapCommandHead(words) : 0;
|
|
@@ -3923,6 +4484,15 @@ async function evaluatePolicy(config, toolName, args, context = {}, hooks = {})
|
|
|
3923
4484
|
function isIgnoredTool(toolName, config) {
|
|
3924
4485
|
return matchesPattern(toolName, config.policy.ignoredTools);
|
|
3925
4486
|
}
|
|
4487
|
+
var TERMINAL_ESCAPE_RE = /\x1b\[[0-9;?]*[A-Za-z]|\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)|\x1b[@-_]|[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g;
|
|
4488
|
+
function stripTerminalEscapes(s) {
|
|
4489
|
+
return s.replace(TERMINAL_ESCAPE_RE, "");
|
|
4490
|
+
}
|
|
4491
|
+
function safeMessage(value, max = 300) {
|
|
4492
|
+
const raw = typeof value === "string" ? value : value instanceof Error ? value.message : String(value ?? "");
|
|
4493
|
+
const s = stripTerminalEscapes(raw).replace(/\s+/g, " ").trim();
|
|
4494
|
+
return s.length > max ? s.slice(0, max - 1) + "\u2026" : s;
|
|
4495
|
+
}
|
|
3926
4496
|
var aws_default = {
|
|
3927
4497
|
name: "aws",
|
|
3928
4498
|
description: "Protects AWS infrastructure from destructive AI operations",
|
|
@@ -6922,7 +7492,7 @@ function escapePango(text) {
|
|
|
6922
7492
|
function buildPlainMessage(toolName, formattedArgs, agent, explainableLabel, locked, allowCount = 1, ruleDescription) {
|
|
6923
7493
|
const lines = [];
|
|
6924
7494
|
if (locked) lines.push("\u26A0\uFE0F LOCKED BY ADMIN POLICY\n");
|
|
6925
|
-
const safeAgent = (agent ?? "AI Agent"
|
|
7495
|
+
const safeAgent = safeMessage(agent ?? "AI Agent", 80);
|
|
6926
7496
|
lines.push(`\u{1F916} ${safeAgent} | \u{1F527} ${toolName}`);
|
|
6927
7497
|
lines.push(`\u{1F6E1}\uFE0F ${explainableLabel || "Security Policy"}`);
|
|
6928
7498
|
if (ruleDescription) lines.push(`\u2139 ${ruleDescription}`);
|
|
@@ -7250,14 +7820,14 @@ async function resolveNode9SaaS(requestId, creds, approved, decidedBy) {
|
|
|
7250
7820
|
if (!res.ok) {
|
|
7251
7821
|
import_fs11.default.appendFileSync(
|
|
7252
7822
|
HOOK_DEBUG_LOG,
|
|
7253
|
-
`[resolve-cloud] PATCH ${resolveUrl} \u2192 HTTP ${res.status}
|
|
7823
|
+
`[resolve-cloud] PATCH ${safeMessage(resolveUrl, 200)} \u2192 HTTP ${res.status}
|
|
7254
7824
|
`
|
|
7255
7825
|
);
|
|
7256
7826
|
}
|
|
7257
7827
|
} catch (err) {
|
|
7258
7828
|
import_fs11.default.appendFileSync(
|
|
7259
7829
|
HOOK_DEBUG_LOG,
|
|
7260
|
-
`[resolve-cloud] PATCH failed for ${requestId}: ${err
|
|
7830
|
+
`[resolve-cloud] PATCH failed for ${safeMessage(requestId, 64)}: ${safeMessage(err)}
|
|
7261
7831
|
`
|
|
7262
7832
|
);
|
|
7263
7833
|
}
|
|
@@ -7358,9 +7928,8 @@ async function authorizeHeadless(toolName, args, meta, options) {
|
|
|
7358
7928
|
if (!options?.calledFromDaemon) {
|
|
7359
7929
|
const actId = (0, import_crypto5.randomUUID)();
|
|
7360
7930
|
const actTs = Date.now();
|
|
7361
|
-
const
|
|
7362
|
-
const
|
|
7363
|
-
const sanitizedMcpServer = meta?.mcpServer ? stripAnsi(meta.mcpServer).slice(0, 40) : void 0;
|
|
7931
|
+
const sanitizedAgent = meta?.agent ? safeMessage(meta.agent, 80) : void 0;
|
|
7932
|
+
const sanitizedMcpServer = meta?.mcpServer ? safeMessage(meta.mcpServer, 40) : void 0;
|
|
7364
7933
|
const socketOk = await notifyActivity({
|
|
7365
7934
|
id: actId,
|
|
7366
7935
|
ts: actTs,
|