diff --git a/tests/codex-catalog-writer.test.ts b/tests/codex-catalog-writer.test.ts index 261fd1942c..a64834247e 100644 --- a/tests/codex-catalog-writer.test.ts +++ b/tests/codex-catalog-writer.test.ts @@ -237,10 +237,30 @@ for (const mutator of mutators) { ); expect(readFileSync(path, "utf8")).toBe("new bytes\n"); - expect(statSync(path).mode & 0o777).toBe(0o600); + // Restriction is asserted in two halves, because it is enforced in two ways. + // + // The platform-independent half: the mutator must harden the exact bytes it + // is about to install. Tying all three effects to one temp path is what makes + // that a claim about this file — "some temp was written, some path was + // hardened, something was published" would hold even if they were different + // files. Hardening lands on the temp, never the destination, because the + // publish step is what puts an already-restricted file in place. + const tempEffect = effects.find(effect => effect.startsWith("temp:")); + expect(tempEffect).toBeDefined(); + const tempPath = tempEffect!.slice("temp:".length); + expect(effects).toContain(`harden:${tempPath}`); + expect(effects).toContain(`${isBackup ? "publish" : "rename"}:${tempPath}->${path}`); + // The other half is the resulting mode, which only carries the claim where + // POSIX modes do. Windows has no mode bits to set: `chmodSync` there moves the + // read-only flag and nothing else, so `statSync` keeps reporting 0o666 however + // the file was written, and this assertion could never pass. Real restriction + // on Windows comes from the per-user NTFS ACL `defaultBackupWriteIO` applies + // through `hardenSecretPath` — machinery these doubles deliberately leave out, + // so there is nothing here for a mode check to observe either way. + if (process.platform !== "win32") { + expect(statSync(path).mode & 0o777).toBe(0o600); + } expect(readdirSync(targetDir).filter(name => name.endsWith(".tmp"))).toEqual([]); - expect(effects.some(effect => effect.startsWith("temp:"))).toBe(true); - expect(effects.some(effect => effect.startsWith(isBackup ? "publish:" : "rename:"))).toBe(true); if (isBackup) expect(result).toBe("written"); }); } diff --git a/tests/dsh-writer-lock.test.ts b/tests/dsh-writer-lock.test.ts index bd7cfeb7f4..60aab47cd8 100644 --- a/tests/dsh-writer-lock.test.ts +++ b/tests/dsh-writer-lock.test.ts @@ -167,7 +167,15 @@ describe("DSH coordinated mutations", () => { const seams = immediateLock(() => { acquisitions += 1; }); expect((await applyIntegrationCoordinated(writeInput(), { lockSeams: seams })).ok).toBe(true); const configPath = INTEGRATION_CLIENTS.dsh.configPath({}, home); - expect(statSync(configPath).mode & 0o777).toBe(0o600); + // "Owner-only" is a mode on POSIX and an ACL on Windows: the write goes + // through `atomicWriteFile`, which applies 0600 plus Windows ACL hardening. + // Only the POSIX half is observable through `statSync`, which reports 0o666 + // on Windows whatever chmod did, so assert the file exists there instead and + // leave the ACL to tests/windows-secret-acl.test.ts. + expect(existsSync(configPath)).toBe(true); + if (process.platform !== "win32") { + expect(statSync(configPath).mode & 0o777).toBe(0o600); + } const second = await applyIntegrationCoordinated(writeInput(), { lockSeams: seams }); expect(second).toMatchObject({ ok: true, changed: false, state: "current" }); expect(acquisitions).toBe(2); diff --git a/tests/native-main-claim.test.ts b/tests/native-main-claim.test.ts index c92546213d..9016a48e15 100644 --- a/tests/native-main-claim.test.ts +++ b/tests/native-main-claim.test.ts @@ -169,8 +169,13 @@ describe("the default hardener is actually reached from a claim", () => { * left behind. On POSIX that is the mode; the Windows branch is proven * separately in tests/windows-secret-acl.test.ts, where the ACL runner can be * observed. + * + * Hence the skip: the paragraph above already scopes this to POSIX, but the + * test ran everywhere and failed on Windows, where `chmodSync` moves only the + * read-only flag and `statSync` reports 0o666 regardless — so neither the + * 0o644 setup nor the 0o600 conclusion can hold there. */ - test("a shared claim narrows a permissive claim database to 0600", async () => { + test.skipIf(process.platform === "win32")("a shared claim narrows a permissive claim database to 0600", async () => { const context = fixture(); const path = nativeMainClaimPath(context); mkdirSync(join(context.codexHome), { recursive: true });