Repository navigation
[Hackathon] test delete-batch --all --status "" permanently deletes every test in the project (and test rerun --all --status "" reruns every test) #498
Description
Verified against (commit SHA or released version)
988c035 (main, v0.14.0), Linux, Node v22.23.3
Discord Username / User ID
949225590181994556
What does this improvement do?
What's broken
--status <list> is the only thing that narrows test delete-batch --all (permanent delete, no restore window) and test rerun --all (dispatches and bills a run per test). When the value is the empty string, both commands treat it as "no filter" and sweep the whole project:
src/commands/test.ts,runDeleteBatch:validateStatusFilter('')returns early ("Empty / undefined → no filter"), then the filter is skipped byif (opts.statusFilter !== undefined && opts.statusFilter !== ''). Every test returned byGET /tests?projectId=…is deleted.- The
--allbranch ofrunTestRerunCorehas the same two lines, so every test is rerun.
An empty --status is easy to produce, and it is never what the caller meant:
--status "$STATUSES"in a cleanup or CI script when the variable is empty (set -udoesn't catch a variable set to an empty string);--status=(a typo, or a value cut off by a templating step);- a generated command line where the status list came back empty.
The behaviour is also inconsistent: --status , and --status " " select nothing (delete zero tests; rerun exits 5). Only the literal "" flips to "everything".
Repro (loopback mock, no real key, nothing deleted for real)
A stub serves a project with three tests (failed, passed, draft) and logs every DELETE /tests/:id and POST /tests/batch/rerun.
On main @ 988c035:
| command | exit | server saw |
|---|---|---|
test delete-batch --all --project p1 --status failed --confirm |
0 | 1 DELETE (t_failed) |
test delete-batch --all --project p1 --status "" --confirm |
0 | 3 DELETEs: every test in the project |
test delete-batch --all --project p1 --status , --confirm |
0 | 0 DELETEs |
test delete-batch --all --project p1 --status " " --confirm |
0 | 0 DELETEs |
test rerun --all --project p1 --status failed |
0 | testIds=["t_failed"] |
test rerun --all --project p1 --status "" |
0 | testIds=["t_failed","t_passed","t_draft"] |
test rerun --all --project p1 --status , |
5 | no dispatch |
Text output for the empty case gives no hint that the filter was dropped:
Resolving tests in project p1…
Resolved 3 tests to delete.
Deleted 3, skipped 0, failed 0.
Expected
A --status that was given but names no status should be refused before any request, with exit 5 and a message saying why. It should never widen a destructive or billing sweep to the whole project. Leaving --status out still means "every test", so nobody loses a way to do that on purpose.
Fix (PR to follow), all in src/commands/test.ts:
Tests: src/commands/test.quickwins.spec.ts (delete-batch --all with --status "", " " or " , ," → VALIDATION_ERROR on status, zero requests) and src/commands/test.rerun.spec.ts (same three values for rerun --all, plus --dry-run --all --status ""). All 7 new tests fail on main and pass with the fix; existing --status failed / failed,blocked tests still pass.
Checked for duplicates (all issues and PRs, open and closed, as of 17 Oct): #160/#163 (--status without --all ignored), #151/#152/#210/#211/#222 (test list --status validation order), #475 (rerun --all --env status source), #376 (flags ignored without their mode), #395/#468/#382/#386 (empty or whitespace ids). None covers an empty --status widening --all to every test.
Details / implementation notes
- Add
parseStatusSelection(raw): runs the existingvalidateStatusFiltertoken check, then requires at least one non-empty token, otherwise throwslocalValidationError('status', …)(VALIDATION_ERROR, exit 5) naming the accepted values. Returns theSetof statuses to keep. runDeleteBatchand the--allbranch ofrunTestRerunCoreuse it instead ofvalidateStatusFilterplus the!== ''guard, refusing before theGET /testslisting, so nothing is listed, deleted or dispatched.validateRerunOptionsalso calls it, sotest rerun --all --dry-run --status ""refuses the same input. Today the rerun dry-run doesn't validate--statusat all.test list --status ""is left alone (read-only).DOCUMENTATION.md: one sentence undertest delete/test delete-batchand one--statusbullet undertest rerun.
Confirmations
- I have searched existing issues and this is not a duplicate.
- I have provided my Discord identity above for reward coordination.
Activity
cipoklean commentedon Oct 17, 2026
I have a fix ready for this on a local branch: an explicitly empty --status is now rejected with a validation error (exit 5) before any request, for both test delete-batch and test rerun, while an omitted --status keeps today's behaviour. 7 tests (fail on main, pass with the fix); typecheck, format, lint and coverage green. I'll comment /assign and open the PR as soon as this is triaged.
zeshi-du commentedon Oct 20, 2026
Thanks @cipoklean. Accepted. Confirmed in v0.15.0: an explicitly empty
--statusmeans "no filter" indelete-batch --allandrerun --all, so one empty shell variable can delete, or re-run and bill, a whole project. Please /assign and open your PR.--statuswith no status names (empty, whitespace, commas only) is refused with the existing validation error, exit 5, before any request.--statuskeeps meaning every test.delete-batch --allandrerun --all(also with--dry-run); leavetest list --statusalone.rerunis being folded intorunand removed in 1.0, so keep the diff small.cipoklean commentedon Oct 20, 2026
/assign
testsprite-hob commentedon Oct 20, 2026
Assigned to @cipoklean. Thanks for taking this on. (2 more slots available.)
Your open assigned issues (1/3):
(none)