Files
govoplan-policy/tests/test_function_assignment_governance.py
T
zemion 5753488375
Module Package Release / publish-packages (push) Successful in 12s
feat(policy): govern delegation and review escalation
2026-08-22 03:12:30 +02:00

190 lines
6.7 KiB
Python

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)
def test_delegation_ceilings_and_escalation_rules_are_bounded(self) -> None:
decision = self.resolve(
function_settings={
"assignment_governance": {
"request_profile": "holder_with_authority_clearance",
"authority_function_id": "authority-1",
"delegation_allowed": True,
"maximum_delegation_depth": 3,
"maximum_delegated_validity_days": 45,
"escalation": {
"holder": {
"target_function_id": "escalation-1",
"timeout_hours": 24,
}
},
}
}
)
self.assertTrue(decision.delegation_allowed)
self.assertEqual(3, decision.maximum_delegation_depth)
self.assertEqual(45, decision.maximum_delegated_validity_days)
self.assertEqual("escalation-1", decision.escalation_rules[0].target_function_id)
self.assertEqual(24, decision.escalation_rules[0].timeout_hours)
def test_escalated_review_requires_explicit_target_holder(self) -> None:
allowed = self.resolve(
action="approve_escalation",
current_state="escalated",
context={
"actor_is_escalation_target": True,
"actor_routes": {"escalation": {"effective": True}},
},
)
unavailable = self.resolve(
action="approve_escalation",
current_state="escalated",
context={
"actor_is_escalation_target": False,
"actor_routes": {
"escalation": {
"effective": False,
"reason": "The target function is vacant.",
}
},
},
)
self.assertTrue(allowed.allowed)
self.assertFalse(unavailable.allowed)
self.assertEqual("The target function is vacant.", unavailable.reason)
if __name__ == "__main__":
unittest.main()