import { describe, expect, it } from "bun:test"; import { delimiter } from "node:path"; import { describe as description, load } from "./config"; const REQUIRED = { STORAGE_DRIVER: "postgres", DATABASE_URL: "postgresql://chopin:secret@database.test/chopin", APP_ORIGIN: "https://chopin.example", GITHUB_APP_SLUG: "chopin-test", GITHUB_APP_CLIENT_ID: "client-id", GITHUB_APP_CLIENT_SECRET: "client-secret", SESSION_ENCRYPTION_KEY: "11".repeat(32), }; function configured(overrides: Record = {}) { let env: Record = { ...REQUIRED, AGENT: undefined, BACKGROUND_JOBS: undefined, WEB_RESEARCH: undefined, HARNESS: undefined, HARNESS_AUTH: undefined, AUTH_MODE: undefined, ATOMIC_PLANNER: undefined, ATOMIC_PLANNER_CHECKOUTS: undefined, ATOMIC_PLANNER_INPUT_TIMEOUT_MS: undefined, SERVER_HOST: undefined, PORT: undefined, MODEL: undefined, CHOPIN_LOCAL_CREDENTIALS_DIR: undefined, GITHUB_ALLOWED_USERS: undefined, GITHUB_ALLOWED_ORGANIZATIONS: undefined, ...overrides, }; let previous = { ...process.env }; for (let [key, value] of Object.entries(env)) { if (value === undefined) delete process.env[key]; else process.env[key] = value; } try { return load(); } finally { for (let key of Object.keys(env)) delete process.env[key]; Object.assign(process.env, previous); } } describe("configuration", () => { it("loads the mandatory GitHub and PostgreSQL services without printing secrets", () => { let config = configured(); expect(config.storage).toEqual({ driver: "postgres", url: REQUIRED.DATABASE_URL, }); expect(config.auth.origin).toBe(REQUIRED.APP_ORIGIN); expect(description(config)).toContain("auth: github"); expect(description(config)).toContain("storage: postgres"); expect(description(config)).not.toContain("secret"); expect(description(config)).not.toContain(REQUIRED.SESSION_ENCRYPTION_KEY); }); it("defaults the built-in adapter to PostgreSQL", () => { expect(configured({ STORAGE_DRIVER: undefined }).storage.driver).toBe("postgres"); }); it("gates background execution and web research behind the hosted agent", () => { expect(configured()).toMatchObject({ agent: true, backgroundJobs: true, webResearch: true }); expect(configured({ WEB_RESEARCH: "off" })).toMatchObject({ agent: true, backgroundJobs: true, webResearch: false, }); expect(configured({ BACKGROUND_JOBS: "off" })).toMatchObject({ agent: true, backgroundJobs: false, webResearch: false, }); expect(configured({ AGENT: "off" })).toMatchObject({ agent: false, backgroundJobs: true, webResearch: false, }); }); it("selects a harness and retains AGENT and MODEL behavior", () => { expect(configured()).toMatchObject({ harness: "copilot-sdk", harnessAuth: undefined, agent: true, model: "gpt-6-luna", }); expect(configured({ HARNESS: "", HARNESS_AUTH: "" })).toMatchObject({ harness: "copilot-sdk", harnessAuth: undefined, }); let config = configured({ HARNESS: "custom", HARNESS_AUTH: "direct", AGENT: "off", MODEL: "named-model", }); expect(config).toMatchObject({ harness: "custom", harnessAuth: "direct", agent: false, model: "named-model", }); expect(description(config)).toContain("harness: custom"); expect(description(config)).not.toContain("direct"); }); it("requires an explicit MODEL under the pi harness", () => { expect(() => configured({ HARNESS: "pi", HARNESS_AUTH: "openai" })) .toThrow("MODEL is required when HARNESS=pi"); expect(configured({ HARNESS: "pi", HARNESS_AUTH: "openai", MODEL: "openai/gpt-5.6" })) .toMatchObject({ harness: "pi", model: "openai/gpt-5.6" }); }); it("requires an explicit provider/model MODEL under the atomic harness", () => { expect(() => configured({ HARNESS: "atomic", HARNESS_AUTH: "auto" })) .toThrow("MODEL is required when HARNESS=atomic"); expect(configured({ HARNESS: "atomic", HARNESS_AUTH: "ai-gateway", MODEL: "vercel-ai-gateway/anthropic/claude-sonnet-4.6", })).toMatchObject({ harness: "atomic", model: "vercel-ai-gateway/anthropic/claude-sonnet-4.6", }); }); it("allows full Atomic Planner only in local atomic mode, with either auth mode", () => { let full = { ATOMIC_PLANNER: "full", AUTH_MODE: "local", HARNESS: "atomic", MODEL: "stub/model", APP_ORIGIN: "http://localhost:8790", PORT: "8790", }; for (let auth of ["auto", "ai-gateway"]) { expect(configured({ ...full, HARNESS_AUTH: auth }).atomicPlanner).toEqual({ checkouts: [], }); } expect(configured().atomicPlanner).toBeUndefined(); for (let mode of ["isolated", "FULL", " "]) { expect(() => configured({ ...full, ATOMIC_PLANNER: mode })).toThrow("ATOMIC_PLANNER"); } for (let auth of [undefined, "hosted"]) { expect(() => configured({ ...full, AUTH_MODE: auth })).toThrow("AUTH_MODE=local"); } for (let harness of [undefined, "pi", "copilot-sdk"]) { expect(() => configured({ ...full, HARNESS: harness })).toThrow("HARNESS=atomic"); } }); it("validates checkout paths and an optional per-request input timeout", () => { let full = { ATOMIC_PLANNER: "full", AUTH_MODE: "local", HARNESS: "atomic", MODEL: "stub/model", APP_ORIGIN: "http://localhost:8790", PORT: "8790", }; expect( configured({ ...full, ATOMIC_PLANNER_CHECKOUTS: ["/tmp/one", "/tmp/two", "/tmp/one"].join(delimiter), ATOMIC_PLANNER_INPUT_TIMEOUT_MS: "1234", }).atomicPlanner, ).toEqual({ checkouts: ["/tmp/one", "/tmp/two", "/tmp/one"], inputTimeoutMs: 1234 }); for (let paths of ["relative", ["/tmp/one", "relative"].join(delimiter)]) { expect(() => configured({ ...full, ATOMIC_PLANNER_CHECKOUTS: paths })).toThrow("absolute"); } for (let timeout of ["0", "-1", "1.5", "oops", "10ms", "2147483648"]) { expect(() => configured({ ...full, ATOMIC_PLANNER_INPUT_TIMEOUT_MS: timeout })).toThrow( "ATOMIC_PLANNER_INPUT_TIMEOUT_MS", ); } }); it("requires a valid PostgreSQL URL", () => { expect(() => configured({ DATABASE_URL: undefined })).toThrow("DATABASE_URL is required"); expect(() => configured({ DATABASE_URL: "https://database.test" })).toThrow("PostgreSQL URL"); expect(() => configured({ STORAGE_DRIVER: "cosmos" })).toThrow("STORAGE_DRIVER"); }); it("requires complete GitHub App configuration and a safe exact origin", () => { expect(() => configured({ GITHUB_APP_CLIENT_ID: undefined })).toThrow( "GITHUB_APP_CLIENT_ID", ); expect(() => configured({ GITHUB_APP_SLUG: "Bad Slug" })).toThrow("GITHUB_APP_SLUG"); expect(() => configured({ APP_ORIGIN: "http://chopin.example" })).toThrow("HTTPS"); expect(() => configured({ APP_ORIGIN: "https://chopin.example/path" })).toThrow( "only an HTTP or HTTPS origin", ); expect(() => configured({ APP_ORIGIN: "http://127.0.0.1:8787" })).not.toThrow(); expect(() => configured({ SESSION_ENCRYPTION_KEY: "short" })).toThrow("32 bytes"); }); it("loads normalized user and organization admission lists", () => { let config = configured({ GITHUB_ALLOWED_USERS: " OctoCat,hubot,octocat,managed_user ", GITHUB_ALLOWED_ORGANIZATIONS: " GitHubNext,github ", }); expect([...config.auth.allowedUsers!]).toEqual(["octocat", "hubot", "managed_user"]); expect([...config.auth.allowedOrganizations!]).toEqual(["githubnext", "github"]); expect(description(config)).toContain("restricted: 3 users, 2 organizations"); expect(description(config)).not.toContain("octocat"); }); it("keeps blank admission lists unrestricted and rejects malformed entries", () => { let config = configured({ GITHUB_ALLOWED_USERS: " ", GITHUB_ALLOWED_ORGANIZATIONS: "" }); expect(config.auth.allowedUsers).toBeUndefined(); expect(config.auth.allowedOrganizations).toBeUndefined(); expect(description(config)).toContain("unrestricted"); expect(() => configured({ GITHUB_ALLOWED_USERS: "octocat,,hubot" })).toThrow( "GITHUB_ALLOWED_USERS", ); expect(() => configured({ GITHUB_ALLOWED_ORGANIZATIONS: "-githubnext" })).toThrow( "GITHUB_ALLOWED_ORGANIZATIONS", ); expect(() => configured({ GITHUB_ALLOWED_ORGANIZATIONS: "managed_org" })).toThrow( "GITHUB_ALLOWED_ORGANIZATIONS", ); }); it("enables a client-secret-free local mode only at the exact loopback port", () => { let local = { AUTH_MODE: "local", GITHUB_APP_CLIENT_SECRET: undefined, APP_ORIGIN: "http://localhost:8790", PORT: "8790", SERVER_HOST: "127.0.0.1", }; let config = configured(local); expect(config.auth.clientSecret).toBeUndefined(); expect(config.auth.local).toMatchObject({ port: 8790 }); expect(description(config)).toContain("github local device flow"); expect(description(config)).not.toContain("secret"); expect(() => configured({ ...local, SERVER_HOST: "0.0.0.0" })).toThrow("loopback"); expect(() => configured({ ...local, APP_ORIGIN: "http://example.test:8790" })) .toThrow("HTTPS"); expect(() => configured({ ...local, APP_ORIGIN: "http://localhost:8791" })) .toThrow("loopback"); expect(() => configured({ ...local, APP_ORIGIN: "https://localhost:8790" })) .not.toThrow(); expect(() => configured({ ...local, AUTH_MODE: "bad" })).toThrow("AUTH_MODE"); expect(() => configured({ GITHUB_APP_CLIENT_SECRET: undefined })).toThrow( "GITHUB_APP_CLIENT_SECRET", ); }); });