mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-11-11 05:11:49 +01:00
Preserve cleanup of empty unreadable fake sandbox directories
This commit is contained in:
1 parent
0b2f3e221e
commit
e9b909015a
2 files changed
+30
-2
No files matched your search
@@ -39,6 +39,24 @@ async function createLease() {
|
||||
}
|
||||
|
||||
describe("fake sandbox lease cleanup", () => {
|
||||
it.each(["destroy", "release"] as const)("%s removes an empty unreadable directory", async (operation) => {
|
||||
const { harness, root, params } = await createLease();
|
||||
const unreadable = path.join(root, "workspace/unreadable");
|
||||
await mkdir(unreadable);
|
||||
await chmod(unreadable, 0o000);
|
||||
try {
|
||||
const result = operation === "destroy"
|
||||
? await harness.destroyLease(params)
|
||||
: await harness.releaseLease(params);
|
||||
expect(result).toBeUndefined();
|
||||
await expect(access(root)).rejects.toMatchObject({ code: "ENOENT" });
|
||||
expect(await harness.inspectLease(params)).toMatchObject({ state: "destroyed" });
|
||||
} finally {
|
||||
await chmod(unreadable, 0o700).catch(() => undefined);
|
||||
await rm(root, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
it.each(["destroy", "release"] as const)("%s removes sealed native runtime context", async (operation) => {
|
||||
const { harness, root, params } = await createLease();
|
||||
const instructions = path.join(root, "workspace/.paperclip-runtime/paperclip-runner/sessions/session/filesystem/context/instructions");
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { constants } from "node:fs";
|
||||
import { open, readdir, rm } from "node:fs/promises";
|
||||
import { lstat, open, readdir, rm, rmdir } from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
|
||||
export interface LeaseRootIdentity {
|
||||
@@ -11,8 +11,18 @@ async function makeDirectoriesWritable(directory: string, expected?: LeaseRootId
|
||||
const handle = await open(
|
||||
directory,
|
||||
constants.O_RDONLY | constants.O_DIRECTORY | constants.O_NOFOLLOW,
|
||||
).catch((error: NodeJS.ErrnoException) => {
|
||||
).catch(async (error: NodeJS.ErrnoException) => {
|
||||
if (error.code === "ENOENT") return null;
|
||||
if (error.code === "EACCES") {
|
||||
const identity = await lstat(directory);
|
||||
if (!identity.isDirectory() || (expected && (identity.dev !== expected.dev || identity.ino !== expected.ino))) {
|
||||
throw new Error("Refusing to remove a replaced fake sandbox lease root");
|
||||
}
|
||||
// Removing an empty directory only needs access to its parent. Opening
|
||||
// it first would regress cleanup of owned directories with mode 000.
|
||||
await rmdir(directory);
|
||||
return null;
|
||||
}
|
||||
throw error;
|
||||
});
|
||||
if (!handle) return false;
|
||||
|
||||
Reference in new issue
Block a user