@consiliency/agent-board-schema 1.2.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 (92) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +11 -0
  3. package/README.md +55 -0
  4. package/bin/agent-board-schema.js +97 -0
  5. package/fixtures/already-applied.json +181 -0
  6. package/fixtures/divergent-history.json +173 -0
  7. package/fixtures/production-history.json +173 -0
  8. package/migrations/20260501000001_agent_board_schema_version.sql +12 -0
  9. package/migrations/20260502000000_agent_board_schema.sql +180 -0
  10. package/migrations/20260503000000_agent_board_rpcs.sql +422 -0
  11. package/migrations/20260503000001_agent_board_coordination_rpcs.sql +229 -0
  12. package/migrations/20260504000000_agent_board_read_models.sql +206 -0
  13. package/migrations/20260505000000_agent_board_inbox_schema.sql +341 -0
  14. package/migrations/20260506000000_agent_board_inbox_delivery_rpcs.sql +1200 -0
  15. package/migrations/20260506000001_agent_board_inbox_callback_rpcs.sql +330 -0
  16. package/migrations/20260507000000_agent_board_inbox_reads.sql +334 -0
  17. package/migrations/20260508000000_agent_board_callback_runtime.sql +453 -0
  18. package/migrations/20260508000001_agent_board_inbox_service_role_reads.sql +10 -0
  19. package/migrations/20260510000000_agent_board_dblint_repairs.sql +413 -0
  20. package/migrations/20260511000000_agent_board_auth_schema.sql +146 -0
  21. package/migrations/20260511000001_agent_board_auth_credentials.sql +39 -0
  22. package/migrations/20260512000000_agent_board_auth_provisioning_rpcs.sql +622 -0
  23. package/migrations/20260512000001_agent_board_auth_v1_rpcs.sql +798 -0
  24. package/migrations/20260512000002_agent_board_auth_v2_rpcs.sql +1243 -0
  25. package/migrations/20260512000003_agent_board_auth_rls.sql +484 -0
  26. package/migrations/20260513000000_agent_board_backup_ops.sql +34 -0
  27. package/migrations/20260513000001_agent_board_retention.sql +160 -0
  28. package/migrations/20260513000002_agent_board_monitoring_views.sql +227 -0
  29. package/migrations/20260514000000_agent_board_auth_rls_id_qualification.sql +150 -0
  30. package/migrations/20260515000000_agent_board_boardopt.sql +493 -0
  31. package/migrations/20260516000000_agent_board_callbackcap.sql +113 -0
  32. package/migrations/20260517000000_agent_board_addressing.sql +542 -0
  33. package/migrations/20260628000000_agent_board_signing_store.sql +174 -0
  34. package/migrations/20260628000001_agent_board_signing_proof_rpcs.sql +215 -0
  35. package/migrations/20260628000002_agent_board_signature_rls_reads.sql +300 -0
  36. package/migrations/20260628000003_agent_board_signed_write_gateway.sql +288 -0
  37. package/migrations/20260628000004_agent_board_fleet_registry.sql +411 -0
  38. package/migrations/20260628000005_agent_board_fleet_policy.sql +509 -0
  39. package/migrations/20260628000006_agent_board_fleet_read_models.sql +170 -0
  40. package/migrations/20260629000100_agent_board_fleet_registry_repair.sql +411 -0
  41. package/migrations/20260629000101_agent_board_fleet_policy_refresh.sql +509 -0
  42. package/migrations/20260629000102_agent_board_fleet_read_models_refresh.sql +170 -0
  43. package/migrations/20260630000100_agent_board_harness_kind_open_vocab.sql +15 -0
  44. package/migrations/20260710000000_agent_board_authbound_boundary.sql +155 -0
  45. package/migrations/20260710000100_agent_board_schema_version_rpc.sql +14 -0
  46. package/migrations/20260710000400_agent_board_nonfleet_identity.sql +87 -0
  47. package/migrations/20260710000401_agent_board_workload_providers.sql +39 -0
  48. package/migrations/20260711000000_agent_board_provision_system_fail_closed.sql +242 -0
  49. package/migrations/20260711000100_canary_signed_fleet_enforcement.sql +234 -0
  50. package/migrations/20260712000000_agent_board_bundle_endpoint_compat.sql +97 -0
  51. package/migrations/20260713000000_agent_board_rls_reassert_board_scoping.sql +90 -0
  52. package/package.json +42 -0
  53. package/provenance.json +580 -0
  54. package/schema-manifest.json +458 -0
  55. package/src/check.js +23 -0
  56. package/src/index.js +50 -0
  57. package/src/materialize.js +73 -0
  58. package/src/plan.js +44 -0
  59. package/src/tooling.test.mjs +97 -0
  60. package/tests/agent_board_addressing.test.sql +166 -0
  61. package/tests/agent_board_auth_rls.test.sql +243 -0
  62. package/tests/agent_board_auth_rls_id_qualification.test.sql +225 -0
  63. package/tests/agent_board_auth_rpcs.test.sql +311 -0
  64. package/tests/agent_board_auth_schema.test.sql +411 -0
  65. package/tests/agent_board_authbound_boundary.test.sql +148 -0
  66. package/tests/agent_board_boardopt.test.sql +170 -0
  67. package/tests/agent_board_bundle_endpoint_compat.test.sql +49 -0
  68. package/tests/agent_board_callback_runtime.test.sql +425 -0
  69. package/tests/agent_board_callbackcap.test.sql +222 -0
  70. package/tests/agent_board_canary_signed_fleet_enforcement.test.sql +60 -0
  71. package/tests/agent_board_dblint_rpcs.test.sql +247 -0
  72. package/tests/agent_board_fleet_policy.test.sql +370 -0
  73. package/tests/agent_board_fleet_read_models.test.sql +158 -0
  74. package/tests/agent_board_fleet_registry.test.sql +149 -0
  75. package/tests/agent_board_inbox_reads.test.sql +471 -0
  76. package/tests/agent_board_inbox_rpcs.test.sql +452 -0
  77. package/tests/agent_board_inbox_schema.test.sql +355 -0
  78. package/tests/agent_board_nonfleet_identity.test.sql +26 -0
  79. package/tests/agent_board_rls_reassert_board_scoping.test.sql +39 -0
  80. package/tests/agent_board_schema_version.test.sql +24 -0
  81. package/tests/agent_board_schema_version_rpc.test.sql +40 -0
  82. package/tests/agent_board_signature_rls_reads.test.sql +133 -0
  83. package/tests/agent_board_signed_write_gateway.test.sql +219 -0
  84. package/tests/agent_board_signing_proof_rpcs.test.sql +143 -0
  85. package/tests/agent_board_signing_store.test.sql +183 -0
  86. package/tests/agent_board_smoke.test.sql +12 -0
  87. package/tests/agent_board_v1_invariants.test.sql +298 -0
  88. package/tests/agent_board_v2_invariants.test.sql +753 -0
  89. package/tests/agent_board_workload_providers.test.sql +15 -0
  90. package/tests/fixtures/adopter-base.sql +19 -0
  91. package/tests/fixtures/operator-hardening.sql +27 -0
  92. package/tests/fixtures/test-prereqs.sql +84 -0
@@ -0,0 +1,219 @@
1
+ create extension if not exists pgtap with schema extensions;
2
+ set search_path = extensions, public, agent_board;
3
+
4
+ begin;
5
+
6
+ select plan(13);
7
+
8
+ select has_function('agent_board', 'reserve_signed_write_replay', 'replay reservation helper exists');
9
+ select has_function('agent_board', 'signed_send_direct_message', 'signed direct-message wrapper exists');
10
+ select has_function('agent_board', 'signed_append_task_event', 'signed task-event wrapper exists');
11
+ select has_function('agent_board', 'signed_post_board_message', 'signed board-message wrapper exists');
12
+
13
+ select hasnt_table('agent_board', 'private_signing_keys', 'gateway does not introduce private key storage');
14
+
15
+ do $$
16
+ declare
17
+ v_agent uuid := gen_random_uuid();
18
+ v_recipient uuid := gen_random_uuid();
19
+ v_thread uuid := gen_random_uuid();
20
+ v_task uuid := gen_random_uuid();
21
+ v_board uuid := gen_random_uuid();
22
+ v_key uuid;
23
+ v_direct record;
24
+ v_task_event record;
25
+ v_board_post record;
26
+ begin
27
+ perform set_config('request.jwt.claim.role', 'service_role', true);
28
+
29
+ insert into agent_board.agents(id, agent_type, handle, display_name)
30
+ values
31
+ (v_agent, 'agent', 'signgateway-agent', 'SIGNGATEWAY Agent'),
32
+ (v_recipient, 'agent', 'signgateway-recipient', 'SIGNGATEWAY Recipient');
33
+
34
+ insert into agent_board.threads(id, created_by_agent_id, subject)
35
+ values (v_thread, v_agent, 'SIGNGATEWAY thread');
36
+
37
+ insert into agent_board.tasks(id, thread_id, created_by_agent_id, title)
38
+ values (v_task, v_thread, v_agent, 'SIGNGATEWAY task');
39
+
40
+ insert into agent_board.boards(id, slug, name, created_by_agent_id)
41
+ values (v_board, 'signgateway', 'SIGNGATEWAY', v_agent);
42
+
43
+ insert into agent_board.board_memberships(board_id, agent_id, membership_state, created_by_agent_id)
44
+ values (v_board, v_agent, 'joined', v_agent);
45
+
46
+ insert into agent_board.agent_signing_keys(
47
+ agent_id,
48
+ key_id,
49
+ key_version,
50
+ public_key,
51
+ public_key_format,
52
+ fingerprint,
53
+ status,
54
+ proof_state
55
+ )
56
+ values (
57
+ v_agent,
58
+ 'primary',
59
+ 1,
60
+ repeat('A', 43),
61
+ 'raw_ed25519_base64url',
62
+ 'sha256:' || repeat('A', 43),
63
+ 'active',
64
+ 'proven'
65
+ )
66
+ returning id into v_key;
67
+
68
+ perform agent_board.reserve_signed_write_replay(v_agent, v_key, 'send_direct_message', 'sha256:' || repeat('d', 64), 'nonce-1', null, now(), now() + interval '10 minutes');
69
+
70
+ select *
71
+ into v_direct
72
+ from agent_board.signed_send_direct_message(
73
+ jsonb_build_object(
74
+ 'p_thread_id', v_thread,
75
+ 'p_author_agent_id', v_agent,
76
+ 'p_recipient_agent_id', v_recipient,
77
+ 'p_subject', 'Signed direct',
78
+ 'p_body', 'verified signature direct message',
79
+ 'p_metadata', jsonb_build_object('source', 'test')
80
+ ),
81
+ jsonb_build_object(
82
+ 'agent_id', v_agent,
83
+ 'signing_key_id', v_key,
84
+ 'key_id', 'primary',
85
+ 'key_version', 1,
86
+ 'algorithm', 'Ed25519',
87
+ 'key_fingerprint', 'sha256:' || repeat('A', 43),
88
+ 'verification_status', 'verified',
89
+ 'payload_digest', 'sha256:' || repeat('d', 64),
90
+ 'signature_digest', 'sha256:' || repeat('e', 64),
91
+ 'canonicalization_version', 'agent-provenance-jcs.v1',
92
+ 'signed_at', now(),
93
+ 'verified_at', now(),
94
+ 'nonce', 'nonce-1',
95
+ 'enforcement_mode', 'require_for_agent_writes',
96
+ 'redacted', true
97
+ )
98
+ );
99
+
100
+ select *
101
+ into v_task_event
102
+ from agent_board.signed_append_task_event(
103
+ jsonb_build_object(
104
+ 'p_task_id', v_task,
105
+ 'p_actor_agent_id', v_agent,
106
+ 'p_event_type', 'status_changed',
107
+ 'p_status', 'completed',
108
+ 'p_payload', jsonb_build_object('source', 'test')
109
+ ),
110
+ jsonb_build_object(
111
+ 'agent_id', v_agent,
112
+ 'signing_key_id', v_key,
113
+ 'key_id', 'primary',
114
+ 'key_version', 1,
115
+ 'verification_status', 'verified',
116
+ 'payload_digest', 'sha256:' || repeat('f', 64),
117
+ 'canonicalization_version', 'agent-provenance-jcs.v1',
118
+ 'enforcement_mode', 'require_for_agent_writes',
119
+ 'redacted', true
120
+ )
121
+ );
122
+
123
+ select *
124
+ into v_board_post
125
+ from agent_board.signed_post_board_message(
126
+ jsonb_build_object(
127
+ 'p_thread_id', v_thread,
128
+ 'p_author_agent_id', v_agent,
129
+ 'p_board_id', v_board,
130
+ 'p_subject', 'Signed board',
131
+ 'p_body', 'verified signature board message',
132
+ 'p_metadata', jsonb_build_object('source', 'test')
133
+ ),
134
+ jsonb_build_object(
135
+ 'agent_id', v_agent,
136
+ 'signing_key_id', v_key,
137
+ 'key_id', 'primary',
138
+ 'key_version', 1,
139
+ 'verification_status', 'warn',
140
+ 'payload_digest', 'sha256:' || repeat('b', 64),
141
+ 'canonicalization_version', 'agent-provenance-jcs.v1',
142
+ 'enforcement_mode', 'warn',
143
+ 'redacted', true
144
+ )
145
+ );
146
+ end
147
+ $$;
148
+
149
+ select ok(
150
+ exists (select 1 from agent_board.signature_evidence where operation = 'send_direct_message' and verification_status = 'verified' and source_message_id is not null),
151
+ 'valid signed direct message records linked signature evidence'
152
+ );
153
+
154
+ select ok(
155
+ exists (select 1 from agent_board.signature_evidence where operation = 'append_task_event' and verification_status = 'verified' and source_task_event_id is not null),
156
+ 'valid signed task event records linked signature evidence'
157
+ );
158
+
159
+ select ok(
160
+ exists (select 1 from agent_board.signature_evidence where operation = 'post_board_message' and verification_status = 'warn' and metadata ->> 'metadata-safe' = 'true'),
161
+ 'warn-mode unsigned compatibility can record metadata-safe evidence'
162
+ );
163
+
164
+ select throws_like(
165
+ $$select * from agent_board.reserve_signed_write_replay(
166
+ (select id from agent_board.agents where handle = 'signgateway-agent'),
167
+ (
168
+ select sk.id
169
+ from agent_board.agent_signing_keys sk
170
+ join agent_board.agents a on a.id = sk.agent_id
171
+ where sk.key_id = 'primary'
172
+ and a.handle = 'signgateway-agent'
173
+ ),
174
+ 'send_direct_message',
175
+ 'sha256:' || repeat('d', 64),
176
+ 'nonce-1',
177
+ null,
178
+ now(),
179
+ now() + interval '10 minutes'
180
+ )$$,
181
+ '%nonce_replay%',
182
+ 'replayed nonce is rejected'
183
+ );
184
+
185
+ select throws_like(
186
+ $$select * from agent_board.signed_send_direct_message(
187
+ jsonb_build_object('p_thread_id', gen_random_uuid(), 'p_recipient_agent_id', gen_random_uuid(), 'p_subject', 'x', 'p_body', 'y'),
188
+ jsonb_build_object('verification_status', 'failed', 'failure_class', 'actor_mismatch')
189
+ )$$,
190
+ '%actor_mismatch%',
191
+ 'actor mismatch fails before canonical write'
192
+ );
193
+
194
+ select ok(
195
+ exists (
196
+ select 1 from agent_board.signature_evidence
197
+ where failure_class is null
198
+ and metadata ->> 'redacted' = 'true'
199
+ ),
200
+ 'signature evidence records redaction posture'
201
+ );
202
+
203
+ select ok(
204
+ not exists (
205
+ select 1
206
+ from agent_board.signature_evidence
207
+ where metadata::text ~* 'private key|service-role|secret|raw signature'
208
+ ),
209
+ 'metadata-safe evidence does not store raw private, service-role, secret, or raw signature text'
210
+ );
211
+
212
+ select ok(
213
+ exists (select 1 from agent_board.schema_version where version >= 5),
214
+ 'schema_version preserves SQL-ahead SIGNSTORE compatibility version'
215
+ );
216
+
217
+ select finish();
218
+
219
+ rollback;
@@ -0,0 +1,143 @@
1
+ create extension if not exists pgtap with schema extensions;
2
+ set search_path = extensions, public, agent_board;
3
+
4
+ begin;
5
+
6
+ select plan(7);
7
+
8
+ select has_function('agent_board', 'issue_signing_key_challenge', array['uuid', 'text', 'interval'], 'issue_signing_key_challenge exists');
9
+ select has_function('agent_board', 'record_signing_key_proof_result', array['uuid', 'uuid', 'text', 'boolean', 'text', 'jsonb'], 'record_signing_key_proof_result exists');
10
+
11
+ do $$
12
+ declare
13
+ v_agent uuid := gen_random_uuid();
14
+ v_challenge record;
15
+ v_result record;
16
+ begin
17
+ insert into agent_board.agents(id, agent_type, handle, display_name)
18
+ values (v_agent, 'agent', 'signproof-agent', 'SIGNPROOF Agent');
19
+
20
+ insert into agent_board.agent_signing_keys(
21
+ agent_id,
22
+ key_id,
23
+ key_version,
24
+ public_key,
25
+ public_key_format,
26
+ fingerprint
27
+ )
28
+ values (
29
+ v_agent,
30
+ 'primary',
31
+ 1,
32
+ repeat('A', 43),
33
+ 'raw_ed25519_base64url',
34
+ 'sha256:' || repeat('Z', 43)
35
+ );
36
+
37
+ set local role service_role;
38
+ select * into v_challenge
39
+ from agent_board.issue_signing_key_challenge(v_agent, 'primary', interval '5 minutes');
40
+
41
+ if v_challenge.challenge !~ '^agent-signing-key-proof\.v1:' then
42
+ raise exception 'challenge bytes did not use proof prefix';
43
+ end if;
44
+
45
+ select * into v_result
46
+ from agent_board.record_signing_key_proof_result(
47
+ v_challenge.challenge_id,
48
+ v_agent,
49
+ 'primary',
50
+ true,
51
+ null,
52
+ '{"proofRuntime":"vitest"}'::jsonb
53
+ );
54
+
55
+ if v_result.proof_state <> 'proven' or v_result.verified_at is null then
56
+ raise exception 'verified proof did not activate proof state';
57
+ end if;
58
+
59
+ begin
60
+ perform *
61
+ from agent_board.record_signing_key_proof_result(
62
+ v_challenge.challenge_id,
63
+ v_agent,
64
+ 'primary',
65
+ true,
66
+ null,
67
+ '{}'::jsonb
68
+ );
69
+ raise exception 'challenge replay unexpectedly succeeded';
70
+ exception
71
+ when unique_violation then null;
72
+ end;
73
+ end
74
+ $$;
75
+
76
+ reset role;
77
+
78
+ select pass('challenge issuance records bounded challenge bytes');
79
+ select pass('verified proof activates the signing key');
80
+ select pass('challenge replay is rejected');
81
+
82
+ do $$
83
+ declare
84
+ v_agent uuid := gen_random_uuid();
85
+ v_challenge record;
86
+ v_result record;
87
+ begin
88
+ insert into agent_board.agents(id, agent_type, handle, display_name)
89
+ values (v_agent, 'agent', 'signproof-fail-agent', 'SIGNPROOF Fail Agent');
90
+
91
+ insert into agent_board.agent_signing_keys(
92
+ agent_id,
93
+ key_id,
94
+ key_version,
95
+ public_key,
96
+ public_key_format,
97
+ fingerprint
98
+ )
99
+ values (
100
+ v_agent,
101
+ 'primary',
102
+ 1,
103
+ repeat('B', 43),
104
+ 'raw_ed25519_base64url',
105
+ 'sha256:' || repeat('Y', 43)
106
+ );
107
+
108
+ set local role service_role;
109
+ select * into v_challenge
110
+ from agent_board.issue_signing_key_challenge(v_agent, 'primary', interval '5 minutes');
111
+
112
+ select * into v_result
113
+ from agent_board.record_signing_key_proof_result(
114
+ v_challenge.challenge_id,
115
+ v_agent,
116
+ 'primary',
117
+ false,
118
+ 'signature_invalid',
119
+ '{}'::jsonb
120
+ );
121
+
122
+ if v_result.proof_state <> 'failed' or v_result.failure_class <> 'signature_invalid' then
123
+ raise exception 'failed proof did not preserve signature_invalid failure class';
124
+ end if;
125
+ end
126
+ $$;
127
+
128
+ select pass('failed proof preserves metadata-safe failure class');
129
+
130
+ select ok(
131
+ not exists (
132
+ select 1
133
+ from information_schema.routine_privileges
134
+ where specific_schema = 'agent_board'
135
+ and routine_name in ('issue_signing_key_challenge', 'record_signing_key_proof_result')
136
+ and grantee = 'anon'
137
+ ),
138
+ 'proof RPCs are not executable by anon'
139
+ );
140
+
141
+ select finish();
142
+
143
+ rollback;
@@ -0,0 +1,183 @@
1
+ create extension if not exists pgtap with schema extensions;
2
+ set search_path = extensions, public, agent_board;
3
+
4
+ begin;
5
+
6
+ select plan(16);
7
+
8
+ select has_table('agent_board', 'agent_signing_keys', 'agent_signing_keys exists');
9
+ select has_table('agent_board', 'agent_signing_key_challenges', 'agent_signing_key_challenges exists');
10
+ select has_table('agent_board', 'signature_evidence', 'signature_evidence exists');
11
+ select has_table('agent_board', 'signature_replay_state', 'signature_replay_state exists');
12
+
13
+ select has_column('agent_board', 'agent_signing_keys', 'key_id', 'key_id is stored');
14
+ select has_column('agent_board', 'agent_signing_keys', 'key_version', 'key_version is stored');
15
+ select has_column('agent_board', 'agent_signing_keys', 'fingerprint', 'fingerprint is stored');
16
+ select col_has_check('agent_board', 'agent_signing_keys', 'algorithm', 'algorithm is constrained');
17
+ select col_has_check('agent_board', 'agent_signing_keys', 'public_key_format', 'public key format is constrained');
18
+ select col_has_check('agent_board', 'agent_signing_keys', 'status', 'status is constrained');
19
+ select col_has_check('agent_board', 'agent_signing_keys', 'proof_state', 'proof state is constrained');
20
+ select has_index('agent_board', 'agent_signing_keys', 'agent_signing_keys_key_id_unique', 'key_id is unique per agent');
21
+ select has_index('agent_board', 'agent_signing_keys', 'agent_signing_keys_key_version_unique', 'key_version is unique per agent');
22
+
23
+ do $$
24
+ declare
25
+ v_agent uuid := gen_random_uuid();
26
+ v_message uuid := gen_random_uuid();
27
+ v_thread uuid := gen_random_uuid();
28
+ v_key uuid;
29
+ begin
30
+ insert into agent_board.agents(id, agent_type, handle, display_name)
31
+ values (v_agent, 'agent', 'signstore-agent', 'SIGNSTORE Agent');
32
+
33
+ insert into agent_board.threads(id, created_by_agent_id, subject)
34
+ values (v_thread, v_agent, 'SIGNSTORE thread');
35
+
36
+ insert into agent_board.messages(id, thread_id, author_agent_id, message_sequence, body)
37
+ values (v_message, v_thread, v_agent, 1, 'signed message');
38
+
39
+ insert into agent_board.agent_signing_keys(
40
+ agent_id,
41
+ key_id,
42
+ key_version,
43
+ public_key,
44
+ public_key_format,
45
+ fingerprint,
46
+ status,
47
+ proof_state
48
+ )
49
+ values (
50
+ v_agent,
51
+ 'primary',
52
+ 1,
53
+ repeat('A', 43),
54
+ 'raw_ed25519_base64url',
55
+ 'sha256:' || repeat('A', 43),
56
+ 'active',
57
+ 'proven'
58
+ )
59
+ returning id into v_key;
60
+
61
+ begin
62
+ insert into agent_board.agent_signing_keys(
63
+ agent_id,
64
+ key_id,
65
+ key_version,
66
+ public_key,
67
+ public_key_format,
68
+ fingerprint
69
+ )
70
+ values (
71
+ v_agent,
72
+ 'secondary',
73
+ 1,
74
+ repeat('B', 43),
75
+ 'raw_ed25519_base64url',
76
+ 'sha256:' || repeat('B', 43)
77
+ );
78
+ raise exception 'duplicate key_version unexpectedly succeeded';
79
+ exception
80
+ when unique_violation then null;
81
+ end;
82
+
83
+ begin
84
+ insert into agent_board.agent_signing_keys(
85
+ agent_id,
86
+ key_id,
87
+ key_version,
88
+ public_key,
89
+ public_key_format,
90
+ fingerprint,
91
+ status,
92
+ proof_state
93
+ )
94
+ values (
95
+ v_agent,
96
+ 'unproven-active',
97
+ 2,
98
+ repeat('C', 43),
99
+ 'raw_ed25519_base64url',
100
+ 'sha256:' || repeat('C', 43),
101
+ 'active',
102
+ 'unproven'
103
+ );
104
+ raise exception 'active key without proof unexpectedly succeeded';
105
+ exception
106
+ when check_violation then null;
107
+ end;
108
+
109
+ insert into agent_board.signature_evidence(
110
+ agent_id,
111
+ signing_key_id,
112
+ key_id,
113
+ key_version,
114
+ source_kind,
115
+ source_message_id,
116
+ operation,
117
+ payload_digest,
118
+ signature_digest,
119
+ verification_status,
120
+ verified_at,
121
+ nonce
122
+ )
123
+ values (
124
+ v_agent,
125
+ v_key,
126
+ 'primary',
127
+ 1,
128
+ 'message',
129
+ v_message,
130
+ 'agent_board.post_message',
131
+ 'sha256:' || repeat('d', 64),
132
+ 'sha256:' || repeat('e', 64),
133
+ 'verified',
134
+ now(),
135
+ 'nonce-1'
136
+ );
137
+
138
+ insert into agent_board.signature_replay_state(
139
+ agent_id,
140
+ signing_key_id,
141
+ operation,
142
+ payload_digest,
143
+ nonce,
144
+ envelope_timestamp,
145
+ expires_at
146
+ )
147
+ values (
148
+ v_agent,
149
+ v_key,
150
+ 'agent_board.post_message',
151
+ 'sha256:' || repeat('d', 64),
152
+ 'nonce-1',
153
+ now(),
154
+ now() + interval '10 minutes'
155
+ );
156
+ end
157
+ $$;
158
+
159
+ select pass('signing key uniqueness, proof-state, signature evidence, and replay metadata checks passed');
160
+
161
+ select ok(
162
+ exists (
163
+ select 1
164
+ from agent_board.schema_version
165
+ where version >= 5
166
+ ),
167
+ 'schema_version advanced to SQL-ahead SIGNSTORE version'
168
+ );
169
+
170
+ select ok(
171
+ not exists (
172
+ select 1
173
+ from information_schema.columns
174
+ where table_schema = 'agent_board'
175
+ and table_name in ('agent_signing_keys', 'signature_evidence')
176
+ and column_name ~* 'private|secret|token'
177
+ ),
178
+ 'SIGNSTORE tables do not expose private key, secret, or token columns'
179
+ );
180
+
181
+ select finish();
182
+
183
+ rollback;
@@ -0,0 +1,12 @@
1
+ SELECT plan(8);
2
+
3
+ SELECT has_schema('agent_board', 'agent_board schema exists');
4
+ SELECT has_table('agent_board', 'agents', 'agents table exists');
5
+ SELECT has_table('agent_board', 'tasks', 'tasks table exists');
6
+ SELECT has_table('agent_board', 'claims', 'claims table exists');
7
+ SELECT has_view('agent_board', 'v_thread_feed', 'thread feed view exists');
8
+ SELECT has_view('agent_board', 'v_task_tree', 'task tree view exists');
9
+ SELECT has_view('agent_board', 'v_active_claims', 'active claims view exists');
10
+ SELECT has_function('agent_board', 'acquire_claim', ARRAY['uuid', 'text', 'text', 'timestamp with time zone', 'uuid', 'uuid', 'jsonb'], 'acquire_claim rpc exists');
11
+
12
+ SELECT finish();