Skip to content

v0.3.0 — multi-user MCP control plane

Choose a tag to compare

@hrishikeshdkakkad hrishikeshdkakkad released this 24 Jul 18:56
· 331 commits to main since this release
1b87a89

Multi-user MCP control plane. Six phases (A–F) and migrations 00110025 turn fluidbox from a single-admin control plane into one that can host many organizations, many users, and many separately-owned credentials without ever letting a model pick an identity.

Every hosted capability is opt-in behind a flag, and the default single-admin Docker deployment is the same product it was in v0.2.0 — with FLUIDBOX_REQUIRE_SSO unset, nothing below is active.

The organizing idea: connector definition ≠ credential-bearing connection ≠ agent connection requirement ≠ per-run resource binding. An agent declares what it requires, never whose credential satisfies it. Run creation resolves each requirement to an explicit, frozen authority source before any model spend. The model picks tools; it can never pick an identity.

Highlights

  • Per-organization, IdP-agnostic identityFLUIDBOX_REQUIRE_SSO=1 confines the admin token to /v1/admin/* as break-glass and introduces three principals: Operator (admin token), User (__Host-fbx_web session cookie), and Pat (fbx_pat_ bearer). Any conformant OIDC issuer is configured per org. No IdP configured ⇒ single-admin mode, unchanged.
  • Tenant isolation with a database floor — every tenant-owned repository method takes a TenantScope, making isolation a signature requirement rather than a remember-to-filter convention. Migration 0018 adds row-level security underneath: 37 tables ENABLE+FORCE RLS keyed on a transaction-local GUC, with FLUIDBOX_RUNTIME_ROLE splitting the pool onto a non-owner role.
  • Connection ownership and per-run resource bindings — brokered MCP tools moved onto four objects, resolved to a tagged authority (connection | subscription_secret | none) across typed slots before provisioning. A personal-connection approval is decidable only by its owner-who-invoked — no role, admin, or operator override.
  • Versioned envelope sealing with a real key-retirement path — per-tenant DEKs wrapped by a KEK (FLUIDBOX_KMS_MODE=off|static|aws), AAD-bound so a sealed blob is untransplantable across tenants or columns. A resumable, CAS-guarded POST /v1/admin/reseal migrates legacy rows; two boot gates fail closed in both directions.
  • One hardened egress boundary — a pure admit_url pre-flight blocks private/loopback/link-local/metadata address classes at every dial site (reqwest dials an IP literal without consulting a resolver, so the pre-flight is what actually stops 169.254.169.254). Broker, delivery callbacks, and both connector-OAuth token legs refuse redirects outright — a 307/308 replays the request body, which would forward an authorization code plus PKCE verifier to the redirect target.
  • MCP 2025-11-25 conformance — per-run upstream sessions; a negotiated version that drifts from the frozen surface denies the call.
  • Frozen tool schemas enforced server-side — arguments validated against the schema photographed at freeze time, dialect chosen by the snapshot's protocol version. Exactly one new stage in the permission gate; nothing else moved.
  • At-most-once brokered dispatch — a durable four-state execution claim per call. Decision idempotency and execution idempotency are now distinct properties.
  • Audience-scoped sandbox credentials — the sandbox's single bearer splits into four tokens (llm | tool | control | workspace).
  • Replica coordination + durable budget admission — approval emission rides the deciding CAS, orchestrator leases with epoch fencing, per-row delivery claims, and request-keyed LLM reservations.
  • Operations — bounded-cardinality metrics at GET /v1/admin/metrics, durable cross-replica egress governance, S3-compatible archives, and a guarded load harness.

Validation

Five hermetic acceptance suites green against CI-identical throwaway databases — identity 87/0, bindings 104/0, secrets 128/0, hardening 274/0, scale 18/0 = 611/0 — plus live Docker-provider tiers and a second live EKS acceptance on arm64/Graviton with the runtime-role RLS split active and an AWS-audited zero-orphan teardown.

Known limitations

The gated 60/150/300-seat load campaign and the final two rollout gates remain open on #34. This release does not claim a proven 300-run production ceiling. The hosted OAuth Connect flow also carries one documented residual: a deliberately-shared start URL can still route a victim's grant into the initiating connection (docs/hosted/threat-model.md).

Upgrading

Migration 0018 is stop the old binary, migrate, then deploy — not a rolling upgrade. A pre-0018 binary sets no tenant GUC and would see zero rows, and it holds transactions across outbound HTTP that would block the migration's ACCESS EXCLUSIVE locks.

Do not drop FLUIDBOX_CREDENTIAL_KEY when enabling FLUIDBOX_KMS_MODE: run POST /v1/admin/reseal and let boot prove zero remaining v1 rows first. From the moment any v2 row exists, the KEK is the root of custody and losing it is unrecoverable — back it up before enabling.


Full changelog: CHANGELOG.md · Hosted deployment: rollout gates and KMS/RLS runbook

helm install fluidbox oci://ghcr.io/hrishikeshdkakkad/charts/fluidbox --version 0.3.0