def test_fixed_role_permission_matrix_is_monotonic(): from app.core.system.permissions import ROLE_PERMISSIONS viewer = ROLE_PERMISSIONS["viewer"] editor = ROLE_PERMISSIONS["editor"] admin = ROLE_PERMISSIONS["admin"] assert viewer < editor < admin assert "governance:read" in viewer assert "governance:edit" in editor assert "users:manage" in admin assert "workflow:activate" in admin assert "ingestion:run" in editor assert "data-elements:edit" in editor assert "ontologies:edit" in editor assert "ingestion:admin" in admin assert "evidence:download" in admin assert "data-elements:publish" in admin assert "ontologies:publish" in admin def test_data_development_paths_have_specific_write_policies(): from app.core.system.permissions import permission_for_request assert permission_for_request( "/api/development/v1/ingestion-jobs", "POST" ) == ("ingestion:run",) assert permission_for_request( "/api/development/v1/ingestion-jobs/job-1/retry", "POST" ) == ("ingestion:admin",) assert permission_for_request( "/api/development/v1/ingestion-jobs/job-1/cancel", "POST" ) == ("ingestion:run",) assert permission_for_request( "/api/development/v1/data-elements", "POST" ) == ("data-elements:edit",) assert permission_for_request( "/api/development/v1/data-elements/element-1/transitions", "POST" ) == ("data-elements:edit",) assert permission_for_request( "/api/development/v1/candidate-decisions", "POST" ) == ("data-elements:edit",) def test_permissions_are_derived_server_side_from_roles(): from app.core.system.permissions import permissions_for_roles permissions = permissions_for_roles(["viewer", "editor"]) assert "governance:read" in permissions assert "governance:edit" in permissions assert "users:manage" not in permissions def test_every_api_path_has_an_explicit_policy(): from app import create_app from app.core.system.permissions import permission_for_request app = create_app() for rule in app.url_map.iter_rules(): if not rule.rule.startswith("/api/"): continue for method in rule.methods - {"HEAD", "OPTIONS"}: assert permission_for_request(rule.rule, method) is not None, ( method, rule.rule, )