Manual Test Runbook — X7: Sandbox Cleanup Workflow
Owner: Sagar | Time: ~5 min (Parts A + B offline) · +10 min (optional Part C live drill) | Sandbox: snowops-sandbox-01
Promotes X7 (
sandbox/cleanup/+.github/workflows/sandbox-cleanup.yml) from 🟦 Code Complete → 🟩 Shipped. Parts A + B are 100% offline (shellcheck + the selection unit test + YAML lint). Part C is a live sandbox drill (~$0): seed three throwaway RGs, run the script, confirm the ephemeral one is deleted and the protected / non-ephemeral ones survive.
Prerequisites
- Local tooling:
bash,python3,shellcheck,ruby(YAML lint) - (Part C only)
az logindone;az account showconfirms the sandbox subscription is selected - (Part C only) Identity has Contributor on the sandbox sub (RG create + delete)
- Working directory: repo root
Steps
Part A — shellcheck + offline selection test (offline, ~3 min)
- Lint both scripts:
Expected: no output (clean).
- Run the offline selection test (feeds a fixture RG list, dry-run, asserts the plan):
Expected: ==> OK: all X7 selection assertions passed — 12 assertions, all ✓.
It proves: the two ephemeral test RGs are selected; the sandbox baseline RG
(protected glob), the state RG (ephemeral=false), a prod RG (no ephemeral tag),
a too-young RG (age guard), and NetworkWatcherRG are all preserved.
Part B — workflow YAML lint (offline, ~2 min)
bash ruby -ryaml -e "YAML.load_file('.github/workflows/sandbox-cleanup.yml'); puts 'parses OK'" # Optional, if installed: actionlint .github/workflows/sandbox-cleanup.yml
Expected: parses OK (and actionlint clean if run).
Part C — live sandbox drill (optional, ~10 min, ~$0)
Empty resource groups are free. This drill creates three, runs the cleanup, and confirms the selection behaves on real Azure exactly as the unit test predicts.
- Seed three throwaway resource groups in the sandbox sub:
# (a) an ephemeral test RG — should be DELETED
az group create -n snowops-x7drill-test -l eastus \
--tags ephemeral=true Owner=terratest
# (b) a name that matches the protected glob — should be PRESERVED
az group create -n snowops-sandbox-x7drill-rg -l eastus \
--tags ephemeral=true Owner=snowops
# (c) a non-ephemeral RG — should be PRESERVED
az group create -n snowops-x7drill-keep -l eastus \
--tags ephemeral=false Owner=snowops
- Preview the plan (dry-run, min-age 0 so the brand-new RG isn't age-skipped):
Expected in the output:
- WOULD DELETE: snowops-x7drill-test
- SKIP (protected): snowops-sandbox-x7drill-rg
- SKIP (not ephemeral): snowops-x7drill-keep
- Run for real:
- Confirm the result (deletes are
--no-wait; allow ~1 min):
az group exists -n snowops-x7drill-test # → false (deleted)
az group exists -n snowops-sandbox-x7drill-rg # → true (preserved)
az group exists -n snowops-x7drill-keep # → true (preserved)
- (Optional) Trigger the workflow itself in dry-run from the Actions tab
(
sandbox-cleanup→ Run workflow → dry_run = true) and confirm the step summary lists the same plan.
Pass criteria
- Part A — shellcheck clean; offline test passes all 12 assertions
- Part B — workflow YAML parses
- (Part C) the ephemeral drill RG is deleted; the protected-name RG and the non-ephemeral RG both survive
- All drill resources removed
Teardown
# Part C: clean up any survivors from the drill.
az group delete -n snowops-sandbox-x7drill-rg --yes --no-wait 2>/dev/null || true
az group delete -n snowops-x7drill-keep --yes --no-wait 2>/dev/null || true
az group delete -n snowops-x7drill-test --yes --no-wait 2>/dev/null || true
Sign-off
- Tester: _ | Date: _ | Result: PASS / FAIL / N/A
- Notes: