WRK-02Record
CodeFlow
Gamified backend-dev learning platform. I built the Kubernetes/gVisor sandbox that runs student code safely, and the in-browser IDE on top of it.
- Status
- Pre-launch — repository private; hardened execution path built but not yet the default
- Updated
- Stack
- FastAPIKubernetesgVisorNext.js 15Monaco EditorPostgreSQL
What it is
CodeFlow teaches backend and API development as a lesson loop: build a small FastAPI endpoint, watch a bot sabotage one line, predict the symptom, explain the break, get graded. It is a team project — roughly six or seven collaborators — and my slice is the part that has to run other people’s code. I built the sandboxed workspace infrastructure, the browser IDE on top of it, the async job pipeline that keeps untrusted execution off the request path, and a pre-launch security audit across all of it. I also led the frontend migration from a Vite SPA to Next.js 15.
How it works
Workspace pods run under gVisor’s runsc userspace kernel rather than a bare container
boundary, in a namespace separate from the control plane: no service-account token, no
network path to Postgres, no shared filesystem. A WorkspaceOrchestrator seam selects
between a mock implementation and the real Kubernetes one from a single environment
variable, so the rest of the team could build against workspaces locally without a
cluster. The browser side pairs Monaco with xterm over a WebSocket bridge to the pod’s
exec stream. Both the interactive workspace and the grading pipelines are
enqueue-and-poll — the backend never executes untrusted code inline inside an HTTP
handler.
Notable decisions
The isolation runtime is one field on the pod spec, so moving to a stronger microVM boundary later is a config change rather than an application rewrite. The separation between control plane and execution plane is enforced by manifests — Pod Security Admission, default-deny NetworkPolicy, ResourceQuota, least-privilege RBAC — and documented as a review checklist rather than tribal knowledge.
Current state
Pre-launch, and the audit I wrote says the honest thing: the hardening is real in code and matches the documented threat model, but as of that audit it was not yet the default running path — the orchestrator still defaulted to the mock implementation and the Kubernetes path had not been validated against a live cluster. The follow-up commit moved the last synchronous execution endpoint to enqueue-and-poll and added a fail-fast production config guard. Standing up and validating the real cluster path end to end is still open.