test_permission_matrix.py 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. def test_fixed_role_permission_matrix_is_monotonic():
  2. from app.core.system.permissions import ROLE_PERMISSIONS
  3. viewer = ROLE_PERMISSIONS["viewer"]
  4. editor = ROLE_PERMISSIONS["editor"]
  5. admin = ROLE_PERMISSIONS["admin"]
  6. assert viewer < editor < admin
  7. assert "governance:read" in viewer
  8. assert "governance:edit" in editor
  9. assert "users:manage" in admin
  10. assert "workflow:activate" in admin
  11. assert "ingestion:run" in editor
  12. assert "data-elements:edit" in editor
  13. assert "ontologies:edit" in editor
  14. assert "governance:responsibilities:read" in viewer
  15. assert "ingestion:admin" in admin
  16. assert "evidence:download" in admin
  17. assert "data-elements:publish" in admin
  18. assert "ontologies:publish" in admin
  19. assert "governance:responsibilities:manage" in admin
  20. assert "device-assets:edit" in editor
  21. def test_data_development_paths_have_specific_write_policies():
  22. from app.core.system.permissions import permission_for_request
  23. assert permission_for_request(
  24. "/api/development/v1/ingestion-jobs", "POST"
  25. ) == ("ingestion:run",)
  26. assert permission_for_request(
  27. "/api/development/v1/ingestion-jobs/job-1/retry", "POST"
  28. ) == ("ingestion:admin",)
  29. assert permission_for_request(
  30. "/api/development/v1/ingestion-jobs/job-1/cancel", "POST"
  31. ) == ("ingestion:run",)
  32. assert permission_for_request(
  33. "/api/development/v1/ingestion-jobs/job-1/execute", "POST"
  34. ) == ("ingestion:run",)
  35. assert permission_for_request(
  36. "/api/development/v1/ingestion-jobs/job-1/catalog-snapshots", "GET"
  37. ) == ("governance:read",)
  38. assert permission_for_request(
  39. "/api/development/v1/ingestion-jobs/job-1/evidence", "GET"
  40. ) == ("governance:read",)
  41. assert permission_for_request(
  42. "/api/development/v1/data-elements", "POST"
  43. ) == ("data-elements:edit",)
  44. assert permission_for_request(
  45. "/api/development/v1/data-elements/element-1/transitions", "POST"
  46. ) == ("data-elements:edit",)
  47. assert permission_for_request(
  48. "/api/development/v1/candidate-decisions", "POST"
  49. ) == ("data-elements:edit",)
  50. assert permission_for_request(
  51. "/api/development/v1/device-assets", "GET"
  52. ) == ("governance:read",)
  53. assert permission_for_request(
  54. "/api/development/v1/device-assets/asset-1", "GET"
  55. ) == ("governance:read",)
  56. assert permission_for_request(
  57. "/api/development/v1/device-assets/import", "POST"
  58. ) == ("device-assets:edit",)
  59. def test_business_domain_read_endpoints_are_available_to_viewers():
  60. from app.core.system.permissions import permission_for_request
  61. assert permission_for_request("/api/bd/list", "POST") == (
  62. "governance:read",
  63. )
  64. assert permission_for_request("/api/bd/detail", "POST") == (
  65. "governance:read",
  66. )
  67. assert permission_for_request("/api/bd/save", "POST") == (
  68. "governance:edit",
  69. )
  70. def test_permissions_are_derived_server_side_from_roles():
  71. from app.core.system.permissions import permissions_for_roles
  72. permissions = permissions_for_roles(["viewer", "editor"])
  73. assert "governance:read" in permissions
  74. assert "governance:edit" in permissions
  75. assert "users:manage" not in permissions
  76. def test_every_api_path_has_an_explicit_policy():
  77. from app import create_app
  78. from app.core.system.permissions import permission_for_request
  79. app = create_app()
  80. for rule in app.url_map.iter_rules():
  81. if not rule.rule.startswith("/api/"):
  82. continue
  83. for method in rule.methods - {"HEAD", "OPTIONS"}:
  84. assert permission_for_request(rule.rule, method) is not None, (
  85. method,
  86. rule.rule,
  87. )
  88. def test_knowledge_search_and_ask_posts_are_read_only():
  89. from app.core.system.permissions import READ_GOVERNANCE, permission_for_request
  90. assert permission_for_request("/api/knowledge/search", "POST") == (
  91. READ_GOVERNANCE,
  92. )
  93. assert permission_for_request("/api/knowledge/ask", "POST") == (READ_GOVERNANCE,)
  94. def test_knowledge_admin_routes_require_dedicated_manage_permission():
  95. from app.core.system.permissions import KNOWLEDGE_MANAGE, permission_for_request
  96. assert permission_for_request("/api/knowledge/admin/sync", "GET") == (
  97. KNOWLEDGE_MANAGE,
  98. )
  99. assert permission_for_request(
  100. "/api/knowledge/admin/change-sets/id/retry", "POST"
  101. ) == (KNOWLEDGE_MANAGE,)
  102. def test_data_rule_routes_separate_read_authoring_and_release_permissions():
  103. from app.core.system.permissions import (
  104. DATAFLOW_RELEASE,
  105. RULES_EDIT,
  106. RULES_PUBLISH,
  107. RULES_READ,
  108. permission_for_request,
  109. )
  110. assert permission_for_request("/api/rules/capabilities", "GET") == (
  111. RULES_READ,
  112. )
  113. assert permission_for_request("/api/rules/interpret", "POST") == (
  114. RULES_EDIT,
  115. )
  116. assert permission_for_request("/api/rules/validate", "POST") == (
  117. RULES_EDIT,
  118. )
  119. assert permission_for_request(
  120. "/api/rules/versions/id/publish", "POST"
  121. ) == (RULES_PUBLISH,)
  122. assert permission_for_request(
  123. "/api/rules/production-lines/id/release", "POST"
  124. ) == (DATAFLOW_RELEASE,)
  125. def test_data_factory_actions_have_independent_permissions():
  126. from app.core.system.permissions import (
  127. DATAFLOW_ACTIVATE,
  128. DATAFLOW_CANARY,
  129. DATAFLOW_DEPLOY,
  130. DATAFLOW_ROLLBACK,
  131. RULES_EXECUTE,
  132. permission_for_request,
  133. )
  134. assert permission_for_request("/api/rules/deployments", "POST") == (
  135. DATAFLOW_DEPLOY,
  136. )
  137. assert permission_for_request(
  138. "/api/rules/deployments/id/deploy-disabled", "POST"
  139. ) == (DATAFLOW_DEPLOY,)
  140. assert permission_for_request(
  141. "/api/rules/deployments/id/canary", "POST"
  142. ) == (DATAFLOW_CANARY, RULES_EXECUTE)
  143. assert permission_for_request(
  144. "/api/rules/deployments/id/execute", "POST"
  145. ) == (RULES_EXECUTE,)
  146. assert permission_for_request(
  147. "/api/rules/deployments/id/activate", "POST"
  148. ) == (DATAFLOW_ACTIVATE,)
  149. assert permission_for_request(
  150. "/api/rules/deployments/id/rollback", "POST"
  151. ) == (DATAFLOW_ROLLBACK,)
  152. assert permission_for_request(
  153. "/api/rules/deployments/id/reconcile-deploy", "POST"
  154. ) == (DATAFLOW_DEPLOY,)
  155. assert permission_for_request(
  156. "/api/rules/deployments/id/reconcile-activate", "POST"
  157. ) == (DATAFLOW_ACTIVATE,)
  158. assert permission_for_request(
  159. "/api/rules/deployments/id/reconcile-rollback", "POST"
  160. ) == (DATAFLOW_ROLLBACK,)
  161. assert permission_for_request(
  162. "/api/rules/deployments/id/reconcile-execute", "POST"
  163. ) == (RULES_EXECUTE,)