mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-23 09:12:32 +00:00
125 lines
4.0 KiB
TypeScript
125 lines
4.0 KiB
TypeScript
// Verifies command explanation spans are reduced to executable highlights and
|
|
// suppressed for unsupported shell-wrapper grammars.
|
|
import { describe, expect, it } from "vitest";
|
|
import { explainShellCommand } from "./extract.js";
|
|
import { formatCommandSpans } from "./format.js";
|
|
import type { CommandExplanation, SourceSpan } from "./types.js";
|
|
|
|
function span(startIndex: number, endIndex: number): SourceSpan {
|
|
return {
|
|
startIndex,
|
|
endIndex,
|
|
startPosition: { row: 0, column: startIndex },
|
|
endPosition: { row: 0, column: endIndex },
|
|
};
|
|
}
|
|
|
|
describe("formatCommandSpans", () => {
|
|
it("returns executable token spans without risk or severity metadata", () => {
|
|
const explanation: CommandExplanation = {
|
|
ok: true,
|
|
source: 'ls | grep "stuff" | python -c \'print("hi")\'',
|
|
shapes: ["pipeline"],
|
|
topLevelCommands: [
|
|
{
|
|
context: "top-level",
|
|
executable: "ls",
|
|
argv: ["ls"],
|
|
text: "ls",
|
|
span: span(0, 2),
|
|
executableSpan: span(0, 2),
|
|
},
|
|
{
|
|
context: "top-level",
|
|
executable: "grep",
|
|
argv: ["grep", "stuff"],
|
|
text: 'grep "stuff"',
|
|
span: span(5, 17),
|
|
executableSpan: span(5, 9),
|
|
},
|
|
{
|
|
context: "top-level",
|
|
executable: "python",
|
|
argv: ["python", "-c", 'print("hi")'],
|
|
text: "python -c 'print(\"hi\")'",
|
|
span: span(20, 42),
|
|
executableSpan: span(20, 26),
|
|
},
|
|
],
|
|
nestedCommands: [],
|
|
risks: [
|
|
{
|
|
kind: "inline-eval",
|
|
command: "python",
|
|
flag: "-c",
|
|
text: "python -c 'print(\"hi\")'",
|
|
span: span(20, 42),
|
|
},
|
|
],
|
|
};
|
|
|
|
expect(formatCommandSpans(explanation)).toEqual([
|
|
{ startIndex: 0, endIndex: 2 },
|
|
{ startIndex: 5, endIndex: 9 },
|
|
{ startIndex: 20, endIndex: 26 },
|
|
]);
|
|
});
|
|
|
|
it("anchors command spans to executable tokens after env assignments", async () => {
|
|
const explanation = await explainShellCommand("FOO=1 python -c 'print(1)'");
|
|
|
|
expect(formatCommandSpans(explanation)).toEqual([{ startIndex: 6, endIndex: 12 }]);
|
|
});
|
|
|
|
it("includes nested executable spans from shell wrapper payloads", async () => {
|
|
const explanation = await explainShellCommand(
|
|
'sh -c \'echo checking "$1"; node -e "console.log(process.argv[1])" "$1"\' sh file.ts',
|
|
);
|
|
|
|
const commandTexts = formatCommandSpans(explanation).map((commandSpan) =>
|
|
explanation.source.slice(commandSpan.startIndex, commandSpan.endIndex),
|
|
);
|
|
expect(commandTexts).toEqual(["sh", "echo", "node"]);
|
|
});
|
|
|
|
it("omits command spans for unsupported shell wrapper languages", async () => {
|
|
const powershell = await explainShellCommand('pwsh -Command "Get-ChildItem"');
|
|
const cmd = await explainShellCommand('cmd.exe /d /s /c "dir"');
|
|
|
|
expect(formatCommandSpans(powershell)).toEqual([]);
|
|
expect(formatCommandSpans(cmd)).toEqual([]);
|
|
});
|
|
|
|
it("omits command spans for unsupported shell wrappers through transparent carriers", async () => {
|
|
const timeoutPowershell = await explainShellCommand('timeout 5 pwsh -Command "Get-ChildItem"');
|
|
const timeCmd = await explainShellCommand('time cmd.exe /d /s /c "dir"');
|
|
const splitEnvPowershell = await explainShellCommand("env -S 'pwsh -Command Get-ChildItem'");
|
|
|
|
expect(formatCommandSpans(timeoutPowershell)).toEqual([]);
|
|
expect(formatCommandSpans(timeCmd)).toEqual([]);
|
|
expect(formatCommandSpans(splitEnvPowershell)).toEqual([]);
|
|
});
|
|
|
|
it("ignores invalid executable spans", () => {
|
|
const explanation: CommandExplanation = {
|
|
ok: true,
|
|
source: "echo hi",
|
|
shapes: [],
|
|
topLevelCommands: [
|
|
{
|
|
context: "top-level",
|
|
executable: "echo",
|
|
argv: ["echo", "hi"],
|
|
text: "echo hi",
|
|
span: span(0, 7),
|
|
executableSpan: span(4, 4),
|
|
},
|
|
],
|
|
nestedCommands: [],
|
|
risks: [],
|
|
};
|
|
|
|
expect(formatCommandSpans(explanation)).toStrictEqual([]);
|
|
});
|
|
});
|