tests/test_authorization.py
2.7 KB · 98 lines · python Raw
1 """Tests for AuthorizationChain and AuthorizationGrant."""
2
3 from __future__ import annotations
4
5 import pytest
6
7 from pqc_ai_governance import (
8 AuthorizationChain,
9 AuthorizationGrant,
10 ConsensusResult,
11 GovernanceError,
12 ProposalKind,
13 )
14
15
16 def _result(decision: str) -> ConsensusResult:
17 return ConsensusResult(
18 proposal_id="p",
19 proposal_hash="h",
20 decision=decision,
21 reason="",
22 approve_weight=0,
23 reject_weight=0,
24 abstain_weight=0,
25 total_weight=0,
26 )
27
28
29 def test_chain_add_wrong_subject_raises() -> None:
30 chain = AuthorizationChain(subject_id="did:pqaid:model-x")
31 grant = AuthorizationGrant(
32 subject_id="did:pqaid:model-y",
33 kind=ProposalKind.AUTHORIZE_MODEL,
34 result=_result("passed"),
35 )
36 with pytest.raises(GovernanceError):
37 chain.add(grant)
38
39
40 def test_is_authorized_true_after_authorize_model_passes() -> None:
41 chain = AuthorizationChain(subject_id="did:pqaid:model-x")
42 chain.add(
43 AuthorizationGrant(
44 subject_id="did:pqaid:model-x",
45 kind=ProposalKind.AUTHORIZE_MODEL,
46 result=_result("passed"),
47 )
48 )
49 assert chain.is_authorized(ProposalKind.AUTHORIZE_MODEL) is True
50
51
52 def test_is_authorized_false_after_subsequent_revoke() -> None:
53 chain = AuthorizationChain(subject_id="did:pqaid:model-x")
54 chain.add(
55 AuthorizationGrant(
56 subject_id="did:pqaid:model-x",
57 kind=ProposalKind.AUTHORIZE_MODEL,
58 result=_result("passed"),
59 )
60 )
61 chain.add(
62 AuthorizationGrant(
63 subject_id="did:pqaid:model-x",
64 kind=ProposalKind.REVOKE_MODEL,
65 result=_result("passed"),
66 )
67 )
68 assert chain.is_authorized(ProposalKind.AUTHORIZE_MODEL) is False
69
70
71 def test_is_authorized_respects_only_passed_grants() -> None:
72 chain = AuthorizationChain(subject_id="did:pqaid:model-x")
73 # Rejected authorization should not authorize anything
74 chain.add(
75 AuthorizationGrant(
76 subject_id="did:pqaid:model-x",
77 kind=ProposalKind.AUTHORIZE_MODEL,
78 result=_result("rejected"),
79 )
80 )
81 assert chain.is_authorized(ProposalKind.AUTHORIZE_MODEL) is False
82 # A rejected revoke should not undo a passed authorize
83 chain.add(
84 AuthorizationGrant(
85 subject_id="did:pqaid:model-x",
86 kind=ProposalKind.AUTHORIZE_MODEL,
87 result=_result("passed"),
88 )
89 )
90 chain.add(
91 AuthorizationGrant(
92 subject_id="did:pqaid:model-x",
93 kind=ProposalKind.REVOKE_MODEL,
94 result=_result("rejected"),
95 )
96 )
97 assert chain.is_authorized(ProposalKind.AUTHORIZE_MODEL) is True
98