|
| 1 | +# GZCTF Challenge Base Images |
| 2 | + |
| 3 | +This repository provides **minimal Alpine-based Docker images** for CTF challenges used with GZCTF platform. Images are published to `ghcr.io/gzctf-org/challenge-base/{name}:{tag}`. |
| 4 | + |
| 5 | +## Architecture |
| 6 | + |
| 7 | +### Base Images Structure |
| 8 | +- **`base/{name}/`**: Each directory contains Dockerfiles and `config.json` defining build variants |
| 9 | +- **Multi-variant pattern**: Single base can generate multiple tagged images (e.g., `python:alpine`, `python:3.11-alpine`, `python:3.12-alpine`) |
| 10 | +- **Alpine-first**: All images target minimal size using Alpine Linux as foundation |
| 11 | + |
| 12 | +### Config-Driven Workflow System |
| 13 | +GitHub Actions workflows are **auto-generated** from `config.json` files using `scripts/gen_action.py`: |
| 14 | + |
| 15 | +```json |
| 16 | +{ |
| 17 | + "action_name": "Python 3.12", // Workflow display name |
| 18 | + "action_file": "python-3.12", // Output: .github/workflows/base.python-3.12.yml |
| 19 | + "dockerfile": "Dockerfile.3.12", // Which Dockerfile to build |
| 20 | + "tag": "3.12-alpine", // Docker tag |
| 21 | + "tier": 1, // Update tier (1 or 2) |
| 22 | + "support_multi_arch": true // Enable arm64 builds |
| 23 | +} |
| 24 | +``` |
| 25 | + |
| 26 | +**Critical**: Never manually edit `.github/workflows/base.*.yml` - regenerate via `python scripts/gen_action.py` |
| 27 | + |
| 28 | +## Key Workflows |
| 29 | + |
| 30 | +### Adding New Base Image |
| 31 | +1. Create `base/{name}/` directory with: |
| 32 | + - `Dockerfile` (or variant-specific `Dockerfile.{version}`) |
| 33 | + - `config.json` with array of build configs |
| 34 | + - Optional: `README.md` with usage example |
| 35 | +2. Run: `python scripts/gen_action.py` to generate workflows |
| 36 | +3. Commit both `base/{name}/` and generated `.github/workflows/base.{name}.yml` |
| 37 | + |
| 38 | +### Triggering Rebuilds |
| 39 | +- **Tier system**: Images are organized into tier 1 and tier 2 based on dependencies |
| 40 | + - **Tier 1**: Base images with no internal dependencies (e.g., socat, readflag, language runtimes) |
| 41 | + - **Tier 2**: Images that depend on tier 1 images (e.g., confine depends on socat, php-mariadb depends on php) |
| 42 | + - Tier separation ensures builds happen in correct order: tier 1 completes before tier 2 starts |
| 43 | +- Update trigger: `python scripts/update.py -t {1|2} -c` creates timestamp in `updates/tier{n}.md` |
| 44 | +- All workflows watch their tier file - updating it triggers rebuilds of all images in that tier |
| 45 | + |
| 46 | +### Multi-Architecture Builds |
| 47 | +- Set `"support_multi_arch": true` in config.json for `linux/amd64,linux/arm64` |
| 48 | +- Disable for architecture-specific binaries (see `readflag` using x86 assembly) |
| 49 | + |
| 50 | +## Project Conventions |
| 51 | + |
| 52 | +### CTF Challenge Pattern |
| 53 | +Images follow GZCTF conventions: |
| 54 | +- User `ctf` (UID varies by base image) |
| 55 | +- Working directory `/home/ctf` |
| 56 | +- `init.sh` script receives `$GZCTF_FLAG` env var, writes to file, unsets var |
| 57 | +- Challenge runs via socat or web server |
| 58 | + |
| 59 | +Example from `base/python/src/init.sh`: |
| 60 | +```bash |
| 61 | +echo $GZCTF_FLAG > /home/ctf/flag |
| 62 | +chmod 444 /home/ctf/flag |
| 63 | +unset GZCTF_FLAG |
| 64 | +socat TCP-LISTEN:1337,reuseaddr,fork EXEC:"python3 challenge.py" |
| 65 | +``` |
| 66 | + |
| 67 | +### Dependency Management |
| 68 | +- Workflows auto-watch: `base/{name}/**`, `updates/tier{n}.md`, own workflow file |
| 69 | +- Dependencies added via `config.json["depends_on"]` array for cross-image deps |
| 70 | + |
| 71 | +### Image Lifecycle |
| 72 | +- **Auto-cleanup**: `dataaxiom/ghcr-cleanup-action` prunes untagged/ghost/partial images after each build |
| 73 | +- **Concurrency**: Cleanup jobs use `group: cleanup-images-{name}` to prevent conflicts |
| 74 | + |
| 75 | +## Common Tasks |
| 76 | + |
| 77 | +**Test config changes locally**: `python scripts/gen_action.py` and inspect generated YAML |
| 78 | +**Force rebuild all tier 1 images**: `python scripts/update.py -t 1 -c && git push` |
| 79 | +**Check existing variants**: Review `base/{name}/config.json` for tag/Dockerfile mappings |
| 80 | +**Debug workflow**: Check `base/{name}/**` paths in generated workflow match actual files |
0 commit comments