fix(kanban): reject direct running transitions in dashboard bulk updates

Salvages #24050 by @kronexoi. The single-task PATCH already rejects
direct status='running' since it bypasses the dispatcher/claim invariant,
but the bulk-update endpoint still accepted it. Aligns bulk with single
by emitting an error result row for any 'running' entry.
This commit is contained in:
kronexoi
2026-05-18 20:38:26 -07:00
committed by Teknium
parent 666b66a066
commit e8ce7b83fa
2 changed files with 36 additions and 1 deletions
+11 -1
View File
@@ -913,7 +913,17 @@ def bulk_update(payload: BulkTaskBody, board: Optional[str] = Query(None)):
ok = kanban_db.unblock_task(conn, tid)
else:
ok = _set_status_direct(conn, tid, "ready")
elif s in {"todo", "running", "triage"}:
elif s == "running":
entry.update(
ok=False,
error=(
"Cannot set status to 'running' directly; "
"use the dispatcher/claim path"
),
)
results.append(entry)
continue
elif s in {"todo", "triage"}:
ok = _set_status_direct(conn, tid, s)
else:
entry.update(ok=False, error=f"unknown status {s!r}")
@@ -880,6 +880,31 @@ def test_bulk_status_done_forwards_completion_summary(client):
conn.close()
def test_bulk_status_running_rejected(client):
"""Bulk updates must match single-task PATCH: direct 'running' is invalid."""
t = client.post("/api/plugins/kanban/tasks", json={"title": "x"}).json()["task"]
r = client.post(
"/api/plugins/kanban/tasks/bulk",
json={"ids": [t["id"]], "status": "running"},
)
assert r.status_code == 200
results = r.json()["results"]
assert len(results) == 1
assert results[0]["id"] == t["id"]
assert results[0]["ok"] is False
assert "running" in results[0]["error"]
board = client.get("/api/plugins/kanban/board").json()
statuses = {
tt["id"]: col["name"]
for col in board["columns"]
for tt in col["tasks"]
}
assert statuses.get(t["id"]) != "running"
def test_dashboard_done_actions_prompt_for_completion_summary():
repo_root = Path(__file__).resolve().parents[2]
bundle = (