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()