import { beforeEach, describe, expect, it } from "@effect/vitest"; import { Effect } from "effect"; import { withQueryContext } from "@executor-js/fumadb/query"; import { collectTables } from "./executor"; import { AuthTemplateSlug, ConnectionName, IntegrationSlug, ToolName } from "./ids"; import type { ExecutorOwnerPolicyContext } from "./owner-policy"; import { definePlugin } from "./plugin"; import { createSqliteTestFumaDb, type SqliteTestFumaDb } from "./sqlite-test-db"; import { resetSubjectTouchCache, touchSubject } from "./subject-registry"; import { makeTestWorkspaceHarness, memoryCredentialsPlugin } from "./test-config"; // `touchSubject` is the only writer of the `subject` table. Written against the // real SQLite bring-up (the same statements local/self-host/D1 boot with) so // the tenant policy, the unique index, and the bigint round-trip are all live. const TENANT = "t1"; const OTHER_TENANT = "t2"; const THROTTLE_MS = 60_000; const withDb = (body: (db: SqliteTestFumaDb) => Effect.Effect): Effect.Effect => Effect.acquireUseRelease( Effect.promise(() => createSqliteTestFumaDb({ tables: collectTables() })), body, (db) => Effect.promise(() => db.close()), ); // Read the way PR 1.3's readers will: through a tenant-bound query context. // `last_seen_at` is a bigint column stored as a SQLite blob, so a raw SQL read // would hand back an unusable buffer — the ORM owns the round-trip. const scopedTo = (db: SqliteTestFumaDb, tenant: string) => withQueryContext(db.db, { tenant, subject: null, } satisfies ExecutorOwnerPolicyContext); const storedSubjects = ( db: SqliteTestFumaDb, tenant = TENANT, ): Effect.Effect => Effect.promise(async () => { const rows = await scopedTo(db, tenant).findMany("subject", { orderBy: ["external_id", "asc"], }); return rows.map((row) => ({ externalId: String(row.external_id), lastSeenMs: row.last_seen_at == null ? null : Number(row.last_seen_at), })); }); // `touchSubject` remembers, per process, which principals it already filed // inside the throttle window. Every case below reuses the same tenant/principal // against a FRESH database, so that memory has to be dropped between them or a // later case would skip the query its assertion depends on. beforeEach(() => { resetSubjectTouchCache(); }); describe("touchSubject", () => { it.effect("creates the row on first sight", () => withDb((db) => Effect.gen(function* () { const before = Date.now(); yield* touchSubject(db.db, { tenant: TENANT, externalId: "user_a" }); const rows = yield* storedSubjects(db); expect(rows).toHaveLength(1); expect(rows[0]?.externalId).toBe("user_a"); // A first sighting IS a sighting: `last_seen_at` is stamped, not left // null for the next request to fill in. expect(rows[0]?.lastSeenMs).toBeGreaterThanOrEqual(before); }), ), ); it.effect("leaves last_seen_at alone while the sighting is inside the throttle", () => withDb((db) => Effect.gen(function* () { yield* touchSubject(db.db, { tenant: TENANT, externalId: "user_a", lastSeenThrottleMs: THROTTLE_MS, }); const [first] = yield* storedSubjects(db); // The hot path: N requests in quick succession must cost zero writes, // so the persisted stamp is unchanged afterwards. yield* Effect.forEach([1, 2, 3], () => touchSubject(db.db, { tenant: TENANT, externalId: "user_a", lastSeenThrottleMs: THROTTLE_MS, }), ); const rows = yield* storedSubjects(db); expect(rows).toHaveLength(1); expect(rows[0]?.lastSeenMs).toBe(first?.lastSeenMs); }), ), ); it.effect("bumps last_seen_at once the sighting falls outside the throttle", () => withDb((db) => Effect.gen(function* () { yield* touchSubject(db.db, { tenant: TENANT, externalId: "user_a" }); const [first] = yield* storedSubjects(db); // Age the row rather than sleeping through the interval. A throttle of // zero would pass even if the staleness comparison were inverted; a row // aged well past the interval only passes if it reads the right way. const stale = (first?.lastSeenMs ?? 0) - 10 * THROTTLE_MS; yield* Effect.promise(() => scopedTo(db, TENANT).updateMany("subject", { where: (b) => b("external_id", "=", "user_a"), set: { last_seen_at: BigInt(stale) }, }), ); // Backdating the row stands in for elapsed time, and elapsed time ages // the process-local sighting memory too — otherwise this would assert // against a clock the memory never saw. Expiring it is what the passage // of time does; the assertion below is unchanged. resetSubjectTouchCache(); yield* touchSubject(db.db, { tenant: TENANT, externalId: "user_a", lastSeenThrottleMs: THROTTLE_MS, }); const rows = yield* storedSubjects(db); expect(rows).toHaveLength(1); expect(rows[0]?.lastSeenMs).toBeGreaterThan(stale); }), ), ); it.effect("issues no query at all for a repeat sighting inside the throttle", () => withDb((db) => Effect.gen(function* () { // THE regression this guards: the request seam runs `touchSubject` on // every HTTP request and MCP session, so a sighting that still costs an // indexed read per request adds a round-trip to every request in the // product. Dropping the table after the first sighting makes any // further query fail loudly — and `touchSubject` swallows storage // failures, so a surviving query would be invisible in the row state. // Counting statements is the only way to see it. yield* touchSubject(db.db, { tenant: TENANT, externalId: "user_a", lastSeenThrottleMs: THROTTLE_MS, }); let queries = 0; const client = db.client as { execute: (...args: never[]) => unknown }; const execute = client.execute.bind(client) as (...args: never[]) => unknown; client.execute = (...args: never[]) => { queries += 1; return execute(...args); }; yield* Effect.forEach([1, 2, 3], () => touchSubject(db.db, { tenant: TENANT, externalId: "user_a", lastSeenThrottleMs: THROTTLE_MS, }), ); client.execute = execute as typeof client.execute; expect(queries).toBe(0); }), ), ); it.effect("re-reads once the remembered sighting ages past the throttle", () => withDb((db) => Effect.gen(function* () { // The memory must expire with the throttle, not pin a principal as // "recently seen" forever: `last_seen_at` still has to advance for a // principal who keeps calling across windows. yield* touchSubject(db.db, { tenant: TENANT, externalId: "user_a", lastSeenThrottleMs: THROTTLE_MS, }); const [first] = yield* storedSubjects(db); // A zero throttle makes every remembered sighting instantly stale, // which is what a caller crossing the window observes. yield* touchSubject(db.db, { tenant: TENANT, externalId: "user_a", lastSeenThrottleMs: 0, }); const rows = yield* storedSubjects(db); expect(rows).toHaveLength(1); expect(rows[0]?.lastSeenMs).toBeGreaterThanOrEqual(first?.lastSeenMs ?? 0); }), ), ); it.effect("remembers a first sighting per tenant, not per principal", () => withDb((db) => Effect.gen(function* () { // One account acting in two orgs is two rows. A memory keyed on the // principal alone would file the first tenant and skip the second, // losing the row the other tenant's admin view depends on. yield* touchSubject(db.db, { tenant: TENANT, externalId: "user_a", lastSeenThrottleMs: THROTTLE_MS, }); yield* touchSubject(db.db, { tenant: OTHER_TENANT, externalId: "user_a", lastSeenThrottleMs: THROTTLE_MS, }); expect((yield* storedSubjects(db, OTHER_TENANT)).map((row) => row.externalId)).toEqual([ "user_a", ]); }), ), ); it.effect("does not remember a sighting that failed to persist", () => withDb((db) => Effect.gen(function* () { // A storage failure is swallowed so the request survives. It must not // also be recorded as a successful sighting, or the principal would // stay unfiled for a whole throttle window after the fault cleared. yield* Effect.promise(() => db.client.execute("DROP TABLE subject")); yield* touchSubject(db.db, { tenant: TENANT, externalId: "user_a", lastSeenThrottleMs: THROTTLE_MS, }); yield* Effect.promise(() => db.client.execute( "CREATE TABLE subject (row_id text PRIMARY KEY NOT NULL, tenant text NOT NULL, external_id text NOT NULL, created_at integer NOT NULL, last_seen_at blob, status text)", ), ); yield* touchSubject(db.db, { tenant: TENANT, externalId: "user_a", lastSeenThrottleMs: THROTTLE_MS, }); expect((yield* storedSubjects(db)).map((row) => row.externalId)).toEqual(["user_a"]); }), ), ); it.effect("records nothing for a pure-org executor", () => withDb((db) => Effect.gen(function* () { yield* touchSubject(db.db, { tenant: TENANT, externalId: null }); expect(yield* storedSubjects(db)).toEqual([]); }), ), ); it.effect("records the host sentinel subject id", () => withDb((db) => Effect.gen(function* () { // apps/local binds every request to the literal subject "local". It is // a real principal here, not a placeholder to skip. yield* touchSubject(db.db, { tenant: TENANT, externalId: "local" }); expect((yield* storedSubjects(db)).map((row) => row.externalId)).toEqual(["local"]); }), ), ); it.effect("files the same principal separately under each tenant", () => withDb((db) => Effect.gen(function* () { // The tenant written is always the one bound to the touch, so the // tenant policy's create check can never reject it — and one account in // two orgs is two rows under two tenants, not a unique-index collision. yield* touchSubject(db.db, { tenant: TENANT, externalId: "user_a" }); yield* touchSubject(db.db, { tenant: OTHER_TENANT, externalId: "user_a", }); expect((yield* storedSubjects(db, TENANT)).map((row) => row.externalId)).toEqual([ "user_a", ]); expect((yield* storedSubjects(db, OTHER_TENANT)).map((row) => row.externalId)).toEqual([ "user_a", ]); }), ), ); it.effect("survives a storage failure without failing its caller", () => withDb((db) => Effect.gen(function* () { // A sighting is bookkeeping. A storage failure must not take down the // request that produced it — `touchSubject` logs and returns void. // Dropping the table is the real shape of the failure this guards // against (a host whose bring-up hasn't reached the new table yet). yield* Effect.promise(() => db.client.execute("DROP TABLE subject")); yield* touchSubject(db.db, { tenant: TENANT, externalId: "user_a" }); }), ), ); }); // --------------------------------------------------------------------------- // The second writer: `connections.create`. The request seam covers every hosted // call, so this is the belt for a direct SDK/CLI caller that never passes // through it. // --------------------------------------------------------------------------- const INTEG = IntegrationSlug.make("vercel"); const TEMPLATE = AuthTemplateSlug.make("apiKey"); const demoPlugin = definePlugin(() => ({ id: "demo" as const, storage: () => ({}), resolveTools: () => Effect.succeed({ tools: [{ name: ToolName.make("deploy") }] }), invokeTool: () => Effect.succeed(null), extension: (ctx) => ({ seed: () => ctx.core.integrations.register({ slug: INTEG, description: "Vercel", config: {}, }), }), }))(); const plugins = [memoryCredentialsPlugin(), demoPlugin] as const; const subjectsOf = ( harness: { readonly config: { readonly db: unknown } }, tenant: string, ): Effect.Effect => Effect.promise(async () => { const rows = await withQueryContext(harness.config.db as never, { tenant, subject: null, } satisfies ExecutorOwnerPolicyContext).findMany("subject", {}); return rows.map((row) => String(row.external_id)); }); describe("connections.create subject sighting", () => { it.effect("records the bound subject", () => Effect.scoped( Effect.gen(function* () { const harness = yield* makeTestWorkspaceHarness({ plugins, tenant: TENANT, }); yield* harness.executor.demo.seed(); yield* harness.executor.connections.create({ owner: "user", name: ConnectionName.make("main"), integration: INTEG, template: TEMPLATE, value: "secret-token", }); expect(yield* subjectsOf(harness, TENANT)).toEqual([harness.subject]); }), ), ); it.effect("records the bound subject even for an org-owned connection", () => Effect.scoped( Effect.gen(function* () { // The row names the acting principal, not the connection's owner tier: // a member who only ever creates org connections still exists. const harness = yield* makeTestWorkspaceHarness({ plugins, tenant: TENANT, }); yield* harness.executor.demo.seed(); yield* harness.executor.connections.create({ owner: "org", name: ConnectionName.make("shared"), integration: INTEG, template: TEMPLATE, value: "secret-token", }); expect(yield* subjectsOf(harness, TENANT)).toEqual([harness.subject]); }), ), ); it.effect("records nothing when the executor has no subject", () => Effect.scoped( Effect.gen(function* () { const harness = yield* makeTestWorkspaceHarness({ plugins, tenant: TENANT, subject: null, }); yield* harness.executor.demo.seed(); yield* harness.executor.connections.create({ owner: "org", name: ConnectionName.make("shared"), integration: INTEG, template: TEMPLATE, value: "secret-token", }); expect(yield* subjectsOf(harness, TENANT)).toEqual([]); }), ), ); });