1import { describe, expect, it } from "vite-plus/test";
2
3import { embeddedScripts } from "./embeddedScripts";
4
5/** Each script's language, its text, and the part of the command that spells it. */
6function scriptsOf(command: string) {
7 return embeddedScripts(command).map((script) => {
8 // Every character maps inside the command, in order.
9 script.starts.forEach((start, index) => {
10 expect(start).toBeLessThan(script.ends[index]!);
11 if (index > 0) expect(start).toBeGreaterThanOrEqual(script.ends[index - 1]!);
12 });
13 return [
14 script.language,
15 script.text,
16 command.slice(script.starts[0], script.ends.at(-1)),
17 ] as const;
18 });
19}
20
21const pythonScript = `from pathlib import Path
22import json
23
24# print every package.json name and version
25for p in sorted(Path('.').glob('**/package.json')):
26 data = json.loads(p.read_text())
27 print(f"{data['name']:16} {data.get('version', '?')}")
28`;
29
30describe("embeddedScripts", () => {
31 it("finds the script inside a Codex login-shell wrapper and the script inside that", () => {
32 // Recorded in the turn_interrupt_mid_tool Codex transcript
33 // (apps/server/src/orchestration-v2/testkit/fixtures).
34 const inner = `console.log('interrupt fixture tool started'); setTimeout(() => {}, 30000)`;
35 const command = `/bin/bash -lc "node -e \\"${inner}\\""`;
36 expect(scriptsOf(command)).toEqual([
37 ["shellscript", `node -e "${inner}"`, `node -e \\"${inner}\\"`],
38 ["javascript", inner, inner],
39 ]);
40 });
41
42 it("highlights a heredoc fed to an interpreter in that interpreter's language", () => {
43 const command = `python3 - <<'PY'\n${pythonScript}PY`;
44 expect(scriptsOf(command)).toEqual([["python", pythonScript, pythonScript]]);
45 });
46
47 it("maps escaped characters back to both source characters", () => {
48 const command = `/bin/zsh -lc "python3 - <<'PY'\nprint(\\"\\$HOME\\")\nPY"`;
49 const [shell, python] = scriptsOf(command);
50 expect(shell?.[1]).toBe(`python3 - <<'PY'\nprint("$HOME")\nPY`);
51 expect(python).toEqual(["python", `print("$HOME")\n`, `print(\\"\\$HOME\\")\n`]);
52 });
53
54 it.each([
55 [`python3 -c 'print(1)'`, "python", "print(1)"],
56 [`python3 -X dev -c 'print(1)'`, "python", "print(1)"],
57 [`py -3 -c 'print(1)'`, "python", "print(1)"],
58 [`C:\\Python312\\python.exe -c 'print(1)'`, "python", "print(1)"],
59 [`"C:\\Program Files\\Python312\\python.exe" -c 'print(1)'`, "python", "print(1)"],
60 [`node --eval "process.exit(0)"`, "javascript", "process.exit(0)"],
61 [`bun -e 'console.log(Bun.version)'`, "typescript", "console.log(Bun.version)"],
62 [`deno eval 'console.log(1)'`, "typescript", "console.log(1)"],
63 [`deno eval --config deno.json 'console.log(1)'`, "typescript", "console.log(1)"],
64 [`deno eval --env-file 'console.log(1)'`, "typescript", "console.log(1)"],
65 [`psql -f schema.sql -c 'select 1'`, "sql", "select 1"],
66 [`node -C development -e 'console.log(1)'`, "javascript", "console.log(1)"],
67 [`ruby -e 'puts 1'`, "ruby", "puts 1"],
68 [`ruby -I lib -e 'puts 1'`, "ruby", "puts 1"],
69 [`perl -E 'say 1'`, "perl", "say 1"],
70 [`sqlite3 app.db "select * from users"`, "sql", "select * from users"],
71 [`psql -d app -c 'select 1'`, "sql", "select 1"],
72 [`pwsh -NoProfile -Command "Get-ChildItem"`, "powershell", "Get-ChildItem"],
73 [`env FOO=1 sudo -u bob python3 -c 'print(1)'`, "python", "print(1)"],
74 [`env -- FOO=1 python3 -c 'print(1)'`, "python", "print(1)"],
75 [`node --eval="process.exit(0)"`, "javascript", "process.exit(0)"],
76 [`psql --command='select 1'`, "sql", "select 1"],
77 [`mysql -c -e 'select 1'`, "sql", "select 1"],
78 [`mysql -f app <<'EOF'\nselect 1;\nEOF`, "sql", "select 1;\n"],
79 [`psql app <<'EOF'\nselect 1;\nEOF`, "sql", "select 1;\n"],
80 [`echo "$(node -e 'console.log(1)')"`, "javascript", "console.log(1)"],
81 [`python3 <<< 'print(1)'`, "python", "print(1)"],
82 ])("finds the inline script in %s", (command, language, script) => {
83 expect(scriptsOf(command)).toEqual([[language, script, expect.any(String)]]);
84 });
85
86 it.each([[`psql -c 'select 1' -c 'select 2'`], [`sqlite3 app.db "select 1" "select 2"`]])(
87 "finds every statement a SQL shell runs: %s",
88 (command) => {
89 expect(scriptsOf(command).map(([language, text]) => [language, text])).toEqual([
90 ["sql", "select 1"],
91 ["sql", "select 2"],
92 ]);
93 },
94 );
95
96 it.each([
97 ["the file `cat` writes", `cat > src/app.ts <<'EOF'\nconst a = 1;\nEOF`, "typescript"],
98 ["the file `tee` writes", `tee -a config.json <<EOF\n{}\nEOF`, "json"],
99 ["its delimiter", `kubectl apply -f - <<'YAML'\nkind: Pod\nYAML`, "yaml"],
100 ["the shell reading it", `bash <<'EOF'\necho hi\nEOF`, "shellscript"],
101 ])("takes a heredoc's language from %s", (_source, command, language) => {
102 expect(scriptsOf(command).map(([lang]) => lang)).toEqual([language]);
103 });
104
105 it.each([
106 ["a script file", `python3 build.py <<EOF\ndata\nEOF`],
107 ["a module", `python3 -m json.tool <<EOF\n{}\nEOF`],
108 ["a SQL file", `psql -f migrate.sql <<EOF\ny\nEOF`],
109 ["a SQL file given with =", `psql --file=migrate.sql <<EOF\ny\nEOF`],
110 ["plain commands", `rg -n "foo" src && git status`],
111 ["an unnamed heredoc into a plain command", `git commit -F - <<'EOF'\nfix: x\nEOF`],
112 ["an empty script", `bash -lc ' '`],
113 ["a heredoc `cat` sends to stdout while stderr goes to a file", `cat 2>log.ts <<'EOF'\nx\nEOF`],
114 ])("finds nothing for %s", (_case, command) => {
115 expect(scriptsOf(command)).toEqual([]);
116 });
117
118 it("trusts nothing in a command whose quoting does not parse", () => {
119 // Codex's secret redaction dropped the backslash of an escaped quote, so
120 // the -lc argument ends early and the rest no longer balances.
121 const command = `/bin/zsh -lc "python3 -c 'token=[REDACTED_SECRET]"apiToken\\"]; print(token)'"`;
122 expect(scriptsOf(command)).toEqual([]);
123 });
124});