From dc4c5887fa8702e442dd8cd8f835ebd3bb23a13a Mon Sep 17 00:00:00 2001 From: Pavan Kumar Gondhi Date: Fri, 24 Jul 2026 15:21:24 +0530 Subject: [PATCH] fix: keep inline eval approvals one-shot [AI] (#112956) * fix: classify inline eval interpreters * fix: cover inline eval flag variants * fix: handle snippet eval option aliases * fix: classify debugger and runtime callbacks * fix: tighten interpreter eval matching * fix: cover gdb early init eval flags * fix: cover bundled eval option forms * fix: cover gdb eval abbreviations * fix: cover iex and guile eval forms --- .../command-analysis/inline-eval.test.ts | 183 +++++++++++++++++ src/infra/command-analysis/inline-eval.ts | 141 ++++++++++++- src/infra/exec-approvals-allow-always.test.ts | 187 ++++++++++++++++++ 3 files changed, 509 insertions(+), 2 deletions(-) diff --git a/src/infra/command-analysis/inline-eval.test.ts b/src/infra/command-analysis/inline-eval.test.ts index 64b5949d3792..8ed36b53733c 100644 --- a/src/infra/command-analysis/inline-eval.test.ts +++ b/src/infra/command-analysis/inline-eval.test.ts @@ -61,6 +61,142 @@ describe("exec inline eval detection", () => { { argv: ["php", "-E", "system('id');"], expected: "php -E" }, { argv: ["php", "-R", "system('id');"], expected: "php -R" }, { argv: ["Rscript", "-e", "system('id')"], expected: "rscript -e" }, + { argv: ["julia", "-e", "run(`id`)"], expected: "julia -e" }, + { argv: ["julia", "-erun(`id`)"], expected: "julia -e" }, + { argv: ["julia", "--eval=run(`id`)"], expected: "julia --eval" }, + { argv: ["julia", "-E", "VERSION"], expected: "julia -E" }, + { argv: ["julia", "-EVERSION"], expected: "julia -E" }, + { argv: ["elixir", "-e", 'System.cmd("id", [])'], expected: "elixir -e" }, + { argv: ["elixir", '--eval=System.cmd("id", [])'], expected: "elixir --eval" }, + { + argv: ["elixir", "--rpc-eval", "worker@127.0.0.1", 'System.cmd("id", [])'], + expected: "elixir --rpc-eval", + }, + { argv: ["iex", "-e", 'System.cmd("id", [])'], expected: "iex -e" }, + { + argv: ["iex", "--rpc-eval", "worker@127.0.0.1", 'System.cmd("id", [])'], + expected: "iex --rpc-eval", + }, + { argv: ["guile", "-c", '(system "id")'], expected: "guile -c" }, + { argv: ["guile", "-e", '(lambda args (system "id"))', "/dev/null"], expected: "guile -e" }, + { argv: ["groovy", "-e", '"id".execute()'], expected: "groovy -e" }, + { argv: ["groovy", '-e"id".execute()'], expected: "groovy -e" }, + { argv: ["groovy", "-ne", '["id"].execute()'], expected: "groovy -e" }, + { argv: ["groovy", "-pe", '["id"].execute()'], expected: "groovy -e" }, + { argv: ["groovy", '-encoding:["id"].execute()'], expected: "groovy -e" }, + { argv: ["scala", "-e", 'sys.process.Process("id").!'], expected: "scala -e" }, + { + argv: ["scala", "--script-snippet", 'sys.process.Process("id").!'], + expected: "scala --script-snippet", + }, + { + argv: ["scala-cli", "--script-snippet", 'sys.process.Process("id").!'], + expected: "scala-cli --script-snippet", + }, + { + argv: ["scala", "--execute-script", 'sys.process.Process("id").!'], + expected: "scala --execute-script", + }, + { + argv: ["scala", "--execute-sc=println(1)"], + expected: "scala --execute-sc", + }, + { + argv: ["scala", "--execute-scala-script=println(1)"], + expected: "scala --execute-scala-script", + }, + { + argv: ["scala", "--scala-snippet=println(1)"], + expected: "scala --scala-snippet", + }, + { + argv: ["scala", "--execute-scala=println(1)"], + expected: "scala --execute-scala", + }, + { + argv: ["scala", "--java-snippet", "class Main {}"], + expected: "scala --java-snippet", + }, + { + argv: ["scala", "--execute-java=class Main {}"], + expected: "scala --execute-java", + }, + { + argv: ["scala", "--markdown-snippet", "```scala\nprintln(1)\n```"], + expected: "scala --markdown-snippet", + }, + { + argv: ["scala", "--md-snippet=```scala\nprintln(1)\n```"], + expected: "scala --md-snippet", + }, + { + argv: ["scala", "--execute-markdown", "```scala\nprintln(1)\n```"], + expected: "scala --execute-markdown", + }, + { + argv: ["scala", "--execute-md=```scala\nprintln(1)\n```"], + expected: "scala --execute-md", + }, + { argv: ["clojure", "-e", '(clojure.java.shell/sh "id")'], expected: "clojure -e" }, + { argv: ["clj", "--eval", "(println 1)"], expected: "clj --eval" }, + { argv: ["raku", "-e", "run 'id'"], expected: "raku -e" }, + { argv: ["raku", "-e say 1"], expected: "raku -e" }, + { argv: ["raku", "-ne", "run 'id'"], expected: "raku -e" }, + { argv: ["perl6", "-e", "run 'id'"], expected: "perl6 -e" }, + { argv: ["perl6", "-pe", "run 'id'"], expected: "perl6 -e" }, + { argv: ["ghc", "-e", 'System.Process.system "id"'], expected: "ghc -e" }, + { argv: ["ghci", "-e", 'System.Process.system "id"'], expected: "ghci -e" }, + { argv: ["erl", "-eval", 'os:cmd("id").'], expected: "erl -eval" }, + { argv: ["erl", "-run", "os", "cmd", "id"], expected: "erl -run" }, + { argv: ["erl", "-s", "os", "cmd", "id"], expected: "erl -s" }, + { argv: ["erl", "-noshell", "-s", "init", "stop"], expected: "erl -s" }, + { argv: ["werl", "-eval", 'os:cmd("id").'], expected: "werl -eval" }, + { argv: ["werl", "-run", "os", "cmd", "id"], expected: "werl -run" }, + { argv: ["gdb", "-ex", "shell id", "-ex", "quit"], expected: "gdb -ex" }, + { argv: ["gdb", "-ex=shell id", "-ex", "quit"], expected: "gdb -ex" }, + { argv: ["gdb", "-iex", "shell id"], expected: "gdb -iex" }, + { argv: ["gdb", "-iex=shell id"], expected: "gdb -iex" }, + { argv: ["gdb", "-ev", "shell id"], expected: "gdb -eval-command" }, + { argv: ["gdb", "-eval", "shell id"], expected: "gdb -eval-command" }, + { argv: ["gdb", "-eval-c", "shell id"], expected: "gdb -eval-command" }, + { argv: ["gdb", "-eval-c=shell id"], expected: "gdb -eval-command" }, + { argv: ["gdb", "-eval-command", "shell id"], expected: "gdb -eval-command" }, + { argv: ["gdb", "-eval-command=shell id"], expected: "gdb -eval-command" }, + { argv: ["gdb", "--ev", "shell id"], expected: "gdb --eval-command" }, + { argv: ["gdb", "--eval", "shell id"], expected: "gdb --eval-command" }, + { argv: ["gdb", "--eval-c=shell id"], expected: "gdb --eval-command" }, + { argv: ["gdb", "--eval-command=shell id"], expected: "gdb --eval-command" }, + { argv: ["gdb", "-init-e", "shell id"], expected: "gdb -init-eval-command" }, + { argv: ["gdb", "-init-eval", "shell id"], expected: "gdb -init-eval-command" }, + { argv: ["gdb", "-init-eval-c=shell id"], expected: "gdb -init-eval-command" }, + { argv: ["gdb", "--init-e", "shell id"], expected: "gdb --init-eval-command" }, + { argv: ["gdb", "--init-eval-command=shell id"], expected: "gdb --init-eval-command" }, + { argv: ["gdb", "--init-eval=shell id"], expected: "gdb --init-eval-command" }, + { argv: ["gdb", "-init-eval-command=shell id"], expected: "gdb -init-eval-command" }, + { argv: ["gdb", "-eiex", "shell id"], expected: "gdb -eiex" }, + { argv: ["gdb", "-eiex=shell id"], expected: "gdb -eiex" }, + { + argv: ["gdb", "-early-init-e", "shell id"], + expected: "gdb -early-init-eval-command", + }, + { + argv: ["gdb", "-early-init-eval", "shell id"], + expected: "gdb -early-init-eval-command", + }, + { + argv: ["gdb", "--early-init-e=shell id"], + expected: "gdb --early-init-eval-command", + }, + { + argv: ["gdb", "--early-init-eval=shell id"], + expected: "gdb --early-init-eval-command", + }, + { + argv: ["gdb", "-early-init-eval-command=shell id"], + expected: "gdb -early-init-eval-command", + }, + { argv: ["expect", "-c", "spawn id"], expected: "expect -c" }, + { argv: ["expect", "-cspawn id"], expected: "expect -c" }, { argv: ["lua", "-eprint(1)"], expected: "lua -e" }, { argv: ["osascript", "-e", "beep"], expected: "osascript -e" }, { argv: ["osascript", '-edisplay alert "hi"'], expected: "osascript -e" }, @@ -121,6 +257,38 @@ describe("exec inline eval detection", () => { expect(detectInterpreterInlineEvalArgv(["perl", "-0xFFpe", "say 1"])).toBeNull(); expect(detectInterpreterInlineEvalArgv(["php", "-F", "filter.php"])).toBeNull(); expect(detectInterpreterInlineEvalArgv(["Rscript", "script.R"])).toBeNull(); + expect(detectInterpreterInlineEvalArgv(["julia", "script.jl"])).toBeNull(); + expect(detectInterpreterInlineEvalArgv(["elixir", "script.exs"])).toBeNull(); + expect(detectInterpreterInlineEvalArgv(["elixir", "-eIO.puts(1)"])).toBeNull(); + expect(detectInterpreterInlineEvalArgv(["iex", "-eIO.puts(1)"])).toBeNull(); + expect(detectInterpreterInlineEvalArgv(["guile", "script.scm"])).toBeNull(); + expect(detectInterpreterInlineEvalArgv(["guile", "-c(display 1)"])).toBeNull(); + expect(detectInterpreterInlineEvalArgv(["guile", "-e(display 1)"])).toBeNull(); + expect(detectInterpreterInlineEvalArgv(["groovy", "script.groovy"])).toBeNull(); + expect( + detectInterpreterInlineEvalArgv(["groovy", "-encoding", "UTF-8", "script.groovy"]), + ).toBeNull(); + expect( + detectInterpreterInlineEvalArgv(["groovy", "-encoding=UTF-8", "script.groovy"]), + ).toBeNull(); + expect(detectInterpreterInlineEvalArgv(["scala", "script.scala"])).toBeNull(); + expect( + detectInterpreterInlineEvalArgv(["scala", "-encoding", "UTF-8", "script.scala"]), + ).toBeNull(); + expect(detectInterpreterInlineEvalArgv(["scala-cli", "script.scala"])).toBeNull(); + expect(detectInterpreterInlineEvalArgv(["clojure", "-M", "-m", "app.main"])).toBeNull(); + expect(detectInterpreterInlineEvalArgv(["clojure", "-e(println 1)"])).toBeNull(); + expect(detectInterpreterInlineEvalArgv(["raku", "script.raku"])).toBeNull(); + expect(detectInterpreterInlineEvalArgv(["ghc", "Main.hs"])).toBeNull(); + expect(detectInterpreterInlineEvalArgv(["ghc", "-exclude-module", "Debug.Trace"])).toBeNull(); + expect(detectInterpreterInlineEvalArgv(["erl", "-sname", "node"])).toBeNull(); + expect(detectInterpreterInlineEvalArgv(["erl", "-setcookie", "cookie"])).toBeNull(); + expect(detectInterpreterInlineEvalArgv(["erl", "-shutdown_time", "1000"])).toBeNull(); + expect(detectInterpreterInlineEvalArgv(["gdb", "-e", "program"])).toBeNull(); + expect(detectInterpreterInlineEvalArgv(["gdb", "--command=commands.gdb"])).toBeNull(); + expect(detectInterpreterInlineEvalArgv(["gdb", "-eix", "early.gdb"])).toBeNull(); + expect(detectInterpreterInlineEvalArgv(["gdb", "-early-init-command", "early.gdb"])).toBeNull(); + expect(detectInterpreterInlineEvalArgv(["expect", "script.exp"])).toBeNull(); expect(detectInterpreterInlineEvalArgv(["r2", "-e", "bin.cache=true", "program"])).toBeNull(); expect(detectInterpreterInlineEvalArgv(["awk", "-f", "script.awk", "data.csv"])).toBeNull(); expect(detectInterpreterInlineEvalArgv(["find", ".", "-name", "*.ts"])).toBeNull(); @@ -142,6 +310,21 @@ describe("exec inline eval detection", () => { expect(isInterpreterLikeAllowlistPattern("pypy3.10")).toBe(true); expect(isInterpreterLikeAllowlistPattern("**/node")).toBe(true); expect(isInterpreterLikeAllowlistPattern("Rscript")).toBe(true); + expect(isInterpreterLikeAllowlistPattern("/opt/bin/julia")).toBe(true); + expect(isInterpreterLikeAllowlistPattern("**/elixir")).toBe(true); + expect(isInterpreterLikeAllowlistPattern("iex")).toBe(true); + expect(isInterpreterLikeAllowlistPattern("guile3.0")).toBe(true); + expect(isInterpreterLikeAllowlistPattern("/usr/bin/groovy")).toBe(true); + expect(isInterpreterLikeAllowlistPattern("scala")).toBe(true); + expect(isInterpreterLikeAllowlistPattern("scala-cli")).toBe(true); + expect(isInterpreterLikeAllowlistPattern("clojure.exe")).toBe(true); + expect(isInterpreterLikeAllowlistPattern("**/clj")).toBe(true); + expect(isInterpreterLikeAllowlistPattern("raku")).toBe(true); + expect(isInterpreterLikeAllowlistPattern("perl6")).toBe(true); + expect(isInterpreterLikeAllowlistPattern("ghci")).toBe(true); + expect(isInterpreterLikeAllowlistPattern("erl")).toBe(true); + expect(isInterpreterLikeAllowlistPattern("gdb")).toBe(true); + expect(isInterpreterLikeAllowlistPattern("expect")).toBe(true); expect(isInterpreterLikeAllowlistPattern("r2")).toBe(false); expect(isInterpreterLikeAllowlistPattern("/usr/bin/awk")).toBe(true); expect(isInterpreterLikeAllowlistPattern("**/gawk")).toBe(true); diff --git a/src/infra/command-analysis/inline-eval.ts b/src/infra/command-analysis/inline-eval.ts index eca8b460e5e1..96f69143d0e2 100644 --- a/src/infra/command-analysis/inline-eval.ts +++ b/src/infra/command-analysis/inline-eval.ts @@ -15,11 +15,22 @@ type PrefixFlagSpec = { prefix: string; }; +type AbbreviatedFlagSpec = { + label: string; + full: string; + min: string; +}; + type InterpreterFlagSpec = { names: readonly string[]; exactFlags: ReadonlySet; rawExactFlags?: ReadonlyMap; rawPrefixFlags?: readonly PrefixFlagSpec[]; + abbreviatedFlags?: readonly AbbreviatedFlagSpec[]; + joinedExactFlags?: ReadonlySet; + joinedRawExactFlags?: ReadonlyMap; + joinedFlagDenyExact?: ReadonlySet; + joinedFlagDenyPrefixes?: readonly string[]; prefixFlags?: readonly PrefixFlagSpec[]; shortClusterFlags?: readonly ShortClusterFlagSpec[]; scanPastDoubleDash?: boolean; @@ -161,6 +172,107 @@ const FLAG_INTERPRETER_INLINE_EVAL_SPECS: readonly InterpreterFlagSpec[] = [ ]), }, { names: ["r", "rscript"], exactFlags: new Set(["-e"]) }, + { + names: ["julia"], + exactFlags: new Set(["-e", "--eval", "--print"]), + rawExactFlags: new Map([["-E", "-E"]]), + }, + { + names: ["elixir", "iex"], + exactFlags: new Set(["-e", "--eval", "--rpc-eval"]), + joinedExactFlags: new Set(), + }, + { names: ["guile"], exactFlags: new Set(["-c", "-e"]), joinedExactFlags: new Set() }, + { + names: ["groovy"], + exactFlags: new Set(["-e"]), + joinedFlagDenyExact: new Set(["-encoding"]), + joinedFlagDenyPrefixes: ["-encoding="], + shortClusterFlags: [ + { + label: "-e", + flag: "e", + prefixChars: new Set(["n", "p"]), + }, + ], + }, + { + names: ["scala", "scala-cli"], + exactFlags: new Set([ + "-e", + "--script-snippet", + "--execute-script", + "--execute-sc", + "--execute-scala-script", + "--scala-snippet", + "--execute-scala", + "--java-snippet", + "--execute-java", + "--markdown-snippet", + "--md-snippet", + "--execute-markdown", + "--execute-md", + ]), + joinedExactFlags: new Set(), + }, + { names: ["clojure", "clj"], exactFlags: new Set(["-e", "--eval"]), joinedExactFlags: new Set() }, + { + names: ["raku", "perl6"], + exactFlags: new Set(["-e"]), + joinedExactFlags: new Set(["-e"]), + shortClusterFlags: [ + { + label: "-e", + flag: "e", + prefixChars: new Set(["n", "p"]), + }, + ], + }, + { names: ["ghc", "ghci"], exactFlags: new Set(["-e"]), joinedExactFlags: new Set() }, + { + names: ["erl", "werl"], + exactFlags: new Set(["-eval", "-run", "-s"]), + joinedExactFlags: new Set(), + }, + { + names: ["gdb"], + exactFlags: new Set([ + "-ex", + "-iex", + "-eiex", + "-eval-command", + "--eval-command", + "-init-eval-command", + "--init-eval-command", + "-early-init-eval-command", + "--early-init-eval-command", + ]), + abbreviatedFlags: [ + { label: "-eval-command", full: "-eval-command", min: "-ev" }, + { label: "--eval-command", full: "--eval-command", min: "--ev" }, + { label: "-init-eval-command", full: "-init-eval-command", min: "-init-e" }, + { label: "--init-eval-command", full: "--init-eval-command", min: "--init-e" }, + { + label: "-early-init-eval-command", + full: "-early-init-eval-command", + min: "-early-init-e", + }, + { + label: "--early-init-eval-command", + full: "--early-init-eval-command", + min: "--early-init-e", + }, + ], + prefixFlags: [ + { label: "-ex", prefix: "-ex=" }, + { label: "-iex", prefix: "-iex=" }, + { label: "-eiex", prefix: "-eiex=" }, + { label: "-eval-command", prefix: "-eval-command=" }, + { label: "-init-eval-command", prefix: "-init-eval-command=" }, + { label: "-early-init-eval-command", prefix: "-early-init-eval-command=" }, + ], + }, + { names: ["expect"], exactFlags: new Set(["-c"]) }, { names: ["lua"], exactFlags: new Set(["-e"]) }, { names: ["osascript"], exactFlags: new Set(["-e"]) }, { @@ -318,19 +430,40 @@ function createInlineEvalHit( }; } +function matchAbbreviatedFlag(spec: InterpreterFlagSpec, lower: string): string | null { + const optionName = lower.split("=", 1)[0] ?? lower; + for (const flag of spec.abbreviatedFlags ?? []) { + if ( + optionName.length >= flag.min.length && + flag.full.startsWith(optionName) && + flag.min.startsWith(optionName.slice(0, flag.min.length)) + ) { + return flag.label; + } + } + return null; +} + function matchJoinedExactFlag( spec: InterpreterFlagSpec, token: string, lower: string, ): string | null { + if ( + spec.joinedFlagDenyExact?.has(lower) === true || + spec.joinedFlagDenyPrefixes?.some((prefix) => lower.startsWith(prefix)) === true + ) { + return null; + } for (const flag of spec.exactFlags) { if (flag.startsWith("--")) { const prefix = `${flag}=`; if (lower.startsWith(prefix) && lower.length > prefix.length) { return flag; } - continue; } + } + for (const flag of spec.joinedExactFlags ?? spec.exactFlags) { if (/^-[A-Za-z]$/.test(flag) && token.startsWith(flag) && token.length > flag.length) { return normalizeLowercaseStringOrEmpty(flag); } @@ -339,7 +472,7 @@ function matchJoinedExactFlag( } function matchJoinedRawExactFlag(spec: InterpreterFlagSpec, token: string): string | null { - for (const [flag, label] of spec.rawExactFlags ?? []) { + for (const [flag, label] of spec.joinedRawExactFlags ?? spec.rawExactFlags ?? []) { if (/^-[A-Za-z]$/.test(flag) && token.startsWith(flag) && token.length > flag.length) { return label; } @@ -424,6 +557,10 @@ export function detectInterpreterInlineEvalArgv( return createInlineEvalHit(executable, argv, rawPrefixFlag.label); } const lower = normalizeLowercaseStringOrEmpty(token); + const abbreviatedFlag = matchAbbreviatedFlag(spec, lower); + if (abbreviatedFlag) { + return createInlineEvalHit(executable, argv, abbreviatedFlag); + } if (spec.exactFlags.has(lower)) { return createInlineEvalHit(executable, argv, lower); } diff --git a/src/infra/exec-approvals-allow-always.test.ts b/src/infra/exec-approvals-allow-always.test.ts index 0e50d1d04e08..00ab09f9d601 100644 --- a/src/infra/exec-approvals-allow-always.test.ts +++ b/src/infra/exec-approvals-allow-always.test.ts @@ -1833,6 +1833,193 @@ $0 \\"$1\\"" touch {marker}`, ).toBe(true); }); + it.each([ + { + executable: "julia", + first: "julia -e 'println(1)'", + second: "julia -e 'run(`id > {marker}`)'", + }, + { + executable: "julia", + first: "julia '-eprintln(1)'", + second: "julia '-Erun(`id > {marker}`)'", + }, + { + executable: "elixir", + first: "elixir -e 'IO.puts(:ok)'", + second: 'elixir -e \'System.cmd("sh", ["-c", "id > {marker}"])\'', + }, + { + executable: "elixir", + first: "elixir --rpc-eval worker@127.0.0.1 'IO.puts(:ok)'", + second: 'elixir --rpc-eval worker@127.0.0.1 \'System.cmd("sh", ["-c", "id > {marker}"])\'', + }, + { + executable: "iex", + first: "iex -e 'IO.puts(:ok)'", + second: 'iex -e \'System.cmd("sh", ["-c", "id > {marker}"])\'', + }, + { + executable: "guile", + first: "guile -c '(display 1)'", + second: "guile -c '(system \"id > {marker}\")'", + }, + { + executable: "guile", + first: "guile -e main /dev/null", + second: "guile -e '(lambda args (system \"id > {marker}\"))' /dev/null", + }, + { + executable: "groovy", + first: "groovy -e 'println 1'", + second: "groovy -e '\"sh -c id > {marker}\".execute()'", + }, + { + executable: "groovy", + first: "groovy '-eprintln 1'", + second: "groovy '-e\"sh -c id > {marker}\".execute()'", + }, + { + executable: "groovy", + first: "groovy '-encoding:println 1'", + second: 'groovy \'-encoding:["sh", "-c", "id > {marker}"].execute()\'', + }, + { + executable: "groovy", + first: "groovy -ne 'println line'", + second: 'groovy -pe \'["sh", "-c", "id > {marker}"].execute()\'', + }, + { + executable: "scala", + first: "scala -e 'println(1)'", + second: "scala -e 'sys.process.Process(\"sh -c id > {marker}\").!'", + }, + { + executable: "scala", + first: "scala --execute-script 'println(1)'", + second: "scala --script-snippet 'sys.process.Process(\"sh -c id > {marker}\").!'", + }, + { + executable: "scala-cli", + first: "scala-cli --execute-script 'println(1)'", + second: "scala-cli --script-snippet 'sys.process.Process(\"sh -c id > {marker}\").!'", + }, + { + executable: "clojure", + first: "clojure -e '(println 1)'", + second: 'clojure -e \'(clojure.java.shell/sh "sh" "-c" "id > {marker}")\'', + }, + { + executable: "clj", + first: "clj -e '(println 1)'", + second: 'clj -e \'(clojure.java.shell/sh "sh" "-c" "id > {marker}")\'', + }, + { + executable: "raku", + first: "raku -e 'say 1'", + second: 'raku -e \'run "sh", "-c", "id > {marker}"\'', + }, + { + executable: "raku", + first: "raku '-esay 1'", + second: 'raku \'-erun "sh", "-c", "id > {marker}"\'', + }, + { + executable: "raku", + first: "raku -ne 'say $_'", + second: 'raku -ne \'run "sh", "-c", "id > {marker}"\'', + }, + { + executable: "perl6", + first: "perl6 -e 'say 1'", + second: 'perl6 -e \'run "sh", "-c", "id > {marker}"\'', + }, + { + executable: "perl6", + first: "perl6 -pe 'say $_'", + second: 'perl6 -pe \'run "sh", "-c", "id > {marker}"\'', + }, + { + executable: "ghc", + first: "ghc -e '1 + 1'", + second: "ghc -e 'System.Process.system \"id > {marker}\"'", + }, + { + executable: "ghci", + first: "ghci -e '1 + 1'", + second: "ghci -e 'System.Process.system \"id > {marker}\"'", + }, + { + executable: "erl", + first: "erl -eval 'erlang:display(ok).' -noshell -s init stop", + second: "erl -eval 'os:cmd(\"id > {marker}\").' -noshell -s init stop", + }, + { + executable: "erl", + first: "erl -noshell -run init stop", + second: "erl -noshell -run os cmd 'id > {marker}' -s init stop", + }, + { + executable: "erl", + first: "erl -noshell -s init stop", + second: "erl -noshell -s os cmd 'id > {marker}' -s init stop", + }, + { + executable: "gdb", + first: "gdb -ex 'print 1' -ex quit", + second: "gdb -ex 'shell id > {marker}' -ex quit", + }, + { + executable: "gdb", + first: "gdb -iex 'print 1'", + second: "gdb -iex 'shell id > {marker}'", + }, + { + executable: "gdb", + first: "gdb -eval-c 'print 1'", + second: "gdb -eval-c 'shell id > {marker}'", + }, + { + executable: "gdb", + first: "gdb -ev 'print 1'", + second: "gdb --ev 'shell id > {marker}'", + }, + { + executable: "gdb", + first: "gdb -eiex 'print 1'", + second: "gdb -early-init-eval 'shell id > {marker}'", + }, + { + executable: "expect", + first: "expect -c 'puts ok'", + second: "expect -c 'exec sh -c \"id > {marker}\"'", + }, + { + executable: "expect", + first: "expect '-cputs ok'", + second: "expect '-cexec sh -c \"id > {marker}\"'", + }, + ] as const)( + "prevents allow-always bypass for additional inline-eval interpreter: $executable", + async ({ executable, first, second }) => { + if (process.platform === "win32") { + return; + } + const dir = makeTempDir(); + makeExecutable(dir, executable); + const env = makePathEnv(dir); + const marker = path.join(dir, `${executable}-marker`); + + await expectAllowAlwaysBypassBlocked({ + dir, + firstCommand: first, + secondCommand: second.replace("{marker}", marker), + env, + persistedPattern: null, + }); + }, + ); + it("prevents allow-always bypass for shell-carried awk interpreters", async () => { if (process.platform === "win32") { return;