@node9/proxy 2.50.0 → 2.51.0
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 +1014 -373
- package/dist/dashboard.mjs +577 -29
- package/dist/hook.js +575 -28
- package/dist/index.js +776 -231
- package/dist/index.mjs +776 -231
- package/dist/scan-ink.mjs +2 -1
- package/package.json +1 -1
package/dist/hook.js
CHANGED
|
@@ -2050,9 +2050,15 @@ function detectDangerousShellExec(command) {
|
|
|
2050
2050
|
if (f === PARSE_FAIL) return null;
|
|
2051
2051
|
let result = null;
|
|
2052
2052
|
const assigned = assignedNames(f);
|
|
2053
|
-
|
|
2053
|
+
const known = plainlyNamedPrograms(f);
|
|
2054
|
+
const calledByName = literallyCalledFunctions(f);
|
|
2055
|
+
const bodies = [];
|
|
2056
|
+
const inBody = (pos) => bodies.some(([a, b]) => pos >= a && pos < b);
|
|
2057
|
+
walkWithCalls(f, (node) => {
|
|
2054
2058
|
if (!node || result === "block") return false;
|
|
2055
2059
|
const n = node;
|
|
2060
|
+
if (n.kind === "FuncDecl" && n.Body && callDepth === 0 && calledByName.has(n.Name?.Value))
|
|
2061
|
+
bodies.push([n.Body.pos, n.Body.end]);
|
|
2056
2062
|
if (n.kind === "BinaryCmd" && n.Y && !listOps().has(n.Op)) {
|
|
2057
2063
|
const call = n.Y.Cmd;
|
|
2058
2064
|
if (call && call.kind === "CallExpr") {
|
|
@@ -2076,7 +2082,8 @@ function detectDangerousShellExec(command) {
|
|
|
2076
2082
|
);
|
|
2077
2083
|
const head = unwrapCommandHead(headWords, false, true);
|
|
2078
2084
|
const lookup = headWords[0]?.toLowerCase() === "command" && headWords.slice(1).some((w) => w === "-v" || w === "-V");
|
|
2079
|
-
|
|
2085
|
+
const unboundBody = callDepth === 0 && inBody(n.pos ?? -1);
|
|
2086
|
+
if (!lookup && !unboundBody && (opaqueExecutable(args[0], assigned, known) || opaqueExecutable(args[head], assigned, known)))
|
|
2080
2087
|
result = "review";
|
|
2081
2088
|
const firstParts = args[0].Parts || [];
|
|
2082
2089
|
if (firstParts.length !== 1 || firstParts[0].kind !== "Lit") return true;
|
|
@@ -2136,11 +2143,105 @@ function assignedNames(f) {
|
|
|
2136
2143
|
});
|
|
2137
2144
|
return names;
|
|
2138
2145
|
}
|
|
2139
|
-
function
|
|
2146
|
+
function literallyCalledFunctions(f) {
|
|
2147
|
+
const declared = /* @__PURE__ */ new Set();
|
|
2148
|
+
const called = /* @__PURE__ */ new Set();
|
|
2149
|
+
walk(f, (node) => {
|
|
2150
|
+
if (!node) return false;
|
|
2151
|
+
if (node.kind === "FuncDecl" && node.Name?.Value) declared.add(node.Name.Value);
|
|
2152
|
+
if (node.kind === "CallExpr") {
|
|
2153
|
+
const head = resolveWordLiteral(node.Args?.[0]);
|
|
2154
|
+
if (head) called.add(head);
|
|
2155
|
+
}
|
|
2156
|
+
return true;
|
|
2157
|
+
});
|
|
2158
|
+
return new Set([...declared].filter((name) => called.has(name)));
|
|
2159
|
+
}
|
|
2160
|
+
function plainlyNamedPrograms(f) {
|
|
2161
|
+
const values = /* @__PURE__ */ new Map();
|
|
2162
|
+
const arrays = /* @__PURE__ */ new Set();
|
|
2163
|
+
const give = (name, value) => {
|
|
2164
|
+
if (value === null || !PLAIN_PROGRAM_NAME.test(value)) {
|
|
2165
|
+
values.set(name, null);
|
|
2166
|
+
return;
|
|
2167
|
+
}
|
|
2168
|
+
const cur = values.get(name);
|
|
2169
|
+
if (cur === null) return;
|
|
2170
|
+
if (cur === void 0) values.set(name, /* @__PURE__ */ new Set([value]));
|
|
2171
|
+
else cur.add(value);
|
|
2172
|
+
};
|
|
2173
|
+
const literalOnly = (w) => {
|
|
2174
|
+
const parts = w?.Parts ?? [];
|
|
2175
|
+
if (parts.length !== 1) return null;
|
|
2176
|
+
const p = parts[0];
|
|
2177
|
+
if (p.kind === "Lit") return p.Value ?? null;
|
|
2178
|
+
if (p.kind === "ParamExp" && expansionName(p) === "FUNCNAME") return "FUNCNAME";
|
|
2179
|
+
if (p.kind === "SglQuoted" && !p.Dollar) return p.Value ?? null;
|
|
2180
|
+
if (p.kind === "DblQuoted") {
|
|
2181
|
+
const inner = p.Parts ?? [];
|
|
2182
|
+
return inner.length === 1 && inner[0].kind === "Lit" ? inner[0].Value ?? null : null;
|
|
2183
|
+
}
|
|
2184
|
+
return null;
|
|
2185
|
+
};
|
|
2186
|
+
let ifsTouched = false;
|
|
2187
|
+
walk(f, (node) => {
|
|
2188
|
+
if (!node) return false;
|
|
2189
|
+
const kind = node.kind;
|
|
2190
|
+
if (kind === "FuncDecl" && node.Name?.Value) give(node.Name.Value, node.Name.Value);
|
|
2191
|
+
if (kind === "Assign" && node.Name?.Value) {
|
|
2192
|
+
const name = node.Name.Value;
|
|
2193
|
+
if (name === "IFS") ifsTouched = true;
|
|
2194
|
+
if (node.Append) values.set(name, null);
|
|
2195
|
+
else if (node.Array) {
|
|
2196
|
+
arrays.add(name);
|
|
2197
|
+
for (const el of node.Array.Elems ?? []) give(name, literalOnly(el.Value));
|
|
2198
|
+
} else if (node.Index) {
|
|
2199
|
+
arrays.add(name);
|
|
2200
|
+
give(name, node.Value ? literalOnly(node.Value) : null);
|
|
2201
|
+
} else give(name, node.Value ? literalOnly(node.Value) : null);
|
|
2202
|
+
}
|
|
2203
|
+
if (kind === "ForClause" && node.Loop?.Name?.Value) values.set(node.Loop.Name.Value, null);
|
|
2204
|
+
if (kind === "CallExpr") {
|
|
2205
|
+
const words = (node.Args ?? []).map((a) => resolveWordLiteral(a));
|
|
2206
|
+
if (VARIABLE_READERS.has(words[0] ?? "")) {
|
|
2207
|
+
for (const w of words.slice(1)) if (w && /^[A-Za-z_]\w*$/.test(w)) values.set(w, null);
|
|
2208
|
+
}
|
|
2209
|
+
}
|
|
2210
|
+
return true;
|
|
2211
|
+
});
|
|
2212
|
+
if (ifsTouched) return /* @__PURE__ */ new Set();
|
|
2213
|
+
const functions = /* @__PURE__ */ new Set();
|
|
2214
|
+
walk(f, (node) => {
|
|
2215
|
+
if (node && node.kind === "FuncDecl" && node.Name?.Value) functions.add(node.Name.Value);
|
|
2216
|
+
return true;
|
|
2217
|
+
});
|
|
2218
|
+
const callable = (v) => functions.has(v) || v === "FUNCNAME" || v === "true" || v === "false" || v === ":";
|
|
2219
|
+
for (const [name, vals] of values) {
|
|
2220
|
+
if (vals && ![...vals].every(callable)) values.set(name, null);
|
|
2221
|
+
}
|
|
2222
|
+
const known = /* @__PURE__ */ new Set();
|
|
2223
|
+
for (const [name, vals] of values)
|
|
2224
|
+
if (vals && (vals.size === 1 || arrays.has(name) && vals.size > 0)) known.add(name);
|
|
2225
|
+
return known;
|
|
2226
|
+
}
|
|
2227
|
+
function expansionName(part) {
|
|
2228
|
+
if (part.kind !== "ParamExp") return null;
|
|
2229
|
+
if (part.Excl || part.Length || part.Width || part.Slice || part.Repl || part.Exp) return null;
|
|
2230
|
+
return part.Param?.Value ?? null;
|
|
2231
|
+
}
|
|
2232
|
+
function executableParts(word, assigned, quoted = false, known = EMPTY_NAMES) {
|
|
2140
2233
|
return (word?.Parts ?? []).flatMap((part) => {
|
|
2141
2234
|
const kind = part.kind;
|
|
2142
|
-
if (kind === "DblQuoted") return executableParts(part, assigned, true);
|
|
2235
|
+
if (kind === "DblQuoted") return executableParts(part, assigned, true, known);
|
|
2143
2236
|
if (kind === "Lit") return [{ kind: "Lit", value: part.Value ?? "", quoted }];
|
|
2237
|
+
const name = expansionName(part);
|
|
2238
|
+
if (name !== null && (known.has(name) || name === "FUNCNAME"))
|
|
2239
|
+
return [{ kind: "Lit", value: name, quoted }];
|
|
2240
|
+
if (name !== null) {
|
|
2241
|
+
const bound = recordedExpansion(name === "@" || name === "*" ? "1" : name);
|
|
2242
|
+
if (typeof bound === "string" && PLAIN_PROGRAM_NAME.test(bound))
|
|
2243
|
+
return [{ kind: "Lit", value: bound, quoted }];
|
|
2244
|
+
}
|
|
2144
2245
|
if (kind === "SglQuoted")
|
|
2145
2246
|
return [{ kind: part.Dollar ? "Dynamic" : "Lit", value: part.Value ?? "", quoted: true }];
|
|
2146
2247
|
if (kind === "ParamExp" && isDefaultExpansion(part) && !assigned.has(part.Param?.Value)) {
|
|
@@ -2148,14 +2249,14 @@ function executableParts(word, assigned, quoted = false) {
|
|
|
2148
2249
|
if (fallback !== null) return [{ kind: "Lit", value: fallback, quoted }];
|
|
2149
2250
|
}
|
|
2150
2251
|
if (kind === "CmdSubst") {
|
|
2151
|
-
const
|
|
2152
|
-
if (
|
|
2252
|
+
const name2 = lookupSubstitution(part);
|
|
2253
|
+
if (name2 !== null) return [{ kind: "Lit", value: name2, quoted }];
|
|
2153
2254
|
}
|
|
2154
2255
|
return [{ kind: "Dynamic", value: "", quoted }];
|
|
2155
2256
|
});
|
|
2156
2257
|
}
|
|
2157
|
-
function opaqueExecutable(word, assigned) {
|
|
2158
|
-
const parts = executableParts(word, assigned);
|
|
2258
|
+
function opaqueExecutable(word, assigned, known = EMPTY_NAMES) {
|
|
2259
|
+
const parts = executableParts(word, assigned, false, known);
|
|
2159
2260
|
let lastSlash = -1;
|
|
2160
2261
|
parts.forEach((p, i) => {
|
|
2161
2262
|
if (p.kind === "Lit" && p.value.includes("/")) lastSlash = i;
|
|
@@ -2277,6 +2378,9 @@ function deriveBinaryOp(sample) {
|
|
|
2277
2378
|
function isListOp(op) {
|
|
2278
2379
|
return listOps().has(op);
|
|
2279
2380
|
}
|
|
2381
|
+
function isPipeOp(op) {
|
|
2382
|
+
return pipeOps().has(op);
|
|
2383
|
+
}
|
|
2280
2384
|
function listOps() {
|
|
2281
2385
|
if (_listOps) return _listOps;
|
|
2282
2386
|
_listOps = new Set(
|
|
@@ -2521,6 +2625,33 @@ function isProtectedCodePath(p) {
|
|
|
2521
2625
|
if (matchSensitivePath(p) !== null) return true;
|
|
2522
2626
|
return SYSTEM_AUTH_FILES.includes(p) || SYSTEM_AUTH_DIRS.some((d) => p === d || p.startsWith(d + "/"));
|
|
2523
2627
|
}
|
|
2628
|
+
function isJailedCodePath(literal, jailPaths) {
|
|
2629
|
+
const value = trimTrailingSlashes(literal.replace(/\\/g, "/"));
|
|
2630
|
+
if (!value) return false;
|
|
2631
|
+
for (const raw of jailPaths) {
|
|
2632
|
+
const jail = trimTrailingSlashes(raw.trim().replace(/\\/g, "/"));
|
|
2633
|
+
if (!jail) continue;
|
|
2634
|
+
const home = homeTail(jail);
|
|
2635
|
+
if (home === null) {
|
|
2636
|
+
if (value === jail || value.startsWith(jail + "/")) return true;
|
|
2637
|
+
continue;
|
|
2638
|
+
}
|
|
2639
|
+
if (!home) continue;
|
|
2640
|
+
const tail = homeTail(value);
|
|
2641
|
+
if (tail !== null && (tail === home || tail.startsWith(home + "/"))) return true;
|
|
2642
|
+
}
|
|
2643
|
+
return false;
|
|
2644
|
+
}
|
|
2645
|
+
function trimTrailingSlashes(s) {
|
|
2646
|
+
let end = s.length;
|
|
2647
|
+
while (end > 0 && s.charCodeAt(end - 1) === 47) end--;
|
|
2648
|
+
return s.slice(0, end);
|
|
2649
|
+
}
|
|
2650
|
+
function homeTail(p) {
|
|
2651
|
+
const m = /^(?:~|\$\{?HOME\}?|\/home\/[^/]+|\/Users\/[^/]+|\/root)(?:\/(.*))?$/.exec(p);
|
|
2652
|
+
if (!m) return null;
|
|
2653
|
+
return m[1] ?? "";
|
|
2654
|
+
}
|
|
2524
2655
|
function inlineExecDescription(r) {
|
|
2525
2656
|
const lead = r ? `The AI is running code directly from the command line: ${inlineExecReason(r).replace(/^This/, "this")}.` : "The AI is running code directly from the command line.";
|
|
2526
2657
|
return `${lead} Review the full script below before allowing it to execute.`;
|
|
@@ -2529,7 +2660,8 @@ function inlineExecReason(r) {
|
|
|
2529
2660
|
const who = r.interp ? `This inline ${r.interp} code` : "This inline code";
|
|
2530
2661
|
return r.evidence ? `${who} ${r.what} (${r.evidence})` : `${who} ${r.what}`;
|
|
2531
2662
|
}
|
|
2532
|
-
function inlineExecReview(command) {
|
|
2663
|
+
function inlineExecReview(command, jailPaths = []) {
|
|
2664
|
+
const isProtected = jailPaths.length === 0 ? isProtectedCodePath : (p) => isProtectedCodePath(p) || isJailedCodePath(p, jailPaths);
|
|
2533
2665
|
const calls = inlineExecCalls(command);
|
|
2534
2666
|
if (calls === PARSE_FAIL) {
|
|
2535
2667
|
return INLINE_EXEC_FALLBACK.test(command) ? { outcome: "unreadable", interp: "", what: "could not be parsed" } : null;
|
|
@@ -2552,7 +2684,7 @@ function inlineExecReview(command) {
|
|
|
2552
2684
|
what: `is ${call.interp} code, which node9 does not read`
|
|
2553
2685
|
};
|
|
2554
2686
|
} else {
|
|
2555
|
-
const judged = judgeInlineCode(language, code,
|
|
2687
|
+
const judged = judgeInlineCode(language, code, isProtected);
|
|
2556
2688
|
if (judged) finding = { ...judged, interp: call.interp };
|
|
2557
2689
|
}
|
|
2558
2690
|
if (finding?.outcome === "dangerous") return finding;
|
|
@@ -2733,6 +2865,11 @@ function recordTopLevelStmt(stmt) {
|
|
|
2733
2865
|
if (t === "DeclClause") return ASSIGNMENT_HEADS.has(stmt.Cmd.Variant?.Value ?? "");
|
|
2734
2866
|
return (stmt.Cmd.Args || []).length === 0 && (stmt.Cmd.Assigns || []).length > 0;
|
|
2735
2867
|
}
|
|
2868
|
+
function arrayElements(value) {
|
|
2869
|
+
if (typeof value !== "string" || !value.startsWith(ARRAY_MARK)) return null;
|
|
2870
|
+
const body = value.slice(ARRAY_MARK.length);
|
|
2871
|
+
return body === "" ? [] : body.split(ARRAY_SEP);
|
|
2872
|
+
}
|
|
2736
2873
|
function recordAssignments(n, at) {
|
|
2737
2874
|
if (!assignmentTable) return;
|
|
2738
2875
|
const t = n.kind;
|
|
@@ -2746,7 +2883,19 @@ function recordAssignments(n, at) {
|
|
|
2746
2883
|
} else return;
|
|
2747
2884
|
for (const a of assigns) {
|
|
2748
2885
|
const name = a?.Name?.Value;
|
|
2749
|
-
if (!name
|
|
2886
|
+
if (!name) continue;
|
|
2887
|
+
if (a.Array) {
|
|
2888
|
+
const elems = (a.Array.Elems || []).map(
|
|
2889
|
+
(e) => e?.Index ? null : resolveWordLiteral(e?.Value)
|
|
2890
|
+
);
|
|
2891
|
+
const literal = elems.every((v) => v !== null);
|
|
2892
|
+
assignmentTable.set(name, {
|
|
2893
|
+
value: literal && !a.Append ? ARRAY_MARK + elems.join(ARRAY_SEP) : null,
|
|
2894
|
+
at
|
|
2895
|
+
});
|
|
2896
|
+
continue;
|
|
2897
|
+
}
|
|
2898
|
+
if (!a.Value || a.Append) continue;
|
|
2750
2899
|
assignmentTable.set(name, { value: resolveWordLiteral(a.Value), at });
|
|
2751
2900
|
}
|
|
2752
2901
|
}
|
|
@@ -2757,7 +2906,33 @@ function resolveTrivialSubst(part) {
|
|
|
2757
2906
|
const st = stmts[0];
|
|
2758
2907
|
if ((st.Redirs || []).length > 0 || st.Negated || st.Background) return void 0;
|
|
2759
2908
|
const cmd = st.Cmd;
|
|
2760
|
-
if (!cmd
|
|
2909
|
+
if (!cmd) return void 0;
|
|
2910
|
+
if (cmd.kind === "BinaryCmd" && pipeOps().has(cmd.Op)) {
|
|
2911
|
+
const left = cmd.X?.Cmd;
|
|
2912
|
+
const right = cmd.Y?.Cmd;
|
|
2913
|
+
if (!left || !right || left.kind !== "CallExpr" || right.kind !== "CallExpr") return void 0;
|
|
2914
|
+
if ((cmd.X.Redirs || []).length > 0 || (cmd.Y.Redirs || []).length > 0) return void 0;
|
|
2915
|
+
const input = trivialCallOutput(left);
|
|
2916
|
+
if (input === void 0) return void 0;
|
|
2917
|
+
const filter = (right.Args || []).map((a) => resolveWordLiteral(a));
|
|
2918
|
+
if (filter.some((w) => w === null)) return void 0;
|
|
2919
|
+
const f = baseWord(filter[0]);
|
|
2920
|
+
const flags = filter.slice(1);
|
|
2921
|
+
if (f === "base64" && flags.length === 1 && /^(-d|-D|--decode)$/.test(flags[0])) {
|
|
2922
|
+
try {
|
|
2923
|
+
const out = Buffer.from(input, "base64").toString("utf8");
|
|
2924
|
+
return /^[\x20-\x7e]*$/.test(out) ? out : void 0;
|
|
2925
|
+
} catch {
|
|
2926
|
+
return void 0;
|
|
2927
|
+
}
|
|
2928
|
+
}
|
|
2929
|
+
if (f === "rev" && flags.length === 0) return [...input].reverse().join("");
|
|
2930
|
+
return void 0;
|
|
2931
|
+
}
|
|
2932
|
+
if (cmd.kind !== "CallExpr") return void 0;
|
|
2933
|
+
return trivialCallOutput(cmd);
|
|
2934
|
+
}
|
|
2935
|
+
function trivialCallOutput(cmd) {
|
|
2761
2936
|
if ((cmd.Assigns || []).length > 0) return void 0;
|
|
2762
2937
|
const words = (cmd.Args || []).map((a) => resolveWordLiteral(a));
|
|
2763
2938
|
if (words.length === 0 || words.some((w) => w === null)) return void 0;
|
|
@@ -2769,9 +2944,16 @@ function resolveTrivialSubst(part) {
|
|
|
2769
2944
|
return rest.slice(i).join(" ");
|
|
2770
2945
|
}
|
|
2771
2946
|
if (head === "printf") {
|
|
2947
|
+
if (rest.length === 1 && /^(?:\\(?:[0-7]{1,3}|x[0-9A-Fa-f]{1,2}))+$/.test(rest[0])) {
|
|
2948
|
+
return rest[0].replace(
|
|
2949
|
+
/\\(?:x([0-9A-Fa-f]{1,2})|([0-7]{1,3}))/g,
|
|
2950
|
+
(_, hex, oct) => String.fromCharCode(hex ? parseInt(hex, 16) : parseInt(oct, 8))
|
|
2951
|
+
);
|
|
2952
|
+
}
|
|
2772
2953
|
if (rest.length !== 2) return void 0;
|
|
2773
|
-
|
|
2774
|
-
return
|
|
2954
|
+
const m = /^([^%]*)%s([^%]*?)(\\n)?$/.exec(rest[0]);
|
|
2955
|
+
if (!m) return void 0;
|
|
2956
|
+
return m[1] + rest[1] + m[2];
|
|
2775
2957
|
}
|
|
2776
2958
|
return void 0;
|
|
2777
2959
|
}
|
|
@@ -2785,11 +2967,28 @@ function isPlainParam(p) {
|
|
|
2785
2967
|
if (p.kind !== "ParamExp") return false;
|
|
2786
2968
|
return !(p.Excl || p.Length || p.Width || p.Index || p.Slice || p.Repl || p.Exp);
|
|
2787
2969
|
}
|
|
2970
|
+
function indexedParam(p) {
|
|
2971
|
+
if (p.kind !== "ParamExp" || !p.Index) return null;
|
|
2972
|
+
if (p.Excl || p.Length || p.Width || p.Slice || p.Repl || p.Exp) return null;
|
|
2973
|
+
const index = resolveWordLiteral(p.Index);
|
|
2974
|
+
const name = p.Param?.Value;
|
|
2975
|
+
return name && index !== null ? { name, index } : null;
|
|
2976
|
+
}
|
|
2788
2977
|
function expandPlainParam(p) {
|
|
2789
2978
|
if (!assignmentTable) return void 0;
|
|
2979
|
+
const indexed = indexedParam(p);
|
|
2980
|
+
if (indexed) {
|
|
2981
|
+
const elems = arrayElements(recordedExpansion(indexed.name));
|
|
2982
|
+
if (elems === null) return void 0;
|
|
2983
|
+
if (indexed.index === "@" || indexed.index === "*") return elems.join(" ");
|
|
2984
|
+
return /^\d+$/.test(indexed.index) ? elems[Number(indexed.index)] ?? null : null;
|
|
2985
|
+
}
|
|
2790
2986
|
if (!isPlainParam(p)) return void 0;
|
|
2791
2987
|
const recorded = recordedExpansion(p.Param?.Value);
|
|
2792
|
-
if (recorded !== void 0)
|
|
2988
|
+
if (recorded !== void 0) {
|
|
2989
|
+
const elems = arrayElements(recorded);
|
|
2990
|
+
return elems === null ? recorded : elems[0] ?? "";
|
|
2991
|
+
}
|
|
2793
2992
|
return HOME_VARIABLES.has(p.Param?.Value) ? "~" : void 0;
|
|
2794
2993
|
}
|
|
2795
2994
|
function functionBodies(f) {
|
|
@@ -5862,7 +6061,59 @@ function dynamicOptionWord(word) {
|
|
|
5862
6061
|
if (/^--[a-z-]+=/.test(prefix) || /^-[cC]/.test(prefix)) return `${prefix}$\u2026`;
|
|
5863
6062
|
return null;
|
|
5864
6063
|
}
|
|
5865
|
-
function
|
|
6064
|
+
function arrayExpansionWords(word) {
|
|
6065
|
+
let parts = word?.Parts || [];
|
|
6066
|
+
if (parts.length === 1 && parts[0].kind === "DblQuoted") parts = parts[0].Parts || [];
|
|
6067
|
+
if (parts.length !== 1 || parts[0].kind !== "ParamExp" || !parts[0].Index) return null;
|
|
6068
|
+
const index = resolveWordLiteral(parts[0].Index);
|
|
6069
|
+
if (index !== "@" && index !== "*") return null;
|
|
6070
|
+
const elems = arrayElements(recordedExpansion(parts[0].Param?.Value));
|
|
6071
|
+
return elems;
|
|
6072
|
+
}
|
|
6073
|
+
function producedLiteral(call) {
|
|
6074
|
+
if ((call.Assigns || []).length > 0) return null;
|
|
6075
|
+
const words = (call.Args || []).map((a) => resolveWordLiteral(a));
|
|
6076
|
+
if (words.length === 0 || words.some((w) => w === null)) return null;
|
|
6077
|
+
const head = baseWord(words[0]);
|
|
6078
|
+
const rest = words.slice(1);
|
|
6079
|
+
if (head === "git" && rest[0] === "rev-parse" && rest[1] === "--show-toplevel" && rest.length === 2)
|
|
6080
|
+
return ":/";
|
|
6081
|
+
if (head === "echo") {
|
|
6082
|
+
let i = 0;
|
|
6083
|
+
while (i < rest.length && /^-[neE]+$/.test(rest[i])) i++;
|
|
6084
|
+
return rest.length - i === 1 ? rest[i] : null;
|
|
6085
|
+
}
|
|
6086
|
+
if (head === "printf" && rest.length === 2 && /^%s(\\[0n])?$/.test(rest[0])) return rest[1];
|
|
6087
|
+
return null;
|
|
6088
|
+
}
|
|
6089
|
+
function treeTopWord(word, treeTopVars = NO_VARS) {
|
|
6090
|
+
let parts = word?.Parts || [];
|
|
6091
|
+
if (parts.length === 1 && parts[0].kind === "DblQuoted") parts = parts[0].Parts || [];
|
|
6092
|
+
if (parts.length !== 1) return false;
|
|
6093
|
+
const p = parts[0];
|
|
6094
|
+
if (p.kind === "ParamExp") {
|
|
6095
|
+
const name = plainParamName(word)?.name;
|
|
6096
|
+
return name === "PWD" || name !== void 0 && treeTopVars.has(name);
|
|
6097
|
+
}
|
|
6098
|
+
if (p.kind !== "CmdSubst") return false;
|
|
6099
|
+
const stmts = p.Stmts || [];
|
|
6100
|
+
if (stmts.length !== 1 || !stmts[0].Cmd || stmts[0].Cmd.kind !== "CallExpr") return false;
|
|
6101
|
+
const words = (stmts[0].Cmd.Args || []).map((a) => resolveWordLiteral(a));
|
|
6102
|
+
if (words.some((w) => w === null)) return false;
|
|
6103
|
+
const head = baseWord(words[0]);
|
|
6104
|
+
if (head === "pwd") return words.length === 1 || words[1] === "-P" || words[1] === "-L";
|
|
6105
|
+
return head === "git" && words[1] === "rev-parse" && words[2] === "--show-toplevel";
|
|
6106
|
+
}
|
|
6107
|
+
function resolveGitWords(word, treeTopVars = NO_VARS, appended = NO_APPENDS) {
|
|
6108
|
+
if (treeTopWord(word, treeTopVars)) return [":/"];
|
|
6109
|
+
const plain = plainParamName(word);
|
|
6110
|
+
if (plain && appended.has(plain.name)) {
|
|
6111
|
+
const v = appended.get(plain.name);
|
|
6112
|
+
if (v === null || v === void 0) return [null];
|
|
6113
|
+
return plain.quoted ? [v] : splitFields(v);
|
|
6114
|
+
}
|
|
6115
|
+
const elems = arrayExpansionWords(word);
|
|
6116
|
+
if (elems !== null) return elems;
|
|
5866
6117
|
const value = resolveWordLiteral(word);
|
|
5867
6118
|
if (value === null) {
|
|
5868
6119
|
if (isPositionalParam(word)) return boundPositionals() ?? [POSITIONAL2];
|
|
@@ -5970,6 +6221,8 @@ function classify(inv) {
|
|
|
5970
6221
|
if (o.flags.has("-n") || o.flags.has("--dry-run")) break;
|
|
5971
6222
|
const forced = o.flags.has("-f") || o.flags.has("--force") || o.flags.has("--force-with-lease") || o.flags.has("--force-if-includes") || o.flags.has("--mirror") || o.operands.some((r) => r.startsWith("+"));
|
|
5972
6223
|
if (forced) found(FORCE_PUSH);
|
|
6224
|
+
const deletes = o.flags.has("-d") || o.flags.has("--delete") || o.operands.some((r) => /^:[^:]/.test(r));
|
|
6225
|
+
if (deletes) found(DESTRUCTIVE);
|
|
5973
6226
|
break;
|
|
5974
6227
|
}
|
|
5975
6228
|
case "reset": {
|
|
@@ -5997,11 +6250,72 @@ function classify(inv) {
|
|
|
5997
6250
|
if (o.flags.has("-d") || o.flags.has("--delete")) found(DESTRUCTIVE);
|
|
5998
6251
|
break;
|
|
5999
6252
|
}
|
|
6253
|
+
// node9Firewall#385: history and work discarded through plumbing. A ref
|
|
6254
|
+
// deleted by hand, a stash dropped, the reflog expired or pruned: the
|
|
6255
|
+
// commits behind them are gone the way `branch -D` loses them.
|
|
6256
|
+
case "update-ref": {
|
|
6257
|
+
const o = parseOptions(inv.args, "m", /* @__PURE__ */ new Set());
|
|
6258
|
+
if (o.flags.has("-d") && (o.dynamic || o.operands.some(isHistoryRef))) found(DESTRUCTIVE);
|
|
6259
|
+
break;
|
|
6260
|
+
}
|
|
6261
|
+
case "reflog": {
|
|
6262
|
+
const o = parseOptions(inv.args, "", /* @__PURE__ */ new Set());
|
|
6263
|
+
if (o.operands[0] === "expire" || o.operands[0] === "delete") found(DESTRUCTIVE);
|
|
6264
|
+
break;
|
|
6265
|
+
}
|
|
6266
|
+
case "gc": {
|
|
6267
|
+
if (inv.config.get("gc.reflogexpire") === "now") found(DESTRUCTIVE);
|
|
6268
|
+
break;
|
|
6269
|
+
}
|
|
6270
|
+
case "stash": {
|
|
6271
|
+
const o = parseOptions(inv.args, "", /* @__PURE__ */ new Set());
|
|
6272
|
+
if (o.operands[0] === "clear" || o.operands[0] === "drop") found(DESTRUCTIVE);
|
|
6273
|
+
break;
|
|
6274
|
+
}
|
|
6275
|
+
case "worktree": {
|
|
6276
|
+
const o = parseOptions(inv.args, "", /* @__PURE__ */ new Set());
|
|
6277
|
+
if (o.operands[0] === "remove" && (o.flags.has("-f") || o.flags.has("--force")))
|
|
6278
|
+
found(DESTRUCTIVE);
|
|
6279
|
+
break;
|
|
6280
|
+
}
|
|
6281
|
+
// The working tree overwritten: `restore` from another ref, a forced
|
|
6282
|
+
// checkout, or `checkout -- .` (every local change dropped). A bare
|
|
6283
|
+
// `restore .` or `checkout .` stays an ordinary undo, as pinned.
|
|
6284
|
+
case "restore": {
|
|
6285
|
+
const o = parseOptions(inv.args, "s", RESTORE_LONG_VALUE);
|
|
6286
|
+
const src = restoreSource(inv.args);
|
|
6287
|
+
const whole = o.dynamic || o.operands.some(wholeTree);
|
|
6288
|
+
if (src !== null && src !== "HEAD" && whole) found(DESTRUCTIVE);
|
|
6289
|
+
break;
|
|
6290
|
+
}
|
|
6291
|
+
case "checkout": {
|
|
6292
|
+
const o = parseOptions(inv.args, "bB", CHECKOUT_LONG_VALUE);
|
|
6293
|
+
const forced = o.flags.has("-f") || o.flags.has("--force");
|
|
6294
|
+
const dropAll = inv.args.includes("--") && o.operands.some(wholeTree);
|
|
6295
|
+
if (forced || dropAll) found(DESTRUCTIVE);
|
|
6296
|
+
break;
|
|
6297
|
+
}
|
|
6000
6298
|
default:
|
|
6001
6299
|
break;
|
|
6002
6300
|
}
|
|
6003
6301
|
return out;
|
|
6004
6302
|
}
|
|
6303
|
+
function isExcludePathspec(operand) {
|
|
6304
|
+
return /^:[!^]/.test(operand) || /^:\([^)]*\bexclude\b[^)]*\)/.test(operand);
|
|
6305
|
+
}
|
|
6306
|
+
function restoreSource(args) {
|
|
6307
|
+
for (let i = 0; i < args.length; i++) {
|
|
6308
|
+
const w = args[i];
|
|
6309
|
+
if (w === null) continue;
|
|
6310
|
+
if (w.startsWith("--source=")) return w.slice("--source=".length);
|
|
6311
|
+
if (w === "--source" || w === "-s") return args[i + 1] ?? null;
|
|
6312
|
+
if (/^-s./.test(w)) return w.slice(2);
|
|
6313
|
+
}
|
|
6314
|
+
return null;
|
|
6315
|
+
}
|
|
6316
|
+
function isHistoryRef(ref) {
|
|
6317
|
+
return /^refs\/(heads|stash)(\/|$)/.test(ref);
|
|
6318
|
+
}
|
|
6005
6319
|
function killSwitchSet(name, value) {
|
|
6006
6320
|
if (value === null) return false;
|
|
6007
6321
|
switch (name) {
|
|
@@ -6059,6 +6373,7 @@ function hooksBypass(inv) {
|
|
|
6059
6373
|
const o = parseOptions(inv.args, "mFCcut", COMMIT_LONG_VALUE);
|
|
6060
6374
|
return o.flags.has("-n") || o.flags.has("--no-verify");
|
|
6061
6375
|
}
|
|
6376
|
+
if (sub === "commit-tree") return true;
|
|
6062
6377
|
if (sub !== void 0 && NO_VERIFY_SUBS.has(sub)) {
|
|
6063
6378
|
return inv.args.some((a) => a === "--no-verify");
|
|
6064
6379
|
}
|
|
@@ -6096,7 +6411,20 @@ function configWritesHooksPath(args) {
|
|
|
6096
6411
|
return write2;
|
|
6097
6412
|
}
|
|
6098
6413
|
function isHookPath(word) {
|
|
6099
|
-
return /(^|[\\/])(\.git[\\/]hooks|\.husky)([\\/]|$)/.test(word);
|
|
6414
|
+
return /(^|[\\/])(\.git[\\/]hooks|\.husky|\.githooks)([\\/]|$)/.test(word);
|
|
6415
|
+
}
|
|
6416
|
+
function isLiveHookFile(word) {
|
|
6417
|
+
if (!isHookPath(word)) return false;
|
|
6418
|
+
const m = /(^|[\\/])(\.git[\\/]hooks|\.husky|\.githooks)(?:[\\/](.*))?$/.exec(word);
|
|
6419
|
+
if (!m) return false;
|
|
6420
|
+
const rest = m[3] ?? "";
|
|
6421
|
+
if (rest === "" || rest === "_") return true;
|
|
6422
|
+
const leaf = rest.replace(/^_[\\/]/, "");
|
|
6423
|
+
return /^[a-z-]+$/.test(leaf);
|
|
6424
|
+
}
|
|
6425
|
+
function hookBodyIsEmpty(text) {
|
|
6426
|
+
const lines = text.split(/\r?\n/).map((l) => l.trim()).filter((l) => l !== "" && !l.startsWith("#"));
|
|
6427
|
+
return lines.every((l) => /^(exit(\s+0)?|true|:|set\s+-[a-zA-Z]+|set\s+-o\s+\w+)$/.test(l));
|
|
6100
6428
|
}
|
|
6101
6429
|
function modeRemovesExecute(mode) {
|
|
6102
6430
|
if (/^[0-7]{3,4}$/.test(mode)) {
|
|
@@ -6105,6 +6433,22 @@ function modeRemovesExecute(mode) {
|
|
|
6105
6433
|
}
|
|
6106
6434
|
return mode.split(",").some((part) => /^[ugoa]*-[rwst]*x/.test(part));
|
|
6107
6435
|
}
|
|
6436
|
+
function redirOpIsAppend(redir) {
|
|
6437
|
+
return redir?.Op === appendOp();
|
|
6438
|
+
}
|
|
6439
|
+
function appendOp() {
|
|
6440
|
+
if (_appendOp !== null) return _appendOp;
|
|
6441
|
+
try {
|
|
6442
|
+
const f = parseShared("echo x >> y");
|
|
6443
|
+
_appendOp = typeof f === "symbol" ? -1 : f.Stmts[0].Redirs[0].Op;
|
|
6444
|
+
} catch {
|
|
6445
|
+
_appendOp = -1;
|
|
6446
|
+
}
|
|
6447
|
+
return _appendOp;
|
|
6448
|
+
}
|
|
6449
|
+
function hooksBypassed(shown) {
|
|
6450
|
+
return { ...HOOKS_BYPASS, shown, reason: `${HOOKS_BYPASS.reason}: ${shown}` };
|
|
6451
|
+
}
|
|
6108
6452
|
function chmodDisarmsHook(args, shown) {
|
|
6109
6453
|
let i = 0;
|
|
6110
6454
|
while (i < args.length) {
|
|
@@ -6147,6 +6491,7 @@ function stagesEverything(inv) {
|
|
|
6147
6491
|
const sub = inv.sub?.toLowerCase();
|
|
6148
6492
|
const prefix = chdirPrefix(inv);
|
|
6149
6493
|
const judge = (operands2) => {
|
|
6494
|
+
if (operands2.length > 0 && operands2.every(isExcludePathspec)) return {};
|
|
6150
6495
|
let conditional = false;
|
|
6151
6496
|
for (const operand of operands2) {
|
|
6152
6497
|
if (!wholeTree(operand)) continue;
|
|
@@ -6439,7 +6784,7 @@ function evaluateAgentFileWrite(args, accesses, context, settings, shell, hooks
|
|
|
6439
6784
|
}
|
|
6440
6785
|
return null;
|
|
6441
6786
|
}
|
|
6442
|
-
function
|
|
6787
|
+
function isPipeOp2(op) {
|
|
6443
6788
|
return !isListOp(op);
|
|
6444
6789
|
}
|
|
6445
6790
|
function isDupInOp(op) {
|
|
@@ -8472,7 +8817,7 @@ async function evaluatePolicyCore(config, toolName, args, context = {}, hooks =
|
|
|
8472
8817
|
if (v?.logged) noteLogged(v);
|
|
8473
8818
|
else if (v) candidates.push(v);
|
|
8474
8819
|
};
|
|
8475
|
-
const inline = reviewsEveryInline(config.settings.mode) ? detectInlineExec(shellCommand) ? void 0 : null : inlineExecReview(shellCommand);
|
|
8820
|
+
const inline = reviewsEveryInline(config.settings.mode) ? detectInlineExec(shellCommand) ? void 0 : null : inlineExecReview(shellCommand, config.policy.jailPaths);
|
|
8476
8821
|
if (inline !== null) {
|
|
8477
8822
|
consider("commands.inline-exec", {
|
|
8478
8823
|
decision: "review",
|
|
@@ -8815,7 +9160,7 @@ function* validCardRuns(text, base2, exemptFractions = true) {
|
|
|
8815
9160
|
let m;
|
|
8816
9161
|
while ((m = re.exec(text)) !== null) {
|
|
8817
9162
|
const digits = m[0].replace(/\D/g, "");
|
|
8818
|
-
const fraction = exemptFractions && isDecimalFraction(text, m.index, digits.length === m[0].length);
|
|
9163
|
+
const fraction = exemptFractions && (isDecimalFraction(text, m.index, digits.length === m[0].length) || isInteriorDotNumber(m[0]));
|
|
8819
9164
|
if (!fraction && validateLuhn(digits)) {
|
|
8820
9165
|
yield { index: m.index, length: m[0].length, digits };
|
|
8821
9166
|
} else {
|
|
@@ -8842,6 +9187,12 @@ function replaceValidCards(text, replace, { exemptFractions = true } = {}) {
|
|
|
8842
9187
|
}
|
|
8843
9188
|
return out;
|
|
8844
9189
|
}
|
|
9190
|
+
function isInteriorDotNumber(run) {
|
|
9191
|
+
const first = run.indexOf(".");
|
|
9192
|
+
if (first <= 0 || first === run.length - 1) return false;
|
|
9193
|
+
if (run.indexOf(".", first + 1) !== -1) return false;
|
|
9194
|
+
return !/[-\s]/.test(run);
|
|
9195
|
+
}
|
|
8845
9196
|
function isDecimalFraction(text, index, unseparated) {
|
|
8846
9197
|
if (!unseparated) return false;
|
|
8847
9198
|
const sep = text[index - 1];
|
|
@@ -9568,7 +9919,7 @@ function matchCanaryArgs(args, values) {
|
|
|
9568
9919
|
return null;
|
|
9569
9920
|
}
|
|
9570
9921
|
}
|
|
9571
|
-
var import_url, import_picomatch, import_safe_regex2, import_picomatch2, import_module, import_picomatch3, import_safe_regex22, import_crypto, import_crypto2, import_crypto3, import_crypto4, getFilename, __filename2, MAX_REGEX_LENGTH, REGEX_CACHE_MAX, regexCache, aws_default, bash_safe_default, docker_default, filesystem_default, github_default, k8s_default, mongodb_default, postgres_default, project_jail_default, redis_default, finance_default, identity_default, publishing_default, settings_default, branches_default, ACTION_TEMPLATES, ACTION_CHECKS, GAP, prog, httpTo, httpWrite, HTTP_WRITE, HTTP_WRITE_ANY, NOT_STRIPE_TEST, postTo, STRIPE_OBJECTS, APP_SHIELD_SPECS, APP_SHIELDS, APP_SHIELD_NAMES, APP_SERVER_GLOB, GENERAL_ACTION_RULES, BUILTIN_SHIELDS, SSRF_MAX_HOST, METADATA_ADDRESSES, STRICT_TIERS, METADATA_HOSTNAMES, v4Octets, TIER_REASON, CHECK_TEXT, LEVELS, MODE_VALUES, SOFT, STRICT, BLOCK_ALL, LEVEL_CHECKS, ASI, ASI_IDS, PACK_SHIELD_OWASP, PACK_RULE_OWASP, VERDICTS, CHECK_VERDICT_RANK, ALL, BUILTIN_DANGEROUS_WORDS, PRODUCT_CHECKS, SHIELD_RULE_NAME, SHIELD_RULES_FOLDED_INTO_PRODUCT, CHECKS, CHECK_BY_ID, LEGACY_TO_ID, PROJECT_JAIL_BLOCK_READ, OVERRIDE_PREFIX, LABEL_WRAPPERS, LEGACY_READERS, syntax, KINDS, STRUCTS, unknownKinds, INVISIBLE_RE, INVISIBLE_ONE, HOMOGLYPHS, HOMOGLYPH_RE, MAX_BLOBS, MIN_DECODED, BASE64_RUN_RE, HEX_RUN_RE, HEX_ESCAPE_RUN_RE, SYSTEM_AUTH_FILES, SYSTEM_AUTH_DIRS, PASSWORD_HASH_FILES, STARTUP_NAMES, SYSTEM_DIRS, SYSTEM_DIRS_EXEMPT, UPLOAD_SYSTEM_DIRS, AGENT_INSTRUCTION_FILES, AGENT_INSTRUCTION_DIRS, LEGACY_SYSTEM_PATH_RE, MAX_ALTERNATIVES, MAX_CALL_DEPTH, MAX_CALL_WALKS, MAX_XARGS_PAYLOAD, POSITIONAL, MAX_DEPTH, MAX_PAYLOAD_DEPTH, unique, clone, SENDING_STDIN, DOWNLOAD_SHORT_VALUE, DOWNLOAD_LONG_VALUE, DOWNLOAD_OUTPUT_FLAGS, DOWNLOAD_DIR_FLAGS, base, quoteGlob, asWord, ops, MAX_INLINE_CODE, WHAT, OUTSIDE, pyImport, either, PYTHON, NODE, PERL, RUBY, PHP, TABLES, STRING_LITERAL, sharedParser, MESSAGE_FLAGS, SHELL_INTERPRETERS, DOWNLOAD_CMDS, NORMALIZE_CACHE_MAX, normalizeCache, codeBodiesCache, AST_CACHE_MAX, astCache, PARSE_FAIL, INTERPRETER_LINE, PROGRAM_DIR, ACCESS_VIEW_CACHE_MAX, accessViewCache, MAX_READING_PAYLOADS, STDIN_CODE_INTERPRETERS, RUNS_TEXT_ELSEWHERE, defaultExpansionOps, VARIABLE_READERS, FS_READ_TOOLS, GREP_SHAPE, PATTERN_VERBS, PATTERN_VERB_NAMES, GREP_FILE_OPERANDS, READER_VALUE_LETTERS, FILE_OPERAND_FLAGS, SCP_VALUE_FLAGS, CURL_SOURCE_FLAGS, CURL_VALUE_LETTERS, WGET_VALUE_LETTERS, TAR_VALUE_LETTERS, ZIP_VALUE_LETTERS, RSYNC_VALUE_LETTERS, RSYNC_SKIP, CP_VALUE_LETTERS, INSTALL_VALUE_LETTERS, COPY_VERBS, TAR_MODE_WORD, COPY_VERB_HEADS, FS_OP_PRESCREEN_RE, HOME_CACHE_ALLOWLIST, SENSITIVE_PATH_RULES, AST_FS_REGEX_RULES, SQL_DB_CLIS, SQL_DDL_RE, CHMOD_OPEN_PERM_TOKENS, COMMAND_WRAPPERS, INLINE_INTERPRETER, RUNNER_WRAPPERS, _redirStdinOps, _listOps, WRAPPER_TAKES_TARGET, FIND_EXEC_FLAGS, FS_MUTATION_TOOLS, INTERP_LEADING_TARGET, MAX_PAYLOAD_NESTING, payloadNesting, MAX_INLINE_CALLS, INLINE_EXEC_FALLBACK, UNREADABLE_SOURCE, SCRIPT_RUNNERS, SCRIPT_RUNNER_VALUE_FLAGS, MAX_SCRIPT_OPERANDS, NET_BINARIES, VALUE_FLAGS, HOME_VARIABLES, assignmentTable, currentStmtOffset, PAYLOAD_BUDGET, payloadBudget, seenPayloads, UNANALYSABLE_NESTING, ASSIGNMENT_HEADS, andOrOps, MAX_CALL_DEPTH2, MAX_CALL_WALKS2, callDepth, callWalks, FS_OP_CACHE_MAX, fsOpCache, stripDotSlash, REDIR_TRUNCATE_OPS, REDIR_FILE_IN_OPS, REDIR_HEREDOC_OPS, FIND_OPTIONS, COPY_RULE_OF, INDIRECT_SHAPE_RE, SOURCES_FILE_RE, SHELL_SET_VARS, pipeOps, callWords, JAILED_GLOB_NAMES, JAILED_DIR_NAMES, shellGlob, GLOB_META, isReaderWord, positionalAfter, NONE, UNKNOWN, FORBIDDEN_PATH_SEGMENTS, BASH_TOOL_NAMES, MCP_EXECUTORS, BUILTIN_FIELDS, ARGV_FIELDS, BARE_WORD, MAX_ARGV_CHARACTERS, exempt, RANK, SEQUENCE_OPS, BIP39_ENGLISH, BIP39_PUBLIC_VECTORS, indices, lengths, hash, MAX_MNEMONIC_HASHES, SECRET_VIEW_LIMITS, IBAN_LENGTH, IBAN_BBAN_SHAPE, B58, B58_INDEX, XPRV_VERSIONS, B62, CRC32_TABLE, GITHUB_TOKEN_RE, B64URL, B64URL_INDEX, CASK_TWO_ZERO_SUFFIX, CASK_FOUR_ZERO_SUFFIX, CF_ODD, CF_EVEN, SPANISH_LETTERS, HETU_CHARS, VERHOEFF_D, VERHOEFF_P, MAX, UNTRUSTED_TOOLS, INJECTION_SIGNALS, MENTION_QUOTE_RE, MENTION_WORD_RE, ASSIGNMENT_CONTEXT_RE, DLP_STOPWORDS, REFERENCE_VALUE_RE, IDENTIFIER_VALUE_RE, PATH_VALUE_RE, DOTTED_REFERENCE_RE, CONCATENATION_RE, EMAIL_VALUE_RE, FIXTURE_NAME_RE, DERIVATIVE_NAME_RE, QUERY_CREDENTIAL_VALUE_RE, OTP_SECRET_RE, OTP_DOC_SECRETS, ASSIGNED_SECRET_VALUE_RE, ASSIGNED_SECRET_NAME_RE, NAME_KEYWORD_RE, ARN_CONTEXT_RE, CIPHER_KEY_NAME_RE, CIPHER_NAME_PARTS, CIPHER_KEY_VALUE_RE, LARAVEL_KEY_VALUE_RE, SQL_PASSWORD_VALUE_RE, GRAFANA_KEY_VALUE_RE, BASIC_VALUE_RE, BASIC_PAIR_RE, BASIC_HEADER_RE, BASIC_HEADER_PAIR_RE, BASIC_PLACEHOLDER_RE, BASIC_TEMPLATE_MARKERS, DROPBOX_SECRET_RE, OTP_CAPTURE_RE, DB_URL_PASSWORD_RE, DLP_PATTERNS, DLP_PATTERNS_GLOBAL, SENSITIVE_PATH_PATTERNS, SENSITIVE_PATH_REGEXES, MAX_DEPTH2, MAX_STRING_BYTES, MAX_JSON_PARSE_BYTES, DLP_SCAN_LIMITS, BATCH_SEPARATOR, ENCODED_RUN_RE, IMPERATIVE, SECRET_TARGET, GUARD, SIGNALS, DESTINATION_RE, REUSED_SIGNALS, NEVER_NEGATED, NEGATION_BEFORE, RDR_IN, COPY_VERBS2, LITERAL_VERBS, GIT_PRESCREEN_RE, MAX_PAYLOAD_DEPTH2, MAX_ALIAS_DEPTH, CACHE_MAX, cache, PAYLOAD_SHELLS, CONFIG_SCOPE_FLAGS, CONFIG_VALUE_FLAGS, GLOBAL_VALUE_OPTIONS, GLOBAL_FLAG_OPTIONS, MAX_LOOP_ITEMS, GitWalk, POSITIONAL2, FORCE_PUSH, DESTRUCTIVE, UNREADABLE, PUSH_LONG_VALUE, BRANCH_LONG_VALUE, TAG_LONG_VALUE, CLEAN_LONG_VALUE, HOOKS_BYPASS, NO_VERIFY_SUBS, HOOK_KILL_SWITCHES, COMMIT_LONG_VALUE, CHMOD_OPTION_RE, STAGE_ALL, ADD_LONG_VALUE, CHECK_ID, RULE_NAME, INERT_LINE_RE, CHECK_ID2, INSTRUCTION_NAMES, SETTINGS_RE, HOOK_WORDS_RE, SHELLS, NETCATS, NET_CLIENTS, SENDERS, NETCAT_EXEC_LONG, DECL_DUMPS, PROC_ENVIRON_RE, DEV_NET_RE, SOCAT_PROGRAM_RE, SOCAT_NET_RE, PRESCREEN_RE, MAX_PAYLOAD_DEPTH3, CACHE_MAX2, cache2, dupInOp, REVERSE_SHELL_DESCRIPTION, ENV_EXFIL_DESCRIPTION, DYNAMIC_WORD, MULTICALL, SHELL_VALUE_OPTIONS, INTERPRETERS, OutboundWalk, NPM_INSTALL_VERBS, NPM_EXEC_VERBS, PNPM_INSTALL_VERBS, YARN_INSTALL_VERBS, BUN_INSTALL_VERBS, DLX_VERBS, NON_REGISTRY_RE, NPM_NAME_RE, EXACT_SEMVER_RE, NPM_VALUE_FLAGS, PNPM_VALUE_FLAGS, YARN_VALUE_FLAGS, BUN_VALUE_FLAGS, PIP_VALUE_FLAGS, UV_VALUE_FLAGS, POETRY_VALUE_FLAGS, PIPENV_VALUE_FLAGS, PIPX_VALUE_FLAGS, PY_SPEC_RE, PY_EXACT_RE, EXACT_VERSION_RE, GEM_NAME_RE, GEM_VALUE_FLAGS, BUNDLE_VALUE_FLAGS, CRATE_NAME_RE, CARGO_ADD_VALUE_FLAGS, CARGO_INSTALL_VALUE_FLAGS, GO_VALUE_FLAGS, GO_PATH_RE, NUGET_NAME_RE, DOTNET_ADD_VALUE_FLAGS, DOTNET_TOOL_VALUE_FLAGS, NUGET_VALUE_FLAGS, MAVEN_COORD_RE, COMPOSER_NAME_RE, COMPOSER_VALUE_FLAGS, EDITOR_HEADS, EXTENSION_ID_RE, MANAGER_HEADS, SHELLS2, MAX_NESTING, SHELL_VALUE_FLAGS, NPM_FAMILY, PIP_FAMILY, NPM_FETCH_VERBS, PIP_FETCH_VERBS, NPM_FLAGS, PIP_FLAGS, NPM_VARS, PIP_VARS, PRESCREEN_RE2, PIP_ATTACHED_RE, MAX_PAYLOAD_DEPTH4, PUBLIC_REGISTRY_HOSTS, TUNING_FIELDS, MAP_GOVERNED, KNOB_GOVERNED, CONFIGURABLE_CHECK_IDS, DEFAULT_EGRESS_ALLOWLIST, PRIVATE_HOST_SUFFIXES, SOURCE_COMMANDS, SINK_COMMANDS, OBFUSCATORS, SENSITIVE_PATTERNS, FLAGS_WITH_VALUES, DESTINATION_ARGS, MCP_DESTINATION_KEYS, ARGUMENT_SCAN_LIMITS, RUN_CHAR, runChar, VERDICT_RANK, SQL_DML_KEYWORDS, MAX_DESTINATIONS, MAX_SCAN_CHARS, EMAIL_RE, URL_RE, IBAN_RE, RECIPIENT_KEYS, DESTRUCTIVE_VERB_RE, PII_EMAIL_RE, PII_SSN_RE, PII_PHONE_RE, PII_CC16_RE, PII_CC15_RE, PII_CC14_RE, PII_CC13_RE, PII_CC19_RE, CARD_PATTERNS, PII_ROUTING_RE, ROUTING_LABEL_RE, ROUTING_LABEL_WINDOW, NATIONAL_ID_SHAPES, NATIONAL_ID_LABEL_RE, NATIONAL_ID_LABEL_CS_RE, idLabelIn, NATIONAL_ID_LABEL_WINDOW, NATIONAL_ID_GUARD_RE, PII_IBAN_RE, REALTIME_PII_PATTERNS, MAX_PII_SCAN_BYTES, IBAN_DESTINATION_KEYS, WHOLE_IBAN_RE, JSON_ESCAPE_RE, JSON_ESCAPES, MASKED_KINDS, ENTRY_RE, IBAN_TEXT_RE, EMAIL_TEXT_RE, ACCOUNT_KEY_RE, ACCOUNT_VALUE_RE, MAX_MASK_DEPTH, EMPTY, CURL_SEND_FLAGS, WGET_SEND_FLAGS, IWR_SEND_FLAGS, WRITE_METHODS, GH_READ, GH_WRITE, GH_HOSTNAME_FLAGS, GH_REPO_VALUE_FLAGS, GH_API_VALUE_FLAGS, GIT_FETCH, PUBLISH, SHELLS3, OWN_HEADS, MAX_DEPTH3, CWD_CHANGERS, TERMINAL_ESCAPE_RE, CONTROL_CHAR_RE, LOOP_MAX_RECORDS, CANARY_MIN_LENGTH, MAX_TEXT, MAX_DEPTH4, MAX_JSON_PARSE, URL_DEPTH, B64_DEPTH, MIN_SEGMENT, SEPARATORS, stripSeparators, looksText, CANARY_DECODERS, VIEWS, LONG_OUTPUT_THRESHOLD_BYTES;
|
|
9922
|
+
var import_url, import_picomatch, import_safe_regex2, import_picomatch2, import_module, import_picomatch3, import_safe_regex22, import_crypto, import_crypto2, import_crypto3, import_crypto4, getFilename, __filename2, MAX_REGEX_LENGTH, REGEX_CACHE_MAX, regexCache, aws_default, bash_safe_default, docker_default, filesystem_default, github_default, k8s_default, mongodb_default, postgres_default, project_jail_default, redis_default, finance_default, identity_default, publishing_default, settings_default, branches_default, ACTION_TEMPLATES, ACTION_CHECKS, GAP, prog, httpTo, httpWrite, HTTP_WRITE, HTTP_WRITE_ANY, NOT_STRIPE_TEST, postTo, STRIPE_OBJECTS, APP_SHIELD_SPECS, APP_SHIELDS, APP_SHIELD_NAMES, APP_SERVER_GLOB, GENERAL_ACTION_RULES, BUILTIN_SHIELDS, SSRF_MAX_HOST, METADATA_ADDRESSES, STRICT_TIERS, METADATA_HOSTNAMES, v4Octets, TIER_REASON, CHECK_TEXT, LEVELS, MODE_VALUES, SOFT, STRICT, BLOCK_ALL, LEVEL_CHECKS, ASI, ASI_IDS, PACK_SHIELD_OWASP, PACK_RULE_OWASP, VERDICTS, CHECK_VERDICT_RANK, ALL, BUILTIN_DANGEROUS_WORDS, PRODUCT_CHECKS, SHIELD_RULE_NAME, SHIELD_RULES_FOLDED_INTO_PRODUCT, CHECKS, CHECK_BY_ID, LEGACY_TO_ID, PROJECT_JAIL_BLOCK_READ, OVERRIDE_PREFIX, LABEL_WRAPPERS, LEGACY_READERS, syntax, KINDS, STRUCTS, unknownKinds, INVISIBLE_RE, INVISIBLE_ONE, HOMOGLYPHS, HOMOGLYPH_RE, MAX_BLOBS, MIN_DECODED, BASE64_RUN_RE, HEX_RUN_RE, HEX_ESCAPE_RUN_RE, SYSTEM_AUTH_FILES, SYSTEM_AUTH_DIRS, PASSWORD_HASH_FILES, STARTUP_NAMES, SYSTEM_DIRS, SYSTEM_DIRS_EXEMPT, UPLOAD_SYSTEM_DIRS, AGENT_INSTRUCTION_FILES, AGENT_INSTRUCTION_DIRS, LEGACY_SYSTEM_PATH_RE, MAX_ALTERNATIVES, MAX_CALL_DEPTH, MAX_CALL_WALKS, MAX_XARGS_PAYLOAD, POSITIONAL, MAX_DEPTH, MAX_PAYLOAD_DEPTH, unique, clone, SENDING_STDIN, DOWNLOAD_SHORT_VALUE, DOWNLOAD_LONG_VALUE, DOWNLOAD_OUTPUT_FLAGS, DOWNLOAD_DIR_FLAGS, base, quoteGlob, asWord, ops, MAX_INLINE_CODE, WHAT, OUTSIDE, pyImport, either, PYTHON, NODE, PERL, RUBY, PHP, TABLES, STRING_LITERAL, sharedParser, MESSAGE_FLAGS, SHELL_INTERPRETERS, DOWNLOAD_CMDS, NORMALIZE_CACHE_MAX, normalizeCache, codeBodiesCache, AST_CACHE_MAX, astCache, PARSE_FAIL, INTERPRETER_LINE, PROGRAM_DIR, ACCESS_VIEW_CACHE_MAX, accessViewCache, MAX_READING_PAYLOADS, STDIN_CODE_INTERPRETERS, RUNS_TEXT_ELSEWHERE, defaultExpansionOps, EMPTY_NAMES, VARIABLE_READERS, PLAIN_PROGRAM_NAME, FS_READ_TOOLS, GREP_SHAPE, PATTERN_VERBS, PATTERN_VERB_NAMES, GREP_FILE_OPERANDS, READER_VALUE_LETTERS, FILE_OPERAND_FLAGS, SCP_VALUE_FLAGS, CURL_SOURCE_FLAGS, CURL_VALUE_LETTERS, WGET_VALUE_LETTERS, TAR_VALUE_LETTERS, ZIP_VALUE_LETTERS, RSYNC_VALUE_LETTERS, RSYNC_SKIP, CP_VALUE_LETTERS, INSTALL_VALUE_LETTERS, COPY_VERBS, TAR_MODE_WORD, COPY_VERB_HEADS, FS_OP_PRESCREEN_RE, HOME_CACHE_ALLOWLIST, SENSITIVE_PATH_RULES, AST_FS_REGEX_RULES, SQL_DB_CLIS, SQL_DDL_RE, CHMOD_OPEN_PERM_TOKENS, COMMAND_WRAPPERS, INLINE_INTERPRETER, RUNNER_WRAPPERS, _redirStdinOps, _listOps, WRAPPER_TAKES_TARGET, FIND_EXEC_FLAGS, FS_MUTATION_TOOLS, INTERP_LEADING_TARGET, MAX_PAYLOAD_NESTING, payloadNesting, MAX_INLINE_CALLS, INLINE_EXEC_FALLBACK, UNREADABLE_SOURCE, SCRIPT_RUNNERS, SCRIPT_RUNNER_VALUE_FLAGS, MAX_SCRIPT_OPERANDS, NET_BINARIES, VALUE_FLAGS, HOME_VARIABLES, assignmentTable, currentStmtOffset, PAYLOAD_BUDGET, payloadBudget, seenPayloads, UNANALYSABLE_NESTING, ASSIGNMENT_HEADS, andOrOps, ARRAY_MARK, ARRAY_SEP, MAX_CALL_DEPTH2, MAX_CALL_WALKS2, callDepth, callWalks, FS_OP_CACHE_MAX, fsOpCache, stripDotSlash, REDIR_TRUNCATE_OPS, REDIR_FILE_IN_OPS, REDIR_HEREDOC_OPS, FIND_OPTIONS, COPY_RULE_OF, INDIRECT_SHAPE_RE, SOURCES_FILE_RE, SHELL_SET_VARS, pipeOps, callWords, JAILED_GLOB_NAMES, JAILED_DIR_NAMES, shellGlob, GLOB_META, isReaderWord, positionalAfter, NONE, UNKNOWN, FORBIDDEN_PATH_SEGMENTS, BASH_TOOL_NAMES, MCP_EXECUTORS, BUILTIN_FIELDS, ARGV_FIELDS, BARE_WORD, MAX_ARGV_CHARACTERS, exempt, RANK, SEQUENCE_OPS, BIP39_ENGLISH, BIP39_PUBLIC_VECTORS, indices, lengths, hash, MAX_MNEMONIC_HASHES, SECRET_VIEW_LIMITS, IBAN_LENGTH, IBAN_BBAN_SHAPE, B58, B58_INDEX, XPRV_VERSIONS, B62, CRC32_TABLE, GITHUB_TOKEN_RE, B64URL, B64URL_INDEX, CASK_TWO_ZERO_SUFFIX, CASK_FOUR_ZERO_SUFFIX, CF_ODD, CF_EVEN, SPANISH_LETTERS, HETU_CHARS, VERHOEFF_D, VERHOEFF_P, MAX, UNTRUSTED_TOOLS, INJECTION_SIGNALS, MENTION_QUOTE_RE, MENTION_WORD_RE, ASSIGNMENT_CONTEXT_RE, DLP_STOPWORDS, REFERENCE_VALUE_RE, IDENTIFIER_VALUE_RE, PATH_VALUE_RE, DOTTED_REFERENCE_RE, CONCATENATION_RE, EMAIL_VALUE_RE, FIXTURE_NAME_RE, DERIVATIVE_NAME_RE, QUERY_CREDENTIAL_VALUE_RE, OTP_SECRET_RE, OTP_DOC_SECRETS, ASSIGNED_SECRET_VALUE_RE, ASSIGNED_SECRET_NAME_RE, NAME_KEYWORD_RE, ARN_CONTEXT_RE, CIPHER_KEY_NAME_RE, CIPHER_NAME_PARTS, CIPHER_KEY_VALUE_RE, LARAVEL_KEY_VALUE_RE, SQL_PASSWORD_VALUE_RE, GRAFANA_KEY_VALUE_RE, BASIC_VALUE_RE, BASIC_PAIR_RE, BASIC_HEADER_RE, BASIC_HEADER_PAIR_RE, BASIC_PLACEHOLDER_RE, BASIC_TEMPLATE_MARKERS, DROPBOX_SECRET_RE, OTP_CAPTURE_RE, DB_URL_PASSWORD_RE, DLP_PATTERNS, DLP_PATTERNS_GLOBAL, SENSITIVE_PATH_PATTERNS, SENSITIVE_PATH_REGEXES, MAX_DEPTH2, MAX_STRING_BYTES, MAX_JSON_PARSE_BYTES, DLP_SCAN_LIMITS, BATCH_SEPARATOR, ENCODED_RUN_RE, IMPERATIVE, SECRET_TARGET, GUARD, SIGNALS, DESTINATION_RE, REUSED_SIGNALS, NEVER_NEGATED, NEGATION_BEFORE, RDR_IN, COPY_VERBS2, LITERAL_VERBS, GIT_PRESCREEN_RE, MAX_PAYLOAD_DEPTH2, MAX_ALIAS_DEPTH, CACHE_MAX, cache, PAYLOAD_SHELLS, CONFIG_SCOPE_FLAGS, CONFIG_VALUE_FLAGS, GLOBAL_VALUE_OPTIONS, GLOBAL_FLAG_OPTIONS, MAX_LOOP_ITEMS, GitWalk, POSITIONAL2, NO_VARS, NO_APPENDS, FORCE_PUSH, DESTRUCTIVE, UNREADABLE, PUSH_LONG_VALUE, BRANCH_LONG_VALUE, TAG_LONG_VALUE, CLEAN_LONG_VALUE, RESTORE_LONG_VALUE, CHECKOUT_LONG_VALUE, HOOKS_BYPASS, NO_VERIFY_SUBS, HOOK_KILL_SWITCHES, COMMIT_LONG_VALUE, CHMOD_OPTION_RE, _appendOp, STAGE_ALL, ADD_LONG_VALUE, CHECK_ID, RULE_NAME, INERT_LINE_RE, CHECK_ID2, INSTRUCTION_NAMES, SETTINGS_RE, HOOK_WORDS_RE, SHELLS, NETCATS, NET_CLIENTS, SENDERS, NETCAT_EXEC_LONG, DECL_DUMPS, PROC_ENVIRON_RE, DEV_NET_RE, SOCAT_PROGRAM_RE, SOCAT_NET_RE, PRESCREEN_RE, MAX_PAYLOAD_DEPTH3, CACHE_MAX2, cache2, dupInOp, REVERSE_SHELL_DESCRIPTION, ENV_EXFIL_DESCRIPTION, DYNAMIC_WORD, MULTICALL, SHELL_VALUE_OPTIONS, INTERPRETERS, OutboundWalk, NPM_INSTALL_VERBS, NPM_EXEC_VERBS, PNPM_INSTALL_VERBS, YARN_INSTALL_VERBS, BUN_INSTALL_VERBS, DLX_VERBS, NON_REGISTRY_RE, NPM_NAME_RE, EXACT_SEMVER_RE, NPM_VALUE_FLAGS, PNPM_VALUE_FLAGS, YARN_VALUE_FLAGS, BUN_VALUE_FLAGS, PIP_VALUE_FLAGS, UV_VALUE_FLAGS, POETRY_VALUE_FLAGS, PIPENV_VALUE_FLAGS, PIPX_VALUE_FLAGS, PY_SPEC_RE, PY_EXACT_RE, EXACT_VERSION_RE, GEM_NAME_RE, GEM_VALUE_FLAGS, BUNDLE_VALUE_FLAGS, CRATE_NAME_RE, CARGO_ADD_VALUE_FLAGS, CARGO_INSTALL_VALUE_FLAGS, GO_VALUE_FLAGS, GO_PATH_RE, NUGET_NAME_RE, DOTNET_ADD_VALUE_FLAGS, DOTNET_TOOL_VALUE_FLAGS, NUGET_VALUE_FLAGS, MAVEN_COORD_RE, COMPOSER_NAME_RE, COMPOSER_VALUE_FLAGS, EDITOR_HEADS, EXTENSION_ID_RE, MANAGER_HEADS, SHELLS2, MAX_NESTING, SHELL_VALUE_FLAGS, NPM_FAMILY, PIP_FAMILY, NPM_FETCH_VERBS, PIP_FETCH_VERBS, NPM_FLAGS, PIP_FLAGS, NPM_VARS, PIP_VARS, PRESCREEN_RE2, PIP_ATTACHED_RE, MAX_PAYLOAD_DEPTH4, PUBLIC_REGISTRY_HOSTS, TUNING_FIELDS, MAP_GOVERNED, KNOB_GOVERNED, CONFIGURABLE_CHECK_IDS, DEFAULT_EGRESS_ALLOWLIST, PRIVATE_HOST_SUFFIXES, SOURCE_COMMANDS, SINK_COMMANDS, OBFUSCATORS, SENSITIVE_PATTERNS, FLAGS_WITH_VALUES, DESTINATION_ARGS, MCP_DESTINATION_KEYS, ARGUMENT_SCAN_LIMITS, RUN_CHAR, runChar, VERDICT_RANK, SQL_DML_KEYWORDS, MAX_DESTINATIONS, MAX_SCAN_CHARS, EMAIL_RE, URL_RE, IBAN_RE, RECIPIENT_KEYS, DESTRUCTIVE_VERB_RE, PII_EMAIL_RE, PII_SSN_RE, PII_PHONE_RE, PII_CC16_RE, PII_CC15_RE, PII_CC14_RE, PII_CC13_RE, PII_CC19_RE, CARD_PATTERNS, PII_ROUTING_RE, ROUTING_LABEL_RE, ROUTING_LABEL_WINDOW, NATIONAL_ID_SHAPES, NATIONAL_ID_LABEL_RE, NATIONAL_ID_LABEL_CS_RE, idLabelIn, NATIONAL_ID_LABEL_WINDOW, NATIONAL_ID_GUARD_RE, PII_IBAN_RE, REALTIME_PII_PATTERNS, MAX_PII_SCAN_BYTES, IBAN_DESTINATION_KEYS, WHOLE_IBAN_RE, JSON_ESCAPE_RE, JSON_ESCAPES, MASKED_KINDS, ENTRY_RE, IBAN_TEXT_RE, EMAIL_TEXT_RE, ACCOUNT_KEY_RE, ACCOUNT_VALUE_RE, MAX_MASK_DEPTH, EMPTY, CURL_SEND_FLAGS, WGET_SEND_FLAGS, IWR_SEND_FLAGS, WRITE_METHODS, GH_READ, GH_WRITE, GH_HOSTNAME_FLAGS, GH_REPO_VALUE_FLAGS, GH_API_VALUE_FLAGS, GIT_FETCH, PUBLISH, SHELLS3, OWN_HEADS, MAX_DEPTH3, CWD_CHANGERS, TERMINAL_ESCAPE_RE, CONTROL_CHAR_RE, LOOP_MAX_RECORDS, CANARY_MIN_LENGTH, MAX_TEXT, MAX_DEPTH4, MAX_JSON_PARSE, URL_DEPTH, B64_DEPTH, MIN_SEGMENT, SEPARATORS, stripSeparators, looksText, CANARY_DECODERS, VIEWS, LONG_OUTPUT_THRESHOLD_BYTES;
|
|
9572
9923
|
var init_dist = __esm({
|
|
9573
9924
|
"packages/policy-engine/dist/index.mjs"() {
|
|
9574
9925
|
"use strict";
|
|
@@ -12846,6 +13197,7 @@ var init_dist = __esm({
|
|
|
12846
13197
|
"sqlite3"
|
|
12847
13198
|
]);
|
|
12848
13199
|
defaultExpansionOps = null;
|
|
13200
|
+
EMPTY_NAMES = /* @__PURE__ */ new Set();
|
|
12849
13201
|
VARIABLE_READERS = /* @__PURE__ */ new Set([
|
|
12850
13202
|
"read",
|
|
12851
13203
|
"mapfile",
|
|
@@ -12858,6 +13210,7 @@ var init_dist = __esm({
|
|
|
12858
13210
|
"readonly",
|
|
12859
13211
|
"printf"
|
|
12860
13212
|
]);
|
|
13213
|
+
PLAIN_PROGRAM_NAME = /^[A-Za-z_][\w.+-]*$/;
|
|
12861
13214
|
FS_READ_TOOLS = /* @__PURE__ */ new Set([
|
|
12862
13215
|
"cat",
|
|
12863
13216
|
"less",
|
|
@@ -13752,6 +14105,8 @@ var init_dist = __esm({
|
|
|
13752
14105
|
AND_OR_OPS: new Set([and, or].filter((o) => o !== null))
|
|
13753
14106
|
};
|
|
13754
14107
|
});
|
|
14108
|
+
ARRAY_MARK = "array";
|
|
14109
|
+
ARRAY_SEP = "";
|
|
13755
14110
|
MAX_CALL_DEPTH2 = 4;
|
|
13756
14111
|
MAX_CALL_WALKS2 = 256;
|
|
13757
14112
|
callDepth = 0;
|
|
@@ -17089,7 +17444,22 @@ zoo`.split("\n");
|
|
|
17089
17444
|
found;
|
|
17090
17445
|
/** Aliases defined earlier in this command: name -> value (null = dynamic). */
|
|
17091
17446
|
aliases = /* @__PURE__ */ new Map();
|
|
17447
|
+
/** node9Firewall#385: variables assigned a tree-top word (`scope="$PWD"`,
|
|
17448
|
+
* `root=$(git rev-parse --show-toplevel)`, `DIR=$(pwd)`), so the
|
|
17449
|
+
* variable reads as the top where it is used. */
|
|
17450
|
+
treeTopVars = /* @__PURE__ */ new Set();
|
|
17451
|
+
/** node9Firewall#385 (c): a string a script builds with `+=` from
|
|
17452
|
+
* literals (`mode=--ha; mode+=rd`). The jail's table does not follow an
|
|
17453
|
+
* append (JAIL-14a); the git rules read the built word, since a flag
|
|
17454
|
+
* spelled in two halves is still that flag. name -> value, null once a
|
|
17455
|
+
* half is unknown. */
|
|
17456
|
+
appended = /* @__PURE__ */ new Map();
|
|
17092
17457
|
payloads = /* @__PURE__ */ new Set();
|
|
17458
|
+
/** node9Firewall#385 (a): the text this command writes to each path
|
|
17459
|
+
* (`cat > /tmp/x.sh <<'SH' ... SH`, `echo '...' > f`, `>>` appends), so
|
|
17460
|
+
* a later statement that runs the path (`bash f`, `sh f`, `./f`) is
|
|
17461
|
+
* judged on what it runs. null once a write to the path is unknown. */
|
|
17462
|
+
written = /* @__PURE__ */ new Map();
|
|
17093
17463
|
/** `for NAME in a b c`: the literal items, or null when one is dynamic. */
|
|
17094
17464
|
loopVars = /* @__PURE__ */ new Map();
|
|
17095
17465
|
/** Walk one command string. Returns false when it did not parse. */
|
|
@@ -17108,6 +17478,25 @@ zoo`.split("\n");
|
|
|
17108
17478
|
const type = n.kind;
|
|
17109
17479
|
if (type === "Stmt") {
|
|
17110
17480
|
this.visitHeredocShell(n, depth);
|
|
17481
|
+
this.visitPipeline(n, depth);
|
|
17482
|
+
this.visitHookWrite(n);
|
|
17483
|
+
this.recordScriptWrite(n);
|
|
17484
|
+
this.visitWrittenScript(n, depth);
|
|
17485
|
+
return true;
|
|
17486
|
+
}
|
|
17487
|
+
if (type === "Assign" && n.Name?.Value && n.Value) {
|
|
17488
|
+
const name = n.Name.Value;
|
|
17489
|
+
if (n.Append) {
|
|
17490
|
+
const prev = this.appended.has(name) ? this.appended.get(name) : resolveWordLiteral(n.Value) === null ? null : void 0;
|
|
17491
|
+
const base2 = prev === void 0 ? recordedExpansion(name) : prev;
|
|
17492
|
+
const piece = resolveWordLiteral(n.Value);
|
|
17493
|
+
this.appended.set(name, typeof base2 === "string" && piece !== null ? base2 + piece : null);
|
|
17494
|
+
this.treeTopVars.delete(name);
|
|
17495
|
+
return true;
|
|
17496
|
+
}
|
|
17497
|
+
this.appended.delete(name);
|
|
17498
|
+
if (treeTopWord(n.Value, this.treeTopVars)) this.treeTopVars.add(name);
|
|
17499
|
+
else this.treeTopVars.delete(name);
|
|
17111
17500
|
return true;
|
|
17112
17501
|
}
|
|
17113
17502
|
if (type === "ForClause") {
|
|
@@ -17136,13 +17525,13 @@ zoo`.split("\n");
|
|
|
17136
17525
|
const param = plainParamName(rawArgs[loopArg]);
|
|
17137
17526
|
for (const item of this.loopVars.get(param.name)) {
|
|
17138
17527
|
const words2 = rawArgs.flatMap(
|
|
17139
|
-
(a, i) => i === loopArg ? param.quoted ? [item] : splitFields(item) : resolveGitWords(a)
|
|
17528
|
+
(a, i) => i === loopArg ? param.quoted ? [item] : splitFields(item) : resolveGitWords(a, this.treeTopVars, this.appended)
|
|
17140
17529
|
);
|
|
17141
17530
|
this.visitWords(words2, new Map(prefixEnv), depth, false);
|
|
17142
17531
|
}
|
|
17143
17532
|
return true;
|
|
17144
17533
|
}
|
|
17145
|
-
const words = rawArgs.flatMap((a) => resolveGitWords(a));
|
|
17534
|
+
const words = rawArgs.flatMap((a) => resolveGitWords(a, this.treeTopVars, this.appended));
|
|
17146
17535
|
this.visitWords(words, prefixEnv, depth, false);
|
|
17147
17536
|
return true;
|
|
17148
17537
|
}
|
|
@@ -17167,6 +17556,23 @@ zoo`.split("\n");
|
|
|
17167
17556
|
if (f) this.found(f);
|
|
17168
17557
|
return;
|
|
17169
17558
|
}
|
|
17559
|
+
if (headWord === "rm" || headWord === "unlink") {
|
|
17560
|
+
if (words.slice(head + 1).some((w) => w !== null && isLiveHookFile(w)))
|
|
17561
|
+
this.found(hooksBypassed(shownOf(words)));
|
|
17562
|
+
return;
|
|
17563
|
+
}
|
|
17564
|
+
if (headWord === "mv") {
|
|
17565
|
+
const operands2 = words.slice(head + 1).filter((w) => w === null || !w.startsWith("-"));
|
|
17566
|
+
const src = operands2[0];
|
|
17567
|
+
if (typeof src === "string" && isLiveHookFile(src)) this.found(hooksBypassed(shownOf(words)));
|
|
17568
|
+
return;
|
|
17569
|
+
}
|
|
17570
|
+
if (headWord === "perl") {
|
|
17571
|
+
const code = words.slice(head + 1).find((w) => w !== null && /\brename\b/.test(w));
|
|
17572
|
+
const m = code ? /rename\s*\(?\s*q[qw]?\s*[(\[{<'"]([^)\]}>'"]+)/.exec(code) : null;
|
|
17573
|
+
if (m && isLiveHookFile(m[1])) this.found(hooksBypassed(shownOf(words)));
|
|
17574
|
+
return;
|
|
17575
|
+
}
|
|
17170
17576
|
if (depth < MAX_PAYLOAD_DEPTH2) {
|
|
17171
17577
|
const payload = literalShellPayload(words, baseWord(words[0]));
|
|
17172
17578
|
if (payload !== null) this.runPayload(payload, depth);
|
|
@@ -17177,6 +17583,127 @@ zoo`.split("\n");
|
|
|
17177
17583
|
this.payloads.add(payload);
|
|
17178
17584
|
this.run(payload, depth + 1);
|
|
17179
17585
|
}
|
|
17586
|
+
/**
|
|
17587
|
+
* node9Firewall#385: a pipeline whose last stage reads its pathspec from
|
|
17588
|
+
* stdin (`git add --pathspec-from-file=-`) or runs git over the names it
|
|
17589
|
+
* is fed (`xargs -0 git add --`), with a producer that is one literal
|
|
17590
|
+
* (`git rev-parse --show-toplevel`, `printf '%s\0' .`): the literal is
|
|
17591
|
+
* the operand, and the call is judged with it.
|
|
17592
|
+
*/
|
|
17593
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
17594
|
+
visitPipeline(stmt, depth) {
|
|
17595
|
+
const cmd = stmt.Cmd;
|
|
17596
|
+
if (!cmd || cmd.kind !== "BinaryCmd" || !isPipeOp(cmd.Op)) return;
|
|
17597
|
+
const stages = [];
|
|
17598
|
+
let cur = cmd;
|
|
17599
|
+
while (cur?.kind === "BinaryCmd" && isPipeOp(cur.Op)) {
|
|
17600
|
+
stages.unshift(cur.Y);
|
|
17601
|
+
const left = cur.X;
|
|
17602
|
+
if (left?.Cmd?.kind === "BinaryCmd" && isPipeOp(left.Cmd.Op)) cur = left.Cmd;
|
|
17603
|
+
else {
|
|
17604
|
+
stages.unshift(left);
|
|
17605
|
+
break;
|
|
17606
|
+
}
|
|
17607
|
+
}
|
|
17608
|
+
if (stages.length < 2) return;
|
|
17609
|
+
const producer = stages[stages.length - 2]?.Cmd;
|
|
17610
|
+
const consumer = stages[stages.length - 1]?.Cmd;
|
|
17611
|
+
if (!producer || !consumer || producer.kind !== "CallExpr" || consumer.kind !== "CallExpr")
|
|
17612
|
+
return;
|
|
17613
|
+
const fed = producedLiteral(producer);
|
|
17614
|
+
if (fed === null) return;
|
|
17615
|
+
const words = (consumer.Args || []).flatMap(
|
|
17616
|
+
(a) => resolveGitWords(a, this.treeTopVars, this.appended)
|
|
17617
|
+
);
|
|
17618
|
+
const head = unwrapCommandHead(words);
|
|
17619
|
+
const viaXargs = words.slice(0, head).some((w) => baseWord(w) === "xargs");
|
|
17620
|
+
const fromFile = words.findIndex(
|
|
17621
|
+
(w) => w === "--pathspec-from-file=-" || w === "--pathspec-from-file"
|
|
17622
|
+
);
|
|
17623
|
+
if (!viaXargs && fromFile < 0) return;
|
|
17624
|
+
let fedWords;
|
|
17625
|
+
if (fromFile >= 0) {
|
|
17626
|
+
fedWords = words.filter(
|
|
17627
|
+
(w, k) => !(k === fromFile || w === "-" && words[k - 1] === "--pathspec-from-file")
|
|
17628
|
+
);
|
|
17629
|
+
fedWords.push(fed);
|
|
17630
|
+
} else fedWords = [...words, fed];
|
|
17631
|
+
this.visitWords(fedWords, /* @__PURE__ */ new Map(), depth, false);
|
|
17632
|
+
}
|
|
17633
|
+
/**
|
|
17634
|
+
* node9Firewall#385 (e): a hook file written with a body that checks
|
|
17635
|
+
* nothing (`cat > .githooks/pre-commit <<'SH' exit 0 SH`, `echo 'exit 0'
|
|
17636
|
+
* > .git/hooks/pre-push`, `: > .githooks/pre-commit`). A real body (a
|
|
17637
|
+
* test, a linter) is ordinary work on the hooks.
|
|
17638
|
+
*/
|
|
17639
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
17640
|
+
visitHookWrite(stmt) {
|
|
17641
|
+
const cmd = stmt.Cmd;
|
|
17642
|
+
if (!cmd || cmd.kind !== "CallExpr") return;
|
|
17643
|
+
const redirs = stmt.Redirs || [];
|
|
17644
|
+
const target = redirs.find((r) => r?.Word && !r.Hdoc && (r.N == null || r.N.Value === "1"));
|
|
17645
|
+
if (!target) return;
|
|
17646
|
+
const path210 = resolveWordLiteral(target.Word);
|
|
17647
|
+
if (path210 === null || !isLiveHookFile(path210)) return;
|
|
17648
|
+
const hdoc = redirs.find((r) => r?.Hdoc);
|
|
17649
|
+
const words = (cmd.Args || []).map((a) => resolveWordLiteral(a));
|
|
17650
|
+
const head = baseWord(words[0]);
|
|
17651
|
+
let body = null;
|
|
17652
|
+
if (hdoc) body = resolveWordLiteral(hdoc.Hdoc);
|
|
17653
|
+
else if (head === ":" || head === "true" || words.length === 0) body = "";
|
|
17654
|
+
else if (head === "echo" || head === "printf") {
|
|
17655
|
+
const rest = words.slice(1);
|
|
17656
|
+
body = rest.some((w) => w === null) ? null : rest.filter((w) => !/^-[neE]+$/.test(w)).join(" ");
|
|
17657
|
+
if (body !== null) body = body.replace(/\\n/g, "\n");
|
|
17658
|
+
}
|
|
17659
|
+
if (body !== null && hookBodyIsEmpty(body)) this.found(hooksBypassed(shownOf(words)));
|
|
17660
|
+
}
|
|
17661
|
+
/** A statement that writes a literal text to a path, by redirect. */
|
|
17662
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
17663
|
+
recordScriptWrite(stmt) {
|
|
17664
|
+
const cmd = stmt.Cmd;
|
|
17665
|
+
if (!cmd || cmd.kind !== "CallExpr") return;
|
|
17666
|
+
const redirs = stmt.Redirs || [];
|
|
17667
|
+
const target = redirs.find((r) => r?.Word && !r.Hdoc && (r.N == null || r.N.Value === "1"));
|
|
17668
|
+
if (!target) return;
|
|
17669
|
+
const path210 = resolveWordLiteral(target.Word);
|
|
17670
|
+
if (path210 === null) return;
|
|
17671
|
+
const append = /^>>/.test(target.Op?.toString() ?? "") || redirOpIsAppend(target);
|
|
17672
|
+
const hdoc = redirs.find((r) => r?.Hdoc);
|
|
17673
|
+
const words = (cmd.Args || []).map((a) => resolveWordLiteral(a));
|
|
17674
|
+
const head = baseWord(words[0]);
|
|
17675
|
+
let text = null;
|
|
17676
|
+
if (hdoc && (head === "cat" || head === "tee")) text = resolveWordLiteral(hdoc.Hdoc);
|
|
17677
|
+
else if (head === "echo" || head === "printf") {
|
|
17678
|
+
const rest = words.slice(1);
|
|
17679
|
+
text = rest.some((w) => w === null) ? null : rest.filter((w) => !/^-[neE]+$/.test(w)).join(" ");
|
|
17680
|
+
if (text !== null && head === "printf") text = text.replace(/\\n/g, "\n");
|
|
17681
|
+
} else return;
|
|
17682
|
+
const prev = this.written.get(path210);
|
|
17683
|
+
if (text === null || append && prev === null) this.written.set(path210, null);
|
|
17684
|
+
else this.written.set(path210, append && typeof prev === "string" ? `${prev}
|
|
17685
|
+
${text}` : text);
|
|
17686
|
+
}
|
|
17687
|
+
/** A statement that runs a path this command wrote: the text is the script. */
|
|
17688
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
17689
|
+
visitWrittenScript(stmt, depth) {
|
|
17690
|
+
const cmd = stmt.Cmd;
|
|
17691
|
+
if (!cmd || cmd.kind !== "CallExpr" || this.written.size === 0 || depth >= MAX_PAYLOAD_DEPTH2)
|
|
17692
|
+
return;
|
|
17693
|
+
const words = (cmd.Args || []).map((a) => resolveWordLiteral(a));
|
|
17694
|
+
const head = unwrapCommandHead(words);
|
|
17695
|
+
const name = baseWord(words[head]);
|
|
17696
|
+
let ran = null;
|
|
17697
|
+
if (PAYLOAD_SHELLS.has(name) && name !== "eval") {
|
|
17698
|
+
const operand = words.slice(head + 1).find((w) => w === null || !w.startsWith("-"));
|
|
17699
|
+
if (typeof operand === "string") ran = operand;
|
|
17700
|
+
} else if (typeof words[head] === "string" && this.written.has(words[head])) {
|
|
17701
|
+
ran = words[head];
|
|
17702
|
+
}
|
|
17703
|
+
if (ran === null) return;
|
|
17704
|
+
const text = this.written.get(ran);
|
|
17705
|
+
if (typeof text === "string") this.runPayload(text, depth);
|
|
17706
|
+
}
|
|
17180
17707
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
17181
17708
|
visitHeredocShell(stmt, depth) {
|
|
17182
17709
|
const cmd = stmt.Cmd;
|
|
@@ -17328,6 +17855,8 @@ zoo`.split("\n");
|
|
|
17328
17855
|
}
|
|
17329
17856
|
};
|
|
17330
17857
|
POSITIONAL2 = "\0positional";
|
|
17858
|
+
NO_VARS = /* @__PURE__ */ new Set();
|
|
17859
|
+
NO_APPENDS = /* @__PURE__ */ new Map();
|
|
17331
17860
|
FORCE_PUSH = {
|
|
17332
17861
|
checkId: "commands.git-destructive",
|
|
17333
17862
|
ruleName: "review-force-push",
|
|
@@ -17386,6 +17915,8 @@ zoo`.split("\n");
|
|
|
17386
17915
|
"--cleanup"
|
|
17387
17916
|
]);
|
|
17388
17917
|
CLEAN_LONG_VALUE = /* @__PURE__ */ new Set(["--exclude"]);
|
|
17918
|
+
RESTORE_LONG_VALUE = /* @__PURE__ */ new Set(["--source", "--pathspec-from-file"]);
|
|
17919
|
+
CHECKOUT_LONG_VALUE = /* @__PURE__ */ new Set(["--pathspec-from-file", "--orphan", "--conflict"]);
|
|
17389
17920
|
HOOKS_BYPASS = {
|
|
17390
17921
|
checkId: "commands.git-hooks-bypass",
|
|
17391
17922
|
ruleName: "review-git-hooks-bypass",
|
|
@@ -17411,6 +17942,7 @@ zoo`.split("\n");
|
|
|
17411
17942
|
"--gpg-sign"
|
|
17412
17943
|
]);
|
|
17413
17944
|
CHMOD_OPTION_RE = /^-[RvcfHLP]+$/;
|
|
17945
|
+
_appendOp = null;
|
|
17414
17946
|
STAGE_ALL = {
|
|
17415
17947
|
checkId: "commands.git-stage-all",
|
|
17416
17948
|
ruleName: "review-git-stage-all",
|
|
@@ -17535,7 +18067,7 @@ zoo`.split("\n");
|
|
|
17535
18067
|
this.visitStmt(n, depth);
|
|
17536
18068
|
return true;
|
|
17537
18069
|
}
|
|
17538
|
-
if (type === "BinaryCmd" &&
|
|
18070
|
+
if (type === "BinaryCmd" && isPipeOp2(n.Op)) {
|
|
17539
18071
|
this.visitPipeline(n);
|
|
17540
18072
|
return true;
|
|
17541
18073
|
}
|
|
@@ -17636,7 +18168,7 @@ zoo`.split("\n");
|
|
|
17636
18168
|
const stages = [];
|
|
17637
18169
|
const flatten = (s) => {
|
|
17638
18170
|
const c = s?.Cmd;
|
|
17639
|
-
if (c && c.kind === "BinaryCmd" &&
|
|
18171
|
+
if (c && c.kind === "BinaryCmd" && isPipeOp2(c.Op)) {
|
|
17640
18172
|
flatten(c.X);
|
|
17641
18173
|
flatten(c.Y);
|
|
17642
18174
|
} else stages.push(s);
|
|
@@ -19265,11 +19797,18 @@ function slug(s) {
|
|
|
19265
19797
|
var B = "[\\s/\\\\]";
|
|
19266
19798
|
var SEP = "[/\\\\]";
|
|
19267
19799
|
function pathToRegexFragment(rawPath) {
|
|
19268
|
-
const
|
|
19800
|
+
const trimmed = rawPath.trim();
|
|
19801
|
+
const tail = trimmed.replace(/^~[\\/]?/, "").replace(/^\$\{?HOME\}?[\\/]?/, "").replace(/^\/(?:home|Users)\/[^\\/]+[\\/]?/, "").replace(/^[A-Za-z]:[\\/]Users[\\/][^\\/]+[\\/]?/, "").replace(/^[\\/]+/, "").replace(/[\\/]+$/, "");
|
|
19269
19802
|
const segments2 = tail.split(/[\\/]+/).filter(Boolean).map(escapeRegex);
|
|
19270
19803
|
if (segments2.length === 0) return "";
|
|
19804
|
+
if (isAbsoluteOutsideHome(trimmed)) {
|
|
19805
|
+
return `(^|[^A-Za-z0-9_.~\\/-])/${segments2.join(SEP)}(${B}|$)`;
|
|
19806
|
+
}
|
|
19271
19807
|
return `(^|${B})${segments2.join(SEP)}(${B}|$)`;
|
|
19272
19808
|
}
|
|
19809
|
+
function isAbsoluteOutsideHome(p) {
|
|
19810
|
+
return p.startsWith("/") && !/^\/(?:home|Users|root)(?:\/|$)/.test(p);
|
|
19811
|
+
}
|
|
19273
19812
|
function pathMatchesFragment(candidate, rawPath) {
|
|
19274
19813
|
const value = pathToRegexFragment(rawPath);
|
|
19275
19814
|
if (!value || !candidate) return false;
|
|
@@ -22303,7 +22842,8 @@ var DEFAULT_CONFIG = {
|
|
|
22303
22842
|
trustedHostsManaged: false,
|
|
22304
22843
|
appPermissions: {},
|
|
22305
22844
|
appLinks: {},
|
|
22306
|
-
managedJailPaths: []
|
|
22845
|
+
managedJailPaths: [],
|
|
22846
|
+
jailPaths: []
|
|
22307
22847
|
},
|
|
22308
22848
|
environments: {}
|
|
22309
22849
|
};
|
|
@@ -22543,7 +23083,8 @@ function getConfig(cwd) {
|
|
|
22543
23083
|
trustedHostsManaged: false,
|
|
22544
23084
|
appPermissions: {},
|
|
22545
23085
|
appLinks: {},
|
|
22546
|
-
managedJailPaths: []
|
|
23086
|
+
managedJailPaths: [],
|
|
23087
|
+
jailPaths: []
|
|
22547
23088
|
};
|
|
22548
23089
|
const mergedEnvironments = { ...DEFAULT_CONFIG.environments };
|
|
22549
23090
|
const rank = (v) => {
|
|
@@ -22938,6 +23479,7 @@ function getConfig(cwd) {
|
|
|
22938
23479
|
mergedPolicy.smartRules.push({ ...r, name: `org:${r.name}` });
|
|
22939
23480
|
}
|
|
22940
23481
|
mergedPolicy.managedJailPaths.push({ path: path41, verdict });
|
|
23482
|
+
mergedPolicy.jailPaths.push(path41);
|
|
22941
23483
|
}
|
|
22942
23484
|
}
|
|
22943
23485
|
if (Array.isArray(mc.trustedHosts)) {
|
|
@@ -23013,6 +23555,11 @@ function getConfig(cwd) {
|
|
|
23013
23555
|
}
|
|
23014
23556
|
}
|
|
23015
23557
|
mergedPolicy.appliedShields = appliedShields.sort();
|
|
23558
|
+
if (appliedShields.includes(USER_JAIL_SHIELD)) {
|
|
23559
|
+
for (const { path: path41 } of readJailPaths()) {
|
|
23560
|
+
if (!mergedPolicy.jailPaths.includes(path41)) mergedPolicy.jailPaths.push(path41);
|
|
23561
|
+
}
|
|
23562
|
+
}
|
|
23016
23563
|
const existingAdvisoryNames = new Set(mergedPolicy.smartRules.map((r) => r.name));
|
|
23017
23564
|
const cc = mergedPolicy.commandChecks ?? {};
|
|
23018
23565
|
const advisoryKnobKey = (name) => {
|