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([]);
}),
),
);
});