@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,509 @@
1
+ create or replace function agent_board.register_fleet_machine(
2
+ p_owner_agent_id uuid,
3
+ p_trust_domain_id uuid,
4
+ p_machine_label text,
5
+ p_machine_fingerprint text,
6
+ p_enrollment_source text default 'portal',
7
+ p_metadata jsonb default '{}'::jsonb
8
+ )
9
+ returns table(machine_id uuid, trust_domain_id uuid, lifecycle_state text, enrolled_at timestamptz)
10
+ language plpgsql
11
+ security definer
12
+ set search_path = agent_board, public
13
+ as $$
14
+ declare
15
+ v_machine agent_board.fleet_machines%rowtype;
16
+ v_actor_agent_id uuid;
17
+ begin
18
+ if nullif(trim(p_machine_label), '') is null or nullif(trim(p_machine_fingerprint), '') is null then
19
+ raise exception 'machine label and fingerprint are required' using errcode = '22023';
20
+ end if;
21
+
22
+ v_actor_agent_id := agent_board._resolved_actor_agent_id(p_owner_agent_id, 'p_owner_agent_id');
23
+
24
+ if not exists (
25
+ select 1
26
+ from agent_board.fleet_trust_domains ftd
27
+ where ftd.id = p_trust_domain_id
28
+ and ftd.owner_agent_id = v_actor_agent_id
29
+ and ftd.lifecycle_state in ('active', 'pending')
30
+ ) then
31
+ raise exception 'trust domain is not active for owner' using errcode = '42501';
32
+ end if;
33
+
34
+ insert into agent_board.fleet_machines(
35
+ trust_domain_id,
36
+ owner_agent_id,
37
+ machine_label,
38
+ machine_fingerprint,
39
+ lifecycle_state,
40
+ enrollment_source,
41
+ enrolled_at,
42
+ revoked_at,
43
+ metadata
44
+ )
45
+ values (
46
+ p_trust_domain_id,
47
+ v_actor_agent_id,
48
+ trim(p_machine_label),
49
+ trim(p_machine_fingerprint),
50
+ 'active',
51
+ coalesce(nullif(p_enrollment_source, ''), 'portal'),
52
+ now(),
53
+ null,
54
+ coalesce(p_metadata, '{}'::jsonb) || jsonb_build_object('redacted', true, 'metadata-safe', true)
55
+ )
56
+ on conflict (machine_fingerprint)
57
+ do update set
58
+ trust_domain_id = excluded.trust_domain_id,
59
+ owner_agent_id = excluded.owner_agent_id,
60
+ machine_label = excluded.machine_label,
61
+ lifecycle_state = 'active',
62
+ enrollment_source = excluded.enrollment_source,
63
+ enrolled_at = coalesce(agent_board.fleet_machines.enrolled_at, excluded.enrolled_at),
64
+ revoked_at = null,
65
+ metadata = excluded.metadata,
66
+ updated_at = now()
67
+ returning * into v_machine;
68
+
69
+ return query select v_machine.id, v_machine.trust_domain_id, v_machine.lifecycle_state, v_machine.enrolled_at;
70
+ end;
71
+ $$;
72
+
73
+ create or replace function agent_board.set_fleet_receive_policy(
74
+ p_recipient_agent_id uuid,
75
+ p_policy_name text,
76
+ p_default_action text default 'deny',
77
+ p_require_signed_sender boolean default false,
78
+ p_board_id uuid default null,
79
+ p_trust_domain_id uuid default null,
80
+ p_metadata jsonb default '{}'::jsonb
81
+ )
82
+ returns table(receive_policy_id uuid, default_action text, require_signed_sender boolean, lifecycle_state text)
83
+ language plpgsql
84
+ security definer
85
+ set search_path = agent_board, public
86
+ as $$
87
+ declare
88
+ v_policy agent_board.fleet_receive_policies%rowtype;
89
+ v_actor_agent_id uuid;
90
+ begin
91
+ if p_recipient_agent_id is null and p_board_id is null and p_trust_domain_id is null then
92
+ raise exception 'receive policy target is required' using errcode = '22023';
93
+ end if;
94
+
95
+ if nullif(trim(p_policy_name), '') is null then
96
+ raise exception 'policy name is required' using errcode = '22023';
97
+ end if;
98
+
99
+ if coalesce(p_default_action, 'deny') not in ('allow', 'deny', 'quarantine', 'non_actionable') then
100
+ raise exception 'unsupported fleet receive action' using errcode = '22023';
101
+ end if;
102
+
103
+ if not agent_board._is_service_role() then
104
+ v_actor_agent_id := agent_board.current_agent_id();
105
+ if v_actor_agent_id is null then
106
+ raise exception 'current agent principal not resolved' using errcode = '42501';
107
+ end if;
108
+ if p_recipient_agent_id is not null and p_recipient_agent_id <> v_actor_agent_id then
109
+ raise exception 'p_recipient_agent_id must match current_agent_id()' using errcode = '42501';
110
+ end if;
111
+ if p_trust_domain_id is not null and not exists (
112
+ select 1
113
+ from agent_board.fleet_trust_domains ftd
114
+ where ftd.id = p_trust_domain_id
115
+ and ftd.owner_agent_id = v_actor_agent_id
116
+ ) then
117
+ raise exception 'trust domain is not owned by current_agent_id()' using errcode = '42501';
118
+ end if;
119
+ if p_board_id is not null and not exists (
120
+ select 1
121
+ from agent_board.boards b
122
+ where b.id = p_board_id
123
+ and b.created_by_agent_id = v_actor_agent_id
124
+ union all
125
+ select 1
126
+ from agent_board.board_memberships bm
127
+ where bm.board_id = p_board_id
128
+ and bm.agent_id = v_actor_agent_id
129
+ and bm.membership_state in ('joined', 'subscribed')
130
+ limit 1
131
+ ) then
132
+ raise exception 'board is not accessible by current_agent_id()' using errcode = '42501';
133
+ end if;
134
+ end if;
135
+
136
+ select *
137
+ into v_policy
138
+ from agent_board.fleet_receive_policies frp
139
+ where frp.recipient_agent_id is not distinct from p_recipient_agent_id
140
+ and frp.board_id is not distinct from p_board_id
141
+ and frp.trust_domain_id is not distinct from p_trust_domain_id
142
+ and frp.policy_name = trim(p_policy_name)
143
+ order by frp.created_at
144
+ limit 1;
145
+
146
+ if v_policy.id is null then
147
+ insert into agent_board.fleet_receive_policies(
148
+ recipient_agent_id,
149
+ board_id,
150
+ trust_domain_id,
151
+ policy_name,
152
+ default_action,
153
+ require_signed_sender,
154
+ lifecycle_state,
155
+ metadata
156
+ )
157
+ values (
158
+ p_recipient_agent_id,
159
+ p_board_id,
160
+ p_trust_domain_id,
161
+ trim(p_policy_name),
162
+ coalesce(p_default_action, 'deny'),
163
+ coalesce(p_require_signed_sender, false),
164
+ 'active',
165
+ coalesce(p_metadata, '{}'::jsonb) || jsonb_build_object('redacted', true, 'metadata-safe', true)
166
+ )
167
+ returning * into v_policy;
168
+ else
169
+ update agent_board.fleet_receive_policies
170
+ set default_action = coalesce(p_default_action, 'deny'),
171
+ require_signed_sender = coalesce(p_require_signed_sender, false),
172
+ lifecycle_state = 'active',
173
+ revoked_at = null,
174
+ metadata = coalesce(p_metadata, '{}'::jsonb) || jsonb_build_object('redacted', true, 'metadata-safe', true),
175
+ updated_at = now()
176
+ where id = v_policy.id
177
+ returning * into v_policy;
178
+ end if;
179
+
180
+ return query select v_policy.id, v_policy.default_action, v_policy.require_signed_sender, v_policy.lifecycle_state;
181
+ end;
182
+ $$;
183
+
184
+ create or replace function agent_board.evaluate_fleet_sender_policy(
185
+ p_sender_agent_id uuid,
186
+ p_recipient_agent_id uuid,
187
+ p_sender_machine_id uuid default null,
188
+ p_recipient_board_id uuid default null,
189
+ p_operation text default 'send_direct_message',
190
+ p_signature_evidence_id uuid default null,
191
+ p_direct_rpc_compatibility boolean default false
192
+ )
193
+ returns table(
194
+ allowed boolean,
195
+ actionable boolean,
196
+ denial_class text,
197
+ receive_policy_id uuid,
198
+ trust_domain_id uuid,
199
+ trust_set_id uuid,
200
+ requires_signature boolean,
201
+ evaluated_at timestamptz
202
+ )
203
+ language plpgsql
204
+ security definer
205
+ set search_path = agent_board, public
206
+ as $$
207
+ declare
208
+ v_machine agent_board.fleet_machines%rowtype;
209
+ v_binding agent_board.fleet_machine_agents%rowtype;
210
+ v_policy agent_board.fleet_receive_policies%rowtype;
211
+ v_trust_set agent_board.fleet_trust_sets%rowtype;
212
+ v_signature agent_board.signature_evidence%rowtype;
213
+ v_actor_agent_id uuid;
214
+ v_action text;
215
+ v_denial text;
216
+ begin
217
+ if not agent_board._is_service_role() then
218
+ v_actor_agent_id := agent_board.current_agent_id();
219
+ if v_actor_agent_id is null
220
+ or (v_actor_agent_id <> p_sender_agent_id and v_actor_agent_id <> p_recipient_agent_id) then
221
+ raise exception 'fleet policy evaluation must involve current_agent_id()' using errcode = '42501';
222
+ end if;
223
+ end if;
224
+
225
+ select fma.*
226
+ into v_binding
227
+ from agent_board.fleet_machine_agents fma
228
+ join agent_board.fleet_machines fm on fm.id = fma.machine_id
229
+ where fma.agent_id = p_sender_agent_id
230
+ and fma.lifecycle_state = 'active'
231
+ and fm.lifecycle_state = 'active'
232
+ and (p_sender_machine_id is null or fma.machine_id = p_sender_machine_id)
233
+ order by fma.updated_at desc
234
+ limit 1;
235
+
236
+ if v_binding.id is not null then
237
+ select * into v_machine from agent_board.fleet_machines where id = v_binding.machine_id;
238
+ elsif p_sender_machine_id is not null then
239
+ select * into v_machine from agent_board.fleet_machines where id = p_sender_machine_id;
240
+ end if;
241
+
242
+ if v_machine.id is null then
243
+ return query select false, false, 'domain_denied'::text, null::uuid, null::uuid, null::uuid, false, now();
244
+ return;
245
+ end if;
246
+
247
+ if v_machine.lifecycle_state = 'revoked'
248
+ or exists (
249
+ select 1 from agent_board.fleet_revocation_events fre
250
+ where (fre.subject_kind = 'machine' and fre.subject_id = v_machine.id)
251
+ or (fre.subject_kind = 'trust_domain' and fre.subject_id = v_machine.trust_domain_id)
252
+ or (fre.subject_kind = 'agent' and fre.subject_id = p_sender_agent_id)
253
+ ) then
254
+ return query select false, false, 'machine_revoked'::text, null::uuid, v_machine.trust_domain_id, null::uuid, false, now();
255
+ return;
256
+ end if;
257
+
258
+ select frp.*
259
+ into v_policy
260
+ from agent_board.fleet_receive_policies frp
261
+ where frp.lifecycle_state = 'active'
262
+ and (frp.recipient_agent_id is null or frp.recipient_agent_id = p_recipient_agent_id)
263
+ and (frp.board_id is null or frp.board_id = p_recipient_board_id)
264
+ and (frp.trust_domain_id is null or frp.trust_domain_id = v_machine.trust_domain_id)
265
+ order by
266
+ case when frp.board_id is not null then 0 else 1 end,
267
+ case when frp.trust_domain_id is not null then 0 else 1 end,
268
+ frp.updated_at desc
269
+ limit 1;
270
+
271
+ if v_policy.id is null then
272
+ return query select false, false, 'recipient_policy_denied'::text, null::uuid, v_machine.trust_domain_id, null::uuid, false, now();
273
+ return;
274
+ end if;
275
+
276
+ if v_policy.require_signed_sender then
277
+ if p_signature_evidence_id is null then
278
+ return query select false, false, 'signature_required'::text, v_policy.id, v_machine.trust_domain_id, null::uuid, true, now();
279
+ return;
280
+ end if;
281
+
282
+ select * into v_signature from agent_board.signature_evidence where id = p_signature_evidence_id;
283
+ if v_signature.id is null or v_signature.agent_id <> p_sender_agent_id then
284
+ return query select false, false, 'signature_required'::text, v_policy.id, v_machine.trust_domain_id, null::uuid, true, now();
285
+ return;
286
+ end if;
287
+
288
+ if v_signature.failure_class = 'key_revoked'
289
+ or exists (
290
+ select 1
291
+ from agent_board.fleet_revocation_events fre
292
+ where fre.subject_kind = 'signing_key'
293
+ and fre.subject_id = v_signature.signing_key_id
294
+ )
295
+ or exists (
296
+ select 1
297
+ from agent_board.agent_signing_keys ask
298
+ where ask.id = v_signature.signing_key_id
299
+ and ask.status in ('revoked', 'compromised')
300
+ ) then
301
+ return query select false, false, 'key_revoked'::text, v_policy.id, v_machine.trust_domain_id, null::uuid, true, now();
302
+ return;
303
+ end if;
304
+
305
+ if v_signature.verification_status not in ('verified', 'warn', 'observed') then
306
+ return query select false, false, 'signature_required'::text, v_policy.id, v_machine.trust_domain_id, null::uuid, true, now();
307
+ return;
308
+ end if;
309
+ end if;
310
+
311
+ select fts.*
312
+ into v_trust_set
313
+ from agent_board.fleet_trust_sets fts
314
+ where fts.receive_policy_id = v_policy.id
315
+ and fts.lifecycle_state = 'active'
316
+ and (
317
+ fts.trust_domain_id = v_machine.trust_domain_id
318
+ or fts.machine_id = v_machine.id
319
+ or fts.agent_id = p_sender_agent_id
320
+ or (v_binding.repo_scope_id is not null and fts.repo_scope_id = v_binding.repo_scope_id)
321
+ or exists (
322
+ select 1
323
+ from agent_board.fleet_repo_scopes frs
324
+ where frs.id = v_binding.repo_scope_id
325
+ and fts.harness_registration_id = frs.harness_registration_id
326
+ )
327
+ )
328
+ order by
329
+ case fts.effect
330
+ when 'deny' then 0
331
+ when 'quarantine' then 1
332
+ when 'non_actionable' then 2
333
+ else 3
334
+ end,
335
+ fts.updated_at desc
336
+ limit 1;
337
+
338
+ v_action := coalesce(v_trust_set.effect, v_policy.default_action);
339
+ v_denial := case
340
+ when v_action = 'deny' and v_trust_set.id is not null then 'sender_denied'
341
+ when v_action = 'deny' then 'recipient_policy_denied'
342
+ when v_action = 'quarantine' then 'quarantined'
343
+ else null
344
+ end;
345
+
346
+ return query
347
+ select
348
+ v_action in ('allow', 'non_actionable'),
349
+ v_action = 'allow',
350
+ v_denial,
351
+ v_policy.id,
352
+ v_machine.trust_domain_id,
353
+ v_trust_set.id,
354
+ v_policy.require_signed_sender,
355
+ now();
356
+ end;
357
+ $$;
358
+
359
+ create or replace function agent_board.revoke_fleet_subject(
360
+ p_subject_kind text,
361
+ p_subject_id uuid,
362
+ p_revoked_by_agent_id uuid,
363
+ p_revocation_reason text,
364
+ p_metadata jsonb default '{}'::jsonb
365
+ )
366
+ returns table(revocation_event_id uuid, subject_kind text, effective_at timestamptz)
367
+ language plpgsql
368
+ security definer
369
+ set search_path = agent_board, public
370
+ as $$
371
+ declare
372
+ v_event agent_board.fleet_revocation_events%rowtype;
373
+ v_actor_agent_id uuid;
374
+ begin
375
+ if p_subject_kind not in ('trust_domain', 'machine', 'harness', 'repo_scope', 'agent', 'signing_key', 'credential') then
376
+ raise exception 'unsupported fleet revocation subject' using errcode = '22023';
377
+ end if;
378
+
379
+ v_actor_agent_id := agent_board._resolved_actor_agent_id(p_revoked_by_agent_id, 'p_revoked_by_agent_id');
380
+
381
+ if not agent_board._is_service_role() then
382
+ if p_subject_kind = 'trust_domain' and not exists (
383
+ select 1 from agent_board.fleet_trust_domains ftd
384
+ where ftd.id = p_subject_id and ftd.owner_agent_id = v_actor_agent_id
385
+ ) then
386
+ raise exception 'trust domain is not owned by current_agent_id()' using errcode = '42501';
387
+ elsif p_subject_kind = 'machine' and not exists (
388
+ select 1 from agent_board.fleet_machines fm
389
+ where fm.id = p_subject_id and fm.owner_agent_id = v_actor_agent_id
390
+ ) then
391
+ raise exception 'machine is not owned by current_agent_id()' using errcode = '42501';
392
+ elsif p_subject_kind = 'harness' and not exists (
393
+ select 1
394
+ from agent_board.fleet_harness_registrations fhr
395
+ join agent_board.fleet_machines fm on fm.id = fhr.machine_id
396
+ where fhr.id = p_subject_id and fm.owner_agent_id = v_actor_agent_id
397
+ ) then
398
+ raise exception 'harness is not owned by current_agent_id()' using errcode = '42501';
399
+ elsif p_subject_kind = 'repo_scope' and not exists (
400
+ select 1
401
+ from agent_board.fleet_repo_scopes frs
402
+ join agent_board.fleet_harness_registrations fhr on fhr.id = frs.harness_registration_id
403
+ join agent_board.fleet_machines fm on fm.id = fhr.machine_id
404
+ where frs.id = p_subject_id and fm.owner_agent_id = v_actor_agent_id
405
+ ) then
406
+ raise exception 'repo scope is not owned by current_agent_id()' using errcode = '42501';
407
+ elsif p_subject_kind = 'agent' and p_subject_id <> v_actor_agent_id then
408
+ raise exception 'agent revocation must target current_agent_id()' using errcode = '42501';
409
+ elsif p_subject_kind = 'signing_key' and not exists (
410
+ select 1 from agent_board.agent_signing_keys ask
411
+ where ask.id = p_subject_id and ask.agent_id = v_actor_agent_id
412
+ ) then
413
+ raise exception 'signing key is not owned by current_agent_id()' using errcode = '42501';
414
+ elsif p_subject_kind = 'credential' and not exists (
415
+ select 1 from agent_board.agent_credentials ac
416
+ where ac.id = p_subject_id and ac.agent_id = v_actor_agent_id
417
+ ) then
418
+ raise exception 'credential is not owned by current_agent_id()' using errcode = '42501';
419
+ end if;
420
+ end if;
421
+
422
+ select *
423
+ into v_event
424
+ from agent_board.fleet_revocation_events fre
425
+ where fre.subject_kind = p_subject_kind
426
+ and fre.subject_id = p_subject_id
427
+ limit 1;
428
+
429
+ if v_event.id is null then
430
+ insert into agent_board.fleet_revocation_events(
431
+ subject_kind,
432
+ subject_id,
433
+ trust_domain_id,
434
+ machine_id,
435
+ harness_registration_id,
436
+ repo_scope_id,
437
+ agent_id,
438
+ signing_key_id,
439
+ revoked_by_agent_id,
440
+ revocation_reason,
441
+ metadata
442
+ )
443
+ values (
444
+ p_subject_kind,
445
+ p_subject_id,
446
+ case when p_subject_kind = 'trust_domain' then p_subject_id end,
447
+ case when p_subject_kind = 'machine' then p_subject_id end,
448
+ case when p_subject_kind = 'harness' then p_subject_id end,
449
+ case when p_subject_kind = 'repo_scope' then p_subject_id end,
450
+ case when p_subject_kind = 'agent' then p_subject_id end,
451
+ case when p_subject_kind = 'signing_key' then p_subject_id end,
452
+ p_revoked_by_agent_id,
453
+ trim(coalesce(p_revocation_reason, 'operator revocation')),
454
+ coalesce(p_metadata, '{}'::jsonb) || jsonb_build_object('redacted', true, 'metadata-safe', true)
455
+ )
456
+ returning * into v_event;
457
+ else
458
+ update agent_board.fleet_revocation_events fre
459
+ set revoked_by_agent_id = p_revoked_by_agent_id,
460
+ revocation_reason = trim(coalesce(p_revocation_reason, 'operator revocation')),
461
+ metadata = coalesce(p_metadata, '{}'::jsonb) || jsonb_build_object('redacted', true, 'metadata-safe', true)
462
+ where fre.id = v_event.id
463
+ returning * into v_event;
464
+ end if;
465
+
466
+ if p_subject_kind = 'trust_domain' then
467
+ update agent_board.fleet_trust_domains
468
+ set lifecycle_state = 'revoked', revoked_at = v_event.effective_at, updated_at = now()
469
+ where id = p_subject_id;
470
+ elsif p_subject_kind = 'machine' then
471
+ update agent_board.fleet_machines
472
+ set lifecycle_state = 'revoked', revoked_at = v_event.effective_at, updated_at = now()
473
+ where id = p_subject_id;
474
+ elsif p_subject_kind = 'harness' then
475
+ update agent_board.fleet_harness_registrations
476
+ set lifecycle_state = 'revoked', revoked_at = v_event.effective_at, updated_at = now()
477
+ where id = p_subject_id;
478
+ elsif p_subject_kind = 'repo_scope' then
479
+ update agent_board.fleet_repo_scopes
480
+ set lifecycle_state = 'revoked', revoked_at = v_event.effective_at, updated_at = now()
481
+ where id = p_subject_id;
482
+ elsif p_subject_kind = 'agent' then
483
+ update agent_board.fleet_machine_agents
484
+ set lifecycle_state = 'revoked', revoked_at = v_event.effective_at, updated_at = now()
485
+ where agent_id = p_subject_id;
486
+ elsif p_subject_kind = 'signing_key' then
487
+ update agent_board.agent_signing_keys
488
+ set status = case when status = 'compromised' then status else 'revoked' end,
489
+ proof_state = 'revoked',
490
+ revoked_at = coalesce(revoked_at, v_event.effective_at),
491
+ revoked_by_agent_id = p_revoked_by_agent_id,
492
+ revocation_reason = trim(coalesce(p_revocation_reason, 'operator revocation')),
493
+ updated_at = now()
494
+ where id = p_subject_id;
495
+ end if;
496
+
497
+ return query select v_event.id, v_event.subject_kind, v_event.effective_at;
498
+ end;
499
+ $$;
500
+
501
+ revoke all on function agent_board.register_fleet_machine(uuid, uuid, text, text, text, jsonb) from public, anon;
502
+ revoke all on function agent_board.set_fleet_receive_policy(uuid, text, text, boolean, uuid, uuid, jsonb) from public, anon;
503
+ revoke all on function agent_board.evaluate_fleet_sender_policy(uuid, uuid, uuid, uuid, text, uuid, boolean) from public, anon;
504
+ revoke all on function agent_board.revoke_fleet_subject(text, uuid, uuid, text, jsonb) from public, anon;
505
+
506
+ grant execute on function agent_board.register_fleet_machine(uuid, uuid, text, text, text, jsonb) to authenticated, service_role;
507
+ grant execute on function agent_board.set_fleet_receive_policy(uuid, text, text, boolean, uuid, uuid, jsonb) to authenticated, service_role;
508
+ grant execute on function agent_board.evaluate_fleet_sender_policy(uuid, uuid, uuid, uuid, text, uuid, boolean) to authenticated, service_role;
509
+ grant execute on function agent_board.revoke_fleet_subject(text, uuid, uuid, text, jsonb) to authenticated, service_role;
@@ -0,0 +1,170 @@
1
+ create or replace view agent_board.v_fleet_machine_status
2
+ with (security_invoker = true)
3
+ as
4
+ select
5
+ fm.id as machine_id,
6
+ fm.trust_domain_id,
7
+ ftd.slug as trust_domain_slug,
8
+ ftd.domain_kind,
9
+ fm.owner_agent_id,
10
+ fm.machine_label,
11
+ fm.machine_fingerprint,
12
+ fm.lifecycle_state as machine_lifecycle_state,
13
+ fm.enrollment_source,
14
+ fm.enrolled_at,
15
+ fm.revoked_at,
16
+ exists (
17
+ select 1
18
+ from agent_board.fleet_revocation_events fre
19
+ where fre.subject_kind = 'machine'
20
+ and fre.subject_id = fm.id
21
+ ) as machine_revoked,
22
+ coalesce(active_agents.active_agent_count, 0)::bigint as active_agent_count,
23
+ active_agents.latest_agent_binding_updated_at
24
+ from agent_board.fleet_machines fm
25
+ join agent_board.fleet_trust_domains ftd on ftd.id = fm.trust_domain_id
26
+ left join lateral (
27
+ select
28
+ count(*) filter (where fma.lifecycle_state = 'active') as active_agent_count,
29
+ max(fma.updated_at) as latest_agent_binding_updated_at
30
+ from agent_board.fleet_machine_agents fma
31
+ where fma.machine_id = fm.id
32
+ ) active_agents on true;
33
+
34
+ create or replace view agent_board.v_fleet_receive_policy_status
35
+ with (security_invoker = true)
36
+ as
37
+ select
38
+ frp.id as receive_policy_id,
39
+ frp.recipient_agent_id,
40
+ frp.board_id,
41
+ frp.trust_domain_id,
42
+ frp.policy_name,
43
+ frp.default_action,
44
+ frp.require_signed_sender,
45
+ frp.lifecycle_state,
46
+ coalesce(trust_sets.allow_trust_set_count, 0)::bigint as allow_trust_set_count,
47
+ coalesce(trust_sets.restrictive_trust_set_count, 0)::bigint as restrictive_trust_set_count,
48
+ frp.updated_at
49
+ from agent_board.fleet_receive_policies frp
50
+ left join lateral (
51
+ select
52
+ count(*) filter (where fts.effect = 'allow' and fts.lifecycle_state = 'active') as allow_trust_set_count,
53
+ count(*) filter (where fts.effect in ('deny', 'quarantine', 'non_actionable') and fts.lifecycle_state = 'active') as restrictive_trust_set_count
54
+ from agent_board.fleet_trust_sets fts
55
+ where fts.receive_policy_id = frp.id
56
+ ) trust_sets on true;
57
+
58
+ drop view if exists agent_board.v_fleet_delivery_posture;
59
+
60
+ create or replace view agent_board.v_fleet_delivery_posture
61
+ with (security_invoker = true)
62
+ as
63
+ select
64
+ dr.id as delivery_recipient_id,
65
+ dr.recipient_agent_id,
66
+ dr.delivery_mode,
67
+ dr.source_kind,
68
+ dr.source_message_id,
69
+ dr.source_task_id,
70
+ dr.source_delegation_id,
71
+ dr.board_id,
72
+ coalesce(m.author_agent_id, t.created_by_agent_id, d.delegated_by_agent_id) as sender_agent_id,
73
+ fm.id as sender_machine_id,
74
+ fm.trust_domain_id,
75
+ frp.id as receive_policy_id,
76
+ frp.require_signed_sender as requires_signature,
77
+ fts.id as trust_set_id,
78
+ coalesce(fts.effect, frp.default_action) as policy_action,
79
+ case
80
+ when fm.id is null then 'domain_denied'
81
+ when fm.lifecycle_state = 'revoked' then 'machine_revoked'
82
+ when frp.id is null then 'recipient_policy_denied'
83
+ when frp.require_signed_sender and se.id is null then 'signature_required'
84
+ when se.failure_class = 'key_revoked' or ask.status in ('revoked', 'compromised') then 'key_revoked'
85
+ when coalesce(fts.effect, frp.default_action) = 'quarantine' then 'quarantined'
86
+ when coalesce(fts.effect, frp.default_action) = 'deny' and fts.id is not null then 'sender_denied'
87
+ when coalesce(fts.effect, frp.default_action) = 'deny' then 'recipient_policy_denied'
88
+ else null
89
+ end as denial_class,
90
+ coalesce(fts.effect, frp.default_action) in ('allow', 'non_actionable') as allowed,
91
+ coalesce(fts.effect, frp.default_action) = 'allow' and coalesce(ii.visible_in_inbox, true) as actionable,
92
+ se.id as signature_evidence_id,
93
+ se.verification_status,
94
+ ask.fingerprint as key_fingerprint,
95
+ se.key_version,
96
+ se.algorithm,
97
+ se.verified_at,
98
+ ii.action_state as inbox_action_state,
99
+ ii.fetch_descriptor,
100
+ dr.created_at
101
+ from agent_board.delivery_recipients dr
102
+ left join agent_board.messages m on m.id = dr.source_message_id
103
+ left join agent_board.tasks t on t.id = dr.source_task_id
104
+ left join agent_board.delegations d on d.id = dr.source_delegation_id
105
+ left join agent_board.inbox_items ii on ii.delivery_recipient_id = dr.id
106
+ left join lateral (
107
+ select fma.*
108
+ from agent_board.fleet_machine_agents fma
109
+ join agent_board.fleet_machines fm_inner on fm_inner.id = fma.machine_id
110
+ where fma.agent_id = coalesce(m.author_agent_id, t.created_by_agent_id, d.delegated_by_agent_id)
111
+ and fma.lifecycle_state = 'active'
112
+ and fm_inner.lifecycle_state = 'active'
113
+ order by fma.updated_at desc
114
+ limit 1
115
+ ) fma on true
116
+ left join agent_board.fleet_machines fm on fm.id = fma.machine_id
117
+ left join lateral (
118
+ select frp_inner.*
119
+ from agent_board.fleet_receive_policies frp_inner
120
+ where frp_inner.lifecycle_state = 'active'
121
+ and (frp_inner.recipient_agent_id is null or frp_inner.recipient_agent_id = dr.recipient_agent_id)
122
+ and (frp_inner.board_id is null or frp_inner.board_id = dr.board_id)
123
+ and (frp_inner.trust_domain_id is null or frp_inner.trust_domain_id = fm.trust_domain_id)
124
+ order by
125
+ case when frp_inner.board_id is not null then 0 else 1 end,
126
+ case when frp_inner.trust_domain_id is not null then 0 else 1 end,
127
+ frp_inner.updated_at desc
128
+ limit 1
129
+ ) frp on true
130
+ left join lateral (
131
+ select fts_inner.*
132
+ from agent_board.fleet_trust_sets fts_inner
133
+ where fts_inner.receive_policy_id = frp.id
134
+ and fts_inner.lifecycle_state = 'active'
135
+ and (
136
+ fts_inner.trust_domain_id = fm.trust_domain_id
137
+ or fts_inner.machine_id = fm.id
138
+ or fts_inner.agent_id = coalesce(m.author_agent_id, t.created_by_agent_id, d.delegated_by_agent_id)
139
+ or fts_inner.repo_scope_id = fma.repo_scope_id
140
+ )
141
+ order by
142
+ case fts_inner.effect
143
+ when 'deny' then 0
144
+ when 'quarantine' then 1
145
+ when 'non_actionable' then 2
146
+ else 3
147
+ end,
148
+ fts_inner.updated_at desc
149
+ limit 1
150
+ ) fts on true
151
+ left join lateral (
152
+ select se_inner.*
153
+ from agent_board.signature_evidence se_inner
154
+ where (se_inner.source_kind = 'delivery_recipient' and se_inner.source_delivery_recipient_id = dr.id)
155
+ or (se_inner.source_kind = 'message' and se_inner.source_message_id = dr.source_message_id)
156
+ or (se_inner.source_kind = 'task_event' and exists (
157
+ select 1
158
+ from agent_board.task_events te
159
+ where te.id = se_inner.source_task_event_id
160
+ and te.task_id = dr.source_task_id
161
+ ))
162
+ order by se_inner.created_at desc
163
+ limit 1
164
+ ) se on true
165
+ left join agent_board.agent_signing_keys ask on ask.id = se.signing_key_id;
166
+
167
+ grant select on agent_board.v_fleet_machine_status,
168
+ agent_board.v_fleet_receive_policy_status,
169
+ agent_board.v_fleet_delivery_posture
170
+ to authenticated, service_role;