bbe7f49c86
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
- A lead opening a test with a pending procedure suggestion awaiting
their review now gets a blocking popup (approve/reject only) instead
of discovering it later in a separate queue.
- Users can be granted more than one role via extra_roles; only one is
ever active at a time (no permission mixing) and a top-bar switcher
lets the user swap which one, taking effect immediately since role
is read fresh from the DB on every request.
- The password-setup/reset webhook now posts the agreed Power Automate
contract ({to, subject, body} with the platform's standard greeting
and signature template) and supports an admin-configured API key
sent as an x-api-key header.
97 lines
3.1 KiB
Python
97 lines
3.1 KiB
Python
"""A user can be granted more than one role but only ever acts under a
|
|
single active one at a time — switching swaps which role is active
|
|
instead of ever mixing permissions from more than one.
|
|
"""
|
|
|
|
|
|
def test_admin_can_grant_extra_roles(api, auth_headers):
|
|
created = api(
|
|
"post", "/api/v1/users", auth_headers,
|
|
json={"full_name": "Multi Role User", "email": "multirole@test.com", "role": "red_tech"},
|
|
)
|
|
assert created.status_code == 201, created.text
|
|
user_id = created.json()["id"]
|
|
|
|
resp = api(
|
|
"patch", f"/api/v1/users/{user_id}", auth_headers,
|
|
json={"extra_roles": ["blue_tech", "red_lead"]},
|
|
)
|
|
assert resp.status_code == 200, resp.text
|
|
assert resp.json()["role"] == "red_tech"
|
|
assert set(resp.json()["extra_roles"]) == {"blue_tech", "red_lead"}
|
|
|
|
|
|
def test_admin_cannot_grant_invalid_extra_role(api, auth_headers):
|
|
created = api(
|
|
"post", "/api/v1/users", auth_headers,
|
|
json={"full_name": "Bad Extra Role", "email": "badextrarole@test.com", "role": "viewer"},
|
|
)
|
|
user_id = created.json()["id"]
|
|
|
|
resp = api(
|
|
"patch", f"/api/v1/users/{user_id}", auth_headers,
|
|
json={"extra_roles": ["superuser"]},
|
|
)
|
|
assert resp.status_code == 400
|
|
|
|
|
|
def test_user_can_switch_to_a_granted_extra_role(api, db, auth_headers):
|
|
from app.auth import hash_password
|
|
from app.models.user import User
|
|
|
|
user = User(
|
|
username="switcher@test.com",
|
|
email="switcher@test.com",
|
|
full_name="Switcher",
|
|
hashed_password=hash_password("SwitcherPass123!@#"),
|
|
role="red_tech",
|
|
extra_roles=["blue_tech"],
|
|
must_change_password=False,
|
|
)
|
|
db.add(user)
|
|
db.commit()
|
|
|
|
login = api(
|
|
"post", "/api/v1/auth/login", {},
|
|
data={"username": "switcher@test.com", "password": "SwitcherPass123!@#"},
|
|
)
|
|
assert login.status_code == 200, login.text
|
|
token = login.json()["access_token"]
|
|
headers = {"Authorization": f"Bearer {token}"}
|
|
|
|
resp = api("post", "/api/v1/users/me/switch-role", headers, json={"role": "blue_tech"})
|
|
assert resp.status_code == 200, resp.text
|
|
body = resp.json()
|
|
assert body["role"] == "blue_tech"
|
|
assert body["extra_roles"] == ["red_tech"]
|
|
|
|
me = api("get", "/api/v1/auth/me", headers)
|
|
assert me.json()["role"] == "blue_tech"
|
|
|
|
|
|
def test_user_cannot_switch_to_an_ungranted_role(api, db, auth_headers):
|
|
from app.auth import hash_password
|
|
from app.models.user import User
|
|
|
|
user = User(
|
|
username="switcher2@test.com",
|
|
email="switcher2@test.com",
|
|
full_name="Switcher Two",
|
|
hashed_password=hash_password("SwitcherPass123!@#"),
|
|
role="red_tech",
|
|
extra_roles=["blue_tech"],
|
|
must_change_password=False,
|
|
)
|
|
db.add(user)
|
|
db.commit()
|
|
|
|
login = api(
|
|
"post", "/api/v1/auth/login", {},
|
|
data={"username": "switcher2@test.com", "password": "SwitcherPass123!@#"},
|
|
)
|
|
token = login.json()["access_token"]
|
|
headers = {"Authorization": f"Bearer {token}"}
|
|
|
|
resp = api("post", "/api/v1/users/me/switch-role", headers, json={"role": "admin"})
|
|
assert resp.status_code == 400
|