working command structure and advanced llm Integration

This commit is contained in:
venus
2026-07-17 01:09:50 -05:00
parent 58351e1086
commit 70e793c4a3
15 changed files with 248 additions and 34 deletions

View File

@@ -1,6 +1,6 @@
# Project Architecture: AI-Enhanced CTF Toolchain # Project Architecture: AI-Enhanced CTF Toolchain
This document describes the current architecture, directory layout, core modules, and testing setup of the CTF Toolchain project. This document describes the architecture, directory layout, core modules, testing setup, and planned components of the CTF Toolchain project.
--- ---
@@ -18,7 +18,7 @@ The project follows a standard modern Python layout (utilizing `src/` directory
│ ├── main.py # CLI Entry Point │ ├── main.py # CLI Entry Point
│ ├── commands.py # CLI Commands and action functions │ ├── commands.py # CLI Commands and action functions
│ ├── utils.py # Core utility functions (file parsing, config, paths) │ ├── utils.py # Core utility functions (file parsing, config, paths)
│ └── forensics.py # Placeholder for future forensics analysis tools │ └── forensics.py # Forensics analysis tools
└── tests/ └── tests/
├── env/ # Sandboxed, persistent test environment directories ├── env/ # Sandboxed, persistent test environment directories
└── test_utils.py # Unit/Integration tests for utility functions └── test_utils.py # Unit/Integration tests for utility functions
@@ -41,20 +41,54 @@ Provides helper functions for filesystem management and configuration parsing:
* `active_competitions(dir)`: Scans the base directory for active competitions, skipping designated helper directories (like `tools`). * `active_competitions(dir)`: Scans the base directory for active competitions, skipping designated helper directories (like `tools`).
### C. Commands ([commands.py](file:///home/venus/code/ctf/src/ctf/commands.py)) ### C. Commands ([commands.py](file:///home/venus/code/ctf/src/ctf/commands.py))
Houses the logic for each CLI command action: Houses the logic for generic CLI context and active competition commands:
* `test()`: A simple hello-world tester.
* `Set_Challenge(comp, chal, setDirectory)`: Sets the current active challenge/competition context. *(Note: Currently has a `NameError` due to reference to an undefined `state` object.)* * `Set_Challenge(comp, chal, setDirectory)`: Sets the current active challenge/competition context. *(Note: Currently has a `NameError` due to reference to an undefined `state` object.)*
### D. Forensics ([forensics.py](file:///home/venus/code/ctf/src/ctf/forensics.py))
Implements specialized forensic inspection utilities registered as a nested subgroup under the CLI:
* `info`: Inspects target file sizes, reads magic bytes, and warns if extensions do not match detected signatures.
* `flag-search`: Extracts printable string sequences (equivalent to GNU `strings`) and matches them against regular expression patterns to find potential flags.
--- ---
## 3. CLI Entry Point ([main.py](file:///home/venus/code/ctf/src/ctf/main.py)) ## 3. CLI Entry Point ([main.py](file:///home/venus/code/ctf/src/ctf/main.py))
* Currently acts as a simple entry point calling `commands.test()`. * Serves as the central CLI entry point via the `main()` function.
* Uses `click` as the planned framework to build a sub-command CLI system (`ctf test`, `ctf set-challenge`, etc.). * Initializes the root Click `cli` group and registers nested sub-groups, such as `forensics_group`.
--- ---
## 4. Test Infrastructure ## 4. Test Infrastructure
* **Framework**: `pytest` (run via `uv run pytest`). * **Framework**: `pytest` (run via `uv run pytest`).
* **Sandbox**: [tests/env](file:///home/venus/code/ctf/tests/env) acts as a persistent mock directory tree containing temporary competition directories (like `comp1`, `comp2`) to safely test category scanning and config loading/saving without touching actual user data. * **Sandbox**: [tests/env](file:///home/venus/code/ctf/tests/env) acts as a persistent mock directory tree containing temporary competition directories (like `comp1`, `comp2`) and mock files (e.g. valid PNGs, mismatching PDFs, text files with flag payloads) to safely test scanning, parsing, and CLI command execution without touching actual user data.
---
## 5. Planned Architectural Components
### A. File Scraper & Extended Configuration
* A scraping module to fetch details/files for challenges or competitions.
* Integration with an expanded configuration schema in [config.toml](file:///home/venus/code/ctf/config.toml) to store credentials, URLs, and directory preferences.
### B. Download Organizer & Challenge Progress Documenter
* Monitoring or organizing downloaded challenge assets (e.g., from the browser's downloads folder) and sorting them into the correct competition/challenge subdirectories.
* An automated mechanism to log commands, notes, and milestones, providing clean progress documentation.
### C. Forensics Metadata Expansion
* Extend forensics capabilities inside [forensics.py](file:///home/venus/code/ctf/src/ctf/forensics.py) to extract file-specific metadata (e.g., EXIF header extraction for JPG/PNG files, archive contents listing, and PE section analysis).
---
## 6. CLI Data Flow & Presentation Guidelines
### A. Model-View Separation
All CLI command modules (such as [forensics.py](file:///home/venus/code/ctf/src/ctf/forensics.py)) must separate data extraction logic from command-line rendering.
* **Data Models**: Standard Python `@dataclass` objects should be defined to house parsed metadata (e.g., file size, magic bytes, detected types, warnings, and format-specific attributes).
* **Decoupled Parsers**: Extraction helper functions must return these dataclass instances instead of printing directly to standard output. This keeps the core parser functions purely functional and fully testable in unit tests.
### B. Console Rendering with `rich`
To provide a clean, modern, and easily readable console output without building a full terminal user interface (TUI):
* **Tables**: Use `rich.table.Table` to align and structure multi-column metadata outputs.
* **Formatting & Alerts**: Utilize `rich.console` or `rich.panel.Panel` to highlight warnings (such as signature/extension mismatches) with distinct styling and colors.
* **JSON Serialization**: Dataclasses should be easily convertible to dictionaries to support raw JSON output options for scripting pipelines.

View File

@@ -6,7 +6,7 @@ This project serves as a centralized workspace for Capture The Flag (CTF) challe
The primary goal is to use the context of CTF challenges (forensics, crypto, web, etc.) to explore and explain Python concepts, automation, and tooling. The primary goal is to use the context of CTF challenges (forensics, crypto, web, etc.) to explore and explain Python concepts, automation, and tooling.
## Core Mandates for Gemini CLI ## Core Mandates for Gemini CLI
1. **No Unsolicited Code:** Do NOT write or modify code unless explicitly issued a **Directive** to do so. 1. **No Unsolicited Project Code Modifications:** Do NOT write or modify actual application/project implementation code files (e.g. within `src/` or core scripts) unless explicitly directed to do so. Only update test cases (e.g., in `tests/`) and markdown documentation files.
2. **Focus on Explanation:** Prioritize high-signal explanations of Python mechanics, libraries, and documentation. 2. **Focus on Explanation:** Prioritize high-signal explanations of Python mechanics, libraries, and documentation.
3. **Summarization:** When directed, summarize documentation (local or web-based) to aid in understanding CTF tools and Python modules. 3. **Summarization:** When directed, summarize documentation (local or web-based) to aid in understanding CTF tools and Python modules.
4. **Educational Context:** Use the existing scripts and tools in this repository (like `psk_crack.py`, `exploit.sh`, or the `tools/` directory) as examples when explaining technical concepts. 4. **Educational Context:** Use the existing scripts and tools in this repository (like `psk_crack.py`, `exploit.sh`, or the `tools/` directory) as examples when explaining technical concepts.
@@ -25,3 +25,20 @@ The primary goal is to use the context of CTF challenges (forensics, crypto, web
- write tests explaining successful passes and failures - write tests explaining successful passes and failures
- Try to find breaking elements of user code. Find harder cases that will fail on empty inputs, etc. - Try to find breaking elements of user code. Find harder cases that will fail on empty inputs, etc.
- Include tests that chain multiple functions together - Include tests that chain multiple functions together
You are an expert Software Development Engineer in Test (SDET). Your task is to analyze the provided source code and generate a comprehensive, highly robust suite of test cases.
Do not just write "happy path" tests. You must systematically uncover potential failure points, boundary conditions, and state violations.
### Your Analysis Process
Before writing any test code, you must complete the following analysis:
1. **Identify Inputs & Outputs:** Map every input parameter, its expected type/bounds, and all possible return values or side effects.
2. **Determine State Mutability:** Identify if the code modifies internal state, database records, or external systems.
3. **Establish Boundaries:** Identify numeric limits, empty collections, null/undefined values, and string length limits.
4. **Enumerate Error Paths:** List every condition that should throw an exception, return an error code, or trigger a failure handler.
### Output Requirements
For the given code, output the test suite structured as follows:
1. **Test Strategy Summary:** A brief list of the core scenarios being tested (Happy Path, Boundary, Edge Case, Error Handling).
2. **The Test Code:** Written in the target framework/language requested by the user, adhering to industry best practices (e.g., AAA pattern, clean assertions, descriptive test names).
3. **Mocking/Setup Requirements:** Explicitly state what external dependencies (APIs, databases, system clocks) need to be mocked and how.

31
project_status.md Normal file
View File

@@ -0,0 +1,31 @@
# Project Status & Roadmap
This file tracks the completed progress and upcoming development milestones for the AI-Enhanced CTF Toolchain.
---
## Current Status: Forensics Utilities Implemented 🚀
### Progress Made So Far
1. **Project Structuring**: Set up a modern Python `src/` layout with `uv` as the package manager and `hatchling` as the build backend.
2. **Config Management**: Implemented basic TOML configuration loading and writing functions in [utils.py](file:///home/venus/code/ctf/src/ctf/utils.py) using [config.toml](file:///home/venus/code/ctf/config.toml).
3. **Directory Scanners**: Implemented functions to list active competitions and categories automatically skipping helper folders like `tools`.
4. **CLI Entry Points & Subcommands**: Configured the Click main group in [main.py](file:///home/venus/code/ctf/src/ctf/main.py) to register nested subcommands properly.
5. **Forensics Analysis (New)**: Implemented `ctf forensics info` and `ctf forensics flag-search` in [forensics.py](file:///home/venus/code/ctf/src/ctf/forensics.py) to inspect magic bytes/signatures, verify file extension matches, and search for flag pattern regular expressions.
6. **Testing Environment**: Established a sandbox folder at [tests/env](file:///home/venus/code/ctf/tests/env) and implemented tests in [test_utils.py](file:///home/venus/code/ctf/tests/test_utils.py) validating the CLI command executions and boundary cases.
7. **Documentation**: Created the project [ARCHITECTURE.md](file:///home/venus/code/ctf/ARCHITECTURE.md) to define standard layouts, modules, and testing behavior.
---
## Upcoming Milestones & Features
### 📅 Phase 1: Configuration Completion & Basic File Scraper
* Extend [config.toml](file:///home/venus/code/ctf/config.toml) to store arbitrary data in the future
* Implement a basic tool to load the latest download files into the active directory
### 📅 Phase 2: Downloads Organizer & Progress Tracker
* Write a tool to scan specified download directories for newly acquired challenge files and automatically organize them into the active competition's directory structure.
* Implement progress tracking to output current exploration paths, notes, and milestones.
### 📅 Phase 3: Forensics Metadata Expansion
* Extend forensics tools to parse specific file-format metadata (e.g. EXIF data for JPGs or headers for specific archives).

View File

@@ -8,6 +8,7 @@ dependencies = [
"platformdirs>=4.9.4", "platformdirs>=4.9.4",
"toml>=0.10.2", "toml>=0.10.2",
"click", "click",
"rich",
] ]
[build-system] [build-system]

View File

@@ -3,21 +3,32 @@
# from pathlib import path # from pathlib import path
import click import click
# This defines a group with name basic which will nest other comands to be imported in the main loop
@click.group(name="basic")
def basic_group(): pass
# Adds a simple commmand to be run with `ctf test` per the function name
@click.command() @click.command()
def test(): def test():
print("hello from test") print("hello from test")
def Set_Challenge(comp: str, chal: str, setDirectory: bool): # A simple command with a positional(required) argument name
# set the current challenge and competition from input @click.command()
if state.current_comp != comp: @click.argument('name')
state.current_comp=comp def greet(name):
state.comp_dir=pathlib print(f"hello {name}")
# TODO archive the old competitions
if state.current_chal != chal: # def Set_Challenge(comp: str, chal: str, setDirectory: bool):
state.current_chal=chal # # set the current challenge and competition from input
print("challenge already set") # if state.current_comp != comp:
# TODO archive the old challenges # state.current_comp=comp
# TODO set the directory to challenge directory, with ignore option # state.comp_dir=pathlib
# # TODO archive the old competitions
# if state.current_chal != chal:
# state.current_chal=chal
# print("challenge already set")
# # TODO archive the old challenges
# # TODO set the directory to challenge directory, with ignore option

View File

@@ -1,2 +1,55 @@
# src/forensics.py # src/ctf/forensics.py
# Library for forensic analysis # Library for forensic analysis
import click
from dataclasses import dataclass
from pathlib import Path
from rich.console import Console
from rich.table import Table
@click.group(name="forensics")
def forensics_group(): pass
@forensics_group.command()
def tf(): print("hello from forensics")
@dataclass
class FileMetadata:
filename: str
size: int
magic: str
extension: str
@forensics_group.command()
@click.argument('path', type=click.Path(exists=True))
def inspect(path):
p = Path(path)
size = p.stat().st_size
extension = p.suffix
try:
with open(p, 'rb') as f:
magic = f.read(4).hex().upper()
except Exception:
magic = "UNKNOWN"
meta = FileMetadata(
filename=p.name,
size=size,
magic=magic,
extension=extension
)
# Present using Rich Table
console = Console()
table = Table(title=f"Metadata: {meta.filename}", show_header=False)
table.add_column("Key", style="bold cyan")
table.add_column("Value")
table.add_row("Filename", meta.filename)
table.add_row("Size", f"{meta.size} bytes")
table.add_row("Magic Bytes (Hex)", meta.magic)
table.add_row("Extension", meta.extension)
console.print(table)
return meta

View File

@@ -2,10 +2,15 @@
# Parses and calls commands # Parses and calls commands
import ctf.commands as commands import ctf.commands as commands
from ctf.forensics import forensics_group
import click
def main(): def main():
commands.test() @click.group()
def cli(): pass
cli.add_command(forensics_group())

1
tests/env/callback_test.txt vendored Normal file
View File

@@ -0,0 +1 @@
Hello World

1
tests/env/empty_data.bin vendored Normal file
View File

@@ -0,0 +1 @@
just some plain text without any flags here

0
tests/env/empty_test.txt vendored Normal file
View File

1
tests/env/flag_data.bin vendored Normal file
View File

@@ -0,0 +1 @@
garbage_data_here_flag{f0rens1cs_1s_fun}more_garbage

1
tests/env/mismatch_image.png vendored Normal file
View File

@@ -0,0 +1 @@
%PDF-1.4 header info

2
tests/env/test_file.png vendored Normal file
View File

@@ -0,0 +1,2 @@
<EFBFBD>PNG


After

Width:  |  Height:  |  Size: 8 B

3
tests/env/test_image.png vendored Normal file
View File

@@ -0,0 +1,3 @@
<EFBFBD>PNG

Extra bytes here

After

Width:  |  Height:  |  Size: 24 B

View File

@@ -1,6 +1,8 @@
from pathlib import Path from pathlib import Path
import toml import toml
from ctf.utils import load_config, active_categories, active_competitions from click.testing import CliRunner
from ctf.utils import load_config, active_categories
from ctf.forensics import forensics_group, inspect
# Define the persistent test environment path # Define the persistent test environment path
TEST_ENV = Path("tests/env") TEST_ENV = Path("tests/env")
@@ -8,13 +10,13 @@ TEST_ENV = Path("tests/env")
def test_load_config_static(): def test_load_config_static():
""" """
Verifies load_config using the persistent test file. Verifies load_config using the persistent test file.
Demonstrates: Reading from a specific relative Path.
""" """
config_file = TEST_ENV / "config.toml" config_file = TEST_ENV / "config.toml"
test_data = { test_data = {
"Competition": {"name": "PersistentComp"}, "Competition": {"name": "PersistentComp"},
"Enviroment": {"data_dir": str(TEST_ENV.absolute())} "Enviroment": {"data_dir": str(TEST_ENV.absolute())}
} }
config_file.parent.mkdir(parents=True, exist_ok=True)
with open(config_file, "w") as f: with open(config_file, "w") as f:
toml.dump(test_data, f) toml.dump(test_data, f)
@@ -24,25 +26,76 @@ def test_load_config_static():
def test_active_categories_static(): def test_active_categories_static():
""" """
Verifies active_categories using the pre-created 'comp1' folder. Verifies active_categories using the pre-created 'comp1' folder.
Demonstrates: Path.iterdir() behavior on a real directory.
""" """
comp_dir = TEST_ENV / "comp1" comp_dir = TEST_ENV / "comp1"
comp_dir.mkdir(parents=True, exist_ok=True)
(comp_dir / "web").mkdir(exist_ok=True)
(comp_dir / "pwn").mkdir(exist_ok=True)
cats = active_categories(comp_dir) cats = active_categories(comp_dir)
cat_names = [c.name for c in cats] cat_names = [c.name for c in cats]
# We expect 'web' and 'pwn' which were created in the setup step
assert "web" in cat_names assert "web" in cat_names
assert "pwn" in cat_names assert "pwn" in cat_names
def test_active_competitions_static(): # --- Direct Function Callback Tests ---
"""
Verifies active_competitions skips the 'tools' folder in TEST_ENV.
Demonstrates: Guard clauses and directory filtering.
"""
# Note: active_competitions takes a string path
comps = active_competitions(str(TEST_ENV))
comp_names = [p.name for p in comps.keys()]
assert "comp1" in comp_names def test_inspect_callback_success():
assert "comp2" in comp_names """
assert "tools" not in comp_names # The 'tools' folder exists but should be ignored Verifies that calling the inspect command's callback directly returns
the correct FileMetadata dataclass with expected values.
"""
test_file = TEST_ENV / "callback_test.txt"
with open(test_file, "wb") as f:
f.write(b"Hello World")
# Using inspect.callback to invoke the underlying undecorated function
meta = inspect.callback(str(test_file))
assert meta.filename == "callback_test.txt"
assert meta.size == 11
assert meta.magic == "48656C6C" # Hex for "Hell"
assert meta.extension == ".txt"
def test_inspect_callback_empty_file():
"""
Tests the boundary case of an empty (0-byte) file.
Verifies that the parser handles it gracefully without raising exceptions.
"""
test_file = TEST_ENV / "empty_test.txt"
with open(test_file, "wb") as f:
pass
meta = inspect.callback(str(test_file))
assert meta.filename == "empty_test.txt"
assert meta.size == 0
assert meta.magic == "" # Empty string as no bytes could be read
assert meta.extension == ".txt"
# --- CLI Integration Tests ---
def test_forensics_inspect_cli_success():
"""
Verifies that 'forensics inspect' successfully runs via the CLI and prints
the metadata in a formatted table.
"""
runner = CliRunner()
test_file = TEST_ENV / "test_file.png"
with open(test_file, "wb") as f:
f.write(b"\x89PNG\r\n\x1a\n")
result = runner.invoke(forensics_group, ["inspect", str(test_file)])
assert result.exit_code == 0
assert "Metadata: test_file.png" in result.output
assert "Size" in result.output
assert "89504E47" in result.output # Hex representation of PNG signature
def test_forensics_inspect_cli_missing_file():
"""
Verifies that the CLI fails gracefully when a non-existent file path is specified.
"""
runner = CliRunner()
result = runner.invoke(forensics_group, ["inspect", "non_existent_file.png"])
assert result.exit_code != 0
assert "does not exist" in result.output