@blogic-cz/agent-tools 1.6.4 → 1.6.5
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/README.md
CHANGED
|
@@ -672,6 +672,8 @@ The bounded Python subprocess proof supports one immutable literal argv binding
|
|
|
672
672
|
|
|
673
673
|
Supported runtime script/tool operands form an argument boundary: a later tool `-c` configuration flag is data. Genuine eval and loader flags, Bun exec/repl and unproved startup-option arity still refuse. Literal Herdr prompts can compose with the existing literal agent-get and pane-read forms and passive consumers. One literal `--sql` operand on the supported `bun run db-tool sql/query` shape can contain SQL braces; substitutions, duplicate SQL operands and unknown wrapper options receive no exception. SQL output pipelines require closed passive consumers, so shell, xargs and unknown executors refuse. Numeric `$?` can appear only in passive echo/printf data operands, with passive pipeline consumers. Explicitly approved environment names can appear in quoted equality or blankness tests, including the quoted empty default `${NAME:-}`. This does not add default-approved names or permit shell evaluators. One sed print program with numeric or escaped-regex addresses/ranges and known `-n`/`-E` flags is passive; execution/read/write callbacks, extra programs and script files receive no print proof. Local file bindings use that same closed print proof and never a generic sed-word fallback. Ordinary path and configured command policies still apply to all these forms.
|
|
674
674
|
|
|
675
|
+
Literal shell bodies receive recursive shared policy replay under exact `sh -c`/`bash -c` and `zsh -f -c` invocations, using only these bare executable names or their `/bin/` and `/usr/bin/` paths and known RTK/command wrappers. Both protected paths and blocked CLIs remain enforced inside the body, along with environment and custom-command policies. A conventional shell-family name or numeric version in an unproved executing operand/control position refuses; proved literal text, reader and file-metadata operands remain data. Only the listed sh/bash/zsh identities receive body replay; rbash/rksh/ksh93 and versioned names refuse, and arbitrary renamed executables are outside this identity proof. Replay permits only existing closed body roles/materializations, at most eight shell levels and 64 KiB per invocation. Unproved options, environment prefixes, active exec/nohup/sudo wrappers, positional/script/stdin forms, executable binders, control flow and outer directory changes around a wrapper refuse. A body-internal proved cd affects body readers; outer redirects retain the outer shell directory. This is a textual body proof, not verification of native binaries or all host startup code. In particular, zsh -f still sources the global zshenv file. For unsupported executable inventories, use separate literal metadata requests and literal candidate invocations; no program name or --version flag receives a special exception.
|
|
676
|
+
|
|
675
677
|
A separate bounded Node proof supports literal `package.json` inventory loops that print `bin` metadata or use the supported scripts filter. The complete invocation must preserve loader identity through known passive commands, closed literal writers, or proved inventories. Startup/environment mutations, unknown commands, loader changes, and other dynamic loading remain unproved and are refused.
|
|
676
678
|
|
|
677
679
|
### Setup for OpenCode
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/credential-guard/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAmB,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAK5E,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAM/D,8CAA8C;AAC9C,MAAM,MAAM,SAAS,GAAG;IACtB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,+CAA+C;AAC/C,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B,CAAC;AAQF,+CAA+C;AAC/C,MAAM,MAAM,eAAe,GAAG;IAC5B,uBAAuB,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,KAAK,IAAI,CAAC;IACxE,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAC3E,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC;IAC7C,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC;IAC7C,sBAAsB,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC;IACrD,iBAAiB,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACjF,kBAAkB,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC;IACjD,kBAAkB,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;CACxD,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/credential-guard/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAmB,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAK5E,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAM/D,8CAA8C;AAC9C,MAAM,MAAM,SAAS,GAAG;IACtB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,+CAA+C;AAC/C,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B,CAAC;AAQF,+CAA+C;AAC/C,MAAM,MAAM,eAAe,GAAG;IAC5B,uBAAuB,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,KAAK,IAAI,CAAC;IACxE,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAC3E,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC;IAC7C,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC;IAC7C,sBAAsB,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC;IACrD,iBAAiB,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACjF,kBAAkB,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC;IACjD,kBAAkB,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;CACxD,CAAC;AA2oFF,6CAA6C;AAC7C,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAErE;AAED,2CAA2C;AAC3C,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAEpE;AAED,2CAA2C;AAC3C,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAEpE;AAMD;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,CAAC,EAAE,qBAAqB,GAAG,eAAe,CA4VrF;AAQD,kEAAkE;AAClE,eAAO,MAAM,uBAAuB,UAjhGD,SAAS,UAAU,UAAU,KAAK,IAihGM,CAAC;AAE5E,oDAAoD;AACpD,eAAO,MAAM,aAAa,YAnhGC,MAAM,KAAK;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,IAmhGjB,CAAC;AAExD,yEAAyE;AACzE,eAAO,MAAM,aAAa,aArhGE,MAAM,KAAK,OAqhGgB,CAAC;AAExD,yDAAyD;AACzD,eAAO,MAAM,aAAa,aAvhGE,MAAM,KAAK,OAuhGgB,CAAC;AAExD,oEAAoE;AACpE,eAAO,MAAM,sBAAsB,YAzhGC,MAAM,KAAK,OAyhG0B,CAAC;AAE1E,iDAAiD;AACjD,eAAO,MAAM,iBAAiB,YA3hGC,MAAM,KAAK;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,IA2hGf,CAAC;AAEhE,wDAAwD;AACxD,eAAO,MAAM,kBAAkB,YA7hGC,MAAM,KAAK,OA6hGsB,CAAC;AAElE,8EAA8E;AAC9E,eAAO,MAAM,kBAAkB,YA/hGC,MAAM,KAAK,MAAM,GAAG,IA+hGa,CAAC"}
|
package/package.json
CHANGED
|
@@ -530,6 +530,114 @@ function isLiteralHerdrRead(argv: string[]): boolean {
|
|
|
530
530
|
);
|
|
531
531
|
}
|
|
532
532
|
|
|
533
|
+
/** Conventional platform shell names and numeric versions; not arbitrary renamed executables. */
|
|
534
|
+
function isShellWord(word: string): boolean {
|
|
535
|
+
return /^(?:sh|bash|rbash|zsh|dash|ash|ksh|rksh|csh|tcsh|fish)(?:[.-]?[0-9]+(?:[.][0-9]+)*)?$/.test(
|
|
536
|
+
word.split("/").at(-1) ?? "",
|
|
537
|
+
);
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
/** Shell-named operands are data only under an existing non-executing argument role. */
|
|
541
|
+
function hasProvedShellDataOperands(argv: string[]): boolean {
|
|
542
|
+
const name = argv[0]?.split("/").at(-1) ?? "";
|
|
543
|
+
if (isPassiveTextCommand(argv) || isLiteralHerdrRead(argv) || isStaticNavigationCommand(argv))
|
|
544
|
+
return true;
|
|
545
|
+
if (["cat", "ls", "uniq", "cut"].includes(name)) return true;
|
|
546
|
+
if (["find", "wc", "sort"].includes(name)) return isProvedCwdSubprocessRole(argv);
|
|
547
|
+
return name === "test" && argv.length === 3 && argv[1] === "-e" && !/[$`]/.test(argv[2] ?? "");
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
const SHELL_IDENTITIES = new Set([
|
|
551
|
+
"sh",
|
|
552
|
+
"bash",
|
|
553
|
+
"zsh",
|
|
554
|
+
"/bin/sh",
|
|
555
|
+
"/usr/bin/sh",
|
|
556
|
+
"/bin/bash",
|
|
557
|
+
"/usr/bin/bash",
|
|
558
|
+
"/bin/zsh",
|
|
559
|
+
"/usr/bin/zsh",
|
|
560
|
+
]);
|
|
561
|
+
|
|
562
|
+
/** Literal argv only. Undefined means a shell was found without a complete invocation proof. */
|
|
563
|
+
function literalShellBodies(command: string): string[] | undefined {
|
|
564
|
+
const parsed = parseStaticShellCommands(command);
|
|
565
|
+
const operands = parsed ?? parseStaticShellCommands(command, true);
|
|
566
|
+
if (!operands || typeof operands === "string") return [];
|
|
567
|
+
const commands = operands.pipelines.flat();
|
|
568
|
+
if (
|
|
569
|
+
commands.some((words) =>
|
|
570
|
+
["exec", "nohup", "sudo"].includes(unwrapStaticCommand(words)[0]?.split("/").at(-1) ?? ""),
|
|
571
|
+
)
|
|
572
|
+
)
|
|
573
|
+
return undefined;
|
|
574
|
+
for (const words of commands) {
|
|
575
|
+
const argv = unwrapStaticCommand(words);
|
|
576
|
+
if (
|
|
577
|
+
!isShellWord(argv[0] ?? "") &&
|
|
578
|
+
argv.some(
|
|
579
|
+
(word, index) =>
|
|
580
|
+
index !== inlineProgramIndex(argv) &&
|
|
581
|
+
(isShellWord(word) ||
|
|
582
|
+
(/^--?[A-Za-z0-9-]+=/.test(word) && isShellWord(word.slice(word.indexOf("=") + 1)))),
|
|
583
|
+
) &&
|
|
584
|
+
!hasProvedShellDataOperands(argv) &&
|
|
585
|
+
!isStaticHerdrPrompt(command)
|
|
586
|
+
)
|
|
587
|
+
return undefined;
|
|
588
|
+
}
|
|
589
|
+
const shells = commands.filter((words) => isShellWord(unwrapStaticCommand(words)[0] ?? ""));
|
|
590
|
+
if (!shells.length) return [];
|
|
591
|
+
if (
|
|
592
|
+
!parsed ||
|
|
593
|
+
typeof parsed === "string" ||
|
|
594
|
+
!literalBindingText(command, "", "") ||
|
|
595
|
+
new TextEncoder().encode(command).byteLength > 65_536 ||
|
|
596
|
+
commands.some((words) => unwrapStaticCommand(words)[0]?.split("/").at(-1) === "cd")
|
|
597
|
+
)
|
|
598
|
+
return undefined;
|
|
599
|
+
const bodies: string[] = [];
|
|
600
|
+
for (const words of shells) {
|
|
601
|
+
const argv = unwrapProofCommand(words, "\0");
|
|
602
|
+
if (!argv || !SHELL_IDENTITIES.has(argv[0] ?? "")) return undefined;
|
|
603
|
+
const name = argv[0]?.split("/").at(-1);
|
|
604
|
+
if (argv.length === 2 && ["--version", "--help"].includes(argv[1] ?? "")) continue;
|
|
605
|
+
const index = name === "zsh" && argv[1] === "-f" ? 2 : 1;
|
|
606
|
+
if ((name === "zsh" && index !== 2) || argv[index] !== "-c" || argv.length !== index + 2)
|
|
607
|
+
return undefined;
|
|
608
|
+
bodies.push(argv[index + 1] ?? "");
|
|
609
|
+
}
|
|
610
|
+
return bodies;
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
function isProvedLiteralShellBody(body: string): boolean {
|
|
614
|
+
if (!body.trim()) return true;
|
|
615
|
+
const materialized = materializeLiteralShell(body)?.command ?? body;
|
|
616
|
+
const parsed = parseStaticShellCommands(materialized);
|
|
617
|
+
if (!parsed || typeof parsed === "string" || !hasProvedNavigationSequence(materialized))
|
|
618
|
+
return false;
|
|
619
|
+
if (isStaticHerdrPrompt(materialized)) return true;
|
|
620
|
+
return parsed.pipelines.flat().every((words) => {
|
|
621
|
+
const argv = unwrapProofCommand(words, "\0");
|
|
622
|
+
if (!argv) return false;
|
|
623
|
+
if (argv[0]?.split("/").at(-1) === "env") return false;
|
|
624
|
+
const name = unwrapStaticCommand(argv)[0]?.split("/").at(-1) ?? "";
|
|
625
|
+
if (isShellWord(name))
|
|
626
|
+
return (
|
|
627
|
+
literalShellBodies(
|
|
628
|
+
words.map((word) => "'" + word.replaceAll("'", "'\"'\"'") + "'").join(" "),
|
|
629
|
+
) !== undefined
|
|
630
|
+
);
|
|
631
|
+
return (
|
|
632
|
+
isProvedCwdSubprocessRole(unwrapStaticCommand(argv)) ||
|
|
633
|
+
(name === "bun" && isSafeLocalAssignmentCommand(argv) && !isUnsupportedInlineRuntime(argv)) ||
|
|
634
|
+
isStaticNavigationCommand(argv) ||
|
|
635
|
+
isLiteralHerdrRead(argv) ||
|
|
636
|
+
(argv.length === 1 && ["true", "false", "pwd"].includes(name))
|
|
637
|
+
);
|
|
638
|
+
});
|
|
639
|
+
}
|
|
640
|
+
|
|
533
641
|
/** A complete stdin-only JSON projection, with no suffix, imports or executable input. */
|
|
534
642
|
function isLiteralStdinJsonDisplay(argv: string[]): boolean {
|
|
535
643
|
if (argv.length !== 3 || !["python", "python3"].includes(argv[0] ?? "") || argv[1] !== "-c")
|
|
@@ -1858,6 +1966,7 @@ function hasEnvironmentRead(
|
|
|
1858
1966
|
command: string,
|
|
1859
1967
|
allowedNames: Set<string>,
|
|
1860
1968
|
allowInventory = hasProvedPackageInventoryInvocation(command),
|
|
1969
|
+
replayedShellBodies: string[] = [],
|
|
1861
1970
|
): boolean {
|
|
1862
1971
|
if (isStaticHerdrPrompt(command)) return false;
|
|
1863
1972
|
if (isHerdrPrompt(command)) return true;
|
|
@@ -1926,7 +2035,13 @@ function hasEnvironmentRead(
|
|
|
1926
2035
|
) {
|
|
1927
2036
|
return true;
|
|
1928
2037
|
}
|
|
1929
|
-
if (
|
|
2038
|
+
if (
|
|
2039
|
+
unwrapped.some(
|
|
2040
|
+
(argv) =>
|
|
2041
|
+
!(SHELL_IDENTITIES.has(argv[0] ?? "") && replayedShellBodies.includes(argv.at(-1) ?? "")) &&
|
|
2042
|
+
hasStaticEnvironmentRead(argv, allowedNames, allowInventory),
|
|
2043
|
+
)
|
|
2044
|
+
) {
|
|
1930
2045
|
return true;
|
|
1931
2046
|
}
|
|
1932
2047
|
|
|
@@ -2743,7 +2858,7 @@ export function createCredentialGuard(config?: CredentialGuardConfig): Credentia
|
|
|
2743
2858
|
return getDangerousBashReason(command) !== null;
|
|
2744
2859
|
}
|
|
2745
2860
|
|
|
2746
|
-
function getDangerousBashReason(command: string): string | null {
|
|
2861
|
+
function getDangerousBashReason(command: string, shellDepth = 0): string | null {
|
|
2747
2862
|
const originalCommand = command;
|
|
2748
2863
|
const allowPackageInventory = hasProvedPackageInventoryInvocation(originalCommand);
|
|
2749
2864
|
const rawEnvironmentSource =
|
|
@@ -2757,20 +2872,30 @@ export function createCredentialGuard(config?: CredentialGuardConfig): Credentia
|
|
|
2757
2872
|
if (rawEnvironmentSource && hasEnvironmentMutationPrefix(originalCommand))
|
|
2758
2873
|
return "blocked by the environment/execution policy after an unproved environment mutation";
|
|
2759
2874
|
command = normalizeProgramHeredocs(command);
|
|
2875
|
+
const shellBodies = literalShellBodies(command);
|
|
2876
|
+
if (!shellBodies || (shellBodies.length && shellDepth >= 8))
|
|
2877
|
+
return "cannot prove a bounded literal shell invocation";
|
|
2878
|
+
for (const body of shellBodies) {
|
|
2879
|
+
const reason = getDangerousBashReason(body, shellDepth + 1);
|
|
2880
|
+
if (reason || getBlockedCliTool(body, true, shellDepth + 1))
|
|
2881
|
+
return reason ?? "invokes a blocked CLI from a shell body";
|
|
2882
|
+
if (!isProvedLiteralShellBody(body)) return "cannot prove a closed literal shell body";
|
|
2883
|
+
}
|
|
2760
2884
|
const proof = materializeLiteralShell(command);
|
|
2761
2885
|
if (!proof && /^\s*for\b/.test(command)) return "cannot prove a bounded literal shell loop";
|
|
2762
2886
|
if (proof) {
|
|
2763
2887
|
if (proof.paths.some((path) => hasSensitiveFileRead("cat " + path, isPathBlocked)))
|
|
2764
2888
|
return "accesses a sensitive file path";
|
|
2765
2889
|
command = proof.command;
|
|
2766
|
-
if (getBlockedCliTool(command))
|
|
2890
|
+
if (getBlockedCliTool(command, true, shellDepth))
|
|
2891
|
+
return "invokes a blocked CLI from a literal expansion";
|
|
2767
2892
|
}
|
|
2768
2893
|
for (const nested of [
|
|
2769
2894
|
...inlineSubprocessCommands(command),
|
|
2770
2895
|
...inlinePackageCommands(command, allowPackageInventory),
|
|
2771
2896
|
]) {
|
|
2772
|
-
const reason = getDangerousBashReason(nested);
|
|
2773
|
-
if (reason || getBlockedCliTool(nested))
|
|
2897
|
+
const reason = getDangerousBashReason(nested, shellDepth);
|
|
2898
|
+
if (reason || getBlockedCliTool(nested, true, shellDepth))
|
|
2774
2899
|
return reason ?? "invokes a blocked CLI from a script";
|
|
2775
2900
|
}
|
|
2776
2901
|
if (
|
|
@@ -2786,7 +2911,21 @@ export function createCredentialGuard(config?: CredentialGuardConfig): Credentia
|
|
|
2786
2911
|
}
|
|
2787
2912
|
if (
|
|
2788
2913
|
hasEnvironmentSourceAccess(command, rawEnvironmentSource, allowedEnvironmentVariables) ||
|
|
2789
|
-
hasEnvironmentRead(
|
|
2914
|
+
hasEnvironmentRead(
|
|
2915
|
+
command,
|
|
2916
|
+
allowedEnvironmentVariables,
|
|
2917
|
+
allowPackageInventory,
|
|
2918
|
+
shellBodies.filter((body) => {
|
|
2919
|
+
const parsed = parseStaticShellCommands(body);
|
|
2920
|
+
return (
|
|
2921
|
+
parsed &&
|
|
2922
|
+
typeof parsed !== "string" &&
|
|
2923
|
+
parsed.pipelines
|
|
2924
|
+
.flat()
|
|
2925
|
+
.every((words) => isPassiveTextCommand(unwrapStaticCommand(words)))
|
|
2926
|
+
);
|
|
2927
|
+
}),
|
|
2928
|
+
)
|
|
2790
2929
|
) {
|
|
2791
2930
|
return "blocked by the environment/execution policy; permitted access or non-execution could not be established for this command form";
|
|
2792
2931
|
}
|
|
@@ -2828,16 +2967,24 @@ export function createCredentialGuard(config?: CredentialGuardConfig): Credentia
|
|
|
2828
2967
|
function getBlockedCliTool(
|
|
2829
2968
|
command: string,
|
|
2830
2969
|
expand = true,
|
|
2970
|
+
shellDepth = 0,
|
|
2831
2971
|
): { name: string; wrapper: string } | null {
|
|
2832
2972
|
command = normalizeProgramHeredocs(command);
|
|
2973
|
+
const shellBodies = literalShellBodies(command);
|
|
2974
|
+
if (shellBodies && shellDepth < 8) {
|
|
2975
|
+
for (const body of shellBodies) {
|
|
2976
|
+
const blocked = getBlockedCliTool(body, true, shellDepth + 1);
|
|
2977
|
+
if (blocked) return blocked;
|
|
2978
|
+
}
|
|
2979
|
+
}
|
|
2833
2980
|
const proof = expand ? materializeLiteralShell(command) : undefined;
|
|
2834
2981
|
if (proof) {
|
|
2835
|
-
const originalBlocked = getBlockedCliTool(command, false);
|
|
2982
|
+
const originalBlocked = getBlockedCliTool(command, false, shellDepth);
|
|
2836
2983
|
if (originalBlocked) return originalBlocked;
|
|
2837
2984
|
command = proof.command;
|
|
2838
2985
|
}
|
|
2839
2986
|
for (const nested of inlineSubprocessCommands(command)) {
|
|
2840
|
-
const blocked = getBlockedCliTool(nested);
|
|
2987
|
+
const blocked = getBlockedCliTool(nested, true, shellDepth);
|
|
2841
2988
|
if (blocked) return blocked;
|
|
2842
2989
|
}
|
|
2843
2990
|
const staticCommands = parseStaticShellCommands(command);
|