@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/dashboard.mjs
CHANGED
|
@@ -2141,9 +2141,15 @@ function detectDangerousShellExec(command) {
|
|
|
2141
2141
|
if (f === PARSE_FAIL) return null;
|
|
2142
2142
|
let result = null;
|
|
2143
2143
|
const assigned = assignedNames(f);
|
|
2144
|
-
|
|
2144
|
+
const known = plainlyNamedPrograms(f);
|
|
2145
|
+
const calledByName = literallyCalledFunctions(f);
|
|
2146
|
+
const bodies = [];
|
|
2147
|
+
const inBody = (pos) => bodies.some(([a, b]) => pos >= a && pos < b);
|
|
2148
|
+
walkWithCalls(f, (node) => {
|
|
2145
2149
|
if (!node || result === "block") return false;
|
|
2146
2150
|
const n = node;
|
|
2151
|
+
if (n.kind === "FuncDecl" && n.Body && callDepth === 0 && calledByName.has(n.Name?.Value))
|
|
2152
|
+
bodies.push([n.Body.pos, n.Body.end]);
|
|
2147
2153
|
if (n.kind === "BinaryCmd" && n.Y && !listOps().has(n.Op)) {
|
|
2148
2154
|
const call = n.Y.Cmd;
|
|
2149
2155
|
if (call && call.kind === "CallExpr") {
|
|
@@ -2167,7 +2173,8 @@ function detectDangerousShellExec(command) {
|
|
|
2167
2173
|
);
|
|
2168
2174
|
const head = unwrapCommandHead(headWords, false, true);
|
|
2169
2175
|
const lookup = headWords[0]?.toLowerCase() === "command" && headWords.slice(1).some((w) => w === "-v" || w === "-V");
|
|
2170
|
-
|
|
2176
|
+
const unboundBody = callDepth === 0 && inBody(n.pos ?? -1);
|
|
2177
|
+
if (!lookup && !unboundBody && (opaqueExecutable(args[0], assigned, known) || opaqueExecutable(args[head], assigned, known)))
|
|
2171
2178
|
result = "review";
|
|
2172
2179
|
const firstParts = args[0].Parts || [];
|
|
2173
2180
|
if (firstParts.length !== 1 || firstParts[0].kind !== "Lit") return true;
|
|
@@ -2227,11 +2234,105 @@ function assignedNames(f) {
|
|
|
2227
2234
|
});
|
|
2228
2235
|
return names;
|
|
2229
2236
|
}
|
|
2230
|
-
function
|
|
2237
|
+
function literallyCalledFunctions(f) {
|
|
2238
|
+
const declared = /* @__PURE__ */ new Set();
|
|
2239
|
+
const called = /* @__PURE__ */ new Set();
|
|
2240
|
+
walk(f, (node) => {
|
|
2241
|
+
if (!node) return false;
|
|
2242
|
+
if (node.kind === "FuncDecl" && node.Name?.Value) declared.add(node.Name.Value);
|
|
2243
|
+
if (node.kind === "CallExpr") {
|
|
2244
|
+
const head = resolveWordLiteral(node.Args?.[0]);
|
|
2245
|
+
if (head) called.add(head);
|
|
2246
|
+
}
|
|
2247
|
+
return true;
|
|
2248
|
+
});
|
|
2249
|
+
return new Set([...declared].filter((name) => called.has(name)));
|
|
2250
|
+
}
|
|
2251
|
+
function plainlyNamedPrograms(f) {
|
|
2252
|
+
const values = /* @__PURE__ */ new Map();
|
|
2253
|
+
const arrays = /* @__PURE__ */ new Set();
|
|
2254
|
+
const give = (name, value) => {
|
|
2255
|
+
if (value === null || !PLAIN_PROGRAM_NAME.test(value)) {
|
|
2256
|
+
values.set(name, null);
|
|
2257
|
+
return;
|
|
2258
|
+
}
|
|
2259
|
+
const cur = values.get(name);
|
|
2260
|
+
if (cur === null) return;
|
|
2261
|
+
if (cur === void 0) values.set(name, /* @__PURE__ */ new Set([value]));
|
|
2262
|
+
else cur.add(value);
|
|
2263
|
+
};
|
|
2264
|
+
const literalOnly = (w) => {
|
|
2265
|
+
const parts = w?.Parts ?? [];
|
|
2266
|
+
if (parts.length !== 1) return null;
|
|
2267
|
+
const p = parts[0];
|
|
2268
|
+
if (p.kind === "Lit") return p.Value ?? null;
|
|
2269
|
+
if (p.kind === "ParamExp" && expansionName(p) === "FUNCNAME") return "FUNCNAME";
|
|
2270
|
+
if (p.kind === "SglQuoted" && !p.Dollar) return p.Value ?? null;
|
|
2271
|
+
if (p.kind === "DblQuoted") {
|
|
2272
|
+
const inner = p.Parts ?? [];
|
|
2273
|
+
return inner.length === 1 && inner[0].kind === "Lit" ? inner[0].Value ?? null : null;
|
|
2274
|
+
}
|
|
2275
|
+
return null;
|
|
2276
|
+
};
|
|
2277
|
+
let ifsTouched = false;
|
|
2278
|
+
walk(f, (node) => {
|
|
2279
|
+
if (!node) return false;
|
|
2280
|
+
const kind = node.kind;
|
|
2281
|
+
if (kind === "FuncDecl" && node.Name?.Value) give(node.Name.Value, node.Name.Value);
|
|
2282
|
+
if (kind === "Assign" && node.Name?.Value) {
|
|
2283
|
+
const name = node.Name.Value;
|
|
2284
|
+
if (name === "IFS") ifsTouched = true;
|
|
2285
|
+
if (node.Append) values.set(name, null);
|
|
2286
|
+
else if (node.Array) {
|
|
2287
|
+
arrays.add(name);
|
|
2288
|
+
for (const el of node.Array.Elems ?? []) give(name, literalOnly(el.Value));
|
|
2289
|
+
} else if (node.Index) {
|
|
2290
|
+
arrays.add(name);
|
|
2291
|
+
give(name, node.Value ? literalOnly(node.Value) : null);
|
|
2292
|
+
} else give(name, node.Value ? literalOnly(node.Value) : null);
|
|
2293
|
+
}
|
|
2294
|
+
if (kind === "ForClause" && node.Loop?.Name?.Value) values.set(node.Loop.Name.Value, null);
|
|
2295
|
+
if (kind === "CallExpr") {
|
|
2296
|
+
const words = (node.Args ?? []).map((a) => resolveWordLiteral(a));
|
|
2297
|
+
if (VARIABLE_READERS.has(words[0] ?? "")) {
|
|
2298
|
+
for (const w of words.slice(1)) if (w && /^[A-Za-z_]\w*$/.test(w)) values.set(w, null);
|
|
2299
|
+
}
|
|
2300
|
+
}
|
|
2301
|
+
return true;
|
|
2302
|
+
});
|
|
2303
|
+
if (ifsTouched) return /* @__PURE__ */ new Set();
|
|
2304
|
+
const functions = /* @__PURE__ */ new Set();
|
|
2305
|
+
walk(f, (node) => {
|
|
2306
|
+
if (node && node.kind === "FuncDecl" && node.Name?.Value) functions.add(node.Name.Value);
|
|
2307
|
+
return true;
|
|
2308
|
+
});
|
|
2309
|
+
const callable = (v) => functions.has(v) || v === "FUNCNAME" || v === "true" || v === "false" || v === ":";
|
|
2310
|
+
for (const [name, vals] of values) {
|
|
2311
|
+
if (vals && ![...vals].every(callable)) values.set(name, null);
|
|
2312
|
+
}
|
|
2313
|
+
const known = /* @__PURE__ */ new Set();
|
|
2314
|
+
for (const [name, vals] of values)
|
|
2315
|
+
if (vals && (vals.size === 1 || arrays.has(name) && vals.size > 0)) known.add(name);
|
|
2316
|
+
return known;
|
|
2317
|
+
}
|
|
2318
|
+
function expansionName(part) {
|
|
2319
|
+
if (part.kind !== "ParamExp") return null;
|
|
2320
|
+
if (part.Excl || part.Length || part.Width || part.Slice || part.Repl || part.Exp) return null;
|
|
2321
|
+
return part.Param?.Value ?? null;
|
|
2322
|
+
}
|
|
2323
|
+
function executableParts(word, assigned, quoted = false, known = EMPTY_NAMES) {
|
|
2231
2324
|
return (word?.Parts ?? []).flatMap((part) => {
|
|
2232
2325
|
const kind = part.kind;
|
|
2233
|
-
if (kind === "DblQuoted") return executableParts(part, assigned, true);
|
|
2326
|
+
if (kind === "DblQuoted") return executableParts(part, assigned, true, known);
|
|
2234
2327
|
if (kind === "Lit") return [{ kind: "Lit", value: part.Value ?? "", quoted }];
|
|
2328
|
+
const name = expansionName(part);
|
|
2329
|
+
if (name !== null && (known.has(name) || name === "FUNCNAME"))
|
|
2330
|
+
return [{ kind: "Lit", value: name, quoted }];
|
|
2331
|
+
if (name !== null) {
|
|
2332
|
+
const bound = recordedExpansion(name === "@" || name === "*" ? "1" : name);
|
|
2333
|
+
if (typeof bound === "string" && PLAIN_PROGRAM_NAME.test(bound))
|
|
2334
|
+
return [{ kind: "Lit", value: bound, quoted }];
|
|
2335
|
+
}
|
|
2235
2336
|
if (kind === "SglQuoted")
|
|
2236
2337
|
return [{ kind: part.Dollar ? "Dynamic" : "Lit", value: part.Value ?? "", quoted: true }];
|
|
2237
2338
|
if (kind === "ParamExp" && isDefaultExpansion(part) && !assigned.has(part.Param?.Value)) {
|
|
@@ -2239,14 +2340,14 @@ function executableParts(word, assigned, quoted = false) {
|
|
|
2239
2340
|
if (fallback !== null) return [{ kind: "Lit", value: fallback, quoted }];
|
|
2240
2341
|
}
|
|
2241
2342
|
if (kind === "CmdSubst") {
|
|
2242
|
-
const
|
|
2243
|
-
if (
|
|
2343
|
+
const name2 = lookupSubstitution(part);
|
|
2344
|
+
if (name2 !== null) return [{ kind: "Lit", value: name2, quoted }];
|
|
2244
2345
|
}
|
|
2245
2346
|
return [{ kind: "Dynamic", value: "", quoted }];
|
|
2246
2347
|
});
|
|
2247
2348
|
}
|
|
2248
|
-
function opaqueExecutable(word, assigned) {
|
|
2249
|
-
const parts = executableParts(word, assigned);
|
|
2349
|
+
function opaqueExecutable(word, assigned, known = EMPTY_NAMES) {
|
|
2350
|
+
const parts = executableParts(word, assigned, false, known);
|
|
2250
2351
|
let lastSlash = -1;
|
|
2251
2352
|
parts.forEach((p, i) => {
|
|
2252
2353
|
if (p.kind === "Lit" && p.value.includes("/")) lastSlash = i;
|
|
@@ -2368,6 +2469,9 @@ function deriveBinaryOp(sample) {
|
|
|
2368
2469
|
function isListOp(op) {
|
|
2369
2470
|
return listOps().has(op);
|
|
2370
2471
|
}
|
|
2472
|
+
function isPipeOp(op) {
|
|
2473
|
+
return pipeOps().has(op);
|
|
2474
|
+
}
|
|
2371
2475
|
function listOps() {
|
|
2372
2476
|
if (_listOps) return _listOps;
|
|
2373
2477
|
_listOps = new Set(
|
|
@@ -2612,6 +2716,33 @@ function isProtectedCodePath(p) {
|
|
|
2612
2716
|
if (matchSensitivePath(p) !== null) return true;
|
|
2613
2717
|
return SYSTEM_AUTH_FILES.includes(p) || SYSTEM_AUTH_DIRS.some((d) => p === d || p.startsWith(d + "/"));
|
|
2614
2718
|
}
|
|
2719
|
+
function isJailedCodePath(literal, jailPaths) {
|
|
2720
|
+
const value = trimTrailingSlashes(literal.replace(/\\/g, "/"));
|
|
2721
|
+
if (!value) return false;
|
|
2722
|
+
for (const raw of jailPaths) {
|
|
2723
|
+
const jail = trimTrailingSlashes(raw.trim().replace(/\\/g, "/"));
|
|
2724
|
+
if (!jail) continue;
|
|
2725
|
+
const home = homeTail(jail);
|
|
2726
|
+
if (home === null) {
|
|
2727
|
+
if (value === jail || value.startsWith(jail + "/")) return true;
|
|
2728
|
+
continue;
|
|
2729
|
+
}
|
|
2730
|
+
if (!home) continue;
|
|
2731
|
+
const tail = homeTail(value);
|
|
2732
|
+
if (tail !== null && (tail === home || tail.startsWith(home + "/"))) return true;
|
|
2733
|
+
}
|
|
2734
|
+
return false;
|
|
2735
|
+
}
|
|
2736
|
+
function trimTrailingSlashes(s) {
|
|
2737
|
+
let end = s.length;
|
|
2738
|
+
while (end > 0 && s.charCodeAt(end - 1) === 47) end--;
|
|
2739
|
+
return s.slice(0, end);
|
|
2740
|
+
}
|
|
2741
|
+
function homeTail(p) {
|
|
2742
|
+
const m = /^(?:~|\$\{?HOME\}?|\/home\/[^/]+|\/Users\/[^/]+|\/root)(?:\/(.*))?$/.exec(p);
|
|
2743
|
+
if (!m) return null;
|
|
2744
|
+
return m[1] ?? "";
|
|
2745
|
+
}
|
|
2615
2746
|
function inlineExecDescription(r) {
|
|
2616
2747
|
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.";
|
|
2617
2748
|
return `${lead} Review the full script below before allowing it to execute.`;
|
|
@@ -2620,7 +2751,8 @@ function inlineExecReason(r) {
|
|
|
2620
2751
|
const who = r.interp ? `This inline ${r.interp} code` : "This inline code";
|
|
2621
2752
|
return r.evidence ? `${who} ${r.what} (${r.evidence})` : `${who} ${r.what}`;
|
|
2622
2753
|
}
|
|
2623
|
-
function inlineExecReview(command) {
|
|
2754
|
+
function inlineExecReview(command, jailPaths = []) {
|
|
2755
|
+
const isProtected = jailPaths.length === 0 ? isProtectedCodePath : (p) => isProtectedCodePath(p) || isJailedCodePath(p, jailPaths);
|
|
2624
2756
|
const calls = inlineExecCalls(command);
|
|
2625
2757
|
if (calls === PARSE_FAIL) {
|
|
2626
2758
|
return INLINE_EXEC_FALLBACK.test(command) ? { outcome: "unreadable", interp: "", what: "could not be parsed" } : null;
|
|
@@ -2643,7 +2775,7 @@ function inlineExecReview(command) {
|
|
|
2643
2775
|
what: `is ${call.interp} code, which node9 does not read`
|
|
2644
2776
|
};
|
|
2645
2777
|
} else {
|
|
2646
|
-
const judged = judgeInlineCode(language, code2,
|
|
2778
|
+
const judged = judgeInlineCode(language, code2, isProtected);
|
|
2647
2779
|
if (judged) finding = { ...judged, interp: call.interp };
|
|
2648
2780
|
}
|
|
2649
2781
|
if (finding?.outcome === "dangerous") return finding;
|
|
@@ -2824,6 +2956,11 @@ function recordTopLevelStmt(stmt) {
|
|
|
2824
2956
|
if (t === "DeclClause") return ASSIGNMENT_HEADS.has(stmt.Cmd.Variant?.Value ?? "");
|
|
2825
2957
|
return (stmt.Cmd.Args || []).length === 0 && (stmt.Cmd.Assigns || []).length > 0;
|
|
2826
2958
|
}
|
|
2959
|
+
function arrayElements(value) {
|
|
2960
|
+
if (typeof value !== "string" || !value.startsWith(ARRAY_MARK)) return null;
|
|
2961
|
+
const body = value.slice(ARRAY_MARK.length);
|
|
2962
|
+
return body === "" ? [] : body.split(ARRAY_SEP);
|
|
2963
|
+
}
|
|
2827
2964
|
function recordAssignments(n, at) {
|
|
2828
2965
|
if (!assignmentTable) return;
|
|
2829
2966
|
const t = n.kind;
|
|
@@ -2837,7 +2974,19 @@ function recordAssignments(n, at) {
|
|
|
2837
2974
|
} else return;
|
|
2838
2975
|
for (const a of assigns) {
|
|
2839
2976
|
const name = a?.Name?.Value;
|
|
2840
|
-
if (!name
|
|
2977
|
+
if (!name) continue;
|
|
2978
|
+
if (a.Array) {
|
|
2979
|
+
const elems = (a.Array.Elems || []).map(
|
|
2980
|
+
(e) => e?.Index ? null : resolveWordLiteral(e?.Value)
|
|
2981
|
+
);
|
|
2982
|
+
const literal = elems.every((v) => v !== null);
|
|
2983
|
+
assignmentTable.set(name, {
|
|
2984
|
+
value: literal && !a.Append ? ARRAY_MARK + elems.join(ARRAY_SEP) : null,
|
|
2985
|
+
at
|
|
2986
|
+
});
|
|
2987
|
+
continue;
|
|
2988
|
+
}
|
|
2989
|
+
if (!a.Value || a.Append) continue;
|
|
2841
2990
|
assignmentTable.set(name, { value: resolveWordLiteral(a.Value), at });
|
|
2842
2991
|
}
|
|
2843
2992
|
}
|
|
@@ -2848,7 +2997,33 @@ function resolveTrivialSubst(part) {
|
|
|
2848
2997
|
const st = stmts[0];
|
|
2849
2998
|
if ((st.Redirs || []).length > 0 || st.Negated || st.Background) return void 0;
|
|
2850
2999
|
const cmd = st.Cmd;
|
|
2851
|
-
if (!cmd
|
|
3000
|
+
if (!cmd) return void 0;
|
|
3001
|
+
if (cmd.kind === "BinaryCmd" && pipeOps().has(cmd.Op)) {
|
|
3002
|
+
const left = cmd.X?.Cmd;
|
|
3003
|
+
const right = cmd.Y?.Cmd;
|
|
3004
|
+
if (!left || !right || left.kind !== "CallExpr" || right.kind !== "CallExpr") return void 0;
|
|
3005
|
+
if ((cmd.X.Redirs || []).length > 0 || (cmd.Y.Redirs || []).length > 0) return void 0;
|
|
3006
|
+
const input = trivialCallOutput(left);
|
|
3007
|
+
if (input === void 0) return void 0;
|
|
3008
|
+
const filter = (right.Args || []).map((a) => resolveWordLiteral(a));
|
|
3009
|
+
if (filter.some((w) => w === null)) return void 0;
|
|
3010
|
+
const f = baseWord(filter[0]);
|
|
3011
|
+
const flags = filter.slice(1);
|
|
3012
|
+
if (f === "base64" && flags.length === 1 && /^(-d|-D|--decode)$/.test(flags[0])) {
|
|
3013
|
+
try {
|
|
3014
|
+
const out = Buffer.from(input, "base64").toString("utf8");
|
|
3015
|
+
return /^[\x20-\x7e]*$/.test(out) ? out : void 0;
|
|
3016
|
+
} catch {
|
|
3017
|
+
return void 0;
|
|
3018
|
+
}
|
|
3019
|
+
}
|
|
3020
|
+
if (f === "rev" && flags.length === 0) return [...input].reverse().join("");
|
|
3021
|
+
return void 0;
|
|
3022
|
+
}
|
|
3023
|
+
if (cmd.kind !== "CallExpr") return void 0;
|
|
3024
|
+
return trivialCallOutput(cmd);
|
|
3025
|
+
}
|
|
3026
|
+
function trivialCallOutput(cmd) {
|
|
2852
3027
|
if ((cmd.Assigns || []).length > 0) return void 0;
|
|
2853
3028
|
const words = (cmd.Args || []).map((a) => resolveWordLiteral(a));
|
|
2854
3029
|
if (words.length === 0 || words.some((w) => w === null)) return void 0;
|
|
@@ -2860,9 +3035,16 @@ function resolveTrivialSubst(part) {
|
|
|
2860
3035
|
return rest.slice(i).join(" ");
|
|
2861
3036
|
}
|
|
2862
3037
|
if (head === "printf") {
|
|
3038
|
+
if (rest.length === 1 && /^(?:\\(?:[0-7]{1,3}|x[0-9A-Fa-f]{1,2}))+$/.test(rest[0])) {
|
|
3039
|
+
return rest[0].replace(
|
|
3040
|
+
/\\(?:x([0-9A-Fa-f]{1,2})|([0-7]{1,3}))/g,
|
|
3041
|
+
(_, hex, oct) => String.fromCharCode(hex ? parseInt(hex, 16) : parseInt(oct, 8))
|
|
3042
|
+
);
|
|
3043
|
+
}
|
|
2863
3044
|
if (rest.length !== 2) return void 0;
|
|
2864
|
-
|
|
2865
|
-
return
|
|
3045
|
+
const m = /^([^%]*)%s([^%]*?)(\\n)?$/.exec(rest[0]);
|
|
3046
|
+
if (!m) return void 0;
|
|
3047
|
+
return m[1] + rest[1] + m[2];
|
|
2866
3048
|
}
|
|
2867
3049
|
return void 0;
|
|
2868
3050
|
}
|
|
@@ -2876,11 +3058,28 @@ function isPlainParam(p) {
|
|
|
2876
3058
|
if (p.kind !== "ParamExp") return false;
|
|
2877
3059
|
return !(p.Excl || p.Length || p.Width || p.Index || p.Slice || p.Repl || p.Exp);
|
|
2878
3060
|
}
|
|
3061
|
+
function indexedParam(p) {
|
|
3062
|
+
if (p.kind !== "ParamExp" || !p.Index) return null;
|
|
3063
|
+
if (p.Excl || p.Length || p.Width || p.Slice || p.Repl || p.Exp) return null;
|
|
3064
|
+
const index = resolveWordLiteral(p.Index);
|
|
3065
|
+
const name = p.Param?.Value;
|
|
3066
|
+
return name && index !== null ? { name, index } : null;
|
|
3067
|
+
}
|
|
2879
3068
|
function expandPlainParam(p) {
|
|
2880
3069
|
if (!assignmentTable) return void 0;
|
|
3070
|
+
const indexed = indexedParam(p);
|
|
3071
|
+
if (indexed) {
|
|
3072
|
+
const elems = arrayElements(recordedExpansion(indexed.name));
|
|
3073
|
+
if (elems === null) return void 0;
|
|
3074
|
+
if (indexed.index === "@" || indexed.index === "*") return elems.join(" ");
|
|
3075
|
+
return /^\d+$/.test(indexed.index) ? elems[Number(indexed.index)] ?? null : null;
|
|
3076
|
+
}
|
|
2881
3077
|
if (!isPlainParam(p)) return void 0;
|
|
2882
3078
|
const recorded = recordedExpansion(p.Param?.Value);
|
|
2883
|
-
if (recorded !== void 0)
|
|
3079
|
+
if (recorded !== void 0) {
|
|
3080
|
+
const elems = arrayElements(recorded);
|
|
3081
|
+
return elems === null ? recorded : elems[0] ?? "";
|
|
3082
|
+
}
|
|
2884
3083
|
return HOME_VARIABLES.has(p.Param?.Value) ? "~" : void 0;
|
|
2885
3084
|
}
|
|
2886
3085
|
function functionBodies(f) {
|
|
@@ -5859,7 +6058,59 @@ function dynamicOptionWord(word) {
|
|
|
5859
6058
|
if (/^--[a-z-]+=/.test(prefix) || /^-[cC]/.test(prefix)) return `${prefix}$\u2026`;
|
|
5860
6059
|
return null;
|
|
5861
6060
|
}
|
|
5862
|
-
function
|
|
6061
|
+
function arrayExpansionWords(word) {
|
|
6062
|
+
let parts = word?.Parts || [];
|
|
6063
|
+
if (parts.length === 1 && parts[0].kind === "DblQuoted") parts = parts[0].Parts || [];
|
|
6064
|
+
if (parts.length !== 1 || parts[0].kind !== "ParamExp" || !parts[0].Index) return null;
|
|
6065
|
+
const index = resolveWordLiteral(parts[0].Index);
|
|
6066
|
+
if (index !== "@" && index !== "*") return null;
|
|
6067
|
+
const elems = arrayElements(recordedExpansion(parts[0].Param?.Value));
|
|
6068
|
+
return elems;
|
|
6069
|
+
}
|
|
6070
|
+
function producedLiteral(call) {
|
|
6071
|
+
if ((call.Assigns || []).length > 0) return null;
|
|
6072
|
+
const words = (call.Args || []).map((a) => resolveWordLiteral(a));
|
|
6073
|
+
if (words.length === 0 || words.some((w) => w === null)) return null;
|
|
6074
|
+
const head = baseWord(words[0]);
|
|
6075
|
+
const rest = words.slice(1);
|
|
6076
|
+
if (head === "git" && rest[0] === "rev-parse" && rest[1] === "--show-toplevel" && rest.length === 2)
|
|
6077
|
+
return ":/";
|
|
6078
|
+
if (head === "echo") {
|
|
6079
|
+
let i = 0;
|
|
6080
|
+
while (i < rest.length && /^-[neE]+$/.test(rest[i])) i++;
|
|
6081
|
+
return rest.length - i === 1 ? rest[i] : null;
|
|
6082
|
+
}
|
|
6083
|
+
if (head === "printf" && rest.length === 2 && /^%s(\\[0n])?$/.test(rest[0])) return rest[1];
|
|
6084
|
+
return null;
|
|
6085
|
+
}
|
|
6086
|
+
function treeTopWord(word, treeTopVars = NO_VARS) {
|
|
6087
|
+
let parts = word?.Parts || [];
|
|
6088
|
+
if (parts.length === 1 && parts[0].kind === "DblQuoted") parts = parts[0].Parts || [];
|
|
6089
|
+
if (parts.length !== 1) return false;
|
|
6090
|
+
const p = parts[0];
|
|
6091
|
+
if (p.kind === "ParamExp") {
|
|
6092
|
+
const name = plainParamName(word)?.name;
|
|
6093
|
+
return name === "PWD" || name !== void 0 && treeTopVars.has(name);
|
|
6094
|
+
}
|
|
6095
|
+
if (p.kind !== "CmdSubst") return false;
|
|
6096
|
+
const stmts = p.Stmts || [];
|
|
6097
|
+
if (stmts.length !== 1 || !stmts[0].Cmd || stmts[0].Cmd.kind !== "CallExpr") return false;
|
|
6098
|
+
const words = (stmts[0].Cmd.Args || []).map((a) => resolveWordLiteral(a));
|
|
6099
|
+
if (words.some((w) => w === null)) return false;
|
|
6100
|
+
const head = baseWord(words[0]);
|
|
6101
|
+
if (head === "pwd") return words.length === 1 || words[1] === "-P" || words[1] === "-L";
|
|
6102
|
+
return head === "git" && words[1] === "rev-parse" && words[2] === "--show-toplevel";
|
|
6103
|
+
}
|
|
6104
|
+
function resolveGitWords(word, treeTopVars = NO_VARS, appended = NO_APPENDS) {
|
|
6105
|
+
if (treeTopWord(word, treeTopVars)) return [":/"];
|
|
6106
|
+
const plain = plainParamName(word);
|
|
6107
|
+
if (plain && appended.has(plain.name)) {
|
|
6108
|
+
const v = appended.get(plain.name);
|
|
6109
|
+
if (v === null || v === void 0) return [null];
|
|
6110
|
+
return plain.quoted ? [v] : splitFields(v);
|
|
6111
|
+
}
|
|
6112
|
+
const elems = arrayExpansionWords(word);
|
|
6113
|
+
if (elems !== null) return elems;
|
|
5863
6114
|
const value = resolveWordLiteral(word);
|
|
5864
6115
|
if (value === null) {
|
|
5865
6116
|
if (isPositionalParam(word)) return boundPositionals() ?? [POSITIONAL2];
|
|
@@ -5967,6 +6218,8 @@ function classify(inv) {
|
|
|
5967
6218
|
if (o.flags.has("-n") || o.flags.has("--dry-run")) break;
|
|
5968
6219
|
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("+"));
|
|
5969
6220
|
if (forced) found(FORCE_PUSH);
|
|
6221
|
+
const deletes = o.flags.has("-d") || o.flags.has("--delete") || o.operands.some((r) => /^:[^:]/.test(r));
|
|
6222
|
+
if (deletes) found(DESTRUCTIVE);
|
|
5970
6223
|
break;
|
|
5971
6224
|
}
|
|
5972
6225
|
case "reset": {
|
|
@@ -5994,11 +6247,72 @@ function classify(inv) {
|
|
|
5994
6247
|
if (o.flags.has("-d") || o.flags.has("--delete")) found(DESTRUCTIVE);
|
|
5995
6248
|
break;
|
|
5996
6249
|
}
|
|
6250
|
+
// node9Firewall#385: history and work discarded through plumbing. A ref
|
|
6251
|
+
// deleted by hand, a stash dropped, the reflog expired or pruned: the
|
|
6252
|
+
// commits behind them are gone the way `branch -D` loses them.
|
|
6253
|
+
case "update-ref": {
|
|
6254
|
+
const o = parseOptions(inv.args, "m", /* @__PURE__ */ new Set());
|
|
6255
|
+
if (o.flags.has("-d") && (o.dynamic || o.operands.some(isHistoryRef))) found(DESTRUCTIVE);
|
|
6256
|
+
break;
|
|
6257
|
+
}
|
|
6258
|
+
case "reflog": {
|
|
6259
|
+
const o = parseOptions(inv.args, "", /* @__PURE__ */ new Set());
|
|
6260
|
+
if (o.operands[0] === "expire" || o.operands[0] === "delete") found(DESTRUCTIVE);
|
|
6261
|
+
break;
|
|
6262
|
+
}
|
|
6263
|
+
case "gc": {
|
|
6264
|
+
if (inv.config.get("gc.reflogexpire") === "now") found(DESTRUCTIVE);
|
|
6265
|
+
break;
|
|
6266
|
+
}
|
|
6267
|
+
case "stash": {
|
|
6268
|
+
const o = parseOptions(inv.args, "", /* @__PURE__ */ new Set());
|
|
6269
|
+
if (o.operands[0] === "clear" || o.operands[0] === "drop") found(DESTRUCTIVE);
|
|
6270
|
+
break;
|
|
6271
|
+
}
|
|
6272
|
+
case "worktree": {
|
|
6273
|
+
const o = parseOptions(inv.args, "", /* @__PURE__ */ new Set());
|
|
6274
|
+
if (o.operands[0] === "remove" && (o.flags.has("-f") || o.flags.has("--force")))
|
|
6275
|
+
found(DESTRUCTIVE);
|
|
6276
|
+
break;
|
|
6277
|
+
}
|
|
6278
|
+
// The working tree overwritten: `restore` from another ref, a forced
|
|
6279
|
+
// checkout, or `checkout -- .` (every local change dropped). A bare
|
|
6280
|
+
// `restore .` or `checkout .` stays an ordinary undo, as pinned.
|
|
6281
|
+
case "restore": {
|
|
6282
|
+
const o = parseOptions(inv.args, "s", RESTORE_LONG_VALUE);
|
|
6283
|
+
const src = restoreSource(inv.args);
|
|
6284
|
+
const whole = o.dynamic || o.operands.some(wholeTree);
|
|
6285
|
+
if (src !== null && src !== "HEAD" && whole) found(DESTRUCTIVE);
|
|
6286
|
+
break;
|
|
6287
|
+
}
|
|
6288
|
+
case "checkout": {
|
|
6289
|
+
const o = parseOptions(inv.args, "bB", CHECKOUT_LONG_VALUE);
|
|
6290
|
+
const forced = o.flags.has("-f") || o.flags.has("--force");
|
|
6291
|
+
const dropAll = inv.args.includes("--") && o.operands.some(wholeTree);
|
|
6292
|
+
if (forced || dropAll) found(DESTRUCTIVE);
|
|
6293
|
+
break;
|
|
6294
|
+
}
|
|
5997
6295
|
default:
|
|
5998
6296
|
break;
|
|
5999
6297
|
}
|
|
6000
6298
|
return out;
|
|
6001
6299
|
}
|
|
6300
|
+
function isExcludePathspec(operand) {
|
|
6301
|
+
return /^:[!^]/.test(operand) || /^:\([^)]*\bexclude\b[^)]*\)/.test(operand);
|
|
6302
|
+
}
|
|
6303
|
+
function restoreSource(args) {
|
|
6304
|
+
for (let i = 0; i < args.length; i++) {
|
|
6305
|
+
const w = args[i];
|
|
6306
|
+
if (w === null) continue;
|
|
6307
|
+
if (w.startsWith("--source=")) return w.slice("--source=".length);
|
|
6308
|
+
if (w === "--source" || w === "-s") return args[i + 1] ?? null;
|
|
6309
|
+
if (/^-s./.test(w)) return w.slice(2);
|
|
6310
|
+
}
|
|
6311
|
+
return null;
|
|
6312
|
+
}
|
|
6313
|
+
function isHistoryRef(ref) {
|
|
6314
|
+
return /^refs\/(heads|stash)(\/|$)/.test(ref);
|
|
6315
|
+
}
|
|
6002
6316
|
function killSwitchSet(name, value) {
|
|
6003
6317
|
if (value === null) return false;
|
|
6004
6318
|
switch (name) {
|
|
@@ -6056,6 +6370,7 @@ function hooksBypass(inv) {
|
|
|
6056
6370
|
const o = parseOptions(inv.args, "mFCcut", COMMIT_LONG_VALUE);
|
|
6057
6371
|
return o.flags.has("-n") || o.flags.has("--no-verify");
|
|
6058
6372
|
}
|
|
6373
|
+
if (sub === "commit-tree") return true;
|
|
6059
6374
|
if (sub !== void 0 && NO_VERIFY_SUBS.has(sub)) {
|
|
6060
6375
|
return inv.args.some((a) => a === "--no-verify");
|
|
6061
6376
|
}
|
|
@@ -6093,7 +6408,20 @@ function configWritesHooksPath(args) {
|
|
|
6093
6408
|
return write;
|
|
6094
6409
|
}
|
|
6095
6410
|
function isHookPath(word) {
|
|
6096
|
-
return /(^|[\\/])(\.git[\\/]hooks|\.husky)([\\/]|$)/.test(word);
|
|
6411
|
+
return /(^|[\\/])(\.git[\\/]hooks|\.husky|\.githooks)([\\/]|$)/.test(word);
|
|
6412
|
+
}
|
|
6413
|
+
function isLiveHookFile(word) {
|
|
6414
|
+
if (!isHookPath(word)) return false;
|
|
6415
|
+
const m = /(^|[\\/])(\.git[\\/]hooks|\.husky|\.githooks)(?:[\\/](.*))?$/.exec(word);
|
|
6416
|
+
if (!m) return false;
|
|
6417
|
+
const rest = m[3] ?? "";
|
|
6418
|
+
if (rest === "" || rest === "_") return true;
|
|
6419
|
+
const leaf = rest.replace(/^_[\\/]/, "");
|
|
6420
|
+
return /^[a-z-]+$/.test(leaf);
|
|
6421
|
+
}
|
|
6422
|
+
function hookBodyIsEmpty(text) {
|
|
6423
|
+
const lines = text.split(/\r?\n/).map((l) => l.trim()).filter((l) => l !== "" && !l.startsWith("#"));
|
|
6424
|
+
return lines.every((l) => /^(exit(\s+0)?|true|:|set\s+-[a-zA-Z]+|set\s+-o\s+\w+)$/.test(l));
|
|
6097
6425
|
}
|
|
6098
6426
|
function modeRemovesExecute(mode) {
|
|
6099
6427
|
if (/^[0-7]{3,4}$/.test(mode)) {
|
|
@@ -6102,6 +6430,22 @@ function modeRemovesExecute(mode) {
|
|
|
6102
6430
|
}
|
|
6103
6431
|
return mode.split(",").some((part) => /^[ugoa]*-[rwst]*x/.test(part));
|
|
6104
6432
|
}
|
|
6433
|
+
function redirOpIsAppend(redir) {
|
|
6434
|
+
return redir?.Op === appendOp();
|
|
6435
|
+
}
|
|
6436
|
+
function appendOp() {
|
|
6437
|
+
if (_appendOp !== null) return _appendOp;
|
|
6438
|
+
try {
|
|
6439
|
+
const f = parseShared("echo x >> y");
|
|
6440
|
+
_appendOp = typeof f === "symbol" ? -1 : f.Stmts[0].Redirs[0].Op;
|
|
6441
|
+
} catch {
|
|
6442
|
+
_appendOp = -1;
|
|
6443
|
+
}
|
|
6444
|
+
return _appendOp;
|
|
6445
|
+
}
|
|
6446
|
+
function hooksBypassed(shown) {
|
|
6447
|
+
return { ...HOOKS_BYPASS, shown, reason: `${HOOKS_BYPASS.reason}: ${shown}` };
|
|
6448
|
+
}
|
|
6105
6449
|
function chmodDisarmsHook(args, shown) {
|
|
6106
6450
|
let i = 0;
|
|
6107
6451
|
while (i < args.length) {
|
|
@@ -6144,6 +6488,7 @@ function stagesEverything(inv) {
|
|
|
6144
6488
|
const sub = inv.sub?.toLowerCase();
|
|
6145
6489
|
const prefix = chdirPrefix(inv);
|
|
6146
6490
|
const judge = (operands2) => {
|
|
6491
|
+
if (operands2.length > 0 && operands2.every(isExcludePathspec)) return {};
|
|
6147
6492
|
let conditional = false;
|
|
6148
6493
|
for (const operand of operands2) {
|
|
6149
6494
|
if (!wholeTree(operand)) continue;
|
|
@@ -6436,7 +6781,7 @@ function evaluateAgentFileWrite(args, accesses, context, settings, shell, hooks
|
|
|
6436
6781
|
}
|
|
6437
6782
|
return null;
|
|
6438
6783
|
}
|
|
6439
|
-
function
|
|
6784
|
+
function isPipeOp2(op) {
|
|
6440
6785
|
return !isListOp(op);
|
|
6441
6786
|
}
|
|
6442
6787
|
function isDupInOp(op) {
|
|
@@ -8469,7 +8814,7 @@ async function evaluatePolicyCore(config, toolName, args, context = {}, hooks =
|
|
|
8469
8814
|
if (v?.logged) noteLogged(v);
|
|
8470
8815
|
else if (v) candidates.push(v);
|
|
8471
8816
|
};
|
|
8472
|
-
const inline = reviewsEveryInline(config.settings.mode) ? detectInlineExec(shellCommand) ? void 0 : null : inlineExecReview(shellCommand);
|
|
8817
|
+
const inline = reviewsEveryInline(config.settings.mode) ? detectInlineExec(shellCommand) ? void 0 : null : inlineExecReview(shellCommand, config.policy.jailPaths);
|
|
8473
8818
|
if (inline !== null) {
|
|
8474
8819
|
consider("commands.inline-exec", {
|
|
8475
8820
|
decision: "review",
|
|
@@ -8812,7 +9157,7 @@ function* validCardRuns(text, base22, exemptFractions = true) {
|
|
|
8812
9157
|
let m;
|
|
8813
9158
|
while ((m = re.exec(text)) !== null) {
|
|
8814
9159
|
const digits = m[0].replace(/\D/g, "");
|
|
8815
|
-
const fraction = exemptFractions && isDecimalFraction(text, m.index, digits.length === m[0].length);
|
|
9160
|
+
const fraction = exemptFractions && (isDecimalFraction(text, m.index, digits.length === m[0].length) || isInteriorDotNumber(m[0]));
|
|
8816
9161
|
if (!fraction && validateLuhn(digits)) {
|
|
8817
9162
|
yield { index: m.index, length: m[0].length, digits };
|
|
8818
9163
|
} else {
|
|
@@ -8839,6 +9184,12 @@ function replaceValidCards(text, replace, { exemptFractions = true } = {}) {
|
|
|
8839
9184
|
}
|
|
8840
9185
|
return out;
|
|
8841
9186
|
}
|
|
9187
|
+
function isInteriorDotNumber(run) {
|
|
9188
|
+
const first = run.indexOf(".");
|
|
9189
|
+
if (first <= 0 || first === run.length - 1) return false;
|
|
9190
|
+
if (run.indexOf(".", first + 1) !== -1) return false;
|
|
9191
|
+
return !/[-\s]/.test(run);
|
|
9192
|
+
}
|
|
8842
9193
|
function isDecimalFraction(text, index, unseparated) {
|
|
8843
9194
|
if (!unseparated) return false;
|
|
8844
9195
|
const sep = text[index - 1];
|
|
@@ -9573,7 +9924,7 @@ function matchCanaryArgs(args, values) {
|
|
|
9573
9924
|
return null;
|
|
9574
9925
|
}
|
|
9575
9926
|
}
|
|
9576
|
-
var getFilename2, __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, POSTURE_CATEGORY_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, 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, 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, CANONICAL_EXTRACTOR_VERSION;
|
|
9927
|
+
var getFilename2, __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, POSTURE_CATEGORY_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, 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, 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, CANONICAL_EXTRACTOR_VERSION;
|
|
9577
9928
|
var init_dist = __esm({
|
|
9578
9929
|
"packages/policy-engine/dist/index.mjs"() {
|
|
9579
9930
|
"use strict";
|
|
@@ -12860,6 +13211,7 @@ var init_dist = __esm({
|
|
|
12860
13211
|
"sqlite3"
|
|
12861
13212
|
]);
|
|
12862
13213
|
defaultExpansionOps = null;
|
|
13214
|
+
EMPTY_NAMES = /* @__PURE__ */ new Set();
|
|
12863
13215
|
VARIABLE_READERS = /* @__PURE__ */ new Set([
|
|
12864
13216
|
"read",
|
|
12865
13217
|
"mapfile",
|
|
@@ -12872,6 +13224,7 @@ var init_dist = __esm({
|
|
|
12872
13224
|
"readonly",
|
|
12873
13225
|
"printf"
|
|
12874
13226
|
]);
|
|
13227
|
+
PLAIN_PROGRAM_NAME = /^[A-Za-z_][\w.+-]*$/;
|
|
12875
13228
|
FS_READ_TOOLS = /* @__PURE__ */ new Set([
|
|
12876
13229
|
"cat",
|
|
12877
13230
|
"less",
|
|
@@ -13766,6 +14119,8 @@ var init_dist = __esm({
|
|
|
13766
14119
|
AND_OR_OPS: new Set([and, or].filter((o) => o !== null))
|
|
13767
14120
|
};
|
|
13768
14121
|
});
|
|
14122
|
+
ARRAY_MARK = "array";
|
|
14123
|
+
ARRAY_SEP = "";
|
|
13769
14124
|
MAX_CALL_DEPTH2 = 4;
|
|
13770
14125
|
MAX_CALL_WALKS2 = 256;
|
|
13771
14126
|
callDepth = 0;
|
|
@@ -17096,7 +17451,22 @@ zoo`.split("\n");
|
|
|
17096
17451
|
found;
|
|
17097
17452
|
/** Aliases defined earlier in this command: name -> value (null = dynamic). */
|
|
17098
17453
|
aliases = /* @__PURE__ */ new Map();
|
|
17454
|
+
/** node9Firewall#385: variables assigned a tree-top word (`scope="$PWD"`,
|
|
17455
|
+
* `root=$(git rev-parse --show-toplevel)`, `DIR=$(pwd)`), so the
|
|
17456
|
+
* variable reads as the top where it is used. */
|
|
17457
|
+
treeTopVars = /* @__PURE__ */ new Set();
|
|
17458
|
+
/** node9Firewall#385 (c): a string a script builds with `+=` from
|
|
17459
|
+
* literals (`mode=--ha; mode+=rd`). The jail's table does not follow an
|
|
17460
|
+
* append (JAIL-14a); the git rules read the built word, since a flag
|
|
17461
|
+
* spelled in two halves is still that flag. name -> value, null once a
|
|
17462
|
+
* half is unknown. */
|
|
17463
|
+
appended = /* @__PURE__ */ new Map();
|
|
17099
17464
|
payloads = /* @__PURE__ */ new Set();
|
|
17465
|
+
/** node9Firewall#385 (a): the text this command writes to each path
|
|
17466
|
+
* (`cat > /tmp/x.sh <<'SH' ... SH`, `echo '...' > f`, `>>` appends), so
|
|
17467
|
+
* a later statement that runs the path (`bash f`, `sh f`, `./f`) is
|
|
17468
|
+
* judged on what it runs. null once a write to the path is unknown. */
|
|
17469
|
+
written = /* @__PURE__ */ new Map();
|
|
17100
17470
|
/** `for NAME in a b c`: the literal items, or null when one is dynamic. */
|
|
17101
17471
|
loopVars = /* @__PURE__ */ new Map();
|
|
17102
17472
|
/** Walk one command string. Returns false when it did not parse. */
|
|
@@ -17115,6 +17485,25 @@ zoo`.split("\n");
|
|
|
17115
17485
|
const type = n.kind;
|
|
17116
17486
|
if (type === "Stmt") {
|
|
17117
17487
|
this.visitHeredocShell(n, depth);
|
|
17488
|
+
this.visitPipeline(n, depth);
|
|
17489
|
+
this.visitHookWrite(n);
|
|
17490
|
+
this.recordScriptWrite(n);
|
|
17491
|
+
this.visitWrittenScript(n, depth);
|
|
17492
|
+
return true;
|
|
17493
|
+
}
|
|
17494
|
+
if (type === "Assign" && n.Name?.Value && n.Value) {
|
|
17495
|
+
const name = n.Name.Value;
|
|
17496
|
+
if (n.Append) {
|
|
17497
|
+
const prev = this.appended.has(name) ? this.appended.get(name) : resolveWordLiteral(n.Value) === null ? null : void 0;
|
|
17498
|
+
const base22 = prev === void 0 ? recordedExpansion(name) : prev;
|
|
17499
|
+
const piece = resolveWordLiteral(n.Value);
|
|
17500
|
+
this.appended.set(name, typeof base22 === "string" && piece !== null ? base22 + piece : null);
|
|
17501
|
+
this.treeTopVars.delete(name);
|
|
17502
|
+
return true;
|
|
17503
|
+
}
|
|
17504
|
+
this.appended.delete(name);
|
|
17505
|
+
if (treeTopWord(n.Value, this.treeTopVars)) this.treeTopVars.add(name);
|
|
17506
|
+
else this.treeTopVars.delete(name);
|
|
17118
17507
|
return true;
|
|
17119
17508
|
}
|
|
17120
17509
|
if (type === "ForClause") {
|
|
@@ -17143,13 +17532,13 @@ zoo`.split("\n");
|
|
|
17143
17532
|
const param = plainParamName(rawArgs[loopArg]);
|
|
17144
17533
|
for (const item of this.loopVars.get(param.name)) {
|
|
17145
17534
|
const words2 = rawArgs.flatMap(
|
|
17146
|
-
(a, i) => i === loopArg ? param.quoted ? [item] : splitFields(item) : resolveGitWords(a)
|
|
17535
|
+
(a, i) => i === loopArg ? param.quoted ? [item] : splitFields(item) : resolveGitWords(a, this.treeTopVars, this.appended)
|
|
17147
17536
|
);
|
|
17148
17537
|
this.visitWords(words2, new Map(prefixEnv), depth, false);
|
|
17149
17538
|
}
|
|
17150
17539
|
return true;
|
|
17151
17540
|
}
|
|
17152
|
-
const words = rawArgs.flatMap((a) => resolveGitWords(a));
|
|
17541
|
+
const words = rawArgs.flatMap((a) => resolveGitWords(a, this.treeTopVars, this.appended));
|
|
17153
17542
|
this.visitWords(words, prefixEnv, depth, false);
|
|
17154
17543
|
return true;
|
|
17155
17544
|
}
|
|
@@ -17174,6 +17563,23 @@ zoo`.split("\n");
|
|
|
17174
17563
|
if (f) this.found(f);
|
|
17175
17564
|
return;
|
|
17176
17565
|
}
|
|
17566
|
+
if (headWord === "rm" || headWord === "unlink") {
|
|
17567
|
+
if (words.slice(head + 1).some((w) => w !== null && isLiveHookFile(w)))
|
|
17568
|
+
this.found(hooksBypassed(shownOf(words)));
|
|
17569
|
+
return;
|
|
17570
|
+
}
|
|
17571
|
+
if (headWord === "mv") {
|
|
17572
|
+
const operands2 = words.slice(head + 1).filter((w) => w === null || !w.startsWith("-"));
|
|
17573
|
+
const src = operands2[0];
|
|
17574
|
+
if (typeof src === "string" && isLiveHookFile(src)) this.found(hooksBypassed(shownOf(words)));
|
|
17575
|
+
return;
|
|
17576
|
+
}
|
|
17577
|
+
if (headWord === "perl") {
|
|
17578
|
+
const code2 = words.slice(head + 1).find((w) => w !== null && /\brename\b/.test(w));
|
|
17579
|
+
const m = code2 ? /rename\s*\(?\s*q[qw]?\s*[(\[{<'"]([^)\]}>'"]+)/.exec(code2) : null;
|
|
17580
|
+
if (m && isLiveHookFile(m[1])) this.found(hooksBypassed(shownOf(words)));
|
|
17581
|
+
return;
|
|
17582
|
+
}
|
|
17177
17583
|
if (depth < MAX_PAYLOAD_DEPTH2) {
|
|
17178
17584
|
const payload = literalShellPayload(words, baseWord(words[0]));
|
|
17179
17585
|
if (payload !== null) this.runPayload(payload, depth);
|
|
@@ -17184,6 +17590,127 @@ zoo`.split("\n");
|
|
|
17184
17590
|
this.payloads.add(payload);
|
|
17185
17591
|
this.run(payload, depth + 1);
|
|
17186
17592
|
}
|
|
17593
|
+
/**
|
|
17594
|
+
* node9Firewall#385: a pipeline whose last stage reads its pathspec from
|
|
17595
|
+
* stdin (`git add --pathspec-from-file=-`) or runs git over the names it
|
|
17596
|
+
* is fed (`xargs -0 git add --`), with a producer that is one literal
|
|
17597
|
+
* (`git rev-parse --show-toplevel`, `printf '%s\0' .`): the literal is
|
|
17598
|
+
* the operand, and the call is judged with it.
|
|
17599
|
+
*/
|
|
17600
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
17601
|
+
visitPipeline(stmt, depth) {
|
|
17602
|
+
const cmd = stmt.Cmd;
|
|
17603
|
+
if (!cmd || cmd.kind !== "BinaryCmd" || !isPipeOp(cmd.Op)) return;
|
|
17604
|
+
const stages = [];
|
|
17605
|
+
let cur = cmd;
|
|
17606
|
+
while (cur?.kind === "BinaryCmd" && isPipeOp(cur.Op)) {
|
|
17607
|
+
stages.unshift(cur.Y);
|
|
17608
|
+
const left = cur.X;
|
|
17609
|
+
if (left?.Cmd?.kind === "BinaryCmd" && isPipeOp(left.Cmd.Op)) cur = left.Cmd;
|
|
17610
|
+
else {
|
|
17611
|
+
stages.unshift(left);
|
|
17612
|
+
break;
|
|
17613
|
+
}
|
|
17614
|
+
}
|
|
17615
|
+
if (stages.length < 2) return;
|
|
17616
|
+
const producer = stages[stages.length - 2]?.Cmd;
|
|
17617
|
+
const consumer = stages[stages.length - 1]?.Cmd;
|
|
17618
|
+
if (!producer || !consumer || producer.kind !== "CallExpr" || consumer.kind !== "CallExpr")
|
|
17619
|
+
return;
|
|
17620
|
+
const fed = producedLiteral(producer);
|
|
17621
|
+
if (fed === null) return;
|
|
17622
|
+
const words = (consumer.Args || []).flatMap(
|
|
17623
|
+
(a) => resolveGitWords(a, this.treeTopVars, this.appended)
|
|
17624
|
+
);
|
|
17625
|
+
const head = unwrapCommandHead(words);
|
|
17626
|
+
const viaXargs = words.slice(0, head).some((w) => baseWord(w) === "xargs");
|
|
17627
|
+
const fromFile = words.findIndex(
|
|
17628
|
+
(w) => w === "--pathspec-from-file=-" || w === "--pathspec-from-file"
|
|
17629
|
+
);
|
|
17630
|
+
if (!viaXargs && fromFile < 0) return;
|
|
17631
|
+
let fedWords;
|
|
17632
|
+
if (fromFile >= 0) {
|
|
17633
|
+
fedWords = words.filter(
|
|
17634
|
+
(w, k) => !(k === fromFile || w === "-" && words[k - 1] === "--pathspec-from-file")
|
|
17635
|
+
);
|
|
17636
|
+
fedWords.push(fed);
|
|
17637
|
+
} else fedWords = [...words, fed];
|
|
17638
|
+
this.visitWords(fedWords, /* @__PURE__ */ new Map(), depth, false);
|
|
17639
|
+
}
|
|
17640
|
+
/**
|
|
17641
|
+
* node9Firewall#385 (e): a hook file written with a body that checks
|
|
17642
|
+
* nothing (`cat > .githooks/pre-commit <<'SH' exit 0 SH`, `echo 'exit 0'
|
|
17643
|
+
* > .git/hooks/pre-push`, `: > .githooks/pre-commit`). A real body (a
|
|
17644
|
+
* test, a linter) is ordinary work on the hooks.
|
|
17645
|
+
*/
|
|
17646
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
17647
|
+
visitHookWrite(stmt) {
|
|
17648
|
+
const cmd = stmt.Cmd;
|
|
17649
|
+
if (!cmd || cmd.kind !== "CallExpr") return;
|
|
17650
|
+
const redirs = stmt.Redirs || [];
|
|
17651
|
+
const target = redirs.find((r) => r?.Word && !r.Hdoc && (r.N == null || r.N.Value === "1"));
|
|
17652
|
+
if (!target) return;
|
|
17653
|
+
const path210 = resolveWordLiteral(target.Word);
|
|
17654
|
+
if (path210 === null || !isLiveHookFile(path210)) return;
|
|
17655
|
+
const hdoc = redirs.find((r) => r?.Hdoc);
|
|
17656
|
+
const words = (cmd.Args || []).map((a) => resolveWordLiteral(a));
|
|
17657
|
+
const head = baseWord(words[0]);
|
|
17658
|
+
let body = null;
|
|
17659
|
+
if (hdoc) body = resolveWordLiteral(hdoc.Hdoc);
|
|
17660
|
+
else if (head === ":" || head === "true" || words.length === 0) body = "";
|
|
17661
|
+
else if (head === "echo" || head === "printf") {
|
|
17662
|
+
const rest = words.slice(1);
|
|
17663
|
+
body = rest.some((w) => w === null) ? null : rest.filter((w) => !/^-[neE]+$/.test(w)).join(" ");
|
|
17664
|
+
if (body !== null) body = body.replace(/\\n/g, "\n");
|
|
17665
|
+
}
|
|
17666
|
+
if (body !== null && hookBodyIsEmpty(body)) this.found(hooksBypassed(shownOf(words)));
|
|
17667
|
+
}
|
|
17668
|
+
/** A statement that writes a literal text to a path, by redirect. */
|
|
17669
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
17670
|
+
recordScriptWrite(stmt) {
|
|
17671
|
+
const cmd = stmt.Cmd;
|
|
17672
|
+
if (!cmd || cmd.kind !== "CallExpr") return;
|
|
17673
|
+
const redirs = stmt.Redirs || [];
|
|
17674
|
+
const target = redirs.find((r) => r?.Word && !r.Hdoc && (r.N == null || r.N.Value === "1"));
|
|
17675
|
+
if (!target) return;
|
|
17676
|
+
const path210 = resolveWordLiteral(target.Word);
|
|
17677
|
+
if (path210 === null) return;
|
|
17678
|
+
const append = /^>>/.test(target.Op?.toString() ?? "") || redirOpIsAppend(target);
|
|
17679
|
+
const hdoc = redirs.find((r) => r?.Hdoc);
|
|
17680
|
+
const words = (cmd.Args || []).map((a) => resolveWordLiteral(a));
|
|
17681
|
+
const head = baseWord(words[0]);
|
|
17682
|
+
let text = null;
|
|
17683
|
+
if (hdoc && (head === "cat" || head === "tee")) text = resolveWordLiteral(hdoc.Hdoc);
|
|
17684
|
+
else if (head === "echo" || head === "printf") {
|
|
17685
|
+
const rest = words.slice(1);
|
|
17686
|
+
text = rest.some((w) => w === null) ? null : rest.filter((w) => !/^-[neE]+$/.test(w)).join(" ");
|
|
17687
|
+
if (text !== null && head === "printf") text = text.replace(/\\n/g, "\n");
|
|
17688
|
+
} else return;
|
|
17689
|
+
const prev = this.written.get(path210);
|
|
17690
|
+
if (text === null || append && prev === null) this.written.set(path210, null);
|
|
17691
|
+
else this.written.set(path210, append && typeof prev === "string" ? `${prev}
|
|
17692
|
+
${text}` : text);
|
|
17693
|
+
}
|
|
17694
|
+
/** A statement that runs a path this command wrote: the text is the script. */
|
|
17695
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
17696
|
+
visitWrittenScript(stmt, depth) {
|
|
17697
|
+
const cmd = stmt.Cmd;
|
|
17698
|
+
if (!cmd || cmd.kind !== "CallExpr" || this.written.size === 0 || depth >= MAX_PAYLOAD_DEPTH2)
|
|
17699
|
+
return;
|
|
17700
|
+
const words = (cmd.Args || []).map((a) => resolveWordLiteral(a));
|
|
17701
|
+
const head = unwrapCommandHead(words);
|
|
17702
|
+
const name = baseWord(words[head]);
|
|
17703
|
+
let ran = null;
|
|
17704
|
+
if (PAYLOAD_SHELLS.has(name) && name !== "eval") {
|
|
17705
|
+
const operand = words.slice(head + 1).find((w) => w === null || !w.startsWith("-"));
|
|
17706
|
+
if (typeof operand === "string") ran = operand;
|
|
17707
|
+
} else if (typeof words[head] === "string" && this.written.has(words[head])) {
|
|
17708
|
+
ran = words[head];
|
|
17709
|
+
}
|
|
17710
|
+
if (ran === null) return;
|
|
17711
|
+
const text = this.written.get(ran);
|
|
17712
|
+
if (typeof text === "string") this.runPayload(text, depth);
|
|
17713
|
+
}
|
|
17187
17714
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
17188
17715
|
visitHeredocShell(stmt, depth) {
|
|
17189
17716
|
const cmd = stmt.Cmd;
|
|
@@ -17335,6 +17862,8 @@ zoo`.split("\n");
|
|
|
17335
17862
|
}
|
|
17336
17863
|
};
|
|
17337
17864
|
POSITIONAL2 = "\0positional";
|
|
17865
|
+
NO_VARS = /* @__PURE__ */ new Set();
|
|
17866
|
+
NO_APPENDS = /* @__PURE__ */ new Map();
|
|
17338
17867
|
FORCE_PUSH = {
|
|
17339
17868
|
checkId: "commands.git-destructive",
|
|
17340
17869
|
ruleName: "review-force-push",
|
|
@@ -17393,6 +17922,8 @@ zoo`.split("\n");
|
|
|
17393
17922
|
"--cleanup"
|
|
17394
17923
|
]);
|
|
17395
17924
|
CLEAN_LONG_VALUE = /* @__PURE__ */ new Set(["--exclude"]);
|
|
17925
|
+
RESTORE_LONG_VALUE = /* @__PURE__ */ new Set(["--source", "--pathspec-from-file"]);
|
|
17926
|
+
CHECKOUT_LONG_VALUE = /* @__PURE__ */ new Set(["--pathspec-from-file", "--orphan", "--conflict"]);
|
|
17396
17927
|
HOOKS_BYPASS = {
|
|
17397
17928
|
checkId: "commands.git-hooks-bypass",
|
|
17398
17929
|
ruleName: "review-git-hooks-bypass",
|
|
@@ -17418,6 +17949,7 @@ zoo`.split("\n");
|
|
|
17418
17949
|
"--gpg-sign"
|
|
17419
17950
|
]);
|
|
17420
17951
|
CHMOD_OPTION_RE = /^-[RvcfHLP]+$/;
|
|
17952
|
+
_appendOp = null;
|
|
17421
17953
|
STAGE_ALL = {
|
|
17422
17954
|
checkId: "commands.git-stage-all",
|
|
17423
17955
|
ruleName: "review-git-stage-all",
|
|
@@ -17542,7 +18074,7 @@ zoo`.split("\n");
|
|
|
17542
18074
|
this.visitStmt(n, depth);
|
|
17543
18075
|
return true;
|
|
17544
18076
|
}
|
|
17545
|
-
if (type === "BinaryCmd" &&
|
|
18077
|
+
if (type === "BinaryCmd" && isPipeOp2(n.Op)) {
|
|
17546
18078
|
this.visitPipeline(n);
|
|
17547
18079
|
return true;
|
|
17548
18080
|
}
|
|
@@ -17643,7 +18175,7 @@ zoo`.split("\n");
|
|
|
17643
18175
|
const stages = [];
|
|
17644
18176
|
const flatten = (s) => {
|
|
17645
18177
|
const c = s?.Cmd;
|
|
17646
|
-
if (c && c.kind === "BinaryCmd" &&
|
|
18178
|
+
if (c && c.kind === "BinaryCmd" && isPipeOp2(c.Op)) {
|
|
17647
18179
|
flatten(c.X);
|
|
17648
18180
|
flatten(c.Y);
|
|
17649
18181
|
} else stages.push(s);
|
|
@@ -18830,7 +19362,7 @@ zoo`.split("\n");
|
|
|
18830
19362
|
{ view: "separators-stripped", decoder: "separators", stripped: true }
|
|
18831
19363
|
];
|
|
18832
19364
|
LONG_OUTPUT_THRESHOLD_BYTES = 100 * 1024;
|
|
18833
|
-
CANONICAL_EXTRACTOR_VERSION = "canonical-
|
|
19365
|
+
CANONICAL_EXTRACTOR_VERSION = "canonical-v37";
|
|
18834
19366
|
}
|
|
18835
19367
|
});
|
|
18836
19368
|
|
|
@@ -20125,11 +20657,18 @@ function slug(s) {
|
|
|
20125
20657
|
return s.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "rule";
|
|
20126
20658
|
}
|
|
20127
20659
|
function pathToRegexFragment(rawPath) {
|
|
20128
|
-
const
|
|
20660
|
+
const trimmed = rawPath.trim();
|
|
20661
|
+
const tail = trimmed.replace(/^~[\\/]?/, "").replace(/^\$\{?HOME\}?[\\/]?/, "").replace(/^\/(?:home|Users)\/[^\\/]+[\\/]?/, "").replace(/^[A-Za-z]:[\\/]Users[\\/][^\\/]+[\\/]?/, "").replace(/^[\\/]+/, "").replace(/[\\/]+$/, "");
|
|
20129
20662
|
const segments2 = tail.split(/[\\/]+/).filter(Boolean).map(escapeRegex);
|
|
20130
20663
|
if (segments2.length === 0) return "";
|
|
20664
|
+
if (isAbsoluteOutsideHome(trimmed)) {
|
|
20665
|
+
return `(^|[^A-Za-z0-9_.~\\/-])/${segments2.join(SEP)}(${B}|$)`;
|
|
20666
|
+
}
|
|
20131
20667
|
return `(^|${B})${segments2.join(SEP)}(${B}|$)`;
|
|
20132
20668
|
}
|
|
20669
|
+
function isAbsoluteOutsideHome(p) {
|
|
20670
|
+
return p.startsWith("/") && !/^\/(?:home|Users|root)(?:\/|$)/.test(p);
|
|
20671
|
+
}
|
|
20133
20672
|
function pathMatchesFragment(candidate, rawPath) {
|
|
20134
20673
|
const value = pathToRegexFragment(rawPath);
|
|
20135
20674
|
if (!value || !candidate) return false;
|
|
@@ -21417,7 +21956,8 @@ function getConfig(cwd) {
|
|
|
21417
21956
|
trustedHostsManaged: false,
|
|
21418
21957
|
appPermissions: {},
|
|
21419
21958
|
appLinks: {},
|
|
21420
|
-
managedJailPaths: []
|
|
21959
|
+
managedJailPaths: [],
|
|
21960
|
+
jailPaths: []
|
|
21421
21961
|
};
|
|
21422
21962
|
const mergedEnvironments = { ...DEFAULT_CONFIG.environments };
|
|
21423
21963
|
const rank = (v) => {
|
|
@@ -21812,6 +22352,7 @@ function getConfig(cwd) {
|
|
|
21812
22352
|
mergedPolicy.smartRules.push({ ...r, name: `org:${r.name}` });
|
|
21813
22353
|
}
|
|
21814
22354
|
mergedPolicy.managedJailPaths.push({ path: path54, verdict });
|
|
22355
|
+
mergedPolicy.jailPaths.push(path54);
|
|
21815
22356
|
}
|
|
21816
22357
|
}
|
|
21817
22358
|
if (Array.isArray(mc.trustedHosts)) {
|
|
@@ -21887,6 +22428,11 @@ function getConfig(cwd) {
|
|
|
21887
22428
|
}
|
|
21888
22429
|
}
|
|
21889
22430
|
mergedPolicy.appliedShields = appliedShields.sort();
|
|
22431
|
+
if (appliedShields.includes(USER_JAIL_SHIELD)) {
|
|
22432
|
+
for (const { path: path54 } of readJailPaths()) {
|
|
22433
|
+
if (!mergedPolicy.jailPaths.includes(path54)) mergedPolicy.jailPaths.push(path54);
|
|
22434
|
+
}
|
|
22435
|
+
}
|
|
21890
22436
|
const existingAdvisoryNames = new Set(mergedPolicy.smartRules.map((r) => r.name));
|
|
21891
22437
|
const cc = mergedPolicy.commandChecks ?? {};
|
|
21892
22438
|
const advisoryKnobKey = (name) => {
|
|
@@ -22154,6 +22700,7 @@ var init_config = __esm({
|
|
|
22154
22700
|
init_shields();
|
|
22155
22701
|
init_managed();
|
|
22156
22702
|
init_build();
|
|
22703
|
+
init_jail();
|
|
22157
22704
|
init_trusted_hosts();
|
|
22158
22705
|
init_dist();
|
|
22159
22706
|
init_dist();
|
|
@@ -22422,7 +22969,8 @@ var init_config = __esm({
|
|
|
22422
22969
|
trustedHostsManaged: false,
|
|
22423
22970
|
appPermissions: {},
|
|
22424
22971
|
appLinks: {},
|
|
22425
|
-
managedJailPaths: []
|
|
22972
|
+
managedJailPaths: [],
|
|
22973
|
+
jailPaths: []
|
|
22426
22974
|
},
|
|
22427
22975
|
environments: {}
|
|
22428
22976
|
};
|