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:
@@ -913,7 +913,17 @@ def bulk_update(payload: BulkTaskBody, board: Optional[str] = Query(None)):
|
|||||||
ok = kanban_db.unblock_task(conn, tid)
|
ok = kanban_db.unblock_task(conn, tid)
|
||||||
else:
|
else:
|
||||||
ok = _set_status_direct(conn, tid, "ready")
|
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)
|
ok = _set_status_direct(conn, tid, s)
|
||||||
else:
|
else:
|
||||||
entry.update(ok=False, error=f"unknown status {s!r}")
|
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()
|
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():
|
def test_dashboard_done_actions_prompt_for_completion_summary():
|
||||||
repo_root = Path(__file__).resolve().parents[2]
|
repo_root = Path(__file__).resolve().parents[2]
|
||||||
bundle = (
|
bundle = (
|
||||||
|
|||||||
Reference in New Issue
Block a user