| name | cleanup-orphaned-resources |
| description | Discover and remove cloud or local resources leaked by aborted or failed eval runs — stale per-run state, leftover kind clusters and their node containers, stuck harness processes, and orphaned GKE clusters, node service accounts, secrets, VPCs and their dependencies, Cloud SQL instances, and Artifact Registry repos in the sandbox project, all scoped to the aborted run's own token. Invoke when a "fresh" run fails instantly, when someone reports leaked or orphaned resources, or asks to "clean up after a failed run", "sweep the sandbox project", or "why does re-running 409?". |
Clean up orphaned resources
A crashed or aborted run leaves debris: scratch state on the host the run
executed on, kind clusters and their node containers, stuck processes, and — worse —
cloud resources a failed teardown never removed. The cloud leftovers cause the
classic "a fresh run fails instantly" symptom, often a 409 already exists. This skill finds that
debris and removes it after explicit confirmation.
The cloud half of this skill is written against GCP, since that is where the
eval projects live. The shape generalizes: discover by run-token prefix, list,
confirm, delete in dependency order.
Flow
1. Local wipe first
Most "instant fresh failure" cases are local stale state, not cloud leaks. Run the
"Before any retry" checklist in
known_issues.md — it wipes
/tmp/devops-bench-runs/*, deletes leftover kind clusters and their orphaned node
containers (which kind get clusters does not track), and kills stale
devops_bench / agent processes from a prior launch. Do this on the host the run
actually ran on. Don't restate the commands here — follow the checklist.
2. Cloud discovery (sandbox project only, list mode)
Confirm the active project is the sandbox / eval project before touching
anything. Then list (never delete yet) the resources a failed teardown leaks.
Match on run-token prefixes so you never sweep shared infra.
PROJECT="my-sandbox-project"
CLUSTER=""
gcloud container clusters list --project "$PROJECT" \
--filter="name~'^c[0-9a-f]{8}-'" --format="table(name,location,status)"
CLUSTER="cbd827e1-bench-opa"
SLUG=$(printf '%s' "$CLUSTER" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9][^a-z0-9]*/-/g' | cut -c1-9 | sed 's/-$//')
SA="gke-nodes-${SLUG}-$(printf '%s' "$CLUSTER" | md5sum | cut -c1-6)@${PROJECT}.iam.gserviceaccount.com"
gcloud iam service-accounts list --project "$PROJECT" --filter="email=$SA" --format="table(email)"
gcloud artifacts repositories list --project \
--filter= --format=
gcloud secrets list --project --filter= --format=
gcloud compute networks list --project --filter= --format=
gcloud sql instances list --project --filter= --format=
Every filter above is anchored to the exact $CLUSTER name, not a substring of
it. Do not relax them to a bare gke-nodes- or hello-app- prefix, and do not
drop the trailing $: a sibling run is very likely live in the same project and
its resources share those prefixes. Read the listing and confirm each name
belongs to the aborted run before deleting anything.
Two notes on Cloud SQL: a deleted instance's dependent resources can take
several days to disappear, and name reuse after deletion is not guaranteed to
be immediate. Neither matters if the instance name carries the run token, which
is what the task-review checklist requires.
3. LIST findings, then get explicit confirmation
Deletion here is destructive and outward-facing — it removes real cloud
resources. Present the discovered list to the operator and get an explicit
go-ahead before deleting anything. Default to list/dry-run; deletion is opt-in.
Only sweep resources whose names carry the run-token prefix of the aborted run(s).
Never touch shared or long-lived infra, and never operate outside the sandbox
project.
4. Delete (only after confirmation)
gcloud container clusters delete <name> --location <loc> --project "$PROJECT" --quiet
gcloud iam service-accounts delete "$SA" --project "$PROJECT" --quiet
gcloud secrets delete <name> --project "$PROJECT" --quiet
gcloud compute firewall-rules delete <rule> --project "$PROJECT" --quiet
gcloud compute networks delete <network> --project "$PROJECT" --quiet
gcloud artifacts repositories delete <name> --location <loc> --project "$PROJECT" --quiet
Delete in dependency order: the cluster before its node SA, and a VPC's
dependents before the VPC. After deleting, re-run the discovery in step 2 and
confirm it returns nothing for this run's token.
5. Report
Report what was found, what was deleted (with names), what was deliberately left,
and confirm the discovery list is now empty so a re-run won't 409.
Guardrails
- Always list and get explicit confirmation before deleting. No silent sweeps.
- Sandbox / eval project only — verify the active project first; never a shared or
production project.
- Match the aborted run's token prefix; never touch shared or long-lived infra.
- Default to list/dry-run mode; deletion is opt-in.
- A stranded
gke-nodes-* SA no longer causes 409 already exists on re-run — the
name carries an md5 of the cluster name — but it is still the most commonly
leaked resource, so sweep it.