diff --git a/src/config.ts b/src/config.ts index be8090c31..14101c21a 100644 --- a/src/config.ts +++ b/src/config.ts @@ -1949,7 +1949,6 @@ export function readConfigAdmissionSnapshot(): ConfigAdmissionSnapshot { const CONFIG_MUTATION_DB_FILENAME = "config-mutation.sqlite"; const CONFIG_MUTATION_DB_SIDECARS = ["-journal", "-wal", "-shm"] as const; -let warnedConfigMutationDirectoryAcl = false; export class ConfigMutationLockError extends Error { readonly code = "CONFIG_MUTATION_LOCK_UNAVAILABLE"; @@ -1971,20 +1970,12 @@ function configMutationDatabasePath(): string { try { chmodSync(dir, 0o700); } catch { /* best-effort on existing dir */ } } if (windowsSecretAclApplies()) { - try { - // Distinct timeout memo from management-token directory harden: a required - // management-dir timeout must not poison config mutation on the same home - // (windows-latest server-management-auth cases). - hardenSecretDir(dir, { required: true, timeoutMemoKey: `${dir}::config-mutation` }); - } catch (error) { - if (!warnedConfigMutationDirectoryAcl) { - warnedConfigMutationDirectoryAcl = true; - const diagnostics = error instanceof Error ? error.message : "ACL hardening failed"; - console.warn( - `[opencodex] Config mutation coordination directory ACL hardening did not complete; continuing without it. ${diagnostics}`, - ); - } - } + // Distinct timeout memo from management-token directory harden: a required + // management-dir timeout must not poison config mutation on the same home + // (windows-latest server-management-auth cases). Required hardening remains + // fail-closed so config and credential writes are never published in a + // directory whose inherited ACLs could not be restricted. + hardenSecretDir(dir, { required: true, timeoutMemoKey: `${dir}::config-mutation` }); } const path = join(dir, CONFIG_MUTATION_DB_FILENAME); recordOwnedConfigPath(dir, path); diff --git a/tests/config.test.ts b/tests/config.test.ts index 121eacc93..1f0381d03 100644 --- a/tests/config.test.ts +++ b/tests/config.test.ts @@ -1903,7 +1903,7 @@ describe("config.ts – Windows ACL hardening integration", () => { } }); - test("saveConfig degrades when config-mutation directory hardening fails on win32", () => { + test("saveConfig fails closed when config-mutation directory hardening fails on win32", () => { const origPlatform = process.platform; Object.defineProperty(process, "platform", { value: "win32", configurable: true }); try { @@ -1911,8 +1911,8 @@ describe("config.ts – Windows ACL hardening integration", () => { if (opts?.required) throw new Error("ACL hardening failed: access denied"); return { ok: true }; }); - expect(() => saveConfig(getDefaultConfig())).not.toThrow(); - expect(existsSync(getConfigPath())).toBe(true); + expect(() => saveConfig(getDefaultConfig())).toThrow(/ACL hardening failed/); + expect(existsSync(getConfigPath())).toBe(false); spy.mockRestore(); } finally { Object.defineProperty(process, "platform", { value: origPlatform, configurable: true });