docs: update architecture and add tests for flag regex generation
This commit is contained in:
@@ -39,10 +39,13 @@ Provides helper functions for filesystem management and configuration parsing:
|
||||
* `write_config(data, path)`: Serializes/updates a dictionary to a TOML file.
|
||||
* `active_categories(path)`: Iterates over a competition path to return all active categories.
|
||||
* `active_competitions(dir)`: Scans the base directory for active competitions, skipping designated helper directories (like `tools`).
|
||||
* `suggest_patterns(flag)`: Analyzes a provided sample flag string and generates a prioritized, deduplicated list of regular expression pattern candidates (ranging from specific to general).
|
||||
|
||||
### C. Commands ([commands.py](file:///home/venus/code/ctf/src/ctf/commands.py))
|
||||
Houses the logic for generic CLI context and active competition commands:
|
||||
* `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-flag-format (pattern)`: Sets the flag regex format in configuration. Supports optional `PATTERN` positional argument or an interactive choice using `-o`/`--original` which takes a sample flag and prompts the user to select from suggested regex patterns.
|
||||
|
||||
|
||||
### 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:
|
||||
|
||||
@@ -47,3 +47,57 @@ def test_basic_set_flag_format_cli():
|
||||
# Restore original config
|
||||
from ctf.utils import write_config
|
||||
write_config(original_config, str(config_file))
|
||||
|
||||
def test_basic_set_flag_format_original_option_cli():
|
||||
"""
|
||||
Verifies that 'basic set-flag-format' with --original/-o option prompts for selection and writes it.
|
||||
"""
|
||||
from ctf.utils import load_config
|
||||
|
||||
runner = CliRunner()
|
||||
config_file = Path("/home/venus/code/ctf/config.toml")
|
||||
|
||||
# Save the original config to restore later
|
||||
original_config = load_config(str(config_file))
|
||||
|
||||
try:
|
||||
# We pass -o SKY-1111-000 and input "2" to choose the second suggested pattern
|
||||
result = runner.invoke(basic_group, ["set-flag-format", "-o", "SKY-1111-000"], input="2\n")
|
||||
assert result.exit_code == 0
|
||||
assert "Suggested regex patterns:" in result.output
|
||||
assert "Select a pattern index" in result.output
|
||||
assert "Flag format set to" in result.output
|
||||
|
||||
# Verify it was written to config.toml
|
||||
updated_config = load_config(str(config_file))
|
||||
selected_pattern = updated_config["Competition"]["flag_format"]
|
||||
assert selected_pattern.startswith("^") and selected_pattern.endswith("$")
|
||||
finally:
|
||||
# Restore original config
|
||||
from ctf.utils import write_config
|
||||
write_config(original_config, str(config_file))
|
||||
|
||||
def test_basic_set_flag_format_validation_cli():
|
||||
"""
|
||||
Verifies validation rules:
|
||||
- Specifying both PATTERN and --original should fail.
|
||||
- Specifying neither PATTERN nor --original should fail.
|
||||
- Specifying empty/whitespace-only original flag should fail.
|
||||
"""
|
||||
runner = CliRunner()
|
||||
|
||||
# Both specified
|
||||
result1 = runner.invoke(basic_group, ["set-flag-format", "PAT", "-o", "SKY-1111-000"])
|
||||
assert result1.exit_code != 0
|
||||
assert "Cannot specify both PATTERN and --original/-o option." in result1.output
|
||||
|
||||
# Neither specified
|
||||
result2 = runner.invoke(basic_group, ["set-flag-format"])
|
||||
assert result2.exit_code != 0
|
||||
assert "Either PATTERN positional argument or --original/-o option must be specified." in result2.output
|
||||
|
||||
# Empty original
|
||||
result3 = runner.invoke(basic_group, ["set-flag-format", "-o", " "])
|
||||
assert result3.exit_code != 0
|
||||
assert "Original flag cannot be empty or whitespace only." in result3.output
|
||||
|
||||
|
||||
100
tests/test_utils.py
Normal file
100
tests/test_utils.py
Normal file
@@ -0,0 +1,100 @@
|
||||
from ctf.utils import suggest_patterns
|
||||
import pytest
|
||||
|
||||
# =====================================================================
|
||||
# 1. Test Strategy Summary
|
||||
# =====================================================================
|
||||
# This suite verifies the `suggest_patterns` utility function which parses
|
||||
# a sample flag string and generates a prioritized, deduplicated list of
|
||||
# candidate regular expression patterns.
|
||||
#
|
||||
# Core scenarios tested:
|
||||
# A. Happy Path:
|
||||
# - Verifying pattern suggestion output for typical flags like 'SKY-1111-000'
|
||||
# and 'CTF{easy_flag_123}'.
|
||||
# - Verifying order and counts of specific vs. general patterns.
|
||||
#
|
||||
# B. Boundary Conditions:
|
||||
# - Handling single character inputs (e.g. 'A', '1', '{').
|
||||
# - Handling strings containing only delimiter/special characters (e.g. '---').
|
||||
# - Handling inputs with no numeric values or no alphabetic values.
|
||||
#
|
||||
# C. Edge Cases:
|
||||
# - Mixing case strings (e.g., 'AbCdEf') and verifying case-insensitive
|
||||
# or case-specific group behavior.
|
||||
#
|
||||
# D. Error Handling:
|
||||
# - Empty strings or strings containing only whitespace characters should
|
||||
# raise ValueError.
|
||||
# =====================================================================
|
||||
|
||||
# =====================================================================
|
||||
# 2. Mocking/Setup Requirements
|
||||
# =====================================================================
|
||||
# - No external database, network APIs, or filesystem mocks are needed
|
||||
# as `suggest_patterns` is a pure string-processing utility.
|
||||
# =====================================================================
|
||||
|
||||
def test_suggest_patterns_happy_path_sky():
|
||||
"""
|
||||
Verifies that the suggestions for a hyphenated alpha-numeric flag like 'SKY-1111-000'
|
||||
include specific character group counts, variable length matches, and the literal match.
|
||||
"""
|
||||
patterns = suggest_patterns("SKY-1111-000")
|
||||
|
||||
# Asserting we get a list of patterns
|
||||
assert isinstance(patterns, list)
|
||||
assert len(patterns) > 0
|
||||
|
||||
# Expected options:
|
||||
# 1. Specific count: ^[A-Z]{3}-\d{4}-\d{3}$
|
||||
assert "^[A-Z]{3}-\\d{4}-\\d{3}$" in patterns
|
||||
# 2. Variable: ^[A-Z]+-\d+-\d+$
|
||||
assert "^[A-Z]+-\\d+-\\d+$" in patterns
|
||||
# 3. Case-insensitive count: ^[A-Za-z]{3}-\d{4}-\d{3}$
|
||||
assert "^[A-Za-z]{3}-\\d{4}-\\d{3}$" in patterns
|
||||
# 4. Alphanumeric + delimiter class: ^[A-Za-z0-9\-]+$
|
||||
assert "^[A-Za-z0-9\\-]+$" in patterns
|
||||
# 5. Literal matching: ^SKY-1111-000$
|
||||
assert "^SKY-1111-000$" in patterns
|
||||
|
||||
def test_suggest_patterns_happy_path_ctf():
|
||||
"""
|
||||
Verifies suggestions for flags with braces and underscores like 'CTF{easy_flag_123}'.
|
||||
Note that special regex characters like '{' and '}' are correctly escaped.
|
||||
"""
|
||||
patterns = suggest_patterns("CTF{easy_flag_123}")
|
||||
|
||||
# 1. Specific count: ^[A-Z]{3}\{[a-z]{4}_[a-z]{4}_\d{3}\}$
|
||||
assert "^[A-Z]{3}\\{[a-z]{4}_[a-z]{4}_\\d{3}\\}$" in patterns
|
||||
# 2. Variable: ^[A-Z]+\{[a-z]+_[a-z]+_\d+\}$
|
||||
assert "^[A-Z]+\\{[a-z]+_[a-z]+_\\d+\\}$" in patterns
|
||||
# 3. Alphanumeric class: ^[A-Za-z0-9_{\}]+$
|
||||
assert "^[A-Za-z0-9_\\{\\}]+$" in patterns
|
||||
# 4. Literal matching: ^CTF\{easy_flag_123\}$
|
||||
assert "^CTF\\{easy_flag_123\\}$" in patterns
|
||||
|
||||
def test_suggest_patterns_only_specials():
|
||||
"""
|
||||
Verifies that a string with only special characters works and generates valid patterns.
|
||||
"""
|
||||
patterns = suggest_patterns("---")
|
||||
# All patterns should deduplicate to just the exact literal match or similar
|
||||
assert "^---$" in patterns
|
||||
|
||||
def test_suggest_patterns_single_char():
|
||||
"""
|
||||
Verifies pattern suggestion on single character flags.
|
||||
"""
|
||||
assert "^[A-Z]{1}$" in suggest_patterns("A")
|
||||
assert "^\\d{1}$" in suggest_patterns("5")
|
||||
|
||||
def test_suggest_patterns_empty_and_whitespace():
|
||||
"""
|
||||
Verifies that empty string or whitespace-only inputs trigger a ValueError.
|
||||
"""
|
||||
with pytest.raises(ValueError, match="Input string cannot be empty or whitespace only."):
|
||||
suggest_patterns("")
|
||||
|
||||
with pytest.raises(ValueError, match="Input string cannot be empty or whitespace only."):
|
||||
suggest_patterns(" ")
|
||||
Reference in New Issue
Block a user