import { chmodSync, existsSync, mkdirSync, mkdtempSync, realpathSync, rmSync, symlinkSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { basename, join } from "node:path"; import { afterEach, expect, test, vi } from "vitest"; import { createAuthDiagnoser } from "../src/auth/diagnostics.js"; import { createAuthenticationConfigProvider } from "../src/auth/config.js"; import { createAuthentikGroupCatalog } from "../src/auth/authentik-group-catalog.js"; import { createLocalUserRegistry } from "../src/auth/local-registry.js"; import { createOidcProtocol, OidcJwksUnavailableError } from "../src/auth/oidc-client.js"; import { validateAuthSessionRoot } from "../src/auth/session-store.js"; import type { LoadedAuthConfig } from "../src/auth/types.js"; const sentinels = [ "oidc-client-secret-UNIQUE-7P3", "authentik-api-token-UNIQUE-9Q7", "cookie-UNIQUE-5M1", "$argon2id$v=19$password-hash-UNIQUE-2T8", "/private/path-UNIQUE-4K6", ]; const roots: string[] = []; const acceptSessionRoot = () => undefined; const validPasswordHash = "$argon2id$v=19$m=65536,t=3,p=1$AAECAwQFBgcICQoLDA0ODw$DRo8ZSPI8G5OCvnFFapbVEjP69aDjy1Sw9i2743cPC4"; afterEach(() => { for (const root of roots.splice(0)) rmSync(root, { recursive: true, force: true }); }); function privateRoot(): string { const root = mkdtempSync(join(realpathSync(tmpdir()), "thothii-auth-diagnostics-")); chmodSync(root, 0o700); roots.push(root); return root; } function oidcConfig(): LoadedAuthConfig { return { revision: "a".repeat(64), sourcePath: "/safe/auth.yaml", value: { version: 1, mode: "oidc", publicUrl: "https://thothii.example.test", session: { regularTtlSeconds: 1, regularIdleSeconds: 1, rememberTtlSeconds: 1, rememberIdleSeconds: 1, oidcTtlSeconds: 1 }, oidc: { issuer: "https://issuer.example.test/application/o/thothii/", clientId: "thothii", clientSecretRef: "THT_OIDC_CLIENT_SECRET", scopes: ["openid"], groupsClaim: "groups" }, groupCatalog: { driver: "authentik", baseUrl: "https://authentik.example.test", apiTokenRef: "THT_AUTHENTIK_API_TOKEN" }, authorization: { groupRoles: { "TOT Users": ["user"], "TOT Admin": ["admin"] } }, }, }; } function localConfig(sourcePath: string): LoadedAuthConfig { return { revision: "b".repeat(64), sourcePath, value: { version: 1, mode: "local", publicUrl: "http://127.0.0.1:8080", session: { regularTtlSeconds: 1, regularIdleSeconds: 1, rememberTtlSeconds: 1, rememberIdleSeconds: 1, oidcTtlSeconds: 1 }, local: { usersFile: "users.yaml" }, }, }; } function registryYaml(role: "user" | "admin", passwordHash = validPasswordHash): string { return [ "version: 1", "users:", " - id: 6ba7b810-9dad-4ed1-80b4-00c04fd430c8", " username: Admin", " displayName: Admin", ` passwordHash: ${passwordHash}`, " roles:", ` - ${role}`, " enabled: true", " authRevision: 1", "", ].join("\n"); } test("reports deterministic live OIDC checks and silently ignores unrelated groups", async () => { const oidcDiagnose = vi.fn(async () => undefined); const fetch = vi.fn(async (input) => { const requested = new URL(String(input)).searchParams.get("name"); return Response.json({ pagination: { next: null }, results: [{ name: requested }, { name: "Unmapped Corporate Group" }], }); }); const groupCatalog = createAuthentikGroupCatalog({ baseUrl: "https://authentik.example.test", apiToken: sentinels[1]!, fetch, }); const report = await createAuthDiagnoser({ authMode: "oidc", authentication: { current: oidcConfig }, authStateRoot: "/safe/auth-state", sessionRootValidator: acceptSessionRoot, secrets: new Map([["THT_OIDC_CLIENT_SECRET", sentinels[0]!], ["THT_AUTHENTIK_API_TOKEN", sentinels[1]!]]), oidcProtocol: { diagnose: oidcDiagnose }, groupCatalog, }).inspect({ live: true }); expect(report).toEqual({ ready: true, mode: "oidc", checks: [expect.objectContaining({ level: "info", code: "auth_ready" })] }); expect(oidcDiagnose).toHaveBeenCalledOnce(); expect(fetch).toHaveBeenCalledTimes(2); expect(fetch.mock.calls.map(([input]) => new URL(String(input)).searchParams.get("name"))) .toEqual(["TOT Admin", "TOT Users"]); expect(report.checks).not.toContainEqual(expect.objectContaining({ level: "warning" })); expect(JSON.stringify(report)).not.toContain("Unmapped Corporate Group"); expect(report.checks.map((item) => item.message).join("\n")).not.toContain("Unmapped Corporate Group"); }); test("requires both fixed OIDC and Authentik secrets only in OIDC mode", async () => { const oidc = createAuthDiagnoser({ authMode: "oidc", authentication: { current: oidcConfig }, authStateRoot: "/safe/auth-state", secrets: new Map(), sessionRootValidator: acceptSessionRoot, }); const local = createAuthDiagnoser({ authMode: "local", authStateRoot: "/safe/auth-state", secrets: new Map(), sessionRootValidator: acceptSessionRoot, authentication: { current: () => localConfig("/safe/auth.yaml") }, localUserRegistry: { hasEnabledAdmin: async () => false } as never, }); await expect(oidc.inspect({ live: false })).resolves.toMatchObject({ ready: false, checks: [ expect.objectContaining({ code: "oidc_secret_missing" }), ] }); await expect(local.inspect({ live: false })).resolves.toMatchObject({ ready: false, checks: [ expect.objectContaining({ code: "local_admin_missing" }), ] }); }); test.each([ ["OIDC maximum", "THT_OIDC_CLIENT_SECRET", 4096, true], ["OIDC overflow", "THT_OIDC_CLIENT_SECRET", 4097, false], ["Authentik maximum", "THT_AUTHENTIK_API_TOKEN", 16 * 1024, true], ["Authentik overflow", "THT_AUTHENTIK_API_TOKEN", 16 * 1024 + 1, false], ])("uses the runtime $s secret boundary in static diagnosis", async (_label, name, length, ready) => { const secrets = new Map([ ["THT_OIDC_CLIENT_SECRET", "o"], ["THT_AUTHENTIK_API_TOKEN", "a"], ]); secrets.set(name, "x".repeat(length)); const report = await createAuthDiagnoser({ authMode: "oidc", authentication: { current: oidcConfig }, authStateRoot: "/safe/auth-state", sessionRootValidator: acceptSessionRoot, secrets, }).inspect({ live: false }); expect(report.ready).toBe(ready); expect(report.checks.map((item) => item.code)).toEqual(ready ? ["auth_ready"] : ["oidc_secret_missing"]); }); test("rejects control characters in either required secret during static diagnosis", async () => { for (const name of ["THT_OIDC_CLIENT_SECRET", "THT_AUTHENTIK_API_TOKEN"] as const) { const secrets = new Map([ ["THT_OIDC_CLIENT_SECRET", "oidc-secret"], ["THT_AUTHENTIK_API_TOKEN", "authentik-token"], ]); secrets.set(name, "invalid\u0000secret"); const report = await createAuthDiagnoser({ authMode: "oidc", authentication: { current: oidcConfig }, authStateRoot: "/safe/auth-state", sessionRootValidator: acceptSessionRoot, secrets, }).inspect({ live: false }); expect(report.checks).toEqual([expect.objectContaining({ code: "oidc_secret_missing" })]); } }); test("distinguishes a valid registry without an enabled admin from a malformed registry", async () => { const validRoot = privateRoot(); const validUsers = join(validRoot, "users.yaml"); writeFileSync(validUsers, registryYaml("user"), { encoding: "utf8", mode: 0o600 }); chmodSync(validUsers, 0o600); const validReport = await createAuthDiagnoser({ authMode: "local", authStateRoot: validRoot, sessionRootValidator: validateAuthSessionRoot, authentication: { current: () => localConfig(join(validRoot, "auth.yaml")) }, localUserRegistry: createLocalUserRegistry(validUsers), }).inspect({ live: false }); expect(validReport.checks).toEqual([expect.objectContaining({ code: "local_admin_missing" })]); const malformedRoot = privateRoot(); const malformedUsers = join(malformedRoot, "users.yaml"); writeFileSync(malformedUsers, registryYaml("admin", sentinels[3]), { encoding: "utf8", mode: 0o600 }); chmodSync(malformedUsers, 0o600); const malformedReport = await createAuthDiagnoser({ authMode: "local", authStateRoot: malformedRoot, sessionRootValidator: validateAuthSessionRoot, authentication: { current: () => localConfig(join(malformedRoot, "auth.yaml")) }, localUserRegistry: createLocalUserRegistry(malformedUsers), }).inspect({ live: false }); expect(malformedReport.checks).toEqual([expect.objectContaining({ code: "local_user_registry_invalid" })]); expect(JSON.stringify(malformedReport)).not.toContain(sentinels[3]); expect(JSON.stringify(malformedReport)).not.toContain(malformedUsers); }); test("maps unsafe auth.yaml storage from the real provider to a redacted config failure", async () => { const root = privateRoot(); const unsafePath = join(root, basename(sentinels[4]!)); writeFileSync(unsafePath, [ "version: 1", "mode: local", "publicUrl: http://127.0.0.1:8080", "local:", " usersFile: users.yaml", "", ].join("\n"), { encoding: "utf8", mode: 0o640 }); chmodSync(unsafePath, 0o640); const report = await createAuthDiagnoser({ authMode: "local", authStateRoot: root, sessionRootValidator: validateAuthSessionRoot, authentication: createAuthenticationConfigProvider(unsafePath), }).inspect({ live: false }); expect(report.checks).toEqual([expect.objectContaining({ code: "auth_config_invalid" })]); expect(JSON.stringify(report)).not.toContain(unsafePath); expect(JSON.stringify(report)).not.toContain(sentinels[4]); }); test("maps OIDC and group catalog failures to only the closed diagnostics code union", async () => { const report = await createAuthDiagnoser({ authMode: "oidc", authentication: { current: oidcConfig }, authStateRoot: "/safe/auth-state", sessionRootValidator: acceptSessionRoot, secrets: new Map([["THT_OIDC_CLIENT_SECRET", sentinels[0]!], ["THT_AUTHENTIK_API_TOKEN", sentinels[1]!]]), oidcProtocol: { diagnose: async () => { throw new Error("issuer unavailable"); } }, groupCatalog: { verifyConfiguredGroups: async () => [{ level: "error", code: "oidc_mapped_group_missing", message: "configured group is missing", field: "TOT Users" }] }, }).inspect({ live: true }); expect(report.ready).toBe(false); expect(report.checks.map((check) => check.code)).toEqual(["oidc_discovery_unreachable", "oidc_mapped_group_missing"]); }); test("reports a JWKS validation failure through its closed diagnostic code", async () => { const report = await createAuthDiagnoser({ authMode: "oidc", authentication: { current: oidcConfig }, authStateRoot: "/safe/auth-state", sessionRootValidator: acceptSessionRoot, secrets: new Map([["THT_OIDC_CLIENT_SECRET", sentinels[0]!], ["THT_AUTHENTIK_API_TOKEN", sentinels[1]!]]), oidcProtocol: { diagnose: async () => { throw new OidcJwksUnavailableError(); } }, groupCatalog: { verifyConfiguredGroups: async () => [] }, }).inspect({ live: true }); expect(report.checks).toEqual([expect.objectContaining({ code: "oidc_jwks_unreachable" })]); }); test("bounds a live diagnosis whose OIDC dependency ignores abort and starts no later checks", async () => { vi.useFakeTimers(); try { let rejectLate: ((error: Error) => void) | undefined; const oidcDiagnose = vi.fn(() => new Promise((_resolve, reject) => { rejectLate = reject; })); const verifyConfiguredGroups = vi.fn(async () => []); const completion = createAuthDiagnoser({ authMode: "oidc", authentication: { current: oidcConfig }, authStateRoot: "/safe/auth-state", sessionRootValidator: acceptSessionRoot, secrets: new Map([["THT_OIDC_CLIENT_SECRET", "oidc"], ["THT_AUTHENTIK_API_TOKEN", "authentik"]]), oidcProtocol: { diagnose: oidcDiagnose }, groupCatalog: { verifyConfiguredGroups }, }).inspect({ live: true }); const outcome = completion.then((report) => report, () => undefined); await vi.advanceTimersByTimeAsync(29_999); await expect(Promise.race([outcome, Promise.resolve("pending")])).resolves.toBe("pending"); await vi.advanceTimersByTimeAsync(1); await expect(outcome).resolves.toMatchObject({ ready: false, checks: [expect.objectContaining({ code: "oidc_discovery_unreachable" })], }); expect(oidcDiagnose).toHaveBeenCalledOnce(); expect(verifyConfiguredGroups).not.toHaveBeenCalled(); rejectLate?.(new Error("late-secret-detail")); await Promise.resolve(); } finally { vi.useRealTimers(); } }); test("composes caller cancellation with the overall live-diagnostic deadline", async () => { const caller = new AbortController(); const verifyConfiguredGroups = vi.fn(async () => []); const completion = createAuthDiagnoser({ authMode: "oidc", authentication: { current: oidcConfig }, authStateRoot: "/safe/auth-state", sessionRootValidator: acceptSessionRoot, secrets: new Map([["THT_OIDC_CLIENT_SECRET", "oidc"], ["THT_AUTHENTIK_API_TOKEN", "authentik"]]), oidcProtocol: { diagnose: async () => await new Promise(() => undefined) }, groupCatalog: { verifyConfiguredGroups }, }).inspect({ live: true, signal: caller.signal }); caller.abort(); await expect(completion).resolves.toMatchObject({ ready: false, checks: [expect.objectContaining({ code: "oidc_discovery_unreachable" })], }); expect(verifyConfiguredGroups).not.toHaveBeenCalled(); }); test("never reports auth_ready when cancellation lands during OIDC completion", async () => { const caller = new AbortController(); const verifyConfiguredGroups = vi.fn(async () => []); const report = await createAuthDiagnoser({ authMode: "oidc", authentication: { current: oidcConfig }, authStateRoot: "/safe/auth-state", sessionRootValidator: acceptSessionRoot, secrets: new Map([["THT_OIDC_CLIENT_SECRET", "oidc"], ["THT_AUTHENTIK_API_TOKEN", "authentik"]]), oidcProtocol: { diagnose: async () => { caller.abort(); } }, groupCatalog: { verifyConfiguredGroups }, }).inspect({ live: true, signal: caller.signal }); expect(report).toMatchObject({ ready: false, checks: [expect.objectContaining({ code: "oidc_discovery_unreachable" })], }); expect(verifyConfiguredGroups).not.toHaveBeenCalled(); }); test("stops starting mapped-group requests when the overall live deadline expires", async () => { vi.useFakeTimers(); try { const loaded = oidcConfig(); if (loaded.value.mode !== "oidc") throw new Error("test configuration is not OIDC"); loaded.value.authorization.groupRoles = Object.fromEntries(Array.from({ length: 10 }, (_unused, index) => [ `Mapped Group ${String(index).padStart(2, "0")}`, index === 0 ? ["admin"] : ["user"], ])); const fetch = vi.fn((input, init) => new Promise((resolve, reject) => { const timer = setTimeout(() => { const name = new URL(String(input)).searchParams.get("name"); resolve(Response.json({ pagination: { next: null }, results: [{ name }] })); }, 4_000); init?.signal?.addEventListener("abort", () => { clearTimeout(timer); reject(new DOMException("aborted", "AbortError")); }, { once: true }); })); const completion = createAuthDiagnoser({ authMode: "oidc", authentication: { current: () => loaded }, authStateRoot: "/safe/auth-state", sessionRootValidator: acceptSessionRoot, secrets: new Map([["THT_OIDC_CLIENT_SECRET", "oidc"], ["THT_AUTHENTIK_API_TOKEN", "authentik"]]), oidcProtocol: { diagnose: async () => undefined }, groupCatalog: createAuthentikGroupCatalog({ baseUrl: "https://authentik.example.test", apiToken: "authentik", fetch, }), }).inspect({ live: true }); await vi.advanceTimersByTimeAsync(30_000); await expect(completion).resolves.toMatchObject({ ready: false, checks: [expect.objectContaining({ code: "oidc_group_catalog_unreachable" })], }); expect(fetch).toHaveBeenCalledTimes(8); await vi.advanceTimersByTimeAsync(30_000); expect(fetch).toHaveBeenCalledTimes(8); } finally { vi.useRealTimers(); } }); test("maps a concrete discovery adapter issuer mismatch to its dedicated code", async () => { const loaded = oidcConfig(); const fetch = vi.fn(async (input) => { const url = new URL(String(input)); if (!url.pathname.includes(".well-known")) throw new Error("JWKS must not be requested after issuer mismatch"); return Response.json({ issuer: "https://different-issuer.example.test", authorization_endpoint: "https://issuer.example.test/authorize", token_endpoint: "https://issuer.example.test/token", jwks_uri: "https://issuer.example.test/jwks", response_types_supported: ["code"], grant_types_supported: ["authorization_code"], subject_types_supported: ["public"], id_token_signing_alg_values_supported: ["RS256"], }); }); const oidcProtocol = createOidcProtocol({ issuer: loaded.value.mode === "oidc" ? loaded.value.oidc.issuer : "", clientId: "thothii", clientSecret: sentinels[0]!, callbackUrl: "https://thothii.example.test/api/auth/oidc/callback", scopes: ["openid"], groupsClaim: "groups", fetch, }); const report = await createAuthDiagnoser({ authMode: "oidc", authentication: { current: () => loaded }, authStateRoot: "/safe/auth-state", sessionRootValidator: acceptSessionRoot, secrets: new Map([["THT_OIDC_CLIENT_SECRET", sentinels[0]!], ["THT_AUTHENTIK_API_TOKEN", sentinels[1]!]]), oidcProtocol, groupCatalog: { verifyConfiguredGroups: async () => [] }, }).inspect({ live: true }); expect(report.checks).toEqual([expect.objectContaining({ code: "oidc_issuer_mismatch" })]); expect(fetch).toHaveBeenCalledOnce(); expect(JSON.stringify(report)).not.toContain("different-issuer"); }); test.each([ ["an upstream error", 503, { issuer: "https://different-issuer.example.test", authorization_endpoint: "https://issuer.example.test/authorize", token_endpoint: "https://issuer.example.test/token", jwks_uri: "https://issuer.example.test/jwks", response_types_supported: ["code"], grant_types_supported: ["authorization_code"], subject_types_supported: ["public"], id_token_signing_alg_values_supported: ["RS256"], }], ["schema-invalid metadata", 200, { issuer: "https://different-issuer.example.test" }], ["an unsafe foreign issuer", 200, { issuer: "http://different-issuer.example.test", authorization_endpoint: "https://issuer.example.test/authorize", token_endpoint: "https://issuer.example.test/token", jwks_uri: "https://issuer.example.test/jwks", response_types_supported: ["code"], subject_types_supported: ["public"], id_token_signing_alg_values_supported: ["RS256"], }], ["an unsafe authorization endpoint", 200, { issuer: "https://different-issuer.example.test", authorization_endpoint: "http://127.0.0.1/authorize", token_endpoint: "https://issuer.example.test/token", jwks_uri: "https://issuer.example.test/jwks", response_types_supported: ["code"], subject_types_supported: ["public"], id_token_signing_alg_values_supported: ["RS256"], }], ["an unsafe token endpoint", 200, { issuer: "https://different-issuer.example.test", authorization_endpoint: "https://issuer.example.test/authorize", token_endpoint: "https://operator:secret@issuer.example.test/token", jwks_uri: "https://issuer.example.test/jwks", response_types_supported: ["code"], subject_types_supported: ["public"], id_token_signing_alg_values_supported: ["RS256"], }], ["an unsafe JWKS endpoint", 200, { issuer: "https://different-issuer.example.test", authorization_endpoint: "https://issuer.example.test/authorize", token_endpoint: "https://issuer.example.test/token", jwks_uri: "https://issuer.example.test/jwks#fragment", response_types_supported: ["code"], subject_types_supported: ["public"], id_token_signing_alg_values_supported: ["RS256"], }], ])("does not classify %s containing an issuer as an issuer mismatch", async (_label, status, body) => { const loaded = oidcConfig(); const fetch = vi.fn(async () => Response.json(body, { status })); const oidcProtocol = createOidcProtocol({ issuer: loaded.value.mode === "oidc" ? loaded.value.oidc.issuer : "", clientId: "thothii", clientSecret: sentinels[0]!, callbackUrl: "https://thothii.example.test/api/auth/oidc/callback", scopes: ["openid"], groupsClaim: "groups", fetch, }); const report = await createAuthDiagnoser({ authMode: "oidc", authentication: { current: () => loaded }, authStateRoot: "/safe/auth-state", sessionRootValidator: acceptSessionRoot, secrets: new Map([["THT_OIDC_CLIENT_SECRET", sentinels[0]!], ["THT_AUTHENTIK_API_TOKEN", sentinels[1]!]]), oidcProtocol, groupCatalog: { verifyConfiguredGroups: async () => [] }, }).inspect({ live: true }); expect(report.checks).toEqual([expect.objectContaining({ code: "oidc_discovery_unreachable" })]); expect(report.checks).not.toContainEqual(expect.objectContaining({ code: "oidc_issuer_mismatch" })); expect(fetch).toHaveBeenCalledOnce(); expect(JSON.stringify(report)).not.toContain("different-issuer"); }); test("redacts exceptional configuration, registry, protocol, and catalog errors", async () => { const detail = sentinels.join(" "); const report = await createAuthDiagnoser({ authMode: "oidc", authentication: { current: () => { throw new Error(detail); } }, authStateRoot: sentinels[4]!, secrets: new Map(), oidcProtocol: { diagnose: async () => { throw new Error(detail); } }, groupCatalog: { verifyConfiguredGroups: async () => { throw new Error(detail); } }, }).inspect({ live: true }); const rendered = JSON.stringify(report); for (const sentinel of sentinels) expect(rendered).not.toContain(sentinel); expect(report.checks.every((check) => check.level === "error" || check.level === "info")).toBe(true); }); test.skipIf(process.platform === "win32")("uses the runtime validator for canonical, private session roots", async () => { const dependencies = (authStateRoot: string) => ({ authMode: "none" as const, authStateRoot, sessionRootValidator: validateAuthSessionRoot, }); const valid = privateRoot(); await expect(createAuthDiagnoser(dependencies(valid)).inspect({ live: false })) .resolves.toMatchObject({ ready: true, checks: [expect.objectContaining({ code: "auth_ready" })] }); const realRoot = join(privateRoot(), "real-auth"); mkdirSync(realRoot, { mode: 0o700 }); chmodSync(realRoot, 0o700); const linkedRoot = join(privateRoot(), "linked-auth"); symlinkSync(realRoot, linkedRoot); const absent = join(privateRoot(), "absent-auth"); const absentParent = join(privateRoot(), "absent-parent"); const absentNested = join(absentParent, "auth"); const blockedParent = join(privateRoot(), "not-a-directory"); writeFileSync(blockedParent, "blocked", { mode: 0o600 }); const traversal = `${valid}/../${basename(valid)}`; const missingReport = await createAuthDiagnoser(dependencies(absent)).inspect({ live: false }); expect(missingReport).toMatchObject({ ready: true, checks: [expect.objectContaining({ code: "auth_ready" })] }); expect(existsSync(absent)).toBe(false); for (const unsafe of [traversal, linkedRoot, absentNested, join(blockedParent, "auth")]) { const report = await createAuthDiagnoser(dependencies(unsafe)).inspect({ live: false }); expect(report).toMatchObject({ ready: false, checks: [expect.objectContaining({ code: "auth_session_store_invalid" })] }); expect(JSON.stringify(report)).not.toContain(unsafe); } expect(existsSync(absentParent)).toBe(false); chmodSync(valid, 0o750); await expect(createAuthDiagnoser(dependencies(valid)).inspect({ live: false })) .resolves.toMatchObject({ ready: false, checks: [expect.objectContaining({ code: "auth_session_store_invalid" })] }); }); test.skipIf(process.platform === "win32")("diagnoses unsafe existing session-store children without creating missing children", async () => { const root = privateRoot(); const outside = privateRoot(); symlinkSync(outside, join(root, "sessions")); const linked = await createAuthDiagnoser({ authMode: "none", authStateRoot: root, sessionRootValidator: validateAuthSessionRoot, }).inspect({ live: false }); expect(linked).toMatchObject({ ready: false, checks: [expect.objectContaining({ code: "auth_session_store_invalid" })], }); expect(existsSync(join(root, "oidc"))).toBe(false); expect(JSON.stringify(linked)).not.toContain(root); rmSync(join(root, "sessions")); mkdirSync(join(root, "sessions"), { mode: 0o700 }); chmodSync(join(root, "sessions"), 0o700); mkdirSync(join(root, "oidc"), { mode: 0o700 }); chmodSync(join(root, "oidc"), 0o750); const nonPrivate = await createAuthDiagnoser({ authMode: "none", authStateRoot: root, sessionRootValidator: validateAuthSessionRoot, }).inspect({ live: false }); expect(nonPrivate).toMatchObject({ ready: false, checks: [expect.objectContaining({ code: "auth_session_store_invalid" })], }); }); test.skipIf(process.platform === "win32")("routes production POSIX static validation through the native auth-storage bridge", async () => { const validateRoot = vi.fn(async () => undefined); const report = await createAuthDiagnoser({ authMode: "none", authStateRoot: "/var/lib/thothii/auth", posixStorageBridge: { validateRoot }, }).inspect({ live: false }); expect(report).toMatchObject({ ready: true }); expect(validateRoot).toHaveBeenCalledOnce(); expect(validateRoot).toHaveBeenCalledWith("/var/lib/thothii/auth"); }); test("routes native Windows static session-root validation through the auth-storage bridge", async () => { const originalPlatform = process.platform; const validateRoot = vi.fn(async () => undefined); Object.defineProperty(process, "platform", { configurable: true, value: "win32" }); try { const report = await createAuthDiagnoser({ authMode: "none", authStateRoot: "C:\\ProgramData\\ThothII\\auth", windowsStorageBridge: { validateRoot } as never, }).inspect({ live: false }); expect(report).toMatchObject({ ready: true }); expect(validateRoot).toHaveBeenCalledOnce(); expect(validateRoot).toHaveBeenCalledWith("C:\\ProgramData\\ThothII\\auth"); } finally { Object.defineProperty(process, "platform", { configurable: true, value: originalPlatform }); } }); test("accepts a platform storage validator without exposing its root or failure", async () => { const platformRoot = "C:\\private-path-UNIQUE-6R2\\auth"; const sessionRootValidator = vi.fn(async () => { throw new Error(`${platformRoot} denied`); }); const report = await createAuthDiagnoser({ authMode: "none", authStateRoot: platformRoot, sessionRootValidator, }).inspect({ live: false }); expect(sessionRootValidator).toHaveBeenCalledWith(platformRoot); expect(report.checks).toEqual([expect.objectContaining({ code: "auth_session_store_invalid" })]); expect(JSON.stringify(report)).not.toContain(platformRoot); });