History

Move product access rules out of the SDK

Rhys Sullivan committed 1 month ago

Commit c676e561 parent a72e51d161 files · +3935 −867Browse files

Showing the changes to apps/cloud/src (5 of 161 files). Show all

Unified · Split

5 files
  1. apps/cloud/src/admin/admin-users-api.ts +1 −1
  2. apps/cloud/src/auth/workos-auth-provider.ts +1 −1
  3. apps/cloud/src/mcp-session.e2e.node.test.ts +2 −0
  4. apps/cloud/src/mcp/session-durable-object.ts +2 −1
  5. apps/cloud/src/observability/oauth-callback-telemetry.test.ts +2 −1
apps/cloud/src/admin/admin-users-api.ts+1−1
@@ -17,7 +17,7 @@ · 16 unmodified lines
17// acting member, and this plane deliberately serves the whole tenant.17// acting member, and this plane deliberately serves the whole tenant.
18//18//
19// The executor is built by `makePlatformExecutor` — `{ tenant, subject:19// The executor is built by `makePlatformExecutor` — `{ tenant, subject:
20// undefined, platformView: true }` — so the reads are tenant-wide and read-only20// undefined, access: platformObserverAccess() }` — so the reads are tenant-wide and read-only
21// by storage policy, and no `subject` row is minted for the caller.21// by storage policy, and no `subject` row is minted for the caller.
22//22//
23// Cross-tenant isolation is structural, not a check in this file: the tenant is23// Cross-tenant isolation is structural, not a check in this file: the tenant is
apps/cloud/src/auth/workos-auth-provider.ts+1−1
@@ -174,7 +174,7 @@ const resolveJwtPrincipal = (token: string, jwt: JwtBearerConfig) => · 173 unmodified lines
174 * `subject: null` + the read-only tenant reach rather than inventing a subject.174 * `subject: null` + the read-only tenant reach rather than inventing a subject.
175 *175 *
176 * The `/admin/*` mount turns this into an executor with `{ tenant:176 * The `/admin/*` mount turns this into an executor with `{ tenant:
177 * organizationId, subject: undefined, platformView: true }`.177 * organizationId, subject: undefined, access: platformObserverAccess() }`.
178 */178 */
179export interface PlatformAuth {179export interface PlatformAuth {
180 readonly kind: "platform";180 readonly kind: "platform";
apps/cloud/src/mcp-session.e2e.node.test.ts+2−0
@@ -39,6 +39,7 @@ import { makeTestWorkOSVaultClient } from "@executor-js/plugin-workos-vault/test · 38 unmodified lines
39import executorConfig from "../executor.config";39import executorConfig from "../executor.config";
40import { DbService } from "./db/db";40import { DbService } from "./db/db";
41import { createDrizzleFumaDb } from "./db/fuma";41import { createDrizzleFumaDb } from "./db/fuma";
42import { testAccess } from "@executor-js/product-access/testing";
42 43
43// ---------------------------------------------------------------------------44// ---------------------------------------------------------------------------
44// Test-only plugin: exposes one in-memory tool that elicits once. Lets the45// Test-only plugin: exposes one in-memory tool that elicits once. Lets the
@@ -124,6 +125,7 @@ const buildScopedExecutor = ( · 79 unmodified lines
124 plugins,125 plugins,
125 httpClientLayer: FetchHttpClient.layer,126 httpClientLayer: FetchHttpClient.layer,
126 onElicitation: "accept-all",127 onElicitation: "accept-all",
128 access: testAccess.member(),
127 });129 });
128 });130 });
129 131
apps/cloud/src/mcp/session-durable-object.ts+2−1
@@ -26,6 +26,7 @@ import { · 25 unmodified lines
26} from "@executor-js/host-mcp/tool-server";26} from "@executor-js/host-mcp/tool-server";
27import { buildResumeApprovalUrl } from "@executor-js/host-mcp/browser-approval";27import { buildResumeApprovalUrl } from "@executor-js/host-mcp/browser-approval";
28import { artifactUrlFor } from "@executor-js/host-mcp/create-artifact";28import { artifactUrlFor } from "@executor-js/host-mcp/create-artifact";
29import { requestBoundMemberAccess } from "@executor-js/product-access";
29import { makeAssetsShellHtmlLoader } from "@executor-js/mcp-apps-shell/worker";30import { makeAssetsShellHtmlLoader } from "@executor-js/mcp-apps-shell/worker";
30import { smokeRenderArtifact } from "@executor-js/mcp-apps-shell/smoke-render";31import { smokeRenderArtifact } from "@executor-js/mcp-apps-shell/smoke-render";
31import {32import {
@@ -349,7 +350,7 @@ export class McpSessionDOSqlite extends McpAgentSessionDOBase<Env, CloudSessionD · 317 unmodified lines
349 sessionMeta.organizationName,350 sessionMeta.organizationName,
350 {351 {
351 mcpResource: sessionMeta.resource,352 mcpResource: sessionMeta.resource,
352 orgWrites: "request",353 access: requestBoundMemberAccess(),
353 },354 },
354 ).pipe(355 ).pipe(
355 // The metered stack tracks each execution to Autumn. It requires356 // The metered stack tracks each execution to Autumn. It requires
apps/cloud/src/observability/oauth-callback-telemetry.test.ts+2−1
@@ -32,6 +32,7 @@ import { createExecutor } from "@executor-js/sdk"; · 31 unmodified lines
32import { makeTestConfig } from "@executor-js/sdk/testing";32import { makeTestConfig } from "@executor-js/sdk/testing";
33 33
34import { UrlRedactingSpanProcessor } from "./redact-span-urls";34import { UrlRedactingSpanProcessor } from "./redact-span-urls";
35import { testAccess } from "@executor-js/product-access/testing";
35 36
36// Synthetic placeholders — never a real authorization code or CSRF state.37// Synthetic placeholders — never a real authorization code or CSRF state.
37const CODE = "synthetic-authorization-code-9f2c";38const CODE = "synthetic-authorization-code-9f2c";
@@ -55,7 +56,7 @@ describe("oauth callback telemetry", () => { · 17 unmodified lines
55 it.effect("exports no span attribute containing the authorization code or state", () =>56 it.effect("exports no span attribute containing the authorization code or state", () =>
56 Effect.gen(function* () {57 Effect.gen(function* () {
57 const { exporter, provider, tracerLayer } = makeTracing();58 const { exporter, provider, tracerLayer } = makeTracing();
58 const executor = yield* createExecutor(makeTestConfig({}));59 const executor = yield* createExecutor(makeTestConfig({ access: testAccess.member() }));
59 60
60 const web = yield* Effect.acquireRelease(61 const web = yield* Effect.acquireRelease(
61 Effect.sync(() =>62 Effect.sync(() =>