@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.
Files changed (68) hide show
  1. package/fixtures/already-applied.json +8 -0
  2. package/migrations/20261005000100_agent_board_enroll_token_single_use.sql +886 -0
  3. package/migrations/20261006000100_agent_board_room_roster_active_first.sql +118 -0
  4. package/package.json +1 -1
  5. package/schema-manifest.json +21 -3
  6. package/src/tooling.test.mjs +7 -2
  7. package/tests/agent_board_atomic_fleet_onboarding.test.sql +35 -35
  8. package/tests/agent_board_atomic_fleet_onboarding_backfill.test.sql +5 -5
  9. package/tests/agent_board_atomic_fleet_onboarding_runtime.test.sql +32 -32
  10. package/tests/agent_board_enroll_federated_identity.test.sql +11 -10
  11. package/tests/agent_board_enroll_pop_binding.test.sql +12 -12
  12. package/tests/agent_board_enroll_resumption.test.sql +1 -1
  13. package/tests/agent_board_enroll_token_single_use.test.sql +538 -0
  14. package/tests/agent_board_enrollment_audit_content.test.sql +3 -3
  15. package/tests/agent_board_federated_lock_order_class.test.sql +5 -5
  16. package/tests/agent_board_fedsession.test.sql +1 -1
  17. package/tests/agent_board_fk_lock_edges.test.sql +23 -0
  18. package/tests/agent_board_identity_providers.test.sql +3 -2
  19. package/tests/agent_board_membership_current_row_class.test.sql +460 -0
  20. package/tests/agent_board_portal_offline_invariant.test.sql +1 -1
  21. package/tests/agent_board_room_roster.test.sql +262 -24
  22. package/tests/agent_board_roomlink.test.sql +2 -2
  23. package/tests/agent_board_rowid.test.sql +15 -2
  24. package/tests/agent_board_write_enforcement_class.test.sql +5 -2
  25. package/tests/catalog/function_execute_privileges.json +12 -3
  26. package/tests/catalog/p_metadata_parameters.json +6 -2
  27. package/tests/isolation/expected/atomic_fedsession_fleet_lock_order.out +1 -1
  28. package/tests/isolation/expected/atomic_fleet_authority_races.out +8 -8
  29. package/tests/isolation/expected/atomic_fleet_binding_revoke.out +2 -2
  30. package/tests/isolation/expected/atomic_fleet_board_archive.out +2 -2
  31. package/tests/isolation/expected/atomic_fleet_human_fresh_revoke.out +2 -2
  32. package/tests/isolation/expected/atomic_fleet_identity_disposition.out +2 -2
  33. package/tests/isolation/expected/atomic_fleet_lifecycle_races.out +22 -22
  34. package/tests/isolation/expected/atomic_fleet_onboarding.out +2 -2
  35. package/tests/isolation/expected/atomic_fleet_subtree_lock_order.out +1 -1
  36. package/tests/isolation/expected/enroll_identity_board_owner_lock_order.out +1 -1
  37. package/tests/isolation/expected/enroll_token_fleet_abort.out +81 -0
  38. package/tests/isolation/expected/enroll_token_pk_backstop.out +36 -0
  39. package/tests/isolation/expected/enroll_token_placement.out +86 -0
  40. package/tests/isolation/expected/enroll_token_rollback_unstrands.out +59 -0
  41. package/tests/isolation/expected/enroll_token_route_race_fleet_first.out +72 -0
  42. package/tests/isolation/expected/enroll_token_route_race_identity_first.out +72 -0
  43. package/tests/isolation/expected/enroll_token_same_key_fleet_then_identity.out +73 -0
  44. package/tests/isolation/expected/enroll_token_same_key_identity_then_fleet.out +73 -0
  45. package/tests/isolation/expected/enroll_token_same_key_resume.out +59 -0
  46. package/tests/isolation/expected/enroll_token_same_token_race.out +58 -0
  47. package/tests/isolation/expected/onboarding_ceiling_lock_order.out +2 -2
  48. package/tests/isolation/specs/atomic_fedsession_fleet_lock_order.spec +1 -1
  49. package/tests/isolation/specs/atomic_fleet_authority_races.spec +2 -2
  50. package/tests/isolation/specs/atomic_fleet_binding_revoke.spec +2 -2
  51. package/tests/isolation/specs/atomic_fleet_board_archive.spec +2 -2
  52. package/tests/isolation/specs/atomic_fleet_human_fresh_revoke.spec +2 -2
  53. package/tests/isolation/specs/atomic_fleet_identity_disposition.spec +2 -2
  54. package/tests/isolation/specs/atomic_fleet_lifecycle_races.spec +2 -2
  55. package/tests/isolation/specs/atomic_fleet_onboarding.spec +2 -2
  56. package/tests/isolation/specs/atomic_fleet_subtree_lock_order.spec +2 -2
  57. package/tests/isolation/specs/enroll_identity_board_owner_lock_order.spec +1 -1
  58. package/tests/isolation/specs/enroll_token_fleet_abort.spec +138 -0
  59. package/tests/isolation/specs/enroll_token_pk_backstop.spec +37 -0
  60. package/tests/isolation/specs/enroll_token_placement.spec +136 -0
  61. package/tests/isolation/specs/enroll_token_rollback_unstrands.spec +71 -0
  62. package/tests/isolation/specs/enroll_token_route_race_fleet_first.spec +119 -0
  63. package/tests/isolation/specs/enroll_token_route_race_identity_first.spec +120 -0
  64. package/tests/isolation/specs/enroll_token_same_key_fleet_then_identity.spec +112 -0
  65. package/tests/isolation/specs/enroll_token_same_key_identity_then_fleet.spec +113 -0
  66. package/tests/isolation/specs/enroll_token_same_key_resume.spec +70 -0
  67. package/tests/isolation/specs/enroll_token_same_token_race.spec +80 -0
  68. package/tests/isolation/specs/onboarding_ceiling_lock_order.spec +1 -1
@@ -0,0 +1,72 @@
1
+ Parsed test spec with 3 sessions
2
+
3
+ starting permutation: fleet_begin fleet_onboard ident_begin ident_enroll fleet_commit ident_rollback check
4
+ count
5
+ -----
6
+ 1
7
+ (1 row)
8
+
9
+ step fleet_begin: BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role';
10
+ step fleet_onboard:
11
+ select agent_handle, identity_disposition
12
+ from agent_board.onboard_federated_fleet_agent(
13
+ 'https://tok521-iso.test', 'message-board', 'tok521-human',
14
+ jsonb_build_object('iss','https://tok521-iso.test','aud','message-board','sub','tok521-human'),
15
+ 'tok521-agent',
16
+ public.test_pubkey('tok521-k1'), 'raw_ed25519_base64url',
17
+ public.test_key_fingerprint('tok521-k1'),
18
+ true, repeat('a', 64), now() + interval '1 hour', null, 'agent',
19
+ ARRAY['board:send'], ARRAY[]::text[],
20
+ (select code from agent_board.board_invite_tokens where created_by_agent_id='52100000-0000-0000-0000-000000000001'),
21
+ (select id from agent_board.boards where slug='tok521-board'),
22
+ '52100000-0000-0000-0000-000000000003', 'codex', 'phase-loop',
23
+ 'message-board', 'sha256:tok521-repo', 'worker', 'phase_worker',
24
+ 'tok521-agent'
25
+ );
26
+
27
+ agent_handle|identity_disposition
28
+ ------------+--------------------
29
+ tok521-agent|created
30
+ (1 row)
31
+
32
+ step ident_begin: BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role';
33
+ step ident_enroll:
34
+ do $$ begin
35
+ perform 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-k2'), 'raw_ed25519_base64url',
40
+ public.test_key_fingerprint('tok521-k2'),
41
+ true, repeat('a', 64), now() + interval '1 hour', null, 'agent',
42
+ ARRAY['board:send'], ARRAY[]::text[], null
43
+ );
44
+ exception when others then
45
+ raise exception 'SQLSTATE %: %', sqlstate, sqlerrm using errcode = sqlstate;
46
+ end $$;
47
+ <waiting ...>
48
+ step fleet_commit: COMMIT;
49
+ step ident_enroll: <... completed>
50
+ ERROR: SQLSTATE MBT01: enroll token already bound to a different key
51
+ step ident_rollback: ROLLBACK;
52
+ step check:
53
+ select
54
+ (select count(*) from agent_board.agents where handle like 'tok521-agent%') as agents,
55
+ (select count(*) from agent_board.agent_signing_keys where fingerprint = public.test_key_fingerprint('tok521-k1')) as k1_keys,
56
+ (select count(*) from agent_board.agent_signing_keys where fingerprint = public.test_key_fingerprint('tok521-k2')) as k2_keys,
57
+ (select count(*) from agent_board.enroll_token_uses) as token_rows,
58
+ (select case u.agent_public_key_fingerprint
59
+ when public.test_key_fingerprint('tok521-k1') then 'K1'
60
+ when public.test_key_fingerprint('tok521-k2') then 'K2'
61
+ else 'other' end
62
+ from agent_board.enroll_token_uses u where u.token_sha256 = repeat('a', 64)) as token_bound_to,
63
+ (select count(*) from agent_board.fleet_harness_registrations where machine_id='52100000-0000-0000-0000-000000000003') as harnesses,
64
+ (select count(*) from agent_board.fleet_repo_scopes r join agent_board.fleet_harness_registrations h on h.id = r.harness_registration_id
65
+ where h.machine_id='52100000-0000-0000-0000-000000000003') as repo_scopes,
66
+ (select count(*) from agent_board.fleet_machine_agents where machine_id='52100000-0000-0000-0000-000000000003') as bindings;
67
+
68
+ agents|k1_keys|k2_keys|token_rows|token_bound_to|harnesses|repo_scopes|bindings
69
+ ------+-------+-------+----------+--------------+---------+-----------+--------
70
+ 1| 1| 0| 1|K1 | 1| 1| 1
71
+ (1 row)
72
+
@@ -0,0 +1,72 @@
1
+ Parsed test spec with 3 sessions
2
+
3
+ starting permutation: ident_begin ident_enroll fleet_begin fleet_onboard ident_commit fleet_rollback check
4
+ count
5
+ -----
6
+ 1
7
+ (1 row)
8
+
9
+ step ident_begin: BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role';
10
+ step ident_enroll:
11
+ select agent_handle
12
+ from agent_board.enroll_federated_identity(
13
+ 'https://tok521-iso.test', 'message-board', 'tok521-human',
14
+ jsonb_build_object('iss','https://tok521-iso.test','aud','message-board','sub','tok521-human'),
15
+ 'tok521-agent',
16
+ public.test_pubkey('tok521-k1'), 'raw_ed25519_base64url',
17
+ public.test_key_fingerprint('tok521-k1'),
18
+ true, repeat('a', 64), now() + interval '1 hour', null, 'agent',
19
+ ARRAY['board:send'], ARRAY[]::text[], null
20
+ );
21
+
22
+ agent_handle
23
+ ------------
24
+ tok521-agent
25
+ (1 row)
26
+
27
+ step fleet_begin: BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role';
28
+ step fleet_onboard:
29
+ do $$ begin
30
+ perform agent_board.onboard_federated_fleet_agent(
31
+ 'https://tok521-iso.test', 'message-board', 'tok521-human',
32
+ jsonb_build_object('iss','https://tok521-iso.test','aud','message-board','sub','tok521-human'),
33
+ 'tok521-agent',
34
+ public.test_pubkey('tok521-k2'), 'raw_ed25519_base64url',
35
+ public.test_key_fingerprint('tok521-k2'),
36
+ true, repeat('a', 64), now() + interval '1 hour', null, 'agent',
37
+ ARRAY['board:send'], ARRAY[]::text[],
38
+ (select code from agent_board.board_invite_tokens where created_by_agent_id='52100000-0000-0000-0000-000000000001'),
39
+ (select id from agent_board.boards where slug='tok521-board'),
40
+ '52100000-0000-0000-0000-000000000003', 'codex', 'phase-loop',
41
+ 'message-board', 'sha256:tok521-repo', 'worker', 'phase_worker',
42
+ 'tok521-agent'
43
+ );
44
+ exception when others then
45
+ raise exception 'SQLSTATE %: %', sqlstate, sqlerrm using errcode = sqlstate;
46
+ end $$;
47
+ <waiting ...>
48
+ step ident_commit: COMMIT;
49
+ step fleet_onboard: <... completed>
50
+ ERROR: SQLSTATE MBT01: enroll token already bound to a different key
51
+ step fleet_rollback: ROLLBACK;
52
+ step check:
53
+ select
54
+ (select count(*) from agent_board.agents where handle like 'tok521-agent%') as agents,
55
+ (select count(*) from agent_board.agent_signing_keys where fingerprint = public.test_key_fingerprint('tok521-k1')) as k1_keys,
56
+ (select count(*) from agent_board.agent_signing_keys where fingerprint = public.test_key_fingerprint('tok521-k2')) as k2_keys,
57
+ (select count(*) from agent_board.enroll_token_uses) as token_rows,
58
+ (select case u.agent_public_key_fingerprint
59
+ when public.test_key_fingerprint('tok521-k1') then 'K1'
60
+ when public.test_key_fingerprint('tok521-k2') then 'K2'
61
+ else 'other' end
62
+ from agent_board.enroll_token_uses u where u.token_sha256 = repeat('a', 64)) as token_bound_to,
63
+ (select count(*) from agent_board.fleet_harness_registrations where machine_id='52100000-0000-0000-0000-000000000003') as harnesses,
64
+ (select count(*) from agent_board.fleet_repo_scopes r join agent_board.fleet_harness_registrations h on h.id = r.harness_registration_id
65
+ where h.machine_id='52100000-0000-0000-0000-000000000003') as repo_scopes,
66
+ (select count(*) from agent_board.fleet_machine_agents where machine_id='52100000-0000-0000-0000-000000000003') as bindings;
67
+
68
+ agents|k1_keys|k2_keys|token_rows|token_bound_to|harnesses|repo_scopes|bindings
69
+ ------+-------+-------+----------+--------------+---------+-----------+--------
70
+ 1| 1| 0| 1|K1 | 0| 0| 0
71
+ (1 row)
72
+
@@ -0,0 +1,73 @@
1
+ Parsed test spec with 3 sessions
2
+
3
+ starting permutation: fleet_begin fleet_onboard ident_begin ident_enroll fleet_commit ident_commit check
4
+ count
5
+ -----
6
+ 1
7
+ (1 row)
8
+
9
+ step fleet_begin: BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role';
10
+ step fleet_onboard:
11
+ select agent_handle, identity_disposition
12
+ from agent_board.onboard_federated_fleet_agent(
13
+ 'https://tok521-iso.test', 'message-board', 'tok521-human',
14
+ jsonb_build_object('iss','https://tok521-iso.test','aud','message-board','sub','tok521-human'),
15
+ 'tok521-agent',
16
+ public.test_pubkey('tok521-k1'), 'raw_ed25519_base64url',
17
+ public.test_key_fingerprint('tok521-k1'),
18
+ true, repeat('a', 64), now() + interval '1 hour', null, 'agent',
19
+ ARRAY['board:send'], ARRAY[]::text[],
20
+ (select code from agent_board.board_invite_tokens where created_by_agent_id='52100000-0000-0000-0000-000000000001'),
21
+ (select id from agent_board.boards where slug='tok521-board'),
22
+ '52100000-0000-0000-0000-000000000003', 'codex', 'phase-loop',
23
+ 'message-board', 'sha256:tok521-repo', 'worker', 'phase_worker',
24
+ 'tok521-agent'
25
+ );
26
+
27
+ agent_handle|identity_disposition
28
+ ------------+--------------------
29
+ tok521-agent|created
30
+ (1 row)
31
+
32
+ step ident_begin: BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role';
33
+ step ident_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
+ <waiting ...>
45
+ step fleet_commit: COMMIT;
46
+ step ident_enroll: <... completed>
47
+ agent_handle
48
+ ------------
49
+ tok521-agent
50
+ (1 row)
51
+
52
+ step ident_commit: COMMIT;
53
+ step check:
54
+ select
55
+ (select count(*) from agent_board.agents where handle like 'tok521-agent%') as agents,
56
+ (select count(*) from agent_board.agent_signing_keys where fingerprint = public.test_key_fingerprint('tok521-k1')) as k1_keys,
57
+ (select count(*) from agent_board.agent_signing_keys where fingerprint = public.test_key_fingerprint('tok521-k2')) as k2_keys,
58
+ (select count(*) from agent_board.enroll_token_uses) as token_rows,
59
+ (select case u.agent_public_key_fingerprint
60
+ when public.test_key_fingerprint('tok521-k1') then 'K1'
61
+ when public.test_key_fingerprint('tok521-k2') then 'K2'
62
+ else 'other' end
63
+ from agent_board.enroll_token_uses u where u.token_sha256 = repeat('a', 64)) as token_bound_to,
64
+ (select count(*) from agent_board.fleet_harness_registrations where machine_id='52100000-0000-0000-0000-000000000003') as harnesses,
65
+ (select count(*) from agent_board.fleet_repo_scopes r join agent_board.fleet_harness_registrations h on h.id = r.harness_registration_id
66
+ where h.machine_id='52100000-0000-0000-0000-000000000003') as repo_scopes,
67
+ (select count(*) from agent_board.fleet_machine_agents where machine_id='52100000-0000-0000-0000-000000000003') as bindings;
68
+
69
+ agents|k1_keys|k2_keys|token_rows|token_bound_to|harnesses|repo_scopes|bindings
70
+ ------+-------+-------+----------+--------------+---------+-----------+--------
71
+ 1| 1| 0| 1|K1 | 1| 1| 1
72
+ (1 row)
73
+
@@ -0,0 +1,73 @@
1
+ Parsed test spec with 3 sessions
2
+
3
+ starting permutation: ident_begin ident_enroll fleet_begin fleet_onboard ident_commit fleet_commit check
4
+ count
5
+ -----
6
+ 1
7
+ (1 row)
8
+
9
+ step ident_begin: BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role';
10
+ step ident_enroll:
11
+ select agent_handle
12
+ from agent_board.enroll_federated_identity(
13
+ 'https://tok521-iso.test', 'message-board', 'tok521-human',
14
+ jsonb_build_object('iss','https://tok521-iso.test','aud','message-board','sub','tok521-human'),
15
+ 'tok521-agent',
16
+ public.test_pubkey('tok521-k1'), 'raw_ed25519_base64url',
17
+ public.test_key_fingerprint('tok521-k1'),
18
+ true, repeat('a', 64), now() + interval '1 hour', null, 'agent',
19
+ ARRAY['board:send'], ARRAY[]::text[], null
20
+ );
21
+
22
+ agent_handle
23
+ ------------
24
+ tok521-agent
25
+ (1 row)
26
+
27
+ step fleet_begin: BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role';
28
+ step fleet_onboard:
29
+ select agent_handle, identity_disposition
30
+ from agent_board.onboard_federated_fleet_agent(
31
+ 'https://tok521-iso.test', 'message-board', 'tok521-human',
32
+ jsonb_build_object('iss','https://tok521-iso.test','aud','message-board','sub','tok521-human'),
33
+ 'tok521-agent',
34
+ public.test_pubkey('tok521-k1'), 'raw_ed25519_base64url',
35
+ public.test_key_fingerprint('tok521-k1'),
36
+ true, repeat('a', 64), now() + interval '1 hour', null, 'agent',
37
+ ARRAY['board:send'], ARRAY[]::text[],
38
+ (select code from agent_board.board_invite_tokens where created_by_agent_id='52100000-0000-0000-0000-000000000001'),
39
+ (select id from agent_board.boards where slug='tok521-board'),
40
+ '52100000-0000-0000-0000-000000000003', 'codex', 'phase-loop',
41
+ 'message-board', 'sha256:tok521-repo', 'worker', 'phase_worker',
42
+ 'tok521-agent'
43
+ );
44
+ <waiting ...>
45
+ step ident_commit: COMMIT;
46
+ step fleet_onboard: <... completed>
47
+ agent_handle|identity_disposition
48
+ ------------+--------------------
49
+ tok521-agent|reused
50
+ (1 row)
51
+
52
+ step fleet_commit: COMMIT;
53
+ step check:
54
+ select
55
+ (select count(*) from agent_board.agents where handle like 'tok521-agent%') as agents,
56
+ (select count(*) from agent_board.agent_signing_keys where fingerprint = public.test_key_fingerprint('tok521-k1')) as k1_keys,
57
+ (select count(*) from agent_board.agent_signing_keys where fingerprint = public.test_key_fingerprint('tok521-k2')) as k2_keys,
58
+ (select count(*) from agent_board.enroll_token_uses) as token_rows,
59
+ (select case u.agent_public_key_fingerprint
60
+ when public.test_key_fingerprint('tok521-k1') then 'K1'
61
+ when public.test_key_fingerprint('tok521-k2') then 'K2'
62
+ else 'other' end
63
+ from agent_board.enroll_token_uses u where u.token_sha256 = repeat('a', 64)) as token_bound_to,
64
+ (select count(*) from agent_board.fleet_harness_registrations where machine_id='52100000-0000-0000-0000-000000000003') as harnesses,
65
+ (select count(*) from agent_board.fleet_repo_scopes r join agent_board.fleet_harness_registrations h on h.id = r.harness_registration_id
66
+ where h.machine_id='52100000-0000-0000-0000-000000000003') as repo_scopes,
67
+ (select count(*) from agent_board.fleet_machine_agents where machine_id='52100000-0000-0000-0000-000000000003') as bindings;
68
+
69
+ agents|k1_keys|k2_keys|token_rows|token_bound_to|harnesses|repo_scopes|bindings
70
+ ------+-------+-------+----------+--------------+---------+-----------+--------
71
+ 1| 1| 0| 1|K1 | 1| 1| 1
72
+ (1 row)
73
+
@@ -0,0 +1,59 @@
1
+ Parsed test spec with 3 sessions
2
+
3
+ starting permutation: a_begin a_enroll b_begin b_enroll a_commit b_commit check
4
+ step a_begin: BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role';
5
+ step a_enroll:
6
+ select agent_handle
7
+ from agent_board.enroll_federated_identity(
8
+ 'https://tok521-iso.test', 'message-board', 'tok521-human',
9
+ jsonb_build_object('iss','https://tok521-iso.test','aud','message-board','sub','tok521-human'),
10
+ 'tok521-agent',
11
+ public.test_pubkey('tok521-k1'), 'raw_ed25519_base64url',
12
+ public.test_key_fingerprint('tok521-k1'),
13
+ true, repeat('a', 64), now() + interval '1 hour', null, 'agent',
14
+ ARRAY['board:send'], ARRAY[]::text[], null
15
+ );
16
+
17
+ agent_handle
18
+ ------------
19
+ tok521-agent
20
+ (1 row)
21
+
22
+ step b_begin: BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role';
23
+ step b_enroll:
24
+ select agent_handle
25
+ from agent_board.enroll_federated_identity(
26
+ 'https://tok521-iso.test', 'message-board', 'tok521-human',
27
+ jsonb_build_object('iss','https://tok521-iso.test','aud','message-board','sub','tok521-human'),
28
+ 'tok521-agent',
29
+ public.test_pubkey('tok521-k1'), 'raw_ed25519_base64url',
30
+ public.test_key_fingerprint('tok521-k1'),
31
+ true, repeat('a', 64), now() + interval '1 hour', null, 'agent',
32
+ ARRAY['board:send'], ARRAY[]::text[], null
33
+ );
34
+ <waiting ...>
35
+ step a_commit: COMMIT;
36
+ step b_enroll: <... completed>
37
+ agent_handle
38
+ ------------
39
+ tok521-agent
40
+ (1 row)
41
+
42
+ step b_commit: COMMIT;
43
+ step check:
44
+ select
45
+ (select count(*) from agent_board.agents where handle like 'tok521-agent%') as agents,
46
+ (select count(*) from agent_board.agent_signing_keys where fingerprint = public.test_key_fingerprint('tok521-k1')) as k1_keys,
47
+ (select count(*) from agent_board.agent_signing_keys where fingerprint = public.test_key_fingerprint('tok521-k2')) as k2_keys,
48
+ (select count(*) from agent_board.enroll_token_uses) as token_rows,
49
+ (select case u.agent_public_key_fingerprint
50
+ when public.test_key_fingerprint('tok521-k1') then 'K1'
51
+ when public.test_key_fingerprint('tok521-k2') then 'K2'
52
+ else 'other' end
53
+ from agent_board.enroll_token_uses u where u.token_sha256 = repeat('a', 64)) as token_bound_to;
54
+
55
+ agents|k1_keys|k2_keys|token_rows|token_bound_to
56
+ ------+-------+-------+----------+--------------
57
+ 1| 1| 0| 1|K1
58
+ (1 row)
59
+
@@ -0,0 +1,58 @@
1
+ Parsed test spec with 3 sessions
2
+
3
+ starting permutation: a_begin a_enroll b_begin b_enroll a_commit b_rollback check
4
+ step a_begin: BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role';
5
+ step a_enroll:
6
+ select agent_handle
7
+ from agent_board.enroll_federated_identity(
8
+ 'https://tok521-iso.test', 'message-board', 'tok521-human',
9
+ jsonb_build_object('iss','https://tok521-iso.test','aud','message-board','sub','tok521-human'),
10
+ 'tok521-agent',
11
+ public.test_pubkey('tok521-k1'), 'raw_ed25519_base64url',
12
+ public.test_key_fingerprint('tok521-k1'),
13
+ true, repeat('a', 64), now() + interval '1 hour', null, 'agent',
14
+ ARRAY['board:send'], ARRAY[]::text[], null
15
+ );
16
+
17
+ agent_handle
18
+ ------------
19
+ tok521-agent
20
+ (1 row)
21
+
22
+ step b_begin: BEGIN; SET LOCAL "request.jwt.claim.role" = 'service_role';
23
+ step b_enroll:
24
+ do $$ begin
25
+ perform agent_board.enroll_federated_identity(
26
+ 'https://tok521-iso.test', 'message-board', 'tok521-human',
27
+ jsonb_build_object('iss','https://tok521-iso.test','aud','message-board','sub','tok521-human'),
28
+ 'tok521-agent',
29
+ public.test_pubkey('tok521-k2'), 'raw_ed25519_base64url',
30
+ public.test_key_fingerprint('tok521-k2'),
31
+ true, repeat('a', 64), now() + interval '1 hour', null, 'agent',
32
+ ARRAY['board:send'], ARRAY[]::text[], null
33
+ );
34
+ exception when others then
35
+ raise exception 'SQLSTATE %: %', sqlstate, sqlerrm using errcode = sqlstate;
36
+ end $$;
37
+ <waiting ...>
38
+ step a_commit: COMMIT;
39
+ step b_enroll: <... completed>
40
+ ERROR: SQLSTATE MBT01: enroll token already bound to a different key
41
+ step b_rollback: ROLLBACK;
42
+ step check:
43
+ select
44
+ (select count(*) from agent_board.agents where handle like 'tok521-agent%') as agents,
45
+ (select count(*) from agent_board.agent_signing_keys where fingerprint = public.test_key_fingerprint('tok521-k1')) as k1_keys,
46
+ (select count(*) from agent_board.agent_signing_keys where fingerprint = public.test_key_fingerprint('tok521-k2')) as k2_keys,
47
+ (select count(*) from agent_board.enroll_token_uses) as token_rows,
48
+ (select case u.agent_public_key_fingerprint
49
+ when public.test_key_fingerprint('tok521-k1') then 'K1'
50
+ when public.test_key_fingerprint('tok521-k2') then 'K2'
51
+ else 'other' end
52
+ from agent_board.enroll_token_uses u where u.token_sha256 = repeat('a', 64)) as token_bound_to;
53
+
54
+ agents|k1_keys|k2_keys|token_rows|token_bound_to
55
+ ------+-------+-------+----------+--------------
56
+ 1| 1| 0| 1|K1
57
+ (1 row)
58
+
@@ -26,7 +26,7 @@ step onboard_call:
26
26
  'yd_DIFGWGusVg3SbktDJQ1bE5UWvtR33xln4b05JIhk',
27
27
  'raw_ed25519_base64url',
28
28
  'sha256:NeVC2vx1MbTY56jUwJcLLr6YwB4IKCERsXWbUwhf5pA',
29
- true, null, 'agent', ARRAY['board:send'], ARRAY[]::text[],
29
+ true, md5(random()::text) || md5(random()::text), now() + make_interval(hours => 1), null, 'agent', ARRAY['board:send'], ARRAY[]::text[],
30
30
  (select code from agent_board.board_invite_tokens where created_by_agent_id='19610000-0000-0000-0000-000000000001'),
31
31
  (select id from agent_board.boards where slug='onboard-ceiling-board'),
32
32
  '19610000-0000-0000-0000-000000000003', 'codex', 'phase-loop',
@@ -83,7 +83,7 @@ step onboard_call:
83
83
  'yd_DIFGWGusVg3SbktDJQ1bE5UWvtR33xln4b05JIhk',
84
84
  'raw_ed25519_base64url',
85
85
  'sha256:NeVC2vx1MbTY56jUwJcLLr6YwB4IKCERsXWbUwhf5pA',
86
- true, null, 'agent', ARRAY['board:send'], ARRAY[]::text[],
86
+ true, md5(random()::text) || md5(random()::text), now() + make_interval(hours => 1), null, 'agent', ARRAY['board:send'], ARRAY[]::text[],
87
87
  (select code from agent_board.board_invite_tokens where created_by_agent_id='19610000-0000-0000-0000-000000000001'),
88
88
  (select id from agent_board.boards where slug='onboard-ceiling-board'),
89
89
  '19610000-0000-0000-0000-000000000003', 'codex', 'phase-loop',
@@ -76,7 +76,7 @@ step "fleet_onboard" {
76
76
  'eRHZmllEy_TZHAG2zB-Qe_a5BFLkaavMTazWWfaE3f0',
77
77
  'raw_ed25519_base64url',
78
78
  'sha256:z8d5LQPfBMYnfZfvu8wVz684_jkp578-SPDU2OMObS8',
79
- true, null, 'agent', ARRAY['board:send'], ARRAY[]::text[],
79
+ true, md5(random()::text) || md5(random()::text), now() + make_interval(hours => 1), null, 'agent', ARRAY['board:send'], ARRAY[]::text[],
80
80
  (select code from agent_board.board_invite_tokens where created_by_agent_id='162a0000-0000-0000-0000-000000000001'),
81
81
  (select id from agent_board.boards where slug='atomic-cross-board'),
82
82
  '162a0000-0000-0000-0000-000000000003',
@@ -93,7 +93,7 @@ setup
93
93
  'yd_DIFGWGusVg3SbktDJQ1bE5UWvtR33xln4b05JIhk',
94
94
  'raw_ed25519_base64url',
95
95
  'sha256:NeVC2vx1MbTY56jUwJcLLr6YwB4IKCERsXWbUwhf5pA',
96
- true, null, 'agent', ARRAY['board:send'], ARRAY[]::text[],
96
+ true, md5(random()::text) || md5(random()::text), now() + make_interval(hours => 1), null, 'agent', ARRAY['board:send'], ARRAY[]::text[],
97
97
  (select code from agent_board.board_invite_tokens where created_by_agent_id='16250000-0000-0000-0000-000000000001'),
98
98
  (select id from agent_board.boards where slug='atomic-authority-board'),
99
99
  '16250000-0000-0000-0000-000000000003', 'codex', 'phase-loop',
@@ -149,7 +149,7 @@ step "retry_onboard" {
149
149
  'yd_DIFGWGusVg3SbktDJQ1bE5UWvtR33xln4b05JIhk',
150
150
  'raw_ed25519_base64url',
151
151
  'sha256:NeVC2vx1MbTY56jUwJcLLr6YwB4IKCERsXWbUwhf5pA',
152
- true, null, 'agent', ARRAY['board:send'], ARRAY[]::text[],
152
+ true, md5(random()::text) || md5(random()::text), now() + make_interval(hours => 1), null, 'agent', ARRAY['board:send'], ARRAY[]::text[],
153
153
  (select code from agent_board.board_invite_tokens where created_by_agent_id='16250000-0000-0000-0000-000000000001'),
154
154
  (select id from agent_board.boards where slug='atomic-authority-board'),
155
155
  '16250000-0000-0000-0000-000000000003', 'codex', 'phase-loop',
@@ -49,7 +49,7 @@ setup
49
49
  'yd_DIFGWGusVg3SbktDJQ1bE5UWvtR33xln4b05JIhk',
50
50
  'raw_ed25519_base64url',
51
51
  'sha256:NeVC2vx1MbTY56jUwJcLLr6YwB4IKCERsXWbUwhf5pA',
52
- true, null, 'agent', ARRAY['board:send'], ARRAY[]::text[],
52
+ true, md5(random()::text) || md5(random()::text), now() + make_interval(hours => 1), null, 'agent', ARRAY['board:send'], ARRAY[]::text[],
53
53
  (select code from agent_board.board_invite_tokens where created_by_agent_id='16230000-0000-0000-0000-000000000001'),
54
54
  (select id from agent_board.boards where slug='atomic-binding-board'),
55
55
  '16230000-0000-0000-0000-000000000003', 'codex', 'phase-loop',
@@ -95,7 +95,7 @@ step "retry_onboard" {
95
95
  jsonb_build_object('iss','https://atomic-binding.test','aud','message-board','sub','human-binding','iat',200),
96
96
  'atomic-binding-agent','yd_DIFGWGusVg3SbktDJQ1bE5UWvtR33xln4b05JIhk',
97
97
  'raw_ed25519_base64url','sha256:NeVC2vx1MbTY56jUwJcLLr6YwB4IKCERsXWbUwhf5pA',
98
- true,null,'agent',ARRAY['board:send'],ARRAY[]::text[],
98
+ true, md5(random()::text) || md5(random()::text), now() + make_interval(hours => 1),null,'agent',ARRAY['board:send'],ARRAY[]::text[],
99
99
  (select code from agent_board.board_invite_tokens where created_by_agent_id='16230000-0000-0000-0000-000000000001'),
100
100
  (select id from agent_board.boards where slug='atomic-binding-board'),
101
101
  '16230000-0000-0000-0000-000000000003','codex','phase-loop',
@@ -49,7 +49,7 @@ setup
49
49
  'yd_DIFGWGusVg3SbktDJQ1bE5UWvtR33xln4b05JIhk',
50
50
  'raw_ed25519_base64url',
51
51
  'sha256:NeVC2vx1MbTY56jUwJcLLr6YwB4IKCERsXWbUwhf5pA',
52
- true, null, 'agent', ARRAY['board:send'], ARRAY[]::text[],
52
+ true, md5(random()::text) || md5(random()::text), now() + make_interval(hours => 1), null, 'agent', ARRAY['board:send'], ARRAY[]::text[],
53
53
  (select code from agent_board.board_invite_tokens where created_by_agent_id='16290000-0000-0000-0000-000000000001'),
54
54
  (select id from agent_board.boards where slug='atomic-archive-board'),
55
55
  '16290000-0000-0000-0000-000000000003', 'codex', 'phase-loop',
@@ -112,7 +112,7 @@ step "retry_onboard" {
112
112
  'yd_DIFGWGusVg3SbktDJQ1bE5UWvtR33xln4b05JIhk',
113
113
  'raw_ed25519_base64url',
114
114
  'sha256:NeVC2vx1MbTY56jUwJcLLr6YwB4IKCERsXWbUwhf5pA',
115
- true, null, 'agent', ARRAY['board:send'], ARRAY[]::text[],
115
+ true, md5(random()::text) || md5(random()::text), now() + make_interval(hours => 1), null, 'agent', ARRAY['board:send'], ARRAY[]::text[],
116
116
  (select code from agent_board.board_invite_tokens where created_by_agent_id='16290000-0000-0000-0000-000000000001'),
117
117
  (select id from agent_board.boards where slug='atomic-archive-board'),
118
118
  '16290000-0000-0000-0000-000000000003', 'codex', 'phase-loop',
@@ -42,7 +42,7 @@ setup
42
42
  'yd_DIFGWGusVg3SbktDJQ1bE5UWvtR33xln4b05JIhk',
43
43
  'raw_ed25519_base64url',
44
44
  'sha256:NeVC2vx1MbTY56jUwJcLLr6YwB4IKCERsXWbUwhf5pA',
45
- true, null, 'agent', ARRAY['board:send'], ARRAY[]::text[], null
45
+ true, md5(random()::text) || md5(random()::text), now() + make_interval(hours => 1), null, 'agent', ARRAY['board:send'], ARRAY[]::text[], null
46
46
  );
47
47
  select count(*) from agent_board.create_fleet_onboarding_invite(
48
48
  (select id from agent_board.boards where slug='atomic-human-board'),
@@ -108,7 +108,7 @@ step "onboard_fresh" {
108
108
  'TDyof3w0SMg4SDYuj-qenolHC_n05cZbrLSckKVGtMo',
109
109
  'raw_ed25519_base64url',
110
110
  'sha256:lSBZnHvmPvQONy8aoygp-fmTg26iZenrZC-L5LN9m7M',
111
- true, null, 'agent', ARRAY['board:send'], ARRAY[]::text[],
111
+ true, md5(random()::text) || md5(random()::text), now() + make_interval(hours => 1), null, 'agent', ARRAY['board:send'], ARRAY[]::text[],
112
112
  (select code from agent_board.board_invite_tokens where created_by_agent_id='16280000-0000-0000-0000-000000000001'),
113
113
  (select id from agent_board.boards where slug='atomic-human-board'),
114
114
  '16280000-0000-0000-0000-000000000003', 'codex', 'phase-loop',
@@ -81,7 +81,7 @@ step "legacy_enroll" {
81
81
  jsonb_build_object('iss','https://atomic-disposition.test','aud','message-board','sub','human-disposition','iat',100),
82
82
  'atomic-disposition-agent',
83
83
  '5TG73fnNhqeYkoSvPf9QwmWkvKWe0yA7B8YinAWQ8m4', 'raw_ed25519_base64url',
84
- 'sha256:qhjEQe9R_x26TBZyBsd-LrpR1fh7Mvnz86rbsCKtjz8', true, null, 'agent',
84
+ 'sha256:qhjEQe9R_x26TBZyBsd-LrpR1fh7Mvnz86rbsCKtjz8', true, md5(random()::text) || md5(random()::text), now() + make_interval(hours => 1), null, 'agent',
85
85
  ARRAY['board:send'], ARRAY[]::text[], null
86
86
  );
87
87
  }
@@ -96,7 +96,7 @@ step "fleet_onboard" {
96
96
  jsonb_build_object('iss','https://atomic-disposition.test','aud','message-board','sub','human-disposition','iat',101),
97
97
  'atomic-disposition-agent',
98
98
  '5TG73fnNhqeYkoSvPf9QwmWkvKWe0yA7B8YinAWQ8m4', 'raw_ed25519_base64url',
99
- 'sha256:qhjEQe9R_x26TBZyBsd-LrpR1fh7Mvnz86rbsCKtjz8', true, null, 'agent',
99
+ 'sha256:qhjEQe9R_x26TBZyBsd-LrpR1fh7Mvnz86rbsCKtjz8', true, md5(random()::text) || md5(random()::text), now() + make_interval(hours => 1), null, 'agent',
100
100
  ARRAY['board:send'], ARRAY[]::text[],
101
101
  (select code from agent_board.board_invite_tokens where created_by_agent_id='16260000-0000-0000-0000-000000000001'),
102
102
  (select id from agent_board.boards where slug='atomic-disposition-board'),
@@ -53,7 +53,7 @@ setup
53
53
  'yd_DIFGWGusVg3SbktDJQ1bE5UWvtR33xln4b05JIhk',
54
54
  'raw_ed25519_base64url',
55
55
  'sha256:NeVC2vx1MbTY56jUwJcLLr6YwB4IKCERsXWbUwhf5pA',
56
- true, null, 'agent', ARRAY['board:send'], ARRAY[]::text[],
56
+ true, md5(random()::text) || md5(random()::text), now() + make_interval(hours => 1), null, 'agent', ARRAY['board:send'], ARRAY[]::text[],
57
57
  (select code from agent_board.board_invite_tokens where created_by_agent_id='16240000-0000-0000-0000-000000000001'),
58
58
  (select id from agent_board.boards where slug='atomic-lifecycle-board'),
59
59
  '16240000-0000-0000-0000-000000000003', 'codex', 'phase-loop',
@@ -114,7 +114,7 @@ step "retry_onboard" {
114
114
  'yd_DIFGWGusVg3SbktDJQ1bE5UWvtR33xln4b05JIhk',
115
115
  'raw_ed25519_base64url',
116
116
  'sha256:NeVC2vx1MbTY56jUwJcLLr6YwB4IKCERsXWbUwhf5pA',
117
- true, null, 'agent', ARRAY['board:send'], ARRAY[]::text[],
117
+ true, md5(random()::text) || md5(random()::text), now() + make_interval(hours => 1), null, 'agent', ARRAY['board:send'], ARRAY[]::text[],
118
118
  (select code from agent_board.board_invite_tokens where created_by_agent_id='16240000-0000-0000-0000-000000000001'),
119
119
  (select id from agent_board.boards where slug='atomic-lifecycle-board'),
120
120
  '16240000-0000-0000-0000-000000000003', 'codex', 'phase-loop',
@@ -57,7 +57,7 @@ step "first_onboard" {
57
57
  'eRHZmllEy_TZHAG2zB-Qe_a5BFLkaavMTazWWfaE3f0',
58
58
  'raw_ed25519_base64url',
59
59
  'sha256:z8d5LQPfBMYnfZfvu8wVz684_jkp578-SPDU2OMObS8',
60
- true, null, 'agent', ARRAY['board:send'], ARRAY[]::text[],
60
+ true, md5(random()::text) || md5(random()::text), now() + make_interval(hours => 1), null, 'agent', ARRAY['board:send'], ARRAY[]::text[],
61
61
  (select code from agent_board.board_invite_tokens where created_by_agent_id = '16220000-0000-0000-0000-000000000001'),
62
62
  (select id from agent_board.boards where slug = 'atomic-race-board'),
63
63
  '16220000-0000-0000-0000-000000000003',
@@ -78,7 +78,7 @@ step "second_onboard" {
78
78
  'eRHZmllEy_TZHAG2zB-Qe_a5BFLkaavMTazWWfaE3f0',
79
79
  'raw_ed25519_base64url',
80
80
  'sha256:z8d5LQPfBMYnfZfvu8wVz684_jkp578-SPDU2OMObS8',
81
- true, null, 'agent', ARRAY['board:send'], ARRAY[]::text[],
81
+ true, md5(random()::text) || md5(random()::text), now() + make_interval(hours => 1), null, 'agent', ARRAY['board:send'], ARRAY[]::text[],
82
82
  (select code from agent_board.board_invite_tokens where created_by_agent_id = '16220000-0000-0000-0000-000000000001'),
83
83
  (select id from agent_board.boards where slug = 'atomic-race-board'),
84
84
  '16220000-0000-0000-0000-000000000003',
@@ -51,7 +51,7 @@ setup
51
51
  'yd_DIFGWGusVg3SbktDJQ1bE5UWvtR33xln4b05JIhk',
52
52
  'raw_ed25519_base64url',
53
53
  'sha256:NeVC2vx1MbTY56jUwJcLLr6YwB4IKCERsXWbUwhf5pA',
54
- true, null, 'agent', ARRAY['board:send'], ARRAY[]::text[],
54
+ true, md5(random()::text) || md5(random()::text), now() + make_interval(hours => 1), null, 'agent', ARRAY['board:send'], ARRAY[]::text[],
55
55
  (select code from agent_board.board_invite_tokens where created_by_agent_id='ffffffff-ffff-ffff-ffff-ffffffffff01'),
56
56
  (select id from agent_board.boards where slug='atomic-subtree-board'),
57
57
  '16270000-0000-0000-0000-000000000003', 'codex', 'phase-loop',
@@ -114,7 +114,7 @@ step "retry_onboard" {
114
114
  'yd_DIFGWGusVg3SbktDJQ1bE5UWvtR33xln4b05JIhk',
115
115
  'raw_ed25519_base64url',
116
116
  'sha256:NeVC2vx1MbTY56jUwJcLLr6YwB4IKCERsXWbUwhf5pA',
117
- true, null, 'agent', ARRAY['board:send'], ARRAY[]::text[],
117
+ true, md5(random()::text) || md5(random()::text), now() + make_interval(hours => 1), null, 'agent', ARRAY['board:send'], ARRAY[]::text[],
118
118
  (select code from agent_board.board_invite_tokens where created_by_agent_id='ffffffff-ffff-ffff-ffff-ffffffffff01'),
119
119
  (select id from agent_board.boards where slug='atomic-subtree-board'),
120
120
  '16270000-0000-0000-0000-000000000003', 'codex', 'phase-loop',
@@ -89,7 +89,7 @@ step "enroll_enroll" {
89
89
  'lo194-iso-agent',
90
90
  public.test_pubkey('lo194-iso-k1'), 'raw_ed25519_base64url',
91
91
  public.test_key_fingerprint('lo194-iso-k1'),
92
- true, null, 'agent', ARRAY[]::text[], ARRAY[]::text[],
92
+ true, md5(random()::text) || md5(random()::text), now() + make_interval(hours => 1), null, 'agent', ARRAY[]::text[], ARRAY[]::text[],
93
93
  'lo194-iso-code'
94
94
  );
95
95
  }