-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtest_proptest.py
More file actions
118 lines (101 loc) · 4.47 KB
/
Copy pathtest_proptest.py
File metadata and controls
118 lines (101 loc) · 4.47 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
"""
Property-based tests using Hypothesis.
These test invariants that must hold for ALL inputs, not just known examples:
- Every action with a forbidden flag must be blocked.
- verify() must be deterministic (same input → same permitted/violations).
- An ownerless machine is always blocked.
- A machine governing a human is always blocked.
Run: pytest tests/test_proptest.py
"""
from hypothesis import given, settings
from hypothesis import strategies as st
try:
from authgate_kernel import ( # noqa: I001
Action, AgentType, Entity, FreedomVerifier,
OwnershipRegistry, Resource, ResourceType, RightsClaim,
)
RUST_KERNEL = True
except ImportError:
from authgate.kernel.entities import AgentType, Entity, Resource, ResourceType # noqa: I001
from authgate.kernel.registry import OwnershipRegistry, RightsClaim
from authgate.kernel.verifier import Action, FreedomVerifier # type: ignore[no-reattr]
RUST_KERNEL = False
FORBIDDEN_FLAGS = [
"increases_machine_sovereignty",
"resists_human_correction",
"bypasses_verifier",
"weakens_verifier",
"disables_corrigibility",
"machine_coalition_dominion",
"coerces",
"deceives",
"self_modification_weakens_verifier",
"machine_coalition_reduces_freedom",
]
def _make_registry_with_bot():
reg = OwnershipRegistry()
alice = Entity("Alice", AgentType.HUMAN)
bot = Entity("TestBot", AgentType.MACHINE)
reg.register_machine(bot, alice)
gpu = Resource("gpu", ResourceType.COMPUTE_SLOT)
reg.add_claim(RightsClaim(alice, gpu, can_read=True, can_write=True, can_delegate=True))
reg.add_claim(RightsClaim(bot, gpu, can_read=True, can_write=True))
return reg, bot, gpu
@given(flag=st.sampled_from(FORBIDDEN_FLAGS))
@settings(max_examples=50)
def test_every_forbidden_flag_blocks(flag):
"""Invariant: ANY action with a forbidden flag must be blocked."""
reg, bot, _gpu = _make_registry_with_bot()
v = FreedomVerifier(reg)
action = Action(action_id=f"test-{flag}", actor=bot, **{flag: True})
result = v.verify(action)
assert not result.permitted, f"Flag {flag} must always block"
assert any("FORBIDDEN" in viol for viol in result.violations), f"Violation list must contain FORBIDDEN for flag {flag}"
@given(
flag=st.sampled_from(FORBIDDEN_FLAGS),
action_id=st.text(alphabet="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_", min_size=1, max_size=32),
)
@settings(max_examples=50)
def test_forbidden_flag_blocks_regardless_of_action_id(flag, action_id):
"""The action_id field must not affect whether a forbidden flag blocks."""
reg, bot, _gpu = _make_registry_with_bot()
v = FreedomVerifier(reg)
action = Action(action_id=action_id, actor=bot, **{flag: True})
result = v.verify(action)
assert not result.permitted
@given(
flag=st.sampled_from(FORBIDDEN_FLAGS),
seed=st.integers(min_value=0, max_value=2**31),
)
@settings(max_examples=30)
def test_verification_is_deterministic(flag, seed):
"""Invariant: verify() on the same input always returns the same permitted/violations."""
reg, bot, _gpu = _make_registry_with_bot()
v = FreedomVerifier(reg)
action = Action(action_id=f"det-{seed}", actor=bot, **{flag: True})
r1 = v.verify(action)
r2 = v.verify(action)
assert r1.permitted == r2.permitted
assert sorted(r1.violations) == sorted(r2.violations)
def test_ownerless_machine_always_blocked():
"""A machine with no registered owner must always be blocked (A4)."""
reg = OwnershipRegistry()
orphan = Entity("Orphan", AgentType.MACHINE)
res = Resource("data", ResourceType.DATASET)
reg.add_claim(RightsClaim(orphan, res, can_read=True))
v = FreedomVerifier(reg)
action = Action(action_id="orphan-read", actor=orphan, resources_read=[res])
result = v.verify(action)
assert not result.permitted
assert any("A4" in viol for viol in result.violations)
@given(human_name=st.text(min_size=1, max_size=20, alphabet="abcdefghijklmnopqrstuvwxyz"))
@settings(max_examples=20)
def test_machine_governs_human_always_blocked(human_name):
"""A machine acting upon a human in a governing capacity is always blocked (A6)."""
reg, bot, _gpu = _make_registry_with_bot()
v = FreedomVerifier(reg)
human_target = Entity(human_name, AgentType.HUMAN)
action = Action(action_id="governs", actor=bot, governs_humans=[human_target])
result = v.verify(action)
assert not result.permitted
assert any("A6" in viol for viol in result.violations)