docs(openapi): add OpenAPI 3.1 management spec (SSOT) + README
ci-arm64-advisory / fast-checks (pull_request) Waiting to run
E2E API Smoke Test / E2E API Smoke Test (pull_request) Blocked by required conditions
E2E Chat / E2E Chat (pull_request) Blocked by required conditions
E2E Staging Canvas (Playwright) / Canvas tabs E2E (pull_request) Blocked by required conditions
Handlers Postgres Integration / Handlers Postgres Integration (pull_request) Blocked by required conditions
Harness Replays / Harness Replays (pull_request) Blocked by required conditions
Lint shellcheck (arm64 pilot) / shellcheck-arm64 (pilot) (pull_request) Successful in 11s
Block internal-flavored paths / Block forbidden paths (pull_request) Successful in 3s
E2E API Smoke Test / detect-changes (pull_request) Successful in 7s
E2E Chat / detect-changes (pull_request) Successful in 6s
Handlers Postgres Integration / detect-changes (pull_request) Successful in 6s
E2E Staging Canvas (Playwright) / detect-changes (pull_request) Successful in 9s
Harness Replays / detect-changes (pull_request) Successful in 3s
Lint forbidden tenant-env keys / Scan workspace_secrets writers for forbidden env keys (pull_request) Successful in 4s
Lint no tenant GITEA or GITHUB token write / Scan for repo-host token write into tenant workspace surface (pull_request) Successful in 4s
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 6s
verify-providers-gen / Regenerate providers artifact and fail on drift (pull_request) Successful in 43s
gate-check-v3 / gate-check (pull_request) Successful in 5s
lint-required-no-paths / lint-required-no-paths (pull_request) Successful in 1m10s
qa-review / approved (pull_request) Failing after 6s
security-review / approved (pull_request) Failing after 5s
sop-checklist / na-declarations (pull_request) N/A: (none)
sop-checklist / all-items-acked (pull_request) Successful in 5s
sop-checklist / review-refire (pull_request) Has been skipped
sop-tier-check / tier-check (pull_request) Successful in 8s
CI / Platform (Go) (pull_request) Has been cancelled
CI / Canvas (Next.js) (pull_request) Has been cancelled
CI / Shellcheck (E2E scripts) (pull_request) Has been cancelled
CI / Canvas Deploy Reminder (pull_request) Has been cancelled
CI / all-required (pull_request) Failing after 40m28s
CI / Detect changes (pull_request) Has been cancelled
CI / Python Lint & Test (pull_request) Has been cancelled
ci-arm64-advisory / fast-checks (pull_request) Waiting to run
E2E API Smoke Test / E2E API Smoke Test (pull_request) Blocked by required conditions
E2E Chat / E2E Chat (pull_request) Blocked by required conditions
E2E Staging Canvas (Playwright) / Canvas tabs E2E (pull_request) Blocked by required conditions
Handlers Postgres Integration / Handlers Postgres Integration (pull_request) Blocked by required conditions
Harness Replays / Harness Replays (pull_request) Blocked by required conditions
Lint shellcheck (arm64 pilot) / shellcheck-arm64 (pilot) (pull_request) Successful in 11s
Block internal-flavored paths / Block forbidden paths (pull_request) Successful in 3s
E2E API Smoke Test / detect-changes (pull_request) Successful in 7s
E2E Chat / detect-changes (pull_request) Successful in 6s
Handlers Postgres Integration / detect-changes (pull_request) Successful in 6s
E2E Staging Canvas (Playwright) / detect-changes (pull_request) Successful in 9s
Harness Replays / detect-changes (pull_request) Successful in 3s
Lint forbidden tenant-env keys / Scan workspace_secrets writers for forbidden env keys (pull_request) Successful in 4s
Lint no tenant GITEA or GITHUB token write / Scan for repo-host token write into tenant workspace surface (pull_request) Successful in 4s
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 6s
verify-providers-gen / Regenerate providers artifact and fail on drift (pull_request) Successful in 43s
gate-check-v3 / gate-check (pull_request) Successful in 5s
lint-required-no-paths / lint-required-no-paths (pull_request) Successful in 1m10s
qa-review / approved (pull_request) Failing after 6s
security-review / approved (pull_request) Failing after 5s
sop-checklist / na-declarations (pull_request) N/A: (none)
sop-checklist / all-items-acked (pull_request) Successful in 5s
sop-checklist / review-refire (pull_request) Has been skipped
sop-tier-check / tier-check (pull_request) Successful in 8s
CI / Platform (Go) (pull_request) Has been cancelled
CI / Canvas (Next.js) (pull_request) Has been cancelled
CI / Shellcheck (E2E scripts) (pull_request) Has been cancelled
CI / Canvas Deploy Reminder (pull_request) Has been cancelled
CI / all-required (pull_request) Failing after 40m28s
CI / Detect changes (pull_request) Has been cancelled
CI / Python Lint & Test (pull_request) Has been cancelled
Author workspace-server/docs/openapi/management.yaml — the hand-authored,
authoritative OpenAPI 3.1 contract for the Molecule platform MANAGEMENT
surface, spanning both services in one spec:
- CP (api.moleculesai.app, /api/v1/*): orgs create/get/list/delete/export/
provision-status, public instance lookup, billing (invoices/checkout/
portal/topup), admin (admin-create-org w/ dry_run, tenant delete +
scrub w/ confirm guard, diagnostics, redeploy + fleet, workspace env
w/ force guard, ListOrgWorkspaces, admin-token, thin-ami + runtime-image
pins), provisioning (provision w/ 422 RUNTIME_PIN_MISSING, deprovision,
status).
- Tenant workspace-server: /workspaces[/:id] CRUD + restart/pause/resume,
budget, llm-billing-mode, /workspaces/:id/secrets, /settings/secrets,
/org/import, /org/templates, /org/tokens (Org API Key mint/revoke),
/templates[/import], /bundles export/import.
Defines the five security tiers as securitySchemes (workosSession cookie,
cpAdminBearer, provisionSecret [+ tenantAdminToken on deprovision], orgApiKey
+ org routing header, workspaceToken) and applies the correct scheme(s)
per-route. Dry-run / confirm / force guards modelled per-operation.
Grounded in the router + handler sources (controlplane + workspace-server),
not just the synthesis doc — notably llm-billing-mode is modelled on the
real tenant route (/admin/workspaces/:id/llm-billing-mode, AdminAuth), with
the divergence from the synthesis doc noted in the README.
Adds README.md documenting the two-service split + the security-scheme→
surface tier matrix. This is the SSOT the management MCP + CLI + docs derive
from (PLATFORM-MANAGEMENT-API.md §5c / RFC #1706). Supersedes the swaggo
/schedules stub for the management surface; runtime surface stays out of scope.
Per dev-sop Phase 1-4 + Five-Axis self-review (in PR body).
Lints clean: npx @redocly/cli lint management.yaml (0 errors, 0 warnings).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,114 @@
|
||||
# Molecule Platform OpenAPI specs
|
||||
|
||||
This directory holds the machine-readable API contracts for the Molecule
|
||||
platform.
|
||||
|
||||
| File | Spec | Scope | Status |
|
||||
|------|------|-------|--------|
|
||||
| `management.yaml` | OpenAPI **3.1** | The **management surface** across both services (orgs, billing, admin, provisioning, workspaces, secrets, templates, org-tokens, bundles). | **SSOT** — hand-authored. |
|
||||
| `swagger.yaml` / `swagger.json` | OpenAPI 2.0 | swaggo-generated stub, `/schedules` only (the per-workspace **runtime** surface). | Legacy stub; superseded for management by `management.yaml`. |
|
||||
|
||||
`management.yaml` is the **single source of truth** the management tooling
|
||||
derives from — the management MCP server, the management CLI (`molecule-cli`),
|
||||
and the human-facing API docs (RFC #1706, the gap closed by
|
||||
`PLATFORM-MANAGEMENT-API.md` §5c). Do not hand-edit those clients' route maps;
|
||||
change them here and regenerate/derive.
|
||||
|
||||
## The two-service split
|
||||
|
||||
One structural fact drives the whole spec: there are **two services with two
|
||||
auth stacks**, and the management surface spans both.
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────┐
|
||||
browser / CLI / MCP │ Control plane (CP) │
|
||||
│ │ molecule-controlplane @ api.moleculesai │
|
||||
│ session │ /api/v1/* (stable) [+ /cp/* sunset] │
|
||||
├───────────────▶│ orgs · members · billing · provisioning │
|
||||
│ admin bearer │ · fleet/admin ops · pins │
|
||||
│ provision sec │ │
|
||||
└────────────────┴──────────────┬───────────────────────────┘
|
||||
│ edge reverse-proxy
|
||||
│ (subdomain / X-Molecule-Org-Slug)
|
||||
▼
|
||||
┌─────────────────────────────────────────┐
|
||||
Org API Key / ws tok │ Tenant workspace-server │
|
||||
│ │ molecule-core/workspace-server │
|
||||
└───────────────▶│ ONE EC2 per org @ <slug>.moleculesai.app│
|
||||
│ workspaces · secrets · templates · │
|
||||
│ org-tokens · bundles │
|
||||
└─────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
- **Control plane (CP)** — `api.moleculesai.app`, routes modelled under
|
||||
`/api/v1/*` (the `/cp/*` mirror is identical but sunset-headed per RFC #61 and
|
||||
is not duplicated in the spec). Owns **orgs, members, billing, provisioning,
|
||||
fleet/admin ops**.
|
||||
- **Tenant workspace-server** — one EC2 per org at `<slug>.moleculesai.app`.
|
||||
Owns **workspaces, agents, secrets, templates, org-tokens, bundles**. Requests
|
||||
may also be sent to the CP host with an `X-Molecule-Org-Slug` header; the CP
|
||||
edge reverse-proxies them to the tenant host (the `Authorization`,
|
||||
`X-Molecule-Org-*`, and cookie headers pass through unchanged and the tenant's
|
||||
own middleware validates them).
|
||||
|
||||
The key consequence, called out in `PLATFORM-MANAGEMENT-API.md`: **the Org API
|
||||
Key is a TENANT credential, not a CP one.** It is full tenant-admin over its own
|
||||
org's workspace-server surface and reaches **nothing** on the CP (org
|
||||
create/delete, billing, members, provisioning all 401/403 it). That is why
|
||||
member/billing tools belong in a separate CP-admin MCP, not the org-key-authed
|
||||
management MCP.
|
||||
|
||||
## Security scheme → surface map (the tier matrix)
|
||||
|
||||
`management.yaml` defines these `securitySchemes`; each operation declares the
|
||||
one(s) it accepts. Mirror of `PLATFORM-MANAGEMENT-API.md` §1:
|
||||
|
||||
| Scheme | What it is | Where it applies |
|
||||
|--------|-----------|------------------|
|
||||
| `workosSession` | WorkOS AuthKit session cookie `mcp_session` (+ org membership/ownership checks) | CP `/api/v1/orgs/*`, `/api/v1/billing/*`. Also accepted on the tenant surface via the CP-session path. |
|
||||
| `cpAdminBearer` | CP `CP_ADMIN_API_TOKEN` operator bearer (AdminGate, constant-time) | CP `/api/v1/admin/*` — admin-create-org, tenant teardown, workspace env, ListOrgWorkspaces, redeploy, pins. |
|
||||
| `provisionSecret` | CP `PROVISION_SHARED_SECRET` bearer | CP `/api/v1/workspaces/provision`, `…/status`. Routes unmounted when the secret is unset. |
|
||||
| `tenantAdminToken` | Per-tenant admin_token (+ `X-Molecule-Org-Id`) | CP `DELETE /api/v1/workspaces/:id` (deprovision) — **in addition to** `provisionSecret` (issue #118). |
|
||||
| `orgApiKey` | Tenant Org API Key — `Authorization: Bearer <key>` + routing header; full tenant-admin, self-minting | **All** tenant routes: `/workspaces[/:id]`, `/workspaces/:id/secrets`, budget, billing-mode, `/settings/secrets`, `/org/import`, `/org/templates`, `/org/tokens`, `/templates`, `/bundles`. |
|
||||
| `workspaceToken` | Per-workspace bearer, bound to one workspace id (+ routing header) | Read/lifecycle/secrets on a single `/workspaces/:id/*`. **Rejected** on admin list/create/delete when ADMIN_TOKEN is set — use `orgApiKey`. |
|
||||
| `orgRoutingHeaderId` / `orgRoutingHeaderSlug` | `X-Molecule-Org-Id` / `X-Molecule-Org-Slug` | Required on every tenant-host request so the edge / TenantGuard route + authorize against the correct org. Send one of them alongside the bearer. |
|
||||
|
||||
### Guards worth knowing (modelled per-operation)
|
||||
|
||||
- **Dry-run:** `POST /api/v1/admin/orgs?dry_run=true` — validate + echo, no org
|
||||
created. (The only dry-run on the whole management API.)
|
||||
- **Confirm token:** `DELETE /api/v1/admin/tenants/:slug` and
|
||||
`…/scrub-artifacts` — body `confirm` MUST equal the URL slug, else `400`
|
||||
before any teardown.
|
||||
- **Force flag:** `POST /api/v1/admin/workspaces/:id/env` — keys matching the
|
||||
secret-keyword guard (`TOKEN`/`SECRET`/`KEY`/`PASSWORD`) require `force=true`.
|
||||
- **Runtime-pin gate:** `POST /api/v1/workspaces/provision` returns `422
|
||||
RUNTIME_PIN_MISSING` when no runtime image pin exists.
|
||||
- **Auto-restart side-effects:** writing a workspace or global secret
|
||||
auto-restarts the affected workspace(s).
|
||||
|
||||
## Security note (carried from the synthesis spec)
|
||||
|
||||
The Org API Key is **full tenant-admin and self-minting** — a management MCP
|
||||
holding one holds tenant root. There is no scope-down today (TODO in
|
||||
`orgtoken`). Per-role / per-workspace scoping should ship alongside the
|
||||
management MCP.
|
||||
|
||||
## Validate
|
||||
|
||||
```bash
|
||||
cd workspace-server/docs/openapi
|
||||
npx @redocly/cli lint management.yaml # must be clean (0 errors, 0 warnings)
|
||||
```
|
||||
|
||||
## Scope notes / best-effort flags
|
||||
|
||||
- The per-workspace **runtime** surface (schedules, agent, registry, a2a,
|
||||
memory, approvals, channels, terminal, files) is intentionally **out of
|
||||
scope** here — that's the runtime contract, not management.
|
||||
- A handful of bodies are **best-effort** from the handlers (org-import inline
|
||||
template, bundle import, list responses with open shapes) and are marked with
|
||||
`additionalProperties: true` in the schema. Tighten as the handler structs
|
||||
stabilise.
|
||||
- `/cp/*` deprecated mirrors are omitted (identical shapes; RFC #61
|
||||
Deprecation/Sunset). Build against `/api/v1/*`.
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user