@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.mjs
CHANGED
|
@@ -1480,6 +1480,19 @@ function parseShared(command) {
|
|
|
1480
1480
|
astCache.set(command, parsed);
|
|
1481
1481
|
return parsed;
|
|
1482
1482
|
}
|
|
1483
|
+
function byteOffsetToCharIndex(command) {
|
|
1484
|
+
if (!/[^\u0000-\u007F]/.test(command)) return null;
|
|
1485
|
+
const map = /* @__PURE__ */ new Map();
|
|
1486
|
+
let byte = 0;
|
|
1487
|
+
for (let i = 0; i < command.length; ) {
|
|
1488
|
+
map.set(byte, i);
|
|
1489
|
+
const cp = command.codePointAt(i);
|
|
1490
|
+
byte += cp < 128 ? 1 : cp < 2048 ? 2 : cp < 65536 ? 3 : 4;
|
|
1491
|
+
i += cp > 65535 ? 2 : 1;
|
|
1492
|
+
}
|
|
1493
|
+
map.set(byte, command.length);
|
|
1494
|
+
return (b) => map.get(b) ?? -1;
|
|
1495
|
+
}
|
|
1483
1496
|
function cachedNormalize(command, compute) {
|
|
1484
1497
|
const hit = normalizeCache.get(command);
|
|
1485
1498
|
if (hit !== void 0) {
|
|
@@ -1509,6 +1522,8 @@ function normalizeCommandForPolicyImpl(command) {
|
|
|
1509
1522
|
const f = parseShared(command);
|
|
1510
1523
|
if (f === PARSE_FAIL) return { posix: command, separator: command };
|
|
1511
1524
|
try {
|
|
1525
|
+
const toCharIndex = byteOffsetToCharIndex(command);
|
|
1526
|
+
const at = (byteOffset) => toCharIndex === null ? byteOffset : toCharIndex(byteOffset);
|
|
1512
1527
|
const strips = [];
|
|
1513
1528
|
const rewrites = [];
|
|
1514
1529
|
const quoteOnlyRewrites = [];
|
|
@@ -1529,8 +1544,9 @@ function normalizeCommandForPolicyImpl(command) {
|
|
|
1529
1544
|
const quotedNode = nextParts[0];
|
|
1530
1545
|
const nt = syntax.NodeType(quotedNode);
|
|
1531
1546
|
const markStrip = () => {
|
|
1532
|
-
const s = next.Pos().Offset();
|
|
1533
|
-
const e = next.End().Offset();
|
|
1547
|
+
const s = at(next.Pos().Offset());
|
|
1548
|
+
const e = at(next.End().Offset());
|
|
1549
|
+
if (s < 0 || e < 0) return;
|
|
1534
1550
|
strips.push([s, e]);
|
|
1535
1551
|
msgSpans.add(`${s}:${e}`);
|
|
1536
1552
|
};
|
|
@@ -1547,8 +1563,9 @@ function normalizeCommandForPolicyImpl(command) {
|
|
|
1547
1563
|
}
|
|
1548
1564
|
}
|
|
1549
1565
|
for (const arg of args) {
|
|
1550
|
-
const s = arg.Pos().Offset();
|
|
1551
|
-
const e = arg.End().Offset();
|
|
1566
|
+
const s = at(arg.Pos().Offset());
|
|
1567
|
+
const e = at(arg.End().Offset());
|
|
1568
|
+
if (s < 0 || e < 0) continue;
|
|
1552
1569
|
if (msgSpans.has(`${s}:${e}`)) continue;
|
|
1553
1570
|
const resolved = resolveWordLiteral(arg);
|
|
1554
1571
|
if (resolved === null) continue;
|
|
@@ -1670,7 +1687,345 @@ var FS_READ_TOOLS = /* @__PURE__ */ new Set([
|
|
|
1670
1687
|
"nl",
|
|
1671
1688
|
"dd"
|
|
1672
1689
|
]);
|
|
1690
|
+
var GREP_SHAPE = {
|
|
1691
|
+
takesValue: /* @__PURE__ */ new Set([
|
|
1692
|
+
"-A",
|
|
1693
|
+
"-B",
|
|
1694
|
+
"-C",
|
|
1695
|
+
"-D",
|
|
1696
|
+
"-d",
|
|
1697
|
+
"-e",
|
|
1698
|
+
"-f",
|
|
1699
|
+
"-m",
|
|
1700
|
+
"--after-context",
|
|
1701
|
+
"--before-context",
|
|
1702
|
+
"--binary-files",
|
|
1703
|
+
"--context",
|
|
1704
|
+
"--devices",
|
|
1705
|
+
"--directories",
|
|
1706
|
+
"--exclude",
|
|
1707
|
+
"--exclude-dir",
|
|
1708
|
+
"--exclude-from",
|
|
1709
|
+
"--file",
|
|
1710
|
+
"--include",
|
|
1711
|
+
"--label",
|
|
1712
|
+
"--max-count",
|
|
1713
|
+
"--regexp"
|
|
1714
|
+
]),
|
|
1715
|
+
noValue: /* @__PURE__ */ new Set([
|
|
1716
|
+
"-E",
|
|
1717
|
+
"-F",
|
|
1718
|
+
"-G",
|
|
1719
|
+
"-P",
|
|
1720
|
+
"-i",
|
|
1721
|
+
"-y",
|
|
1722
|
+
"-v",
|
|
1723
|
+
"-V",
|
|
1724
|
+
"-w",
|
|
1725
|
+
"-x",
|
|
1726
|
+
"-c",
|
|
1727
|
+
"-l",
|
|
1728
|
+
"-L",
|
|
1729
|
+
"-o",
|
|
1730
|
+
"-q",
|
|
1731
|
+
"-s",
|
|
1732
|
+
"-b",
|
|
1733
|
+
"-H",
|
|
1734
|
+
"-h",
|
|
1735
|
+
"-n",
|
|
1736
|
+
"-T",
|
|
1737
|
+
"-Z",
|
|
1738
|
+
"-z",
|
|
1739
|
+
"-R",
|
|
1740
|
+
"-r",
|
|
1741
|
+
"-U",
|
|
1742
|
+
"-u",
|
|
1743
|
+
"-I",
|
|
1744
|
+
"-a",
|
|
1745
|
+
"--basic-regexp",
|
|
1746
|
+
"--binary",
|
|
1747
|
+
"--byte-offset",
|
|
1748
|
+
"--color",
|
|
1749
|
+
"--colour",
|
|
1750
|
+
"--count",
|
|
1751
|
+
"--dereference-recursive",
|
|
1752
|
+
"--extended-regexp",
|
|
1753
|
+
"--files-with-matches",
|
|
1754
|
+
"--files-without-match",
|
|
1755
|
+
"--fixed-strings",
|
|
1756
|
+
"--help",
|
|
1757
|
+
"--ignore-case",
|
|
1758
|
+
"--initial-tab",
|
|
1759
|
+
"--invert-match",
|
|
1760
|
+
"--line-buffered",
|
|
1761
|
+
"--line-number",
|
|
1762
|
+
"--line-regexp",
|
|
1763
|
+
"--no-filename",
|
|
1764
|
+
"--no-group-separator",
|
|
1765
|
+
"--no-ignore-case",
|
|
1766
|
+
"--no-messages",
|
|
1767
|
+
"--null",
|
|
1768
|
+
"--null-data",
|
|
1769
|
+
"--only-matching",
|
|
1770
|
+
"--perl-regexp",
|
|
1771
|
+
"--quiet",
|
|
1772
|
+
"--recursive",
|
|
1773
|
+
"--silent",
|
|
1774
|
+
"--text",
|
|
1775
|
+
"--version",
|
|
1776
|
+
"--with-filename",
|
|
1777
|
+
"--word-regexp"
|
|
1778
|
+
]),
|
|
1779
|
+
patternFlags: /* @__PURE__ */ new Set(["-e", "--regexp"]),
|
|
1780
|
+
noPatternFlags: /* @__PURE__ */ new Set(["-f", "--file"])
|
|
1781
|
+
};
|
|
1782
|
+
var PATTERN_VERBS = {
|
|
1783
|
+
grep: GREP_SHAPE,
|
|
1784
|
+
// /usr/bin/egrep and /usr/bin/fgrep are 41-byte shell wrappers that exec
|
|
1785
|
+
// `grep -E` and `grep -F`. Read in full, not assumed.
|
|
1786
|
+
egrep: GREP_SHAPE,
|
|
1787
|
+
fgrep: GREP_SHAPE,
|
|
1788
|
+
// ripgrep 14.1.1, complete from its own --help. An earlier comment here said rg
|
|
1789
|
+
// was not installed on the measuring machine; it is, and that stale claim is why
|
|
1790
|
+
// this table shipped incomplete for two rounds, blocking ordinary searches like
|
|
1791
|
+
// `rg --sort-files .env src` (/code-review round 4).
|
|
1792
|
+
rg: {
|
|
1793
|
+
takesValue: /* @__PURE__ */ new Set([
|
|
1794
|
+
"-A",
|
|
1795
|
+
"-B",
|
|
1796
|
+
"-C",
|
|
1797
|
+
"-d",
|
|
1798
|
+
"-E",
|
|
1799
|
+
"-e",
|
|
1800
|
+
"-f",
|
|
1801
|
+
"-g",
|
|
1802
|
+
"-j",
|
|
1803
|
+
"-M",
|
|
1804
|
+
"-m",
|
|
1805
|
+
"-r",
|
|
1806
|
+
"-t",
|
|
1807
|
+
"-T",
|
|
1808
|
+
"--after-context",
|
|
1809
|
+
"--before-context",
|
|
1810
|
+
"--color",
|
|
1811
|
+
"--colors",
|
|
1812
|
+
"--context",
|
|
1813
|
+
"--context-separator",
|
|
1814
|
+
"--dfa-size-limit",
|
|
1815
|
+
"--encoding",
|
|
1816
|
+
"--engine",
|
|
1817
|
+
"--field-context-separator",
|
|
1818
|
+
"--field-match-separator",
|
|
1819
|
+
"--file",
|
|
1820
|
+
"--generate",
|
|
1821
|
+
"--glob",
|
|
1822
|
+
"--hostname-bin",
|
|
1823
|
+
"--hyperlink-format",
|
|
1824
|
+
"--iglob",
|
|
1825
|
+
"--ignore-file",
|
|
1826
|
+
"--max-columns",
|
|
1827
|
+
"--max-count",
|
|
1828
|
+
"--max-depth",
|
|
1829
|
+
// An ALIAS of --max-depth, and it takes a value. The round-5 extraction read
|
|
1830
|
+
// alias lines as plain switches and swept it into noValue, which hard-blocked
|
|
1831
|
+
// `rg --maxdepth 2 .env src` while `--max-depth 2` ran (/code-review round 7).
|
|
1832
|
+
"--maxdepth",
|
|
1833
|
+
"--max-filesize",
|
|
1834
|
+
"--path-separator",
|
|
1835
|
+
"--pre",
|
|
1836
|
+
"--pre-glob",
|
|
1837
|
+
"--regexp",
|
|
1838
|
+
"--regex-size-limit",
|
|
1839
|
+
"--replace",
|
|
1840
|
+
"--sort",
|
|
1841
|
+
"--sortr",
|
|
1842
|
+
"--threads",
|
|
1843
|
+
"--type",
|
|
1844
|
+
"--type-add",
|
|
1845
|
+
"--type-clear",
|
|
1846
|
+
"--type-not"
|
|
1847
|
+
]),
|
|
1848
|
+
noValue: /* @__PURE__ */ new Set([
|
|
1849
|
+
"-.",
|
|
1850
|
+
"-0",
|
|
1851
|
+
"-a",
|
|
1852
|
+
"-b",
|
|
1853
|
+
"-c",
|
|
1854
|
+
"-F",
|
|
1855
|
+
"-h",
|
|
1856
|
+
"-H",
|
|
1857
|
+
"-i",
|
|
1858
|
+
"-I",
|
|
1859
|
+
"-l",
|
|
1860
|
+
"-L",
|
|
1861
|
+
"-n",
|
|
1862
|
+
"-N",
|
|
1863
|
+
"-o",
|
|
1864
|
+
"-p",
|
|
1865
|
+
"-P",
|
|
1866
|
+
"-q",
|
|
1867
|
+
"-s",
|
|
1868
|
+
"-S",
|
|
1869
|
+
"-u",
|
|
1870
|
+
"-U",
|
|
1871
|
+
"-v",
|
|
1872
|
+
"-V",
|
|
1873
|
+
"-w",
|
|
1874
|
+
"-x",
|
|
1875
|
+
"-z",
|
|
1876
|
+
"--auto-hybrid-regex",
|
|
1877
|
+
"--binary",
|
|
1878
|
+
"--block-buffered",
|
|
1879
|
+
"--byte-offset",
|
|
1880
|
+
"--case-sensitive",
|
|
1881
|
+
"--column",
|
|
1882
|
+
"--count",
|
|
1883
|
+
"--count-matches",
|
|
1884
|
+
"--crlf",
|
|
1885
|
+
"--debug",
|
|
1886
|
+
"--files",
|
|
1887
|
+
"--files-with-matches",
|
|
1888
|
+
"--files-without-match",
|
|
1889
|
+
"--fixed-strings",
|
|
1890
|
+
"--follow",
|
|
1891
|
+
"--glob-case-insensitive",
|
|
1892
|
+
"--heading",
|
|
1893
|
+
"--help",
|
|
1894
|
+
"--hidden",
|
|
1895
|
+
"--ignore-case",
|
|
1896
|
+
"--ignore-file-case-insensitive",
|
|
1897
|
+
"--include-zero",
|
|
1898
|
+
"--invert-match",
|
|
1899
|
+
"--json",
|
|
1900
|
+
"--line-buffered",
|
|
1901
|
+
"--line-number",
|
|
1902
|
+
"--line-regexp",
|
|
1903
|
+
"--max-columns-preview",
|
|
1904
|
+
"--mmap",
|
|
1905
|
+
"--multiline",
|
|
1906
|
+
"--multiline-dotall",
|
|
1907
|
+
"--no-column",
|
|
1908
|
+
"--no-config",
|
|
1909
|
+
"--no-context-separator",
|
|
1910
|
+
"--no-encoding",
|
|
1911
|
+
"--no-filename",
|
|
1912
|
+
"--no-ignore",
|
|
1913
|
+
"--no-ignore-dot",
|
|
1914
|
+
"--no-ignore-exclude",
|
|
1915
|
+
"--no-ignore-files",
|
|
1916
|
+
"--no-ignore-global",
|
|
1917
|
+
"--no-ignore-messages",
|
|
1918
|
+
"--no-ignore-parent",
|
|
1919
|
+
"--no-ignore-vcs",
|
|
1920
|
+
"--no-line-number",
|
|
1921
|
+
"--no-messages",
|
|
1922
|
+
"--no-pcre2-unicode",
|
|
1923
|
+
"--no-pre",
|
|
1924
|
+
"--no-require-git",
|
|
1925
|
+
"--no-unicode",
|
|
1926
|
+
"--null",
|
|
1927
|
+
"--null-data",
|
|
1928
|
+
"--one-file-system",
|
|
1929
|
+
"--only-matching",
|
|
1930
|
+
"--passthru",
|
|
1931
|
+
"--pcre2",
|
|
1932
|
+
"--pcre2-version",
|
|
1933
|
+
"--pretty",
|
|
1934
|
+
"--print0",
|
|
1935
|
+
"--quiet",
|
|
1936
|
+
"--search-zip",
|
|
1937
|
+
"--smart-case",
|
|
1938
|
+
"--sort-files",
|
|
1939
|
+
"--stats",
|
|
1940
|
+
"--stop-on-nonmatch",
|
|
1941
|
+
"--text",
|
|
1942
|
+
"--trace",
|
|
1943
|
+
"--trim",
|
|
1944
|
+
"--type-list",
|
|
1945
|
+
"--unrestricted",
|
|
1946
|
+
"--version",
|
|
1947
|
+
"--vimgrep",
|
|
1948
|
+
"--with-filename",
|
|
1949
|
+
"--word-regexp",
|
|
1950
|
+
// The COMPLETE remainder of `rg --help`, added after /code-review round 5
|
|
1951
|
+
// found 40 documented switches in neither set. The table is now the whole
|
|
1952
|
+
// option list: `rg --help` yields 149 long options, 35 of them value-taking.
|
|
1953
|
+
"--ignore",
|
|
1954
|
+
"--ignore-dot",
|
|
1955
|
+
"--ignore-exclude",
|
|
1956
|
+
"--ignore-files",
|
|
1957
|
+
"--ignore-global",
|
|
1958
|
+
"--ignore-messages",
|
|
1959
|
+
"--ignore-parent",
|
|
1960
|
+
"--ignore-vcs",
|
|
1961
|
+
"--messages",
|
|
1962
|
+
"--no-auto-hybrid-regex",
|
|
1963
|
+
"--no-binary",
|
|
1964
|
+
"--no-block-buffered",
|
|
1965
|
+
"--no-byte-offset",
|
|
1966
|
+
"--no-crlf",
|
|
1967
|
+
"--no-fixed-strings",
|
|
1968
|
+
"--no-follow",
|
|
1969
|
+
"--no-glob-case-insensitive",
|
|
1970
|
+
"--no-heading",
|
|
1971
|
+
"--no-hidden",
|
|
1972
|
+
"--no-ignore-file-case-insensitive",
|
|
1973
|
+
"--no-include-zero",
|
|
1974
|
+
"--no-invert-match",
|
|
1975
|
+
"--no-json",
|
|
1976
|
+
"--no-line-buffered",
|
|
1977
|
+
"--no-max-columns-preview",
|
|
1978
|
+
"--no-mmap",
|
|
1979
|
+
"--no-multiline",
|
|
1980
|
+
"--no-multiline-dotall",
|
|
1981
|
+
"--no-one-file-system",
|
|
1982
|
+
"--no-pcre2",
|
|
1983
|
+
"--no-search-zip",
|
|
1984
|
+
"--no-sort-files",
|
|
1985
|
+
"--no-stats",
|
|
1986
|
+
"--no-text",
|
|
1987
|
+
"--no-trim",
|
|
1988
|
+
"--passthrough",
|
|
1989
|
+
"--pcre2-unicode",
|
|
1990
|
+
"--require-git",
|
|
1991
|
+
"--unicode"
|
|
1992
|
+
]),
|
|
1993
|
+
patternFlags: /* @__PURE__ */ new Set(["-e", "--regexp"]),
|
|
1994
|
+
// `--files` and `--type-list` list or enumerate without a pattern. Founder
|
|
1995
|
+
// decision 2026-09-13: `rg --files ~/.ssh` stays BLOCKED, which this achieves
|
|
1996
|
+
// by leaving the directory in the judged list.
|
|
1997
|
+
noPatternFlags: /* @__PURE__ */ new Set(["-f", "--file", "--files", "--type-list", "--pcre2-version"])
|
|
1998
|
+
}
|
|
1999
|
+
};
|
|
2000
|
+
var PATTERN_VERB_NAMES = Object.keys(PATTERN_VERBS);
|
|
2001
|
+
var GREP_FILE_OPERANDS = /* @__PURE__ */ new Set(["-f", "--file", "--exclude-from", "--include"]);
|
|
2002
|
+
var READER_VALUE_LETTERS = {
|
|
2003
|
+
awk: ["F", "v", "f"],
|
|
2004
|
+
gawk: ["F", "v", "f", "e", "E", "i", "l", "o", "p", "D"],
|
|
2005
|
+
sed: ["e", "f", "i", "l"],
|
|
2006
|
+
sort: ["C", "k", "o", "S", "t", "T"]
|
|
2007
|
+
};
|
|
2008
|
+
var FILE_OPERAND_FLAGS = {
|
|
2009
|
+
grep: GREP_FILE_OPERANDS,
|
|
2010
|
+
egrep: GREP_FILE_OPERANDS,
|
|
2011
|
+
fgrep: GREP_FILE_OPERANDS,
|
|
2012
|
+
// rg and gawk are NOT installed on the measuring machine: these two rows are
|
|
2013
|
+
// from the shipped documentation (ripgrep `-f/--file`, `--ignore-file`; gawk
|
|
2014
|
+
// `-f/--file`) and are marked as such in the spec.
|
|
2015
|
+
// `-g/--glob/--iglob` name which files ripgrep SEARCHES, so an operand naming
|
|
2016
|
+
// a credential makes rg open it -- the same reason grep's `--include` is here.
|
|
2017
|
+
// Measured (/code-review round 3): `rg --hidden -g .env AWS tree` opened .env
|
|
2018
|
+
// and printed its contents.
|
|
2019
|
+
rg: /* @__PURE__ */ new Set(["-f", "--file", "--ignore-file", "-g", "--glob", "--iglob"]),
|
|
2020
|
+
sed: /* @__PURE__ */ new Set(["-f", "--file"]),
|
|
2021
|
+
awk: /* @__PURE__ */ new Set(["-f", "--file"]),
|
|
2022
|
+
gawk: /* @__PURE__ */ new Set(["-f", "--file"]),
|
|
2023
|
+
sort: /* @__PURE__ */ new Set(["--files0-from"])
|
|
2024
|
+
};
|
|
1673
2025
|
var SCP_VALUE_FLAGS = ["i", "F", "o", "c", "S", "P", "J", "D", "W", "l"];
|
|
2026
|
+
var TAR_VALUE_LETTERS = ["b", "C", "f", "F", "g", "H", "I", "K", "L", "N", "T", "V", "X"];
|
|
2027
|
+
var ZIP_VALUE_LETTERS = ["b", "n", "P", "t", "s", "O", "x", "i"];
|
|
2028
|
+
var RSYNC_VALUE_LETTERS = ["e", "f", "T", "B", "M"];
|
|
1674
2029
|
var RSYNC_SKIP = [
|
|
1675
2030
|
"e",
|
|
1676
2031
|
"--rsh",
|
|
@@ -1682,21 +2037,35 @@ var RSYNC_SKIP = [
|
|
|
1682
2037
|
"f",
|
|
1683
2038
|
"--filter"
|
|
1684
2039
|
];
|
|
2040
|
+
var CP_VALUE_LETTERS = ["S", "t"];
|
|
2041
|
+
var INSTALL_VALUE_LETTERS = ["S", "t", "g", "m", "o"];
|
|
1685
2042
|
var COPY_VERBS = {
|
|
1686
|
-
cp: { source: "allButLast", targetDirFlag: true },
|
|
1687
|
-
mv: { source: "allButLast", targetDirFlag: true },
|
|
1688
|
-
install: { source: "allButLast", targetDirFlag: true },
|
|
1689
|
-
ln: { source: "first", targetDirFlag: true },
|
|
1690
|
-
scp: { source: "allButLast", skipFlags: SCP_VALUE_FLAGS },
|
|
1691
|
-
rsync: { source: "allButLast", skipFlags: RSYNC_SKIP },
|
|
2043
|
+
cp: { source: "allButLast", targetDirFlag: true, valueLetters: CP_VALUE_LETTERS },
|
|
2044
|
+
mv: { source: "allButLast", targetDirFlag: true, valueLetters: CP_VALUE_LETTERS },
|
|
2045
|
+
install: { source: "allButLast", targetDirFlag: true, valueLetters: INSTALL_VALUE_LETTERS },
|
|
2046
|
+
ln: { source: "first", targetDirFlag: true, valueLetters: CP_VALUE_LETTERS },
|
|
2047
|
+
scp: { source: "allButLast", skipFlags: SCP_VALUE_FLAGS, valueLetters: SCP_VALUE_FLAGS },
|
|
2048
|
+
rsync: { source: "allButLast", skipFlags: RSYNC_SKIP, valueLetters: RSYNC_VALUE_LETTERS },
|
|
1692
2049
|
tar: {
|
|
1693
2050
|
source: "archive",
|
|
1694
2051
|
archive: "tar",
|
|
1695
|
-
skipFlags: ["f", "X", "T", "--file", "--exclude", "--exclude-from", "--files-from"]
|
|
2052
|
+
skipFlags: ["f", "X", "T", "--file", "--exclude", "--exclude-from", "--files-from"],
|
|
2053
|
+
valueLetters: TAR_VALUE_LETTERS
|
|
2054
|
+
},
|
|
2055
|
+
zip: {
|
|
2056
|
+
source: "archive",
|
|
2057
|
+
archive: "zip",
|
|
2058
|
+
skipFlags: ["x", "i", "--exclude", "--include"],
|
|
2059
|
+
valueLetters: ZIP_VALUE_LETTERS
|
|
1696
2060
|
},
|
|
1697
|
-
zip: { source: "archive", archive: "zip", skipFlags: ["x", "i", "--exclude", "--include"] },
|
|
1698
2061
|
ar: { source: "archive", archive: "ar" },
|
|
1699
|
-
|
|
2062
|
+
// 7z switches are INLINE only (`-mx9`, `-px`, `-x!pat`), so no following word is
|
|
2063
|
+
// ever a switch's operand -- which is why the short `x` is NOT a skipFlag here
|
|
2064
|
+
// and valueLetters is empty. Keeping the short `x` made `7z a out.7z -mx KEY`
|
|
2065
|
+
// drop the credential as an exclusion operand (/code-review round 8), and the
|
|
2066
|
+
// derived "every skipped letter is a value letter" row in jail-copy.spec.ts is
|
|
2067
|
+
// what keeps the two tables honest about it.
|
|
2068
|
+
"7z": { source: "archive", archive: "7z", skipFlags: ["--exclude"], valueLetters: [] },
|
|
1700
2069
|
gzip: { source: "all" },
|
|
1701
2070
|
bzip2: { source: "all" },
|
|
1702
2071
|
xz: { source: "all" },
|
|
@@ -2556,7 +2925,7 @@ function analyzeFsOperationImpl(command, depth = 0) {
|
|
|
2556
2925
|
return result?.verdict !== "block";
|
|
2557
2926
|
}
|
|
2558
2927
|
if (nodeType !== "CallExpr") return true;
|
|
2559
|
-
const { name, flags, paths, words } = extractLiteralArgs(n);
|
|
2928
|
+
const { name, flags, paths, words, args } = extractLiteralArgs(n);
|
|
2560
2929
|
if (!name) return true;
|
|
2561
2930
|
if (name === "rm") {
|
|
2562
2931
|
const flagStr = flags.join("").toLowerCase();
|
|
@@ -2596,7 +2965,7 @@ function analyzeFsOperationImpl(command, depth = 0) {
|
|
|
2596
2965
|
return true;
|
|
2597
2966
|
}
|
|
2598
2967
|
}
|
|
2599
|
-
const readPaths = FS_READ_TOOLS.has(name) ?
|
|
2968
|
+
const readPaths = FS_READ_TOOLS.has(name) ? [...readTargets(name, args, flags, words, 1), ...flagOperandFiles(name, words, 1)] : wrappedReadPaths(words, name);
|
|
2600
2969
|
if (readPaths) {
|
|
2601
2970
|
for (const p of readPaths) {
|
|
2602
2971
|
result = stricter(result, matchSensitivePath2(p));
|
|
@@ -2632,9 +3001,22 @@ function flagIs(w, names) {
|
|
|
2632
3001
|
const f = flagInfo(w);
|
|
2633
3002
|
return names.some((n) => n.startsWith("--") ? f.long === n : f.letter === n);
|
|
2634
3003
|
}
|
|
2635
|
-
function operandOf(a, names) {
|
|
3004
|
+
function operandOf(a, names, valueLetters) {
|
|
2636
3005
|
if (!names || a.afterFlag === null) return false;
|
|
2637
|
-
|
|
3006
|
+
const w = a.afterFlag;
|
|
3007
|
+
if (!w.startsWith("--") && valueLetters) {
|
|
3008
|
+
const letters = w.slice(1);
|
|
3009
|
+
for (let i = 0; i < letters.length; i++) {
|
|
3010
|
+
if (!valueLetters.includes(letters[i])) continue;
|
|
3011
|
+
return i === letters.length - 1 && names.includes(letters[i]);
|
|
3012
|
+
}
|
|
3013
|
+
return false;
|
|
3014
|
+
}
|
|
3015
|
+
if (w.startsWith("--") && !w.includes("=")) {
|
|
3016
|
+
const longs = names.filter((n) => n.startsWith("--"));
|
|
3017
|
+
if (longs.some((n) => n === w || w.length >= 3 && n.startsWith(w))) return true;
|
|
3018
|
+
}
|
|
3019
|
+
return flagIs(w, names) && flagInfo(w).attached === null;
|
|
2638
3020
|
}
|
|
2639
3021
|
function resolveCopyShape(words, h) {
|
|
2640
3022
|
const verb = baseWord(words[h]);
|
|
@@ -2659,7 +3041,7 @@ function findStartPoints(words, h) {
|
|
|
2659
3041
|
const k = words.findIndex((w, i) => i > h && w !== null && FIND_EXEC_FLAGS.has(w));
|
|
2660
3042
|
if (k < 0) return { k, starts: [] };
|
|
2661
3043
|
const firstPredicate = words.findIndex(
|
|
2662
|
-
(w, i) => i > h && w !== null && w.startsWith("-") && !FIND_OPTIONS.has(w)
|
|
3044
|
+
(w, i) => i > h && w !== null && w !== "--" && w.startsWith("-") && !FIND_OPTIONS.has(w)
|
|
2663
3045
|
);
|
|
2664
3046
|
const end = firstPredicate > h ? firstPredicate : k;
|
|
2665
3047
|
return { k, starts: positionalAfter(words, h + 1, end) };
|
|
@@ -2679,14 +3061,35 @@ function copySourcePaths(words) {
|
|
|
2679
3061
|
const { shape, last } = r;
|
|
2680
3062
|
const args = positionedArgs(words, last + 1);
|
|
2681
3063
|
const tail = words.slice(last + 1);
|
|
2682
|
-
const
|
|
2683
|
-
const
|
|
2684
|
-
const
|
|
3064
|
+
const copyOptionsEnd = tail.findIndex((w) => w === "--");
|
|
3065
|
+
const copyPastOptions = (a) => copyOptionsEnd >= 0 && a.argv > last + 1 + copyOptionsEnd;
|
|
3066
|
+
const skipped = (a) => !copyPastOptions(a) && operandOf(a, shape.skipFlags, shape.valueLetters);
|
|
3067
|
+
const firstValueLetter = (w) => {
|
|
3068
|
+
const letters = w.slice(1);
|
|
3069
|
+
for (let i = 0; i < letters.length; i++) {
|
|
3070
|
+
if ((shape.valueLetters ?? []).includes(letters[i]))
|
|
3071
|
+
return { letter: letters[i], last: i === letters.length - 1 };
|
|
3072
|
+
}
|
|
3073
|
+
return null;
|
|
3074
|
+
};
|
|
3075
|
+
const isTargetDirFlag = (w) => {
|
|
3076
|
+
if (w.startsWith("--")) {
|
|
3077
|
+
const name = w.includes("=") ? w.slice(0, w.indexOf("=")) : w;
|
|
3078
|
+
return name.length >= 3 && "--target-directory".startsWith(name);
|
|
3079
|
+
}
|
|
3080
|
+
return firstValueLetter(w)?.letter === "t";
|
|
3081
|
+
};
|
|
3082
|
+
const targetDir = shape.targetDirFlag === true && tail.some((w) => w !== null && w.startsWith("-") && isTargetDirFlag(w));
|
|
3083
|
+
const targetTakesNextWord = (w) => {
|
|
3084
|
+
if (w.startsWith("--"))
|
|
3085
|
+
return !w.includes("=") && w.length >= 3 && "--target-directory".startsWith(w);
|
|
3086
|
+
const f = firstValueLetter(w);
|
|
3087
|
+
return f !== null && f.letter === "t" && f.last;
|
|
3088
|
+
};
|
|
3089
|
+
const targetOperand = (a) => targetDir && a.afterFlag !== null && !copyPastOptions(a) && targetTakesNextWord(a.afterFlag);
|
|
2685
3090
|
const lastOperand = [...tail].reverse().find((w) => w === null || !w.startsWith("-"));
|
|
2686
3091
|
const dynamicDest = lastOperand === null;
|
|
2687
3092
|
const destIsLastOperand = (shape.source === "allButLast" || shape.source === "first") && !targetDir && !dynamicDest;
|
|
2688
|
-
if (destIsLastOperand && typeof lastOperand === "string" && matchSensitivePath2(lastOperand))
|
|
2689
|
-
return [];
|
|
2690
3093
|
let src;
|
|
2691
3094
|
switch (shape.source) {
|
|
2692
3095
|
case "all":
|
|
@@ -2696,11 +3099,17 @@ function copySourcePaths(words) {
|
|
|
2696
3099
|
src = targetDir ? args : args.slice(0, 1);
|
|
2697
3100
|
break;
|
|
2698
3101
|
case "flagOperand": {
|
|
2699
|
-
const
|
|
3102
|
+
const namesSource = (f) => {
|
|
3103
|
+
const names = shape.sourceFlags ?? [];
|
|
3104
|
+
if (f.long !== null)
|
|
3105
|
+
return names.some(
|
|
3106
|
+
(n) => n.startsWith("--") && (n === f.long || f.long.length >= 3 && n.startsWith(f.long))
|
|
3107
|
+
);
|
|
3108
|
+
return f.letter !== null && names.includes(f.letter);
|
|
3109
|
+
};
|
|
3110
|
+
const inline = tail.filter((w) => w !== null && w.startsWith("-")).map((w) => flagInfo(w)).filter((f) => f.attached !== null && namesSource(f)).map((f) => f.attached);
|
|
2700
3111
|
return [
|
|
2701
|
-
...args.filter(
|
|
2702
|
-
(a) => flagIs(a.afterFlag, shape.sourceFlags ?? []) && flagInfo(a.afterFlag).attached === null
|
|
2703
|
-
).map((a) => a.value),
|
|
3112
|
+
...args.filter((a) => !copyPastOptions(a) && operandOf(a, shape.sourceFlags, shape.valueLetters)).map((a) => a.value),
|
|
2704
3113
|
...inline
|
|
2705
3114
|
];
|
|
2706
3115
|
}
|
|
@@ -2711,7 +3120,14 @@ function copySourcePaths(words) {
|
|
|
2711
3120
|
src = targetDir || dynamicDest ? args : args.slice(0, -1);
|
|
2712
3121
|
break;
|
|
2713
3122
|
}
|
|
2714
|
-
|
|
3123
|
+
const sources = src.filter((a) => !skipped(a) && !targetOperand(a)).map((a) => a.value);
|
|
3124
|
+
if (destIsLastOperand && typeof lastOperand === "string" && matchSensitivePath2(lastOperand)) {
|
|
3125
|
+
const jailedSources = sources.filter((p) => matchSensitivePath2(p));
|
|
3126
|
+
const dirOf = (p) => /[\\/]/.test(p) ? p.replace(/[\\/][^\\/]*$/, "") : "";
|
|
3127
|
+
if (jailedSources.length === 0) return [];
|
|
3128
|
+
if (jailedSources.every((p) => dirOf(p) === dirOf(lastOperand))) return [];
|
|
3129
|
+
}
|
|
3130
|
+
return sources;
|
|
2715
3131
|
}
|
|
2716
3132
|
function archiveInputs(kind, args, tail) {
|
|
2717
3133
|
const first = args[0];
|
|
@@ -2723,13 +3139,17 @@ function archiveInputs(kind, args, tail) {
|
|
|
2723
3139
|
const writing = /[cruA]/.test(bareKey ? first.value : "") || /(^|\s)-[a-zA-Z]*[cruA]|--create|--append|--update|--concatenate/.test(flagsText);
|
|
2724
3140
|
if (extracting && !writing) return [];
|
|
2725
3141
|
void mode;
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
if (
|
|
2731
|
-
|
|
2732
|
-
|
|
3142
|
+
if (!bareKey) return args;
|
|
3143
|
+
let i = 1;
|
|
3144
|
+
const fromDirs = [];
|
|
3145
|
+
for (const ch of first.value) {
|
|
3146
|
+
if (!TAR_VALUE_LETTERS.includes(ch)) continue;
|
|
3147
|
+
const operand = args[i];
|
|
3148
|
+
if (!operand || operand.afterFlag !== null) break;
|
|
3149
|
+
i += 1;
|
|
3150
|
+
if (ch === "C") fromDirs.push(operand);
|
|
3151
|
+
}
|
|
3152
|
+
return [...fromDirs, ...args.slice(i)];
|
|
2733
3153
|
}
|
|
2734
3154
|
if (kind === "zip") return first && first.afterFlag === "-" ? args : args.slice(1);
|
|
2735
3155
|
if (kind === "ar") return bareKey ? args.slice(2) : args.slice(1);
|
|
@@ -2764,6 +3184,140 @@ function baseWord(w) {
|
|
|
2764
3184
|
}
|
|
2765
3185
|
var isReaderWord = (w) => w !== null && FS_READ_TOOLS.has(baseWord(w));
|
|
2766
3186
|
var positionalAfter = (words, from, to = words.length) => positionedArgs(words, from, to).map((a) => a.value);
|
|
3187
|
+
function namesFlag(name, candidates, known) {
|
|
3188
|
+
if (candidates.has(name)) return true;
|
|
3189
|
+
if (!name.startsWith("--") || name.length < 3) return false;
|
|
3190
|
+
if (known?.has(name)) return false;
|
|
3191
|
+
for (const c of candidates) if (c.startsWith(name)) return true;
|
|
3192
|
+
return false;
|
|
3193
|
+
}
|
|
3194
|
+
function knownLongFlags(verb) {
|
|
3195
|
+
const out = /* @__PURE__ */ new Set();
|
|
3196
|
+
const shape = PATTERN_VERBS[verb];
|
|
3197
|
+
if (shape) {
|
|
3198
|
+
for (const set of [shape.takesValue, shape.noValue, shape.patternFlags, shape.noPatternFlags])
|
|
3199
|
+
for (const f of set) if (f.startsWith("--")) out.add(f);
|
|
3200
|
+
}
|
|
3201
|
+
for (const f of FILE_OPERAND_FLAGS[verb] ?? []) if (f.startsWith("--")) out.add(f);
|
|
3202
|
+
return out;
|
|
3203
|
+
}
|
|
3204
|
+
function flagNamesOf(token, shape) {
|
|
3205
|
+
if (token.startsWith("--")) {
|
|
3206
|
+
const eq = token.indexOf("=");
|
|
3207
|
+
return [eq > 0 ? token.slice(0, eq) : token];
|
|
3208
|
+
}
|
|
3209
|
+
const out = [];
|
|
3210
|
+
for (const c of token.slice(1)) {
|
|
3211
|
+
const name = `-${c}`;
|
|
3212
|
+
out.push(name);
|
|
3213
|
+
if (shape?.takesValue.has(name)) break;
|
|
3214
|
+
}
|
|
3215
|
+
return out;
|
|
3216
|
+
}
|
|
3217
|
+
var NONE = { kind: "none" };
|
|
3218
|
+
var UNKNOWN = { kind: "unknown" };
|
|
3219
|
+
function flagEffect(token, shape, known) {
|
|
3220
|
+
if (token === "--") return NONE;
|
|
3221
|
+
if (/^-+$/.test(token)) return UNKNOWN;
|
|
3222
|
+
if (/^-\d+$/.test(token)) return NONE;
|
|
3223
|
+
if (token.startsWith("--")) {
|
|
3224
|
+
if (token.includes("=")) return NONE;
|
|
3225
|
+
const takes = namesFlag(token, shape.takesValue, known);
|
|
3226
|
+
const none = namesFlag(token, shape.noValue, known);
|
|
3227
|
+
if (takes && none) return UNKNOWN;
|
|
3228
|
+
if (takes) return { kind: "takes", flag: token };
|
|
3229
|
+
if (none) return NONE;
|
|
3230
|
+
return UNKNOWN;
|
|
3231
|
+
}
|
|
3232
|
+
const letters = token.slice(1);
|
|
3233
|
+
if (!letters) return NONE;
|
|
3234
|
+
for (let i = 0; i < letters.length; i++) {
|
|
3235
|
+
const name = `-${letters[i]}`;
|
|
3236
|
+
if (shape.takesValue.has(name)) {
|
|
3237
|
+
return i === letters.length - 1 ? { kind: "takes", flag: name } : NONE;
|
|
3238
|
+
}
|
|
3239
|
+
if (!shape.noValue.has(name)) return UNKNOWN;
|
|
3240
|
+
}
|
|
3241
|
+
return NONE;
|
|
3242
|
+
}
|
|
3243
|
+
function readTargets(verb, args, flags, words = [], from = 1) {
|
|
3244
|
+
const shape = PATTERN_VERBS[verb];
|
|
3245
|
+
if (!shape) return args.map((a) => a.value);
|
|
3246
|
+
const known = knownLongFlags(verb);
|
|
3247
|
+
const names = flags.flatMap((f) => flagNamesOf(f, shape));
|
|
3248
|
+
const patternElsewhere = names.some(
|
|
3249
|
+
(n) => namesFlag(n, shape.patternFlags, known) || namesFlag(n, shape.noPatternFlags, known)
|
|
3250
|
+
);
|
|
3251
|
+
const excused = /* @__PURE__ */ new Set();
|
|
3252
|
+
const fileFlags = FILE_OPERAND_FLAGS[verb];
|
|
3253
|
+
const optionsEnd = words.findIndex((w, i) => i >= from && w === "--");
|
|
3254
|
+
const pastOptions = (a) => optionsEnd >= 0 && a.argv > optionsEnd;
|
|
3255
|
+
for (const a of args) {
|
|
3256
|
+
if (a.afterFlag === null || pastOptions(a)) continue;
|
|
3257
|
+
const e = flagEffect(a.afterFlag, shape, known);
|
|
3258
|
+
if (e.kind !== "takes") continue;
|
|
3259
|
+
if (fileFlags && namesFlag(e.flag, fileFlags, known)) continue;
|
|
3260
|
+
excused.add(a);
|
|
3261
|
+
}
|
|
3262
|
+
const patternArgv = (() => {
|
|
3263
|
+
for (let i = from; i < words.length; i++) {
|
|
3264
|
+
const w = words[i];
|
|
3265
|
+
if (w === null) return -1;
|
|
3266
|
+
if (w === "--") return i + 1;
|
|
3267
|
+
if (w.startsWith("-")) {
|
|
3268
|
+
const e = flagEffect(w, shape, known);
|
|
3269
|
+
if (e.kind === "takes") i += 1;
|
|
3270
|
+
else if (e.kind === "unknown") return -1;
|
|
3271
|
+
continue;
|
|
3272
|
+
}
|
|
3273
|
+
return i;
|
|
3274
|
+
}
|
|
3275
|
+
return -1;
|
|
3276
|
+
})();
|
|
3277
|
+
if (!patternElsewhere && patternArgv >= 0) {
|
|
3278
|
+
const a = args.find((x) => x.argv === patternArgv);
|
|
3279
|
+
if (a) excused.add(a);
|
|
3280
|
+
}
|
|
3281
|
+
return args.filter((a) => !excused.has(a)).map((a) => a.value);
|
|
3282
|
+
}
|
|
3283
|
+
function flagOperandFiles(verb, words, from) {
|
|
3284
|
+
const flags = FILE_OPERAND_FLAGS[verb];
|
|
3285
|
+
if (!flags) return [];
|
|
3286
|
+
const known = knownLongFlags(verb);
|
|
3287
|
+
const out = [];
|
|
3288
|
+
for (let i = from; i < words.length; i++) {
|
|
3289
|
+
const w = words[i];
|
|
3290
|
+
if (w === null || !w.startsWith("-") || w === "--") continue;
|
|
3291
|
+
if (w.startsWith("--")) {
|
|
3292
|
+
const eq = w.indexOf("=");
|
|
3293
|
+
if (eq <= 0) continue;
|
|
3294
|
+
const name = w.slice(0, eq);
|
|
3295
|
+
const value = w.slice(eq + 1);
|
|
3296
|
+
if (!value) continue;
|
|
3297
|
+
if (namesFlag(name, flags, known)) {
|
|
3298
|
+
out.push(value);
|
|
3299
|
+
continue;
|
|
3300
|
+
}
|
|
3301
|
+
const shape2 = PATTERN_VERBS[verb];
|
|
3302
|
+
if (!shape2) continue;
|
|
3303
|
+
const recognised = namesFlag(name, shape2.takesValue, known) || namesFlag(name, shape2.noValue, known) || namesFlag(name, shape2.patternFlags, known) || namesFlag(name, shape2.noPatternFlags, known);
|
|
3304
|
+
if (!recognised) out.push(value);
|
|
3305
|
+
continue;
|
|
3306
|
+
}
|
|
3307
|
+
const shape = PATTERN_VERBS[verb];
|
|
3308
|
+
const letters = w.slice(1);
|
|
3309
|
+
for (let j = 0; j < letters.length; j++) {
|
|
3310
|
+
const name = `-${letters[j]}`;
|
|
3311
|
+
const isFileFlag = flags.has(name);
|
|
3312
|
+
const argTaking = isFileFlag || (shape?.takesValue.has(name) ?? false) || (READER_VALUE_LETTERS[verb] ?? []).includes(letters[j]);
|
|
3313
|
+
if (!argTaking) continue;
|
|
3314
|
+
const attached = letters.slice(j + 1);
|
|
3315
|
+
if (isFileFlag && attached) out.push(attached);
|
|
3316
|
+
break;
|
|
3317
|
+
}
|
|
3318
|
+
}
|
|
3319
|
+
return out;
|
|
3320
|
+
}
|
|
2767
3321
|
function wrappedReadPaths(words, name) {
|
|
2768
3322
|
if (name === "find") {
|
|
2769
3323
|
const { k, starts } = findStartPoints(words, 0);
|
|
@@ -2771,7 +3325,14 @@ function wrappedReadPaths(words, name) {
|
|
|
2771
3325
|
}
|
|
2772
3326
|
if (!COMMAND_WRAPPERS.has(name) && !RUNNER_WRAPPERS.has(name)) return null;
|
|
2773
3327
|
const h = unwrapCommandHead(words);
|
|
2774
|
-
|
|
3328
|
+
if (h <= 0 || !isReaderWord(words[h] ?? null)) return null;
|
|
3329
|
+
const head = baseWord(words[h]);
|
|
3330
|
+
const rest = words.slice(h + 1);
|
|
3331
|
+
const restFlags = rest.filter((w) => w !== null && w.startsWith("-"));
|
|
3332
|
+
return [
|
|
3333
|
+
...readTargets(head, positionedArgs(words, h + 1), restFlags, words, h + 1),
|
|
3334
|
+
...flagOperandFiles(head, words, h + 1)
|
|
3335
|
+
];
|
|
2775
3336
|
}
|
|
2776
3337
|
function literalShellPayload(words, name) {
|
|
2777
3338
|
const h = COMMAND_WRAPPERS.has(name) || RUNNER_WRAPPERS.has(name) ? unwrapCommandHead(words) : 0;
|
|
@@ -3893,6 +4454,15 @@ async function evaluatePolicy(config, toolName, args, context = {}, hooks = {})
|
|
|
3893
4454
|
function isIgnoredTool(toolName, config) {
|
|
3894
4455
|
return matchesPattern(toolName, config.policy.ignoredTools);
|
|
3895
4456
|
}
|
|
4457
|
+
var TERMINAL_ESCAPE_RE = /\x1b\[[0-9;?]*[A-Za-z]|\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)|\x1b[@-_]|[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g;
|
|
4458
|
+
function stripTerminalEscapes(s) {
|
|
4459
|
+
return s.replace(TERMINAL_ESCAPE_RE, "");
|
|
4460
|
+
}
|
|
4461
|
+
function safeMessage(value, max = 300) {
|
|
4462
|
+
const raw = typeof value === "string" ? value : value instanceof Error ? value.message : String(value ?? "");
|
|
4463
|
+
const s = stripTerminalEscapes(raw).replace(/\s+/g, " ").trim();
|
|
4464
|
+
return s.length > max ? s.slice(0, max - 1) + "\u2026" : s;
|
|
4465
|
+
}
|
|
3896
4466
|
var aws_default = {
|
|
3897
4467
|
name: "aws",
|
|
3898
4468
|
description: "Protects AWS infrastructure from destructive AI operations",
|
|
@@ -6892,7 +7462,7 @@ function escapePango(text) {
|
|
|
6892
7462
|
function buildPlainMessage(toolName, formattedArgs, agent, explainableLabel, locked, allowCount = 1, ruleDescription) {
|
|
6893
7463
|
const lines = [];
|
|
6894
7464
|
if (locked) lines.push("\u26A0\uFE0F LOCKED BY ADMIN POLICY\n");
|
|
6895
|
-
const safeAgent = (agent ?? "AI Agent"
|
|
7465
|
+
const safeAgent = safeMessage(agent ?? "AI Agent", 80);
|
|
6896
7466
|
lines.push(`\u{1F916} ${safeAgent} | \u{1F527} ${toolName}`);
|
|
6897
7467
|
lines.push(`\u{1F6E1}\uFE0F ${explainableLabel || "Security Policy"}`);
|
|
6898
7468
|
if (ruleDescription) lines.push(`\u2139 ${ruleDescription}`);
|
|
@@ -7220,14 +7790,14 @@ async function resolveNode9SaaS(requestId, creds, approved, decidedBy) {
|
|
|
7220
7790
|
if (!res.ok) {
|
|
7221
7791
|
fs11.appendFileSync(
|
|
7222
7792
|
HOOK_DEBUG_LOG,
|
|
7223
|
-
`[resolve-cloud] PATCH ${resolveUrl} \u2192 HTTP ${res.status}
|
|
7793
|
+
`[resolve-cloud] PATCH ${safeMessage(resolveUrl, 200)} \u2192 HTTP ${res.status}
|
|
7224
7794
|
`
|
|
7225
7795
|
);
|
|
7226
7796
|
}
|
|
7227
7797
|
} catch (err) {
|
|
7228
7798
|
fs11.appendFileSync(
|
|
7229
7799
|
HOOK_DEBUG_LOG,
|
|
7230
|
-
`[resolve-cloud] PATCH failed for ${requestId}: ${err
|
|
7800
|
+
`[resolve-cloud] PATCH failed for ${safeMessage(requestId, 64)}: ${safeMessage(err)}
|
|
7231
7801
|
`
|
|
7232
7802
|
);
|
|
7233
7803
|
}
|
|
@@ -7328,9 +7898,8 @@ async function authorizeHeadless(toolName, args, meta, options) {
|
|
|
7328
7898
|
if (!options?.calledFromDaemon) {
|
|
7329
7899
|
const actId = randomUUID();
|
|
7330
7900
|
const actTs = Date.now();
|
|
7331
|
-
const
|
|
7332
|
-
const
|
|
7333
|
-
const sanitizedMcpServer = meta?.mcpServer ? stripAnsi(meta.mcpServer).slice(0, 40) : void 0;
|
|
7901
|
+
const sanitizedAgent = meta?.agent ? safeMessage(meta.agent, 80) : void 0;
|
|
7902
|
+
const sanitizedMcpServer = meta?.mcpServer ? safeMessage(meta.mcpServer, 40) : void 0;
|
|
7334
7903
|
const socketOk = await notifyActivity({
|
|
7335
7904
|
id: actId,
|
|
7336
7905
|
ts: actTs,
|