Files
challenge_status_tracker/README.md
T
Casually9790andClaude Opus 5.5 e00f40eaf4 Split ctf_status.py into a tracker package, config from .env only
ctf_status.py is now just the command line; the work lives in tracker/.
The rules that decide whether a challenge is believed are in
tracker/checks.py, one function per rule, listed in README_CHECKS and
REPO_CHECKS. Output is unchanged.

Read the config from .env only (ctf_status.env.example -> .env.example),
let single_run_lock() hold its own lock files, and rewrite the README as
a short overview of what the repo does and how to run it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 19:40:24 +02:00

127 lines
4.4 KiB
Markdown

# CTF challenge status tracker
Tracks the progress of the h4tum CTF challenges. It reads every repo in the
GitLab challenges group, works out each challenge's status, category and
difficulty from its `README.md`, and checks that challenges marked as ready
really are. The result goes to:
- **a HedgeDoc note**: an overview of all challenges, refreshed every 30 minutes
- **`challs.txt` in the deployment repo**: the clone URLs of every challenge
ready for infra testing, updated daily
- **the terminal**: the same overview, for a quick look
## Requirements
- Python 3.9+
- [`requests`](https://pypi.org/project/requests/) and [`PyYAML`](https://pypi.org/project/PyYAML/)
(`python-requests python-yaml` on Arch, `python3-requests python3-yaml` on Debian)
## Configuration
```sh
cp .env.example .env && chmod 600 .env
```
| Key | Required | Meaning |
|---|---|---|
| `GITLAB_GROUP_URL` | yes | GitLab group that holds one repo per challenge |
| `GITLAB_TOKEN` | yes | Personal access token, see below |
| `HEDGEDOC_NOTE` | for `--update` | URL of an existing note; its permission must be **freely** |
| `HEDGEDOC_TAGS` | no | Tags written into the note's front matter |
| `CHALLS_REPO_URL` | for `--challs` | Deployment repo that holds `challs.txt` |
| `CHALLS_PATH` | no | Path of the file in that repo (default `2026/challs.txt`) |
| `CHALLS_BRANCH` | no | Branch to commit to (default: the repo's default branch) |
The token needs **Project: Read** and **Repository: Read** on the challenges
group. For `--challs` it also needs **Repository: Read + Write** on the deployment
repo, and permission to push to the branch if it is protected.
Environment variables override the values in `.env`.
## Usage
```sh
./ctf_status.py # print the overview
./ctf_status.py -o overview.md # also write the note's markdown to a file
./ctf_status.py --update # overwrite the HedgeDoc note
./ctf_status.py --challs # commit challs.txt, if it changed
./ctf_status.py -q --challs-out - # preview challs.txt without committing
```
`./ctf_status.py --help` lists all options. With `--quiet`, a run prints nothing
unless something changed or failed.
## Deployment
On the server, with `.env` in place:
```sh
./install-timer.sh
```
This installs and starts two systemd user timers:
| Timer | Runs | Does |
|---|---|---|
| `ctf-status.timer` | every 30 minutes | `--update`: refresh the HedgeDoc note |
| `ctf-challs.timer` | daily at 04:00 | `--challs`: commit `challs.txt` |
Re-running the script is safe. To check on the timers:
```sh
systemctl --user list-timers 'ctf-*'
journalctl --user -u ctf-status.service -n 50
journalctl --user -u ctf-challs.service -n 50
```
## How challenges are evaluated
Each challenge repo starts from a template whose README begins with:
```
### Challenge Name
- Category: crypto
- Difficulty: medium
- Event: ...
- Author: ...
- Tester: ...
- Status: Testing Ready
```
The status is one of **Planning → PoC Draft → Testing Ready → Tested → Ready**.
Loosely written values are normalised. If a status names several stages, the
least advanced one counts.
Two kinds of finding are reported:
- **Problems** are missing or unclear README fields, such as no category, an
unreadable status, or a Testing Ready challenge with no tester. They are
listed under *Needs attention* and change nothing else.
- **Blockers** are signs that a challenge claiming Testing Ready or beyond is not
actually finished: `description.yml` is missing or still the template, its
category or flag is wrong, a `deploy_dir` or its `Dockerfile` is missing, or
there is no `solve.py`. A blocked challenge (⛔) is kept out of `challs.txt`.
Passing every check does not prove that a challenge builds or solves. That is
what testing is for.
All rules are in [`tracker/checks.py`](tracker/checks.py), one function each.
## Project layout
```
ctf_status.py command line entry point
tracker/
checks.py the rules: README problems and repo blockers
challenge.py reads a README header into a Challenge
gitlab.py GitLab API access
overview.py runs parsing and checks over all repos
terminal.py terminal output
markdown.py HedgeDoc note
challs.py challs.txt
hedgedoc.py writes the note to HedgeDoc
config.py reads the configuration
install-timer.sh installs the systemd units below
ctf-*.service/.timer systemd unit templates
```