import { describe, expect, it } from "@effect/vitest";import { Effect } from "effect";import { type InStatement } from "@libsql/client"; import { ADMIN_DEFAULT_PAGE_SIZE, ADMIN_MAX_PAGE_SIZE, collectTables, createExecutor, type Executor,} from "./executor";import { StorageError } from "./fuma-runtime";import { createSqliteTestFumaDb, type SqliteTestFumaDb } from "./sqlite-test-db";import { ConnectionName, IntegrationSlug, OAuthClientSlug, ProviderItemId, ProviderKey, Subject, Tenant,} from "./ids";import { definePlugin } from "./plugin";import { resetSubjectTouchCache, touchSubject } from "./subject-registry"; // The platform view: `executor.admin`, an OPT-IN read-only surface that reads// across every subject in the tenant. Written against the real SQLite bring-up// so the tenant-reach policy, the bigint `last_seen_at` round-trip, and the// field allowlist are all live. const TENANT = "t1";const OTHER_TENANT = "t2";const SUBJECT_A = "user_a";const SUBJECT_B = "user_b"; /** Every column on `connection` that could resolve, or help resolve, a * credential. NONE of these may appear on an admin shape — enumerated so a * future column addition has to be argued with this list. */const FORBIDDEN_CONNECTION_FIELDS = [ "item_ids", "itemIds", "refresh_item_id", "refreshItemId", "provider", "provider_state", "providerState", "oauth_token_url", "oauthTokenUrl", "template", "client_secret", "clientSecret", "secret", "token",] as const; /** * The upstream-derived halves of a stored health verdict: the account identity * extracted from the configured `identityField` (typically the user's email AT * the provider), a raw diagnostic that can quote an upstream error body, and a * bounded sample of the real response body. * * These are NOT on the list above, and that is deliberate rather than an * oversight. This layer is the in-process platform view, not a wire shape: * `AdminConnection.lastHealth` is the full `HealthCheckResult`, and the * narrowing to status + checkedAt happens where the response is BUILT, in * `@executor-js/api`'s `admin/reads.ts` → `AdminConnectionHealth`. Listing them * as forbidden top-level connection keys would pass without testing anything, * because they never were top-level keys — they live nested inside * `lastHealth`. That vacuous-green assertion is precisely the failure mode this * comment exists to prevent. * * So the assertion below pins the SEAM instead: this layer DOES carry them, and * anyone who "fixes" the leak here rather than at the projection has moved the * boundary. The absence assertions live in `packages/core/api`'s * `admin-users.test.ts`, against real HTTP responses. */const UPSTREAM_HEALTH_FIELDS = ["identity", "detail", "responseSample"] as const; const withDb = <A, E>(body: (db: SqliteTestFumaDb) => Effect.Effect<A, E>): Effect.Effect<A, E> => Effect.acquireUseRelease( Effect.promise(() => createSqliteTestFumaDb({ tables: collectTables() })), body, (db) => Effect.promise(() => db.close()), ); const insertConnection = ( db: SqliteTestFumaDb, row: { readonly rowId: string; readonly tenant: string; readonly owner: string; readonly subject: string; readonly integration: string; readonly name: string; readonly oauthScope?: string | null; },): Effect.Effect<void> => Effect.promise(async () => { await db.client.execute({ sql: `INSERT INTO connection ( row_id, tenant, owner, subject, integration, name, template, provider, item_ids, refresh_item_id, oauth_scope, last_health, created_at, updated_at ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, args: [ row.rowId, row.tenant, row.owner, row.subject, row.integration, row.name, "oauth2", "memory", // Deliberately secret-bearing: the assertions below prove these never // leave the storage layer. JSON.stringify({ token: `SECRET-item-${row.rowId}` }), `SECRET-refresh-${row.rowId}`, row.oauthScope ?? null, // A full stored verdict, upstream-derived fields included — that is // what a real health check writes. This layer is entitled to read them // back (see UPSTREAM_HEALTH_FIELDS); the API's projection is what keeps // them off the wire. JSON.stringify({ status: "healthy", checkedAt: 1_700_000_000_000, identity: `UPSTREAM-identity-${row.rowId}@provider.test`, detail: `UPSTREAM-detail-${row.rowId}`, responseSample: [{ path: "user.email", value: `UPSTREAM-sample-${row.rowId}` }], }), Date.now(), Date.now(), ], }); }); /** A tenant-scoped `integration` row, inserted raw. Needed because * `integrations.remove` short-circuits on an absent slug — without a real row * the call returns success having touched no storage, which would make a * read-only assertion vacuous. */const insertIntegration = (db: SqliteTestFumaDb, slug: string): Effect.Effect<void> => Effect.promise(async () => { await db.client.execute({ sql: `INSERT INTO integration ( row_id, tenant, slug, plugin_id, name, description, config, can_remove, can_refresh, created_at, updated_at ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, args: [ `i-${slug}`, TENANT, slug, "demo", slug, null, JSON.stringify({}), 1, 0, Date.now(), Date.now(), ], }); }); /** Seed two users and an org connection under `t1`, plus an untouchable other * tenant. Subjects go in through `touchSubject` (the only legitimate writer); * connections go in raw, because no single bound executor could have written * another subject's rows. */const seed = (db: SqliteTestFumaDb): Effect.Effect<void> => Effect.gen(function* () { // `touchSubject` keeps a process-local memory of principals it already // filed, so a second seed against a FRESH database would be skipped as a // repeat sighting and leave the table empty. Each seed is a new world. resetSubjectTouchCache(); yield* touchSubject(db.db, { tenant: TENANT, externalId: SUBJECT_A }); yield* touchSubject(db.db, { tenant: TENANT, externalId: SUBJECT_B }); yield* touchSubject(db.db, { tenant: OTHER_TENANT, externalId: "user_elsewhere" }); yield* insertConnection(db, { rowId: "c-a1", tenant: TENANT, owner: "user", subject: SUBJECT_A, integration: "github", name: "personal", oauthScope: "repo read:user", }); yield* insertConnection(db, { rowId: "c-a2", tenant: TENANT, owner: "user", subject: SUBJECT_A, integration: "linear", name: "work", }); yield* insertConnection(db, { rowId: "c-b1", tenant: TENANT, owner: "user", subject: SUBJECT_B, integration: "github", name: "b-personal", oauthScope: "repo", }); yield* insertConnection(db, { rowId: "c-org", tenant: TENANT, owner: "org", subject: "", integration: "stripe", name: "shared", }); yield* insertConnection(db, { rowId: "c-other", tenant: OTHER_TENANT, owner: "user", subject: SUBJECT_A, integration: "github", name: "other-tenant", }); }); /** * A plugin contributing one writable credential provider. * * `oauth.createClient` stores the client secret out-of-band and fails BEFORE * touching storage when no writable provider is registered. Without this, the * read-only assertion below would pass on the wrong error and prove nothing — * so the provider is here to make the write actually reach the owner policy. */const providerPlugin = definePlugin(() => { const store = new Map<string, string>(); return { id: "memory-provider" as const, storage: () => ({}), credentialProviders: [ { key: ProviderKey.make("memory"), writable: true, get: (id: ProviderItemId) => Effect.sync(() => store.get(String(id)) ?? null), set: (id: ProviderItemId, value: string) => Effect.sync(() => void store.set(String(id), value)), delete: (id: ProviderItemId) => Effect.sync(() => void store.delete(String(id))), }, ], };})(); const makePlatformExecutor = ( db: SqliteTestFumaDb, options?: { readonly platformView?: boolean; readonly subject?: string | null },): Effect.Effect<Executor, never> => createExecutor({ tenant: Tenant.make(TENANT), ...(options?.subject === null ? {} : { subject: Subject.make(options?.subject ?? SUBJECT_A) }), db: db.db, plugins: [providerPlugin], onElicitation: "accept-all", ...(options?.platformView === false ? {} : { platformView: true }), }).pipe(Effect.orDie); const requireAdmin = (executor: Executor) => { const admin = executor.admin; if (!admin) return Effect.die("expected the platform view to be enabled"); return Effect.succeed(admin);}; describe("platform view — admin.listSubjects", () => { it.effect("lists every subject in the tenant and no other tenant's", () => withDb((db) => Effect.gen(function* () { yield* seed(db); const executor = yield* makePlatformExecutor(db); const admin = yield* requireAdmin(executor); const subjects = yield* admin.listSubjects(); // `user_elsewhere` lives under t2 — invisible at any reach. expect(subjects.map((entry) => entry.externalId).sort()).toEqual([SUBJECT_A, SUBJECT_B]); }), ), ); it.effect("returns created_at and the bigint last_seen_at through the ORM", () => withDb((db) => Effect.gen(function* () { const before = Date.now(); yield* seed(db); const executor = yield* makePlatformExecutor(db); const admin = yield* requireAdmin(executor); const subjects = yield* admin.listSubjects(); const entry = subjects.find((row) => row.externalId === SUBJECT_A); expect(entry?.createdAt).toBeInstanceOf(Date); // A raw SQL read would hand back an unusable blob here. expect(typeof entry?.lastSeenAt).toBe("number"); expect(entry?.lastSeenAt ?? 0).toBeGreaterThanOrEqual(before); expect(entry?.status).toBeNull(); }), ), ); it.effect("pages with a stable order", () => withDb((db) => Effect.gen(function* () { yield* seed(db); const executor = yield* makePlatformExecutor(db); const admin = yield* requireAdmin(executor); const all = yield* admin.listSubjects(); const first = yield* admin.listSubjects({ limit: 1 }); const second = yield* admin.listSubjects({ limit: 1, offset: 1 }); expect(all).toHaveLength(2); expect(first.map((entry) => entry.externalId)).toEqual([all[0]?.externalId]); expect(second.map((entry) => entry.externalId)).toEqual([all[1]?.externalId]); }), ), ); // Drizzle's SQLite dialect emits OFFSET only alongside LIMIT, and SQLite // rejects a bare OFFSET — so forwarding the two independently made // `{ offset }` a SQL syntax error on every SQLite host. The default limit is // what makes an offset-only page a legal query at all. it.effect("accepts an offset with no limit", () => withDb((db) => Effect.gen(function* () { yield* seed(db); const admin = yield* requireAdmin(yield* makePlatformExecutor(db)); const all = yield* admin.listSubjects(); const skipped = yield* admin.listSubjects({ offset: 1 }); expect(skipped.map((entry) => entry.externalId)).toEqual([all[1]?.externalId]); // Past the end is an empty page, not an error. expect(yield* admin.listSubjects({ offset: 50 })).toEqual([]); expect(yield* admin.listSubjectsWithConnections({ offset: 1 })).toHaveLength(1); }), ), ); // A fraction is a 400 at the HTTP contract, but the SDK is a public entry // point of its own: a fractional limit reaching the driver is a `datatype // mismatch` failure, so it is floored here rather than forwarded. it.effect("floors a fractional limit and offset instead of failing the query", () => withDb((db) => Effect.gen(function* () { yield* seed(db); const admin = yield* requireAdmin(yield* makePlatformExecutor(db)); const all = yield* admin.listSubjects(); expect(yield* admin.listSubjects({ limit: 1.5 })).toEqual([all[0]]); expect(yield* admin.listSubjects({ offset: 1.9 })).toEqual([all[1]]); }), ), ); // The no-args call is the one an API consumer writes by default, and // `listSubjectsWithConnections` turns each returned row into its own // sequential connection query. Unbounded, that is the whole tenant inside one // request. it.effect("bounds an unpaged call to the default page size, and clamps past the maximum", () => withDb((db) => Effect.gen(function* () { // One more subject than a default page holds, so "no arguments" and // "everything" are distinguishable. for (let index = 0; index < ADMIN_DEFAULT_PAGE_SIZE + 5; index += 1) { yield* touchSubject(db.db, { tenant: TENANT, // Zero-padded: `external_id` breaks `created_at` ties, and these // rows are written inside the same millisecond. externalId: `user_${String(index).padStart(4, "0")}`, }); } const admin = yield* requireAdmin(yield* makePlatformExecutor(db)); expect(yield* admin.listSubjects()).toHaveLength(ADMIN_DEFAULT_PAGE_SIZE); expect(yield* admin.listSubjectsWithConnections()).toHaveLength(ADMIN_DEFAULT_PAGE_SIZE); // A caller may ask for more, up to the ceiling — and no further. expect(yield* admin.listSubjects({ limit: ADMIN_MAX_PAGE_SIZE * 10 })).toHaveLength( ADMIN_DEFAULT_PAGE_SIZE + 5, ); }), ), );}); // ---------------------------------------------------------------------------// The platform view is read-only across EVERY surface, not just `admin`.//// A platform executor is subject-less but still bound to the tenant's ORG// partition, so before `writes: "denied"` its ordinary product surfaces formed// an unguarded pure-org executor: it could create, update and delete every// `owner: "org"` row in the tenant through `connections`, `policies`,// `integrations` and `oauth`, while only the `admin` handle was actually// guarded. These pin that the guarantee now covers the whole executor.// --------------------------------------------------------------------------- /** * The owner policy refuses a write by failing the storage effect. `Effect.flip` * makes a SUCCEEDING write a test failure outright rather than something to * assert on afterwards. * * The message is checked too, not just the failure: several of these surfaces * can fail for unrelated reasons BEFORE reaching storage (an absent row, a * missing credential provider), and such a failure would let the assertion pass * without the policy ever having been consulted. */const expectWriteRefused = <A, E extends { readonly _tag: string }>( effect: Effect.Effect<A, E | StorageError>,) => // The surfaces under test fail with different unions (StorageFailure, // ConnectionNotFoundError, …). The refusal this pins is always a // StorageError, so the effect is widened for the catch; `orDie` below still // turns every OTHER tag into a test failure, and a write that SUCCEEDS dies // rather than reaching an assertion — so the hole can never pass silently. (effect as Effect.Effect<A, StorageError>).pipe( Effect.flatMap(() => Effect.die("expected the platform view to refuse this write")), Effect.catchTag("StorageError", (error: StorageError) => { expect(error.message).toContain("read-only"); return Effect.void; }), Effect.orDie, ); describe("platform view — read-only across every surface", () => { it.effect("refuses org-row writes through policies and oauth", () => withDb((db) => Effect.gen(function* () { yield* seed(db); const executor = yield* makePlatformExecutor(db, { subject: null }); yield* expectWriteRefused( executor.policies.create({ owner: "org", pattern: "tools.*", action: "block" }), ); yield* expectWriteRefused( executor.oauth.createClient({ owner: "org", slug: OAuthClientSlug.make("intruder"), authorizationUrl: "https://acme.test/authorize", tokenUrl: "https://acme.test/token", grant: "authorization_code", clientId: "intruder-id", clientSecret: "intruder-secret", }), ); // Nothing landed. expect(yield* executor.policies.list()).toEqual([]); expect(yield* executor.oauth.listClients()).toEqual([]); }), ), ); // A DELETE is the sharpest case: it carries no values to check against, so // the reach/writes guard is the only thing between this executor and the // tenant's org rows. it.effect("refuses to delete the tenant's org rows", () => withDb((db) => Effect.gen(function* () { yield* seed(db); // A real `integration` row: `integrations.remove` returns success // without touching storage when the slug is absent, so asserting // against a missing row would prove nothing. yield* insertIntegration(db, "stripe"); const executor = yield* makePlatformExecutor(db, { subject: null }); yield* expectWriteRefused( executor.connections.remove({ owner: "org", integration: IntegrationSlug.make("stripe"), name: ConnectionName.make("shared"), }), ); yield* expectWriteRefused( executor.oauth.removeClient("org", OAuthClientSlug.make("anything")), ); yield* expectWriteRefused(executor.integrations.remove(IntegrationSlug.make("stripe"))); // Every row survived. const admin = yield* requireAdmin(executor); expect(yield* admin.listSubjects()).toHaveLength(2); const connections = yield* Effect.promise(() => db.client.execute({ sql: `SELECT name FROM connection WHERE owner = 'org'`, args: [] }), ); expect(connections.rows).toHaveLength(1); const integrations = yield* Effect.promise(() => db.client.execute({ sql: `SELECT slug FROM integration`, args: [] }), ); expect(integrations.rows).toHaveLength(1); }), ), ); // Read-only is the WRITE axis only. The ordinary surfaces keep BOUND reach on // purpose: widening them would hand every subject's connection row — // credential item ids included — to a surface that only ever needed the admin // projection. it.effect("does not widen the ordinary surfaces' reads to other subjects", () =>Lines 1–500 of 901. Load more
import { describe, expect, it } from "@effect/vitest"; import { Effect } from "effect"; import { type InStatement } from "@libsql/client"; import { ADMIN_DEFAULT_PAGE_SIZE, ADMIN_MAX_PAGE_SIZE, collectTables, createExecutor, type Executor, } from "./executor"; import { StorageError } from "./fuma-runtime"; import { createSqliteTestFumaDb, type SqliteTestFumaDb } from "./sqlite-test-db"; import { ConnectionName, IntegrationSlug, OAuthClientSlug, ProviderItemId, ProviderKey, Subject, Tenant, } from "./ids"; import { definePlugin } from "./plugin"; import { resetSubjectTouchCache, touchSubject } from "./subject-registry"; // The platform view: `executor.admin`, an OPT-IN read-only surface that reads // across every subject in the tenant. Written against the real SQLite bring-up // so the tenant-reach policy, the bigint `last_seen_at` round-trip, and the // field allowlist are all live. const TENANT = "t1"; const OTHER_TENANT = "t2"; const SUBJECT_A = "user_a"; const SUBJECT_B = "user_b"; /** Every column on `connection` that could resolve, or help resolve, a * credential. NONE of these may appear on an admin shape — enumerated so a * future column addition has to be argued with this list. */ const FORBIDDEN_CONNECTION_FIELDS = [ "item_ids", "itemIds", "refresh_item_id", "refreshItemId", "provider", "provider_state", "providerState", "oauth_token_url", "oauthTokenUrl", "template", "client_secret", "clientSecret", "secret", "token", ] as const; /** * The upstream-derived halves of a stored health verdict: the account identity * extracted from the configured `identityField` (typically the user's email AT * the provider), a raw diagnostic that can quote an upstream error body, and a * bounded sample of the real response body. * * These are NOT on the list above, and that is deliberate rather than an * oversight. This layer is the in-process platform view, not a wire shape: * `AdminConnection.lastHealth` is the full `HealthCheckResult`, and the * narrowing to status + checkedAt happens where the response is BUILT, in * `@executor-js/api`'s `admin/reads.ts` → `AdminConnectionHealth`. Listing them * as forbidden top-level connection keys would pass without testing anything, * because they never were top-level keys — they live nested inside * `lastHealth`. That vacuous-green assertion is precisely the failure mode this * comment exists to prevent. * * So the assertion below pins the SEAM instead: this layer DOES carry them, and * anyone who "fixes" the leak here rather than at the projection has moved the * boundary. The absence assertions live in `packages/core/api`'s * `admin-users.test.ts`, against real HTTP responses. */ const UPSTREAM_HEALTH_FIELDS = ["identity", "detail", "responseSample"] as const; const withDb = <A, E>(body: (db: SqliteTestFumaDb) => Effect.Effect<A, E>): Effect.Effect<A, E> => Effect.acquireUseRelease( Effect.promise(() => createSqliteTestFumaDb({ tables: collectTables() })), body, (db) => Effect.promise(() => db.close()), ); const insertConnection = ( db: SqliteTestFumaDb, row: { readonly rowId: string; readonly tenant: string; readonly owner: string; readonly subject: string; readonly integration: string; readonly name: string; readonly oauthScope?: string | null; }, ): Effect.Effect<void> => Effect.promise(async () => { await db.client.execute({ sql: `INSERT INTO connection ( row_id, tenant, owner, subject, integration, name, template, provider, item_ids, refresh_item_id, oauth_scope, last_health, created_at, updated_at ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, args: [ row.rowId, row.tenant, row.owner, row.subject, row.integration, row.name, "oauth2", "memory", // Deliberately secret-bearing: the assertions below prove these never // leave the storage layer. JSON.stringify({ token: `SECRET-item-${row.rowId}` }), `SECRET-refresh-${row.rowId}`, row.oauthScope ?? null, // A full stored verdict, upstream-derived fields included — that is // what a real health check writes. This layer is entitled to read them // back (see UPSTREAM_HEALTH_FIELDS); the API's projection is what keeps // them off the wire. JSON.stringify({ status: "healthy", checkedAt: 1_700_000_000_000, identity: `UPSTREAM-identity-${row.rowId}@provider.test`, detail: `UPSTREAM-detail-${row.rowId}`, responseSample: [{ path: "user.email", value: `UPSTREAM-sample-${row.rowId}` }], }), Date.now(), Date.now(), ], }); }); /** A tenant-scoped `integration` row, inserted raw. Needed because * `integrations.remove` short-circuits on an absent slug — without a real row * the call returns success having touched no storage, which would make a * read-only assertion vacuous. */ const insertIntegration = (db: SqliteTestFumaDb, slug: string): Effect.Effect<void> => Effect.promise(async () => { await db.client.execute({ sql: `INSERT INTO integration ( row_id, tenant, slug, plugin_id, name, description, config, can_remove, can_refresh, created_at, updated_at ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, args: [ `i-${slug}`, TENANT, slug, "demo", slug, null, JSON.stringify({}), 1, 0, Date.now(), Date.now(), ], }); }); /** Seed two users and an org connection under `t1`, plus an untouchable other * tenant. Subjects go in through `touchSubject` (the only legitimate writer); * connections go in raw, because no single bound executor could have written * another subject's rows. */ const seed = (db: SqliteTestFumaDb): Effect.Effect<void> => Effect.gen(function* () { // `touchSubject` keeps a process-local memory of principals it already // filed, so a second seed against a FRESH database would be skipped as a // repeat sighting and leave the table empty. Each seed is a new world. resetSubjectTouchCache(); yield* touchSubject(db.db, { tenant: TENANT, externalId: SUBJECT_A }); yield* touchSubject(db.db, { tenant: TENANT, externalId: SUBJECT_B }); yield* touchSubject(db.db, { tenant: OTHER_TENANT, externalId: "user_elsewhere" }); yield* insertConnection(db, { rowId: "c-a1", tenant: TENANT, owner: "user", subject: SUBJECT_A, integration: "github", name: "personal", oauthScope: "repo read:user", }); yield* insertConnection(db, { rowId: "c-a2", tenant: TENANT, owner: "user", subject: SUBJECT_A, integration: "linear", name: "work", }); yield* insertConnection(db, { rowId: "c-b1", tenant: TENANT, owner: "user", subject: SUBJECT_B, integration: "github", name: "b-personal", oauthScope: "repo", }); yield* insertConnection(db, { rowId: "c-org", tenant: TENANT, owner: "org", subject: "", integration: "stripe", name: "shared", }); yield* insertConnection(db, { rowId: "c-other", tenant: OTHER_TENANT, owner: "user", subject: SUBJECT_A, integration: "github", name: "other-tenant", }); }); /** * A plugin contributing one writable credential provider. * * `oauth.createClient` stores the client secret out-of-band and fails BEFORE * touching storage when no writable provider is registered. Without this, the * read-only assertion below would pass on the wrong error and prove nothing — * so the provider is here to make the write actually reach the owner policy. */ const providerPlugin = definePlugin(() => { const store = new Map<string, string>(); return { id: "memory-provider" as const, storage: () => ({}), credentialProviders: [ { key: ProviderKey.make("memory"), writable: true, get: (id: ProviderItemId) => Effect.sync(() => store.get(String(id)) ?? null), set: (id: ProviderItemId, value: string) => Effect.sync(() => void store.set(String(id), value)), delete: (id: ProviderItemId) => Effect.sync(() => void store.delete(String(id))), }, ], }; })(); const makePlatformExecutor = ( db: SqliteTestFumaDb, options?: { readonly platformView?: boolean; readonly subject?: string | null }, ): Effect.Effect<Executor, never> => createExecutor({ tenant: Tenant.make(TENANT), ...(options?.subject === null ? {} : { subject: Subject.make(options?.subject ?? SUBJECT_A) }), db: db.db, plugins: [providerPlugin], onElicitation: "accept-all", ...(options?.platformView === false ? {} : { platformView: true }), }).pipe(Effect.orDie); const requireAdmin = (executor: Executor) => { const admin = executor.admin; if (!admin) return Effect.die("expected the platform view to be enabled"); return Effect.succeed(admin); }; describe("platform view — admin.listSubjects", () => { it.effect("lists every subject in the tenant and no other tenant's", () => withDb((db) => Effect.gen(function* () { yield* seed(db); const executor = yield* makePlatformExecutor(db); const admin = yield* requireAdmin(executor); const subjects = yield* admin.listSubjects(); // `user_elsewhere` lives under t2 — invisible at any reach. expect(subjects.map((entry) => entry.externalId).sort()).toEqual([SUBJECT_A, SUBJECT_B]); }), ), ); it.effect("returns created_at and the bigint last_seen_at through the ORM", () => withDb((db) => Effect.gen(function* () { const before = Date.now(); yield* seed(db); const executor = yield* makePlatformExecutor(db); const admin = yield* requireAdmin(executor); const subjects = yield* admin.listSubjects(); const entry = subjects.find((row) => row.externalId === SUBJECT_A); expect(entry?.createdAt).toBeInstanceOf(Date); // A raw SQL read would hand back an unusable blob here. expect(typeof entry?.lastSeenAt).toBe("number"); expect(entry?.lastSeenAt ?? 0).toBeGreaterThanOrEqual(before); expect(entry?.status).toBeNull(); }), ), ); it.effect("pages with a stable order", () => withDb((db) => Effect.gen(function* () { yield* seed(db); const executor = yield* makePlatformExecutor(db); const admin = yield* requireAdmin(executor); const all = yield* admin.listSubjects(); const first = yield* admin.listSubjects({ limit: 1 }); const second = yield* admin.listSubjects({ limit: 1, offset: 1 }); expect(all).toHaveLength(2); expect(first.map((entry) => entry.externalId)).toEqual([all[0]?.externalId]); expect(second.map((entry) => entry.externalId)).toEqual([all[1]?.externalId]); }), ), ); // Drizzle's SQLite dialect emits OFFSET only alongside LIMIT, and SQLite // rejects a bare OFFSET — so forwarding the two independently made // `{ offset }` a SQL syntax error on every SQLite host. The default limit is // what makes an offset-only page a legal query at all. it.effect("accepts an offset with no limit", () => withDb((db) => Effect.gen(function* () { yield* seed(db); const admin = yield* requireAdmin(yield* makePlatformExecutor(db)); const all = yield* admin.listSubjects(); const skipped = yield* admin.listSubjects({ offset: 1 }); expect(skipped.map((entry) => entry.externalId)).toEqual([all[1]?.externalId]); // Past the end is an empty page, not an error. expect(yield* admin.listSubjects({ offset: 50 })).toEqual([]); expect(yield* admin.listSubjectsWithConnections({ offset: 1 })).toHaveLength(1); }), ), ); // A fraction is a 400 at the HTTP contract, but the SDK is a public entry // point of its own: a fractional limit reaching the driver is a `datatype // mismatch` failure, so it is floored here rather than forwarded. it.effect("floors a fractional limit and offset instead of failing the query", () => withDb((db) => Effect.gen(function* () { yield* seed(db); const admin = yield* requireAdmin(yield* makePlatformExecutor(db)); const all = yield* admin.listSubjects(); expect(yield* admin.listSubjects({ limit: 1.5 })).toEqual([all[0]]); expect(yield* admin.listSubjects({ offset: 1.9 })).toEqual([all[1]]); }), ), ); // The no-args call is the one an API consumer writes by default, and // `listSubjectsWithConnections` turns each returned row into its own // sequential connection query. Unbounded, that is the whole tenant inside one // request. it.effect("bounds an unpaged call to the default page size, and clamps past the maximum", () => withDb((db) => Effect.gen(function* () { // One more subject than a default page holds, so "no arguments" and // "everything" are distinguishable. for (let index = 0; index < ADMIN_DEFAULT_PAGE_SIZE + 5; index += 1) { yield* touchSubject(db.db, { tenant: TENANT, // Zero-padded: `external_id` breaks `created_at` ties, and these // rows are written inside the same millisecond. externalId: `user_${String(index).padStart(4, "0")}`, }); } const admin = yield* requireAdmin(yield* makePlatformExecutor(db)); expect(yield* admin.listSubjects()).toHaveLength(ADMIN_DEFAULT_PAGE_SIZE); expect(yield* admin.listSubjectsWithConnections()).toHaveLength(ADMIN_DEFAULT_PAGE_SIZE); // A caller may ask for more, up to the ceiling — and no further. expect(yield* admin.listSubjects({ limit: ADMIN_MAX_PAGE_SIZE * 10 })).toHaveLength( ADMIN_DEFAULT_PAGE_SIZE + 5, ); }), ), ); }); // --------------------------------------------------------------------------- // The platform view is read-only across EVERY surface, not just `admin`. // // A platform executor is subject-less but still bound to the tenant's ORG // partition, so before `writes: "denied"` its ordinary product surfaces formed // an unguarded pure-org executor: it could create, update and delete every // `owner: "org"` row in the tenant through `connections`, `policies`, // `integrations` and `oauth`, while only the `admin` handle was actually // guarded. These pin that the guarantee now covers the whole executor. // --------------------------------------------------------------------------- /** * The owner policy refuses a write by failing the storage effect. `Effect.flip` * makes a SUCCEEDING write a test failure outright rather than something to * assert on afterwards. * * The message is checked too, not just the failure: several of these surfaces * can fail for unrelated reasons BEFORE reaching storage (an absent row, a * missing credential provider), and such a failure would let the assertion pass * without the policy ever having been consulted. */ const expectWriteRefused = <A, E extends { readonly _tag: string }>( effect: Effect.Effect<A, E | StorageError>, ) => // The surfaces under test fail with different unions (StorageFailure, // ConnectionNotFoundError, …). The refusal this pins is always a // StorageError, so the effect is widened for the catch; `orDie` below still // turns every OTHER tag into a test failure, and a write that SUCCEEDS dies // rather than reaching an assertion — so the hole can never pass silently. (effect as Effect.Effect<A, StorageError>).pipe( Effect.flatMap(() => Effect.die("expected the platform view to refuse this write")), Effect.catchTag("StorageError", (error: StorageError) => { expect(error.message).toContain("read-only"); return Effect.void; }), Effect.orDie, ); describe("platform view — read-only across every surface", () => { it.effect("refuses org-row writes through policies and oauth", () => withDb((db) => Effect.gen(function* () { yield* seed(db); const executor = yield* makePlatformExecutor(db, { subject: null }); yield* expectWriteRefused( executor.policies.create({ owner: "org", pattern: "tools.*", action: "block" }), ); yield* expectWriteRefused( executor.oauth.createClient({ owner: "org", slug: OAuthClientSlug.make("intruder"), authorizationUrl: "https://acme.test/authorize", tokenUrl: "https://acme.test/token", grant: "authorization_code", clientId: "intruder-id", clientSecret: "intruder-secret", }), ); // Nothing landed. expect(yield* executor.policies.list()).toEqual([]); expect(yield* executor.oauth.listClients()).toEqual([]); }), ), ); // A DELETE is the sharpest case: it carries no values to check against, so // the reach/writes guard is the only thing between this executor and the // tenant's org rows. it.effect("refuses to delete the tenant's org rows", () => withDb((db) => Effect.gen(function* () { yield* seed(db); // A real `integration` row: `integrations.remove` returns success // without touching storage when the slug is absent, so asserting // against a missing row would prove nothing. yield* insertIntegration(db, "stripe"); const executor = yield* makePlatformExecutor(db, { subject: null }); yield* expectWriteRefused( executor.connections.remove({ owner: "org", integration: IntegrationSlug.make("stripe"), name: ConnectionName.make("shared"), }), ); yield* expectWriteRefused( executor.oauth.removeClient("org", OAuthClientSlug.make("anything")), ); yield* expectWriteRefused(executor.integrations.remove(IntegrationSlug.make("stripe"))); // Every row survived. const admin = yield* requireAdmin(executor); expect(yield* admin.listSubjects()).toHaveLength(2); const connections = yield* Effect.promise(() => db.client.execute({ sql: `SELECT name FROM connection WHERE owner = 'org'`, args: [] }), ); expect(connections.rows).toHaveLength(1); const integrations = yield* Effect.promise(() => db.client.execute({ sql: `SELECT slug FROM integration`, args: [] }), ); expect(integrations.rows).toHaveLength(1); }), ), ); // Read-only is the WRITE axis only. The ordinary surfaces keep BOUND reach on // purpose: widening them would hand every subject's connection row — // credential item ids included — to a surface that only ever needed the admin // projection. it.effect("does not widen the ordinary surfaces' reads to other subjects", () =>