@consiliency/agent-board-schema 1.54.0 → 1.55.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 +4 -0
- package/migrations/20261005000100_agent_board_enroll_token_single_use.sql +886 -0
- package/package.json +1 -1
- package/schema-manifest.json +12 -3
- package/src/tooling.test.mjs +4 -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_portal_offline_invariant.test.sql +1 -1
- package/tests/agent_board_roomlink.test.sql +2 -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,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"
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# Consiliency/message-board#521 I-8b -- the same token and the SAME key across routes,
|
|
2
|
+
# fleet first. The identity enrollment waits (at the fingerprint advisory lock), then its
|
|
3
|
+
# bind is a no-op and it resumes the fleet-created identity: same handle, no MBT01, no
|
|
4
|
+
# second key, no second agent.
|
|
5
|
+
|
|
6
|
+
setup
|
|
7
|
+
{
|
|
8
|
+
insert into agent_board.identity_providers(
|
|
9
|
+
issuer, audience, supported, policy_approved,
|
|
10
|
+
allowed_scopes, allowed_board_scopes, allowed_agent_kinds
|
|
11
|
+
) values (
|
|
12
|
+
'https://tok521-iso.test', 'message-board', true, true,
|
|
13
|
+
ARRAY['board:send'], ARRAY[]::text[], ARRAY['agent']
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
-- Materialize the owner auth.users row the enrollment derives, through the SAME helper,
|
|
17
|
+
-- so a contender blocks on the owner row lock (the serialisation under test) and not on
|
|
18
|
+
-- a racing INSERT inside _ensure_agent_auth_user.
|
|
19
|
+
create table tok521_owner as
|
|
20
|
+
select agent_board._ensure_agent_auth_user(
|
|
21
|
+
agent_board._federated_identity_slug('https://tok521-iso.test', 'tok521-human')) as uid;
|
|
22
|
+
|
|
23
|
+
insert into agent_board.agents(id, agent_type, kind, handle, display_name, status)
|
|
24
|
+
values ('52100000-0000-0000-0000-000000000001', 'agent', 'agent',
|
|
25
|
+
'tok521-creator', 'Tok521 Creator', 'active');
|
|
26
|
+
select count(*) from agent_board.create_board(
|
|
27
|
+
'52100000-0000-0000-0000-000000000001',
|
|
28
|
+
'tok521-board', 'Tok521 Board',
|
|
29
|
+
'Consiliency/message-board#521 token single-use isolation proof',
|
|
30
|
+
jsonb_build_object(), 'private'
|
|
31
|
+
);
|
|
32
|
+
insert into agent_board.fleet_trust_domains(
|
|
33
|
+
id, slug, display_name, domain_kind, owner_agent_id, lifecycle_state, approved_at
|
|
34
|
+
) values (
|
|
35
|
+
'52100000-0000-0000-0000-000000000002', 'tok521-domain',
|
|
36
|
+
'Tok521 Domain', 'tailnet', '52100000-0000-0000-0000-000000000001',
|
|
37
|
+
'active', now()
|
|
38
|
+
);
|
|
39
|
+
insert into agent_board.fleet_machines(
|
|
40
|
+
id, trust_domain_id, owner_agent_id, machine_label, machine_fingerprint,
|
|
41
|
+
lifecycle_state, enrollment_source, enrolled_at
|
|
42
|
+
) values (
|
|
43
|
+
'52100000-0000-0000-0000-000000000003',
|
|
44
|
+
'52100000-0000-0000-0000-000000000002',
|
|
45
|
+
'52100000-0000-0000-0000-000000000001',
|
|
46
|
+
'claw', 'sha256:tok521-machine', 'active', 'portal', now()
|
|
47
|
+
);
|
|
48
|
+
select count(*) from agent_board.create_fleet_onboarding_invite(
|
|
49
|
+
(select id from agent_board.boards where slug='tok521-board'),
|
|
50
|
+
'52100000-0000-0000-0000-000000000003', 'codex', 'phase-loop',
|
|
51
|
+
'message-board', 'sha256:tok521-repo', 'worker', 'phase_worker',
|
|
52
|
+
'tok521-agent', 2, now() + interval '1 hour',
|
|
53
|
+
'52100000-0000-0000-0000-000000000001', jsonb_build_object()
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
session "fleet"
|
|
58
|
+
step "fleet_begin" { BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role'; }
|
|
59
|
+
step "fleet_onboard" {
|
|
60
|
+
select agent_handle, identity_disposition
|
|
61
|
+
from agent_board.onboard_federated_fleet_agent(
|
|
62
|
+
'https://tok521-iso.test', 'message-board', 'tok521-human',
|
|
63
|
+
jsonb_build_object('iss','https://tok521-iso.test','aud','message-board','sub','tok521-human'),
|
|
64
|
+
'tok521-agent',
|
|
65
|
+
public.test_pubkey('tok521-k1'), 'raw_ed25519_base64url',
|
|
66
|
+
public.test_key_fingerprint('tok521-k1'),
|
|
67
|
+
true, repeat('a', 64), now() + interval '1 hour', null, 'agent',
|
|
68
|
+
ARRAY['board:send'], ARRAY[]::text[],
|
|
69
|
+
(select code from agent_board.board_invite_tokens where created_by_agent_id='52100000-0000-0000-0000-000000000001'),
|
|
70
|
+
(select id from agent_board.boards where slug='tok521-board'),
|
|
71
|
+
'52100000-0000-0000-0000-000000000003', 'codex', 'phase-loop',
|
|
72
|
+
'message-board', 'sha256:tok521-repo', 'worker', 'phase_worker',
|
|
73
|
+
'tok521-agent'
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
step "fleet_commit" { COMMIT; }
|
|
77
|
+
|
|
78
|
+
session "ident"
|
|
79
|
+
step "ident_begin" { BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role'; }
|
|
80
|
+
step "ident_enroll" {
|
|
81
|
+
select agent_handle
|
|
82
|
+
from agent_board.enroll_federated_identity(
|
|
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-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[], null
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
step "ident_commit" { COMMIT; }
|
|
93
|
+
|
|
94
|
+
session "check"
|
|
95
|
+
step "check" {
|
|
96
|
+
select
|
|
97
|
+
(select count(*) from agent_board.agents where handle like 'tok521-agent%') as agents,
|
|
98
|
+
(select count(*) from agent_board.agent_signing_keys where fingerprint = public.test_key_fingerprint('tok521-k1')) as k1_keys,
|
|
99
|
+
(select count(*) from agent_board.agent_signing_keys where fingerprint = public.test_key_fingerprint('tok521-k2')) as k2_keys,
|
|
100
|
+
(select count(*) from agent_board.enroll_token_uses) as token_rows,
|
|
101
|
+
(select case u.agent_public_key_fingerprint
|
|
102
|
+
when public.test_key_fingerprint('tok521-k1') then 'K1'
|
|
103
|
+
when public.test_key_fingerprint('tok521-k2') then 'K2'
|
|
104
|
+
else 'other' end
|
|
105
|
+
from agent_board.enroll_token_uses u where u.token_sha256 = repeat('a', 64)) as token_bound_to,
|
|
106
|
+
(select count(*) from agent_board.fleet_harness_registrations where machine_id='52100000-0000-0000-0000-000000000003') as harnesses,
|
|
107
|
+
(select count(*) from agent_board.fleet_repo_scopes r join agent_board.fleet_harness_registrations h on h.id = r.harness_registration_id
|
|
108
|
+
where h.machine_id='52100000-0000-0000-0000-000000000003') as repo_scopes,
|
|
109
|
+
(select count(*) from agent_board.fleet_machine_agents where machine_id='52100000-0000-0000-0000-000000000003') as bindings;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
permutation "fleet_begin" "fleet_onboard" "ident_begin" "ident_enroll" "fleet_commit" "ident_commit" "check"
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# Consiliency/message-board#521 I-8a -- the same token and the SAME key across routes,
|
|
2
|
+
# identity first. The fleet onboarding waits (at the fingerprint advisory lock), then its
|
|
3
|
+
# nested call's bind is a no-op and it falls through into the unchanged resumption:
|
|
4
|
+
# identity_disposition = reused, no MBT01, no second key, no second agent -- exactly what
|
|
5
|
+
# the same-key retry got before #521.
|
|
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
|
+
insert into agent_board.agents(id, agent_type, kind, handle, display_name, status)
|
|
25
|
+
values ('52100000-0000-0000-0000-000000000001', 'agent', 'agent',
|
|
26
|
+
'tok521-creator', 'Tok521 Creator', 'active');
|
|
27
|
+
select count(*) from agent_board.create_board(
|
|
28
|
+
'52100000-0000-0000-0000-000000000001',
|
|
29
|
+
'tok521-board', 'Tok521 Board',
|
|
30
|
+
'Consiliency/message-board#521 token single-use isolation proof',
|
|
31
|
+
jsonb_build_object(), 'private'
|
|
32
|
+
);
|
|
33
|
+
insert into agent_board.fleet_trust_domains(
|
|
34
|
+
id, slug, display_name, domain_kind, owner_agent_id, lifecycle_state, approved_at
|
|
35
|
+
) values (
|
|
36
|
+
'52100000-0000-0000-0000-000000000002', 'tok521-domain',
|
|
37
|
+
'Tok521 Domain', 'tailnet', '52100000-0000-0000-0000-000000000001',
|
|
38
|
+
'active', now()
|
|
39
|
+
);
|
|
40
|
+
insert into agent_board.fleet_machines(
|
|
41
|
+
id, trust_domain_id, owner_agent_id, machine_label, machine_fingerprint,
|
|
42
|
+
lifecycle_state, enrollment_source, enrolled_at
|
|
43
|
+
) values (
|
|
44
|
+
'52100000-0000-0000-0000-000000000003',
|
|
45
|
+
'52100000-0000-0000-0000-000000000002',
|
|
46
|
+
'52100000-0000-0000-0000-000000000001',
|
|
47
|
+
'claw', 'sha256:tok521-machine', 'active', 'portal', now()
|
|
48
|
+
);
|
|
49
|
+
select count(*) from agent_board.create_fleet_onboarding_invite(
|
|
50
|
+
(select id from agent_board.boards where slug='tok521-board'),
|
|
51
|
+
'52100000-0000-0000-0000-000000000003', 'codex', 'phase-loop',
|
|
52
|
+
'message-board', 'sha256:tok521-repo', 'worker', 'phase_worker',
|
|
53
|
+
'tok521-agent', 2, now() + interval '1 hour',
|
|
54
|
+
'52100000-0000-0000-0000-000000000001', jsonb_build_object()
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
session "ident"
|
|
59
|
+
step "ident_begin" { BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role'; }
|
|
60
|
+
step "ident_enroll" {
|
|
61
|
+
select agent_handle
|
|
62
|
+
from agent_board.enroll_federated_identity(
|
|
63
|
+
'https://tok521-iso.test', 'message-board', 'tok521-human',
|
|
64
|
+
jsonb_build_object('iss','https://tok521-iso.test','aud','message-board','sub','tok521-human'),
|
|
65
|
+
'tok521-agent',
|
|
66
|
+
public.test_pubkey('tok521-k1'), 'raw_ed25519_base64url',
|
|
67
|
+
public.test_key_fingerprint('tok521-k1'),
|
|
68
|
+
true, repeat('a', 64), now() + interval '1 hour', null, 'agent',
|
|
69
|
+
ARRAY['board:send'], ARRAY[]::text[], null
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
step "ident_commit" { COMMIT; }
|
|
73
|
+
|
|
74
|
+
session "fleet"
|
|
75
|
+
step "fleet_begin" { BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role'; }
|
|
76
|
+
step "fleet_onboard" {
|
|
77
|
+
select agent_handle, identity_disposition
|
|
78
|
+
from agent_board.onboard_federated_fleet_agent(
|
|
79
|
+
'https://tok521-iso.test', 'message-board', 'tok521-human',
|
|
80
|
+
jsonb_build_object('iss','https://tok521-iso.test','aud','message-board','sub','tok521-human'),
|
|
81
|
+
'tok521-agent',
|
|
82
|
+
public.test_pubkey('tok521-k1'), 'raw_ed25519_base64url',
|
|
83
|
+
public.test_key_fingerprint('tok521-k1'),
|
|
84
|
+
true, repeat('a', 64), now() + interval '1 hour', null, 'agent',
|
|
85
|
+
ARRAY['board:send'], ARRAY[]::text[],
|
|
86
|
+
(select code from agent_board.board_invite_tokens where created_by_agent_id='52100000-0000-0000-0000-000000000001'),
|
|
87
|
+
(select id from agent_board.boards where slug='tok521-board'),
|
|
88
|
+
'52100000-0000-0000-0000-000000000003', 'codex', 'phase-loop',
|
|
89
|
+
'message-board', 'sha256:tok521-repo', 'worker', 'phase_worker',
|
|
90
|
+
'tok521-agent'
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
step "fleet_commit" { COMMIT; }
|
|
94
|
+
|
|
95
|
+
session "check"
|
|
96
|
+
step "check" {
|
|
97
|
+
select
|
|
98
|
+
(select count(*) from agent_board.agents where handle like 'tok521-agent%') as agents,
|
|
99
|
+
(select count(*) from agent_board.agent_signing_keys where fingerprint = public.test_key_fingerprint('tok521-k1')) as k1_keys,
|
|
100
|
+
(select count(*) from agent_board.agent_signing_keys where fingerprint = public.test_key_fingerprint('tok521-k2')) as k2_keys,
|
|
101
|
+
(select count(*) from agent_board.enroll_token_uses) as token_rows,
|
|
102
|
+
(select case u.agent_public_key_fingerprint
|
|
103
|
+
when public.test_key_fingerprint('tok521-k1') then 'K1'
|
|
104
|
+
when public.test_key_fingerprint('tok521-k2') then 'K2'
|
|
105
|
+
else 'other' end
|
|
106
|
+
from agent_board.enroll_token_uses u where u.token_sha256 = repeat('a', 64)) as token_bound_to,
|
|
107
|
+
(select count(*) from agent_board.fleet_harness_registrations where machine_id='52100000-0000-0000-0000-000000000003') as harnesses,
|
|
108
|
+
(select count(*) from agent_board.fleet_repo_scopes r join agent_board.fleet_harness_registrations h on h.id = r.harness_registration_id
|
|
109
|
+
where h.machine_id='52100000-0000-0000-0000-000000000003') as repo_scopes,
|
|
110
|
+
(select count(*) from agent_board.fleet_machine_agents where machine_id='52100000-0000-0000-0000-000000000003') as bindings;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
permutation "ident_begin" "ident_enroll" "fleet_begin" "fleet_onboard" "ident_commit" "fleet_commit" "check"
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Consiliency/message-board#521 I-3 -- the same token with the SAME key, concurrently: a
|
|
2
|
+
# retry. B blocks (at the fingerprint advisory lock, which precedes the owner lock), and
|
|
3
|
+
# when A commits, B's bind is a no-op and B falls through into the unchanged #176
|
|
4
|
+
# resumption, returning the same handle. One agent, one key, one token row.
|
|
5
|
+
|
|
6
|
+
setup
|
|
7
|
+
{
|
|
8
|
+
insert into agent_board.identity_providers(
|
|
9
|
+
issuer, audience, supported, policy_approved,
|
|
10
|
+
allowed_scopes, allowed_board_scopes, allowed_agent_kinds
|
|
11
|
+
) values (
|
|
12
|
+
'https://tok521-iso.test', 'message-board', true, true,
|
|
13
|
+
ARRAY['board:send'], ARRAY[]::text[], ARRAY['agent']
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
-- Materialize the owner auth.users row the enrollment derives, through the SAME helper,
|
|
17
|
+
-- so a contender blocks on the owner row lock (the serialisation under test) and not on
|
|
18
|
+
-- a racing INSERT inside _ensure_agent_auth_user.
|
|
19
|
+
create table tok521_owner as
|
|
20
|
+
select agent_board._ensure_agent_auth_user(
|
|
21
|
+
agent_board._federated_identity_slug('https://tok521-iso.test', 'tok521-human')) as uid;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
session "a"
|
|
25
|
+
step "a_begin" { BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role'; }
|
|
26
|
+
step "a_enroll" {
|
|
27
|
+
select agent_handle
|
|
28
|
+
from agent_board.enroll_federated_identity(
|
|
29
|
+
'https://tok521-iso.test', 'message-board', 'tok521-human',
|
|
30
|
+
jsonb_build_object('iss','https://tok521-iso.test','aud','message-board','sub','tok521-human'),
|
|
31
|
+
'tok521-agent',
|
|
32
|
+
public.test_pubkey('tok521-k1'), 'raw_ed25519_base64url',
|
|
33
|
+
public.test_key_fingerprint('tok521-k1'),
|
|
34
|
+
true, repeat('a', 64), now() + interval '1 hour', null, 'agent',
|
|
35
|
+
ARRAY['board:send'], ARRAY[]::text[], null
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
step "a_commit" { COMMIT; }
|
|
39
|
+
|
|
40
|
+
session "b"
|
|
41
|
+
step "b_begin" { BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role'; }
|
|
42
|
+
step "b_enroll" {
|
|
43
|
+
select agent_handle
|
|
44
|
+
from agent_board.enroll_federated_identity(
|
|
45
|
+
'https://tok521-iso.test', 'message-board', 'tok521-human',
|
|
46
|
+
jsonb_build_object('iss','https://tok521-iso.test','aud','message-board','sub','tok521-human'),
|
|
47
|
+
'tok521-agent',
|
|
48
|
+
public.test_pubkey('tok521-k1'), 'raw_ed25519_base64url',
|
|
49
|
+
public.test_key_fingerprint('tok521-k1'),
|
|
50
|
+
true, repeat('a', 64), now() + interval '1 hour', null, 'agent',
|
|
51
|
+
ARRAY['board:send'], ARRAY[]::text[], null
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
step "b_commit" { COMMIT; }
|
|
55
|
+
|
|
56
|
+
session "check"
|
|
57
|
+
step "check" {
|
|
58
|
+
select
|
|
59
|
+
(select count(*) from agent_board.agents where handle like 'tok521-agent%') as agents,
|
|
60
|
+
(select count(*) from agent_board.agent_signing_keys where fingerprint = public.test_key_fingerprint('tok521-k1')) as k1_keys,
|
|
61
|
+
(select count(*) from agent_board.agent_signing_keys where fingerprint = public.test_key_fingerprint('tok521-k2')) as k2_keys,
|
|
62
|
+
(select count(*) from agent_board.enroll_token_uses) as token_rows,
|
|
63
|
+
(select case u.agent_public_key_fingerprint
|
|
64
|
+
when public.test_key_fingerprint('tok521-k1') then 'K1'
|
|
65
|
+
when public.test_key_fingerprint('tok521-k2') then 'K2'
|
|
66
|
+
else 'other' end
|
|
67
|
+
from agent_board.enroll_token_uses u where u.token_sha256 = repeat('a', 64)) as token_bound_to;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
permutation "a_begin" "a_enroll" "b_begin" "b_enroll" "a_commit" "b_commit" "check"
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# Consiliency/message-board#521 I-1 -- one verified token, two keys, concurrently, on the
|
|
2
|
+
# identity route. A holds the token's derived owner row (it has not committed); B presents
|
|
3
|
+
# the SAME token with a DIFFERENT key and blocks at enroll_federated_identity's owner lock,
|
|
4
|
+
# which is the serialisation the bind relies on (no lock of its own). When A commits, B's
|
|
5
|
+
# bind reads A's committed row and raises MBT01. Exactly one agent, one key, one token row.
|
|
6
|
+
#
|
|
7
|
+
# The token is fixed (repeat('a',64)) so both sessions present the same token_sha256.
|
|
8
|
+
#
|
|
9
|
+
# The step expected to FAIL runs inside a DO block that re-raises with the SQLSTATE in the
|
|
10
|
+
# message, because isolationtester prints only `ERROR: <message>`: without it a raise with
|
|
11
|
+
# the same text and a different errcode would leave this golden green.
|
|
12
|
+
|
|
13
|
+
setup
|
|
14
|
+
{
|
|
15
|
+
insert into agent_board.identity_providers(
|
|
16
|
+
issuer, audience, supported, policy_approved,
|
|
17
|
+
allowed_scopes, allowed_board_scopes, allowed_agent_kinds
|
|
18
|
+
) values (
|
|
19
|
+
'https://tok521-iso.test', 'message-board', true, true,
|
|
20
|
+
ARRAY['board:send'], ARRAY[]::text[], ARRAY['agent']
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
-- Materialize the owner auth.users row the enrollment derives, through the SAME helper,
|
|
24
|
+
-- so a contender blocks on the owner row lock (the serialisation under test) and not on
|
|
25
|
+
-- a racing INSERT inside _ensure_agent_auth_user.
|
|
26
|
+
create table tok521_owner as
|
|
27
|
+
select agent_board._ensure_agent_auth_user(
|
|
28
|
+
agent_board._federated_identity_slug('https://tok521-iso.test', 'tok521-human')) as uid;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
session "a"
|
|
32
|
+
step "a_begin" { BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role'; }
|
|
33
|
+
step "a_enroll" {
|
|
34
|
+
select agent_handle
|
|
35
|
+
from agent_board.enroll_federated_identity(
|
|
36
|
+
'https://tok521-iso.test', 'message-board', 'tok521-human',
|
|
37
|
+
jsonb_build_object('iss','https://tok521-iso.test','aud','message-board','sub','tok521-human'),
|
|
38
|
+
'tok521-agent',
|
|
39
|
+
public.test_pubkey('tok521-k1'), 'raw_ed25519_base64url',
|
|
40
|
+
public.test_key_fingerprint('tok521-k1'),
|
|
41
|
+
true, repeat('a', 64), now() + interval '1 hour', null, 'agent',
|
|
42
|
+
ARRAY['board:send'], ARRAY[]::text[], null
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
step "a_commit" { COMMIT; }
|
|
46
|
+
|
|
47
|
+
session "b"
|
|
48
|
+
step "b_begin" { BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role'; }
|
|
49
|
+
step "b_enroll" {
|
|
50
|
+
do $$ begin
|
|
51
|
+
perform agent_board.enroll_federated_identity(
|
|
52
|
+
'https://tok521-iso.test', 'message-board', 'tok521-human',
|
|
53
|
+
jsonb_build_object('iss','https://tok521-iso.test','aud','message-board','sub','tok521-human'),
|
|
54
|
+
'tok521-agent',
|
|
55
|
+
public.test_pubkey('tok521-k2'), 'raw_ed25519_base64url',
|
|
56
|
+
public.test_key_fingerprint('tok521-k2'),
|
|
57
|
+
true, repeat('a', 64), now() + interval '1 hour', null, 'agent',
|
|
58
|
+
ARRAY['board:send'], ARRAY[]::text[], null
|
|
59
|
+
);
|
|
60
|
+
exception when others then
|
|
61
|
+
raise exception 'SQLSTATE %: %', sqlstate, sqlerrm using errcode = sqlstate;
|
|
62
|
+
end $$;
|
|
63
|
+
}
|
|
64
|
+
step "b_rollback" { ROLLBACK; }
|
|
65
|
+
|
|
66
|
+
session "check"
|
|
67
|
+
step "check" {
|
|
68
|
+
select
|
|
69
|
+
(select count(*) from agent_board.agents where handle like 'tok521-agent%') as agents,
|
|
70
|
+
(select count(*) from agent_board.agent_signing_keys where fingerprint = public.test_key_fingerprint('tok521-k1')) as k1_keys,
|
|
71
|
+
(select count(*) from agent_board.agent_signing_keys where fingerprint = public.test_key_fingerprint('tok521-k2')) as k2_keys,
|
|
72
|
+
(select count(*) from agent_board.enroll_token_uses) as token_rows,
|
|
73
|
+
(select case u.agent_public_key_fingerprint
|
|
74
|
+
when public.test_key_fingerprint('tok521-k1') then 'K1'
|
|
75
|
+
when public.test_key_fingerprint('tok521-k2') then 'K2'
|
|
76
|
+
else 'other' end
|
|
77
|
+
from agent_board.enroll_token_uses u where u.token_sha256 = repeat('a', 64)) as token_bound_to;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
permutation "a_begin" "a_enroll" "b_begin" "b_enroll" "a_commit" "b_rollback" "check"
|
|
@@ -143,7 +143,7 @@ step "onboard_call" {
|
|
|
143
143
|
'yd_DIFGWGusVg3SbktDJQ1bE5UWvtR33xln4b05JIhk',
|
|
144
144
|
'raw_ed25519_base64url',
|
|
145
145
|
'sha256:NeVC2vx1MbTY56jUwJcLLr6YwB4IKCERsXWbUwhf5pA',
|
|
146
|
-
true, null, 'agent', ARRAY['board:send'], ARRAY[]::text[],
|
|
146
|
+
true, md5(random()::text) || md5(random()::text), now() + make_interval(hours => 1), null, 'agent', ARRAY['board:send'], ARRAY[]::text[],
|
|
147
147
|
(select code from agent_board.board_invite_tokens where created_by_agent_id='19610000-0000-0000-0000-000000000001'),
|
|
148
148
|
(select id from agent_board.boards where slug='onboard-ceiling-board'),
|
|
149
149
|
'19610000-0000-0000-0000-000000000003', 'codex', 'phase-loop',
|