diff --git a/server/src/__tests__/setup-supertest.ts b/server/src/__tests__/setup-supertest.ts index 9c7db2179d4..e1318c6f950 100644 --- a/server/src/__tests__/setup-supertest.ts +++ b/server/src/__tests__/setup-supertest.ts @@ -27,9 +27,20 @@ process.env.PAPERCLIP_TEST_HOST_HOME ??= process.env.PAPERCLIP_HOME?.trim() || p // Receipt-spool recovery must never scan a developer's instance during tests. const paperclipTestHome = fs.mkdtempSync(path.join(os.tmpdir(), "paperclip-vitest-home-")); process.env.PAPERCLIP_HOME = paperclipTestHome; +// Runtime-context bundles are published read-only (0o555 directories), so +// restore owner write access on directories before removing the tree. +function restoreDirectoryWriteAccess(target: string): void { + const stat = fs.lstatSync(target, { throwIfNoEntry: false }); + if (!stat?.isDirectory()) return; + fs.chmodSync(target, 0o700); + for (const entry of fs.readdirSync(target)) restoreDirectoryWriteAccess(path.join(target, entry)); +} // Setup-file afterAll hooks run before suites drain asynchronous heartbeats. // Cleanup at worker exit, after all suite teardown, avoids deleting live state. -process.once("exit", () => fs.rmSync(paperclipTestHome, { recursive: true, force: true, maxRetries: 8, retryDelay: 50 })); +process.once("exit", () => { + restoreDirectoryWriteAccess(paperclipTestHome); + fs.rmSync(paperclipTestHome, { recursive: true, force: true, maxRetries: 8, retryDelay: 50 }); +}); const require = createRequire(import.meta.url); const SupertestTest = require("supertest/lib/test.js") as SupertestTestConstructor;