diff --git a/apps/contrail-e2e/package.json b/apps/contrail-e2e/package.json index ed43978..aa17c4f 100644 --- a/apps/contrail-e2e/package.json +++ b/apps/contrail-e2e/package.json @@ -11,6 +11,7 @@ }, "dependencies": { "@atmo-dev/contrail": "workspace:*", + "@atmo-dev/contrail-community": "workspace:*", "pg": "^8.20.0" }, "devDependencies": { diff --git a/apps/contrail-e2e/tests/community-delete.test.ts b/apps/contrail-e2e/tests/community-delete.test.ts index 4e2ffd3..0106c66 100644 --- a/apps/contrail-e2e/tests/community-delete.test.ts +++ b/apps/contrail-e2e/tests/community-delete.test.ts @@ -26,7 +26,6 @@ import { describe, it, expect, beforeAll, afterAll } from "vitest"; import pg from "pg"; import type { Client } from "@atcute/client"; import "@atcute/atproto"; -import { Contrail } from "@atmo-dev/contrail"; import { createHandler } from "@atmo-dev/contrail/server"; import { createPostgresDatabase } from "@atmo-dev/contrail/postgres"; import { config as baseConfig } from "../config"; @@ -34,6 +33,7 @@ import { createTestAccount, createIsolatedSchema, createDevnetResolver, + setupCommunityContrail, createCaller, login, jsonOr, @@ -66,14 +66,10 @@ describe("community.delete e2e (soft-delete + cascade, real DB)", () => { cleanupSchema = iso.cleanup; const db = createPostgresDatabase(pool); - const contrail = new Contrail({ - ...baseConfig, + const contrail = await setupCommunityContrail({ db, - spaces: { - type: SPACE_TYPE, - serviceDid: CONTRAIL_SERVICE_DID, - resolver: createDevnetResolver(), - }, + baseConfig, + spaceType: SPACE_TYPE, community: { serviceDid: CONTRAIL_SERVICE_DID, masterKey: TEST_MASTER_KEY, diff --git a/apps/contrail-e2e/tests/community-invites.test.ts b/apps/contrail-e2e/tests/community-invites.test.ts index e3a5fd0..58b0b31 100644 --- a/apps/contrail-e2e/tests/community-invites.test.ts +++ b/apps/contrail-e2e/tests/community-invites.test.ts @@ -27,7 +27,6 @@ import { describe, it, expect, beforeAll, afterAll } from "vitest"; import pg from "pg"; import type { Client } from "@atcute/client"; import "@atcute/atproto"; -import { Contrail } from "@atmo-dev/contrail"; import { createHandler } from "@atmo-dev/contrail/server"; import { createPostgresDatabase } from "@atmo-dev/contrail/postgres"; import { config as baseConfig } from "../config"; @@ -35,6 +34,7 @@ import { createTestAccount, createIsolatedSchema, createDevnetResolver, + setupCommunityContrail, createCaller, login, jsonOr, @@ -80,14 +80,10 @@ describe("invite e2e (community + user-owned, real JWT)", () => { cleanupSchema = iso.cleanup; const db = createPostgresDatabase(pool); - const contrail = new Contrail({ - ...baseConfig, + const contrail = await setupCommunityContrail({ db, - spaces: { - type: SPACE_TYPE, - serviceDid: CONTRAIL_SERVICE_DID, - resolver: createDevnetResolver(), - }, + baseConfig, + spaceType: SPACE_TYPE, community: { serviceDid: CONTRAIL_SERVICE_DID, masterKey: TEST_MASTER_KEY, diff --git a/apps/contrail-e2e/tests/community-lifecycle.test.ts b/apps/contrail-e2e/tests/community-lifecycle.test.ts index 137991c..7a40f60 100644 --- a/apps/contrail-e2e/tests/community-lifecycle.test.ts +++ b/apps/contrail-e2e/tests/community-lifecycle.test.ts @@ -25,7 +25,6 @@ import { describe, it, expect, beforeAll, afterAll } from "vitest"; import pg from "pg"; import type { Client } from "@atcute/client"; import "@atcute/atproto"; -import { Contrail } from "@atmo-dev/contrail"; import { createHandler } from "@atmo-dev/contrail/server"; import { createPostgresDatabase } from "@atmo-dev/contrail/postgres"; import { config as baseConfig } from "../config"; @@ -33,6 +32,7 @@ import { createTestAccount, createIsolatedSchema, createDevnetResolver, + setupCommunityContrail, createCaller, login, jsonOr, @@ -78,14 +78,10 @@ describe("community lifecycle (mint → grant → list → revoke, + gap probes) cleanupSchema = iso.cleanup; const db = createPostgresDatabase(pool); - const contrail = new Contrail({ - ...baseConfig, + const contrail = await setupCommunityContrail({ db, - spaces: { - type: SPACE_TYPE, - serviceDid: CONTRAIL_SERVICE_DID, - resolver: createDevnetResolver(), - }, + baseConfig, + spaceType: SPACE_TYPE, community: { serviceDid: CONTRAIL_SERVICE_DID, masterKey: TEST_MASTER_KEY, diff --git a/apps/contrail-e2e/tests/community-publishing.test.ts b/apps/contrail-e2e/tests/community-publishing.test.ts index 6087dd7..8a11f89 100644 --- a/apps/contrail-e2e/tests/community-publishing.test.ts +++ b/apps/contrail-e2e/tests/community-publishing.test.ts @@ -22,7 +22,7 @@ import { describe, it, expect, beforeAll, afterAll } from "vitest"; import pg from "pg"; import type { Client } from "@atcute/client"; import "@atcute/atproto"; -import { Contrail, runPersistent } from "@atmo-dev/contrail"; +import { runPersistent } from "@atmo-dev/contrail"; import { createHandler } from "@atmo-dev/contrail/server"; import { createPostgresDatabase } from "@atmo-dev/contrail/postgres"; import { config as baseConfig } from "../config"; @@ -30,6 +30,7 @@ import { createTestAccount, createIsolatedSchema, createDevnetResolver, + setupCommunityContrail, createCaller, createAppPasswordFor, devnetRewriteFetch, @@ -85,14 +86,10 @@ describe("community publishing (proxy → PDS → Jetstream → index)", () => { cleanupSchema = iso.cleanup; const db = createPostgresDatabase(pool); - const contrail = new Contrail({ - ...baseConfig, + const contrail = await setupCommunityContrail({ db, - spaces: { - type: SPACE_TYPE, - serviceDid: CONTRAIL_SERVICE_DID, - resolver: createDevnetResolver(), - }, + baseConfig, + spaceType: SPACE_TYPE, community: { serviceDid: CONTRAIL_SERVICE_DID, masterKey: TEST_MASTER_KEY, diff --git a/apps/contrail-e2e/tests/helpers.ts b/apps/contrail-e2e/tests/helpers.ts index 64f493f..264bf67 100644 --- a/apps/contrail-e2e/tests/helpers.ts +++ b/apps/contrail-e2e/tests/helpers.ts @@ -12,6 +12,9 @@ import { PlcDidDocumentResolver, } from "@atcute/identity-resolver"; import type { Did as AtDid, Nsid } from "@atcute/lexicons"; +import { Contrail, generateAuthoritySigningKey, resolveConfig } from "@atmo-dev/contrail"; +import type { ContrailConfig, Database, SpacesConfig } from "@atmo-dev/contrail"; +import { createCommunityIntegration } from "@atmo-dev/contrail-community"; export type Did = `did:${string}:${string}`; @@ -46,6 +49,61 @@ export function createDevnetResolver() { }); } +/** + * Build a `spaces` config block in the post-PR30 split shape: authority owns + * ACL + credential signing, recordHost owns storage. Tests that previously + * passed the flat `{ type, serviceDid, resolver }` shape now get this — the + * config validator enforces the split, and `community` requires `authority`. + * + * Pass the `type` NSID for the kind of space (e.g. "rsvp.atmo.event.space"). + * A fresh signing key is generated per call so credential issuance works in + * the auth tests without leaking key material across suites. + */ +export async function makeSpacesConfig(type: string): Promise { + return { + authority: { + type, + serviceDid: CONTRAIL_SERVICE_DID, + signing: await generateAuthoritySigningKey(), + resolver: createDevnetResolver(), + }, + recordHost: {}, + }; +} + +/** + * Build a Contrail wired with a community integration. Post-PR30, community + * routes are not registered by passing a `community` config block alone — the + * caller must construct a `CommunityIntegration` from the resolved config and + * pass it as `communityIntegration` to the `Contrail` constructor (the same + * pattern `createApp({ community })` uses in the contrail-community unit + * tests). + * + * `community` is forwarded into the Contrail config so the integration can + * read `masterKey`, `fetch`, etc. through `config.community`. + */ +export async function setupCommunityContrail(opts: { + db: Database; + baseConfig: ContrailConfig; + spaceType: string; + community: Record; +}): Promise { + const fullConfig: ContrailConfig = { + ...opts.baseConfig, + spaces: await makeSpacesConfig(opts.spaceType), + community: opts.community, + }; + const integration = createCommunityIntegration({ + db: opts.db, + config: resolveConfig(fullConfig), + }); + return new Contrail({ + ...fullConfig, + db: opts.db, + communityIntegration: integration, + }); +} + /** * Mint an atproto service-auth JWT via the PDS's getServiceAuth endpoint. * Requires the client to already be authed for a user. Returns the raw JWT diff --git a/apps/contrail-e2e/tests/spaces-auth.test.ts b/apps/contrail-e2e/tests/spaces-auth.test.ts index 7e5124a..a9981fc 100644 --- a/apps/contrail-e2e/tests/spaces-auth.test.ts +++ b/apps/contrail-e2e/tests/spaces-auth.test.ts @@ -21,7 +21,7 @@ import { config as baseConfig } from "../config"; import { createTestAccount, createIsolatedSchema, - createDevnetResolver, + makeSpacesConfig, mintServiceAuthJwt, CONTRAIL_SERVICE_DID, PDS_URL, @@ -51,11 +51,7 @@ describe("spaces auth (devnet PDS JWT → Contrail verifier)", () => { const contrail = new Contrail({ ...baseConfig, db, - spaces: { - type: SPACE_TYPE, - serviceDid: CONTRAIL_SERVICE_DID, - resolver: createDevnetResolver(), - }, + spaces: await makeSpacesConfig(SPACE_TYPE), }); await contrail.init(); handle = createHandler(contrail); diff --git a/apps/contrail-e2e/tests/spaces-firehose-invisibility.test.ts b/apps/contrail-e2e/tests/spaces-firehose-invisibility.test.ts index 07f7827..4d81933 100644 --- a/apps/contrail-e2e/tests/spaces-firehose-invisibility.test.ts +++ b/apps/contrail-e2e/tests/spaces-firehose-invisibility.test.ts @@ -24,7 +24,7 @@ import { config as baseConfig } from "../config"; import { createTestAccount, createIsolatedSchema, - createDevnetResolver, + makeSpacesConfig, mintServiceAuthJwt, CONTRAIL_SERVICE_DID, PDS_URL, @@ -57,11 +57,7 @@ describe("spaces firehose invisibility", () => { const contrail = new Contrail({ ...baseConfig, db, - spaces: { - type: SPACE_TYPE, - serviceDid: CONTRAIL_SERVICE_DID, - resolver: createDevnetResolver(), - }, + spaces: await makeSpacesConfig(SPACE_TYPE), }); await contrail.init(); handle = createHandler(contrail); diff --git a/apps/contrail-e2e/tests/spaces-table-isolation.test.ts b/apps/contrail-e2e/tests/spaces-table-isolation.test.ts index 9a3c8c8..c61aed5 100644 --- a/apps/contrail-e2e/tests/spaces-table-isolation.test.ts +++ b/apps/contrail-e2e/tests/spaces-table-isolation.test.ts @@ -21,7 +21,7 @@ import { config as baseConfig } from "../config"; import { createTestAccount, createIsolatedSchema, - createDevnetResolver, + makeSpacesConfig, mintServiceAuthJwt, CONTRAIL_SERVICE_DID, PDS_URL, @@ -52,11 +52,7 @@ describe("spaces table isolation", () => { const contrail = new Contrail({ ...baseConfig, db, - spaces: { - type: SPACE_TYPE, - serviceDid: CONTRAIL_SERVICE_DID, - resolver: createDevnetResolver(), - }, + spaces: await makeSpacesConfig(SPACE_TYPE), }); await contrail.init(); handle = createHandler(contrail); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2d68ee6..adc192d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -45,6 +45,9 @@ importers: '@atmo-dev/contrail': specifier: workspace:* version: link:../../packages/contrail + '@atmo-dev/contrail-community': + specifier: workspace:* + version: link:../../packages/contrail-community pg: specifier: ^8.20.0 version: 8.20.0