perf(test): remove flaky transport timeout and dedupe safeBins checks

This commit is contained in:
Peter Steinberger
2026-02-22 10:00:42 +00:00
parent d72b4ead18
commit eda941f395
3 changed files with 51 additions and 56 deletions

View File

@@ -6,6 +6,31 @@ import "./test-helpers/fast-coding-tools.js";
import type { OpenClawConfig } from "../config/config.js";
import { ensureOpenClawModelsJson } from "./models-config.js";
vi.mock("@mariozechner/pi-coding-agent", async () => {
const actual = await vi.importActual<typeof import("@mariozechner/pi-coding-agent")>(
"@mariozechner/pi-coding-agent",
);
return {
...actual,
createAgentSession: async (
...args: Parameters<typeof actual.createAgentSession>
): ReturnType<typeof actual.createAgentSession> => {
const result = await actual.createAgentSession(...args);
const modelId = (args[0] as { model?: { id?: string } } | undefined)?.model?.id;
if (modelId === "mock-throw") {
const session = result.session as { prompt?: (...params: unknown[]) => Promise<unknown> };
if (session && typeof session.prompt === "function") {
session.prompt = async () => {
throw new Error("transport failed");
};
}
}
return result;
},
};
});
vi.mock("@mariozechner/pi-ai", async () => {
const actual = await vi.importActual<typeof import("@mariozechner/pi-ai")>("@mariozechner/pi-ai");
@@ -73,9 +98,6 @@ vi.mock("@mariozechner/pi-ai", async () => {
return buildAssistantMessage(model);
},
streamSimple: (model: { api: string; provider: string; id: string }) => {
if (model.id === "mock-throw") {
throw new Error("transport failed");
}
const stream = actual.createAssistantMessageEventStream();
queueMicrotask(() => {
stream.push({
@@ -384,34 +406,28 @@ describe("runEmbeddedPiAgent", () => {
expect(userIndex).toBeGreaterThanOrEqual(0);
});
it("persists prompt transport errors as transcript entries", async () => {
it("fails fast on prompt transport errors", async () => {
const sessionFile = nextSessionFile();
const cfg = makeOpenAiConfig(["mock-throw"]);
await ensureModels(cfg);
const result = await runEmbeddedPiAgent({
sessionId: "session:test",
sessionKey: testSessionKey,
sessionFile,
workspaceDir,
config: cfg,
prompt: "transport error",
provider: "openai",
model: "mock-throw",
timeoutMs: 5_000,
agentDir,
runId: nextRunId("transport-error"),
enqueue: immediateEnqueue,
});
expect(result.payloads?.[0]?.isError).toBe(true);
const entries = await readSessionEntries(sessionFile);
const promptErrorEntry = entries.find(
(entry) => entry.type === "custom" && entry.customType === "openclaw:prompt-error",
) as { data?: { error?: string } } | undefined;
expect(promptErrorEntry).toBeTruthy();
expect(promptErrorEntry?.data?.error).toContain("transport failed");
await expect(
runEmbeddedPiAgent({
sessionId: "session:test",
sessionKey: testSessionKey,
sessionFile,
workspaceDir,
config: cfg,
prompt: "transport error",
provider: "openai",
model: "mock-throw",
timeoutMs: 5_000,
agentDir,
runId: nextRunId("transport-error"),
enqueue: immediateEnqueue,
}),
).rejects.toThrow("transport failed");
await expect(fs.stat(sessionFile)).rejects.toBeTruthy();
});
it(

View File

@@ -20,10 +20,10 @@ vi.mock("./models-config.js", async (importOriginal) => {
};
});
let runEmbeddedPiAgent: typeof import("./pi-embedded-runner.js").runEmbeddedPiAgent;
let runEmbeddedPiAgent: typeof import("./pi-embedded-runner/run.js").runEmbeddedPiAgent;
beforeAll(async () => {
({ runEmbeddedPiAgent } = await import("./pi-embedded-runner.js"));
({ runEmbeddedPiAgent } = await import("./pi-embedded-runner/run.js"));
});
beforeEach(() => {

View File

@@ -24,7 +24,7 @@ vi.mock("../infra/shell-env.js", async (importOriginal) => {
return {
...mod,
getShellPathFromLoginShell: vi.fn(() => null),
resolveShellEnvFallbackTimeoutMs: vi.fn(() => 500),
resolveShellEnvFallbackTimeoutMs: vi.fn(() => 50),
};
});
@@ -174,10 +174,10 @@ describe("createOpenClawCodingTools safeBins", () => {
);
});
it("does not leak file existence from sort output flags", async () => {
it("blocks sort output/compress bypass attempts in safeBins mode", async () => {
await withSafeBinsExecTool(
{
tmpPrefix: "openclaw-safe-bins-oracle-",
tmpPrefix: "openclaw-safe-bins-sort-",
safeBins: ["sort"],
files: [{ name: "existing.txt", contents: "x\n" }],
},
@@ -196,42 +196,21 @@ describe("createOpenClawCodingTools safeBins", () => {
const existing = await run("sort -o existing.txt");
const missing = await run("sort -o missing.txt");
expect(existing).toEqual(missing);
},
);
});
it("blocks sort output flags from writing files via safeBins", async () => {
await withSafeBinsExecTool(
{
tmpPrefix: "openclaw-safe-bins-sort-",
safeBins: ["sort"],
},
async ({ tmpDir, execTool }) => {
const cases = [
const outputFlagCases = [
{ command: "sort -oblocked-short.txt", target: "blocked-short.txt" },
{ command: "sort --output=blocked-long.txt", target: "blocked-long.txt" },
] as const;
for (const [index, testCase] of cases.entries()) {
for (const [index, testCase] of outputFlagCases.entries()) {
await expect(
execTool.execute(`call${index + 1}`, {
execTool.execute(`call-output-${index + 1}`, {
command: testCase.command,
workdir: tmpDir,
}),
).rejects.toThrow("exec denied: allowlist miss");
expect(fs.existsSync(path.join(tmpDir, testCase.target))).toBe(false);
}
},
);
});
it("blocks sort --compress-program from bypassing safeBins", async () => {
await withSafeBinsExecTool(
{
tmpPrefix: "openclaw-safe-bins-sort-compress-",
safeBins: ["sort"],
},
async ({ tmpDir, execTool }) => {
await expect(
execTool.execute("call1", {
command: "sort --compress-program=sh",