A self-hosted C programming platform. Students write C in the browser and get immediate feedback from private tests, run in an isolated sandbox.
CTester ships no exercises: a separate content repository supplies them, and the engine reads it
without knowing anything about the course inside. See docs/content/format.md
for the format, and scripts/demo_content.py for a runnable example of it.
It was built for TCH009 at ÉTS, which is one deployment.
- Browser C editor with multi-file exercises, syntax hints and IDE shortcuts
- Three grading modes: quizzes, stdin/stdout programs, Unity unit tests
- An interactive Console to run any C program and type into it
- Drafts, progress tracking, skills and achievements
- A moderated help forum and chat, optionally bridged to Discord
- Team assignments with live collaborative editing, revision history and ZIP hand-in
- Course content published independently of the application, with scheduled releases
- Interface in English and French, chosen per student; a language is one JSON file (docs/translations.md)
flowchart LR
B["Browser<br/>Svelte (GitHub Pages)"]
A["API<br/>FastAPI"]
Q[("Spool")]
W["Host judge<br/>judge/ (Rust)"]
S["Sandbox<br/>Docker + gVisor"]
DB[("PostgreSQL")]
B -->|HTTP / WebSocket| A
A --> DB
A -->|job files| Q
W -->|claims jobs| Q
W --> S
The API never compiles or runs code and cannot read the tests. It writes a job to the spool and returns immediately. A worker on the host claims the job, judges it in a disposable container with no network, and writes the verdict back for the browser to poll.
Course content lives in a separate private repository. worker/publish_content.py validates it and writes a
versioned public projection. current.json points at the active release, so a rollback is a pointer
change.
app/ FastAPI application (routers = HTTP, services = logic, state.py = SQL)
frontend/ Svelte 5 + TypeScript page, built with Vite
judge/ host judge (Rust): queue, sandbox, verdicts, verdict cache, console sessions
worker/
judge.py the judge's grading rules, for the content tools
local_build.py the sandbox build scripts, run on the host, for those tools
content_catalog.py content validation and access rules
publish_content.py release publication and rollback
typst_build.py Typst statement rendering
build-*.sh what runs inside the sandbox for each mode
scripts/
validate_content.py content validation
verify_content.py reference solutions against their tests
render_statement.py local Typst preview
import_teams.py team roster corrections
load_test.py load testing
deploy/ Compose stack, systemd units, update scripts, env.example
tests/ backend, sandbox and PostgreSQL checks
bot/bridge.py Discord bridge
typst/ statement template and vendored Typst packages
docs/ operations, content format, Typst and translation guides
pip install -r requirements-dev.txt
npm ci
npm run check && npm run build && npm test
python3 tests/test_ctester.py
python3 tests/test_api.pyRun the page and API locally against published content:
python3 scripts/demo_content.py --out /tmp/demo # or your own content repository
CTESTER_KEY=dev CTESTER_PUBLISHED=/tmp/demo/published CTESTER_PAGE=frontend/dist python3 app/main.pyReal verdicts also need a worker, which requires Docker and gVisor. See docs/operations.md for the full list of checks, deployment and troubleshooting.
| Layer | Technology |
|---|---|
| Backend | Python 3.13, FastAPI, Uvicorn |
| Frontend | Svelte 5, TypeScript, Vite |
| Database | PostgreSQL |
| Execution | Rust judge, Docker + gVisor |
| Collaboration | Yjs over WebSocket |
| Deployment | Compose, systemd, GitHub Pages |