import { describe, expect, it } from "vitest"; import { createIdentityConfig, IdentityConfigError } from "../src/identity/config.js"; const validSecret = "correct-horse-battery-staple-0123456789"; const validBaseUrl = "https://identity.example.test"; const validTrustedOrigins = ["https://identity.example.test", "https://dashboard.example.test"]; function validInput() { return { baseUrl: validBaseUrl, secret: validSecret, trustedOrigins: validTrustedOrigins }; } /** The loopback/`http` shape only `{ environment: "development" }` accepts — used by the tests that * exercise development-only behavior (such as explicitly enabling public signup) so they never * accidentally pass through production validation. */ function developmentInput() { return { baseUrl: "http://localhost:3000", secret: validSecret, trustedOrigins: ["http://localhost:3000"], }; } describe("Core identity configuration", () => { it("accepts a valid secret, base URL, and trusted origins", () => { const config = createIdentityConfig(validInput(), { environment: "production" }); expect(config).toEqual({ baseUrl: validBaseUrl, publicSignupEnabled: false, secret: validSecret, trustedOrigins: validTrustedOrigins, }); expect(Object.isFrozen(config)).toBe(true); expect(Object.isFrozen(config.trustedOrigins)).toBe(true); }); it("rejects a missing secret", () => { expect(() => createIdentityConfig({ ...validInput(), secret: undefined }, { environment: "production" }), ).toThrow(IdentityConfigError); try { createIdentityConfig({ ...validInput(), secret: undefined }); } catch (error) { expect(error).toMatchObject({ code: "SECRET_MISSING" }); } }); it("rejects a secret shorter than 32 characters", () => { let captured: unknown; try { createIdentityConfig({ ...validInput(), secret: "x".repeat(31) }); } catch (error) { captured = error; } expect(captured).toMatchObject({ code: "SECRET_TOO_SHORT" }); }); it("accepts a secret of exactly 32 characters", () => { const secret = "aB1cD2eF3gH4iJ5kL6mN7oP8qR9sT0uV"; expect(secret).toHaveLength(32); const config = createIdentityConfig({ ...validInput(), secret }); expect(config.secret).toBe(secret); }); it("rejects a degenerate single-character-repeated secret", () => { let captured: unknown; try { createIdentityConfig({ ...validInput(), secret: "a".repeat(40) }); } catch (error) { captured = error; } expect(captured).toMatchObject({ code: "SECRET_LOW_ENTROPY" }); }); it("rejects an invalid base URL", () => { for (const baseUrl of [undefined, "", "not-a-url", "ftp://example.test", "example.test"]) { let captured: unknown; try { createIdentityConfig({ ...validInput(), baseUrl }); } catch (error) { captured = error; } expect(captured).toBeInstanceOf(IdentityConfigError); } }); it("rejects missing trusted origins", () => { let captured: unknown; try { createIdentityConfig({ ...validInput(), trustedOrigins: undefined }); } catch (error) { captured = error; } expect(captured).toMatchObject({ code: "TRUSTED_ORIGINS_MISSING" }); }); it("rejects an empty trusted origins array", () => { let captured: unknown; try { createIdentityConfig({ ...validInput(), trustedOrigins: [] }); } catch (error) { captured = error; } expect(captured).toMatchObject({ code: "TRUSTED_ORIGINS_EMPTY" }); }); it("rejects a trusted origin containing a path, query, or fragment", () => { for (const origin of [ "https://example.test/", "https://example.test/path", "https://example.test#fragment", ]) { let captured: unknown; try { createIdentityConfig({ ...validInput(), trustedOrigins: [origin] }); } catch (error) { captured = error; } expect(captured).toMatchObject({ code: "TRUSTED_ORIGIN_INVALID" }); } }); it("rejects wildcard trusted origins", () => { for (const origin of ["https://*.example.test", "https://app?.example.test"]) { let captured: unknown; try { createIdentityConfig({ ...validInput(), trustedOrigins: [origin] }); } catch (error) { captured = error; } expect(captured).toMatchObject({ code: "TRUSTED_ORIGIN_WILDCARD_UNSUPPORTED" }); } }); it("rejects insecure http origins and loopback hosts in production", () => { let httpError: unknown; try { createIdentityConfig( { ...validInput(), trustedOrigins: ["http://identity.example.test"] }, { environment: "production" }, ); } catch (error) { httpError = error; } expect(httpError).toMatchObject({ code: "TRUSTED_ORIGIN_INSECURE_IN_PRODUCTION" }); let loopbackError: unknown; try { createIdentityConfig( { ...validInput(), baseUrl: "https://localhost", trustedOrigins: ["https://localhost"] }, { environment: "production" }, ); } catch (error) { loopbackError = error; } expect(loopbackError).toMatchObject({ code: "BASE_URL_LOOPBACK_IN_PRODUCTION" }); }); it("defaults to production validation when environment is not specified", () => { let captured: unknown; try { createIdentityConfig({ ...validInput(), baseUrl: "http://identity.example.test" }); } catch (error) { captured = error; } expect(captured).toMatchObject({ code: "BASE_URL_INSECURE_IN_PRODUCTION" }); }); it("explicitly allows local development origins only when environment is development", () => { const config = createIdentityConfig( { baseUrl: "http://localhost:3000", secret: validSecret, trustedOrigins: ["http://localhost:3000"], }, { environment: "development" }, ); expect(config.baseUrl).toBe("http://localhost:3000"); }); it("defaults publicSignupEnabled to false when entirely omitted", () => { const config = createIdentityConfig(validInput(), { environment: "production" }); expect(config.publicSignupEnabled).toBe(false); }); it("accepts an explicit boolean publicSignupEnabled in development", () => { expect( createIdentityConfig( { ...developmentInput(), publicSignupEnabled: true }, { environment: "development" }, ).publicSignupEnabled, ).toBe(true); expect( createIdentityConfig( { ...developmentInput(), publicSignupEnabled: false }, { environment: "development" }, ).publicSignupEnabled, ).toBe(false); }); it('accepts the exact strings "true"/"false" in development (environment variables are always strings)', () => { expect( createIdentityConfig( { ...developmentInput(), publicSignupEnabled: "true" }, { environment: "development" }, ).publicSignupEnabled, ).toBe(true); expect( createIdentityConfig( { ...developmentInput(), publicSignupEnabled: "false" }, { environment: "development" }, ).publicSignupEnabled, ).toBe(false); }); it("accepts an explicitly disabled publicSignupEnabled in production", () => { for (const publicSignupEnabled of [false, "false"]) { expect( createIdentityConfig( { ...validInput(), publicSignupEnabled }, { environment: "production" }, ).publicSignupEnabled, ).toBe(false); } }); it("refuses to enable public signup in production until durable abuse controls exist", () => { // Ekklesia has no verified email, invitation requirement, CAPTCHA, or durable shared/edge // limiter yet, so a production deployment must not be able to open public registration at all // — not even deliberately. This is a fail-closed configuration error, never a warning. for (const publicSignupEnabled of [true, "true"]) { let captured: unknown; try { createIdentityConfig( { ...validInput(), publicSignupEnabled }, { environment: "production" }, ); } catch (error) { captured = error; } expect(captured).toBeInstanceOf(IdentityConfigError); expect(captured).toMatchObject({ code: "PUBLIC_SIGNUP_UNSUPPORTED_IN_PRODUCTION" }); } }); it("defaults to production validation for public signup when environment is not specified", () => { let captured: unknown; try { createIdentityConfig({ ...validInput(), publicSignupEnabled: "true" }); } catch (error) { captured = error; } expect(captured).toMatchObject({ code: "PUBLIC_SIGNUP_UNSUPPORTED_IN_PRODUCTION" }); }); it("reports a malformed public-signup value as malformed even in production, never as unsupported", () => { let captured: unknown; try { createIdentityConfig( { ...validInput(), publicSignupEnabled: "TRUE" }, { environment: "production" }, ); } catch (error) { captured = error; } expect(captured).toMatchObject({ code: "PUBLIC_SIGNUP_ENABLED_INVALID" }); }); it("rejects a misspelled, loosely-truthy, or malformed publicSignupEnabled rather than silently defaulting", () => { for (const publicSignupEnabled of ["1", "0", "yes", "no", "TRUE", "True", " true", "", 1, 0]) { let captured: unknown; try { createIdentityConfig({ ...validInput(), publicSignupEnabled }); } catch (error) { captured = error; } expect(captured).toMatchObject({ code: "PUBLIC_SIGNUP_ENABLED_INVALID" }); } }); it("never leaks the secret, base URL, or trusted origins through a thrown error", () => { const hostileSecret = "s3cr3t-do-not-log-0123456789abcdef"; let captured: unknown; try { createIdentityConfig({ baseUrl: "not-a-url", secret: hostileSecret, trustedOrigins: [] }); } catch (error) { captured = error; } expect(captured).toBeInstanceOf(IdentityConfigError); const publicText = `${String(captured)}\n${ captured instanceof Error ? (captured.stack ?? "") : "" }\n${JSON.stringify(captured)}`; expect(publicText).not.toContain(hostileSecret); expect(publicText).not.toContain(validBaseUrl); for (const origin of validTrustedOrigins) { expect(publicText).not.toContain(origin); } }); });