test(agents): dedupe patch and cli credential assertions

This commit is contained in:
Peter Steinberger
2026-02-19 08:43:35 +00:00
parent 429b8783fd
commit 50805d8977
2 changed files with 43 additions and 43 deletions

View File

@@ -13,6 +13,23 @@ async function withTempDir<T>(fn: (dir: string) => Promise<T>) {
} }
} }
function buildAddFilePatch(targetPath: string): string {
return `*** Begin Patch
*** Add File: ${targetPath}
+escaped
*** End Patch`;
}
async function expectOutsideWriteRejected(params: {
dir: string;
patchTargetPath: string;
outsidePath: string;
}) {
const patch = buildAddFilePatch(params.patchTargetPath);
await expect(applyPatch(patch, { cwd: params.dir })).rejects.toThrow(/Path escapes sandbox root/);
await expect(fs.readFile(params.outsidePath, "utf8")).rejects.toBeDefined();
}
describe("applyPatch", () => { describe("applyPatch", () => {
it("adds a file", async () => { it("adds a file", async () => {
await withTempDir(async (dir) => { await withTempDir(async (dir) => {
@@ -79,14 +96,12 @@ describe("applyPatch", () => {
); );
const relativeEscape = path.relative(dir, escapedPath); const relativeEscape = path.relative(dir, escapedPath);
const patch = `*** Begin Patch
*** Add File: ${relativeEscape}
+escaped
*** End Patch`;
try { try {
await expect(applyPatch(patch, { cwd: dir })).rejects.toThrow(/Path escapes sandbox root/); await expectOutsideWriteRejected({
await expect(fs.readFile(escapedPath, "utf8")).rejects.toBeDefined(); dir,
patchTargetPath: relativeEscape,
outsidePath: escapedPath,
});
} finally { } finally {
await fs.rm(escapedPath, { force: true }); await fs.rm(escapedPath, { force: true });
} }
@@ -97,14 +112,12 @@ describe("applyPatch", () => {
await withTempDir(async (dir) => { await withTempDir(async (dir) => {
const escapedPath = path.join(os.tmpdir(), `openclaw-apply-patch-${Date.now()}.txt`); const escapedPath = path.join(os.tmpdir(), `openclaw-apply-patch-${Date.now()}.txt`);
const patch = `*** Begin Patch
*** Add File: ${escapedPath}
+escaped
*** End Patch`;
try { try {
await expect(applyPatch(patch, { cwd: dir })).rejects.toThrow(/Path escapes sandbox root/); await expectOutsideWriteRejected({
await expect(fs.readFile(escapedPath, "utf8")).rejects.toBeDefined(); dir,
patchTargetPath: escapedPath,
outsidePath: escapedPath,
});
} finally { } finally {
await fs.rm(escapedPath, { force: true }); await fs.rm(escapedPath, { force: true });
} }

View File

@@ -5,6 +5,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
const execSyncMock = vi.fn(); const execSyncMock = vi.fn();
const execFileSyncMock = vi.fn(); const execFileSyncMock = vi.fn();
const CLI_CREDENTIALS_CACHE_TTL_MS = 15 * 60 * 1000;
function mockExistingClaudeKeychainItem() { function mockExistingClaudeKeychainItem() {
execFileSyncMock.mockImplementation((file: unknown, args: unknown) => { execFileSyncMock.mockImplementation((file: unknown, args: unknown) => {
@@ -31,6 +32,16 @@ function getAddGenericPasswordCall() {
); );
} }
async function readCachedClaudeCliCredentials(allowKeychainPrompt: boolean) {
const { readClaudeCliCredentialsCached } = await import("./cli-credentials.js");
return readClaudeCliCredentialsCached({
allowKeychainPrompt,
ttlMs: CLI_CREDENTIALS_CACHE_TTL_MS,
platform: "darwin",
execSync: execSyncMock,
});
}
describe("cli credentials", () => { describe("cli credentials", () => {
beforeEach(() => { beforeEach(() => {
vi.useFakeTimers(); vi.useFakeTimers();
@@ -189,20 +200,8 @@ describe("cli credentials", () => {
vi.setSystemTime(new Date("2025-01-01T00:00:00Z")); vi.setSystemTime(new Date("2025-01-01T00:00:00Z"));
const { readClaudeCliCredentialsCached } = await import("./cli-credentials.js"); const first = await readCachedClaudeCliCredentials(true);
const second = await readCachedClaudeCliCredentials(false);
const first = readClaudeCliCredentialsCached({
allowKeychainPrompt: true,
ttlMs: 15 * 60 * 1000,
platform: "darwin",
execSync: execSyncMock,
});
const second = readClaudeCliCredentialsCached({
allowKeychainPrompt: false,
ttlMs: 15 * 60 * 1000,
platform: "darwin",
execSync: execSyncMock,
});
expect(first).toBeTruthy(); expect(first).toBeTruthy();
expect(second).toEqual(first); expect(second).toEqual(first);
@@ -222,23 +221,11 @@ describe("cli credentials", () => {
vi.setSystemTime(new Date("2025-01-01T00:00:00Z")); vi.setSystemTime(new Date("2025-01-01T00:00:00Z"));
const { readClaudeCliCredentialsCached } = await import("./cli-credentials.js"); const first = await readCachedClaudeCliCredentials(true);
const first = readClaudeCliCredentialsCached({ vi.advanceTimersByTime(CLI_CREDENTIALS_CACHE_TTL_MS + 1);
allowKeychainPrompt: true,
ttlMs: 15 * 60 * 1000,
platform: "darwin",
execSync: execSyncMock,
});
vi.advanceTimersByTime(15 * 60 * 1000 + 1); const second = await readCachedClaudeCliCredentials(true);
const second = readClaudeCliCredentialsCached({
allowKeychainPrompt: true,
ttlMs: 15 * 60 * 1000,
platform: "darwin",
execSync: execSyncMock,
});
expect(first).toBeTruthy(); expect(first).toBeTruthy();
expect(second).toBeTruthy(); expect(second).toBeTruthy();