-
-
Notifications
You must be signed in to change notification settings - Fork 19
Lab Anatomy
Every lab lives in its own directory after the template. The template lives
at labs/_template/. Validation skips the template and checks your copy.
labs/<track>/<lab>/
├── lab.yml # name, track, difficulty, description, flag_hash
├── README.md # player brief: story, setup, goal
├── docker-compose.yml # service definition
├── Dockerfile # pinned base image
└── app/ # lab internals; the flag lives here
Flat YAML, one key: value per line. Every field is required.
| Key | Rules |
|---|---|
name |
matches the directory name, lowercase, hyphens |
track |
one of web, binary, crypto, network, osint
|
difficulty |
one of easy, medium, hard, insane
|
description |
one line, shown in the lab index |
flag_hash |
SHA-256 of the full flag string, 64 lowercase hex |
README.md is the player-facing brief. It has three parts.
- Title with the difficulty and track.
- Brief: the story and the surface.
- Goal: how to check the solve.
The brief never contains the flag. It states the setup and the goal plainly.
docker-compose.yml defines one service with one documented host port.
Dockerfile pins a base image to a full version tag. python:3.12-alpine
is fine, python:latest is not. Prefer a digest pin when the base publishes
one.
The plaintext flag appears only in files under the lab directory that ship
the service, inside app/ and the like. It never appears in lab.yml, in
the lab README.md, or anywhere outside labs/.
CI runs the same validator you run locally.
python3 scripts/validate.pyIt checks structure, metadata, and flag hygiene. Add --compose to also run
docker compose config on every lab.
-
namematches the directory -
trackanddifficultyare valid -
flag_hashis 64 lowercase hex - no plaintext flag appears where it should not
A lab that passes validation is a lab that can merge.
openlabs is an open-source project. Code is Apache-2.0. Written content is CC-BY-4.0.