What happened
DELETE /jobs/{job_id} deletes the on-disk working directory for a scan job, but it does not remove the corresponding rows from the SQLite database. After deletion the job still appears in dashboard charts (/trends, /cwe-distribution, /dependency-diff) and the findings are still returned by /jobs/{job_id}/findings, even though the workspace is gone.
Steps to reproduce
- Run a scan (upload a ZIP or paste a GitHub URL). Note the returned
job_id.
- Call
DELETE /jobs/{job_id}.
- Call
GET /trends — the deleted job's scan is still counted.
- Call
GET /jobs/{job_id}/findings — it still returns the old findings.
- Check the working directory
$PATCHPILOT_WORKDIR/<job_id> — it has been deleted.
Expected behaviour
Deleting a job removes:
- The on-disk workspace (already happens ✅)
- All rows in
findings where job_id = ?
- All rows in
verify_outcomes where job_id = ?
- The row in
jobs where job_id = ?
These three deletions should be wrapped in a single database transaction so they succeed or fail together.
Actual behaviour
Only safe_rmtree(job_dir) is called. No SQL DELETE statements are executed.
Relevant code — backend/app/main.py, lines 1022–1027:
@app.delete("/jobs/{job_id}")
def delete_job(job_id: str):
job_dir = WORK_ROOT / job_id
if job_dir.exists():
safe_rmtree(job_dir)
return {"deleted": True}
Environment
| Field |
Value |
| OS |
Any |
| Python version |
3.10+ |
| PatchPilot version / commit |
main |
| Scan method |
Any |
Logs
No error is raised — the endpoint returns {"deleted": true} normally. The issue is silent data leakage, not a crash.
Additional context
The fix is a few lines of SQL added to delete_job. The function should also be made async so it can await the DB calls. A test should be added to tests/test_job_endpoints.py that:
- Creates a scan job (mock or fixture).
- Calls
DELETE /jobs/{job_id}.
- Verifies the DB rows are gone.
Acceptance criteria:
What happened
DELETE /jobs/{job_id}deletes the on-disk working directory for a scan job, but it does not remove the corresponding rows from the SQLite database. After deletion the job still appears in dashboard charts (/trends,/cwe-distribution,/dependency-diff) and the findings are still returned by/jobs/{job_id}/findings, even though the workspace is gone.Steps to reproduce
job_id.DELETE /jobs/{job_id}.GET /trends— the deleted job's scan is still counted.GET /jobs/{job_id}/findings— it still returns the old findings.$PATCHPILOT_WORKDIR/<job_id>— it has been deleted.Expected behaviour
Deleting a job removes:
findingswherejob_id = ?verify_outcomeswherejob_id = ?jobswherejob_id = ?These three deletions should be wrapped in a single database transaction so they succeed or fail together.
Actual behaviour
Only
safe_rmtree(job_dir)is called. No SQLDELETEstatements are executed.Relevant code —
backend/app/main.py, lines 1022–1027:Environment
mainLogs
No error is raised — the endpoint returns
{"deleted": true}normally. The issue is silent data leakage, not a crash.Additional context
The fix is a few lines of SQL added to
delete_job. The function should also be madeasyncso it canawaitthe DB calls. A test should be added totests/test_job_endpoints.pythat:DELETE /jobs/{job_id}.Acceptance criteria:
DELETE /jobs/{job_id}deletes rows fromfindings,verify_outcomes, andjobsin a transaction.{"deleted": true}only if all DB deletions succeed.tests/test_job_endpoints.pycovers the DB cleanup.