Skip to content

feat(api): add stateless deploy endpoint (POST /api/deploy)#11

Merged
Che-Zhu merged 4 commits into
mainfrom
feat/stateless-deploy-api
May 27, 2026
Merged

feat(api): add stateless deploy endpoint (POST /api/deploy)#11
Che-Zhu merged 4 commits into
mainfrom
feat/stateless-deploy-api

Conversation

@Che-Zhu

@Che-Zhu Che-Zhu commented May 27, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • New POST /api/deploy SSE endpoint that accepts kubeconfig + GitHub token + repo URL, drives the full deployment pipeline (Devbox → Codex Gateway → brain-github-deploy skill → BuildKit → GHCR push), and returns Crossplane AP YAML — all without any database persistence
  • Zero-session design: authenticates via kubeconfig → AIProxy token, bypasses GitHub OAuth entirely
  • Client disconnect handling via AbortController triggers Gateway turn interruption and Devbox cleanup

Changes

New files (6):

  • app/api/deploy/route.ts — SSE endpoint with input validation, GitHub URL restriction, AbortController
  • lib/deploy-api/types.ts — DeployPhase, DeployErrorCode, DeployError class
  • lib/deploy-api/auth.ts — kubeconfig → AIProxy → GatewayConfig
  • lib/deploy-api/orchestrator.ts — Core orchestration with abort support and phase tracking
  • lib/deploy-api/prompt.ts — Deploy prompt with Sealos context injection
  • lib/deploy-api/result-parser.ts — Reads deployment-output.json + ap.yaml from Devbox

Modified files (1):

  • lib/devbox/runtime.ts — Skill marker changed from sealos-deploy to brain-github-deploy; added post-install verification

Documentation (1):

  • DEPLOY_API.md — Full technical documentation (API contract, auth flow, architecture, error codes)

Test plan

  • pnpm type-check passes (verified)

  • pnpm lint passes with 0 errors (verified)

  • pnpm format:check passes (verified)

  • Manual test: invalid kubeconfig → 401 JSON response, no Devbox created

  • Manual test: non-GitHub repoUrl → 400 JSON response

  • Manual test: valid inputs → SSE stream with progress events → complete event with YAML

  • Manual test: client disconnect during execution → Devbox cleaned up

    🤖 Generated with [Qoder][https://qoder.com]

Che-Zhu added 3 commits May 27, 2026 11:11
New POST /api/deploy endpoint that accepts kubeconfig, GitHub token,
repo URL, and branch, then drives the full deployment pipeline without
any database persistence:

- Authenticates via kubeconfig → AIProxy token (no OAuth/cookie required)
- Creates an in-memory fake Task to reuse ensureTaskDevboxRuntime
- Provisions Devbox runtime, clones repo, installs brain-sandbox-skills
- Starts Codex Gateway session and sends brain-github-deploy prompt
- Polls for AI turn completion, streams progress via SSE
- Extracts deployment-output.json and crossplane/ap.yaml from Devbox
- Returns image ref + Crossplane AP YAML in the final SSE event
- Cleans up Gateway session and Devbox in the finally block

New files:
- app/api/deploy/route.ts
- lib/deploy-api/auth.ts
- lib/deploy-api/orchestrator.ts
- lib/deploy-api/prompt.ts
- lib/deploy-api/result-parser.ts
- lib/deploy-api/types.ts

🤖 Generated with [Qoder][https://qoder.com]
Documents the stateless deploy API endpoint including:
- API contract (request/response/SSE events)
- Authentication design (kubeconfig → AIProxy)
- Zero-persistence strategy (in-memory fake Task)
- Full execution flow diagram
- brain-github-deploy skill phase overview
- Module structure and dependency graph
- Crossplane AP YAML format reference
- Timeout and resource management table
- Design decision rationale

🤖 Generated with [Qoder][https://qoder.com]
P1 - Skill marker now checks brain-github-deploy (was sealos-deploy):
  - lib/devbox/runtime.ts: change agent/codex skill markers from
    sealos-deploy/SKILL.md to brain-github-deploy/SKILL.md so that
    repos with an older sealos-deploy install correctly trigger
    reinstallation of brain-sandbox-skills
  - Added post-install verification: bootstrap exits non-zero if
    brain-github-deploy/SKILL.md is still absent after running
    the install command

P1 - Devbox cleanup is now awaited:
  - lib/deploy-api/orchestrator.ts: await deleteDevbox() with a
    static error log on failure; cleanup always completes before
    the SSE stream closes

P1 - Client disconnect now aborts the deployment:
  - app/api/deploy/route.ts: AbortController triggered by both
    ReadableStream.cancel() and req.signal (request disconnect)
  - lib/deploy-api/orchestrator.ts: accepts AbortSignal, checks
    abort before each poll, calls interruptCodexGatewayTurn() then
    throws DeployError('aborted') for prompt cleanup

P2 - repoUrl validated as GitHub HTTPS URL:
  - app/api/deploy/route.ts: GITHUB_REPO_URL_PATTERN regex rejects
    any URL that is not https://github.com/{owner}/{repo}[.git]

P2 - Error events now include stable code and phase:
  - lib/deploy-api/types.ts: add DeployErrorCode type and DeployError
    class; update DeployErrorEvent to include code + phase fields
  - lib/deploy-api/result-parser.ts: throw DeployError with
    appropriate code (build_failed, result_missing) instead of
    plain Error
  - lib/deploy-api/orchestrator.ts: track currentPhase, propagate
    code/phase to error SSE event; map unknown errors to
    internal_error code

🤖 Generated with [Qoder][https://qoder.com]

if (
combined.includes('buildkit') ||
combined.includes('ghcr.io') ||

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 82c4b3e387

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread app/api/deploy/route.ts
const abortController = new AbortController()

// Propagate request-level disconnect signal
req.signal.addEventListener('abort', () => abortController.abort(), { once: true })

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Handle already-aborted requests before starting work

If the client disconnects while validateKubeconfig() is still awaiting the AIProxy network call, req.signal is already aborted by the time this listener is added, and abort listeners are not invoked retroactively. In that case the handler still creates the SSE stream and starts runDeployOrchestration(), which can provision a Devbox and run the deployment even though there is no client left to receive it; check req.signal.aborted immediately after auth (or wire the signal into auth) before launching orchestration.

Useful? React with 👍 / 👎.


sendEvent('complete', result)
} catch (error) {
console.error('Deploy orchestration error:', error)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid logging dynamic deployment errors

AGENTS.md forbids dynamic values in console.* logs outside the approved task-flow logging utility, and this catch logs the full runtime error for an endpoint that handles user-supplied kubeconfigs, GitHub tokens, repo URLs, and gateway/devbox diagnostics. When a Devbox/Gateway failure includes request details or tool output, this bypasses the static-log/redaction policy; keep the log message static or explicitly sanitize before logging.

Useful? React with 👍 / 👎.

@Che-Zhu Che-Zhu merged commit 8acde00 into main May 27, 2026
4 of 5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants