feat(cli): fix runHTTP auth bug + add management verbs #13
Reference in New Issue
Block a user
Delete Branch "feat/management-cli-verbs"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Extends
molecule-clifrom a runtime-bridge into a management CLI, and fixes the auth bug first.1. Auth bug fix (the priority)
internal/cmd/http.gorunHTTP— and theinternal/clientPlatformHTTP helpers, which had the same gap — sent noAuthorizationheader, so management calls (workspace create/delete, secrets, tokens, …) 401'd a hardened tenant. Now every request attaches:Authorization: Bearer $MOLECULE_API_KEY(the Org API Key — tenant-admin)X-Molecule-Org-Id: $MOLECULE_ORG_IDwhen set (the tenantTenantGuardrouting gate)Headers are omitted when the env vars are unset, so fresh self-host/dev tenants keep working. Regression test
TestRunHTTP_SetsAuthHeaderasserts the header is set, and is proven load-bearing: reverting the fix makes it fail withAuthorization header = "". A second test (TestClientAuthHeaders+ the per-verb table) proves auth flows on every client method.2. Management verbs (PLATFORM-MANAGEMENT-API.md §5(b))
Each wired to the documented endpoint at the correct auth tier:
orglistgetcreate --slug/--namecreate --templateexporttoken {list,create,revoke}allowlistworkspacelistgetcreatedeleterestartpauseresumebudgetbilling-modetoken mintsecretws {list,set,delete}·org {list,set,delete}templatelistimportrefreshbundleexportimportevents·approvalsOrg-lifecycle verbs target the control plane (
MOLECULE_CP_URL, default =--api-url); tenant verbs target the tenant host with the Org API Key. All honor--json(plus existing-o table|json|yaml).OpenAPI / SSOT alignment
The brief pointed at a parallel
feat/openapi-management-specbranch inmolecule-core— that branch does not exist (verified via Gitea API; only the/schedulesswagger stub is onmain). Per SOP Phase 1 this load-bearing claim is falsified, so request/response shapes were reconciled against the actual SSOT: the liveworkspace-server/internal/router/router.goroute table + handler structs, and the controlplaneorgs.go/models.Organization. Concretely: budget =PATCH /workspaces/:id/budget {budget_limits: {hourly|daily|weekly|monthly: cents}}; billing-mode =PUT /admin/workspaces/:id/llm-billing-mode {mode}; org-from-template =POST /org/import {dir, mode}; secrets ={key,value}; template import ={name, files}; org create (CP) =POST /api/v1/orgs {slug, name}.Tests / verification (Phase 4)
go build ./...,go vet ./...,go test ./...— all greengofmtclean on edited files only (no wildcard)httptestmock--jsonresolution, CP-url fallback, auth-helper env readsAuthorization: Bearer …+X-Molecule-Org-Idreach the server;org listtable and--jsonboth renderTier:
tier:medium(touches auth). Do not self-merge — needs a non-author approval per SOP.🤖 Generated with Claude Code
Fix the auth bug FIRST: internal/cmd/http.go runHTTP (and the internal/client Platform HTTP helpers, which had the same gap) sent NO Authorization header, so management calls (workspace create/delete, secrets, tokens, …) 401'd a hardened tenant. Now every request attaches `Authorization: Bearer $MOLECULE_API_KEY` and, when set, `X-Molecule-Org-Id: $MOLECULE_ORG_ID` (the tenant TenantGuard routing gate). Headers are omitted when the env vars are unset so fresh self-host/dev tenants keep working. Regression test TestRunHTTP_SetsAuthHeader asserts the header is set and is proven load-bearing (fails with `Authorization header = ""` when the fix is reverted). Add the management verbs (PLATFORM-MANAGEMENT-API.md §5(b)), each wired to the OpenAPI-documented endpoint at the correct auth tier (verified against the live workspace-server router.go + handlers and controlplane orgs handler, since the parallel feat/openapi-management-spec branch does not exist in molecule-core — reconciled to the actual handler source instead): org list|get|create --slug/--name|create --template|export token list|create|revoke | allowlist workspace list|get|create|delete|restart|pause|resume budget|billing-mode|token mint secret ws list|set|delete org list|set|delete template list|import|refresh bundle export|import events approvals Org-lifecycle verbs target the control plane (MOLECULE_CP_URL, default = api-url); tenant verbs target the tenant host with the Org API Key. All verbs honor --json (and existing -o table|json|yaml). Request/ response shapes match the handler structs (budget USD-cents budget_limits; billing-mode {mode}; org import {dir,mode}; secrets {key,value}; template import {name,files}; etc.). Tests: table-driven request-construction tests (method/path/body/auth) for all 30 management methods against an httptest mock, plus cmd-layer branch tests (budget flag→limits, billing-mode validation, template file mapping, --json resolution, CP-url fallback). Existing workspace/agent/platform commands switched to the authenticated client. go build ./..., go vet ./..., go test ./... all green; gofmt clean on edited files. Binary smoke-tested end-to-end: auth headers reach the server and --json output renders. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>Approved per comprehensive pre-merge review at HEAD
e878dca— build/vet/test green, cpURL no-fallback, PathEscape, CP-admin routing verified vs controlplane router. CTO-authorized.Second approval under CTO authorization.