@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.
- package/LICENSE +202 -0
- package/NOTICE +11 -0
- package/README.md +55 -0
- package/bin/agent-board-schema.js +97 -0
- package/fixtures/already-applied.json +181 -0
- package/fixtures/divergent-history.json +173 -0
- package/fixtures/production-history.json +173 -0
- package/migrations/20260501000001_agent_board_schema_version.sql +12 -0
- package/migrations/20260502000000_agent_board_schema.sql +180 -0
- package/migrations/20260503000000_agent_board_rpcs.sql +422 -0
- package/migrations/20260503000001_agent_board_coordination_rpcs.sql +229 -0
- package/migrations/20260504000000_agent_board_read_models.sql +206 -0
- package/migrations/20260505000000_agent_board_inbox_schema.sql +341 -0
- package/migrations/20260506000000_agent_board_inbox_delivery_rpcs.sql +1200 -0
- package/migrations/20260506000001_agent_board_inbox_callback_rpcs.sql +330 -0
- package/migrations/20260507000000_agent_board_inbox_reads.sql +334 -0
- package/migrations/20260508000000_agent_board_callback_runtime.sql +453 -0
- package/migrations/20260508000001_agent_board_inbox_service_role_reads.sql +10 -0
- package/migrations/20260510000000_agent_board_dblint_repairs.sql +413 -0
- package/migrations/20260511000000_agent_board_auth_schema.sql +146 -0
- package/migrations/20260511000001_agent_board_auth_credentials.sql +39 -0
- package/migrations/20260512000000_agent_board_auth_provisioning_rpcs.sql +622 -0
- package/migrations/20260512000001_agent_board_auth_v1_rpcs.sql +798 -0
- package/migrations/20260512000002_agent_board_auth_v2_rpcs.sql +1243 -0
- package/migrations/20260512000003_agent_board_auth_rls.sql +484 -0
- package/migrations/20260513000000_agent_board_backup_ops.sql +34 -0
- package/migrations/20260513000001_agent_board_retention.sql +160 -0
- package/migrations/20260513000002_agent_board_monitoring_views.sql +227 -0
- package/migrations/20260514000000_agent_board_auth_rls_id_qualification.sql +150 -0
- package/migrations/20260515000000_agent_board_boardopt.sql +493 -0
- package/migrations/20260516000000_agent_board_callbackcap.sql +113 -0
- package/migrations/20260517000000_agent_board_addressing.sql +542 -0
- package/migrations/20260628000000_agent_board_signing_store.sql +174 -0
- package/migrations/20260628000001_agent_board_signing_proof_rpcs.sql +215 -0
- package/migrations/20260628000002_agent_board_signature_rls_reads.sql +300 -0
- package/migrations/20260628000003_agent_board_signed_write_gateway.sql +288 -0
- package/migrations/20260628000004_agent_board_fleet_registry.sql +411 -0
- package/migrations/20260628000005_agent_board_fleet_policy.sql +509 -0
- package/migrations/20260628000006_agent_board_fleet_read_models.sql +170 -0
- package/migrations/20260629000100_agent_board_fleet_registry_repair.sql +411 -0
- package/migrations/20260629000101_agent_board_fleet_policy_refresh.sql +509 -0
- package/migrations/20260629000102_agent_board_fleet_read_models_refresh.sql +170 -0
- package/migrations/20260630000100_agent_board_harness_kind_open_vocab.sql +15 -0
- package/migrations/20260710000000_agent_board_authbound_boundary.sql +155 -0
- package/migrations/20260710000100_agent_board_schema_version_rpc.sql +14 -0
- package/migrations/20260710000400_agent_board_nonfleet_identity.sql +87 -0
- package/migrations/20260710000401_agent_board_workload_providers.sql +39 -0
- package/migrations/20260711000000_agent_board_provision_system_fail_closed.sql +242 -0
- package/migrations/20260711000100_canary_signed_fleet_enforcement.sql +234 -0
- package/migrations/20260712000000_agent_board_bundle_endpoint_compat.sql +97 -0
- package/migrations/20260713000000_agent_board_rls_reassert_board_scoping.sql +90 -0
- package/package.json +42 -0
- package/provenance.json +580 -0
- package/schema-manifest.json +458 -0
- package/src/check.js +23 -0
- package/src/index.js +50 -0
- package/src/materialize.js +73 -0
- package/src/plan.js +44 -0
- package/src/tooling.test.mjs +97 -0
- package/tests/agent_board_addressing.test.sql +166 -0
- package/tests/agent_board_auth_rls.test.sql +243 -0
- package/tests/agent_board_auth_rls_id_qualification.test.sql +225 -0
- package/tests/agent_board_auth_rpcs.test.sql +311 -0
- package/tests/agent_board_auth_schema.test.sql +411 -0
- package/tests/agent_board_authbound_boundary.test.sql +148 -0
- package/tests/agent_board_boardopt.test.sql +170 -0
- package/tests/agent_board_bundle_endpoint_compat.test.sql +49 -0
- package/tests/agent_board_callback_runtime.test.sql +425 -0
- package/tests/agent_board_callbackcap.test.sql +222 -0
- package/tests/agent_board_canary_signed_fleet_enforcement.test.sql +60 -0
- package/tests/agent_board_dblint_rpcs.test.sql +247 -0
- package/tests/agent_board_fleet_policy.test.sql +370 -0
- package/tests/agent_board_fleet_read_models.test.sql +158 -0
- package/tests/agent_board_fleet_registry.test.sql +149 -0
- package/tests/agent_board_inbox_reads.test.sql +471 -0
- package/tests/agent_board_inbox_rpcs.test.sql +452 -0
- package/tests/agent_board_inbox_schema.test.sql +355 -0
- package/tests/agent_board_nonfleet_identity.test.sql +26 -0
- package/tests/agent_board_rls_reassert_board_scoping.test.sql +39 -0
- package/tests/agent_board_schema_version.test.sql +24 -0
- package/tests/agent_board_schema_version_rpc.test.sql +40 -0
- package/tests/agent_board_signature_rls_reads.test.sql +133 -0
- package/tests/agent_board_signed_write_gateway.test.sql +219 -0
- package/tests/agent_board_signing_proof_rpcs.test.sql +143 -0
- package/tests/agent_board_signing_store.test.sql +183 -0
- package/tests/agent_board_smoke.test.sql +12 -0
- package/tests/agent_board_v1_invariants.test.sql +298 -0
- package/tests/agent_board_v2_invariants.test.sql +753 -0
- package/tests/agent_board_workload_providers.test.sql +15 -0
- package/tests/fixtures/adopter-base.sql +19 -0
- package/tests/fixtures/operator-hardening.sql +27 -0
- 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;
|