Add function assignment governance profiles
This commit is contained in:
@@ -0,0 +1,137 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import unittest
|
||||
|
||||
from govoplan_core.core.access import PrincipalRef
|
||||
from govoplan_core.core.policy import FunctionAssignmentGovernanceRequest
|
||||
from govoplan_policy.backend.function_assignment_governance import (
|
||||
FunctionAssignmentGovernancePolicyProvider,
|
||||
)
|
||||
|
||||
|
||||
class FunctionAssignmentGovernancePolicyTests(unittest.TestCase):
|
||||
def setUp(self) -> None:
|
||||
self.provider = FunctionAssignmentGovernancePolicyProvider()
|
||||
self.actor = PrincipalRef(
|
||||
account_id="account-1",
|
||||
membership_id="membership-1",
|
||||
tenant_id="tenant-1",
|
||||
identity_id="identity-1",
|
||||
)
|
||||
|
||||
def resolve(self, **overrides):
|
||||
values = {
|
||||
"tenant_id": "tenant-1",
|
||||
"kind": "request",
|
||||
"action": "submit",
|
||||
"function_id": "function-1",
|
||||
"actor": self.actor,
|
||||
"candidate_identity_id": "identity-1",
|
||||
"function_settings": {
|
||||
"assignment_governance": {
|
||||
"request_profile": "holder_with_authority_clearance",
|
||||
"grant_profile": "holder_with_authority_clearance",
|
||||
"authority_function_id": "authority-1",
|
||||
},
|
||||
},
|
||||
"context": {
|
||||
"candidate_is_actor": True,
|
||||
"actor_is_holder": False,
|
||||
"actor_is_authority": False,
|
||||
"has_evidence": True,
|
||||
},
|
||||
}
|
||||
values.update(overrides)
|
||||
return self.provider.resolve_function_assignment_action(
|
||||
request=FunctionAssignmentGovernanceRequest(**values)
|
||||
)
|
||||
|
||||
def test_self_request_resolves_holder_and_authority_steps(self) -> None:
|
||||
decision = self.resolve()
|
||||
|
||||
self.assertTrue(decision.allowed)
|
||||
self.assertEqual(("holder", "authority"), decision.required_steps)
|
||||
self.assertEqual("authority-1", decision.authority_function_id)
|
||||
|
||||
def test_grant_profiles_recheck_holder_and_authority(self) -> None:
|
||||
holder_grant = self.resolve(
|
||||
kind="grant",
|
||||
context={"actor_is_holder": True, "has_evidence": True},
|
||||
)
|
||||
unauthorized = self.resolve(
|
||||
kind="grant",
|
||||
context={"actor_is_holder": False, "has_evidence": True},
|
||||
)
|
||||
authority_approval = self.resolve(
|
||||
kind="grant",
|
||||
action="approve_authority",
|
||||
context={"actor_is_authority": True, "has_evidence": True},
|
||||
)
|
||||
|
||||
self.assertTrue(holder_grant.allowed)
|
||||
self.assertIn("recipient", holder_grant.required_steps)
|
||||
self.assertFalse(unauthorized.allowed)
|
||||
self.assertTrue(authority_approval.allowed)
|
||||
|
||||
def test_missing_authority_and_evidence_fail_closed(self) -> None:
|
||||
decision = self.resolve(
|
||||
function_settings={
|
||||
"assignment_governance": {
|
||||
"request_profile": "holder_with_authority_clearance",
|
||||
"evidence_required": True,
|
||||
},
|
||||
},
|
||||
context={"candidate_is_actor": True, "has_evidence": False},
|
||||
)
|
||||
|
||||
self.assertFalse(decision.allowed)
|
||||
self.assertEqual(
|
||||
("authority_function", "evidence"),
|
||||
decision.requirements,
|
||||
)
|
||||
|
||||
def test_rejection_is_limited_to_the_current_reviewer(self) -> None:
|
||||
holder_reject = self.resolve(
|
||||
action="reject",
|
||||
current_state="awaiting_holder",
|
||||
context={"actor_is_holder": True},
|
||||
)
|
||||
authority_cannot_reject_holder_step = self.resolve(
|
||||
action="reject",
|
||||
current_state="awaiting_holder",
|
||||
context={"actor_is_authority": True},
|
||||
)
|
||||
recipient_reject = self.resolve(
|
||||
action="reject",
|
||||
current_state="awaiting_recipient",
|
||||
context={"candidate_is_actor": True},
|
||||
)
|
||||
|
||||
self.assertTrue(holder_reject.allowed)
|
||||
self.assertFalse(authority_cannot_reject_holder_step.allowed)
|
||||
self.assertTrue(recipient_reject.allowed)
|
||||
|
||||
def test_change_request_and_response_follow_current_participants(self) -> None:
|
||||
reviewer = self.resolve(
|
||||
action="request_changes",
|
||||
current_state="awaiting_holder",
|
||||
context={"actor_is_holder": True},
|
||||
)
|
||||
responder = self.resolve(
|
||||
action="respond",
|
||||
current_state="changes_requested",
|
||||
context={"actor_is_initiator": True},
|
||||
)
|
||||
unrelated = self.resolve(
|
||||
action="respond",
|
||||
current_state="changes_requested",
|
||||
context={},
|
||||
)
|
||||
|
||||
self.assertTrue(reviewer.allowed)
|
||||
self.assertTrue(responder.allowed)
|
||||
self.assertFalse(unrelated.allowed)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -6,6 +6,7 @@ import unittest
|
||||
|
||||
from govoplan_core.core.policy import (
|
||||
CAPABILITY_POLICY_DEFINITION_GOVERNANCE,
|
||||
CAPABILITY_POLICY_FUNCTION_ASSIGNMENT_GOVERNANCE,
|
||||
CAPABILITY_POLICY_PRIVACY_RETENTION,
|
||||
CAPABILITY_POLICY_SCHEDULING_PARTICIPANT_PRIVACY,
|
||||
CAPABILITY_POLICY_VIEW_GOVERNANCE,
|
||||
@@ -18,11 +19,17 @@ ROOT = pathlib.Path(__file__).resolve().parents[1]
|
||||
|
||||
class PolicyModuleContractTests(unittest.TestCase):
|
||||
def test_policy_package_does_not_hard_require_access(self) -> None:
|
||||
project = tomllib.loads((ROOT / "pyproject.toml").read_text(encoding="utf-8"))["project"]
|
||||
project = tomllib.loads((ROOT / "pyproject.toml").read_text(encoding="utf-8"))[
|
||||
"project"
|
||||
]
|
||||
dependencies = tuple(project["dependencies"])
|
||||
|
||||
self.assertTrue(any(item.startswith("govoplan-core>=") for item in dependencies))
|
||||
self.assertFalse(any(item.startswith("govoplan-access") for item in dependencies))
|
||||
self.assertTrue(
|
||||
any(item.startswith("govoplan-core>=") for item in dependencies)
|
||||
)
|
||||
self.assertFalse(
|
||||
any(item.startswith("govoplan-access") for item in dependencies)
|
||||
)
|
||||
|
||||
def test_policy_source_does_not_import_access_implementation(self) -> None:
|
||||
offenders: list[str] = []
|
||||
@@ -37,6 +44,7 @@ class PolicyModuleContractTests(unittest.TestCase):
|
||||
self.assertEqual(
|
||||
{
|
||||
CAPABILITY_POLICY_DEFINITION_GOVERNANCE,
|
||||
CAPABILITY_POLICY_FUNCTION_ASSIGNMENT_GOVERNANCE,
|
||||
CAPABILITY_POLICY_PRIVACY_RETENTION,
|
||||
CAPABILITY_POLICY_SCHEDULING_PARTICIPANT_PRIVACY,
|
||||
CAPABILITY_POLICY_VIEW_GOVERNANCE,
|
||||
|
||||
Reference in New Issue
Block a user