diff --git a/src/cron/run-log.test.ts b/src/cron/run-log.test.ts index b44603b0188..ec4f5df961a 100644 --- a/src/cron/run-log.test.ts +++ b/src/cron/run-log.test.ts @@ -95,21 +95,24 @@ describe("cron run log", () => { }); }); - it("writes run log files with secure permissions", async () => { - await withRunLogDir("openclaw-cron-log-perms-", async (dir) => { - const logPath = path.join(dir, "runs", "job-1.jsonl"); + it.skipIf(process.platform === "win32")( + "writes run log files with secure permissions", + async () => { + await withRunLogDir("openclaw-cron-log-perms-", async (dir) => { + const logPath = path.join(dir, "runs", "job-1.jsonl"); - await appendCronRunLog(logPath, { - ts: 1, - jobId: "job-1", - action: "finished", - status: "ok", + await appendCronRunLog(logPath, { + ts: 1, + jobId: "job-1", + action: "finished", + status: "ok", + }); + + const mode = (await fs.stat(logPath)).mode & 0o777; + expect(mode).toBe(0o600); }); - - const mode = (await fs.stat(logPath)).mode & 0o777; - expect(mode).toBe(0o600); - }); - }); + }, + ); it("reads newest entries and filters by jobId", async () => { await withRunLogDir("openclaw-cron-log-read-", async (dir) => { diff --git a/src/cron/run-log.ts b/src/cron/run-log.ts index 097c76544c2..e2a7f2b8121 100644 --- a/src/cron/run-log.ts +++ b/src/cron/run-log.ts @@ -145,7 +145,9 @@ export async function appendCronRunLog( const next = prev .catch(() => undefined) .then(async () => { - await fs.mkdir(path.dirname(resolved), { recursive: true, mode: 0o700 }); + const runDir = path.dirname(resolved); + await fs.mkdir(runDir, { recursive: true, mode: 0o700 }); + await fs.chmod(runDir, 0o700).catch(() => undefined); await fs.appendFile(resolved, `${JSON.stringify(entry)}\n`, { encoding: "utf-8", mode: 0o600, diff --git a/src/cron/store.test.ts b/src/cron/store.test.ts index ad388a5979b..049096aece0 100644 --- a/src/cron/store.test.ts +++ b/src/cron/store.test.ts @@ -80,20 +80,23 @@ describe("cron store", () => { expect(JSON.parse(backupRaw)).toEqual(first); }); - it("writes store and backup files with secure permissions", async () => { - const store = await makeStorePath(); - const first = makeStore("job-1", true); - const second = makeStore("job-2", false); + it.skipIf(process.platform === "win32")( + "writes store and backup files with secure permissions", + async () => { + const store = await makeStorePath(); + const first = makeStore("job-1", true); + const second = makeStore("job-2", false); - await saveCronStore(store.storePath, first); - await saveCronStore(store.storePath, second); + await saveCronStore(store.storePath, first); + await saveCronStore(store.storePath, second); - const storeMode = (await fs.stat(store.storePath)).mode & 0o777; - const backupMode = (await fs.stat(`${store.storePath}.bak`)).mode & 0o777; + const storeMode = (await fs.stat(store.storePath)).mode & 0o777; + const backupMode = (await fs.stat(`${store.storePath}.bak`)).mode & 0o777; - expect(storeMode).toBe(0o600); - expect(backupMode).toBe(0o600); - }); + expect(storeMode).toBe(0o600); + expect(backupMode).toBe(0o600); + }, + ); }); describe("saveCronStore", () => { diff --git a/src/cron/store.ts b/src/cron/store.ts index ca540aa0b36..8e8f0440f35 100644 --- a/src/cron/store.ts +++ b/src/cron/store.ts @@ -65,7 +65,9 @@ export async function saveCronStore( store: CronStoreFile, opts?: SaveCronStoreOptions, ) { - await fs.promises.mkdir(path.dirname(storePath), { recursive: true, mode: 0o700 }); + const storeDir = path.dirname(storePath); + await fs.promises.mkdir(storeDir, { recursive: true, mode: 0o700 }); + await fs.promises.chmod(storeDir, 0o700).catch(() => undefined); const json = JSON.stringify(store, null, 2); const cached = serializedStoreCache.get(storePath); if (cached === json) {