| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315 |
- 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 "governance:responsibilities:read" in viewer
- assert "ingestion:admin" in admin
- assert "evidence:download" in admin
- assert "data-elements:publish" in admin
- assert "ontologies:publish" in admin
- assert "governance:responsibilities:manage" in admin
- assert "device-assets:edit" in editor
- assert "device-semantics:edit" in editor
- assert "device-semantics:review" not in editor
- assert "device-semantics:review" in admin
- assert "device-entities:edit" in editor
- assert "device-entities:review" not in editor
- assert "device-entities:review" in admin
- assert "device-quality:edit" in editor
- assert "device-quality:execute" in editor
- assert "device-quality:publish" not in editor
- assert "device-quality:publish" in admin
- assert "quality-issues:edit" in editor
- assert "quality-issues:review" not in editor
- assert "quality-issues:review" in admin
- assert "device-observability:edit" in editor
- assert "data-observability:read" in viewer
- assert "data-observability:operate" in editor
- assert "data-observability:manage" not in editor
- assert "data-observability:manage" in admin
- assert "governance-audit:read" not in editor
- assert "governance-audit:read" in admin
- assert "governance-audit:seal" 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/ingestion-jobs/job-1/execute", "POST"
- ) == ("ingestion:run",)
- assert permission_for_request(
- "/api/development/v1/ingestion-jobs/job-1/catalog-snapshots", "GET"
- ) == ("governance:read",)
- assert permission_for_request(
- "/api/development/v1/ingestion-jobs/job-1/evidence", "GET"
- ) == ("governance:read",)
- 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",)
- assert permission_for_request(
- "/api/development/v1/device-assets", "GET"
- ) == ("governance:read",)
- assert permission_for_request(
- "/api/development/v1/device-assets/asset-1", "GET"
- ) == ("governance:read",)
- assert permission_for_request(
- "/api/development/v1/device-assets/import", "POST"
- ) == ("device-assets:edit",)
- assert permission_for_request(
- "/api/development/v1/device-semantics/profile", "GET"
- ) == ("governance:read",)
- assert permission_for_request(
- "/api/development/v1/device-semantics/bootstrap", "POST"
- ) == ("device-semantics:edit",)
- assert permission_for_request(
- "/api/development/v1/device-semantics/codes/code-1/submit",
- "POST",
- ) == ("device-semantics:edit",)
- assert permission_for_request(
- "/api/development/v1/device-semantics/codes/code-1/review",
- "POST",
- ) == ("device-semantics:review",)
- assert permission_for_request(
- "/api/development/v1/device-entities/candidates", "GET"
- ) == ("governance:read",)
- assert permission_for_request(
- "/api/development/v1/device-entities/candidates/generate", "POST"
- ) == ("device-entities:edit",)
- assert permission_for_request(
- "/api/development/v1/device-entities/candidates/candidate-1/review",
- "POST",
- ) == ("device-entities:review",)
- assert permission_for_request(
- "/api/development/v1/device-entities/merges/merge-1/rollback",
- "POST",
- ) == ("device-entities:review",)
- assert permission_for_request(
- "/api/development/v1/device-quality/profile", "GET"
- ) == ("governance:read",)
- assert permission_for_request(
- "/api/development/v1/device-quality/bootstrap", "POST"
- ) == ("device-quality:edit",)
- assert permission_for_request(
- "/api/development/v1/device-quality/profile/versions/version-1/publish",
- "POST",
- ) == ("device-quality:publish",)
- assert permission_for_request(
- "/api/development/v1/device-quality/runs", "POST"
- ) == ("device-quality:execute",)
- assert permission_for_request(
- "/api/development/v1/device-quality/issues", "GET"
- ) == ("governance:read",)
- assert permission_for_request(
- "/api/development/v1/device-quality/issues/import", "POST"
- ) == ("quality-issues:edit",)
- assert permission_for_request(
- "/api/development/v1/device-quality/issues/issue-1/review",
- "POST",
- ) == ("quality-issues:review",)
- assert permission_for_request(
- "/api/development/v1/device-observability/events",
- "GET",
- ) == ("governance:read",)
- assert permission_for_request(
- "/api/development/v1/device-observability/graph",
- "GET",
- ) == ("governance:read",)
- assert permission_for_request(
- "/api/development/v1/device-observability/root-cause",
- "GET",
- ) == ("governance:read",)
- assert permission_for_request(
- "/api/development/v1/device-observability/import",
- "POST",
- ) == ("device-observability:edit",)
- assert permission_for_request(
- "/api/development/v1/governance-metrics/summary",
- "GET",
- ) == ("governance:read",)
- assert permission_for_request(
- "/api/development/v1/governance-metrics/details",
- "GET",
- ) == ("governance:read",)
- assert permission_for_request(
- "/api/datafactory/observability/overview",
- "GET",
- ) == ("data-observability:read",)
- assert permission_for_request(
- "/api/datafactory/observability/collect",
- "POST",
- ) == ("data-observability:operate",)
- assert permission_for_request(
- "/api/datafactory/observability/slos",
- "POST",
- ) == ("data-observability:manage",)
- assert permission_for_request(
- "/api/system/governance-audit/events",
- "GET",
- ) == ("governance-audit:read",)
- assert permission_for_request(
- "/api/system/governance-audit/seals",
- "POST",
- ) == ("governance-audit:seal",)
- def test_business_domain_read_endpoints_are_available_to_viewers():
- from app.core.system.permissions import permission_for_request
- assert permission_for_request("/api/bd/list", "POST") == (
- "governance:read",
- )
- assert permission_for_request("/api/bd/detail", "POST") == (
- "governance:read",
- )
- assert permission_for_request("/api/bd/save", "POST") == (
- "governance: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,
- )
- def test_knowledge_search_and_ask_posts_are_read_only():
- from app.core.system.permissions import READ_GOVERNANCE, permission_for_request
- assert permission_for_request("/api/knowledge/search", "POST") == (
- READ_GOVERNANCE,
- )
- assert permission_for_request("/api/knowledge/ask", "POST") == (READ_GOVERNANCE,)
- def test_knowledge_admin_routes_require_dedicated_manage_permission():
- from app.core.system.permissions import KNOWLEDGE_MANAGE, permission_for_request
- assert permission_for_request("/api/knowledge/admin/sync", "GET") == (
- KNOWLEDGE_MANAGE,
- )
- assert permission_for_request(
- "/api/knowledge/admin/change-sets/id/retry", "POST"
- ) == (KNOWLEDGE_MANAGE,)
- assert permission_for_request(
- "/api/knowledge/admin/device-sources", "GET"
- ) == (KNOWLEDGE_MANAGE,)
- assert permission_for_request(
- "/api/knowledge/admin/device-sources/id/scope", "PUT"
- ) == (KNOWLEDGE_MANAGE,)
- assert permission_for_request(
- "/api/knowledge/admin/query-audits", "GET"
- ) == (KNOWLEDGE_MANAGE,)
- def test_data_rule_routes_separate_read_authoring_and_release_permissions():
- from app.core.system.permissions import (
- DATAFLOW_RELEASE,
- RULES_EDIT,
- RULES_PUBLISH,
- RULES_READ,
- permission_for_request,
- )
- assert permission_for_request("/api/rules/capabilities", "GET") == (
- RULES_READ,
- )
- assert permission_for_request("/api/rules/interpret", "POST") == (
- RULES_EDIT,
- )
- assert permission_for_request("/api/rules/validate", "POST") == (
- RULES_EDIT,
- )
- assert permission_for_request(
- "/api/rules/versions/id/publish", "POST"
- ) == (RULES_PUBLISH,)
- assert permission_for_request(
- "/api/rules/production-lines/id/release", "POST"
- ) == (DATAFLOW_RELEASE,)
- def test_data_factory_actions_have_independent_permissions():
- from app.core.system.permissions import (
- DATAFLOW_ACTIVATE,
- DATAFLOW_CANARY,
- DATAFLOW_DEPLOY,
- DATAFLOW_ROLLBACK,
- RULES_EXECUTE,
- permission_for_request,
- )
- assert permission_for_request("/api/rules/deployments", "POST") == (
- DATAFLOW_DEPLOY,
- )
- assert permission_for_request(
- "/api/rules/deployments/id/deploy-disabled", "POST"
- ) == (DATAFLOW_DEPLOY,)
- assert permission_for_request(
- "/api/rules/deployments/id/canary", "POST"
- ) == (DATAFLOW_CANARY, RULES_EXECUTE)
- assert permission_for_request(
- "/api/rules/deployments/id/execute", "POST"
- ) == (RULES_EXECUTE,)
- assert permission_for_request(
- "/api/rules/deployments/id/activate", "POST"
- ) == (DATAFLOW_ACTIVATE,)
- assert permission_for_request(
- "/api/rules/deployments/id/rollback", "POST"
- ) == (DATAFLOW_ROLLBACK,)
- assert permission_for_request(
- "/api/rules/deployments/id/reconcile-deploy", "POST"
- ) == (DATAFLOW_DEPLOY,)
- assert permission_for_request(
- "/api/rules/deployments/id/reconcile-activate", "POST"
- ) == (DATAFLOW_ACTIVATE,)
- assert permission_for_request(
- "/api/rules/deployments/id/reconcile-rollback", "POST"
- ) == (DATAFLOW_ROLLBACK,)
- assert permission_for_request(
- "/api/rules/deployments/id/reconcile-execute", "POST"
- ) == (RULES_EXECUTE,)
|