Spaces:
Sleeping
Sleeping
File size: 9,819 Bytes
73b272a 80a4a65 04fc815 80a4a65 73b272a | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 | ---
title: CyberArena Backend
emoji: π‘οΈ
colorFrom: purple
colorTo: blue
sdk: docker
app_port: 7860
pinned: false
license: mit
---
# CyberArena β Backend
> FastAPI backend for the CyberArena cybersecurity training platform.
> Single source of truth: this directory. The old `Apex/backend/` has
> been removed.
## Quick start
```bash
cd CyberArena
pip install -r requirements.txt
python main.py # serves on http://localhost:8090
```
The server loads `.env` automatically from this folder.
## Project layout
```
CyberArena/
βββ main.py β 5-line uvicorn entry
βββ requirements.txt
βββ Dockerfile
βββ start.cmd
β
βββ app/ β all real code
β βββ main.py β FastAPI app, middleware, startup
β βββ types.py β Pydantic request models
β β
β βββ core/ β constants + pure helpers (no I/O)
β β βββ config.py β env-loaded handles (Supabase, AI URLs, keys)
β β βββ constants.py β topic catalog, fallback HTML, cert config
β β βββ security.py β normalize_vuln_key, ip/ioc/time matchers
β β βββ text.py β parse_json_safe (LLM JSON parser)
β β βββ module_router.py β module β challenge_type dispatcher
β β
β βββ services/ β business logic / I/O
β β βββ supabase_service.py β PostgREST client (CRUD on pool tables)
β β βββ challenge_loader.py β row β TrainingData mappers (per type)
β β βββ scenario_service.py β Groq scenario + challenge generation
β β βββ evaluator.py β /evaluate handlers (5 types)
β β βββ completion_service.py β user_completions idempotent tracker
β β βββ certificate_service.py β PDF build + cert issue/verify/download
β β βββ file_storage.py β write downloadable files to disk
β β
β βββ generators/ β per-type AI pool generators
β β βββ __init__.py β REGISTRY: list of (slug, module, teams)
β β βββ crypto.py β owns encryption_challenges
β β βββ code_fixing.py β owns code_fixing_challenges
β β βββ log_analysis.py β owns log_analysis_challenges
β β βββ vulnerability_hunter.py β owns vulnerability_hunter_challenges
β β
β βββ sandbox/ β in-process OS simulator sandbox
β β βββ workdir.py β per-challenge tempdir + safe_join
β β βββ tools.py β built-in cat/ls/sha256sum/base64/β¦
β β βββ terminal.py β shlex parse + whitelist subprocess run
β β
β βββ api/ β FastAPI routers (HTTP shell only)
β βββ auth.py β /api/auth
β βββ xp.py β /api/xp
β βββ leaderboard.py β /api/leaderboard
β βββ certificates.py β /api/certificates*
β βββ training.py β /api/training/*
β βββ terminal.py β /api/training/terminal*
β βββ onevone.py β /api/onevone/* (head-to-head matches)
β
βββ db/ β all database concerns
β βββ schema/ β numbered, idempotent SQL migrations
β β βββ 000_extensions.sql
β β βββ 001_users.sql
β β βββ 002_encryption_challenges.sql
β β βββ 004_code_fixing_challenges.sql
β β βββ 005_log_analysis_challenges.sql
β β βββ 006_vulnerability_hunter_challenges.sql
β β βββ 007_onevone.sql
β β βββ 008_certificates.sql
β β βββ 009_user_completions.sql
β β βββ 010_challenge_files_bucket.sql
β β βββ 011_challenge_type_normalization.sql
β β βββ 012_onevone_vuln_hunter.sql
β βββ seed/ β per-type example JSON (template)
β β βββ README.md
β β βββ crypto.example.json
β β βββ web.example.json
β β βββ code_fixing.example.json
β β βββ log_analysis.example.json
β β βββ vulnerability_hunter.example.json
β βββ apply.py β apply every schema/*.sql in order
β βββ README.md
β
βββ scripts/ β ops utilities
β βββ check_state.py β one-page DB health report
β βββ seed_pools.py β pool size + status (read-only by default)
β
βββ .env β secrets (never commit)
βββ README.md
> **No local file storage.** AI-generated challenge files are uploaded
> to the `challenge-files` Supabase Storage bucket (see
> `db/schema/010_challenge_files_bucket.sql`) and the public URL is
> returned in the training payload. The backend never writes to its
> own disk.
```
## API surface
The FastAPI app exposes **28 routes** under `/api/`. The full list
lives in `app/main.py`; the most important are:
| Method | Path | Notes |
|--------|-------------------------------------|-------|
| POST | `/api/auth` | proxied to Supabase `apex-auth` edge function |
| POST | `/api/xp` | proxied to Supabase `apex-xp` edge function |
| GET | `/api/leaderboard` | top users by XP |
| GET | `/api/training/list` | dashboard cards |
| POST | `/api/training/generate` | hydrate cached scenario into a full challenge |
| POST | `/api/training/evaluate` | legacy red+blue AI evaluator |
| POST | `/api/training/evaluate-web` | 3-layer web exploitation validator |
| POST | `/api/training/evaluate-code-fix` | AI code-fix grader |
| POST | `/api/training/evaluate-log-analysis` | 4-field exact match + Mistral feedback |
| POST | `/api/training/evaluate-vulnerability-hunter` | exact canonical-key match |
| POST | `/api/training/terminal*` | OS simulator sandbox |
| POST | `/api/certificates` | list / issue |
| GET | `/api/certificates/{id}/pdf` | streamed PDF |
| GET | `/api/certificates/verify/{code}` | public QR landing |
| GET | `/api/certificates/progress` | (completions, required) |
| POST | `/api/onevone/rooms` | 1v1 mode (see `app/api/onevone.py`) |
## Pool architecture
Each challenge type owns its own table + its own generator. The
orchestrator in `app/main.py::populate_pool_background` walks
`app.generators.REGISTRY` and starts one watcher per (type, team).
Pool model: `POOL_TARGET / POOL_THRESHOLD / POOL_BATCH` are module
constants inside each generator. The watcher refills the table
when the count drops to `POOL_THRESHOLD` and inserts `POOL_BATCH` new
rows in parallel via `asyncio.gather`.
See `../AGENTS.md` "Pool Architecture" for the full contract.
## Database
Apply the migrations to Supabase with:
```bash
python db/apply.py # needs SUPABASE_SERVICE_KEY in .env
```
Each `.sql` file is idempotent (`CREATE β¦ IF NOT EXISTS`, `DROP
POLICY IF EXISTS + CREATE`). See `db/README.md` for details.
## Running tests
There is no formal test suite yet. Use:
```bash
python -c "from app.main import app; print(len(app.routes), 'routes')"
python scripts/check_state.py # requires SUPABASE_URL
```
## Deployment
The provided `Dockerfile` pins `python:3.11-slim` and starts the
server on `PORT` (default 7860, matches Hugging Face Spaces).
### Hugging Face Spaces (Docker SDK)
1. Create a new Space β **Docker** SDK.
2. Push this folder (`CyberArena/`) to the Space's git remote:
```bash
cd CyberArena
git remote add hf https://huggingface.co/spaces/Alpha-Team/CyberArena
git push hf main
```
3. In the Space's **Settings β Repository secrets**, add every key
the backend needs. HF injects them as environment variables
(the loader in `app/_env.py` does **not** override process env,
so secrets take priority over any `.env` shipped in the repo).
| Secret | Required |
|---|---|
| `SUPABASE_URL` | yes |
| `SUPABASE_ANON_KEY` | yes |
| `CLOUDFLARE_API_TOKEN` | yes (primary AI) |
| `CLOUDFLARE_ACCOUNT_ID` | yes |
| `CLOUDFLARE_MODEL` | optional (default `@cf/qwen/qwen2.5-coder-32b-instruct`) |
| `GROQ_API_KEY` | yes (fallback AI) |
| `GROQ_MODEL` | optional (default `llama-3.1-8b-instant`) |
| `NVIDIA_API_KEY` | yes (tertiary AI) |
| `NVIDIA_MODEL` | optional (default `deepseek-ai/deepseek-v4-pro`) |
| `MISTRAL_API_KEY` | yes (quaternary AI + vuln-hunter grader) |
| `MISTRAL_MODEL` | optional (default `mistral-small-latest`) |
4. The Space URL will be `https://<user>-<space>.hf.space`. The
frontend's `VITE_API_URL` must be set to that URL + `/api`
(e.g. `https://alpha-team-cyberarena.hf.space/api`).
5. **Workdir caveat**: per-challenge user scripts (`solve.py`, β¦)
live in `tempfile.mkdtemp()` on the container's `/tmp`. The
container's disk is **lost on Space sleep / restart**, but
challenge data and user XP live in Supabase and persist.
6. The Space can sleep after 48h of inactivity. To stay always-on,
upgrade the Space's hardware tier or wake it manually before
class.
> The `.env` file is **never** uploaded β it's listed in
> `.dockerignore`. The HF secrets panel is the only source of
> environment variables in production.
|