-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtest_delegate.py
More file actions
163 lines (124 loc) · 5.92 KB
/
Copy pathtest_delegate.py
File metadata and controls
163 lines (124 loc) · 5.92 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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
"""
Delegation attenuation tests.
The core invariant: you cannot grant authority you do not have.
Every test tries to violate attenuation and expects PermissionError.
"""
import pytest
from authgate import (
AgentType,
Entity,
OwnershipRegistry,
Resource,
ResourceType,
RightsClaim,
)
@pytest.fixture
def alice():
return Entity("Alice", AgentType.HUMAN)
@pytest.fixture
def bot(alice, registry):
b = Entity("Bot", AgentType.MACHINE)
registry.register_machine(b, alice)
return b
@pytest.fixture
def sub_bot(alice, registry):
s = Entity("SubBot", AgentType.MACHINE)
registry.register_machine(s, alice)
return s
@pytest.fixture
def resource():
return Resource("shared-db", ResourceType.DATABASE_TABLE, scope="/db/")
@pytest.fixture
def registry():
return OwnershipRegistry()
# ── valid delegation ──────────────────────────────────────────────────────────
def test_delegate_success(alice, bot, resource, registry):
registry.add_claim(
RightsClaim(alice, resource, can_read=True, can_write=True, can_delegate=True)
)
registry.delegate(RightsClaim(bot, resource, can_read=True), delegated_by=alice)
ok, conf, _ = registry.can_act(bot, resource, "read")
assert ok
assert conf == 1.0
def test_delegate_write_success(alice, bot, resource, registry):
registry.add_claim(
RightsClaim(alice, resource, can_read=True, can_write=True, can_delegate=True)
)
registry.delegate(
RightsClaim(bot, resource, can_read=True, can_write=True), delegated_by=alice
)
ok, _, _ = registry.can_act(bot, resource, "write")
assert ok
def test_delegate_reduced_confidence(alice, bot, resource, registry):
registry.add_claim(
RightsClaim(alice, resource, can_read=True, can_delegate=True, confidence=0.9)
)
registry.delegate(
RightsClaim(bot, resource, can_read=True, confidence=0.7), delegated_by=alice
)
ok, conf, _ = registry.can_act(bot, resource, "read")
assert ok
assert conf == pytest.approx(0.7)
# ── no delegatable claim ──────────────────────────────────────────────────────
def test_delegate_requires_can_delegate(alice, bot, resource, registry):
registry.add_claim(RightsClaim(alice, resource, can_read=True, can_delegate=False))
with pytest.raises(PermissionError, match="delegatable"):
registry.delegate(RightsClaim(bot, resource, can_read=True), delegated_by=alice)
def test_delegate_no_claim_at_all_raises(alice, bot, resource, registry):
with pytest.raises(PermissionError, match="delegatable"):
registry.delegate(RightsClaim(bot, resource, can_read=True), delegated_by=alice)
# ── permission attenuation ────────────────────────────────────────────────────
def test_cannot_delegate_write_without_write(alice, bot, resource, registry):
registry.add_claim(
RightsClaim(alice, resource, can_read=True, can_write=False, can_delegate=True)
)
with pytest.raises(PermissionError, match="write"):
registry.delegate(
RightsClaim(bot, resource, can_read=True, can_write=True),
delegated_by=alice,
)
def test_cannot_delegate_read_without_read(alice, bot, resource, registry):
registry.add_claim(
RightsClaim(alice, resource, can_read=False, can_write=True, can_delegate=True)
)
with pytest.raises(PermissionError, match="read"):
registry.delegate(RightsClaim(bot, resource, can_read=True), delegated_by=alice)
def test_cannot_subdelegate_without_can_delegate(alice, bot, resource, registry):
registry.add_claim(RightsClaim(alice, resource, can_read=True, can_delegate=True))
registry.delegate(
RightsClaim(bot, resource, can_read=True, can_delegate=False), delegated_by=alice
)
sub = Entity("Sub", AgentType.MACHINE)
registry.register_machine(sub, alice)
with pytest.raises(PermissionError, match="delegatable"):
registry.delegate(RightsClaim(sub, resource, can_read=True), delegated_by=bot)
# ── confidence attenuation ────────────────────────────────────────────────────
def test_confidence_cannot_exceed_delegator(alice, bot, resource, registry):
registry.add_claim(
RightsClaim(alice, resource, can_read=True, can_delegate=True, confidence=0.8)
)
with pytest.raises(PermissionError, match="confidence"):
registry.delegate(
RightsClaim(bot, resource, can_read=True, confidence=0.9), delegated_by=alice
)
def test_confidence_equal_to_delegator_is_ok(alice, bot, resource, registry):
registry.add_claim(
RightsClaim(alice, resource, can_read=True, can_delegate=True, confidence=0.8)
)
registry.delegate(
RightsClaim(bot, resource, can_read=True, confidence=0.8), delegated_by=alice
)
ok, conf, _ = registry.can_act(bot, resource, "read")
assert ok
assert conf == pytest.approx(0.8)
# ── conflict detection on delegation ─────────────────────────────────────────
def test_delegation_detects_write_conflict(alice, bot, resource, registry):
bob = Entity("Bob", AgentType.HUMAN)
conflicts = []
registry.set_conflict_hook(lambda c: conflicts.append(c))
registry.add_claim(RightsClaim(bob, resource, can_write=True))
registry.add_claim(
RightsClaim(alice, resource, can_read=True, can_write=True, can_delegate=True)
)
registry.delegate(RightsClaim(bot, resource, can_write=True), delegated_by=alice)
assert any(c.resource == resource for c in conflicts)