@consiliency/agent-board-schema 1.54.0 → 1.56.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/20261005000100_agent_board_enroll_token_single_use.sql +886 -0
- package/migrations/20261006000100_agent_board_room_roster_active_first.sql +118 -0
- package/package.json +1 -1
- package/schema-manifest.json +21 -3
- package/src/tooling.test.mjs +7 -2
- package/tests/agent_board_atomic_fleet_onboarding.test.sql +35 -35
- package/tests/agent_board_atomic_fleet_onboarding_backfill.test.sql +5 -5
- package/tests/agent_board_atomic_fleet_onboarding_runtime.test.sql +32 -32
- package/tests/agent_board_enroll_federated_identity.test.sql +11 -10
- package/tests/agent_board_enroll_pop_binding.test.sql +12 -12
- package/tests/agent_board_enroll_resumption.test.sql +1 -1
- package/tests/agent_board_enroll_token_single_use.test.sql +538 -0
- package/tests/agent_board_enrollment_audit_content.test.sql +3 -3
- package/tests/agent_board_federated_lock_order_class.test.sql +5 -5
- package/tests/agent_board_fedsession.test.sql +1 -1
- package/tests/agent_board_fk_lock_edges.test.sql +23 -0
- package/tests/agent_board_identity_providers.test.sql +3 -2
- package/tests/agent_board_membership_current_row_class.test.sql +460 -0
- package/tests/agent_board_portal_offline_invariant.test.sql +1 -1
- package/tests/agent_board_room_roster.test.sql +262 -24
- package/tests/agent_board_roomlink.test.sql +2 -2
- package/tests/agent_board_rowid.test.sql +15 -2
- package/tests/agent_board_write_enforcement_class.test.sql +5 -2
- package/tests/catalog/function_execute_privileges.json +12 -3
- package/tests/catalog/p_metadata_parameters.json +6 -2
- package/tests/isolation/expected/atomic_fedsession_fleet_lock_order.out +1 -1
- package/tests/isolation/expected/atomic_fleet_authority_races.out +8 -8
- package/tests/isolation/expected/atomic_fleet_binding_revoke.out +2 -2
- package/tests/isolation/expected/atomic_fleet_board_archive.out +2 -2
- package/tests/isolation/expected/atomic_fleet_human_fresh_revoke.out +2 -2
- package/tests/isolation/expected/atomic_fleet_identity_disposition.out +2 -2
- package/tests/isolation/expected/atomic_fleet_lifecycle_races.out +22 -22
- package/tests/isolation/expected/atomic_fleet_onboarding.out +2 -2
- package/tests/isolation/expected/atomic_fleet_subtree_lock_order.out +1 -1
- package/tests/isolation/expected/enroll_identity_board_owner_lock_order.out +1 -1
- package/tests/isolation/expected/enroll_token_fleet_abort.out +81 -0
- package/tests/isolation/expected/enroll_token_pk_backstop.out +36 -0
- package/tests/isolation/expected/enroll_token_placement.out +86 -0
- package/tests/isolation/expected/enroll_token_rollback_unstrands.out +59 -0
- package/tests/isolation/expected/enroll_token_route_race_fleet_first.out +72 -0
- package/tests/isolation/expected/enroll_token_route_race_identity_first.out +72 -0
- package/tests/isolation/expected/enroll_token_same_key_fleet_then_identity.out +73 -0
- package/tests/isolation/expected/enroll_token_same_key_identity_then_fleet.out +73 -0
- package/tests/isolation/expected/enroll_token_same_key_resume.out +59 -0
- package/tests/isolation/expected/enroll_token_same_token_race.out +58 -0
- package/tests/isolation/expected/onboarding_ceiling_lock_order.out +2 -2
- package/tests/isolation/specs/atomic_fedsession_fleet_lock_order.spec +1 -1
- package/tests/isolation/specs/atomic_fleet_authority_races.spec +2 -2
- package/tests/isolation/specs/atomic_fleet_binding_revoke.spec +2 -2
- package/tests/isolation/specs/atomic_fleet_board_archive.spec +2 -2
- package/tests/isolation/specs/atomic_fleet_human_fresh_revoke.spec +2 -2
- package/tests/isolation/specs/atomic_fleet_identity_disposition.spec +2 -2
- package/tests/isolation/specs/atomic_fleet_lifecycle_races.spec +2 -2
- package/tests/isolation/specs/atomic_fleet_onboarding.spec +2 -2
- package/tests/isolation/specs/atomic_fleet_subtree_lock_order.spec +2 -2
- package/tests/isolation/specs/enroll_identity_board_owner_lock_order.spec +1 -1
- package/tests/isolation/specs/enroll_token_fleet_abort.spec +138 -0
- package/tests/isolation/specs/enroll_token_pk_backstop.spec +37 -0
- package/tests/isolation/specs/enroll_token_placement.spec +136 -0
- package/tests/isolation/specs/enroll_token_rollback_unstrands.spec +71 -0
- package/tests/isolation/specs/enroll_token_route_race_fleet_first.spec +119 -0
- package/tests/isolation/specs/enroll_token_route_race_identity_first.spec +120 -0
- package/tests/isolation/specs/enroll_token_same_key_fleet_then_identity.spec +112 -0
- package/tests/isolation/specs/enroll_token_same_key_identity_then_fleet.spec +113 -0
- package/tests/isolation/specs/enroll_token_same_key_resume.spec +70 -0
- package/tests/isolation/specs/enroll_token_same_token_race.spec +80 -0
- package/tests/isolation/specs/onboarding_ceiling_lock_order.spec +1 -1
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# Consiliency/message-board#521 I-7 -- a fleet onboarding that fails AFTER its nested
|
|
2
|
+
# enroll_federated_identity has bound the token, while a contender waits behind it.
|
|
3
|
+
#
|
|
4
|
+
# A presents (T, K1) with a slug whose server-assigned handle is NOT the invite's authorized
|
|
5
|
+
# handle, so onboard_federated_fleet_agent raises `server-assigned handle does not match`
|
|
6
|
+
# right after the nested call returns -- by then A's transaction holds the bind row, the K1
|
|
7
|
+
# key and the K1 agent. B presents (T, K2) with the correct slug.
|
|
8
|
+
#
|
|
9
|
+
# The failure has to happen while B is ALREADY waiting, or the spec proves nothing about a
|
|
10
|
+
# contender: a statement error releases the transaction's locks at once, so a failure that
|
|
11
|
+
# fires before B arrives leaves B nothing to wait for (measured -- the first draft of this
|
|
12
|
+
# spec did exactly that). So a "hold" session inserts, uncommitted, an agent carrying A's
|
|
13
|
+
# handle: A binds the token, reaches its agent insert inside the nested call and waits on
|
|
14
|
+
# that uncommitted handle. B then waits behind A (on the invite row, which onboarding locks
|
|
15
|
+
# first -- the outcome does not depend on which lock). The hold rolls back, A creates its
|
|
16
|
+
# agent, returns to onboard, fails; its whole transaction -- bind row included -- is gone.
|
|
17
|
+
# B SUCCEEDS, the token row names K2, and nothing of K1 survives.
|
|
18
|
+
|
|
19
|
+
setup
|
|
20
|
+
{
|
|
21
|
+
insert into agent_board.identity_providers(
|
|
22
|
+
issuer, audience, supported, policy_approved,
|
|
23
|
+
allowed_scopes, allowed_board_scopes, allowed_agent_kinds
|
|
24
|
+
) values (
|
|
25
|
+
'https://tok521-iso.test', 'message-board', true, true,
|
|
26
|
+
ARRAY['board:send'], ARRAY[]::text[], ARRAY['agent']
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
-- Materialize the owner auth.users row the enrollment derives, through the SAME helper,
|
|
30
|
+
-- so a contender blocks on the owner row lock (the serialisation under test) and not on
|
|
31
|
+
-- a racing INSERT inside _ensure_agent_auth_user.
|
|
32
|
+
create table tok521_owner as
|
|
33
|
+
select agent_board._ensure_agent_auth_user(
|
|
34
|
+
agent_board._federated_identity_slug('https://tok521-iso.test', 'tok521-human')) as uid;
|
|
35
|
+
|
|
36
|
+
insert into agent_board.agents(id, agent_type, kind, handle, display_name, status)
|
|
37
|
+
values ('52100000-0000-0000-0000-000000000001', 'agent', 'agent',
|
|
38
|
+
'tok521-creator', 'Tok521 Creator', 'active');
|
|
39
|
+
select count(*) from agent_board.create_board(
|
|
40
|
+
'52100000-0000-0000-0000-000000000001',
|
|
41
|
+
'tok521-board', 'Tok521 Board',
|
|
42
|
+
'Consiliency/message-board#521 token single-use isolation proof',
|
|
43
|
+
jsonb_build_object(), 'private'
|
|
44
|
+
);
|
|
45
|
+
insert into agent_board.fleet_trust_domains(
|
|
46
|
+
id, slug, display_name, domain_kind, owner_agent_id, lifecycle_state, approved_at
|
|
47
|
+
) values (
|
|
48
|
+
'52100000-0000-0000-0000-000000000002', 'tok521-domain',
|
|
49
|
+
'Tok521 Domain', 'tailnet', '52100000-0000-0000-0000-000000000001',
|
|
50
|
+
'active', now()
|
|
51
|
+
);
|
|
52
|
+
insert into agent_board.fleet_machines(
|
|
53
|
+
id, trust_domain_id, owner_agent_id, machine_label, machine_fingerprint,
|
|
54
|
+
lifecycle_state, enrollment_source, enrolled_at
|
|
55
|
+
) values (
|
|
56
|
+
'52100000-0000-0000-0000-000000000003',
|
|
57
|
+
'52100000-0000-0000-0000-000000000002',
|
|
58
|
+
'52100000-0000-0000-0000-000000000001',
|
|
59
|
+
'claw', 'sha256:tok521-machine', 'active', 'portal', now()
|
|
60
|
+
);
|
|
61
|
+
select count(*) from agent_board.create_fleet_onboarding_invite(
|
|
62
|
+
(select id from agent_board.boards where slug='tok521-board'),
|
|
63
|
+
'52100000-0000-0000-0000-000000000003', 'codex', 'phase-loop',
|
|
64
|
+
'message-board', 'sha256:tok521-repo', 'worker', 'phase_worker',
|
|
65
|
+
'tok521-agent', 2, now() + interval '1 hour',
|
|
66
|
+
'52100000-0000-0000-0000-000000000001', jsonb_build_object()
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
session "hold"
|
|
71
|
+
step "hold_begin" { BEGIN; }
|
|
72
|
+
step "hold_handle" {
|
|
73
|
+
insert into agent_board.agents(id, agent_type, kind, handle, display_name, status)
|
|
74
|
+
values ('52100000-0000-0000-0000-0000000000ff', 'agent', 'agent', 'tok521-wrong-handle', 'Tok521 Hold', 'active');
|
|
75
|
+
}
|
|
76
|
+
step "hold_rollback" { ROLLBACK; }
|
|
77
|
+
|
|
78
|
+
session "a"
|
|
79
|
+
step "a_begin" { BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role'; }
|
|
80
|
+
step "a_onboard" {
|
|
81
|
+
select agent_handle, identity_disposition
|
|
82
|
+
from agent_board.onboard_federated_fleet_agent(
|
|
83
|
+
'https://tok521-iso.test', 'message-board', 'tok521-human',
|
|
84
|
+
jsonb_build_object('iss','https://tok521-iso.test','aud','message-board','sub','tok521-human'),
|
|
85
|
+
'tok521-wrong-handle',
|
|
86
|
+
public.test_pubkey('tok521-k1'), 'raw_ed25519_base64url',
|
|
87
|
+
public.test_key_fingerprint('tok521-k1'),
|
|
88
|
+
true, repeat('a', 64), now() + interval '1 hour', null, 'agent',
|
|
89
|
+
ARRAY['board:send'], ARRAY[]::text[],
|
|
90
|
+
(select code from agent_board.board_invite_tokens where created_by_agent_id='52100000-0000-0000-0000-000000000001'),
|
|
91
|
+
(select id from agent_board.boards where slug='tok521-board'),
|
|
92
|
+
'52100000-0000-0000-0000-000000000003', 'codex', 'phase-loop',
|
|
93
|
+
'message-board', 'sha256:tok521-repo', 'worker', 'phase_worker',
|
|
94
|
+
'tok521-agent'
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
step "a_rollback" { ROLLBACK; }
|
|
98
|
+
|
|
99
|
+
session "b"
|
|
100
|
+
step "b_begin" { BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role'; }
|
|
101
|
+
step "b_onboard" {
|
|
102
|
+
select agent_handle, identity_disposition
|
|
103
|
+
from agent_board.onboard_federated_fleet_agent(
|
|
104
|
+
'https://tok521-iso.test', 'message-board', 'tok521-human',
|
|
105
|
+
jsonb_build_object('iss','https://tok521-iso.test','aud','message-board','sub','tok521-human'),
|
|
106
|
+
'tok521-agent',
|
|
107
|
+
public.test_pubkey('tok521-k2'), 'raw_ed25519_base64url',
|
|
108
|
+
public.test_key_fingerprint('tok521-k2'),
|
|
109
|
+
true, repeat('a', 64), now() + interval '1 hour', null, 'agent',
|
|
110
|
+
ARRAY['board:send'], ARRAY[]::text[],
|
|
111
|
+
(select code from agent_board.board_invite_tokens where created_by_agent_id='52100000-0000-0000-0000-000000000001'),
|
|
112
|
+
(select id from agent_board.boards where slug='tok521-board'),
|
|
113
|
+
'52100000-0000-0000-0000-000000000003', 'codex', 'phase-loop',
|
|
114
|
+
'message-board', 'sha256:tok521-repo', 'worker', 'phase_worker',
|
|
115
|
+
'tok521-agent'
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
step "b_commit" { COMMIT; }
|
|
119
|
+
|
|
120
|
+
session "check"
|
|
121
|
+
step "check" {
|
|
122
|
+
select
|
|
123
|
+
(select count(*) from agent_board.agents where handle like 'tok521-agent%') as agents,
|
|
124
|
+
(select count(*) from agent_board.agent_signing_keys where fingerprint = public.test_key_fingerprint('tok521-k1')) as k1_keys,
|
|
125
|
+
(select count(*) from agent_board.agent_signing_keys where fingerprint = public.test_key_fingerprint('tok521-k2')) as k2_keys,
|
|
126
|
+
(select count(*) from agent_board.enroll_token_uses) as token_rows,
|
|
127
|
+
(select case u.agent_public_key_fingerprint
|
|
128
|
+
when public.test_key_fingerprint('tok521-k1') then 'K1'
|
|
129
|
+
when public.test_key_fingerprint('tok521-k2') then 'K2'
|
|
130
|
+
else 'other' end
|
|
131
|
+
from agent_board.enroll_token_uses u where u.token_sha256 = repeat('a', 64)) as token_bound_to,
|
|
132
|
+
(select count(*) from agent_board.fleet_harness_registrations where machine_id='52100000-0000-0000-0000-000000000003') as harnesses,
|
|
133
|
+
(select count(*) from agent_board.fleet_repo_scopes r join agent_board.fleet_harness_registrations h on h.id = r.harness_registration_id
|
|
134
|
+
where h.machine_id='52100000-0000-0000-0000-000000000003') as repo_scopes,
|
|
135
|
+
(select count(*) from agent_board.fleet_machine_agents where machine_id='52100000-0000-0000-0000-000000000003') as bindings;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
permutation "hold_begin" "hold_handle" "a_begin" "a_onboard" "b_begin" "b_onboard" "hold_rollback" "a_rollback" "b_commit" "check"
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Consiliency/message-board#521 I-6 -- the primary key is the fail-closed backstop. Two
|
|
2
|
+
# sessions call _enroll_token_bind directly, as its owner, WITHOUT the owner lock the RPCs
|
|
3
|
+
# take, with the same token and different fingerprints. B's insert waits on A's
|
|
4
|
+
# uncommitted key; when A commits, B fails 23505. It never binds a second key silently.
|
|
5
|
+
#
|
|
6
|
+
# The step expected to FAIL runs inside a DO block that re-raises with the SQLSTATE in the
|
|
7
|
+
# message, because isolationtester prints only `ERROR: <message>`: without it a raise with
|
|
8
|
+
# the same text and a different errcode would leave this golden green.
|
|
9
|
+
|
|
10
|
+
setup
|
|
11
|
+
{
|
|
12
|
+
select 1;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
session "a"
|
|
16
|
+
step "a_begin" { BEGIN; }
|
|
17
|
+
step "a_bind" { select agent_board._enroll_token_bind(repeat('a', 64), now() + interval '1 hour', 'sha256:tok521-fp-a'); }
|
|
18
|
+
step "a_commit" { COMMIT; }
|
|
19
|
+
|
|
20
|
+
session "b"
|
|
21
|
+
step "b_begin" { BEGIN; }
|
|
22
|
+
step "b_bind" {
|
|
23
|
+
do $$ begin
|
|
24
|
+
perform agent_board._enroll_token_bind(repeat('a', 64), now() + interval '1 hour', 'sha256:tok521-fp-b');
|
|
25
|
+
exception when others then
|
|
26
|
+
raise exception 'SQLSTATE %: %', sqlstate, sqlerrm using errcode = sqlstate;
|
|
27
|
+
end $$;
|
|
28
|
+
}
|
|
29
|
+
step "b_rollback" { ROLLBACK; }
|
|
30
|
+
|
|
31
|
+
session "check"
|
|
32
|
+
step "check" {
|
|
33
|
+
select token_sha256 = repeat('a', 64) as is_t, agent_public_key_fingerprint
|
|
34
|
+
from agent_board.enroll_token_uses order by 1, 2;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
permutation "a_begin" "a_bind" "b_begin" "b_bind" "a_commit" "b_rollback" "check"
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# Consiliency/message-board#521 I-5 -- PLACEMENT of the bind, not merely its presence.
|
|
2
|
+
# A guard session holds the invite creator's board_memberships row. The fleet onboarding
|
|
3
|
+
# (T, K2) takes the derived owner row FOR UPDATE and then parks on the guard. The identity
|
|
4
|
+
# enrollment (T, K1) parks on that owner row. When the guard commits, the fleet onboarding
|
|
5
|
+
# completes and binds T -> K2; the identity enrollment then binds and gets MBT01.
|
|
6
|
+
#
|
|
7
|
+
# If the bind were hoisted ABOVE the owner lock (the rejected "token lock at the top"
|
|
8
|
+
# design), the identity enrollment would insert T -> K1 and THEN wait for the owner, while
|
|
9
|
+
# the fleet onboarding holds the owner and waits on that uncommitted token row: the golden
|
|
10
|
+
# would show `deadlock detected` (40P01) instead of a clean MBT01. The golden records only
|
|
11
|
+
# the deterministic outcome: which session completes, and with what.
|
|
12
|
+
#
|
|
13
|
+
# The step expected to FAIL runs inside a DO block that re-raises with the SQLSTATE in the
|
|
14
|
+
# message, because isolationtester prints only `ERROR: <message>`: without it a raise with
|
|
15
|
+
# the same text and a different errcode would leave this golden green.
|
|
16
|
+
|
|
17
|
+
setup
|
|
18
|
+
{
|
|
19
|
+
insert into agent_board.identity_providers(
|
|
20
|
+
issuer, audience, supported, policy_approved,
|
|
21
|
+
allowed_scopes, allowed_board_scopes, allowed_agent_kinds
|
|
22
|
+
) values (
|
|
23
|
+
'https://tok521-iso.test', 'message-board', true, true,
|
|
24
|
+
ARRAY['board:send'], ARRAY[]::text[], ARRAY['agent']
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
-- Materialize the owner auth.users row the enrollment derives, through the SAME helper,
|
|
28
|
+
-- so a contender blocks on the owner row lock (the serialisation under test) and not on
|
|
29
|
+
-- a racing INSERT inside _ensure_agent_auth_user.
|
|
30
|
+
create table tok521_owner as
|
|
31
|
+
select agent_board._ensure_agent_auth_user(
|
|
32
|
+
agent_board._federated_identity_slug('https://tok521-iso.test', 'tok521-human')) as uid;
|
|
33
|
+
|
|
34
|
+
insert into agent_board.agents(id, agent_type, kind, handle, display_name, status)
|
|
35
|
+
values ('52100000-0000-0000-0000-000000000001', 'agent', 'agent',
|
|
36
|
+
'tok521-creator', 'Tok521 Creator', 'active');
|
|
37
|
+
select count(*) from agent_board.create_board(
|
|
38
|
+
'52100000-0000-0000-0000-000000000001',
|
|
39
|
+
'tok521-board', 'Tok521 Board',
|
|
40
|
+
'Consiliency/message-board#521 token single-use isolation proof',
|
|
41
|
+
jsonb_build_object(), 'private'
|
|
42
|
+
);
|
|
43
|
+
insert into agent_board.fleet_trust_domains(
|
|
44
|
+
id, slug, display_name, domain_kind, owner_agent_id, lifecycle_state, approved_at
|
|
45
|
+
) values (
|
|
46
|
+
'52100000-0000-0000-0000-000000000002', 'tok521-domain',
|
|
47
|
+
'Tok521 Domain', 'tailnet', '52100000-0000-0000-0000-000000000001',
|
|
48
|
+
'active', now()
|
|
49
|
+
);
|
|
50
|
+
insert into agent_board.fleet_machines(
|
|
51
|
+
id, trust_domain_id, owner_agent_id, machine_label, machine_fingerprint,
|
|
52
|
+
lifecycle_state, enrollment_source, enrolled_at
|
|
53
|
+
) values (
|
|
54
|
+
'52100000-0000-0000-0000-000000000003',
|
|
55
|
+
'52100000-0000-0000-0000-000000000002',
|
|
56
|
+
'52100000-0000-0000-0000-000000000001',
|
|
57
|
+
'claw', 'sha256:tok521-machine', 'active', 'portal', now()
|
|
58
|
+
);
|
|
59
|
+
select count(*) from agent_board.create_fleet_onboarding_invite(
|
|
60
|
+
(select id from agent_board.boards where slug='tok521-board'),
|
|
61
|
+
'52100000-0000-0000-0000-000000000003', 'codex', 'phase-loop',
|
|
62
|
+
'message-board', 'sha256:tok521-repo', 'worker', 'phase_worker',
|
|
63
|
+
'tok521-agent', 2, now() + interval '1 hour',
|
|
64
|
+
'52100000-0000-0000-0000-000000000001', jsonb_build_object()
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
session "guard"
|
|
69
|
+
step "guard_begin" { BEGIN; }
|
|
70
|
+
step "guard_lock" {
|
|
71
|
+
select 1 as locked from agent_board.board_memberships bm
|
|
72
|
+
where bm.board_id = (select id from agent_board.boards where slug='tok521-board')
|
|
73
|
+
and bm.agent_id = '52100000-0000-0000-0000-000000000001'
|
|
74
|
+
for update;
|
|
75
|
+
}
|
|
76
|
+
step "guard_commit" { COMMIT; }
|
|
77
|
+
|
|
78
|
+
session "fleet"
|
|
79
|
+
step "fleet_begin" { BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role'; }
|
|
80
|
+
step "fleet_onboard" {
|
|
81
|
+
select agent_handle, identity_disposition
|
|
82
|
+
from agent_board.onboard_federated_fleet_agent(
|
|
83
|
+
'https://tok521-iso.test', 'message-board', 'tok521-human',
|
|
84
|
+
jsonb_build_object('iss','https://tok521-iso.test','aud','message-board','sub','tok521-human'),
|
|
85
|
+
'tok521-agent',
|
|
86
|
+
public.test_pubkey('tok521-k2'), 'raw_ed25519_base64url',
|
|
87
|
+
public.test_key_fingerprint('tok521-k2'),
|
|
88
|
+
true, repeat('a', 64), now() + interval '1 hour', null, 'agent',
|
|
89
|
+
ARRAY['board:send'], ARRAY[]::text[],
|
|
90
|
+
(select code from agent_board.board_invite_tokens where created_by_agent_id='52100000-0000-0000-0000-000000000001'),
|
|
91
|
+
(select id from agent_board.boards where slug='tok521-board'),
|
|
92
|
+
'52100000-0000-0000-0000-000000000003', 'codex', 'phase-loop',
|
|
93
|
+
'message-board', 'sha256:tok521-repo', 'worker', 'phase_worker',
|
|
94
|
+
'tok521-agent'
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
step "fleet_commit" { COMMIT; }
|
|
98
|
+
|
|
99
|
+
session "ident"
|
|
100
|
+
step "ident_begin" { BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role'; }
|
|
101
|
+
step "ident_enroll" {
|
|
102
|
+
do $$ begin
|
|
103
|
+
perform agent_board.enroll_federated_identity(
|
|
104
|
+
'https://tok521-iso.test', 'message-board', 'tok521-human',
|
|
105
|
+
jsonb_build_object('iss','https://tok521-iso.test','aud','message-board','sub','tok521-human'),
|
|
106
|
+
'tok521-agent',
|
|
107
|
+
public.test_pubkey('tok521-k1'), 'raw_ed25519_base64url',
|
|
108
|
+
public.test_key_fingerprint('tok521-k1'),
|
|
109
|
+
true, repeat('a', 64), now() + interval '1 hour', null, 'agent',
|
|
110
|
+
ARRAY['board:send'], ARRAY[]::text[], null
|
|
111
|
+
);
|
|
112
|
+
exception when others then
|
|
113
|
+
raise exception 'SQLSTATE %: %', sqlstate, sqlerrm using errcode = sqlstate;
|
|
114
|
+
end $$;
|
|
115
|
+
}
|
|
116
|
+
step "ident_rollback" { ROLLBACK; }
|
|
117
|
+
|
|
118
|
+
session "check"
|
|
119
|
+
step "check" {
|
|
120
|
+
select
|
|
121
|
+
(select count(*) from agent_board.agents where handle like 'tok521-agent%') as agents,
|
|
122
|
+
(select count(*) from agent_board.agent_signing_keys where fingerprint = public.test_key_fingerprint('tok521-k1')) as k1_keys,
|
|
123
|
+
(select count(*) from agent_board.agent_signing_keys where fingerprint = public.test_key_fingerprint('tok521-k2')) as k2_keys,
|
|
124
|
+
(select count(*) from agent_board.enroll_token_uses) as token_rows,
|
|
125
|
+
(select case u.agent_public_key_fingerprint
|
|
126
|
+
when public.test_key_fingerprint('tok521-k1') then 'K1'
|
|
127
|
+
when public.test_key_fingerprint('tok521-k2') then 'K2'
|
|
128
|
+
else 'other' end
|
|
129
|
+
from agent_board.enroll_token_uses u where u.token_sha256 = repeat('a', 64)) as token_bound_to,
|
|
130
|
+
(select count(*) from agent_board.fleet_harness_registrations where machine_id='52100000-0000-0000-0000-000000000003') as harnesses,
|
|
131
|
+
(select count(*) from agent_board.fleet_repo_scopes r join agent_board.fleet_harness_registrations h on h.id = r.harness_registration_id
|
|
132
|
+
where h.machine_id='52100000-0000-0000-0000-000000000003') as repo_scopes,
|
|
133
|
+
(select count(*) from agent_board.fleet_machine_agents where machine_id='52100000-0000-0000-0000-000000000003') as bindings;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
permutation "guard_begin" "guard_lock" "fleet_begin" "fleet_onboard" "ident_begin" "ident_enroll" "guard_commit" "fleet_commit" "ident_rollback" "check"
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# Consiliency/message-board#521 I-2 -- a transaction that aborts AFTER binding strands
|
|
2
|
+
# nothing. A binds token T to K1 inside its enrollment and then ROLLS BACK; B, waiting at
|
|
3
|
+
# the owner lock with the same token and K2, then succeeds, and the token row names K2. No
|
|
4
|
+
# K1 key survives. The bind row is written inside the enrolling transaction, so it goes
|
|
5
|
+
# with it.
|
|
6
|
+
|
|
7
|
+
setup
|
|
8
|
+
{
|
|
9
|
+
insert into agent_board.identity_providers(
|
|
10
|
+
issuer, audience, supported, policy_approved,
|
|
11
|
+
allowed_scopes, allowed_board_scopes, allowed_agent_kinds
|
|
12
|
+
) values (
|
|
13
|
+
'https://tok521-iso.test', 'message-board', true, true,
|
|
14
|
+
ARRAY['board:send'], ARRAY[]::text[], ARRAY['agent']
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
-- Materialize the owner auth.users row the enrollment derives, through the SAME helper,
|
|
18
|
+
-- so a contender blocks on the owner row lock (the serialisation under test) and not on
|
|
19
|
+
-- a racing INSERT inside _ensure_agent_auth_user.
|
|
20
|
+
create table tok521_owner as
|
|
21
|
+
select agent_board._ensure_agent_auth_user(
|
|
22
|
+
agent_board._federated_identity_slug('https://tok521-iso.test', 'tok521-human')) as uid;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
session "a"
|
|
26
|
+
step "a_begin" { BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role'; }
|
|
27
|
+
step "a_enroll" {
|
|
28
|
+
select agent_handle
|
|
29
|
+
from agent_board.enroll_federated_identity(
|
|
30
|
+
'https://tok521-iso.test', 'message-board', 'tok521-human',
|
|
31
|
+
jsonb_build_object('iss','https://tok521-iso.test','aud','message-board','sub','tok521-human'),
|
|
32
|
+
'tok521-agent',
|
|
33
|
+
public.test_pubkey('tok521-k1'), 'raw_ed25519_base64url',
|
|
34
|
+
public.test_key_fingerprint('tok521-k1'),
|
|
35
|
+
true, repeat('a', 64), now() + interval '1 hour', null, 'agent',
|
|
36
|
+
ARRAY['board:send'], ARRAY[]::text[], null
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
step "a_rollback" { ROLLBACK; }
|
|
40
|
+
|
|
41
|
+
session "b"
|
|
42
|
+
step "b_begin" { BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role'; }
|
|
43
|
+
step "b_enroll" {
|
|
44
|
+
select agent_handle
|
|
45
|
+
from agent_board.enroll_federated_identity(
|
|
46
|
+
'https://tok521-iso.test', 'message-board', 'tok521-human',
|
|
47
|
+
jsonb_build_object('iss','https://tok521-iso.test','aud','message-board','sub','tok521-human'),
|
|
48
|
+
'tok521-agent',
|
|
49
|
+
public.test_pubkey('tok521-k2'), 'raw_ed25519_base64url',
|
|
50
|
+
public.test_key_fingerprint('tok521-k2'),
|
|
51
|
+
true, repeat('a', 64), now() + interval '1 hour', null, 'agent',
|
|
52
|
+
ARRAY['board:send'], ARRAY[]::text[], null
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
step "b_commit" { COMMIT; }
|
|
56
|
+
|
|
57
|
+
session "check"
|
|
58
|
+
step "check" {
|
|
59
|
+
select
|
|
60
|
+
(select count(*) from agent_board.agents where handle like 'tok521-agent%') as agents,
|
|
61
|
+
(select count(*) from agent_board.agent_signing_keys where fingerprint = public.test_key_fingerprint('tok521-k1')) as k1_keys,
|
|
62
|
+
(select count(*) from agent_board.agent_signing_keys where fingerprint = public.test_key_fingerprint('tok521-k2')) as k2_keys,
|
|
63
|
+
(select count(*) from agent_board.enroll_token_uses) as token_rows,
|
|
64
|
+
(select case u.agent_public_key_fingerprint
|
|
65
|
+
when public.test_key_fingerprint('tok521-k1') then 'K1'
|
|
66
|
+
when public.test_key_fingerprint('tok521-k2') then 'K2'
|
|
67
|
+
else 'other' end
|
|
68
|
+
from agent_board.enroll_token_uses u where u.token_sha256 = repeat('a', 64)) as token_bound_to;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
permutation "a_begin" "a_enroll" "b_begin" "b_enroll" "a_rollback" "b_commit" "check"
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# Consiliency/message-board#521 I-4b -- fleet route first, identity route second, same
|
|
2
|
+
# token, different keys. The identity enrollment blocks at the owner lock the fleet
|
|
3
|
+
# onboarding already holds; when the onboarding commits, the identity bind raises MBT01.
|
|
4
|
+
# One agent (the fleet one), one key, one binding. No deadlock.
|
|
5
|
+
#
|
|
6
|
+
# The step expected to FAIL runs inside a DO block that re-raises with the SQLSTATE in the
|
|
7
|
+
# message, because isolationtester prints only `ERROR: <message>`: without it a raise with
|
|
8
|
+
# the same text and a different errcode would leave this golden green.
|
|
9
|
+
|
|
10
|
+
setup
|
|
11
|
+
{
|
|
12
|
+
insert into agent_board.identity_providers(
|
|
13
|
+
issuer, audience, supported, policy_approved,
|
|
14
|
+
allowed_scopes, allowed_board_scopes, allowed_agent_kinds
|
|
15
|
+
) values (
|
|
16
|
+
'https://tok521-iso.test', 'message-board', true, true,
|
|
17
|
+
ARRAY['board:send'], ARRAY[]::text[], ARRAY['agent']
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
-- Materialize the owner auth.users row the enrollment derives, through the SAME helper,
|
|
21
|
+
-- so a contender blocks on the owner row lock (the serialisation under test) and not on
|
|
22
|
+
-- a racing INSERT inside _ensure_agent_auth_user.
|
|
23
|
+
create table tok521_owner as
|
|
24
|
+
select agent_board._ensure_agent_auth_user(
|
|
25
|
+
agent_board._federated_identity_slug('https://tok521-iso.test', 'tok521-human')) as uid;
|
|
26
|
+
|
|
27
|
+
insert into agent_board.agents(id, agent_type, kind, handle, display_name, status)
|
|
28
|
+
values ('52100000-0000-0000-0000-000000000001', 'agent', 'agent',
|
|
29
|
+
'tok521-creator', 'Tok521 Creator', 'active');
|
|
30
|
+
select count(*) from agent_board.create_board(
|
|
31
|
+
'52100000-0000-0000-0000-000000000001',
|
|
32
|
+
'tok521-board', 'Tok521 Board',
|
|
33
|
+
'Consiliency/message-board#521 token single-use isolation proof',
|
|
34
|
+
jsonb_build_object(), 'private'
|
|
35
|
+
);
|
|
36
|
+
insert into agent_board.fleet_trust_domains(
|
|
37
|
+
id, slug, display_name, domain_kind, owner_agent_id, lifecycle_state, approved_at
|
|
38
|
+
) values (
|
|
39
|
+
'52100000-0000-0000-0000-000000000002', 'tok521-domain',
|
|
40
|
+
'Tok521 Domain', 'tailnet', '52100000-0000-0000-0000-000000000001',
|
|
41
|
+
'active', now()
|
|
42
|
+
);
|
|
43
|
+
insert into agent_board.fleet_machines(
|
|
44
|
+
id, trust_domain_id, owner_agent_id, machine_label, machine_fingerprint,
|
|
45
|
+
lifecycle_state, enrollment_source, enrolled_at
|
|
46
|
+
) values (
|
|
47
|
+
'52100000-0000-0000-0000-000000000003',
|
|
48
|
+
'52100000-0000-0000-0000-000000000002',
|
|
49
|
+
'52100000-0000-0000-0000-000000000001',
|
|
50
|
+
'claw', 'sha256:tok521-machine', 'active', 'portal', now()
|
|
51
|
+
);
|
|
52
|
+
select count(*) from agent_board.create_fleet_onboarding_invite(
|
|
53
|
+
(select id from agent_board.boards where slug='tok521-board'),
|
|
54
|
+
'52100000-0000-0000-0000-000000000003', 'codex', 'phase-loop',
|
|
55
|
+
'message-board', 'sha256:tok521-repo', 'worker', 'phase_worker',
|
|
56
|
+
'tok521-agent', 2, now() + interval '1 hour',
|
|
57
|
+
'52100000-0000-0000-0000-000000000001', jsonb_build_object()
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
session "fleet"
|
|
62
|
+
step "fleet_begin" { BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role'; }
|
|
63
|
+
step "fleet_onboard" {
|
|
64
|
+
select agent_handle, identity_disposition
|
|
65
|
+
from agent_board.onboard_federated_fleet_agent(
|
|
66
|
+
'https://tok521-iso.test', 'message-board', 'tok521-human',
|
|
67
|
+
jsonb_build_object('iss','https://tok521-iso.test','aud','message-board','sub','tok521-human'),
|
|
68
|
+
'tok521-agent',
|
|
69
|
+
public.test_pubkey('tok521-k1'), 'raw_ed25519_base64url',
|
|
70
|
+
public.test_key_fingerprint('tok521-k1'),
|
|
71
|
+
true, repeat('a', 64), now() + interval '1 hour', null, 'agent',
|
|
72
|
+
ARRAY['board:send'], ARRAY[]::text[],
|
|
73
|
+
(select code from agent_board.board_invite_tokens where created_by_agent_id='52100000-0000-0000-0000-000000000001'),
|
|
74
|
+
(select id from agent_board.boards where slug='tok521-board'),
|
|
75
|
+
'52100000-0000-0000-0000-000000000003', 'codex', 'phase-loop',
|
|
76
|
+
'message-board', 'sha256:tok521-repo', 'worker', 'phase_worker',
|
|
77
|
+
'tok521-agent'
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
step "fleet_commit" { COMMIT; }
|
|
81
|
+
|
|
82
|
+
session "ident"
|
|
83
|
+
step "ident_begin" { BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role'; }
|
|
84
|
+
step "ident_enroll" {
|
|
85
|
+
do $$ begin
|
|
86
|
+
perform agent_board.enroll_federated_identity(
|
|
87
|
+
'https://tok521-iso.test', 'message-board', 'tok521-human',
|
|
88
|
+
jsonb_build_object('iss','https://tok521-iso.test','aud','message-board','sub','tok521-human'),
|
|
89
|
+
'tok521-agent',
|
|
90
|
+
public.test_pubkey('tok521-k2'), 'raw_ed25519_base64url',
|
|
91
|
+
public.test_key_fingerprint('tok521-k2'),
|
|
92
|
+
true, repeat('a', 64), now() + interval '1 hour', null, 'agent',
|
|
93
|
+
ARRAY['board:send'], ARRAY[]::text[], null
|
|
94
|
+
);
|
|
95
|
+
exception when others then
|
|
96
|
+
raise exception 'SQLSTATE %: %', sqlstate, sqlerrm using errcode = sqlstate;
|
|
97
|
+
end $$;
|
|
98
|
+
}
|
|
99
|
+
step "ident_rollback" { ROLLBACK; }
|
|
100
|
+
|
|
101
|
+
session "check"
|
|
102
|
+
step "check" {
|
|
103
|
+
select
|
|
104
|
+
(select count(*) from agent_board.agents where handle like 'tok521-agent%') as agents,
|
|
105
|
+
(select count(*) from agent_board.agent_signing_keys where fingerprint = public.test_key_fingerprint('tok521-k1')) as k1_keys,
|
|
106
|
+
(select count(*) from agent_board.agent_signing_keys where fingerprint = public.test_key_fingerprint('tok521-k2')) as k2_keys,
|
|
107
|
+
(select count(*) from agent_board.enroll_token_uses) as token_rows,
|
|
108
|
+
(select case u.agent_public_key_fingerprint
|
|
109
|
+
when public.test_key_fingerprint('tok521-k1') then 'K1'
|
|
110
|
+
when public.test_key_fingerprint('tok521-k2') then 'K2'
|
|
111
|
+
else 'other' end
|
|
112
|
+
from agent_board.enroll_token_uses u where u.token_sha256 = repeat('a', 64)) as token_bound_to,
|
|
113
|
+
(select count(*) from agent_board.fleet_harness_registrations where machine_id='52100000-0000-0000-0000-000000000003') as harnesses,
|
|
114
|
+
(select count(*) from agent_board.fleet_repo_scopes r join agent_board.fleet_harness_registrations h on h.id = r.harness_registration_id
|
|
115
|
+
where h.machine_id='52100000-0000-0000-0000-000000000003') as repo_scopes,
|
|
116
|
+
(select count(*) from agent_board.fleet_machine_agents where machine_id='52100000-0000-0000-0000-000000000003') as bindings;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
permutation "fleet_begin" "fleet_onboard" "ident_begin" "ident_enroll" "fleet_commit" "ident_rollback" "check"
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# Consiliency/message-board#521 I-4a -- identity route first, fleet route second, same
|
|
2
|
+
# token, different keys. The fleet onboarding blocks at its own owner lock (taken before
|
|
3
|
+
# its nested enroll_federated_identity call); when the identity enrollment commits, the
|
|
4
|
+
# nested bind raises MBT01 and the WHOLE onboarding rolls back: no K2 key, no harness,
|
|
5
|
+
# repo scope or binding rows. No deadlock, in this order or the other (I-4b).
|
|
6
|
+
#
|
|
7
|
+
# The step expected to FAIL runs inside a DO block that re-raises with the SQLSTATE in the
|
|
8
|
+
# message, because isolationtester prints only `ERROR: <message>`: without it a raise with
|
|
9
|
+
# the same text and a different errcode would leave this golden green.
|
|
10
|
+
|
|
11
|
+
setup
|
|
12
|
+
{
|
|
13
|
+
insert into agent_board.identity_providers(
|
|
14
|
+
issuer, audience, supported, policy_approved,
|
|
15
|
+
allowed_scopes, allowed_board_scopes, allowed_agent_kinds
|
|
16
|
+
) values (
|
|
17
|
+
'https://tok521-iso.test', 'message-board', true, true,
|
|
18
|
+
ARRAY['board:send'], ARRAY[]::text[], ARRAY['agent']
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
-- Materialize the owner auth.users row the enrollment derives, through the SAME helper,
|
|
22
|
+
-- so a contender blocks on the owner row lock (the serialisation under test) and not on
|
|
23
|
+
-- a racing INSERT inside _ensure_agent_auth_user.
|
|
24
|
+
create table tok521_owner as
|
|
25
|
+
select agent_board._ensure_agent_auth_user(
|
|
26
|
+
agent_board._federated_identity_slug('https://tok521-iso.test', 'tok521-human')) as uid;
|
|
27
|
+
|
|
28
|
+
insert into agent_board.agents(id, agent_type, kind, handle, display_name, status)
|
|
29
|
+
values ('52100000-0000-0000-0000-000000000001', 'agent', 'agent',
|
|
30
|
+
'tok521-creator', 'Tok521 Creator', 'active');
|
|
31
|
+
select count(*) from agent_board.create_board(
|
|
32
|
+
'52100000-0000-0000-0000-000000000001',
|
|
33
|
+
'tok521-board', 'Tok521 Board',
|
|
34
|
+
'Consiliency/message-board#521 token single-use isolation proof',
|
|
35
|
+
jsonb_build_object(), 'private'
|
|
36
|
+
);
|
|
37
|
+
insert into agent_board.fleet_trust_domains(
|
|
38
|
+
id, slug, display_name, domain_kind, owner_agent_id, lifecycle_state, approved_at
|
|
39
|
+
) values (
|
|
40
|
+
'52100000-0000-0000-0000-000000000002', 'tok521-domain',
|
|
41
|
+
'Tok521 Domain', 'tailnet', '52100000-0000-0000-0000-000000000001',
|
|
42
|
+
'active', now()
|
|
43
|
+
);
|
|
44
|
+
insert into agent_board.fleet_machines(
|
|
45
|
+
id, trust_domain_id, owner_agent_id, machine_label, machine_fingerprint,
|
|
46
|
+
lifecycle_state, enrollment_source, enrolled_at
|
|
47
|
+
) values (
|
|
48
|
+
'52100000-0000-0000-0000-000000000003',
|
|
49
|
+
'52100000-0000-0000-0000-000000000002',
|
|
50
|
+
'52100000-0000-0000-0000-000000000001',
|
|
51
|
+
'claw', 'sha256:tok521-machine', 'active', 'portal', now()
|
|
52
|
+
);
|
|
53
|
+
select count(*) from agent_board.create_fleet_onboarding_invite(
|
|
54
|
+
(select id from agent_board.boards where slug='tok521-board'),
|
|
55
|
+
'52100000-0000-0000-0000-000000000003', 'codex', 'phase-loop',
|
|
56
|
+
'message-board', 'sha256:tok521-repo', 'worker', 'phase_worker',
|
|
57
|
+
'tok521-agent', 2, now() + interval '1 hour',
|
|
58
|
+
'52100000-0000-0000-0000-000000000001', jsonb_build_object()
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
session "ident"
|
|
63
|
+
step "ident_begin" { BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role'; }
|
|
64
|
+
step "ident_enroll" {
|
|
65
|
+
select agent_handle
|
|
66
|
+
from agent_board.enroll_federated_identity(
|
|
67
|
+
'https://tok521-iso.test', 'message-board', 'tok521-human',
|
|
68
|
+
jsonb_build_object('iss','https://tok521-iso.test','aud','message-board','sub','tok521-human'),
|
|
69
|
+
'tok521-agent',
|
|
70
|
+
public.test_pubkey('tok521-k1'), 'raw_ed25519_base64url',
|
|
71
|
+
public.test_key_fingerprint('tok521-k1'),
|
|
72
|
+
true, repeat('a', 64), now() + interval '1 hour', null, 'agent',
|
|
73
|
+
ARRAY['board:send'], ARRAY[]::text[], null
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
step "ident_commit" { COMMIT; }
|
|
77
|
+
|
|
78
|
+
session "fleet"
|
|
79
|
+
step "fleet_begin" { BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role'; }
|
|
80
|
+
step "fleet_onboard" {
|
|
81
|
+
do $$ begin
|
|
82
|
+
perform agent_board.onboard_federated_fleet_agent(
|
|
83
|
+
'https://tok521-iso.test', 'message-board', 'tok521-human',
|
|
84
|
+
jsonb_build_object('iss','https://tok521-iso.test','aud','message-board','sub','tok521-human'),
|
|
85
|
+
'tok521-agent',
|
|
86
|
+
public.test_pubkey('tok521-k2'), 'raw_ed25519_base64url',
|
|
87
|
+
public.test_key_fingerprint('tok521-k2'),
|
|
88
|
+
true, repeat('a', 64), now() + interval '1 hour', null, 'agent',
|
|
89
|
+
ARRAY['board:send'], ARRAY[]::text[],
|
|
90
|
+
(select code from agent_board.board_invite_tokens where created_by_agent_id='52100000-0000-0000-0000-000000000001'),
|
|
91
|
+
(select id from agent_board.boards where slug='tok521-board'),
|
|
92
|
+
'52100000-0000-0000-0000-000000000003', 'codex', 'phase-loop',
|
|
93
|
+
'message-board', 'sha256:tok521-repo', 'worker', 'phase_worker',
|
|
94
|
+
'tok521-agent'
|
|
95
|
+
);
|
|
96
|
+
exception when others then
|
|
97
|
+
raise exception 'SQLSTATE %: %', sqlstate, sqlerrm using errcode = sqlstate;
|
|
98
|
+
end $$;
|
|
99
|
+
}
|
|
100
|
+
step "fleet_rollback" { ROLLBACK; }
|
|
101
|
+
|
|
102
|
+
session "check"
|
|
103
|
+
step "check" {
|
|
104
|
+
select
|
|
105
|
+
(select count(*) from agent_board.agents where handle like 'tok521-agent%') as agents,
|
|
106
|
+
(select count(*) from agent_board.agent_signing_keys where fingerprint = public.test_key_fingerprint('tok521-k1')) as k1_keys,
|
|
107
|
+
(select count(*) from agent_board.agent_signing_keys where fingerprint = public.test_key_fingerprint('tok521-k2')) as k2_keys,
|
|
108
|
+
(select count(*) from agent_board.enroll_token_uses) as token_rows,
|
|
109
|
+
(select case u.agent_public_key_fingerprint
|
|
110
|
+
when public.test_key_fingerprint('tok521-k1') then 'K1'
|
|
111
|
+
when public.test_key_fingerprint('tok521-k2') then 'K2'
|
|
112
|
+
else 'other' end
|
|
113
|
+
from agent_board.enroll_token_uses u where u.token_sha256 = repeat('a', 64)) as token_bound_to,
|
|
114
|
+
(select count(*) from agent_board.fleet_harness_registrations where machine_id='52100000-0000-0000-0000-000000000003') as harnesses,
|
|
115
|
+
(select count(*) from agent_board.fleet_repo_scopes r join agent_board.fleet_harness_registrations h on h.id = r.harness_registration_id
|
|
116
|
+
where h.machine_id='52100000-0000-0000-0000-000000000003') as repo_scopes,
|
|
117
|
+
(select count(*) from agent_board.fleet_machine_agents where machine_id='52100000-0000-0000-0000-000000000003') as bindings;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
permutation "ident_begin" "ident_enroll" "fleet_begin" "fleet_onboard" "ident_commit" "fleet_rollback" "check"
|