Skip to content
This repository was archived by the owner on Dec 17, 2025. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
d6e8338
Add 'protocol' to challenge-example.yml
ColdHeat Feb 21, 2023
78881df
Bump certifi from 2022.9.24 to 2022.12.7 (#108)
dependabot[bot] Mar 8, 2023
45ffa11
Replace flake8 with ruff (#112)
ColdHeat Mar 11, 2023
cdabe54
Challenge Deploy v2 (#113)
ColdHeat Mar 14, 2023
31c92d0
Add timeout to cloud challenge deployment (#116)
pl4nty Apr 4, 2023
bbcbfd0
Add configurable cookies via config file (#114)
pl4nty May 17, 2023
de3dcee
Mark 0.0.12 (#119)
ColdHeat Jun 25, 2023
a9d6f11
Plugin improvements (#122)
MilyMilo Jul 20, 2023
755acf8
add directory option to ctfcli add (#123)
MilyMilo Jul 20, 2023
faa8409
Bump PyYAML version to 6.0.1 (#125)
ColdHeat Jul 27, 2023
1c11ea6
Allow provided `connection_info` in `deploy` (#121)
pl4nty Jul 27, 2023
b9e47eb
Fix the PyYAML version in setup.py (#129)
ColdHeat Jul 29, 2023
7b4a09a
Mark 0.0.13 (#128)
ColdHeat Jul 29, 2023
c385e70
Refactor CTFCLI to more OOP approach (#130)
MilyMilo Aug 23, 2023
928966c
use poetry to build and publish, add entrypoint for pipx and recommen…
MilyMilo Aug 31, 2023
3c78ec4
ignore state when syncing deployed challenge (#132)
MilyMilo Sep 4, 2023
d00925d
Mark 0.1.0 (#133)
ColdHeat Oct 3, 2023
93f8cae
add challenge mirror, verify, format functionality (#134)
MilyMilo Nov 7, 2023
91872e0
Update README.md
ColdHeat Nov 10, 2023
4e636f5
Add option to use certain commands outside of a ctfcli project (#136)
MilyMilo Nov 29, 2023
12eb664
do not expose helper methods as commands (#138)
MilyMilo Dec 1, 2023
0170030
Properly add challenge.yml for templates into the poetry built packag…
ColdHeat Dec 3, 2023
588443f
Mark 0.1.1 (#140)
ColdHeat Dec 11, 2023
ff5c8a9
better file comparing (#142)
MilyMilo Jan 30, 2024
922b8ca
Support remote images (#143)
MilyMilo Feb 26, 2024
06abcc2
Mark 0.1.2 (#144)
ColdHeat Feb 26, 2024
26bcec8
Mark 0.1.2 in pyproject.toml (#145)
ColdHeat Feb 26, 2024
891852e
Add bulk challenge pull and push, and auto pull after push (#149)
MilyMilo Apr 17, 2024
31ec803
feat: add `--load` to `docker build` (#148)
pl4nty Apr 17, 2024
40f72fa
add support for git subrepo (#150)
MilyMilo Jul 14, 2024
7a6067d
Add Challenge.clone staticmethod to clone challenges from remote (#153)
ColdHeat Aug 20, 2024
704a864
Mark 0.1.3 (#154)
ColdHeat Aug 20, 2024
8fa7f3d
Manage CTFd configuration from ctfcli (#155)
ColdHeat Aug 24, 2024
609e940
Add ability to store manage media files locally and reference their U…
ColdHeat Aug 24, 2024
5c25270
Fix instance config pull (#157)
ColdHeat Sep 4, 2024
d8e08da
Add attribution field to challenge.yml spec (#158)
ColdHeat Sep 27, 2024
763c2de
Set challenge attribution (#164)
fuyu0425 Nov 26, 2024
d78a030
fix: Crashing when files field is empty (#166)
caffeine-addictt Dec 30, 2024
ab35147
feat: allow specifying access_token as an env var (#179)
VaiTon Apr 25, 2025
b29f6d7
Bump Python Fire version and add Python 3.13 to test matrix (#180)
ColdHeat Apr 25, 2025
0d946b4
Add slugify to dependencies and add slugify to cloud image deployment…
ColdHeat Apr 29, 2025
668f523
Added next and anonymize in requirements (#169)
herosi Apr 29, 2025
61c03f0
Mark 0.1.4 (#182)
ColdHeat Apr 29, 2025
850fcbe
Support hint title (#184)
ColdHeat May 4, 2025
c5abdd4
Allow titled hints to omit a cost (#185)
ColdHeat May 4, 2025
7393941
Fix issue with resolving relative challenge paths during install (#189)
ColdHeat Sep 3, 2025
2dbc5e2
Add logic key to challenge specification (#190)
ColdHeat Sep 4, 2025
826d1e6
Mark 0.1.5 (#191)
ColdHeat Sep 4, 2025
d98ab55
Deploy all shouldn't error if a challenge image is null/empty (#192)
mew1033 Sep 12, 2025
71f7cb7
Can't compare relative paths to absolute paths (#193)
mew1033 Nov 10, 2025
b3f0d74
always save connection info (#194)
MilyMilo Dec 15, 2025
36f5112
use uv and ruff (#195)
MilyMilo Dec 16, 2025
ab6d0f7
Sync ignore checksum (#183)
JPaja Jan 6, 2026
0d807ef
Mark 0.1.6 (#196)
ColdHeat Jan 6, 2026
84bb18b
add branch to challenges (#197)
MilyMilo Feb 12, 2026
56448ed
Add support for solutions based on writeups (#198)
ColdHeat Feb 26, 2026
9055ae1
If a solution exists but we want to remove it it should be deleted fr…
ColdHeat Feb 26, 2026
c79eff1
Mark 0.1.7 (#201)
ColdHeat Feb 26, 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
13 changes: 13 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
root = true

[*]
end_of_line = lf
insert_final_newline = true

[*.py]
charset = utf-8
indent_style = space
indent_size = 4

[Makefile]
indent_style = tab
25 changes: 9 additions & 16 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
@@ -1,29 +1,22 @@
---
name: Linting
name: Lint

on: [push, pull_request]

jobs:
build:

lint:
runs-on: ubuntu-latest

strategy:
matrix:
python-version: ['3.8']

name: Linting
steps:
- uses: actions/checkout@v2
- name: Setup python
uses: actions/setup-python@v2
- uses: actions/checkout@v5

- name: Install uv
uses: astral-sh/setup-uv@v7
with:
python-version: ${{ matrix.python-version }}
architecture: x64
activate-environment: true

- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install -r development.txt
run: uv sync --all-groups

- name: Lint
run: make lint
49 changes: 16 additions & 33 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,51 +1,34 @@
name: Build wheels
---
name: Build

on:
release:
types: [published]
pull_request:
types: [opened, reopened, edited, synchronize]

# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
# This workflow contains a single job called "build"
build:
# The type of runner that the job will run on
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [3.8]

# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v2
- uses: actions/checkout@v5

# Set up Python environment
- name: Set up Python 3.8
uses: actions/setup-python@v2
with:
python-version: 3.8
- name: Install uv
uses: astral-sh/setup-uv@v7

# Install dependencies
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r development.txt
run: uv sync

# Build wheels
- name: Build wheels
run: python setup.py sdist bdist_wheel
- name: Build package
run: uv build

- uses: actions/upload-artifact@v2
- name: Upload artifacts
uses: actions/upload-artifact@v6
with:
path: |
./dist/*.tar.gz
path: ./dist/

# Publish to pypi
- name: Publish to pypi
- name: Publish
if: ${{ github.event_name == 'release' }}
run: uv publish
env:
TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }}
TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
if: ${{ github.event_name == 'release' && env.TWINE_USERNAME != null }}
run: twine upload --repository pypi dist/*
UV_PUBLISH_TOKEN: ${{ secrets.PYPI_PASSWORD }}

27 changes: 27 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
---
name: Test

on: [push, pull_request]

jobs:
test:
runs-on: ubuntu-latest

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

steps:
- uses: actions/checkout@v5

- name: Install uv
uses: astral-sh/setup-uv@v7
with:
activate-environment: true
python-version: ${{ matrix.python-version }}

- name: Install dependencies
run: uv sync --all-groups

- name: Test
run: make test
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ db.sqlite3
db.sqlite3-journal

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
Expand Down Expand Up @@ -131,5 +130,7 @@ dmypy.json
# Miscellaneous
.DS_Store
.vscode/
.idea/

.ctf/
!tests/fixtures/challenges/.ctf
11 changes: 0 additions & 11 deletions .gitlab-ci.yml

This file was deleted.

152 changes: 152 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,157 @@
# Changelog

# 0.1.7 / 2026-02-26

### Added

- Add support for branches to challenge repo URLs
- Add support for solutions based on writeups in the challenge repo

# 0.1.6 / 2026-01-06

### Added

- Add `sha1sum` to `--ignore` as part of `ctf challenge sync` to allow syncing files when the remote checksum or local checksum is corrupted

### Fixed

- Fix an issue where if deployment returned updated connection info we wouldn't update it in challenge.yml
- Fix an issue where relative paths would not deploy due to a logging error

### Changed

- Challenges without an image will be considered a skipped deploy instead of a failed deploy
- Switch from poetry to uv
- Switch from to ruff

# 0.1.5 / 2025-09-04

### Added

- Support for hint titles
- Support `logic` key for challenges

### Fixed

- Fix issue with resolving relative challenge paths during install

# 0.1.4 / 2025-04-29

### Added

- Added support for `ctf instance` with the `ctf instance config` command which can be used to `get` and `set` configuration on CTFd
- Added `ctf media add`, `ctf media rm`, `ctf media url`
- Allows ctfcli repos to manage files locally and reference the actual server URLs of media files in Pages
- Adds concept of replacing placeholders like `{{ media/ctfd.png }}` with the actual URL on the server
- Added the `attribution` field to challenge.yml
- Added the `next` field to challenge.yml
- Added ability to anoymize challenges while specifying prerequisites
- Added specifying CTFd instance URL and access token via envvars: `CTFCLI_URL`, `CTFCLI_ACCESS_TOKEN`

### Fixed

- Fix issue with managing challenges with an empty files section
- Fix issue where images could not be deployed due to being named incorrectly

# 0.1.3 / 2024-08-20

### Added

- Added support for `git subrepo` instead of only `git subtree`
- Added the `--create` switch to `ctf challenge mirror` to create local copies of challenges that exist on a remote CTFd instance

### Fixed

- `ctf challenge {push, pull}` will now push / pull all challenges instead of the challenge in the current working directory.

### Changed

- Use `--load` switch as part of docker build to support alternate build drivers

# 0.1.2 / 2023-02-26

### Added

- Before uploading files to CTFd, ctfcli will check for CTFd's SHA1 hash of the previously uploaded file and skip uploading if it is the same
- Support using remote Docker images instead of having to build and push local images

# 0.1.1 / 2023-12-11

### Added

- Added `ctf challenge mirror` command to pull changes from the remote CTFd instance into the local project

### Fixed

- Properly include challenge.yml when generating a challenge from a template

### Changed

- No longer require a ctfcli project to run all `ctf challenge` (e.g. `new`, `format`, `lint`)

# 0.1.0 / 2023-10-03

### Added

- ctfcli has been separated into two main modules `cli` and `core`. The `core` module now packages logic previously found inside `utils`, wrapped into classes.
- The classes in the `core` module will only print out warnings instead of interrupting the whole process. Everything else will throw exceptions which can be caught and handled however desired
- `cli` and `core` internal modules have type hints
- Improved error messages
- Unit tests have been added for the entire `core` module
- ctfcli will now ask to initialize a new project if one does not exist
- Added `--hidden` to `ctf challenge install` which will deploy the challenge / challenges in a hidden state regardless of their `challenge.yml` value.
- Added `ctf challenge edit <name>` and `ctf challenge edit <name> --dockerfile` to open challenge.yml or Dockerfile for that challenge
- Added aliases under `ctf templates` and `ctf plugins` for `dir` (`path`) and for `view` (`show`)
- Progress bars for `ctf challenge deploy` / `ctf challenge install` / `ctf challenge sync`
- `ctf challenge deploy` will now deploy ALL deployable challenges if a specific challenge is not specified
- For the SSH and Registry deployments, to facilitate this behaviour the challenge name will be automatically appended. So the host should be for example: `registry://registry.example.com/example-project` and the challenge name will be appended for a full location.
- `ctf challenge deploy` will now also automatically login to the registry with Cloud and Registry deployments.
- For cloud deployments the instance url must be ctfd assigned (e.g. example.ctfd.io) - this is because to log-in to the registry we require a username like `admin@example.ctfd.io`. The deployment will use the access token as the password.
- For registry deployment it will look for the `username` and `password` keys inside a `[registry]` section in the project config file.
- ctfcli will read a `LOGLEVEL` environment variable to enable DEBUG logging has been added

### Fixed

- When syncing a challenge to a remote instance, state specified in challenge.yml will now be ignored to prevent accidental challenge leaking
- The CLI will now exit with a 0 if everything went right, and 1 if something went wrong.
- With `install`/`sync`/`deploy` - exit code will be 1 if ANY of the challenges failed to `install`/`sync`/`deploy`.

### Changed

- Built using poetry and `pyproject.toml`
- `python-fire` has been updated to 0.5.0

### Removed

- Removed the `ctf challenge finalize` command

# 0.0.13 / 2023-07-29

### Added

- Add env variable `CTFCLI_PLUGIN_DIR` to override the default plugin dir for development.
- Add `--directory` argument to `ctfcli challenge add`
- Can also be called as `ctf challenge add git@github.com:repo.git directory`
- Useful for grouping challenges into separate directories like: `web/challenge1`.
- `connection_info` specified in challenge.yml will be used instead of details generated by a deploy handler

### Fixed

- Bump PyYAML version to 6.0.1

# 0.0.12 / 2023-06-25

### Added

- Add cloud deploy for hosted CTFd instances
- Add the `protocol` field in the challenge.yml spec
- Further define what other deployment methods should provide & return
- Add the ability to add HTTP cookies to ctfcli requests via the config file

### Fixed

- Allow ignoring category during challenge sync

# 0.0.11 / 2022-11-09

### Added
Expand Down
5 changes: 0 additions & 5 deletions MANIFEST.in

This file was deleted.

34 changes: 12 additions & 22 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,29 +1,19 @@
.PHONY: all
.IGNORE: lint format

lint:
flake8 --ignore=E402,E501,E712,W503,E203,I002 --exclude=ctfcli/templates **/*.py
black --check --exclude=ctfcli/templates .
ruff format --check .
ruff check .

format:
black --exclude=ctfcli/templates .

install:
python3 setup.py install
ruff check --select F401 --select TID252 --select I --fix .
ruff format .

build:
python3 setup.py sdist bdist_wheel
test:
pytest --cov=ctfcli tests

clean:
rm -rf build/
rm -rf dist/
rm -rf ctfcli.egg-info/

publish-test:
@echo "Publishing to TestPyPI"
@echo "Are you sure? [y/N] " && read ans && [ $${ans:-N} == y ]
python3 setup.py sdist bdist_wheel
twine upload --repository test dist/*

publish-pypi:
@echo "Publishing to PyPI"
@echo "ARE YOU ABSOLUTELY SURE? [y/N] " && read ans && [ $${ans:-N} == y ]
python3 setup.py sdist bdist_wheel
twine upload --repository pypi dist/*
rm -rf .ruff_cache
rm -rf .pytest_cache
rm -f .coverage
Loading