fix(tests): restrict On Hold/Resume to whichever team currently owns the test

canHold checked role OR role instead of matching the current phase, so
a red_tech still saw (and could call) Hold/Resume on a test already
sitting in blue_evaluating. Fixed on both frontend and backend — the
API had the same gap, not just the button visibility.
This commit is contained in:
kitos
2026-07-14 17:24:05 +02:00
parent 8fcd733d4a
commit 1b7fd6fb36
3 changed files with 85 additions and 3 deletions
+19
View File
@@ -1310,6 +1310,21 @@ def assign_test_operators(
# ---------------------------------------------------------------------------
def _check_hold_permission(current_user: User, test) -> None:
"""Only whichever team currently owns the test may hold/resume it.
``require_any_role_strict("red_tech", "blue_tech")`` alone lets either
role through regardless of phase — a red_tech could otherwise hold (or
resume) a test that has already moved into blue_evaluating.
"""
expected_role = "blue_tech" if test.state == TestState.blue_evaluating else "red_tech"
if current_user.role != expected_role:
raise HTTPException(
status_code=403,
detail=f"Only {expected_role.replace('_', ' ')} can do this while the test is in '{test.state}'.",
)
@router.post("/{test_id}/hold", response_model=TestOut)
def hold_test(
test_id: uuid.UUID,
@@ -1330,6 +1345,8 @@ def hold_test(
detail=f"Cannot hold a test in state '{test.state}'. Only pre-validation states can be held.",
)
_check_hold_permission(current_user, test)
if test.is_on_hold:
raise HTTPException(status_code=400, detail="Test is already on hold")
@@ -1370,6 +1387,8 @@ def resume_test(
if not test.is_on_hold:
raise HTTPException(status_code=400, detail="Test is not on hold")
_check_hold_permission(current_user, test)
test.is_on_hold = False
test.hold_reason = None
test.held_at = None