Component · control-plane/

control-plane

The hub. A Fastify REST API in front of an orchestrator that drives the session lifecycle through a pluggable backend, mints and withholds credentials, records an immutable audit log, streams over SSE, and enforces org-scoped tenancy. Everything else is a client of this.

Role in the architecture#

The control plane is the single place session logic lives. It boots in src/index.ts, registers routes in server.ts, and delegates the lifecycle to orchestrator.ts; backends live under src/backends/.

Source
control-plane/src/index.ts (boot) → server.ts (routes) → orchestrator.ts; backends in src/backends/ (backend.ts, simulator.ts, docker.ts, kubernetes.ts, factory.ts).

REST routes#

Every session route is authenticated and scope-guarded. Full detail on the REST API page.

MethodPathScopePurpose
GET/healthznoneLiveness + backend reachability.
POST/sessionssessions:writeCreate + run a session.
GET/sessionssessions:readList sessions in the caller's org.
GET/sessions/:idsessions:readStatus — no token field, no brokered secret.
GET/sessions/:id/resultsessions:readStructured result.
GET/sessions/:id/auditsessions:readImmutable audit trail.
GET/sessions/:id/streamsessions:readLive SSE stream.
DELETE/sessions/:idsessions:writeTeardown.

Orchestrator#

The Orchestrator owns the session lifecycle end to end. Every accessor funnels through an org-scoped ownedBy() check — the single tenancy enforcement point.

createSession(req: CreateSessionRequest, principal: Principal): Promise<Session>
Validates the request, stamps orgId/createdBy, and hands the LaunchSpec to the backend. No token is placed on the public Session.
getSession(id, principal) · listSessions(principal)
Org-scoped reads. A cross-org lookup never reveals existence.
getAudit(id, principal) · teardown(id, principal)
Org-scoped audit fetch and idempotent teardown.
publicView(session): Session  // = structuredClone(session)
The only view ever returned. Because the token is never on the Session type, the clone structurally cannot leak it.

SessionBackend#

The whole control plane is backend-pluggable behind one interface. The orchestrator builds a LaunchSpec and reports progress via a BackendEventSink — both backend-agnostic.

control-plane/src/backends/backend.tsts
interface SessionBackend {
  readonly name: string;
  // Launch the session; returns once accepted, runs async via the sink.
  launch(spec: LaunchSpec, sink: BackendEventSink): Promise<void>;
  // Reclaim all resources for a session. Idempotent.
  teardown(sessionId: string): Promise<void>;
  // Optional readiness probe.
  health?(): Promise<{ ok: boolean; detail?: string }>;
}

interface LaunchSpec {
  sessionId: string;
  code: string;
  language: "python" | "node";
  limits: Required<SessionLimits>;
  egress: EgressPolicy;
  serviceBindings?: string[];   // injected at the egress proxy, not in the sandbox
}

interface BackendEventSink {
  phase(phase: SessionPhase, info?: { killReason?: KillReason }): void;
  stdout(chunk: string): void;
  stderr(chunk: string): void;
  egress(host: string, allowed: boolean): void;
  result(result: SessionResult): void;
}

Credential broker#

For a private-repo git source, the broker mints a short-lived scoped git token. It is mounted only on the clone init-container, withheld from the workload pod, and never returned to the caller. No token is ever placed on the public Session.

issueGitToken(sessionId, scopes, ttlSeconds?): { token: string }
The token lives only in the clone init-container's env Secret — it never crosses into the workload or any public surface.

Auth & tenancy#

An auth hook verifies a user JWT (HS256, ENCLAVE_JWT_SECRET) or an API key (introspected against console-api) and sets req.principal. Each route then calls authorize(req, reply, scope) before doing work, and the orchestrator filters by orgId. A dev bypass exists only when ENCLAVE_AUTH_DISABLED=1, is never the default, and is loudly logged.