feat: establish core identity foundation
Adds Core-owned identity contracts, a Core-owned Better Auth database schema (ekklesia_core_user/session/account/verification), a first-class Core-owned migration source that coexists with module-owned migrations under the exact existing migration system, and an explicit Better Auth construction boundary. No authentication endpoint or sign-in UI is exposed yet (ADR 0010). Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
df0f20d8af
commit
679a5d225c
@@ -200,6 +200,7 @@ describe("Ekklesia Doctor diagnostics", () => {
|
||||
"migrations.discovery",
|
||||
"postgresql.connection",
|
||||
"postgresql.plan",
|
||||
"identity.configuration",
|
||||
"object-storage.integration",
|
||||
]);
|
||||
expect(check(report, "modules.discovery").details).toEqual(["people 0.1.0", "calendar 0.2.0"]);
|
||||
@@ -438,4 +439,73 @@ describe("Ekklesia Doctor diagnostics", () => {
|
||||
expect(services.discoverSchemas).toHaveBeenCalledOnce();
|
||||
expect(services.discoverMigrations).toHaveBeenCalledOnce();
|
||||
});
|
||||
|
||||
it("skips identity configuration (not a failure) when none of it is set", async () => {
|
||||
const report = await diagnoseEkklesia(options(), dependencies());
|
||||
|
||||
const identity = check(report, "identity.configuration");
|
||||
expect(identity.status).toBe("skipped");
|
||||
expect(identity.details[0]).toContain("Core identity schema defines 4 tables");
|
||||
expect(report.result).toBe("ready-with-warnings");
|
||||
expect(doctorExitCode(report)).toBe(0);
|
||||
});
|
||||
|
||||
it("passes identity configuration when a valid secret, base URL, and trusted origins are provided", async () => {
|
||||
const report = await diagnoseEkklesia(
|
||||
{
|
||||
...options(),
|
||||
identityConfiguration: {
|
||||
baseUrl: "https://identity.example.test",
|
||||
environment: "production",
|
||||
secret: "correct-horse-battery-staple-0123456789",
|
||||
trustedOrigins: ["https://identity.example.test"],
|
||||
},
|
||||
},
|
||||
dependencies(),
|
||||
);
|
||||
|
||||
const identity = check(report, "identity.configuration");
|
||||
expect(identity.status).toBe("pass");
|
||||
expect(report.result).toBe("ready-with-warnings"); // PostgreSQL is still skipped in this fixture
|
||||
});
|
||||
|
||||
it("fails identity configuration for an invalid secret without leaking it", async () => {
|
||||
const hostileSecret = "s3cr3t-do-not-log";
|
||||
const report = await diagnoseEkklesia(
|
||||
{
|
||||
...options(),
|
||||
identityConfiguration: {
|
||||
baseUrl: "https://identity.example.test",
|
||||
environment: "production",
|
||||
secret: hostileSecret,
|
||||
trustedOrigins: ["https://identity.example.test"],
|
||||
},
|
||||
},
|
||||
dependencies(),
|
||||
);
|
||||
|
||||
const identity = check(report, "identity.configuration");
|
||||
expect(identity.status).toBe("failure");
|
||||
expect(identity.details.some((detail) => detail.includes("SECRET_TOO_SHORT"))).toBe(true);
|
||||
expect(report.result).toBe("not-ready");
|
||||
expect(doctorExitCode(report)).toBe(1);
|
||||
expect(JSON.stringify(report)).not.toContain(hostileSecret);
|
||||
});
|
||||
|
||||
it("never constructs a migration database or Better Auth merely to check identity configuration", async () => {
|
||||
const services = dependencies();
|
||||
await diagnoseEkklesia(
|
||||
{
|
||||
...options(),
|
||||
identityConfiguration: {
|
||||
baseUrl: "https://identity.example.test",
|
||||
secret: "correct-horse-battery-staple-0123456789",
|
||||
trustedOrigins: ["https://identity.example.test"],
|
||||
},
|
||||
},
|
||||
services,
|
||||
);
|
||||
|
||||
expect(services.createMigrationDatabase).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user