{"slug":"architecture/ROUND_2_ENVIRONMENT_ISOLATION","title":"Round 2 — Environment and Tenancy Isolation Manifest","section":"architecture","sectionLabel":"Architecture","status":"unclassified","type":"document","path":"architecture/ROUND_2_ENVIRONMENT_ISOLATION.mdx","bytes":7254,"description":null,"updated":null,"source":"integratewise/Integratewise-docs-wiki","content":"\n**Date:** 2026-07-29  \n**Status:** Code-level isolation exists; live verification needed\n\n---\n\n## Three Runtime Profiles — Isolation Matrix\n\n### Dev Internal\n\n| Dimension      | Value                                      | Enforcement                 |\n| -------------- | ------------------------------------------ | --------------------------- |\n| **Tenant ID**  | Local dev tenant (e.g., `dev-local`)       | `.env` or seed auth         |\n| **Database**   | Local Neon/Docker Postgres                 | `DATABASE_URL` env var      |\n| **Workers**    | Local via `turbo dev`                      | Local process               |\n| **Connectors** | Full set, test accounts, sandbox providers | No credential validation    |\n| **Auth**       | Dev Clerk keys or mock                     | `.env`                      |\n| **Secrets**    | Local `.env` files                         | Gitignored                  |\n| **Routines**   | Full diagnostic routes, seed tools         | Tenant-gated by `tenant_id` |\n| **Isolation**  | Process-level (local machine)              | N/A                         |\n\n### Customer Zero\n\n| Dimension      | Value                                                 | Enforcement                                                    |\n| -------------- | ----------------------------------------------------- | -------------------------------------------------------------- |\n| **Tenant ID**  | `iw-customer-zero`                                    | Hardcoded check in `clerk-auth.ts` via `isCustomerZeroEmail()` |\n| **Database**   | Dedicated Neon database or schema                     | Separate `DATABASE_URL` binding                                |\n| **Workers**    | Dedicated or tagged Cloudflare Workers                | `IW_CUSTOMER_ZERO=true` env                                    |\n| **Connectors** | Real production connectors, real providers            | Full credential set in Secret Store                            |\n| **Auth**       | Clerk production, `@integratewise.ai` domain          | Clerk org `iw-customer-zero`                                   |\n| **Secrets**    | `CUSTOMER_ZERO_*` namespace in Secret Store           | Cloudflare Workers secrets                                     |\n| **Routines**   | Full diagnostic routes, internal tools, seed controls | Tenant ID gate                                                 |\n| **Isolation**  | Tenant-level (dedicated DB, dedicated Workers)        | Gateway tenant resolution                                      |\n\n### External Product\n\n| Dimension      | Value                                                | Enforcement                                                  |\n| -------------- | ---------------------------------------------------- | ------------------------------------------------------------ |\n| **Tenant ID**  | Auto-generated `<tenant-slug>`                       | Created at marketplace installation                          |\n| **Database**   | Shared Neon + strict RLS                             | `USING (tenant_id = current_setting('app.tenant_id')::text)` |\n| **Workers**    | Shared stateless Cloudflare Workers                  | Same deployment as Customer Zero                             |\n| **Connectors** | Same binaries; tenant-scoped credentials             | Secret Store `TENANT_<slug>_*`                               |\n| **Auth**       | Clerk production, external domains + marketplace JWT | Clerk org per tenant                                         |\n| **Secrets**    | `TENANT_<slug>_*` namespace in Secret Store          | Cloudflare Workers secrets                                   |\n| **Routines**   | 19-tool public contract only; no diagnostics         | Tenant ID gate + profile check                               |\n| **Isolation**  | Row-level (shared DB, strict RLS)                    | Database-level enforcement                                   |\n\n---\n\n## Code-Level Isolation Points\n\n### 1. Gateway Tenant Resolution\n\n**File:** `services/gateway/src/index.ts`\n\n```typescript\n// Tenant resolution from verified identity\nconst tenantId = verifiedPrincipal.tenantId;\n\n// Trusted header overwrite (prevents spoofing)\nif (isTrustedOrigin(request)) {\n  request.headers.set(\"x-tenant-id\", tenantId);\n}\n```\n\n### 2. MCP Connector Tool Gating\n\n**File:** `services/mcp-connector/src/continuity-bridge.ts`\n\n```typescript\nconst isCustomerZero = actor.tenant_id === \"iw-customer-zero\";\n\nif (isCustomerZero) {\n  // 19 public + 4 internal tools\n  tools: [\n    ...PUBLIC_CONTINUITY_BRIDGE_TOOL_DEFINITIONS,\n    ...INTERNAL_CONTINUITY_BRIDGE_TOOL_DEFINITIONS,\n  ];\n} else {\n  // 19 public tools only\n  tools: PUBLIC_CONTINUITY_BRIDGE_TOOL_DEFINITIONS;\n}\n```\n\n### 3. Gateway Internal Route Gating\n\n**File:** `services/gateway/src/index.ts`\n\n```typescript\n// Internal routes blocked for external tenants\nif (!isInternalTenant(tenantId) && isInternalRoute(path)) {\n  return new Response(\"Forbidden\", { status: 403 });\n}\n```\n\n### 4. Neon Query Tenant Isolation\n\n**File:** `services/spine/src/neon-workbench.ts`\n\n```typescript\n// Every Neon query includes tenant_id as first bind parameter\nconst result = await neon.query(\"SELECT * FROM workbench WHERE tenant_id = $1\", [tenantId]);\n```\n\n### 5. Frontend Server-Resolved Identity\n\n**File:** `apps/web/src/lib/platform/index.ts`\n\n```typescript\n// Frontend calls /api/v1/workspace/discovery first\nconst discovery = await fetch(`${NEXT_PUBLIC_IW_API_URL}/api/v1/workspace/discovery`);\n// Renders from server-resolved identity, not client inference\n```\n\n---\n\n## Verification Checklist\n\n| Check                         | Command                                                     | Expected                             |\n| ----------------------------- | ----------------------------------------------------------- | ------------------------------------ |\n| Dev Internal: local DB        | `DATABASE_URL=... pnpm --filter @integratewise/spine dev`   | Connects to local DB                 |\n| Customer Zero: dedicated DB   | Query Neon: `SELECT current_database()`                     | Returns Customer Zero DB name        |\n| External: RLS enforced        | Query Neon as external tenant                               | Returns only rows matching tenant_id |\n| Gateway: tenant isolation     | `curl -H \"x-tenant-id: iw-customer-zero\" ...`               | Returns Customer Zero data           |\n| Gateway: external tenant      | `curl -H \"x-tenant-id: acme-corp\" ...`                      | Returns Acme Corp data only          |\n| Gateway: cross-tenant denial  | `curl -H \"x-tenant-id: acme-corp\" .../iw-customer-zero/...` | Returns 403                          |\n| MCP Connector: tool gating    | MCP list_tools as external tenant                           | Returns 19 tools only                |\n| MCP Connector: internal tools | MCP list_tools as iw-customer-zero                          | Returns 23 tools                     |\n| Frontend: no direct DB        | Grep `apps/web` for `postgres://` or `neon.tech`            | Zero hits                            |\n| Frontend: no direct provider  | Grep `apps/web` for provider API URLs                       | Zero hits                            |\n"}