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
6 changes: 4 additions & 2 deletions .github/skills/ctf-testing/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,17 @@ Run from repository root:
2. **Challenge setup** - Files exist, services running, permissions correct
3. **Solution commands** - Each challenge returns valid flag
4. **Flag submission** - All 18 flags accepted by `verify`
5. **Reboot resilience** (with `--with-reboot`) - Services restart, progress persists
5. **Verification token system** - Instance secrets, token generation, token format validation
6. **Reboot resilience** (with `--with-reboot`) - Services restart, progress persists

## Expected Results

A successful run shows **69 tests passing**:
A successful run shows **~84 tests passing**:
- 7 verify subcommand tests
- 24 challenge setup verifications
- 18 solution command tests
- 20 flag verification tests
- 15 verification token tests

## Troubleshooting

Expand Down
96 changes: 96 additions & 0 deletions .github/skills/ctf-testing/test_ctf_challenges.sh
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,102 @@ verify_captured_flag 18
run_test_output "verify progress shows 18/18" \
"verify progress" "18/18"

# ============================================================================
section "VERIFICATION TOKEN TESTS"
# ============================================================================

echo "Testing the verification token export system..."

# Test that verification secrets were created
run_test "Verification secrets: instance_id exists" \
"test -f /etc/ctf/instance_id && test -s /etc/ctf/instance_id"

run_test "Verification secrets: verification_secret exists" \
"test -f /etc/ctf/verification_secret && test -s /etc/ctf/verification_secret"

run_test "Verification secrets: instance_id is 32 hex chars" \
"test \$(cat /etc/ctf/instance_id | wc -c) -eq 33" # 32 chars + newline

run_test "Verification secrets: verification_secret is 64 hex chars (SHA256)" \
"test \$(cat /etc/ctf/verification_secret | wc -c) -eq 65" # 64 chars + newline

# Test export command now that all challenges are complete
echo "Testing verify export command..."

EXPORT_OUTPUT=$(verify export testuser 2>&1) || true
# Save to file to avoid issues with special characters in ASCII art
echo "$EXPORT_OUTPUT" > /tmp/ctf_export_output.txt

# Check export output contains expected content (using file to avoid shell escaping issues)
if grep -q "COMPLETION CERTIFICATE" /tmp/ctf_export_output.txt 2>/dev/null; then
pass "verify export creates certificate"
else
fail "verify export creates certificate"
fi

if grep -q "testuser" /tmp/ctf_export_output.txt 2>/dev/null; then
pass "verify export shows GitHub username"
else
fail "verify export shows GitHub username"
fi

if grep -q "BEGIN L2C CTF TOKEN" /tmp/ctf_export_output.txt 2>/dev/null; then
pass "verify export generates verification token"
else
fail "verify export generates verification token"
fi

# Extract and validate token format (using file to avoid shell escaping)
TOKEN=$(sed -n '/BEGIN L2C CTF TOKEN/,/END L2C CTF TOKEN/p' /tmp/ctf_export_output.txt | grep -v 'L2C CTF TOKEN' | tr -d '\n ')
if [ -n "$TOKEN" ]; then
pass "verify export: Token extracted"

# Token should be valid base64
DECODED=$(echo "$TOKEN" | base64 -d 2>/dev/null) || DECODED=""
if [ -n "$DECODED" ]; then
pass "verify export: Token is valid base64"

# Check token contains expected JSON fields
if echo "$DECODED" | grep -q '"payload"'; then
pass "verify export: Token contains payload"
else
fail "verify export: Token missing payload field"
fi

if echo "$DECODED" | grep -q '"signature"'; then
pass "verify export: Token contains signature"
else
fail "verify export: Token missing signature field"
fi

if echo "$DECODED" | grep -q '"github_username":"testuser"'; then
pass "verify export: Token contains correct github_username"
else
fail "verify export: Token has wrong or missing github_username"
fi

if echo "$DECODED" | grep -q '"challenges":18'; then
pass "verify export: Token shows 18 challenges"
else
fail "verify export: Token has wrong challenge count"
fi

if echo "$DECODED" | grep -q '"instance_id"'; then
pass "verify export: Token contains instance_id"
else
fail "verify export: Token missing instance_id"
fi
else
fail "verify export: Token is not valid base64"
fi
else
fail "verify export: No token found in output"
fi

# Test that export without username shows usage
run_test_output "verify export without username shows usage" \
"verify export 2>&1" "Usage:"

# ============================================================================
section "TEST SUMMARY"
# ============================================================================
Expand Down
1 change: 1 addition & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ For thorough testing (includes reboot verification):
- Services are running and accessible
- Flags can be discovered and submitted
- Progress tracking works
- Verification token generation and format
- (With `--with-reboot`) Services survive VM restart

See [.github/skills/ctf-testing/SKILL.md](.github/skills/ctf-testing/SKILL.md) for detailed documentation.
Expand Down
24 changes: 24 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,30 @@ Deploy your CTF lab using your preferred cloud provider:
| Azure | ~$0.05 | [Azure Setup](./azure/README.md) |
| GCP | ~$0.03 | [GCP Setup](./gcp/README.md) |

## Completing the CTF

Once you've solved all 18 challenges, export your completion certificate:

```bash
verify export <your-github-username>
```

> [!IMPORTANT]
> Enter your GitHub username **exactly** as it appears on GitHub—no `@` symbol, no extra spaces, no special characters. For example: `verify export octocat` not `verify export @octocat`. The verification system will reject tokens with incorrect usernames.

This generates a cryptographically signed token. To verify your completion:

1. Go to [learntocloud.guide/phase2](https://learntocloud.guide/phase2)
2. Sign in with the **same GitHub account** you used in the export command
3. Copy **only the token** (the long string of characters between the markers):
```
--- BEGIN L2C CTF TOKEN ---
eyJwYXlsb2FkIjp7...your-unique-token-here...fQ==
--- END L2C CTF TOKEN ---
```
> **Copy everything between the markers, but NOT the `--- BEGIN/END ---` lines themselves.**
4. Paste the token into the verification form

## Tips

- Use `man` pages to learn commands (e.g., `man find`)
Expand Down
Loading