Files
rootnode-academy/platform
ced4568 ae75bb4cbe feat(auth): add server-controlled student and admin sessions
Replaces the Phase 2A pilot ?sid= query param with an HttpOnly,
SameSite=Lax session cookie. Gateway now derives student identity from
the session (via Platform API's /api/session/whoami) instead of trusting
a client-suppliable id, and checks ownership on every proxied HTTP and
WebSocket Lab request, not just the initial navigation.

Fixes a routing bug found during testing: the fallback route was using
'does this session own a running environment' to decide whether an
unprefixed /api/* call belonged to the Lab UI or the dashboard — true in
both places. Replaced with an explicit LAB_OWNED_PATHS allowlist of the
exact unprefixed paths the existing Lab UI actually calls.

e2e-phase2a.js rewritten to use a cookie jar instead of headers/query
params, with explicit impersonation-rejection tests added. 10/10 passing.
2026-08-18 12:22:58 -05:00
..

RootNode Academy — Platform

The full multi-student platform, layered on top of the unmodified Lab image at the repo root. Start here, then go to the component you need:

  • provisioner/ — Postgres-backed environment registry and lifecycle. Design: docs/LAB_ARCHITECTURE.md, docs/PHASE1_PLATFORM_FOUNDATION.md. Operational reference: provisioner/README.md.
  • gateway/ — the only student-facing path to a Lab (HTTP + WebSocket proxy, environment-aware routing, student identity glue). Design: docs/PHASE2A_GATEWAY_AND_STUDENT_FLOW.md.
  • egress-proxy/ — shared allowlisting proxy every Lab's outbound traffic passes through.
  • docker-compose.dev.yml — the full stack (Postgres, egress proxy, Provisioner, a persistent "identity" instance, Gateway) on one machine. This is the Phase 1/2A local dev exception — production is the two-VM Proxmox split described in docs/LAB_ARCHITECTURE.md §1.

Running the full stack locally

cd platform
echo "PROVISIONER_SHARED_SECRET=$(openssl rand -hex 32)" > .env
docker compose -f docker-compose.dev.yml build
docker compose -f docker-compose.dev.yml up -d

Wait for identity to boot (it runs a real k3s cluster, same as any Lab — check with curl http://localhost:7554/api/health), then the whole platform is reachable at http://localhost:4200 (the Gateway) — that's the one origin a student's browser would use.

Tests

  • provisioner/test/run.js — fast, isolated Provisioner tests (network/container/firewall mechanics, no Gateway/identity involved). Run against provisioner/docker-compose.dev.yml.
  • test/e2e-phase2a.js — slow, full-stack tests against the compose file above: roster → login → curriculum → launch → Gateway routing → cross-student rejection → progress relay → reset. Real k3s boots, budget several minutes. Run whenever the Gateway, Provisioner API surface, or the identity backend's progress/roster/curriculum routes change.

Neither substitutes for the manual real-Lab-image checks (node-pty, terminal WebSocket, kubectl, scenario validation) in docs/PHASE2A_GATEWAY_AND_STUDENT_FLOW.md §8 — those need a browser-equivalent client and aren't automated here.

Known limitations

See provisioner/README.md (Phase 1) and docs/PHASE2A_GATEWAY_AND_STUDENT_FLOW.md §9 (Phase 2A) for the full, honest lists — including the identity service's network_mode: bridge requirement and its unused-k3s resource cost, both flagged as real, not swept under the rug.