@consiliency/agent-board-schema 1.56.0 → 1.58.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fixtures/already-applied.json +8 -0
- package/migrations/20261007000100_agent_board_onboard_requests.sql +139 -0
- package/migrations/20261008000100_agent_board_hosted_delegates.sql +3152 -0
- package/package.json +1 -1
- package/schema-manifest.json +21 -3
- package/src/tooling.test.mjs +8 -2
- package/tests/agent_board_atomic_fleet_onboarding.test.sql +13 -0
- package/tests/agent_board_consent_emission.test.sql +4 -2
- package/tests/agent_board_delegate_role_class.test.sql +736 -0
- package/tests/agent_board_federated_identity_injective_slug.test.sql +5 -2
- package/tests/agent_board_fedsession_stored_identity_gate.test.sql +71 -14
- package/tests/agent_board_fk_lock_edges.test.sql +9 -0
- package/tests/agent_board_hosted_delegates.test.sql +1134 -0
- package/tests/agent_board_ledger_authority.test.sql +34 -5
- package/tests/agent_board_membership_current_row_class.test.sql +3 -1
- package/tests/agent_board_onboard_requests.test.sql +353 -0
- package/tests/agent_board_rowid.test.sql +18 -5
- package/tests/agent_board_signer_lifecycle.test.sql +3 -0
- package/tests/agent_board_write_enforcement_class.test.sql +8 -3
- package/tests/catalog/function_execute_privileges.json +278 -2
- package/tests/catalog/p_metadata_parameters.json +48 -0
- package/tests/isolation/expected/hosted_delegate_exchange_race.out +93 -0
- package/tests/isolation/expected/hosted_delegate_first_exchange_race.out +129 -0
- package/tests/isolation/expected/hosted_delegate_owner_provisioning_race.out +91 -0
- package/tests/isolation/expected/hosted_delegate_owner_revoke_race.out +137 -0
- package/tests/isolation/expected/hosted_delegate_revoke_race.out +87 -0
- package/tests/isolation/expected/hosted_delegate_withdraw_evict_race.out +235 -0
- package/tests/isolation/specs/hosted_delegate_exchange_race.spec +64 -0
- package/tests/isolation/specs/hosted_delegate_first_exchange_race.spec +72 -0
- package/tests/isolation/specs/hosted_delegate_owner_provisioning_race.spec +73 -0
- package/tests/isolation/specs/hosted_delegate_owner_revoke_race.spec +93 -0
- package/tests/isolation/specs/hosted_delegate_revoke_race.spec +59 -0
- package/tests/isolation/specs/hosted_delegate_withdraw_evict_race.spec +145 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
Parsed test spec with 3 sessions
|
|
2
|
+
|
|
3
|
+
starting permutation: h_begin h_enroll x_begin x_exchange h_commit x_commit check
|
|
4
|
+
step h_begin: BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role';
|
|
5
|
+
step h_enroll:
|
|
6
|
+
select status from agent_board.enroll_federated_human(
|
|
7
|
+
'https://iso-prov.test', 'message-board', 'iso-prov-owner',
|
|
8
|
+
jsonb_build_object('sub', 'iso-prov-owner'), 'Iso Prov Owner');
|
|
9
|
+
|
|
10
|
+
status
|
|
11
|
+
------
|
|
12
|
+
active
|
|
13
|
+
(1 row)
|
|
14
|
+
|
|
15
|
+
step x_begin: BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role';
|
|
16
|
+
step x_exchange:
|
|
17
|
+
select count(*) as issued from agent_board.exchange_delegate_credential(jsonb_build_object(
|
|
18
|
+
'iss', 'https://iso-prov.test', 'sub', 'iso-prov-owner', 'slot_resource', null,
|
|
19
|
+
'agent_board_delegate_instance', jsonb_build_object(
|
|
20
|
+
'instance_id', 'iso_prov_instance_0001', 'grant_id', 'iso_grant_0000000001', 'generation', 1,
|
|
21
|
+
'owner_sub', 'iso-prov-owner', 'client_id', 'iso-client', 'status', 'active', 'client_change', null)));
|
|
22
|
+
<waiting ...>
|
|
23
|
+
step h_commit: COMMIT;
|
|
24
|
+
step x_exchange: <... completed>
|
|
25
|
+
issued
|
|
26
|
+
------
|
|
27
|
+
1
|
|
28
|
+
(1 row)
|
|
29
|
+
|
|
30
|
+
step x_commit: COMMIT;
|
|
31
|
+
step check:
|
|
32
|
+
select (select count(*) from auth.users
|
|
33
|
+
where email = 'agent+' || agent_board._federated_identity_slug('https://iso-prov.test', 'iso-prov-owner')
|
|
34
|
+
|| '@agent-board.local') as owner_auth_users,
|
|
35
|
+
(select count(*) from agent_board.agents
|
|
36
|
+
where handle = agent_board._federated_identity_slug('https://iso-prov.test', 'iso-prov-owner')) as human_rows,
|
|
37
|
+
(select h.auth_user_id = di.owner_user_id
|
|
38
|
+
from agent_board.agents h, agent_board.delegate_instances di
|
|
39
|
+
where h.handle = agent_board._federated_identity_slug('https://iso-prov.test', 'iso-prov-owner')
|
|
40
|
+
and di.instance_id = 'iso_prov_instance_0001') as delegate_owned_by_human;
|
|
41
|
+
|
|
42
|
+
owner_auth_users|human_rows|delegate_owned_by_human
|
|
43
|
+
----------------+----------+-----------------------
|
|
44
|
+
1| 1|t
|
|
45
|
+
(1 row)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
starting permutation: x_begin x_exchange h_begin h_enroll x_commit h_commit check
|
|
49
|
+
step x_begin: BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role';
|
|
50
|
+
step x_exchange:
|
|
51
|
+
select count(*) as issued from agent_board.exchange_delegate_credential(jsonb_build_object(
|
|
52
|
+
'iss', 'https://iso-prov.test', 'sub', 'iso-prov-owner', 'slot_resource', null,
|
|
53
|
+
'agent_board_delegate_instance', jsonb_build_object(
|
|
54
|
+
'instance_id', 'iso_prov_instance_0001', 'grant_id', 'iso_grant_0000000001', 'generation', 1,
|
|
55
|
+
'owner_sub', 'iso-prov-owner', 'client_id', 'iso-client', 'status', 'active', 'client_change', null)));
|
|
56
|
+
|
|
57
|
+
issued
|
|
58
|
+
------
|
|
59
|
+
1
|
|
60
|
+
(1 row)
|
|
61
|
+
|
|
62
|
+
step h_begin: BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role';
|
|
63
|
+
step h_enroll:
|
|
64
|
+
select status from agent_board.enroll_federated_human(
|
|
65
|
+
'https://iso-prov.test', 'message-board', 'iso-prov-owner',
|
|
66
|
+
jsonb_build_object('sub', 'iso-prov-owner'), 'Iso Prov Owner');
|
|
67
|
+
<waiting ...>
|
|
68
|
+
step x_commit: COMMIT;
|
|
69
|
+
step h_enroll: <... completed>
|
|
70
|
+
status
|
|
71
|
+
------
|
|
72
|
+
active
|
|
73
|
+
(1 row)
|
|
74
|
+
|
|
75
|
+
step h_commit: COMMIT;
|
|
76
|
+
step check:
|
|
77
|
+
select (select count(*) from auth.users
|
|
78
|
+
where email = 'agent+' || agent_board._federated_identity_slug('https://iso-prov.test', 'iso-prov-owner')
|
|
79
|
+
|| '@agent-board.local') as owner_auth_users,
|
|
80
|
+
(select count(*) from agent_board.agents
|
|
81
|
+
where handle = agent_board._federated_identity_slug('https://iso-prov.test', 'iso-prov-owner')) as human_rows,
|
|
82
|
+
(select h.auth_user_id = di.owner_user_id
|
|
83
|
+
from agent_board.agents h, agent_board.delegate_instances di
|
|
84
|
+
where h.handle = agent_board._federated_identity_slug('https://iso-prov.test', 'iso-prov-owner')
|
|
85
|
+
and di.instance_id = 'iso_prov_instance_0001') as delegate_owned_by_human;
|
|
86
|
+
|
|
87
|
+
owner_auth_users|human_rows|delegate_owned_by_human
|
|
88
|
+
----------------+----------+-----------------------
|
|
89
|
+
1| 1|t
|
|
90
|
+
(1 row)
|
|
91
|
+
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
Parsed test spec with 3 sessions
|
|
2
|
+
|
|
3
|
+
starting permutation: x_begin x_new r_begin r_revoke x_commit r_commit check
|
|
4
|
+
count
|
|
5
|
+
-----
|
|
6
|
+
1
|
|
7
|
+
(1 row)
|
|
8
|
+
|
|
9
|
+
step x_begin: BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role';
|
|
10
|
+
step x_new:
|
|
11
|
+
select count(*) as issued from agent_board.exchange_delegate_credential(jsonb_build_object(
|
|
12
|
+
'iss', 'https://iso-rev.test', 'sub', 'iso-rev-owner', 'slot_resource', null,
|
|
13
|
+
'agent_board_delegate_instance', jsonb_build_object(
|
|
14
|
+
'instance_id', 'iso_rev_new_000000001', 'grant_id', 'iso_grant_0000000001', 'generation', 1,
|
|
15
|
+
'owner_sub', 'iso-rev-owner', 'client_id', 'iso-client', 'status', 'active', 'client_change', null)));
|
|
16
|
+
|
|
17
|
+
issued
|
|
18
|
+
------
|
|
19
|
+
1
|
|
20
|
+
(1 row)
|
|
21
|
+
|
|
22
|
+
step r_begin: BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role';
|
|
23
|
+
step r_revoke:
|
|
24
|
+
select revoked_agent_count from agent_board.revoke_human_subtree(
|
|
25
|
+
(select auth_user_id from agent_board.agents
|
|
26
|
+
where handle = agent_board._federated_identity_slug('https://iso-rev.test', 'iso-rev-owner')),
|
|
27
|
+
'16310000-0000-0000-0000-000000000001', 'iso owner revoke race');
|
|
28
|
+
<waiting ...>
|
|
29
|
+
step x_commit: COMMIT;
|
|
30
|
+
step r_revoke: <... completed>
|
|
31
|
+
revoked_agent_count
|
|
32
|
+
-------------------
|
|
33
|
+
3
|
|
34
|
+
(1 row)
|
|
35
|
+
|
|
36
|
+
step r_commit: COMMIT;
|
|
37
|
+
step check:
|
|
38
|
+
select (select count(*) from agent_board.fleet_human_revocations where issuer = 'https://iso-rev.test') as markers,
|
|
39
|
+
(select count(*) from agent_board.delegate_instances where instance_id like 'iso\_rev\_%') as instances,
|
|
40
|
+
(select count(*) from agent_board.agents where handle like 'delegate-%' and status = 'active') as active_delegates,
|
|
41
|
+
(select count(*) from agent_board.agent_credentials ac
|
|
42
|
+
join agent_board.delegate_instances di on di.agent_id = ac.agent_id
|
|
43
|
+
where di.instance_id like 'iso\_rev\_%' and ac.revoked_at is null) as live_delegate_credentials;
|
|
44
|
+
|
|
45
|
+
markers|instances|active_delegates|live_delegate_credentials
|
|
46
|
+
-------+---------+----------------+-------------------------
|
|
47
|
+
1| 2| 0| 0
|
|
48
|
+
(1 row)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
starting permutation: r_begin r_revoke x_begin x_new r_commit x_commit check
|
|
52
|
+
count
|
|
53
|
+
-----
|
|
54
|
+
1
|
|
55
|
+
(1 row)
|
|
56
|
+
|
|
57
|
+
step r_begin: BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role';
|
|
58
|
+
step r_revoke:
|
|
59
|
+
select revoked_agent_count from agent_board.revoke_human_subtree(
|
|
60
|
+
(select auth_user_id from agent_board.agents
|
|
61
|
+
where handle = agent_board._federated_identity_slug('https://iso-rev.test', 'iso-rev-owner')),
|
|
62
|
+
'16310000-0000-0000-0000-000000000001', 'iso owner revoke race');
|
|
63
|
+
|
|
64
|
+
revoked_agent_count
|
|
65
|
+
-------------------
|
|
66
|
+
2
|
|
67
|
+
(1 row)
|
|
68
|
+
|
|
69
|
+
step x_begin: BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role';
|
|
70
|
+
step x_new:
|
|
71
|
+
select count(*) as issued from agent_board.exchange_delegate_credential(jsonb_build_object(
|
|
72
|
+
'iss', 'https://iso-rev.test', 'sub', 'iso-rev-owner', 'slot_resource', null,
|
|
73
|
+
'agent_board_delegate_instance', jsonb_build_object(
|
|
74
|
+
'instance_id', 'iso_rev_new_000000001', 'grant_id', 'iso_grant_0000000001', 'generation', 1,
|
|
75
|
+
'owner_sub', 'iso-rev-owner', 'client_id', 'iso-client', 'status', 'active', 'client_change', null)));
|
|
76
|
+
<waiting ...>
|
|
77
|
+
step r_commit: COMMIT;
|
|
78
|
+
step x_new: <... completed>
|
|
79
|
+
ERROR: owner_inactive
|
|
80
|
+
step x_commit: COMMIT;
|
|
81
|
+
step check:
|
|
82
|
+
select (select count(*) from agent_board.fleet_human_revocations where issuer = 'https://iso-rev.test') as markers,
|
|
83
|
+
(select count(*) from agent_board.delegate_instances where instance_id like 'iso\_rev\_%') as instances,
|
|
84
|
+
(select count(*) from agent_board.agents where handle like 'delegate-%' and status = 'active') as active_delegates,
|
|
85
|
+
(select count(*) from agent_board.agent_credentials ac
|
|
86
|
+
join agent_board.delegate_instances di on di.agent_id = ac.agent_id
|
|
87
|
+
where di.instance_id like 'iso\_rev\_%' and ac.revoked_at is null) as live_delegate_credentials;
|
|
88
|
+
|
|
89
|
+
markers|instances|active_delegates|live_delegate_credentials
|
|
90
|
+
-------+---------+----------------+-------------------------
|
|
91
|
+
1| 1| 0| 0
|
|
92
|
+
(1 row)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
starting permutation: r_begin r_revoke x_begin x_existing r_commit x_commit check
|
|
96
|
+
count
|
|
97
|
+
-----
|
|
98
|
+
1
|
|
99
|
+
(1 row)
|
|
100
|
+
|
|
101
|
+
step r_begin: BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role';
|
|
102
|
+
step r_revoke:
|
|
103
|
+
select revoked_agent_count from agent_board.revoke_human_subtree(
|
|
104
|
+
(select auth_user_id from agent_board.agents
|
|
105
|
+
where handle = agent_board._federated_identity_slug('https://iso-rev.test', 'iso-rev-owner')),
|
|
106
|
+
'16310000-0000-0000-0000-000000000001', 'iso owner revoke race');
|
|
107
|
+
|
|
108
|
+
revoked_agent_count
|
|
109
|
+
-------------------
|
|
110
|
+
2
|
|
111
|
+
(1 row)
|
|
112
|
+
|
|
113
|
+
step x_begin: BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role';
|
|
114
|
+
step x_existing:
|
|
115
|
+
select count(*) as issued from agent_board.exchange_delegate_credential(jsonb_build_object(
|
|
116
|
+
'iss', 'https://iso-rev.test', 'sub', 'iso-rev-owner', 'slot_resource', null,
|
|
117
|
+
'agent_board_delegate_instance', jsonb_build_object(
|
|
118
|
+
'instance_id', 'iso_rev_existing_00001', 'grant_id', 'iso_grant_0000000001', 'generation', 1,
|
|
119
|
+
'owner_sub', 'iso-rev-owner', 'client_id', 'iso-client', 'status', 'active', 'client_change', null)));
|
|
120
|
+
<waiting ...>
|
|
121
|
+
step r_commit: COMMIT;
|
|
122
|
+
step x_existing: <... completed>
|
|
123
|
+
ERROR: owner_inactive
|
|
124
|
+
step x_commit: COMMIT;
|
|
125
|
+
step check:
|
|
126
|
+
select (select count(*) from agent_board.fleet_human_revocations where issuer = 'https://iso-rev.test') as markers,
|
|
127
|
+
(select count(*) from agent_board.delegate_instances where instance_id like 'iso\_rev\_%') as instances,
|
|
128
|
+
(select count(*) from agent_board.agents where handle like 'delegate-%' and status = 'active') as active_delegates,
|
|
129
|
+
(select count(*) from agent_board.agent_credentials ac
|
|
130
|
+
join agent_board.delegate_instances di on di.agent_id = ac.agent_id
|
|
131
|
+
where di.instance_id like 'iso\_rev\_%' and ac.revoked_at is null) as live_delegate_credentials;
|
|
132
|
+
|
|
133
|
+
markers|instances|active_delegates|live_delegate_credentials
|
|
134
|
+
-------+---------+----------------+-------------------------
|
|
135
|
+
1| 1| 0| 0
|
|
136
|
+
(1 row)
|
|
137
|
+
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
Parsed test spec with 3 sessions
|
|
2
|
+
|
|
3
|
+
starting permutation: ex_begin ex_exchange rv_begin rv_tombstone ex_commit rv_commit check
|
|
4
|
+
count
|
|
5
|
+
-----
|
|
6
|
+
1
|
|
7
|
+
(1 row)
|
|
8
|
+
|
|
9
|
+
step ex_begin: BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role';
|
|
10
|
+
step ex_exchange:
|
|
11
|
+
select count(*) as issued from agent_board.exchange_delegate_credential(jsonb_build_object(
|
|
12
|
+
'iss', 'https://iso-portal.test', 'sub', 'iso-owner', 'slot_resource', null,
|
|
13
|
+
'agent_board_delegate_instance', jsonb_build_object(
|
|
14
|
+
'instance_id', 'iso_revoke_race_00001', 'grant_id', 'iso_grant_0000000002', 'generation', 2,
|
|
15
|
+
'owner_sub', 'iso-owner', 'client_id', 'iso-client', 'status', 'active', 'client_change', null)));
|
|
16
|
+
|
|
17
|
+
issued
|
|
18
|
+
------
|
|
19
|
+
1
|
|
20
|
+
(1 row)
|
|
21
|
+
|
|
22
|
+
step rv_begin: BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role';
|
|
23
|
+
step rv_tombstone:
|
|
24
|
+
select first from agent_board.tombstone_delegate_instance(
|
|
25
|
+
'iso_revoke_race_00001', 'https://iso-portal.test', 'iso-owner', 'owner_revoked');
|
|
26
|
+
<waiting ...>
|
|
27
|
+
step ex_commit: COMMIT;
|
|
28
|
+
step rv_tombstone: <... completed>
|
|
29
|
+
first
|
|
30
|
+
-----
|
|
31
|
+
t
|
|
32
|
+
(1 row)
|
|
33
|
+
|
|
34
|
+
step rv_commit: COMMIT;
|
|
35
|
+
step check:
|
|
36
|
+
select (di.tombstoned_at is not null) as tombstoned,
|
|
37
|
+
(select count(*) from agent_board.agent_credentials ac where ac.agent_id = di.agent_id and ac.revoked_at is null) as live_credentials,
|
|
38
|
+
(select count(*) from agent_board.agent_credentials ac where ac.agent_id = di.agent_id) as all_credentials,
|
|
39
|
+
(select a.status from agent_board.agents a where a.id = di.agent_id) as agent_status
|
|
40
|
+
from agent_board.delegate_instances di where di.instance_id = 'iso_revoke_race_00001';
|
|
41
|
+
|
|
42
|
+
tombstoned|live_credentials|all_credentials|agent_status
|
|
43
|
+
----------+----------------+---------------+------------
|
|
44
|
+
t | 0| 2|revoked
|
|
45
|
+
(1 row)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
starting permutation: rv_begin rv_tombstone ex_begin ex_exchange rv_commit ex_commit check
|
|
49
|
+
count
|
|
50
|
+
-----
|
|
51
|
+
1
|
|
52
|
+
(1 row)
|
|
53
|
+
|
|
54
|
+
step rv_begin: BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role';
|
|
55
|
+
step rv_tombstone:
|
|
56
|
+
select first from agent_board.tombstone_delegate_instance(
|
|
57
|
+
'iso_revoke_race_00001', 'https://iso-portal.test', 'iso-owner', 'owner_revoked');
|
|
58
|
+
|
|
59
|
+
first
|
|
60
|
+
-----
|
|
61
|
+
t
|
|
62
|
+
(1 row)
|
|
63
|
+
|
|
64
|
+
step ex_begin: BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role';
|
|
65
|
+
step ex_exchange:
|
|
66
|
+
select count(*) as issued from agent_board.exchange_delegate_credential(jsonb_build_object(
|
|
67
|
+
'iss', 'https://iso-portal.test', 'sub', 'iso-owner', 'slot_resource', null,
|
|
68
|
+
'agent_board_delegate_instance', jsonb_build_object(
|
|
69
|
+
'instance_id', 'iso_revoke_race_00001', 'grant_id', 'iso_grant_0000000002', 'generation', 2,
|
|
70
|
+
'owner_sub', 'iso-owner', 'client_id', 'iso-client', 'status', 'active', 'client_change', null)));
|
|
71
|
+
<waiting ...>
|
|
72
|
+
step rv_commit: COMMIT;
|
|
73
|
+
step ex_exchange: <... completed>
|
|
74
|
+
ERROR: instance_revoked
|
|
75
|
+
step ex_commit: COMMIT;
|
|
76
|
+
step check:
|
|
77
|
+
select (di.tombstoned_at is not null) as tombstoned,
|
|
78
|
+
(select count(*) from agent_board.agent_credentials ac where ac.agent_id = di.agent_id and ac.revoked_at is null) as live_credentials,
|
|
79
|
+
(select count(*) from agent_board.agent_credentials ac where ac.agent_id = di.agent_id) as all_credentials,
|
|
80
|
+
(select a.status from agent_board.agents a where a.id = di.agent_id) as agent_status
|
|
81
|
+
from agent_board.delegate_instances di where di.instance_id = 'iso_revoke_race_00001';
|
|
82
|
+
|
|
83
|
+
tombstoned|live_credentials|all_credentials|agent_status
|
|
84
|
+
----------+----------------+---------------+------------
|
|
85
|
+
t | 0| 1|revoked
|
|
86
|
+
(1 row)
|
|
87
|
+
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
Parsed test spec with 4 sessions
|
|
2
|
+
|
|
3
|
+
starting permutation: a_begin a_evict o_begin o_withdraw a_commit o_commit check o_readd check
|
|
4
|
+
step a_begin:
|
|
5
|
+
BEGIN;
|
|
6
|
+
select set_config('request.jwt.claims',
|
|
7
|
+
json_build_object('role', 'authenticated', 'sub', '16320000-0000-4000-8000-000000000001')::text, true) is not null as admin_session;
|
|
8
|
+
|
|
9
|
+
admin_session
|
|
10
|
+
-------------
|
|
11
|
+
t
|
|
12
|
+
(1 row)
|
|
13
|
+
|
|
14
|
+
step a_evict:
|
|
15
|
+
select membership_state from agent_board.update_board_membership(
|
|
16
|
+
'16322000-0000-4000-8000-000000000001',
|
|
17
|
+
(select agent_id from agent_board.delegate_instances where instance_id = 'iso_wd_instance_00001'),
|
|
18
|
+
'removed');
|
|
19
|
+
|
|
20
|
+
membership_state
|
|
21
|
+
----------------
|
|
22
|
+
removed
|
|
23
|
+
(1 row)
|
|
24
|
+
|
|
25
|
+
step o_begin:
|
|
26
|
+
BEGIN;
|
|
27
|
+
select set_config('request.jwt.claims', json_build_object('role', 'authenticated', 'sub',
|
|
28
|
+
(select auth_user_id from agent_board.agents
|
|
29
|
+
where handle = agent_board._federated_identity_slug('https://iso-wd.test', 'iso-wd-owner')))::text, true) is not null as owner_session;
|
|
30
|
+
|
|
31
|
+
owner_session
|
|
32
|
+
-------------
|
|
33
|
+
t
|
|
34
|
+
(1 row)
|
|
35
|
+
|
|
36
|
+
step o_withdraw:
|
|
37
|
+
select membership_state from agent_board.update_board_membership(
|
|
38
|
+
'16322000-0000-4000-8000-000000000001',
|
|
39
|
+
(select agent_id from agent_board.delegate_instances where instance_id = 'iso_wd_instance_00001'),
|
|
40
|
+
'left');
|
|
41
|
+
<waiting ...>
|
|
42
|
+
step a_commit: COMMIT;
|
|
43
|
+
step o_withdraw: <... completed>
|
|
44
|
+
ERROR: a principal may withdraw its delegate only from an active or pending membership
|
|
45
|
+
step o_commit: COMMIT;
|
|
46
|
+
step check:
|
|
47
|
+
select (select bm.membership_state from agent_board.board_memberships bm
|
|
48
|
+
join agent_board.delegate_instances di on di.agent_id = bm.agent_id
|
|
49
|
+
where bm.board_id = '16322000-0000-4000-8000-000000000001' and di.instance_id = 'iso_wd_instance_00001'
|
|
50
|
+
order by bm.created_at desc, bm.id desc limit 1) as delegate_state,
|
|
51
|
+
(select bm.membership_state from agent_board.board_memberships bm
|
|
52
|
+
where bm.board_id = '16322000-0000-4000-8000-000000000001'
|
|
53
|
+
and bm.agent_id = '16321000-0000-4000-8000-000000000002'
|
|
54
|
+
order by bm.created_at desc, bm.id desc limit 1) as member_state;
|
|
55
|
+
|
|
56
|
+
delegate_state|member_state
|
|
57
|
+
--------------+------------
|
|
58
|
+
removed |joined
|
|
59
|
+
(1 row)
|
|
60
|
+
|
|
61
|
+
step o_readd:
|
|
62
|
+
select set_config('request.jwt.claims', json_build_object('role', 'authenticated', 'sub',
|
|
63
|
+
(select auth_user_id from agent_board.agents
|
|
64
|
+
where handle = agent_board._federated_identity_slug('https://iso-wd.test', 'iso-wd-owner')))::text, false) is not null as owner_session;
|
|
65
|
+
select membership_state from agent_board.add_delegate_to_board(
|
|
66
|
+
(select agent_id from agent_board.delegate_instances where instance_id = 'iso_wd_instance_00001'),
|
|
67
|
+
'16322000-0000-4000-8000-000000000001');
|
|
68
|
+
|
|
69
|
+
owner_session
|
|
70
|
+
-------------
|
|
71
|
+
t
|
|
72
|
+
(1 row)
|
|
73
|
+
|
|
74
|
+
ERROR: a removed delegate stays removed; a board admin must lift the removal
|
|
75
|
+
step check:
|
|
76
|
+
select (select bm.membership_state from agent_board.board_memberships bm
|
|
77
|
+
join agent_board.delegate_instances di on di.agent_id = bm.agent_id
|
|
78
|
+
where bm.board_id = '16322000-0000-4000-8000-000000000001' and di.instance_id = 'iso_wd_instance_00001'
|
|
79
|
+
order by bm.created_at desc, bm.id desc limit 1) as delegate_state,
|
|
80
|
+
(select bm.membership_state from agent_board.board_memberships bm
|
|
81
|
+
where bm.board_id = '16322000-0000-4000-8000-000000000001'
|
|
82
|
+
and bm.agent_id = '16321000-0000-4000-8000-000000000002'
|
|
83
|
+
order by bm.created_at desc, bm.id desc limit 1) as member_state;
|
|
84
|
+
|
|
85
|
+
delegate_state|member_state
|
|
86
|
+
--------------+------------
|
|
87
|
+
removed |joined
|
|
88
|
+
(1 row)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
starting permutation: o_begin o_withdraw a_begin a_evict o_commit a_commit check o_readd check
|
|
92
|
+
step o_begin:
|
|
93
|
+
BEGIN;
|
|
94
|
+
select set_config('request.jwt.claims', json_build_object('role', 'authenticated', 'sub',
|
|
95
|
+
(select auth_user_id from agent_board.agents
|
|
96
|
+
where handle = agent_board._federated_identity_slug('https://iso-wd.test', 'iso-wd-owner')))::text, true) is not null as owner_session;
|
|
97
|
+
|
|
98
|
+
owner_session
|
|
99
|
+
-------------
|
|
100
|
+
t
|
|
101
|
+
(1 row)
|
|
102
|
+
|
|
103
|
+
step o_withdraw:
|
|
104
|
+
select membership_state from agent_board.update_board_membership(
|
|
105
|
+
'16322000-0000-4000-8000-000000000001',
|
|
106
|
+
(select agent_id from agent_board.delegate_instances where instance_id = 'iso_wd_instance_00001'),
|
|
107
|
+
'left');
|
|
108
|
+
|
|
109
|
+
membership_state
|
|
110
|
+
----------------
|
|
111
|
+
left
|
|
112
|
+
(1 row)
|
|
113
|
+
|
|
114
|
+
step a_begin:
|
|
115
|
+
BEGIN;
|
|
116
|
+
select set_config('request.jwt.claims',
|
|
117
|
+
json_build_object('role', 'authenticated', 'sub', '16320000-0000-4000-8000-000000000001')::text, true) is not null as admin_session;
|
|
118
|
+
|
|
119
|
+
admin_session
|
|
120
|
+
-------------
|
|
121
|
+
t
|
|
122
|
+
(1 row)
|
|
123
|
+
|
|
124
|
+
step a_evict:
|
|
125
|
+
select membership_state from agent_board.update_board_membership(
|
|
126
|
+
'16322000-0000-4000-8000-000000000001',
|
|
127
|
+
(select agent_id from agent_board.delegate_instances where instance_id = 'iso_wd_instance_00001'),
|
|
128
|
+
'removed');
|
|
129
|
+
<waiting ...>
|
|
130
|
+
step o_commit: COMMIT;
|
|
131
|
+
step a_evict: <... completed>
|
|
132
|
+
membership_state
|
|
133
|
+
----------------
|
|
134
|
+
removed
|
|
135
|
+
(1 row)
|
|
136
|
+
|
|
137
|
+
step a_commit: COMMIT;
|
|
138
|
+
step check:
|
|
139
|
+
select (select bm.membership_state from agent_board.board_memberships bm
|
|
140
|
+
join agent_board.delegate_instances di on di.agent_id = bm.agent_id
|
|
141
|
+
where bm.board_id = '16322000-0000-4000-8000-000000000001' and di.instance_id = 'iso_wd_instance_00001'
|
|
142
|
+
order by bm.created_at desc, bm.id desc limit 1) as delegate_state,
|
|
143
|
+
(select bm.membership_state from agent_board.board_memberships bm
|
|
144
|
+
where bm.board_id = '16322000-0000-4000-8000-000000000001'
|
|
145
|
+
and bm.agent_id = '16321000-0000-4000-8000-000000000002'
|
|
146
|
+
order by bm.created_at desc, bm.id desc limit 1) as member_state;
|
|
147
|
+
|
|
148
|
+
delegate_state|member_state
|
|
149
|
+
--------------+------------
|
|
150
|
+
removed |joined
|
|
151
|
+
(1 row)
|
|
152
|
+
|
|
153
|
+
step o_readd:
|
|
154
|
+
select set_config('request.jwt.claims', json_build_object('role', 'authenticated', 'sub',
|
|
155
|
+
(select auth_user_id from agent_board.agents
|
|
156
|
+
where handle = agent_board._federated_identity_slug('https://iso-wd.test', 'iso-wd-owner')))::text, false) is not null as owner_session;
|
|
157
|
+
select membership_state from agent_board.add_delegate_to_board(
|
|
158
|
+
(select agent_id from agent_board.delegate_instances where instance_id = 'iso_wd_instance_00001'),
|
|
159
|
+
'16322000-0000-4000-8000-000000000001');
|
|
160
|
+
|
|
161
|
+
owner_session
|
|
162
|
+
-------------
|
|
163
|
+
t
|
|
164
|
+
(1 row)
|
|
165
|
+
|
|
166
|
+
ERROR: a removed delegate stays removed; a board admin must lift the removal
|
|
167
|
+
step check:
|
|
168
|
+
select (select bm.membership_state from agent_board.board_memberships bm
|
|
169
|
+
join agent_board.delegate_instances di on di.agent_id = bm.agent_id
|
|
170
|
+
where bm.board_id = '16322000-0000-4000-8000-000000000001' and di.instance_id = 'iso_wd_instance_00001'
|
|
171
|
+
order by bm.created_at desc, bm.id desc limit 1) as delegate_state,
|
|
172
|
+
(select bm.membership_state from agent_board.board_memberships bm
|
|
173
|
+
where bm.board_id = '16322000-0000-4000-8000-000000000001'
|
|
174
|
+
and bm.agent_id = '16321000-0000-4000-8000-000000000002'
|
|
175
|
+
order by bm.created_at desc, bm.id desc limit 1) as member_state;
|
|
176
|
+
|
|
177
|
+
delegate_state|member_state
|
|
178
|
+
--------------+------------
|
|
179
|
+
removed |joined
|
|
180
|
+
(1 row)
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
starting permutation: a_begin a_evict_member m_begin m_leave a_commit m_commit check
|
|
184
|
+
step a_begin:
|
|
185
|
+
BEGIN;
|
|
186
|
+
select set_config('request.jwt.claims',
|
|
187
|
+
json_build_object('role', 'authenticated', 'sub', '16320000-0000-4000-8000-000000000001')::text, true) is not null as admin_session;
|
|
188
|
+
|
|
189
|
+
admin_session
|
|
190
|
+
-------------
|
|
191
|
+
t
|
|
192
|
+
(1 row)
|
|
193
|
+
|
|
194
|
+
step a_evict_member:
|
|
195
|
+
select membership_state from agent_board.update_board_membership(
|
|
196
|
+
'16322000-0000-4000-8000-000000000001', '16321000-0000-4000-8000-000000000002', 'removed');
|
|
197
|
+
|
|
198
|
+
membership_state
|
|
199
|
+
----------------
|
|
200
|
+
removed
|
|
201
|
+
(1 row)
|
|
202
|
+
|
|
203
|
+
step m_begin:
|
|
204
|
+
BEGIN;
|
|
205
|
+
select set_config('request.jwt.claims',
|
|
206
|
+
json_build_object('role', 'authenticated', 'sub', '16320000-0000-4000-8000-000000000002')::text, true) is not null as member_session;
|
|
207
|
+
|
|
208
|
+
member_session
|
|
209
|
+
--------------
|
|
210
|
+
t
|
|
211
|
+
(1 row)
|
|
212
|
+
|
|
213
|
+
step m_leave:
|
|
214
|
+
select membership_state from agent_board.update_board_membership(
|
|
215
|
+
'16322000-0000-4000-8000-000000000001', '16321000-0000-4000-8000-000000000002', 'left');
|
|
216
|
+
<waiting ...>
|
|
217
|
+
step a_commit: COMMIT;
|
|
218
|
+
step m_leave: <... completed>
|
|
219
|
+
ERROR: self membership change not permitted; use the join/approval path
|
|
220
|
+
step m_commit: COMMIT;
|
|
221
|
+
step check:
|
|
222
|
+
select (select bm.membership_state from agent_board.board_memberships bm
|
|
223
|
+
join agent_board.delegate_instances di on di.agent_id = bm.agent_id
|
|
224
|
+
where bm.board_id = '16322000-0000-4000-8000-000000000001' and di.instance_id = 'iso_wd_instance_00001'
|
|
225
|
+
order by bm.created_at desc, bm.id desc limit 1) as delegate_state,
|
|
226
|
+
(select bm.membership_state from agent_board.board_memberships bm
|
|
227
|
+
where bm.board_id = '16322000-0000-4000-8000-000000000001'
|
|
228
|
+
and bm.agent_id = '16321000-0000-4000-8000-000000000002'
|
|
229
|
+
order by bm.created_at desc, bm.id desc limit 1) as member_state;
|
|
230
|
+
|
|
231
|
+
delegate_state|member_state
|
|
232
|
+
--------------+------------
|
|
233
|
+
joined |removed
|
|
234
|
+
(1 row)
|
|
235
|
+
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# HOSTED (v11) SL-2, IF-0-HOSTED-7: two concurrent exchanges of ONE instance at different
|
|
2
|
+
# generations serialise on the instance row lock (`select ... for update`), in both orders.
|
|
3
|
+
#
|
|
4
|
+
# new first: the generation-3 exchange commits; the generation-2 exchange, blocked on the
|
|
5
|
+
# row, then sees r = 3 and is refused generation_superseded.
|
|
6
|
+
# old first: the generation-2 exchange commits; the generation-3 exchange, blocked, then
|
|
7
|
+
# sees r = 2, records 3 and revokes every lower-generation credential.
|
|
8
|
+
#
|
|
9
|
+
# Either way the recorded generation is 3 and the only live credential is generation 3.
|
|
10
|
+
# Without the row lock the generation-2 exchange does not wait for the read, decides against
|
|
11
|
+
# r = 1, and the trace and the final generation both change (the mutation receipt).
|
|
12
|
+
|
|
13
|
+
setup
|
|
14
|
+
{
|
|
15
|
+
select count(*) from agent_board.exchange_delegate_credential(jsonb_build_object(
|
|
16
|
+
'iss', 'https://iso-portal.test', 'sub', 'iso-owner', 'slot_resource', null,
|
|
17
|
+
'agent_board_delegate_instance', jsonb_build_object(
|
|
18
|
+
'instance_id', 'iso_exchange_race_0001', 'grant_id', 'iso_grant_0000000001', 'generation', 1,
|
|
19
|
+
'owner_sub', 'iso-owner', 'client_id', 'iso-client', 'status', 'active', 'client_change', null)));
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
teardown
|
|
23
|
+
{
|
|
24
|
+
delete from agent_board.agent_credentials
|
|
25
|
+
where agent_id in (select agent_id from agent_board.delegate_instances where instance_id like 'iso\_%');
|
|
26
|
+
delete from agent_board.delegate_instances where instance_id like 'iso\_%';
|
|
27
|
+
delete from agent_board.agents where handle like 'delegate-%';
|
|
28
|
+
delete from auth.identities where provider_id like 'delegate-%' or provider_id like 'fed-human-%';
|
|
29
|
+
delete from auth.users where email like 'agent+delegate-%' or email like 'agent+fed-human-%';
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
session "new"
|
|
33
|
+
step "new_begin" { BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role'; }
|
|
34
|
+
step "new_exchange" {
|
|
35
|
+
select count(*) as issued from agent_board.exchange_delegate_credential(jsonb_build_object(
|
|
36
|
+
'iss', 'https://iso-portal.test', 'sub', 'iso-owner', 'slot_resource', null,
|
|
37
|
+
'agent_board_delegate_instance', jsonb_build_object(
|
|
38
|
+
'instance_id', 'iso_exchange_race_0001', 'grant_id', 'iso_grant_0000000003', 'generation', 3,
|
|
39
|
+
'owner_sub', 'iso-owner', 'client_id', 'iso-client', 'status', 'active', 'client_change', null)));
|
|
40
|
+
}
|
|
41
|
+
step "new_commit" { COMMIT; }
|
|
42
|
+
|
|
43
|
+
session "old"
|
|
44
|
+
step "old_begin" { BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role'; }
|
|
45
|
+
step "old_exchange" {
|
|
46
|
+
select count(*) as issued from agent_board.exchange_delegate_credential(jsonb_build_object(
|
|
47
|
+
'iss', 'https://iso-portal.test', 'sub', 'iso-owner', 'slot_resource', null,
|
|
48
|
+
'agent_board_delegate_instance', jsonb_build_object(
|
|
49
|
+
'instance_id', 'iso_exchange_race_0001', 'grant_id', 'iso_grant_0000000002', 'generation', 2,
|
|
50
|
+
'owner_sub', 'iso-owner', 'client_id', 'iso-client', 'status', 'active', 'client_change', null)));
|
|
51
|
+
}
|
|
52
|
+
step "old_commit" { COMMIT; }
|
|
53
|
+
|
|
54
|
+
session "check"
|
|
55
|
+
step "check" {
|
|
56
|
+
select di.generation as recorded_generation, di.grant_id as recorded_grant,
|
|
57
|
+
(select string_agg(ac.generation::text, ',' order by ac.generation)
|
|
58
|
+
from agent_board.agent_credentials ac where ac.agent_id = di.agent_id and ac.revoked_at is null) as live_generations,
|
|
59
|
+
(select count(*) from agent_board.agents a where a.handle like 'delegate-%') as delegate_agents
|
|
60
|
+
from agent_board.delegate_instances di where di.instance_id = 'iso_exchange_race_0001';
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
permutation "new_begin" "new_exchange" "old_begin" "old_exchange" "new_commit" "old_commit" "check"
|
|
64
|
+
permutation "old_begin" "old_exchange" "new_begin" "new_exchange" "old_commit" "new_commit" "check"
|