Skip to content

feat(openapi): document every registered route — completeness pass - #17

Merged
mastermanas805 merged 1 commit into
masterfrom
feat/openapi-completeness
May 11, 2026
Merged

mastermanas805 merged 1 commit into
masterfrom
feat/openapi-completeness

Conversation

@mastermanas805

Copy link
Copy Markdown
Member

Summary

Audits the agent API's OpenAPI 3.1 spec against the actually-registered routes in internal/router/router.go and fills in every gap. 36 paths that were live but undocumented now have a summary, description, security, parameters, request body schema (where applicable), and an exhaustive list of response statuses. Two supporting component schemas (StorageProvisionResponse, DeployItem) added.

The diff is additive — no existing path was changed. Existing TestOpenAPISpecParses and all TestOpenAPI_* sibling gates still pass.

What was missing

Anonymous / public surface

  • GET /metrics — Prometheus scrape, token-gated when METRICS_TOKEN set
  • GET /openapi.json — self-describing
  • POST /storage/new — full schema, including the (one-shot) secret_access_key
  • GET /resources/{token}/logs — SSE pod logs (growth-tier only; token is the credential)
  • GET /stacks/{slug}/logs/{svc} — SSE stack service logs
  • PATCH /stacks/{slug}/env — env-vars-noted-for-next-redeploy MVP shape
  • POST /razorpay/webhook — HMAC-verified Razorpay subscription lifecycle (charged/cancelled/payment.failed)
  • POST /billing/checkout — legacy alias of /api/v1/billing/checkout

Auth surface (browser + programmatic + magic-link + CLI device flow)

  • POST /auth/github, GET /auth/github/start, GET /auth/github/callback
  • POST /auth/email/start, GET /auth/email/callback
  • POST /auth/cli, GET /auth/cli/{id}

Authenticated /api/v1 surface

  • GET /api/v1/resources/{id}/credentials (the AES-decrypted connection URL read)
  • Team-member CRUD: /api/v1/team/members, .../members/invite, .../members/leave, .../members/{user_id}, .../invitations, .../invitations/{id}, .../invitations/{id}/accept
  • Deployment list/get/delete aliases under /api/v1/deployments
  • Stack list under /api/v1/stacks
  • Custom-domain CRUD: /api/v1/stacks/{slug}/domains, .../verify, .../{id}
  • Personal Access Tokens: /api/v1/auth/api-keys (POST/GET) and .../{id} (DELETE)
  • GET /api/v1/audit — Recent Activity feed

Internal / ops (dev-only) — flagged with "x-instanode-internal": true and clearly noted in description as only enabled when ENVIRONMENT=development

  • POST /internal/set-tier — bypass-Razorpay manual tier elevation

Verification

go test -run TestOpenAPISpecParses ./internal/handlers/...   # PASS
go test -run TestOpenAPI ./internal/handlers/... -v          # 8/8 PASS

Test plan

  • TestOpenAPISpecParses passes (spec is valid JSON 3.1.0)
  • All 7 sibling TestOpenAPI_* gates still pass (whoami, claim flow, deploy env vars, stacks, etc.)
  • Spot-check curl http://localhost:30080/openapi.json | jq '.paths | keys | length' after deploy and confirm count jumped by ~36
  • Spot-check a couple of new schemas render in any OpenAPI viewer (Swagger UI, Redoc, etc.)

🤖 Generated with Claude Code

Audits the agent API's OpenAPI 3.1 spec against the actually-registered
routes in internal/router/router.go and fills in every gap. 36 paths
that were live but undocumented now have summary + description + auth
+ request/response schemas:

Anonymous / public:
  GET  /metrics  (Prometheus, token-gated when METRICS_TOKEN set)
  GET  /openapi.json (self-describing)
  POST /storage/new (with new StorageProvisionResponse schema)
  GET  /resources/{token}/logs (SSE pod logs for growth-tier)
  GET  /stacks/{slug}/logs/{svc} (SSE stack service logs)
  PATCH /stacks/{slug}/env (auth required)
  POST /razorpay/webhook (HMAC-verified, returns 200 to retries)
  POST /billing/checkout (legacy alias of /api/v1/billing/checkout)

Auth flow surface (browser + programmatic + magic-link + CLI device):
  POST /auth/github, GET /auth/github/start, GET /auth/github/callback
  POST /auth/email/start, GET /auth/email/callback
  POST /auth/cli, GET /auth/cli/{id}

Authenticated /api/v1 surface:
  GET    /api/v1/resources/{id}/credentials
  GET    /api/v1/team/members
  POST   /api/v1/team/members/invite
  POST   /api/v1/team/members/leave
  DELETE /api/v1/team/members/{user_id}
  GET    /api/v1/team/invitations
  DELETE /api/v1/team/invitations/{id}
  POST   /api/v1/team/invitations/{id}/accept
  GET    /api/v1/deployments
  GET    /api/v1/deployments/{id}
  DELETE /api/v1/deployments/{id}
  GET    /api/v1/stacks
  POST   /api/v1/stacks/{slug}/domains
  GET    /api/v1/stacks/{slug}/domains
  POST   /api/v1/stacks/{slug}/domains/{id}/verify
  DELETE /api/v1/stacks/{slug}/domains/{id}
  POST   /api/v1/auth/api-keys
  GET    /api/v1/auth/api-keys
  DELETE /api/v1/auth/api-keys/{id}
  GET    /api/v1/audit

Internal (dev-only) endpoints carry x-instanode-internal: true and
are clearly flagged in their description as only available when
ENVIRONMENT=development:
  POST /internal/set-tier

Adds StorageProvisionResponse and DeployItem to components.schemas.
Verified via existing TestOpenAPISpecParses gate plus all TestOpenAPI_*
sibling tests.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@mastermanas805
mastermanas805 merged commit 4ea72af into master May 11, 2026
@mastermanas805
mastermanas805 deleted the feat/openapi-completeness branch May 11, 2026 15:58
mastermanas805 added a commit that referenced this pull request Jun 2, 2026
… 404 leak, Team dedicated (#218)

* fix(api): bug-bash batch — free TTL, brevo non-clobber, dedup expiry, 404 leak, Team dedicated

Five confirmed bugs from the 2026-06-02 platform bug bash:

- #4 (P1) free-tier resources never expired: authenticated provisions
  hardcoded ExpiresAt=nil even for free/anonymous tiers. Add
  resourceExpiryForTier (24h for ephemeral tiers, nil for paid) and apply it
  at all 10 authenticated CreateResource sites. Per product decision: enforce
  plans.yaml's documented 24h TTL for claimed-unpaid resources.
- #6 (P1) Brevo 'delivered' webhook clobbered a terminal bounce/complaint on
  out-of-order delivery, corrupting the email truth surface (rule 12). Guard
  the UPDATE against terminal classes; distinguish terminal-kept from unknown.
- #17/#20 (P2) fingerprint dedup-return handed back credentials for
  active-but-expired anonymous resources: add the expires_at filter to both
  GetActiveResourceByFingerprint[Type], matching GetAllActiveResourcesByFingerprint.
- #22 (P3) deploy CancelDelete returned 403 cross-tenant (leaking existence);
  now 404 like the other deploy endpoints.
- #12 (P2) Team tier gets dedicated infra: add dedicated:true to team +
  team_yearly in plans.yaml (pairs with common defaultYAML). Per product
  decision 2026-06-02.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* test(brevo): cover #6 terminal-kept non-clobber path + fix delivered mocks

The delivered UPDATE now carries the terminal-class guard (8 args) and a 0-row
result triggers an existence probe. Update expectDeliveredUpdate to the new arg
list, add the SELECT mock to the unknown-message test, and add a terminal-kept
regression (delivered-after-bounce → matched:true, class preserved). Closes the
batch-1 patch-coverage gap on brevo_webhook.go.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* test(api): update existing tests for batch-1 behavior changes

CI (full real-DB suite) caught three existing tests that encoded the
pre-fix behavior batch-1 deliberately changed:
- TestPlansRegistry_IsDedicatedTier: team is now dedicated (#12).
- TestDeployCancelDelete_CrossTeam: cross-tenant now 404 not 403 (#22).
- TestBrevo_Receive_UnknownMessageID (billing_coverage): delivered UPDATE now
  carries the terminal-class guard (8 args) + an existence-probe SELECT (#6).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* test(brevo): cover delivered-handler SELECT-probe error branch (#218 coverage)

diff-cover flagged brevo_webhook.go:530-531 — the `if qErr != nil` arm of the
delivered handler's existence probe (bug bash #6). When the terminal-class-
guarded UPDATE affects 0 rows, a follow-up SELECT distinguishes terminal-kept
from genuinely-unknown; a non-ErrNoRows fault on that probe must surface as an
error (→ 500) so Brevo retries rather than the message being mislabeled.

Adds TestBrevo_Receive_Delivered_ProbeError (sqlmock, hermetic): UPDATE → 0
rows, SELECT probe → generic error, asserts 500.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant