Add definition governance policy
This commit is contained in:
147
tests/test_definition_governance.py
Normal file
147
tests/test_definition_governance.py
Normal file
@@ -0,0 +1,147 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import unittest
|
||||
|
||||
from govoplan_core.core.access import PrincipalRef
|
||||
from govoplan_core.core.policy import (
|
||||
DefinitionGovernanceRequest,
|
||||
DefinitionScopeRef,
|
||||
)
|
||||
from govoplan_policy.backend.definition_governance import (
|
||||
DefinitionGovernancePolicyProvider,
|
||||
)
|
||||
|
||||
|
||||
class DefinitionGovernancePolicyTests(unittest.TestCase):
|
||||
def setUp(self) -> None:
|
||||
self.policy = DefinitionGovernancePolicyProvider()
|
||||
self.actor = PrincipalRef(
|
||||
account_id="account-1",
|
||||
membership_id="user-1",
|
||||
tenant_id="tenant-1",
|
||||
group_ids=frozenset({"group-1"}),
|
||||
)
|
||||
|
||||
def _resolve(self, **overrides):
|
||||
values = {
|
||||
"module_id": "dataflow",
|
||||
"definition_ref": "pipeline:1",
|
||||
"tenant_id": "tenant-1",
|
||||
"definition_scope": DefinitionScopeRef(
|
||||
"tenant",
|
||||
"tenant-1",
|
||||
),
|
||||
"target_scope": DefinitionScopeRef("tenant", "tenant-1"),
|
||||
"definition_kind": "flow",
|
||||
"action": "view",
|
||||
"actor": self.actor,
|
||||
"status": "active",
|
||||
"inherit_to_lower_scopes": False,
|
||||
"allow_run": True,
|
||||
"allow_reuse": False,
|
||||
"allow_automation": False,
|
||||
}
|
||||
values.update(overrides)
|
||||
return self.policy.resolve_definition_action(
|
||||
request=DefinitionGovernanceRequest(**values)
|
||||
)
|
||||
|
||||
def test_system_definition_is_read_only_when_inherited(self) -> None:
|
||||
view = self._resolve(
|
||||
definition_scope=DefinitionScopeRef("system"),
|
||||
inherit_to_lower_scopes=True,
|
||||
)
|
||||
edit = self._resolve(
|
||||
definition_scope=DefinitionScopeRef("system"),
|
||||
inherit_to_lower_scopes=True,
|
||||
action="edit",
|
||||
)
|
||||
|
||||
self.assertTrue(view.allowed)
|
||||
self.assertFalse(edit.allowed)
|
||||
self.assertEqual(
|
||||
["system", "tenant:tenant-1"],
|
||||
[step.path for step in view.source_path],
|
||||
)
|
||||
|
||||
def test_templates_cannot_run_or_be_automated(self) -> None:
|
||||
run = self._resolve(
|
||||
definition_kind="template",
|
||||
action="run",
|
||||
allow_run=True,
|
||||
)
|
||||
automated = self._resolve(
|
||||
definition_kind="template",
|
||||
action="automate",
|
||||
allow_run=True,
|
||||
allow_automation=True,
|
||||
)
|
||||
|
||||
self.assertFalse(run.allowed)
|
||||
self.assertFalse(automated.allowed)
|
||||
|
||||
def test_reuse_and_automation_are_independent_narrowing_grants(self) -> None:
|
||||
reuse = self._resolve(action="reuse", allow_reuse=True)
|
||||
automated = self._resolve(
|
||||
action="automate",
|
||||
allow_run=True,
|
||||
allow_automation=False,
|
||||
)
|
||||
|
||||
self.assertTrue(reuse.allowed)
|
||||
self.assertFalse(automated.allowed)
|
||||
|
||||
def test_ancestor_limits_cannot_be_broadened(self) -> None:
|
||||
decision = self._resolve(
|
||||
action="reuse",
|
||||
allow_reuse=True,
|
||||
context={
|
||||
"ancestor_limits": {"allow_reuse": False},
|
||||
"ancestor_source": {
|
||||
"scope_type": "system",
|
||||
"label": "System template",
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
self.assertFalse(decision.allowed)
|
||||
self.assertFalse(
|
||||
decision.details["effective_limits"]["allow_reuse"]
|
||||
)
|
||||
self.assertEqual("system", decision.source_path[0].path)
|
||||
|
||||
def test_ancestor_inheritance_limit_controls_visibility(self) -> None:
|
||||
decision = self._resolve(
|
||||
definition_scope=DefinitionScopeRef("system"),
|
||||
inherit_to_lower_scopes=True,
|
||||
context={
|
||||
"ancestor_limits": {
|
||||
"inherit_to_lower_scopes": False,
|
||||
},
|
||||
"ancestor_source": {
|
||||
"scope_type": "system",
|
||||
"label": "Restricted ancestor",
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
self.assertFalse(decision.allowed)
|
||||
self.assertEqual(
|
||||
"The system definition is not inherited by lower scopes.",
|
||||
decision.reason,
|
||||
)
|
||||
|
||||
def test_group_and_user_scopes_are_visible_only_to_the_actor(self) -> None:
|
||||
group = self._resolve(
|
||||
definition_scope=DefinitionScopeRef("group", "group-1")
|
||||
)
|
||||
user = self._resolve(
|
||||
definition_scope=DefinitionScopeRef("user", "user-2")
|
||||
)
|
||||
|
||||
self.assertTrue(group.allowed)
|
||||
self.assertFalse(user.allowed)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -5,6 +5,7 @@ import tomllib
|
||||
import unittest
|
||||
|
||||
from govoplan_core.core.policy import (
|
||||
CAPABILITY_POLICY_DEFINITION_GOVERNANCE,
|
||||
CAPABILITY_POLICY_PRIVACY_RETENTION,
|
||||
CAPABILITY_POLICY_SCHEDULING_PARTICIPANT_PRIVACY,
|
||||
)
|
||||
@@ -34,6 +35,7 @@ class PolicyModuleContractTests(unittest.TestCase):
|
||||
def test_policy_manifest_exposes_policy_capabilities(self) -> None:
|
||||
self.assertEqual(
|
||||
{
|
||||
CAPABILITY_POLICY_DEFINITION_GOVERNANCE,
|
||||
CAPABILITY_POLICY_PRIVACY_RETENTION,
|
||||
CAPABILITY_POLICY_SCHEDULING_PARTICIPANT_PRIVACY,
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user