History

mcp: pin per-user auth isolation with an SDK-level regression test

Two executors share an in-memory adapter and blob store, modeling a multi-tenant cloud topology: user A signs in and installs a shared MCP source at the org scope; user B (scope stack [userB, org]) has no connection or per-user secret. Run a real HTTP MCP server that records the Authorization header on every request so "leaked a token" becomes a direct assertion against the captured header. Covers both auth kinds the plugin supports for remote sources: * oauth2 — auth points at a Connection id that only resolves through user A's scope stack. * header — auth points at a per-user SecretId only planted in user A's scope. User A's invocation asserts the server actually saw user A's bearer on the wire (so the negative path can't pass by accident). User B's invocation must surface as ToolInvocationError wrapping an McpConnectionError, and no server request after that point may carry user A's token. Induced-regression check: replacing the `accessToken(...)` failure with `Effect.orElseSucceed(() => "")` makes user B's invoke succeed; the new test flips to Left→Right and fails as expected. Reverted after verification. No code fix — the SDK-level flow is correct. `resolveConnectorInput` maps `ConnectionNotFoundError` and `secrets.get(...) === null` into McpConnectionError, and `findInnermostConnectionRow` only walks the caller's scope stack, so user A's row at userA scope is invisible to user B's [userB, org] stack. Adds @executor/storage-core to the MCP plugin's devDependencies so the test can use `makeMemoryAdapter` directly for the shared-adapter harness.

Rhys Sullivan committed 6 months ago

Commit def0d991 parent e9fad473 files · +1 −-1Browse files

Unified · Split

3 files
  1. bun.lock +1 −0
  2. packages/plugins/mcp/package.json +1 −0
  3. packages/plugins/mcp/src/sdk/per-user-auth-isolation.test.ts +0 −0
bun.lock+1−0
@@ -624,6 +624,7 @@ · 623 unmodified lines
624624 "@effect/vitest": "catalog:",
625625 "@executor/api": "workspace:*",
626626 "@executor/react": "workspace:*",
627+ "@executor/storage-core": "workspace:*",
627628 "@types/node": "catalog:",
628629 "@types/react": "catalog:",
629630 "bun-types": "catalog:",
packages/plugins/mcp/package.json+1−0
@@ -60,6 +60,7 @@ · 59 unmodified lines
6060 "@effect/vitest": "catalog:",
6161 "@executor/api": "workspace:*",
6262 "@executor/react": "workspace:*",
63+ "@executor/storage-core": "workspace:*",
6364 "@types/node": "catalog:",
6465 "@types/react": "catalog:",
6566 "bun-types": "catalog:",
packages/plugins/mcp/src/sdk/per-user-auth-isolation.test.ts+0−0

Binary file not shown.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t