@node9/proxy 2.54.0 → 2.54.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli-main.js +76 -11
- package/dist/dashboard.mjs +76 -11
- package/dist/hook.js +76 -11
- package/dist/index.js +76 -11
- package/dist/index.mjs +76 -11
- package/package.json +1 -1
package/dist/cli-main.js
CHANGED
|
@@ -976,12 +976,46 @@ function wordValues(word, state) {
|
|
|
976
976
|
if (!dynamic) return out.map(asWord);
|
|
977
977
|
return out.filter((piece) => piece.value !== "").map((piece) => ({ value: piece.value, pattern: piece.pattern + "*", dynamic: true }));
|
|
978
978
|
}
|
|
979
|
+
function sedSubstitutions(script) {
|
|
980
|
+
const out = [];
|
|
981
|
+
for (const raw of script.split(/\r?\n|;/)) {
|
|
982
|
+
const cmd = raw.trim();
|
|
983
|
+
if (cmd === "") continue;
|
|
984
|
+
const m = /^(?:(?:\d+|\$|\/(?:\\.|[^\\/])*\/)(?:,(?:\d+|\$|\/(?:\\.|[^\\/])*\/))?)?s(.)/.exec(
|
|
985
|
+
cmd
|
|
986
|
+
);
|
|
987
|
+
if (!m) return null;
|
|
988
|
+
const delimiter = m[1];
|
|
989
|
+
if (delimiter === "\\") return null;
|
|
990
|
+
const parts = [];
|
|
991
|
+
let cur = "";
|
|
992
|
+
let i = m[0].length;
|
|
993
|
+
for (; i < cmd.length && parts.length < 2; i++) {
|
|
994
|
+
const ch = cmd[i];
|
|
995
|
+
if (ch === "\\" && i + 1 < cmd.length) {
|
|
996
|
+
cur += ch + cmd[++i];
|
|
997
|
+
continue;
|
|
998
|
+
}
|
|
999
|
+
if (ch === delimiter) {
|
|
1000
|
+
parts.push(cur);
|
|
1001
|
+
cur = "";
|
|
1002
|
+
continue;
|
|
1003
|
+
}
|
|
1004
|
+
cur += ch;
|
|
1005
|
+
}
|
|
1006
|
+
if (parts.length < 2) return null;
|
|
1007
|
+
if (!/^[gpiImM0-9]*$/.test(cmd.slice(i))) return null;
|
|
1008
|
+
out.push(parts[1].replace(/\\(.)/g, "$1"));
|
|
1009
|
+
}
|
|
1010
|
+
return out.length > 0 ? out : null;
|
|
1011
|
+
}
|
|
979
1012
|
function collectShellFileAccesses(command, context = {}) {
|
|
980
1013
|
const out = [];
|
|
981
1014
|
let payloads = 256;
|
|
982
1015
|
const functions = /* @__PURE__ */ new Map();
|
|
983
1016
|
const seenCalls = /* @__PURE__ */ new Set();
|
|
984
1017
|
const pipedStdin = /* @__PURE__ */ new WeakMap();
|
|
1018
|
+
let currentStdin = null;
|
|
985
1019
|
let callWalks2 = MAX_CALL_WALKS;
|
|
986
1020
|
const initial = {
|
|
987
1021
|
cwd: [context.cwd ?? ""],
|
|
@@ -1076,8 +1110,9 @@ function collectShellFileAccesses(command, context = {}) {
|
|
|
1076
1110
|
}
|
|
1077
1111
|
const locate = (p) => tokens.find((w) => w?.value === p) ?? { value: p };
|
|
1078
1112
|
if (name === "sed") {
|
|
1079
|
-
let inplace = false, hasScript = false, ended = false;
|
|
1113
|
+
let inplace = false, hasScript = false, ended = false, scriptUnknown = false;
|
|
1080
1114
|
const files = [];
|
|
1115
|
+
const scriptParts = [];
|
|
1081
1116
|
for (let i = 0; i < args.length; i++) {
|
|
1082
1117
|
const token = args[i];
|
|
1083
1118
|
if (!token) {
|
|
@@ -1095,7 +1130,11 @@ function collectShellFileAccesses(command, context = {}) {
|
|
|
1095
1130
|
hasScript = true;
|
|
1096
1131
|
const eq = value.indexOf("=");
|
|
1097
1132
|
const script = eq < 0 ? args[++i] : { value: value.slice(eq + 1) };
|
|
1098
|
-
if (value.startsWith("--file")
|
|
1133
|
+
if (value.startsWith("--file")) {
|
|
1134
|
+
scriptUnknown = true;
|
|
1135
|
+
if (script) add("read", script, state);
|
|
1136
|
+
} else if (script?.value) scriptParts.push(script.value);
|
|
1137
|
+
else scriptUnknown = true;
|
|
1099
1138
|
}
|
|
1100
1139
|
continue;
|
|
1101
1140
|
}
|
|
@@ -1110,7 +1149,11 @@ function collectShellFileAccesses(command, context = {}) {
|
|
|
1110
1149
|
if (flag === "e" || flag === "f") {
|
|
1111
1150
|
hasScript = true;
|
|
1112
1151
|
const script = value.slice(j + 1) ? { value: value.slice(j + 1) } : args[++i];
|
|
1113
|
-
if (flag === "f"
|
|
1152
|
+
if (flag === "f") {
|
|
1153
|
+
scriptUnknown = true;
|
|
1154
|
+
if (script) add("read", script, state);
|
|
1155
|
+
} else if (script?.value) scriptParts.push(script.value);
|
|
1156
|
+
else scriptUnknown = true;
|
|
1114
1157
|
break;
|
|
1115
1158
|
}
|
|
1116
1159
|
if (flag === "l") {
|
|
@@ -1120,10 +1163,14 @@ function collectShellFileAccesses(command, context = {}) {
|
|
|
1120
1163
|
}
|
|
1121
1164
|
continue;
|
|
1122
1165
|
}
|
|
1123
|
-
if (!hasScript)
|
|
1124
|
-
|
|
1166
|
+
if (!hasScript) {
|
|
1167
|
+
hasScript = true;
|
|
1168
|
+
scriptParts.push(value);
|
|
1169
|
+
} else files.push(token);
|
|
1125
1170
|
}
|
|
1126
|
-
|
|
1171
|
+
const edits = inplace && !scriptUnknown ? sedSubstitutions(scriptParts.join("\n")) : null;
|
|
1172
|
+
for (const file2 of files)
|
|
1173
|
+
add(inplace ? "write" : "read", file2, state, edits ? { edits } : {});
|
|
1127
1174
|
return;
|
|
1128
1175
|
}
|
|
1129
1176
|
if (FS_READ_TOOLS.has(name) && name !== "dd") {
|
|
@@ -1250,9 +1297,11 @@ function collectShellFileAccesses(command, context = {}) {
|
|
|
1250
1297
|
continue;
|
|
1251
1298
|
const remove = name === "rm" || name === "unlink";
|
|
1252
1299
|
const append = name === "tee" && strings.some((s) => s === "--append" || /^-[^-]*a/.test(s));
|
|
1300
|
+
const teed = name === "tee" && !append ? currentStdin : null;
|
|
1253
1301
|
add(remove ? "remove" : name === "touch" ? "create" : "write", token, state, {
|
|
1254
1302
|
recursive: remove && strings.some((s) => /^-[^-]*[rR]/.test(s) || s === "--recursive"),
|
|
1255
|
-
...append ? { append: true } : {}
|
|
1303
|
+
...append ? { append: true } : {},
|
|
1304
|
+
...teed !== null ? { text: teed } : {}
|
|
1256
1305
|
});
|
|
1257
1306
|
}
|
|
1258
1307
|
return;
|
|
@@ -1574,11 +1623,18 @@ function collectShellFileAccesses(command, context = {}) {
|
|
|
1574
1623
|
if (stmt.Background) state = clone(state);
|
|
1575
1624
|
const headWord = stmt.Cmd && stmt.Cmd.kind === "CallExpr" ? base(resolveWordLiteral(stmt.Cmd.Args?.[0])) : "";
|
|
1576
1625
|
const sends = SENDING_STDIN.has(headWord);
|
|
1626
|
+
let produced;
|
|
1577
1627
|
for (const redir of stmt.Redirs ?? []) {
|
|
1578
1628
|
substitutions2(redir.Word, state, depth);
|
|
1579
1629
|
for (const word of wordValues(redir.Word, state)) {
|
|
1580
|
-
if (ops().WRITES.has(redir.Op))
|
|
1581
|
-
|
|
1630
|
+
if (ops().WRITES.has(redir.Op)) {
|
|
1631
|
+
if (ops().APPENDS.has(redir.Op)) add("write", word, state, { append: true });
|
|
1632
|
+
else {
|
|
1633
|
+
const stdout = redir.N == null || redir.N.Value === "1";
|
|
1634
|
+
if (stdout && produced === void 0) produced = producedText(stmt);
|
|
1635
|
+
add("write", word, state, stdout && produced ? { text: produced } : {});
|
|
1636
|
+
}
|
|
1637
|
+
}
|
|
1582
1638
|
if (ops().READS.has(redir.Op)) add("read", word, state, sends ? { upload: true } : {});
|
|
1583
1639
|
if (redir.Op === ops().DUP_OUT && word.value && !/^\d+$/.test(word.value))
|
|
1584
1640
|
add("write", word, state);
|
|
@@ -1590,6 +1646,7 @@ function collectShellFileAccesses(command, context = {}) {
|
|
|
1590
1646
|
stdinScript(stmt, state, depth);
|
|
1591
1647
|
const fedText = stdinText(stmt);
|
|
1592
1648
|
if (fedText !== null) nestedPayload(xargsPayload(stmt, fedText), clone(state), depth);
|
|
1649
|
+
currentStdin = fedText;
|
|
1593
1650
|
switch (cmd.kind) {
|
|
1594
1651
|
case "CallExpr":
|
|
1595
1652
|
call(cmd, state, depth);
|
|
@@ -6717,8 +6774,16 @@ function evaluateGitHooksFileAccess(args, accesses, context, settings, shell) {
|
|
|
6717
6774
|
disarms = true;
|
|
6718
6775
|
how = "removed";
|
|
6719
6776
|
} else if (texts === null) {
|
|
6720
|
-
|
|
6721
|
-
|
|
6777
|
+
if (access.edits) {
|
|
6778
|
+
disarms = access.edits.some(editDisarms);
|
|
6779
|
+
how = "edited to exit";
|
|
6780
|
+
} else if (access.text !== void 0) {
|
|
6781
|
+
disarms = hookTextRunsNothing(access.text);
|
|
6782
|
+
how = "emptied";
|
|
6783
|
+
} else {
|
|
6784
|
+
disarms = true;
|
|
6785
|
+
how = "overwritten";
|
|
6786
|
+
}
|
|
6722
6787
|
} else if (texts.whole.length > 0) {
|
|
6723
6788
|
disarms = texts.whole.some(hookTextRunsNothing);
|
|
6724
6789
|
how = "emptied";
|
package/dist/dashboard.mjs
CHANGED
|
@@ -994,12 +994,46 @@ function wordValues(word, state) {
|
|
|
994
994
|
if (!dynamic) return out.map(asWord);
|
|
995
995
|
return out.filter((piece) => piece.value !== "").map((piece) => ({ value: piece.value, pattern: piece.pattern + "*", dynamic: true }));
|
|
996
996
|
}
|
|
997
|
+
function sedSubstitutions(script) {
|
|
998
|
+
const out = [];
|
|
999
|
+
for (const raw of script.split(/\r?\n|;/)) {
|
|
1000
|
+
const cmd = raw.trim();
|
|
1001
|
+
if (cmd === "") continue;
|
|
1002
|
+
const m = /^(?:(?:\d+|\$|\/(?:\\.|[^\\/])*\/)(?:,(?:\d+|\$|\/(?:\\.|[^\\/])*\/))?)?s(.)/.exec(
|
|
1003
|
+
cmd
|
|
1004
|
+
);
|
|
1005
|
+
if (!m) return null;
|
|
1006
|
+
const delimiter = m[1];
|
|
1007
|
+
if (delimiter === "\\") return null;
|
|
1008
|
+
const parts = [];
|
|
1009
|
+
let cur = "";
|
|
1010
|
+
let i = m[0].length;
|
|
1011
|
+
for (; i < cmd.length && parts.length < 2; i++) {
|
|
1012
|
+
const ch = cmd[i];
|
|
1013
|
+
if (ch === "\\" && i + 1 < cmd.length) {
|
|
1014
|
+
cur += ch + cmd[++i];
|
|
1015
|
+
continue;
|
|
1016
|
+
}
|
|
1017
|
+
if (ch === delimiter) {
|
|
1018
|
+
parts.push(cur);
|
|
1019
|
+
cur = "";
|
|
1020
|
+
continue;
|
|
1021
|
+
}
|
|
1022
|
+
cur += ch;
|
|
1023
|
+
}
|
|
1024
|
+
if (parts.length < 2) return null;
|
|
1025
|
+
if (!/^[gpiImM0-9]*$/.test(cmd.slice(i))) return null;
|
|
1026
|
+
out.push(parts[1].replace(/\\(.)/g, "$1"));
|
|
1027
|
+
}
|
|
1028
|
+
return out.length > 0 ? out : null;
|
|
1029
|
+
}
|
|
997
1030
|
function collectShellFileAccesses(command, context = {}) {
|
|
998
1031
|
const out = [];
|
|
999
1032
|
let payloads = 256;
|
|
1000
1033
|
const functions = /* @__PURE__ */ new Map();
|
|
1001
1034
|
const seenCalls = /* @__PURE__ */ new Set();
|
|
1002
1035
|
const pipedStdin = /* @__PURE__ */ new WeakMap();
|
|
1036
|
+
let currentStdin = null;
|
|
1003
1037
|
let callWalks2 = MAX_CALL_WALKS;
|
|
1004
1038
|
const initial = {
|
|
1005
1039
|
cwd: [context.cwd ?? ""],
|
|
@@ -1094,8 +1128,9 @@ function collectShellFileAccesses(command, context = {}) {
|
|
|
1094
1128
|
}
|
|
1095
1129
|
const locate = (p) => tokens.find((w) => w?.value === p) ?? { value: p };
|
|
1096
1130
|
if (name === "sed") {
|
|
1097
|
-
let inplace = false, hasScript = false, ended = false;
|
|
1131
|
+
let inplace = false, hasScript = false, ended = false, scriptUnknown = false;
|
|
1098
1132
|
const files = [];
|
|
1133
|
+
const scriptParts = [];
|
|
1099
1134
|
for (let i = 0; i < args.length; i++) {
|
|
1100
1135
|
const token = args[i];
|
|
1101
1136
|
if (!token) {
|
|
@@ -1113,7 +1148,11 @@ function collectShellFileAccesses(command, context = {}) {
|
|
|
1113
1148
|
hasScript = true;
|
|
1114
1149
|
const eq = value.indexOf("=");
|
|
1115
1150
|
const script = eq < 0 ? args[++i] : { value: value.slice(eq + 1) };
|
|
1116
|
-
if (value.startsWith("--file")
|
|
1151
|
+
if (value.startsWith("--file")) {
|
|
1152
|
+
scriptUnknown = true;
|
|
1153
|
+
if (script) add("read", script, state);
|
|
1154
|
+
} else if (script?.value) scriptParts.push(script.value);
|
|
1155
|
+
else scriptUnknown = true;
|
|
1117
1156
|
}
|
|
1118
1157
|
continue;
|
|
1119
1158
|
}
|
|
@@ -1128,7 +1167,11 @@ function collectShellFileAccesses(command, context = {}) {
|
|
|
1128
1167
|
if (flag === "e" || flag === "f") {
|
|
1129
1168
|
hasScript = true;
|
|
1130
1169
|
const script = value.slice(j + 1) ? { value: value.slice(j + 1) } : args[++i];
|
|
1131
|
-
if (flag === "f"
|
|
1170
|
+
if (flag === "f") {
|
|
1171
|
+
scriptUnknown = true;
|
|
1172
|
+
if (script) add("read", script, state);
|
|
1173
|
+
} else if (script?.value) scriptParts.push(script.value);
|
|
1174
|
+
else scriptUnknown = true;
|
|
1132
1175
|
break;
|
|
1133
1176
|
}
|
|
1134
1177
|
if (flag === "l") {
|
|
@@ -1138,10 +1181,14 @@ function collectShellFileAccesses(command, context = {}) {
|
|
|
1138
1181
|
}
|
|
1139
1182
|
continue;
|
|
1140
1183
|
}
|
|
1141
|
-
if (!hasScript)
|
|
1142
|
-
|
|
1184
|
+
if (!hasScript) {
|
|
1185
|
+
hasScript = true;
|
|
1186
|
+
scriptParts.push(value);
|
|
1187
|
+
} else files.push(token);
|
|
1143
1188
|
}
|
|
1144
|
-
|
|
1189
|
+
const edits = inplace && !scriptUnknown ? sedSubstitutions(scriptParts.join("\n")) : null;
|
|
1190
|
+
for (const file2 of files)
|
|
1191
|
+
add(inplace ? "write" : "read", file2, state, edits ? { edits } : {});
|
|
1145
1192
|
return;
|
|
1146
1193
|
}
|
|
1147
1194
|
if (FS_READ_TOOLS.has(name) && name !== "dd") {
|
|
@@ -1268,9 +1315,11 @@ function collectShellFileAccesses(command, context = {}) {
|
|
|
1268
1315
|
continue;
|
|
1269
1316
|
const remove = name === "rm" || name === "unlink";
|
|
1270
1317
|
const append = name === "tee" && strings.some((s) => s === "--append" || /^-[^-]*a/.test(s));
|
|
1318
|
+
const teed = name === "tee" && !append ? currentStdin : null;
|
|
1271
1319
|
add(remove ? "remove" : name === "touch" ? "create" : "write", token, state, {
|
|
1272
1320
|
recursive: remove && strings.some((s) => /^-[^-]*[rR]/.test(s) || s === "--recursive"),
|
|
1273
|
-
...append ? { append: true } : {}
|
|
1321
|
+
...append ? { append: true } : {},
|
|
1322
|
+
...teed !== null ? { text: teed } : {}
|
|
1274
1323
|
});
|
|
1275
1324
|
}
|
|
1276
1325
|
return;
|
|
@@ -1592,11 +1641,18 @@ function collectShellFileAccesses(command, context = {}) {
|
|
|
1592
1641
|
if (stmt.Background) state = clone(state);
|
|
1593
1642
|
const headWord = stmt.Cmd && stmt.Cmd.kind === "CallExpr" ? base(resolveWordLiteral(stmt.Cmd.Args?.[0])) : "";
|
|
1594
1643
|
const sends = SENDING_STDIN.has(headWord);
|
|
1644
|
+
let produced;
|
|
1595
1645
|
for (const redir of stmt.Redirs ?? []) {
|
|
1596
1646
|
substitutions(redir.Word, state, depth);
|
|
1597
1647
|
for (const word of wordValues(redir.Word, state)) {
|
|
1598
|
-
if (ops().WRITES.has(redir.Op))
|
|
1599
|
-
|
|
1648
|
+
if (ops().WRITES.has(redir.Op)) {
|
|
1649
|
+
if (ops().APPENDS.has(redir.Op)) add("write", word, state, { append: true });
|
|
1650
|
+
else {
|
|
1651
|
+
const stdout = redir.N == null || redir.N.Value === "1";
|
|
1652
|
+
if (stdout && produced === void 0) produced = producedText(stmt);
|
|
1653
|
+
add("write", word, state, stdout && produced ? { text: produced } : {});
|
|
1654
|
+
}
|
|
1655
|
+
}
|
|
1600
1656
|
if (ops().READS.has(redir.Op)) add("read", word, state, sends ? { upload: true } : {});
|
|
1601
1657
|
if (redir.Op === ops().DUP_OUT && word.value && !/^\d+$/.test(word.value))
|
|
1602
1658
|
add("write", word, state);
|
|
@@ -1608,6 +1664,7 @@ function collectShellFileAccesses(command, context = {}) {
|
|
|
1608
1664
|
stdinScript(stmt, state, depth);
|
|
1609
1665
|
const fedText = stdinText(stmt);
|
|
1610
1666
|
if (fedText !== null) nestedPayload(xargsPayload(stmt, fedText), clone(state), depth);
|
|
1667
|
+
currentStdin = fedText;
|
|
1611
1668
|
switch (cmd.kind) {
|
|
1612
1669
|
case "CallExpr":
|
|
1613
1670
|
call(cmd, state, depth);
|
|
@@ -6641,8 +6698,16 @@ function evaluateGitHooksFileAccess(args, accesses, context, settings, shell) {
|
|
|
6641
6698
|
disarms = true;
|
|
6642
6699
|
how = "removed";
|
|
6643
6700
|
} else if (texts === null) {
|
|
6644
|
-
|
|
6645
|
-
|
|
6701
|
+
if (access.edits) {
|
|
6702
|
+
disarms = access.edits.some(editDisarms);
|
|
6703
|
+
how = "edited to exit";
|
|
6704
|
+
} else if (access.text !== void 0) {
|
|
6705
|
+
disarms = hookTextRunsNothing(access.text);
|
|
6706
|
+
how = "emptied";
|
|
6707
|
+
} else {
|
|
6708
|
+
disarms = true;
|
|
6709
|
+
how = "overwritten";
|
|
6710
|
+
}
|
|
6646
6711
|
} else if (texts.whole.length > 0) {
|
|
6647
6712
|
disarms = texts.whole.some(hookTextRunsNothing);
|
|
6648
6713
|
how = "emptied";
|
package/dist/hook.js
CHANGED
|
@@ -903,12 +903,46 @@ function wordValues(word, state) {
|
|
|
903
903
|
if (!dynamic) return out.map(asWord);
|
|
904
904
|
return out.filter((piece) => piece.value !== "").map((piece) => ({ value: piece.value, pattern: piece.pattern + "*", dynamic: true }));
|
|
905
905
|
}
|
|
906
|
+
function sedSubstitutions(script) {
|
|
907
|
+
const out = [];
|
|
908
|
+
for (const raw of script.split(/\r?\n|;/)) {
|
|
909
|
+
const cmd = raw.trim();
|
|
910
|
+
if (cmd === "") continue;
|
|
911
|
+
const m = /^(?:(?:\d+|\$|\/(?:\\.|[^\\/])*\/)(?:,(?:\d+|\$|\/(?:\\.|[^\\/])*\/))?)?s(.)/.exec(
|
|
912
|
+
cmd
|
|
913
|
+
);
|
|
914
|
+
if (!m) return null;
|
|
915
|
+
const delimiter = m[1];
|
|
916
|
+
if (delimiter === "\\") return null;
|
|
917
|
+
const parts = [];
|
|
918
|
+
let cur = "";
|
|
919
|
+
let i = m[0].length;
|
|
920
|
+
for (; i < cmd.length && parts.length < 2; i++) {
|
|
921
|
+
const ch = cmd[i];
|
|
922
|
+
if (ch === "\\" && i + 1 < cmd.length) {
|
|
923
|
+
cur += ch + cmd[++i];
|
|
924
|
+
continue;
|
|
925
|
+
}
|
|
926
|
+
if (ch === delimiter) {
|
|
927
|
+
parts.push(cur);
|
|
928
|
+
cur = "";
|
|
929
|
+
continue;
|
|
930
|
+
}
|
|
931
|
+
cur += ch;
|
|
932
|
+
}
|
|
933
|
+
if (parts.length < 2) return null;
|
|
934
|
+
if (!/^[gpiImM0-9]*$/.test(cmd.slice(i))) return null;
|
|
935
|
+
out.push(parts[1].replace(/\\(.)/g, "$1"));
|
|
936
|
+
}
|
|
937
|
+
return out.length > 0 ? out : null;
|
|
938
|
+
}
|
|
906
939
|
function collectShellFileAccesses(command, context = {}) {
|
|
907
940
|
const out = [];
|
|
908
941
|
let payloads = 256;
|
|
909
942
|
const functions = /* @__PURE__ */ new Map();
|
|
910
943
|
const seenCalls = /* @__PURE__ */ new Set();
|
|
911
944
|
const pipedStdin = /* @__PURE__ */ new WeakMap();
|
|
945
|
+
let currentStdin = null;
|
|
912
946
|
let callWalks2 = MAX_CALL_WALKS;
|
|
913
947
|
const initial = {
|
|
914
948
|
cwd: [context.cwd ?? ""],
|
|
@@ -1003,8 +1037,9 @@ function collectShellFileAccesses(command, context = {}) {
|
|
|
1003
1037
|
}
|
|
1004
1038
|
const locate = (p) => tokens.find((w) => w?.value === p) ?? { value: p };
|
|
1005
1039
|
if (name === "sed") {
|
|
1006
|
-
let inplace = false, hasScript = false, ended = false;
|
|
1040
|
+
let inplace = false, hasScript = false, ended = false, scriptUnknown = false;
|
|
1007
1041
|
const files = [];
|
|
1042
|
+
const scriptParts = [];
|
|
1008
1043
|
for (let i = 0; i < args.length; i++) {
|
|
1009
1044
|
const token = args[i];
|
|
1010
1045
|
if (!token) {
|
|
@@ -1022,7 +1057,11 @@ function collectShellFileAccesses(command, context = {}) {
|
|
|
1022
1057
|
hasScript = true;
|
|
1023
1058
|
const eq = value.indexOf("=");
|
|
1024
1059
|
const script = eq < 0 ? args[++i] : { value: value.slice(eq + 1) };
|
|
1025
|
-
if (value.startsWith("--file")
|
|
1060
|
+
if (value.startsWith("--file")) {
|
|
1061
|
+
scriptUnknown = true;
|
|
1062
|
+
if (script) add("read", script, state);
|
|
1063
|
+
} else if (script?.value) scriptParts.push(script.value);
|
|
1064
|
+
else scriptUnknown = true;
|
|
1026
1065
|
}
|
|
1027
1066
|
continue;
|
|
1028
1067
|
}
|
|
@@ -1037,7 +1076,11 @@ function collectShellFileAccesses(command, context = {}) {
|
|
|
1037
1076
|
if (flag === "e" || flag === "f") {
|
|
1038
1077
|
hasScript = true;
|
|
1039
1078
|
const script = value.slice(j + 1) ? { value: value.slice(j + 1) } : args[++i];
|
|
1040
|
-
if (flag === "f"
|
|
1079
|
+
if (flag === "f") {
|
|
1080
|
+
scriptUnknown = true;
|
|
1081
|
+
if (script) add("read", script, state);
|
|
1082
|
+
} else if (script?.value) scriptParts.push(script.value);
|
|
1083
|
+
else scriptUnknown = true;
|
|
1041
1084
|
break;
|
|
1042
1085
|
}
|
|
1043
1086
|
if (flag === "l") {
|
|
@@ -1047,10 +1090,14 @@ function collectShellFileAccesses(command, context = {}) {
|
|
|
1047
1090
|
}
|
|
1048
1091
|
continue;
|
|
1049
1092
|
}
|
|
1050
|
-
if (!hasScript)
|
|
1051
|
-
|
|
1093
|
+
if (!hasScript) {
|
|
1094
|
+
hasScript = true;
|
|
1095
|
+
scriptParts.push(value);
|
|
1096
|
+
} else files.push(token);
|
|
1052
1097
|
}
|
|
1053
|
-
|
|
1098
|
+
const edits = inplace && !scriptUnknown ? sedSubstitutions(scriptParts.join("\n")) : null;
|
|
1099
|
+
for (const file2 of files)
|
|
1100
|
+
add(inplace ? "write" : "read", file2, state, edits ? { edits } : {});
|
|
1054
1101
|
return;
|
|
1055
1102
|
}
|
|
1056
1103
|
if (FS_READ_TOOLS.has(name) && name !== "dd") {
|
|
@@ -1177,9 +1224,11 @@ function collectShellFileAccesses(command, context = {}) {
|
|
|
1177
1224
|
continue;
|
|
1178
1225
|
const remove = name === "rm" || name === "unlink";
|
|
1179
1226
|
const append = name === "tee" && strings.some((s) => s === "--append" || /^-[^-]*a/.test(s));
|
|
1227
|
+
const teed = name === "tee" && !append ? currentStdin : null;
|
|
1180
1228
|
add(remove ? "remove" : name === "touch" ? "create" : "write", token, state, {
|
|
1181
1229
|
recursive: remove && strings.some((s) => /^-[^-]*[rR]/.test(s) || s === "--recursive"),
|
|
1182
|
-
...append ? { append: true } : {}
|
|
1230
|
+
...append ? { append: true } : {},
|
|
1231
|
+
...teed !== null ? { text: teed } : {}
|
|
1183
1232
|
});
|
|
1184
1233
|
}
|
|
1185
1234
|
return;
|
|
@@ -1501,11 +1550,18 @@ function collectShellFileAccesses(command, context = {}) {
|
|
|
1501
1550
|
if (stmt.Background) state = clone(state);
|
|
1502
1551
|
const headWord = stmt.Cmd && stmt.Cmd.kind === "CallExpr" ? base(resolveWordLiteral(stmt.Cmd.Args?.[0])) : "";
|
|
1503
1552
|
const sends = SENDING_STDIN.has(headWord);
|
|
1553
|
+
let produced;
|
|
1504
1554
|
for (const redir of stmt.Redirs ?? []) {
|
|
1505
1555
|
substitutions(redir.Word, state, depth);
|
|
1506
1556
|
for (const word of wordValues(redir.Word, state)) {
|
|
1507
|
-
if (ops().WRITES.has(redir.Op))
|
|
1508
|
-
|
|
1557
|
+
if (ops().WRITES.has(redir.Op)) {
|
|
1558
|
+
if (ops().APPENDS.has(redir.Op)) add("write", word, state, { append: true });
|
|
1559
|
+
else {
|
|
1560
|
+
const stdout = redir.N == null || redir.N.Value === "1";
|
|
1561
|
+
if (stdout && produced === void 0) produced = producedText(stmt);
|
|
1562
|
+
add("write", word, state, stdout && produced ? { text: produced } : {});
|
|
1563
|
+
}
|
|
1564
|
+
}
|
|
1509
1565
|
if (ops().READS.has(redir.Op)) add("read", word, state, sends ? { upload: true } : {});
|
|
1510
1566
|
if (redir.Op === ops().DUP_OUT && word.value && !/^\d+$/.test(word.value))
|
|
1511
1567
|
add("write", word, state);
|
|
@@ -1517,6 +1573,7 @@ function collectShellFileAccesses(command, context = {}) {
|
|
|
1517
1573
|
stdinScript(stmt, state, depth);
|
|
1518
1574
|
const fedText = stdinText(stmt);
|
|
1519
1575
|
if (fedText !== null) nestedPayload(xargsPayload(stmt, fedText), clone(state), depth);
|
|
1576
|
+
currentStdin = fedText;
|
|
1520
1577
|
switch (cmd.kind) {
|
|
1521
1578
|
case "CallExpr":
|
|
1522
1579
|
call(cmd, state, depth);
|
|
@@ -6644,8 +6701,16 @@ function evaluateGitHooksFileAccess(args, accesses, context, settings, shell) {
|
|
|
6644
6701
|
disarms = true;
|
|
6645
6702
|
how = "removed";
|
|
6646
6703
|
} else if (texts === null) {
|
|
6647
|
-
|
|
6648
|
-
|
|
6704
|
+
if (access.edits) {
|
|
6705
|
+
disarms = access.edits.some(editDisarms);
|
|
6706
|
+
how = "edited to exit";
|
|
6707
|
+
} else if (access.text !== void 0) {
|
|
6708
|
+
disarms = hookTextRunsNothing(access.text);
|
|
6709
|
+
how = "emptied";
|
|
6710
|
+
} else {
|
|
6711
|
+
disarms = true;
|
|
6712
|
+
how = "overwritten";
|
|
6713
|
+
}
|
|
6649
6714
|
} else if (texts.whole.length > 0) {
|
|
6650
6715
|
disarms = texts.whole.some(hookTextRunsNothing);
|
|
6651
6716
|
how = "emptied";
|
package/dist/index.js
CHANGED
|
@@ -957,12 +957,46 @@ function wordValues(word, state) {
|
|
|
957
957
|
if (!dynamic) return out.map(asWord);
|
|
958
958
|
return out.filter((piece) => piece.value !== "").map((piece) => ({ value: piece.value, pattern: piece.pattern + "*", dynamic: true }));
|
|
959
959
|
}
|
|
960
|
+
function sedSubstitutions(script) {
|
|
961
|
+
const out = [];
|
|
962
|
+
for (const raw of script.split(/\r?\n|;/)) {
|
|
963
|
+
const cmd = raw.trim();
|
|
964
|
+
if (cmd === "") continue;
|
|
965
|
+
const m = /^(?:(?:\d+|\$|\/(?:\\.|[^\\/])*\/)(?:,(?:\d+|\$|\/(?:\\.|[^\\/])*\/))?)?s(.)/.exec(
|
|
966
|
+
cmd
|
|
967
|
+
);
|
|
968
|
+
if (!m) return null;
|
|
969
|
+
const delimiter = m[1];
|
|
970
|
+
if (delimiter === "\\") return null;
|
|
971
|
+
const parts = [];
|
|
972
|
+
let cur = "";
|
|
973
|
+
let i = m[0].length;
|
|
974
|
+
for (; i < cmd.length && parts.length < 2; i++) {
|
|
975
|
+
const ch = cmd[i];
|
|
976
|
+
if (ch === "\\" && i + 1 < cmd.length) {
|
|
977
|
+
cur += ch + cmd[++i];
|
|
978
|
+
continue;
|
|
979
|
+
}
|
|
980
|
+
if (ch === delimiter) {
|
|
981
|
+
parts.push(cur);
|
|
982
|
+
cur = "";
|
|
983
|
+
continue;
|
|
984
|
+
}
|
|
985
|
+
cur += ch;
|
|
986
|
+
}
|
|
987
|
+
if (parts.length < 2) return null;
|
|
988
|
+
if (!/^[gpiImM0-9]*$/.test(cmd.slice(i))) return null;
|
|
989
|
+
out.push(parts[1].replace(/\\(.)/g, "$1"));
|
|
990
|
+
}
|
|
991
|
+
return out.length > 0 ? out : null;
|
|
992
|
+
}
|
|
960
993
|
function collectShellFileAccesses(command, context = {}) {
|
|
961
994
|
const out = [];
|
|
962
995
|
let payloads = 256;
|
|
963
996
|
const functions = /* @__PURE__ */ new Map();
|
|
964
997
|
const seenCalls = /* @__PURE__ */ new Set();
|
|
965
998
|
const pipedStdin = /* @__PURE__ */ new WeakMap();
|
|
999
|
+
let currentStdin = null;
|
|
966
1000
|
let callWalks2 = MAX_CALL_WALKS;
|
|
967
1001
|
const initial = {
|
|
968
1002
|
cwd: [context.cwd ?? ""],
|
|
@@ -1057,8 +1091,9 @@ function collectShellFileAccesses(command, context = {}) {
|
|
|
1057
1091
|
}
|
|
1058
1092
|
const locate = (p) => tokens.find((w) => w?.value === p) ?? { value: p };
|
|
1059
1093
|
if (name === "sed") {
|
|
1060
|
-
let inplace = false, hasScript = false, ended = false;
|
|
1094
|
+
let inplace = false, hasScript = false, ended = false, scriptUnknown = false;
|
|
1061
1095
|
const files = [];
|
|
1096
|
+
const scriptParts = [];
|
|
1062
1097
|
for (let i = 0; i < args.length; i++) {
|
|
1063
1098
|
const token = args[i];
|
|
1064
1099
|
if (!token) {
|
|
@@ -1076,7 +1111,11 @@ function collectShellFileAccesses(command, context = {}) {
|
|
|
1076
1111
|
hasScript = true;
|
|
1077
1112
|
const eq = value.indexOf("=");
|
|
1078
1113
|
const script = eq < 0 ? args[++i] : { value: value.slice(eq + 1) };
|
|
1079
|
-
if (value.startsWith("--file")
|
|
1114
|
+
if (value.startsWith("--file")) {
|
|
1115
|
+
scriptUnknown = true;
|
|
1116
|
+
if (script) add("read", script, state);
|
|
1117
|
+
} else if (script?.value) scriptParts.push(script.value);
|
|
1118
|
+
else scriptUnknown = true;
|
|
1080
1119
|
}
|
|
1081
1120
|
continue;
|
|
1082
1121
|
}
|
|
@@ -1091,7 +1130,11 @@ function collectShellFileAccesses(command, context = {}) {
|
|
|
1091
1130
|
if (flag === "e" || flag === "f") {
|
|
1092
1131
|
hasScript = true;
|
|
1093
1132
|
const script = value.slice(j + 1) ? { value: value.slice(j + 1) } : args[++i];
|
|
1094
|
-
if (flag === "f"
|
|
1133
|
+
if (flag === "f") {
|
|
1134
|
+
scriptUnknown = true;
|
|
1135
|
+
if (script) add("read", script, state);
|
|
1136
|
+
} else if (script?.value) scriptParts.push(script.value);
|
|
1137
|
+
else scriptUnknown = true;
|
|
1095
1138
|
break;
|
|
1096
1139
|
}
|
|
1097
1140
|
if (flag === "l") {
|
|
@@ -1101,10 +1144,14 @@ function collectShellFileAccesses(command, context = {}) {
|
|
|
1101
1144
|
}
|
|
1102
1145
|
continue;
|
|
1103
1146
|
}
|
|
1104
|
-
if (!hasScript)
|
|
1105
|
-
|
|
1147
|
+
if (!hasScript) {
|
|
1148
|
+
hasScript = true;
|
|
1149
|
+
scriptParts.push(value);
|
|
1150
|
+
} else files.push(token);
|
|
1106
1151
|
}
|
|
1107
|
-
|
|
1152
|
+
const edits = inplace && !scriptUnknown ? sedSubstitutions(scriptParts.join("\n")) : null;
|
|
1153
|
+
for (const file2 of files)
|
|
1154
|
+
add(inplace ? "write" : "read", file2, state, edits ? { edits } : {});
|
|
1108
1155
|
return;
|
|
1109
1156
|
}
|
|
1110
1157
|
if (FS_READ_TOOLS.has(name) && name !== "dd") {
|
|
@@ -1231,9 +1278,11 @@ function collectShellFileAccesses(command, context = {}) {
|
|
|
1231
1278
|
continue;
|
|
1232
1279
|
const remove = name === "rm" || name === "unlink";
|
|
1233
1280
|
const append = name === "tee" && strings.some((s) => s === "--append" || /^-[^-]*a/.test(s));
|
|
1281
|
+
const teed = name === "tee" && !append ? currentStdin : null;
|
|
1234
1282
|
add(remove ? "remove" : name === "touch" ? "create" : "write", token, state, {
|
|
1235
1283
|
recursive: remove && strings.some((s) => /^-[^-]*[rR]/.test(s) || s === "--recursive"),
|
|
1236
|
-
...append ? { append: true } : {}
|
|
1284
|
+
...append ? { append: true } : {},
|
|
1285
|
+
...teed !== null ? { text: teed } : {}
|
|
1237
1286
|
});
|
|
1238
1287
|
}
|
|
1239
1288
|
return;
|
|
@@ -1555,11 +1604,18 @@ function collectShellFileAccesses(command, context = {}) {
|
|
|
1555
1604
|
if (stmt.Background) state = clone(state);
|
|
1556
1605
|
const headWord = stmt.Cmd && stmt.Cmd.kind === "CallExpr" ? base(resolveWordLiteral(stmt.Cmd.Args?.[0])) : "";
|
|
1557
1606
|
const sends = SENDING_STDIN.has(headWord);
|
|
1607
|
+
let produced;
|
|
1558
1608
|
for (const redir of stmt.Redirs ?? []) {
|
|
1559
1609
|
substitutions(redir.Word, state, depth);
|
|
1560
1610
|
for (const word of wordValues(redir.Word, state)) {
|
|
1561
|
-
if (ops().WRITES.has(redir.Op))
|
|
1562
|
-
|
|
1611
|
+
if (ops().WRITES.has(redir.Op)) {
|
|
1612
|
+
if (ops().APPENDS.has(redir.Op)) add("write", word, state, { append: true });
|
|
1613
|
+
else {
|
|
1614
|
+
const stdout = redir.N == null || redir.N.Value === "1";
|
|
1615
|
+
if (stdout && produced === void 0) produced = producedText(stmt);
|
|
1616
|
+
add("write", word, state, stdout && produced ? { text: produced } : {});
|
|
1617
|
+
}
|
|
1618
|
+
}
|
|
1563
1619
|
if (ops().READS.has(redir.Op)) add("read", word, state, sends ? { upload: true } : {});
|
|
1564
1620
|
if (redir.Op === ops().DUP_OUT && word.value && !/^\d+$/.test(word.value))
|
|
1565
1621
|
add("write", word, state);
|
|
@@ -1571,6 +1627,7 @@ function collectShellFileAccesses(command, context = {}) {
|
|
|
1571
1627
|
stdinScript(stmt, state, depth);
|
|
1572
1628
|
const fedText = stdinText(stmt);
|
|
1573
1629
|
if (fedText !== null) nestedPayload(xargsPayload(stmt, fedText), clone(state), depth);
|
|
1630
|
+
currentStdin = fedText;
|
|
1574
1631
|
switch (cmd.kind) {
|
|
1575
1632
|
case "CallExpr":
|
|
1576
1633
|
call(cmd, state, depth);
|
|
@@ -6572,8 +6629,16 @@ function evaluateGitHooksFileAccess(args, accesses, context, settings, shell) {
|
|
|
6572
6629
|
disarms = true;
|
|
6573
6630
|
how = "removed";
|
|
6574
6631
|
} else if (texts === null) {
|
|
6575
|
-
|
|
6576
|
-
|
|
6632
|
+
if (access.edits) {
|
|
6633
|
+
disarms = access.edits.some(editDisarms);
|
|
6634
|
+
how = "edited to exit";
|
|
6635
|
+
} else if (access.text !== void 0) {
|
|
6636
|
+
disarms = hookTextRunsNothing(access.text);
|
|
6637
|
+
how = "emptied";
|
|
6638
|
+
} else {
|
|
6639
|
+
disarms = true;
|
|
6640
|
+
how = "overwritten";
|
|
6641
|
+
}
|
|
6577
6642
|
} else if (texts.whole.length > 0) {
|
|
6578
6643
|
disarms = texts.whole.some(hookTextRunsNothing);
|
|
6579
6644
|
how = "emptied";
|
package/dist/index.mjs
CHANGED
|
@@ -944,12 +944,46 @@ function wordValues(word, state) {
|
|
|
944
944
|
if (!dynamic) return out.map(asWord);
|
|
945
945
|
return out.filter((piece) => piece.value !== "").map((piece) => ({ value: piece.value, pattern: piece.pattern + "*", dynamic: true }));
|
|
946
946
|
}
|
|
947
|
+
function sedSubstitutions(script) {
|
|
948
|
+
const out = [];
|
|
949
|
+
for (const raw of script.split(/\r?\n|;/)) {
|
|
950
|
+
const cmd = raw.trim();
|
|
951
|
+
if (cmd === "") continue;
|
|
952
|
+
const m = /^(?:(?:\d+|\$|\/(?:\\.|[^\\/])*\/)(?:,(?:\d+|\$|\/(?:\\.|[^\\/])*\/))?)?s(.)/.exec(
|
|
953
|
+
cmd
|
|
954
|
+
);
|
|
955
|
+
if (!m) return null;
|
|
956
|
+
const delimiter = m[1];
|
|
957
|
+
if (delimiter === "\\") return null;
|
|
958
|
+
const parts = [];
|
|
959
|
+
let cur = "";
|
|
960
|
+
let i = m[0].length;
|
|
961
|
+
for (; i < cmd.length && parts.length < 2; i++) {
|
|
962
|
+
const ch = cmd[i];
|
|
963
|
+
if (ch === "\\" && i + 1 < cmd.length) {
|
|
964
|
+
cur += ch + cmd[++i];
|
|
965
|
+
continue;
|
|
966
|
+
}
|
|
967
|
+
if (ch === delimiter) {
|
|
968
|
+
parts.push(cur);
|
|
969
|
+
cur = "";
|
|
970
|
+
continue;
|
|
971
|
+
}
|
|
972
|
+
cur += ch;
|
|
973
|
+
}
|
|
974
|
+
if (parts.length < 2) return null;
|
|
975
|
+
if (!/^[gpiImM0-9]*$/.test(cmd.slice(i))) return null;
|
|
976
|
+
out.push(parts[1].replace(/\\(.)/g, "$1"));
|
|
977
|
+
}
|
|
978
|
+
return out.length > 0 ? out : null;
|
|
979
|
+
}
|
|
947
980
|
function collectShellFileAccesses(command, context = {}) {
|
|
948
981
|
const out = [];
|
|
949
982
|
let payloads = 256;
|
|
950
983
|
const functions = /* @__PURE__ */ new Map();
|
|
951
984
|
const seenCalls = /* @__PURE__ */ new Set();
|
|
952
985
|
const pipedStdin = /* @__PURE__ */ new WeakMap();
|
|
986
|
+
let currentStdin = null;
|
|
953
987
|
let callWalks2 = MAX_CALL_WALKS;
|
|
954
988
|
const initial = {
|
|
955
989
|
cwd: [context.cwd ?? ""],
|
|
@@ -1044,8 +1078,9 @@ function collectShellFileAccesses(command, context = {}) {
|
|
|
1044
1078
|
}
|
|
1045
1079
|
const locate = (p) => tokens.find((w) => w?.value === p) ?? { value: p };
|
|
1046
1080
|
if (name === "sed") {
|
|
1047
|
-
let inplace = false, hasScript = false, ended = false;
|
|
1081
|
+
let inplace = false, hasScript = false, ended = false, scriptUnknown = false;
|
|
1048
1082
|
const files = [];
|
|
1083
|
+
const scriptParts = [];
|
|
1049
1084
|
for (let i = 0; i < args.length; i++) {
|
|
1050
1085
|
const token = args[i];
|
|
1051
1086
|
if (!token) {
|
|
@@ -1063,7 +1098,11 @@ function collectShellFileAccesses(command, context = {}) {
|
|
|
1063
1098
|
hasScript = true;
|
|
1064
1099
|
const eq = value.indexOf("=");
|
|
1065
1100
|
const script = eq < 0 ? args[++i] : { value: value.slice(eq + 1) };
|
|
1066
|
-
if (value.startsWith("--file")
|
|
1101
|
+
if (value.startsWith("--file")) {
|
|
1102
|
+
scriptUnknown = true;
|
|
1103
|
+
if (script) add("read", script, state);
|
|
1104
|
+
} else if (script?.value) scriptParts.push(script.value);
|
|
1105
|
+
else scriptUnknown = true;
|
|
1067
1106
|
}
|
|
1068
1107
|
continue;
|
|
1069
1108
|
}
|
|
@@ -1078,7 +1117,11 @@ function collectShellFileAccesses(command, context = {}) {
|
|
|
1078
1117
|
if (flag === "e" || flag === "f") {
|
|
1079
1118
|
hasScript = true;
|
|
1080
1119
|
const script = value.slice(j + 1) ? { value: value.slice(j + 1) } : args[++i];
|
|
1081
|
-
if (flag === "f"
|
|
1120
|
+
if (flag === "f") {
|
|
1121
|
+
scriptUnknown = true;
|
|
1122
|
+
if (script) add("read", script, state);
|
|
1123
|
+
} else if (script?.value) scriptParts.push(script.value);
|
|
1124
|
+
else scriptUnknown = true;
|
|
1082
1125
|
break;
|
|
1083
1126
|
}
|
|
1084
1127
|
if (flag === "l") {
|
|
@@ -1088,10 +1131,14 @@ function collectShellFileAccesses(command, context = {}) {
|
|
|
1088
1131
|
}
|
|
1089
1132
|
continue;
|
|
1090
1133
|
}
|
|
1091
|
-
if (!hasScript)
|
|
1092
|
-
|
|
1134
|
+
if (!hasScript) {
|
|
1135
|
+
hasScript = true;
|
|
1136
|
+
scriptParts.push(value);
|
|
1137
|
+
} else files.push(token);
|
|
1093
1138
|
}
|
|
1094
|
-
|
|
1139
|
+
const edits = inplace && !scriptUnknown ? sedSubstitutions(scriptParts.join("\n")) : null;
|
|
1140
|
+
for (const file2 of files)
|
|
1141
|
+
add(inplace ? "write" : "read", file2, state, edits ? { edits } : {});
|
|
1095
1142
|
return;
|
|
1096
1143
|
}
|
|
1097
1144
|
if (FS_READ_TOOLS.has(name) && name !== "dd") {
|
|
@@ -1218,9 +1265,11 @@ function collectShellFileAccesses(command, context = {}) {
|
|
|
1218
1265
|
continue;
|
|
1219
1266
|
const remove = name === "rm" || name === "unlink";
|
|
1220
1267
|
const append = name === "tee" && strings.some((s) => s === "--append" || /^-[^-]*a/.test(s));
|
|
1268
|
+
const teed = name === "tee" && !append ? currentStdin : null;
|
|
1221
1269
|
add(remove ? "remove" : name === "touch" ? "create" : "write", token, state, {
|
|
1222
1270
|
recursive: remove && strings.some((s) => /^-[^-]*[rR]/.test(s) || s === "--recursive"),
|
|
1223
|
-
...append ? { append: true } : {}
|
|
1271
|
+
...append ? { append: true } : {},
|
|
1272
|
+
...teed !== null ? { text: teed } : {}
|
|
1224
1273
|
});
|
|
1225
1274
|
}
|
|
1226
1275
|
return;
|
|
@@ -1542,11 +1591,18 @@ function collectShellFileAccesses(command, context = {}) {
|
|
|
1542
1591
|
if (stmt.Background) state = clone(state);
|
|
1543
1592
|
const headWord = stmt.Cmd && stmt.Cmd.kind === "CallExpr" ? base(resolveWordLiteral(stmt.Cmd.Args?.[0])) : "";
|
|
1544
1593
|
const sends = SENDING_STDIN.has(headWord);
|
|
1594
|
+
let produced;
|
|
1545
1595
|
for (const redir of stmt.Redirs ?? []) {
|
|
1546
1596
|
substitutions(redir.Word, state, depth);
|
|
1547
1597
|
for (const word of wordValues(redir.Word, state)) {
|
|
1548
|
-
if (ops().WRITES.has(redir.Op))
|
|
1549
|
-
|
|
1598
|
+
if (ops().WRITES.has(redir.Op)) {
|
|
1599
|
+
if (ops().APPENDS.has(redir.Op)) add("write", word, state, { append: true });
|
|
1600
|
+
else {
|
|
1601
|
+
const stdout = redir.N == null || redir.N.Value === "1";
|
|
1602
|
+
if (stdout && produced === void 0) produced = producedText(stmt);
|
|
1603
|
+
add("write", word, state, stdout && produced ? { text: produced } : {});
|
|
1604
|
+
}
|
|
1605
|
+
}
|
|
1550
1606
|
if (ops().READS.has(redir.Op)) add("read", word, state, sends ? { upload: true } : {});
|
|
1551
1607
|
if (redir.Op === ops().DUP_OUT && word.value && !/^\d+$/.test(word.value))
|
|
1552
1608
|
add("write", word, state);
|
|
@@ -1558,6 +1614,7 @@ function collectShellFileAccesses(command, context = {}) {
|
|
|
1558
1614
|
stdinScript(stmt, state, depth);
|
|
1559
1615
|
const fedText = stdinText(stmt);
|
|
1560
1616
|
if (fedText !== null) nestedPayload(xargsPayload(stmt, fedText), clone(state), depth);
|
|
1617
|
+
currentStdin = fedText;
|
|
1561
1618
|
switch (cmd.kind) {
|
|
1562
1619
|
case "CallExpr":
|
|
1563
1620
|
call(cmd, state, depth);
|
|
@@ -6559,8 +6616,16 @@ function evaluateGitHooksFileAccess(args, accesses, context, settings, shell) {
|
|
|
6559
6616
|
disarms = true;
|
|
6560
6617
|
how = "removed";
|
|
6561
6618
|
} else if (texts === null) {
|
|
6562
|
-
|
|
6563
|
-
|
|
6619
|
+
if (access.edits) {
|
|
6620
|
+
disarms = access.edits.some(editDisarms);
|
|
6621
|
+
how = "edited to exit";
|
|
6622
|
+
} else if (access.text !== void 0) {
|
|
6623
|
+
disarms = hookTextRunsNothing(access.text);
|
|
6624
|
+
how = "emptied";
|
|
6625
|
+
} else {
|
|
6626
|
+
disarms = true;
|
|
6627
|
+
how = "overwritten";
|
|
6628
|
+
}
|
|
6564
6629
|
} else if (texts.whole.length > 0) {
|
|
6565
6630
|
disarms = texts.whole.some(hookTextRunsNothing);
|
|
6566
6631
|
how = "emptied";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@node9/proxy",
|
|
3
|
-
"version": "2.54.
|
|
3
|
+
"version": "2.54.1",
|
|
4
4
|
"description": "Access control for AI agents. Set what Claude Code, Codex, Gemini, Cursor and any MCP server are allowed to do, review risky actions before they run, and keep every action on the record.",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|