58c0143304
Aegis CI / lint-and-test (push) Has been cancelled
Snyk Security Scan / Python vulnerabilities (backend) (push) Has been cancelled
Snyk Security Scan / npm vulnerabilities (frontend) (push) Has been cancelled
Snyk Security Scan / Docker image vulnerabilities (backend) (push) Has been cancelled
Admin administers the site — it no longer has any override on
validate-red/blue, review-red/blue, resolve-dispute, request-discussion,
reopen, hold, resume, assign-operators, or classification-update.
Introduces require_any_role_strict(), a role dependency without the
global admin bypass, so these specific endpoints truly exclude admin
instead of only removing it from the (redundant) role tuple.
Managers gain the ability to assign red_tech/blue_tech operators
(POST /tests/{id}/assign, GET /users/operators) alongside leads, since
that's coordination, not resolving a ticket.
Also enlarges and repositions the operator-assignment controls next
to the Start Execution button, and fixes a literal '\u2014' rendering
as text instead of an em dash in the test detail technique line.
34 lines
1.5 KiB
Python
34 lines
1.5 KiB
Python
"""Admin must be locked out of every Test-workflow *action* endpoint.
|
|
|
|
Admin administers the site; leads/managers/operators run the test workflow.
|
|
The permission dependency runs before any DB lookup, so a random UUID is
|
|
enough to prove the 403 — the request never reaches the handler body.
|
|
"""
|
|
|
|
import uuid
|
|
|
|
import pytest
|
|
|
|
DUMMY_ID = str(uuid.uuid4())
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"method,path,payload",
|
|
[
|
|
("post", f"/api/v1/tests/{DUMMY_ID}/review-red", {"decision": "approve"}),
|
|
("post", f"/api/v1/tests/{DUMMY_ID}/review-blue", {"decision": "approve"}),
|
|
("post", f"/api/v1/tests/{DUMMY_ID}/validate-red", {"red_validation_status": "approved"}),
|
|
("post", f"/api/v1/tests/{DUMMY_ID}/validate-blue", {"blue_validation_status": "approved"}),
|
|
("post", f"/api/v1/tests/{DUMMY_ID}/resolve-dispute", {"target_team": "red"}),
|
|
("post", f"/api/v1/tests/{DUMMY_ID}/request-discussion", None),
|
|
("post", f"/api/v1/tests/{DUMMY_ID}/reopen", None),
|
|
("post", f"/api/v1/tests/{DUMMY_ID}/hold", {"reason": "x"}),
|
|
("post", f"/api/v1/tests/{DUMMY_ID}/resume", None),
|
|
("post", f"/api/v1/tests/{DUMMY_ID}/assign", {"red_tech_assignee": DUMMY_ID}),
|
|
("patch", f"/api/v1/tests/{DUMMY_ID}/classification", {"data_classification": "pii"}),
|
|
],
|
|
)
|
|
def test_admin_forbidden(client, auth_headers, method, path, payload):
|
|
resp = getattr(client, method)(path, json=payload, headers=auth_headers)
|
|
assert resp.status_code == 403, f"{method.upper()} {path} -> {resp.status_code}: {resp.text}"
|