Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
14 changes: 10 additions & 4 deletions .github/skills/ctf-testing/test_ctf_challenges.sh
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ if [[ -f "${REBOOT_MARKER}" ]]; then
EXPECTED=$(cat "$PROGRESS_SNAPSHOT")
ACTUAL=$(sort -u /var/ctf/completed_challenges 2>/dev/null | wc -l)
if [ "$ACTUAL" -ge "$EXPECTED" ]; then
_pass "Progress persisted after reboot ($ACTUAL challenges)"
_pass "Progress persisted after reboot ($ACTUAL checks)"
else
_fail "Progress lost after reboot (expected ${EXPECTED}, got ${ACTUAL})"
fi
Expand Down Expand Up @@ -192,6 +192,12 @@ else
exit 1
fi

if echo "${VERIFY_OUTPUT}" | grep -q "1/19"; then
_pass "verify progress counts the example check"
else
_fail "verify progress did not show 1/19 after the example check"
fi

if [[ -f /var/ctf/ctf_start_time ]]; then
_pass "Timer starts after first numeric verify command"
else
Expand Down Expand Up @@ -580,10 +586,10 @@ fi
_section "VERIFICATION TOKEN TEST"

PROGRESS=$(verify progress 2>&1)
if echo "${PROGRESS}" | grep -q "18/18"; then
_pass "All 18 challenges completed"
if echo "${PROGRESS}" | grep -q "19/19"; then
_pass "All 19 progress checks completed"
else
_fail "Not all challenges completed: ${PROGRESS}"
_fail "Not all progress checks completed: ${PROGRESS}"
fi

EXPORT_OUT=$(verify export testuser 2>&1) || true
Expand Down
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,9 @@ Save the token it generates — you'll need it to verify your progress at [learn

- `verify time` shows **wall clock elapsed time** (not active keyboard time).
- The timer starts when you first submit a challenge with `verify <number> <flag>`.
- The timer freezes on your first successful `verify export` after reaching 18/18.
- Run `verify 0 CTF{example}` early. The example challenge is part of verify progress tracking.
- Progress tracks 19 total checks: the example verification plus the 18 real challenges.
- After `verify 0 CTF{example}`, `verify progress` should show `1/19`.
- The timer freezes on your first successful `verify export` after you've solved all 18 real challenges.

### Troubleshooting Your Token

Expand Down
2 changes: 1 addition & 1 deletion gcp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@

## Timer Behavior

`verify time` uses wall clock elapsed time. The timer starts on your first challenge submission and freezes on your first successful `verify export` after 18/18.
`verify time` uses wall clock elapsed time. The timer starts on your first challenge submission and freezes on your first successful `verify export` after you've solved all 18 real challenges.


## Cleaning Up
Expand Down
38 changes: 24 additions & 14 deletions verify/src/verify/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,15 +68,25 @@
]


def completed_count() -> int:
EXAMPLE_CHALLENGE_NUMBER = 0
MAX_CHALLENGE_NUMBER = len(CHALLENGE_NAMES) - 1
REAL_CHALLENGE_COUNT = MAX_CHALLENGE_NUMBER
TOTAL_PROGRESS_CHECKS = len(CHALLENGE_NAMES)


def completed_progress_count() -> int:
return len(read_completed())


def completed_challenge_count() -> int:
completed = read_completed()
return max(len(completed - {0}), 0)
return max(len(completed - {EXAMPLE_CHALLENGE_NUMBER}), 0)


def show_progress() -> None:
count = completed_count()
console.print(f"Flags Found: {count}/18")
if count == 18:
count = completed_progress_count()
console.print(f"Flags Found: {count}/{TOTAL_PROGRESS_CHECKS}")
if count == TOTAL_PROGRESS_CHECKS:
console.print("Congratulations! You've completed all challenges!")


Expand All @@ -98,7 +108,7 @@ def elapsed_seconds() -> int | None:
def freeze_end_time_on_export() -> None:
if END_TIME_FILE.exists():
return
if completed_count() >= 18:
if completed_challenge_count() >= REAL_CHALLENGE_COUNT:
END_TIME_FILE.write_text(f"{int(time.time())}\n")
END_TIME_FILE.chmod(0o666)

Expand All @@ -114,8 +124,8 @@ def format_elapsed(seconds: int, *, include_seconds: bool) -> str:

def check_flag(state: CtfState, challenge_num: str, submitted_flag: str) -> int:
init_timer()
if not challenge_num.isdigit() or not 0 <= int(challenge_num) <= 18:
console.print("✗ Invalid challenge number. Use 0-18.")
if not challenge_num.isdigit() or not 0 <= int(challenge_num) <= MAX_CHALLENGE_NUMBER:
console.print(f"✗ Invalid challenge number. Use 0-{MAX_CHALLENGE_NUMBER}.")
return 1

num = int(challenge_num)
Expand Down Expand Up @@ -158,8 +168,8 @@ def show_list() -> int:


def show_hint(num_text: str | None) -> int:
if num_text is None or not num_text.isdigit() or int(num_text) > 18:
console.print("Usage: verify hint [0-18]")
if num_text is None or not num_text.isdigit() or int(num_text) > MAX_CHALLENGE_NUMBER:
console.print(f"Usage: verify hint [0-{MAX_CHALLENGE_NUMBER}]")
return 1
num = int(num_text)
console.print("======================================")
Expand All @@ -171,10 +181,10 @@ def show_hint(num_text: str | None) -> int:


def export_certificate(state: CtfState, github_username: str | None) -> int:
count = completed_count()
if count < 18:
console.print("Complete all 18 challenges to earn your certificate!")
console.print(f"Current progress: {count}/18")
count = completed_challenge_count()
if count < REAL_CHALLENGE_COUNT:
console.print(f"Complete all {REAL_CHALLENGE_COUNT} challenges to earn your certificate!")
console.print(f"Current progress: {count}/{REAL_CHALLENGE_COUNT}")
return 1

if not github_username:
Expand Down
Loading