test: run the posix-only ai agent tests on linux only

This commit is contained in:
LukeGus committed 2026-10-03 16:12:38 -05:00
1 parent bf817d8bd1
commit 7305a44b19
3 files changed
+42 -15

No files matched your search

@@ -12,6 +12,9 @@ import {
import { providerPath } from "../../../src/backend/agents/routes.js"; import { providerPath } from "../../../src/backend/agents/routes.js";
import { REMOTE_RUNNER } from "../../../src/backend/agents/remote-runner.js"; import { REMOTE_RUNNER } from "../../../src/backend/agents/remote-runner.js";
// These run sh, git and agent binaries the way a remote Linux host does.
const posix = it.skipIf(process.platform === "win32");
describe("remote agent boundaries", () => { describe("remote agent boundaries", () => {
it("rejects shell syntax and invalid targets", () => { it("rejects shell syntax and invalid targets", () => {
const start = { const start = {
@@ -78,7 +81,9 @@ if(args[0]==='serve') {
}); });
`; `;
for (const agent of ["pi", "claude", "codex", "opencode"] as const) { for (const agent of ["pi", "claude", "codex", "opencode"] as const) {
it(`${agent}: native protocol streams a turn and returns to ready`, async () => { posix(
`${agent}: native protocol streams a turn and returns to ready`,
async () => {
const dir = await mkdtemp(join(tmpdir(), "termix-agent-test-")); const dir = await mkdtemp(join(tmpdir(), "termix-agent-test-"));
const executable = join(dir, "fake-agent"); const executable = join(dir, "fake-agent");
const image = join(dir, "image.png"); const image = join(dir, "image.png");
@@ -147,5 +152,7 @@ for (const agent of ["pi", "claude", "codex", "opencode"] as const) {
await new Promise((resolve) => child.once("exit", resolve)); await new Promise((resolve) => child.once("exit", resolve));
await rm(dir, { recursive: true, force: true }); await rm(dir, { recursive: true, force: true });
} }
}, 15000); },
15000,
);
} }
@@ -8,6 +8,9 @@ import {
forwardingScript, forwardingScript,
} from "../../../src/backend/agents/forwarding.js"; } from "../../../src/backend/agents/forwarding.js";
// These run sh, git and agent binaries the way a remote Linux host does.
const posix = it.skipIf(process.platform === "win32");
async function fixture(mode = "no") { async function fixture(mode = "no") {
const dir = await mkdtemp(join(tmpdir(), "termix-forwarding-")); const dir = await mkdtemp(join(tmpdir(), "termix-forwarding-"));
const bin = join(dir, "bin"); const bin = join(dir, "bin");
@@ -53,7 +56,9 @@ exit 0
}; };
} }
it("adds a scoped rule before existing Match blocks and is idempotent", async () => { posix(
"adds a scoped rule before existing Match blocks and is idempotent",
async () => {
const f = await fixture(); const f = await fixture();
try { try {
expect(f.run()).toContain("Enabled loopback remote forwarding"); expect(f.run()).toContain("Enabled loopback remote forwarding");
@@ -67,8 +72,9 @@ it("adds a scoped rule before existing Match blocks and is idempotent", async ()
} finally { } finally {
await f.close(); await f.close();
} }
}); },
it("preserves existing local forwarding", async () => { );
posix("preserves existing local forwarding", async () => {
const f = await fixture("local"); const f = await fixture("local");
try { try {
f.run(); f.run();
@@ -11,6 +11,9 @@ import { tmpdir } from "node:os";
import { join } from "node:path"; import { join } from "node:path";
import { spawnSync, execFileSync } from "node:child_process"; import { spawnSync, execFileSync } from "node:child_process";
import { REMOTE_WORKSPACE } from "../../../src/backend/agents/workspace.js"; import { REMOTE_WORKSPACE } from "../../../src/backend/agents/workspace.js";
// These run sh, git and agent binaries the way a remote Linux host does.
const posix = it.skipIf(process.platform === "win32");
let home: string, cwd: string; let home: string, cwd: string;
beforeEach(() => { beforeEach(() => {
home = mkdtempSync(join(tmpdir(), "termix-workspace-")); home = mkdtempSync(join(tmpdir(), "termix-workspace-"));
@@ -34,7 +37,9 @@ function git(...args: string[]) {
stdio: ["pipe", "pipe", "pipe"], stdio: ["pipe", "pipe", "pipe"],
}); });
} }
it("uploads an image without trusting the caller's MIME type and preserves exact bytes", () => { posix(
"uploads an image without trusting the caller's MIME type and preserves exact bytes",
() => {
const data = Buffer.from([137, 80, 78, 71, 13, 10, 26, 10, 0, 1, 2]); const data = Buffer.from([137, 80, 78, 71, 13, 10, 26, 10, 0, 1, 2]);
const a = run({ const a = run({
operation: "upload", operation: "upload",
@@ -48,15 +53,21 @@ it("uploads an image without trusting the caller's MIME type and preserves exact
join(home, ".local/state/termix-agents/test/attachments"), join(home, ".local/state/termix-agents/test/attachments"),
), ),
).toBe(true); ).toBe(true);
}); },
it("rejects oversized files, directories and references outside the workspace", () => { );
posix(
"rejects oversized files, directories and references outside the workspace",
() => {
writeFileSync(join(home, "outside"), "secret"); writeFileSync(join(home, "outside"), "secret");
symlinkSync(join(home, "outside"), join(cwd, "escape")); symlinkSync(join(home, "outside"), join(cwd, "escape"));
writeFileSync(join(cwd, "large"), Buffer.alloc(1024 * 1024 + 1)); writeFileSync(join(cwd, "large"), Buffer.alloc(1024 * 1024 + 1));
for (const path of ["../outside", "escape", "large", "."]) for (const path of ["../outside", "escape", "large", "."])
expect(() => run({ operation: "reference", path })).toThrow(); expect(() => run({ operation: "reference", path })).toThrow();
}); },
it("shows staged, unstaged and untracked changes and creates an isolated branch", () => { );
posix(
"shows staged, unstaged and untracked changes and creates an isolated branch",
() => {
git("init"); git("init");
git("config", "user.name", "Test"); git("config", "user.name", "Test");
git("config", "user.email", "test@example.com"); git("config", "user.email", "test@example.com");
@@ -82,13 +93,16 @@ it("shows staged, unstaged and untracked changes and creates an isolated branch"
const wt = run({ operation: "worktree", branch: "termix/test" }); const wt = run({ operation: "worktree", branch: "termix/test" });
expect(readFileSync(join(wt.path, "file.txt"), "utf8")).toBe("base\n"); expect(readFileSync(join(wt.path, "file.txt"), "utf8")).toBe("base\n");
expect(readFileSync(join(cwd, "file.txt"), "utf8")).toBe("working\n"); expect(readFileSync(join(cwd, "file.txt"), "utf8")).toBe("working\n");
expect(() => run({ operation: "worktree", branch: "termix/test" })).toThrow(); expect(() =>
run({ operation: "worktree", branch: "termix/test" }),
).toThrow();
rmSync(join(cwd, "nested"), { recursive: true }); rmSync(join(cwd, "nested"), { recursive: true });
expect(run({ operation: "diff", path: "nested/deleted.txt" }).diff).toContain( expect(
"-nested base", run({ operation: "diff", path: "nested/deleted.txt" }).diff,
); ).toContain("-nested base");
rmSync(join(cwd, "file.txt")); rmSync(join(cwd, "file.txt"));
expect(run({ operation: "diff", path: "file.txt" }).diff).toContain( expect(run({ operation: "diff", path: "file.txt" }).diff).toContain(
"-staged", "-staged",
); );
}); },
);