Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
0496d27
Move src/* files under src/challenge_toolkit/
VaiTon Feb 3, 2026
182ece0
Wrap CLI entry in main function
VaiTon Feb 3, 2026
f202e94
Qualify library imports with package name
VaiTon Feb 3, 2026
5ccffad
Add pyproject, lockfile, and package skeleton
VaiTon Feb 3, 2026
253fda8
Update README with package install instructions
VaiTon Feb 3, 2026
1cc36b8
Delete src/requirements.txt
VaiTon Feb 3, 2026
31316b6
Update README pt.2
VaiTon Feb 3, 2026
aa4e428
Remove challenge-toolkit entry from README
VaiTon Feb 3, 2026
56a9efc
Use hatchling as build backend, update pyproject metadata
VaiTon Feb 3, 2026
3020cd2
Remove Git submodule instructions from README
VaiTon Feb 3, 2026
205e2a8
Update author / maintainer email
VaiTon Feb 3, 2026
570ff4b
Bump version to 1.1.3-dev
VaiTon Feb 3, 2026
e1af12c
Update project URLs in pyproject.toml
VaiTon Feb 3, 2026
9cdd327
Update usage wording in README.md
VaiTon Feb 3, 2026
57cdf3a
Mention example templates directory in README
VaiTon Feb 3, 2026
e7e8fcb
Remove template copy example from README
VaiTon Feb 3, 2026
64bd521
Rename CLI from ctf-toolkit to challenge-toolkit
VaiTon Feb 3, 2026
e0ff79c
Recommend pinning install version in README
VaiTon Feb 3, 2026
dd133e2
Rename ctf module to cli and update entrypoint
VaiTon Feb 3, 2026
58a205e
feat: switch package to be installed as `challenge-toolkit` through p…
The0mikkel Feb 3, 2026
4106b74
Merge branch 'main' into develop
The0mikkel Feb 3, 2026
4175a58
Rename dataTest.py to test_data.py
VaiTon Feb 3, 2026
ce7bdee
Add pytest to dev dependency group
VaiTon Feb 3, 2026
fbc253a
Remove obsolete test runner script
VaiTon Feb 3, 2026
64a277c
Move tests to top-level tests and fix data location in test_data.py
VaiTon Feb 3, 2026
92a5e6e
Use pathlib for test data path
VaiTon Feb 3, 2026
13dd00f
Enable pytest importlib import mode
VaiTon Feb 3, 2026
45f51fc
Replace '/' operator with joinpath in test_data.py
VaiTon Feb 3, 2026
6f87a8c
Add Running tests section to README
VaiTon Feb 3, 2026
96fc932
feat(test): add pytest with uv (#19)
The0mikkel Feb 3, 2026
dc3a9ed
Add GitHub Actions CI workflow
VaiTon Feb 3, 2026
690654a
Pin GitHub Actions to specific SHAs
VaiTon Feb 3, 2026
e689ebe
feat(ci): add automated testing across python 3.10-3.14 (#22)
The0mikkel Feb 3, 2026
226dd56
chore(ci): add missing permissions for CI workflow
The0mikkel Feb 3, 2026
7187d4a
feat(release): add automatic update of version in pyproject.toml
The0mikkel Feb 5, 2026
1fd65ee
refactor(release): reorder GitHub plugin configuration in .releaserc.…
The0mikkel Feb 5, 2026
c2652cc
chore(release): update release workflow to use stable version v1.4.0
The0mikkel Feb 5, 2026
a889df6
Add automatic update of version in pyproject.toml (#23)
The0mikkel Feb 5, 2026
d63c6ea
chore(release): 1.2.0-rc.1 [skip ci]
semantic-release-bot Feb 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
name: CI

on:
push:
branches:
- main
- develop
pull_request:
branches:
- main
- develop

jobs:
build:
name: Build and Test
runs-on: ubuntu-latest
permissions:
contents: read

strategy:
matrix:
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
fail-fast: false

steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6

- name: Install uv
uses: astral-sh/setup-uv@803947b9bd8e9f986429fa0c5a41c367cd732b41 # v7
with:
enable-cache: true

- name: Set up Python
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6
with:
python-version: ${{ matrix.python-version }}

- name: Install the project
run: uv sync --locked --all-extras --dev

- name: Build project
run: uv build

- name: Run tests
run: uv run pytest

- name: Minimize uv cache
run: uv cache prune --ci
4 changes: 3 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@ on:
jobs:
release:
name: Release
uses: ctfpilot/ci/.github/workflows/release.yml@v1.3.0
uses: ctfpilot/ci/.github/workflows/release.yml@v1.4.0
permissions:
contents: write
packages: write
id-token: write
secrets:
RELEASE_GH_TOKEN: ${{ secrets.RELEASE_GH_TOKEN }}
PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }}
with:
repository: ctfpilot/challenge-toolkit
plugins: "semantic-release-pypi"
ENVIRONMENT: Release
51 changes: 51 additions & 0 deletions .releaserc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
{
"branches": [
"main",
{
"name": "develop",
"prerelease": "rc"
}
],
"plugins": [
[
"@semantic-release/commit-analyzer",
{
"preset": "conventionalcommits"
}
],
[
"@semantic-release/release-notes-generator",
{
"preset": "conventionalcommits"
}
],
[
"@semantic-release/exec",
{
"prepareCmd": "echo ${nextRelease.version} > version.txt",
"publishCmd": "echo 'Published version ${nextRelease.version}'"
}
],
[
"semantic-release-pypi",
{
"pypiPublish": false
}
],
[
"@semantic-release/git",
{
"assets": [
"pyproject.toml"
],
"message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
}
],
[
"@semantic-release/github",
{
"successComment": false
}
]
]
}
101 changes: 42 additions & 59 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,42 +16,36 @@ The Challenge Toolkit streamlines the entire CTF challenge lifecycle, from boots

## How to run

> [!NOTE]
> We are currently working on making it easier to use the tool.
The project uses standard Python packaging, therefore it can be installed by virtually any Python package manager.

The current tool is only provided as the raw python files.
Therefore, in order to run the tool, first clone this repository:
> [!IMPORTANT]
> We recommend always locking the version you install.
> This can be done by adding `@<version>` at the end of the install command, such as `@v1.2.0` to pin the install to `v1.2.0`.

```sh
git clone https://github.com/ctfpilot/challenge-toolkit
```

In order to install required dependencies, run:

```sh
pip install -r challenge-toolkit/src/requirements.txt
uv tool install git+https://github.com/ctfpilot/challenge-toolkit
# or using pipx
pipx install git+https://github.com/ctfpilot/challenge-toolkit
# or using pip (be sure to use a virtual environment)
pip install git+https://github.com/ctfpilot/challenge-toolkit
```

> [!IMPORTANT]
> The tool assumes, that the current working directory is the root of a challenge repository.
> Read more about the expected structure of a challenge repository in the **[Challenge repository structure documentation](#challenge-repository-structure)** section.

You can then run the tool using python:
You can then run the tool from the command line:

```sh
python challenge-toolkit/src/ctf.py <command> [arguments] [options]
challenge-toolkit <command> [arguments] [options]
```

> [!IMPORTANT]
> Deployment templates are essential for a number of commands to work properly.

In order to use `create`, `template`, and `page` you need to copy the deployment templates into the `template/` directory of your challenge repository (In accordance with the **[Template structure](#template-structure)** section).

This can be done by running:

```sh
cp -r challenge-toolkit/template/ .
```
Example templates can be found in the [`template` directory](./template)

### Environment Variables

Expand All @@ -65,32 +59,12 @@ The toolkit supports the following optional environment variables:

Currently, the following dependencies are required:

- Python 3.8 or higher
- Python 3.10 or higher
- `pyyaml` Python package
- `python-slugify` Python package
- Docker (for building challenge images with the `pipeline` command)

`pyyaml` and `python-slugify` are defined in the `requirements.txt` file.

### Including the tool in your project as a git submodule

One way to include it into your own project is to add it as a git submodule:

```sh
git submodule add https://github.com/ctfpilot/challenge-toolkit
```

To then clone your own project with the submodule included, run:

```sh
git clone --recurse-submodules <your-repo-url>
```

Or if you already have cloned your repository, run:

```sh
git submodule update --init --recursive
```
Python dependencies are listed in the `pyproject.toml` file and are automatically installed when installing the package via pip or similar tools.

### Typical usage

Expand Down Expand Up @@ -156,7 +130,7 @@ DEFAULT = {
The toolkit provides several commands to manage CTF challenges throughout their lifecycle. All commands follow the format:

```sh
python challenge-toolkit/src/ctf.py <command> [arguments] [options]
challenge-toolkit <command> [arguments] [options]
```

### Command Overview
Expand All @@ -180,7 +154,7 @@ Bootstrap a new challenge with the proper directory structure and template files
> The new challenge will then be located in `challenges/<category>/<slug>/`.

```sh
python challenge-toolkit/src/ctf.py create [options]
challenge-toolkit create [options]
```

**Options:**
Expand Down Expand Up @@ -208,10 +182,10 @@ python challenge-toolkit/src/ctf.py create [options]

```sh
# Interactive mode (recommended for first-time users)
python challenge-toolkit/src/ctf.py create
challenge-toolkit create

# Non-interactive mode with all parameters
python challenge-toolkit/src/ctf.py create \
challenge-toolkit create \
--no-prompts \
--name "SQL Injection 101" \
--slug "sql-injection-101" \
Expand All @@ -235,7 +209,7 @@ Generate Kubernetes deployment files, ConfigMaps, or handout archives for challe
> The command should be run from the root of a challenge repository, as it relies on the challenge directory structure defined in the [Challenge repository structure](#challenge-repository-structure) section.

```sh
python challenge-toolkit/src/ctf.py template <renderer> <challenge> [options]
challenge-toolkit template <renderer> <challenge> [options]
```

**Arguments:**
Expand Down Expand Up @@ -298,18 +272,18 @@ python challenge-toolkit/src/ctf.py template <renderer> <challenge> [options]

```sh
# Generate Kubernetes deployment files
python challenge-toolkit/src/ctf.py template k8s web/sql-injection-101
challenge-toolkit template k8s web/sql-injection-101

# Generate ConfigMap with custom expiry time (2 hours) and repo
python challenge-toolkit/src/ctf.py template configmap web/sql-injection-101 \
challenge-toolkit template configmap web/sql-injection-101 \
--expires 7200 \
--repo ctfpilot/ctf-challenges

# Create handout archive
python challenge-toolkit/src/ctf.py template handout web/sql-injection-101
challenge-toolkit template handout web/sql-injection-101

# Clean generated files
python challenge-toolkit/src/ctf.py template clean web/sql-injection-101
challenge-toolkit template clean web/sql-injection-101
```

### `pipeline` - Build and tag Docker images
Expand All @@ -322,7 +296,7 @@ Build Docker images for challenges and tag them appropriately for container regi
> The command should be run from the root of a challenge repository, as it relies on the challenge directory structure defined in the [Challenge repository structure](#challenge-repository-structure) section.

```sh
python challenge-toolkit/src/ctf.py pipeline <challenge> <registry> <image_prefix> [options]
challenge-toolkit pipeline <challenge> <registry> <image_prefix> [options]
```

**Arguments:**
Expand Down Expand Up @@ -350,13 +324,13 @@ python challenge-toolkit/src/ctf.py pipeline <challenge> <registry> <image_prefi

```sh
# Build and tag Docker image
python challenge-toolkit/src/ctf.py pipeline \
challenge-toolkit pipeline \
web/sql-injection-101 \
ghcr.io \
ctfpilot/ctf-challenges

# Build with custom suffix (e.g., for staging)
python challenge-toolkit/src/ctf.py pipeline \
challenge-toolkit pipeline \
web/sql-injection-101 \
ghcr.io \
ctfpilot/ctf-challenges \
Expand All @@ -376,7 +350,7 @@ Generate Kubernetes ConfigMaps pages, following the [CTF Pilot's Page Schema](ht
> The command should be run from the root of a challenge repository, as it relies on the challenge directory structure defined in the [Challenge repository structure](#challenge-repository-structure) section.

```sh
python challenge-toolkit/src/ctf.py page <page> [options]
challenge-toolkit page <page> [options]
```

**Arguments:**
Expand All @@ -398,10 +372,10 @@ python challenge-toolkit/src/ctf.py page <page> [options]

```sh
# Render a custom page
python challenge-toolkit/src/ctf.py page rules --repo ctfpilot/ctf-challenges
challenge-toolkit page rules --repo ctfpilot/ctf-challenges

# Render about page
python challenge-toolkit/src/ctf.py page about
challenge-toolkit page about
```

### `slugify` - Convert strings to URL-safe slugs
Expand All @@ -411,7 +385,7 @@ Utility command to convert challenge names into URL-safe slugs following the too
**Usage:**

```sh
python challenge-toolkit/src/ctf.py slugify <name>
challenge-toolkit slugify <name>
```

**Arguments:**
Expand All @@ -424,11 +398,11 @@ python challenge-toolkit/src/ctf.py slugify <name>

```sh
# Convert challenge name to slug
python challenge-toolkit/src/ctf.py slugify "SQL Injection 101"
challenge-toolkit slugify "SQL Injection 101"
# Output: sql-injection-101

# Convert with special characters
python challenge-toolkit/src/ctf.py slugify "Web: XSS & CSRF"
challenge-toolkit slugify "Web: XSS & CSRF"
# Output: web-xss-csrf
```

Expand Down Expand Up @@ -462,7 +436,6 @@ The structure is as follows:
├── pages/
│ └── page-1/
├── template/
├── challenge-toolkit/
└── <other files>
```

Expand Down Expand Up @@ -620,6 +593,16 @@ We welcome contributions of all kinds, from **code** and **documentation** to **

Please check the [Contribution Guidelines (`CONTRIBUTING.md`)](/CONTRIBUTING.md) for detailed guidelines on how to contribute.

### Running tests

To run the test suite, ensure you have all development dependencies installed. You can then execute the tests using `pytest`:

```sh
uv run pytest
```

### Contributor License Agreement (CLA)

To maintain the ability to distribute contributions across all our licensing models, **all code contributions require signing a Contributor License Agreement (CLA)**.
You can review **[the CLA here](https://github.com/ctfpilot/cla)**. CLA signing happens automatically when you create your first pull request.
To administrate the CLA signing process, we are using **[CLA assistant lite](https://github.com/marketplace/actions/cla-assistant-lite)**.
Expand Down
Loading