@creatornader/agent-bridge 0.4.0 → 0.5.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 (76) hide show
  1. package/CHANGELOG.md +73 -1
  2. package/README.md +73 -7
  3. package/ROADMAP.md +29 -0
  4. package/SECURITY.md +23 -0
  5. package/SKILL.md +5 -1
  6. package/dist/archive.d.ts +2 -2
  7. package/dist/{bridge-service-YTjGr91A.d.ts → bridge-service-CNBKdYXh.d.ts} +2 -1
  8. package/dist/{bridge-store-Boaj-ZbO.d.ts → bridge-store-ByJ6CaJk.d.ts} +1 -0
  9. package/dist/bridge.d.ts +15 -8
  10. package/dist/bridge.js +10 -8
  11. package/dist/{chunk-PDIHDBP3.js → chunk-7VJI2MXI.js} +116 -26
  12. package/dist/chunk-7VJI2MXI.js.map +1 -0
  13. package/dist/{chunk-4VB44KJU.js → chunk-AWE3DFZV.js} +3 -2
  14. package/dist/chunk-AWE3DFZV.js.map +1 -0
  15. package/dist/{chunk-IHZFI7TH.js → chunk-E4OWHGUE.js} +5 -2
  16. package/dist/chunk-E4OWHGUE.js.map +1 -0
  17. package/dist/{chunk-SYGONYMM.js → chunk-HUHG7XTB.js} +6 -5
  18. package/dist/chunk-HUHG7XTB.js.map +1 -0
  19. package/dist/{chunk-DQOZJJZ2.js → chunk-IVG4XWWS.js} +5 -5
  20. package/dist/{chunk-DQOZJJZ2.js.map → chunk-IVG4XWWS.js.map} +1 -1
  21. package/dist/{chunk-3YHVUPU2.js → chunk-P635FAN4.js} +4 -4
  22. package/dist/chunk-P635FAN4.js.map +1 -0
  23. package/dist/{chunk-6BTJE6D4.js → chunk-QNXHDOJ5.js} +56 -23
  24. package/dist/chunk-QNXHDOJ5.js.map +1 -0
  25. package/dist/{chunk-MCKKVNCE.js → chunk-QPC6JHA3.js} +5 -5
  26. package/dist/{chunk-SV3SVBYS.js → chunk-SN7PIVDF.js} +2 -2
  27. package/dist/{chunk-2DFNOLMO.js → chunk-XDNT6ZNZ.js} +9 -6
  28. package/dist/chunk-XDNT6ZNZ.js.map +1 -0
  29. package/dist/{chunk-LAHNQZDN.js → chunk-Z6JP6MYD.js} +2 -2
  30. package/dist/cli.js +9 -9
  31. package/dist/cli.js.map +1 -1
  32. package/dist/client-runtime.d.ts +3 -3
  33. package/dist/client-runtime.js +6 -6
  34. package/dist/contracts/generate.js +1 -1
  35. package/dist/dr.js +3 -3
  36. package/dist/{gateway-BQHpV-MZ.d.ts → gateway-CW-61lvs.d.ts} +2 -2
  37. package/dist/gateway-main.js +5 -5
  38. package/dist/gateway.d.ts +3 -3
  39. package/dist/gateway.js +3 -3
  40. package/dist/index.js +7 -7
  41. package/dist/{postgres-bridge-store-WASumj26.d.ts → postgres-bridge-store-C9KG9Z69.d.ts} +1 -1
  42. package/dist/postgres-production-preflight.d.ts +32 -0
  43. package/dist/postgres-production-preflight.js +249 -0
  44. package/dist/postgres-production-preflight.js.map +1 -0
  45. package/dist/server.js +7 -7
  46. package/dist/{sqlite-edge-store-Bc15DvpX.d.ts → sqlite-edge-store-CdMIOrho.d.ts} +1 -1
  47. package/dist/sqlite.d.ts +3 -3
  48. package/dist/sqlite.js +2 -2
  49. package/docs/architecture-v2.md +36 -5
  50. package/docs/deployment.md +144 -0
  51. package/llms.txt +2 -1
  52. package/openapi/agent-bridge-v2.openapi.json +5 -1
  53. package/package.json +5 -1
  54. package/schemas/agent-bridge-v2.capabilities.json +2 -1
  55. package/schemas/agent-bridge-v2.mcp.json +5 -1
  56. package/schemas/agent-bridge-v2.schema.json +4 -0
  57. package/sql/migrations/007_runtime_role.sql +8 -4
  58. package/sql/migrations/013_row_isolation.sql +71 -8
  59. package/sql/migrations/014_owner_control_plane.sql +124 -31
  60. package/sql/migrations/015_portable_archives.sql +143 -41
  61. package/sql/migrations/016_native_dr_fence.sql +102 -35
  62. package/sql/migrations/018_endpoint_migration_challenges.sql +36 -10
  63. package/sql/migrations/019_endpoint_migration_same_successor.sql +34 -10
  64. package/sql/migrations/020_managed_authority_compat.sql +698 -0
  65. package/sql/migrations/021_native_backup_reader.sql +421 -0
  66. package/sql/setup.sql +1 -3
  67. package/dist/chunk-2DFNOLMO.js.map +0 -1
  68. package/dist/chunk-3YHVUPU2.js.map +0 -1
  69. package/dist/chunk-4VB44KJU.js.map +0 -1
  70. package/dist/chunk-6BTJE6D4.js.map +0 -1
  71. package/dist/chunk-IHZFI7TH.js.map +0 -1
  72. package/dist/chunk-PDIHDBP3.js.map +0 -1
  73. package/dist/chunk-SYGONYMM.js.map +0 -1
  74. /package/dist/{chunk-MCKKVNCE.js.map → chunk-QPC6JHA3.js.map} +0 -0
  75. /package/dist/{chunk-SV3SVBYS.js.map → chunk-SN7PIVDF.js.map} +0 -0
  76. /package/dist/{chunk-LAHNQZDN.js.map → chunk-Z6JP6MYD.js.map} +0 -0
@@ -0,0 +1,698 @@
1
+ begin;
2
+
3
+ select pg_advisory_xact_lock(1646705660);
4
+
5
+ do $readiness$
6
+ begin
7
+ if not agent_bridge.security_schema_ready() then
8
+ raise exception 'managed authority compatibility security readiness validation failed';
9
+ elsif not agent_bridge.owner_control_plane_ready() then
10
+ raise exception 'managed authority compatibility owner readiness validation failed';
11
+ elsif not agent_bridge.gateway_authority_ready() then
12
+ raise exception 'managed authority compatibility gateway readiness validation failed';
13
+ elsif not agent_bridge.endpoint_migration_challenge_ready() then
14
+ raise exception 'managed authority compatibility endpoint readiness validation failed';
15
+ elsif not agent_bridge.portable_archive_ready() then
16
+ raise exception 'managed authority compatibility archive readiness validation failed';
17
+ end if;
18
+ end
19
+ $readiness$;
20
+
21
+ alter table agent_bridge.portable_archive_attestations
22
+ drop constraint portable_archive_attestation_name;
23
+ alter table agent_bridge.portable_archive_attestations
24
+ add constraint portable_archive_attestation_name
25
+ check(name ~ '^portable-archive-v[0-9]+$');
26
+
27
+ create or replace function agent_bridge.assert_control_actor(requested_capability text)
28
+ returns void language plpgsql security definer set search_path = '' as $$
29
+ declare
30
+ suffix text := substr(md5(current_database()),1,16);
31
+ schema_owner name;
32
+ operator_role name := ('agent_bridge_control_operator_'||suffix)::name;
33
+ auditor_role name := ('agent_bridge_control_auditor_'||suffix)::name;
34
+ operator_allowed boolean := false;
35
+ auditor_allowed boolean := false;
36
+ begin
37
+ select pg_catalog.pg_get_userbyid(namespace.nspowner)::name into schema_owner
38
+ from pg_catalog.pg_namespace namespace where namespace.nspname='agent_bridge';
39
+ if requested_capability is null or requested_capability not in ('operator','inventory') then
40
+ raise exception 'control capability is invalid';
41
+ end if;
42
+
43
+ perform pg_catalog.pg_advisory_xact_lock(pg_catalog.hashtextextended(
44
+ 'control-membership'||chr(31)||session_user||chr(31)||'global',1646705661
45
+ ));
46
+ perform pg_catalog.pg_advisory_xact_lock(pg_catalog.hashtextextended(
47
+ 'control-membership'||chr(31)||session_user||chr(31)||'operator',1646705661
48
+ ));
49
+ if requested_capability='inventory' then
50
+ perform pg_catalog.pg_advisory_xact_lock(pg_catalog.hashtextextended(
51
+ 'control-membership'||chr(31)||session_user||chr(31)||'auditor',1646705661
52
+ ));
53
+ end if;
54
+
55
+ with latest as (
56
+ select distinct on (event.control_role) event.control_role,event.action
57
+ from agent_bridge.control_membership_events event
58
+ where event.member_role=session_user and event.control_role in ('operator','auditor')
59
+ order by event.control_role,event.sequence desc
60
+ ), direct_membership as (
61
+ select granted.rolname control_role,
62
+ bool_or(membership.admin_option) admin_option,
63
+ bool_or(coalesce((to_jsonb(membership)->>'inherit_option')::boolean,true)) inherit_option,
64
+ bool_or(coalesce((to_jsonb(membership)->>'set_option')::boolean,true)) set_option,
65
+ bool_and(case when member.rolname=schema_owner then
66
+ (membership.grantor=10 and membership.admin_option
67
+ and coalesce((to_jsonb(membership)->>'inherit_option')::boolean,true)
68
+ =coalesce((to_jsonb(membership)->>'set_option')::boolean,true))
69
+ or (membership.grantor=member.oid
70
+ and coalesce((to_jsonb(membership)->>'inherit_option')::boolean,true)
71
+ and coalesce((to_jsonb(membership)->>'set_option')::boolean,true))
72
+ else membership.grantor=(select oid from pg_catalog.pg_roles where rolname=schema_owner)
73
+ and not membership.admin_option
74
+ and coalesce((to_jsonb(membership)->>'inherit_option')::boolean,true)
75
+ and coalesce((to_jsonb(membership)->>'set_option')::boolean,true) end) grants_valid
76
+ from pg_catalog.pg_auth_members membership
77
+ join pg_catalog.pg_roles granted on granted.oid=membership.roleid
78
+ join pg_catalog.pg_roles member on member.oid=membership.member
79
+ where member.rolname=session_user and granted.rolname in (operator_role,auditor_role)
80
+ group by granted.rolname
81
+ )
82
+ select
83
+ coalesce(bool_or(membership.control_role=operator_role
84
+ and membership.inherit_option and membership.set_option and membership.grants_valid and (
85
+ (session_user=schema_owner and membership.admin_option)
86
+ or (latest.control_role='operator' and latest.action='register'
87
+ and not membership.admin_option)
88
+ )),false),
89
+ coalesce(bool_or(membership.control_role=auditor_role
90
+ and membership.inherit_option and membership.set_option and membership.grants_valid and (
91
+ (session_user=schema_owner and membership.admin_option)
92
+ or (latest.control_role='auditor' and latest.action='register'
93
+ and not membership.admin_option)
94
+ )),false)
95
+ into operator_allowed,auditor_allowed
96
+ from direct_membership membership left join latest on latest.control_role=case
97
+ membership.control_role when operator_role then 'operator' else 'auditor' end;
98
+
99
+ if session_user<>schema_owner and (exists (
100
+ select 1 from pg_catalog.pg_roles inherited
101
+ where inherited.rolname<>session_user
102
+ and pg_catalog.pg_has_role(session_user,inherited.rolname,'MEMBER')
103
+ and not (
104
+ (inherited.rolname=operator_role and operator_allowed)
105
+ or (inherited.rolname=auditor_role and auditor_allowed)
106
+ )
107
+ ) or exists (
108
+ select 1 from pg_catalog.pg_roles candidate
109
+ where candidate.rolname not in (session_user,schema_owner)
110
+ and not candidate.rolsuper
111
+ and pg_catalog.pg_has_role(candidate.rolname,session_user,'MEMBER')
112
+ ) or exists (
113
+ select 1 from pg_catalog.pg_roles actor
114
+ where actor.rolname=session_user and (
115
+ not actor.rolcanlogin or actor.rolsuper or actor.rolcreaterole or actor.rolcreatedb
116
+ or actor.rolreplication or actor.rolbypassrls
117
+ )
118
+ )) then
119
+ raise exception 'control actor has an unsafe membership graph';
120
+ end if;
121
+
122
+ if (requested_capability='operator' and not operator_allowed)
123
+ or (requested_capability='inventory' and not (operator_allowed or auditor_allowed)) then
124
+ raise exception 'control actor is not registered for requested capability';
125
+ end if;
126
+ end
127
+ $$;
128
+
129
+ create or replace function agent_bridge.assert_archive_actor()
130
+ returns void language plpgsql security definer set search_path = '' as $$
131
+ declare
132
+ suffix text := substr(md5(current_database()),1,16);
133
+ schema_owner name;
134
+ archive_role name := ('agent_bridge_archive_operator_'||suffix)::name;
135
+ archive_allowed boolean := false;
136
+ begin
137
+ if not agent_bridge.portable_archive_ready() then
138
+ raise exception 'portable archive readiness validation failed';
139
+ end if;
140
+ select pg_catalog.pg_get_userbyid(namespace.nspowner)::name into schema_owner
141
+ from pg_catalog.pg_namespace namespace where namespace.nspname='agent_bridge';
142
+ perform pg_catalog.pg_advisory_xact_lock(pg_catalog.hashtextextended(
143
+ 'archive-membership'||chr(31)||session_user||chr(31)||'global',1646705662
144
+ ));
145
+ perform pg_catalog.pg_advisory_xact_lock(pg_catalog.hashtextextended(
146
+ 'archive-membership'||chr(31)||session_user||chr(31)||'operator',1646705662
147
+ ));
148
+
149
+ with latest as (
150
+ select event.action from agent_bridge.archive_membership_events event
151
+ where event.member_role=session_user order by event.sequence desc limit 1
152
+ ), direct_membership as (
153
+ select bool_or(membership.admin_option) admin_option,
154
+ bool_or(coalesce((to_jsonb(membership)->>'inherit_option')::boolean,true)) inherit_option,
155
+ bool_or(coalesce((to_jsonb(membership)->>'set_option')::boolean,true)) set_option,
156
+ bool_and(case when member.rolname=schema_owner then
157
+ (membership.grantor=10 and membership.admin_option
158
+ and coalesce((to_jsonb(membership)->>'inherit_option')::boolean,true)
159
+ =coalesce((to_jsonb(membership)->>'set_option')::boolean,true))
160
+ or (membership.grantor=member.oid
161
+ and coalesce((to_jsonb(membership)->>'inherit_option')::boolean,true)
162
+ and coalesce((to_jsonb(membership)->>'set_option')::boolean,true))
163
+ else membership.grantor=(select oid from pg_catalog.pg_roles where rolname=schema_owner)
164
+ and not membership.admin_option
165
+ and coalesce((to_jsonb(membership)->>'inherit_option')::boolean,true)
166
+ and coalesce((to_jsonb(membership)->>'set_option')::boolean,true) end) grants_valid
167
+ from pg_catalog.pg_auth_members membership
168
+ join pg_catalog.pg_roles granted on granted.oid=membership.roleid
169
+ join pg_catalog.pg_roles member on member.oid=membership.member
170
+ where member.rolname=session_user and granted.rolname=archive_role
171
+ )
172
+ select coalesce(bool_or(
173
+ membership.inherit_option and membership.set_option and membership.grants_valid and (
174
+ (session_user=schema_owner and membership.admin_option)
175
+ or (latest.action='register' and not membership.admin_option)
176
+ )
177
+ ),false) into archive_allowed
178
+ from direct_membership membership left join latest on true;
179
+
180
+ if session_user<>schema_owner and (exists (
181
+ select 1 from pg_catalog.pg_roles inherited
182
+ where inherited.rolname<>session_user
183
+ and pg_catalog.pg_has_role(session_user,inherited.rolname,'MEMBER')
184
+ and inherited.rolname<>archive_role
185
+ ) or exists (
186
+ select 1 from pg_catalog.pg_roles candidate
187
+ where candidate.rolname not in (session_user,schema_owner)
188
+ and not candidate.rolsuper
189
+ and pg_catalog.pg_has_role(candidate.rolname,session_user,'MEMBER')
190
+ ) or exists (
191
+ select 1 from pg_catalog.pg_roles actor where actor.rolname=session_user and (
192
+ not actor.rolcanlogin or actor.rolsuper or actor.rolcreaterole or actor.rolcreatedb
193
+ or actor.rolreplication or actor.rolbypassrls
194
+ )
195
+ )) then
196
+ raise exception 'archive actor has an unsafe membership graph';
197
+ end if;
198
+ if not archive_allowed then
199
+ raise exception 'archive actor is not registered';
200
+ end if;
201
+ end
202
+ $$;
203
+
204
+ do $ownership$
205
+ declare
206
+ owner_role text := 'agent_bridge_control_owner_'||substr(md5(current_database()),1,16);
207
+ begin
208
+ execute format('grant create on schema agent_bridge to %I',owner_role);
209
+ execute format(
210
+ 'grant insert on agent_bridge.owner_control_attestations to %I',
211
+ owner_role
212
+ );
213
+ perform set_config('role',owner_role,false);
214
+ end
215
+ $ownership$;
216
+
217
+ create or replace function agent_bridge.owner_control_attestation_definition()
218
+ returns text language sql stable set search_path = '' as $$
219
+ with names as (select
220
+ ('agent_bridge_control_owner_'||substr(md5(current_database()),1,16))::name owner_role,
221
+ ('agent_bridge_control_operator_'||substr(md5(current_database()),1,16))::name operator_role,
222
+ ('agent_bridge_control_auditor_'||substr(md5(current_database()),1,16))::name auditor_role,
223
+ (select namespace.nspowner from pg_catalog.pg_namespace namespace
224
+ where namespace.nspname='agent_bridge') schema_owner
225
+ ), control_roles(role_name) as (
226
+ select owner_role from names union all select operator_role from names
227
+ union all select auditor_role from names
228
+ ), raw_records(record) as (
229
+ select unnest(string_to_array(
230
+ agent_bridge.owner_control_catalog_definition(),E'\x1e'
231
+ ))
232
+ ), protected_relations(oid) as (
233
+ select distinct pg_catalog.to_regclass(split_part(record,E'\x1f',2))
234
+ from raw_records where split_part(record,E'\x1f',1) in ('relation','relation_acl')
235
+ union
236
+ select distinct relation.oid
237
+ from raw_records
238
+ join pg_catalog.pg_attribute attribute
239
+ on not attribute.attisdropped and attribute.attnum>0
240
+ join pg_catalog.pg_class relation on relation.oid=attribute.attrelid
241
+ and relation.oid::regclass::text||'.'||attribute.attname=
242
+ split_part(record,E'\x1f',2)
243
+ where split_part(record,E'\x1f',1)='column_acl'
244
+ ), default_acl_keys(owner_oid,namespace_oid,object_type) as (
245
+ select role.oid,0::oid,object_type
246
+ from pg_catalog.pg_roles role
247
+ cross join (values ('r'::"char"),('S'::"char"),('f'::"char"),
248
+ ('T'::"char"),('n'::"char")) object_types(object_type)
249
+ where role.oid in (
250
+ (select schema_owner from names),
251
+ (select oid from pg_catalog.pg_roles where rolname=(select owner_role from names))
252
+ )
253
+ union
254
+ select default_acl.defaclrole,default_acl.defaclnamespace,default_acl.defaclobjtype
255
+ from pg_catalog.pg_default_acl default_acl
256
+ left join pg_catalog.pg_namespace namespace on namespace.oid=default_acl.defaclnamespace
257
+ where (namespace.nspname='agent_bridge' or default_acl.defaclnamespace=0)
258
+ and default_acl.defaclrole in (
259
+ (select schema_owner from names),
260
+ (select oid from pg_catalog.pg_roles where rolname=(select owner_role from names))
261
+ )
262
+ ), catalog_objects(kind,identity,definition) as (
263
+ select split_part(record,E'\x1f',1),split_part(record,E'\x1f',2),
264
+ split_part(record,E'\x1f',3)
265
+ from raw_records where split_part(record,E'\x1f',1) not in (
266
+ 'membership','relation_acl','column_acl','default_acl'
267
+ )
268
+ union all
269
+ select 'membership',granted.rolname||'->'||member.rolname,
270
+ bool_or(membership.admin_option)::text||':'||
271
+ bool_or(coalesce((to_jsonb(membership)->>'inherit_option')::boolean,true))::text||':'||
272
+ bool_or(coalesce((to_jsonb(membership)->>'set_option')::boolean,true))::text
273
+ from pg_catalog.pg_auth_members membership
274
+ join pg_catalog.pg_roles granted on granted.oid=membership.roleid
275
+ join pg_catalog.pg_roles member on member.oid=membership.member
276
+ where member.rolname in (select role_name from control_roles)
277
+ or granted.rolname=(select owner_role from names)
278
+ group by granted.rolname,member.rolname
279
+ union all
280
+ select 'relation_acl',relation.oid::regclass::text,
281
+ pg_catalog.pg_get_userbyid(privilege.grantor)||':'||
282
+ case when privilege.grantee=0 then 'PUBLIC'
283
+ else pg_catalog.pg_get_userbyid(privilege.grantee) end||':'||
284
+ privilege.privilege_type||':'||privilege.is_grantable::text
285
+ from pg_catalog.pg_class relation
286
+ cross join lateral pg_catalog.aclexplode(coalesce(relation.relacl,
287
+ pg_catalog.acldefault(
288
+ case when relation.relkind='S' then 'S'::"char" else 'r'::"char" end,
289
+ relation.relowner
290
+ ))) privilege
291
+ where relation.oid in (select oid from protected_relations)
292
+ and relation.relkind in ('r','p','v','m','f','S')
293
+ and privilege.grantee<>relation.relowner
294
+ union all
295
+ select 'column_acl',relation.oid::regclass::text||'.'||attribute.attname,
296
+ pg_catalog.pg_get_userbyid(privilege.grantor)||':'||
297
+ case when privilege.grantee=0 then 'PUBLIC'
298
+ else pg_catalog.pg_get_userbyid(privilege.grantee) end||':'||
299
+ privilege.privilege_type||':'||privilege.is_grantable::text
300
+ from pg_catalog.pg_attribute attribute
301
+ join pg_catalog.pg_class relation on relation.oid=attribute.attrelid
302
+ cross join lateral pg_catalog.aclexplode(attribute.attacl) privilege
303
+ where relation.oid in (select oid from protected_relations)
304
+ and attribute.attnum>0 and not attribute.attisdropped
305
+ and attribute.attacl is not null and privilege.grantee<>relation.relowner
306
+ union all
307
+ select 'default_acl',owner.rolname||':'||coalesce(namespace.nspname,'')||':'||
308
+ keys.object_type::text,
309
+ pg_catalog.pg_get_userbyid(privilege.grantor)||':'||
310
+ case when privilege.grantee=0 then 'PUBLIC'
311
+ else pg_catalog.pg_get_userbyid(privilege.grantee) end||':'||
312
+ privilege.privilege_type||':'||privilege.is_grantable::text
313
+ from default_acl_keys keys
314
+ join pg_catalog.pg_roles owner on owner.oid=keys.owner_oid
315
+ left join pg_catalog.pg_namespace namespace on namespace.oid=keys.namespace_oid
316
+ left join pg_catalog.pg_default_acl default_acl
317
+ on default_acl.defaclrole=keys.owner_oid
318
+ and default_acl.defaclnamespace=keys.namespace_oid
319
+ and default_acl.defaclobjtype=keys.object_type
320
+ cross join lateral pg_catalog.aclexplode(case when keys.namespace_oid=0 then
321
+ coalesce(default_acl.defaclacl,pg_catalog.acldefault(keys.object_type,keys.owner_oid))
322
+ else coalesce(default_acl.defaclacl,'{}'::pg_catalog.aclitem[]) end) privilege
323
+ where privilege.grantee<>keys.owner_oid
324
+ union all
325
+ select 'attestation_function',procedure.oid::regprocedure::text,
326
+ pg_catalog.pg_get_userbyid(procedure.proowner)||':'||
327
+ pg_catalog.pg_get_functiondef(procedure.oid)
328
+ from pg_catalog.pg_proc procedure
329
+ where procedure.oid=
330
+ 'agent_bridge.owner_control_attestation_definition()'::regprocedure
331
+ )
332
+ select string_agg(kind||E'\x1f'||identity||E'\x1f'||definition,E'\x1e'
333
+ order by kind,identity,definition) from catalog_objects
334
+ $$;
335
+
336
+ reset role;
337
+
338
+ do $ownership$
339
+ declare
340
+ owner_role text := 'agent_bridge_control_owner_'||substr(md5(current_database()),1,16);
341
+ begin
342
+ execute format('revoke create on schema agent_bridge from %I',owner_role);
343
+ end
344
+ $ownership$;
345
+
346
+ create or replace function agent_bridge.portable_archive_attestation_definition()
347
+ returns text language sql stable set search_path = '' as $$
348
+ with names as (select
349
+ ('agent_bridge_archive_operator_'||substr(md5(current_database()),1,16))::name archive_role,
350
+ namespace.nspowner schema_owner
351
+ from pg_catalog.pg_namespace namespace where namespace.nspname='agent_bridge'
352
+ ), raw_records(record) as (
353
+ select unnest(string_to_array(
354
+ agent_bridge.portable_archive_catalog_definition(),E'\x1e'
355
+ ))
356
+ ), protected_relations(oid) as (
357
+ select distinct pg_catalog.to_regclass(split_part(record,E'\x1f',2))
358
+ from raw_records where split_part(record,E'\x1f',1)='relation'
359
+ ), default_acl_keys(owner_oid,namespace_oid,object_type) as (
360
+ select (select schema_owner from names),0::oid,object_type
361
+ from (values ('r'::"char"),('S'::"char"),('f'::"char"),
362
+ ('T'::"char"),('n'::"char")) object_types(object_type)
363
+ union
364
+ select default_acl.defaclrole,default_acl.defaclnamespace,default_acl.defaclobjtype
365
+ from pg_catalog.pg_default_acl default_acl
366
+ left join pg_catalog.pg_namespace namespace on namespace.oid=default_acl.defaclnamespace
367
+ where namespace.nspname='agent_bridge'
368
+ or default_acl.defaclrole=(select schema_owner from names)
369
+ ), catalog_objects(kind,identity,definition) as (
370
+ select split_part(record,E'\x1f',1),split_part(record,E'\x1f',2),
371
+ split_part(record,E'\x1f',3)
372
+ from raw_records where split_part(record,E'\x1f',1) not in (
373
+ 'owner_membership','relation_acl','column_acl','default_acl'
374
+ )
375
+ union all
376
+ select 'owner_membership',granted.rolname||'->'||member.rolname,
377
+ bool_or(membership.admin_option)::text||':'||
378
+ bool_or(coalesce((to_jsonb(membership)->>'inherit_option')::boolean,true))::text||':'||
379
+ bool_or(coalesce((to_jsonb(membership)->>'set_option')::boolean,true))::text
380
+ from pg_catalog.pg_auth_members membership
381
+ join pg_catalog.pg_roles granted on granted.oid=membership.roleid
382
+ join pg_catalog.pg_roles member on member.oid=membership.member
383
+ where granted.rolname=(select archive_role from names)
384
+ and member.oid=(select schema_owner from names)
385
+ group by granted.rolname,member.rolname
386
+ union all
387
+ select 'relation_acl',relation.oid::regclass::text,
388
+ pg_catalog.pg_get_userbyid(privilege.grantor)||':'||
389
+ case when privilege.grantee=0 then 'PUBLIC'
390
+ else pg_catalog.pg_get_userbyid(privilege.grantee) end||':'||
391
+ privilege.privilege_type||':'||privilege.is_grantable::text
392
+ from pg_catalog.pg_class relation
393
+ cross join lateral pg_catalog.aclexplode(coalesce(relation.relacl,
394
+ pg_catalog.acldefault(
395
+ case when relation.relkind='S' then 'S'::"char" else 'r'::"char" end,
396
+ relation.relowner
397
+ ))) privilege
398
+ where relation.oid in (select oid from protected_relations)
399
+ and relation.relkind in ('r','p','v','m','f','S')
400
+ and privilege.grantee<>relation.relowner
401
+ union all
402
+ select 'column_acl',relation.oid::regclass::text||'.'||attribute.attname,
403
+ pg_catalog.pg_get_userbyid(privilege.grantor)||':'||
404
+ case when privilege.grantee=0 then 'PUBLIC'
405
+ else pg_catalog.pg_get_userbyid(privilege.grantee) end||':'||
406
+ privilege.privilege_type||':'||privilege.is_grantable::text
407
+ from pg_catalog.pg_attribute attribute
408
+ join pg_catalog.pg_class relation on relation.oid=attribute.attrelid
409
+ cross join lateral pg_catalog.aclexplode(attribute.attacl) privilege
410
+ where relation.oid in (select oid from protected_relations)
411
+ and attribute.attnum>0 and not attribute.attisdropped
412
+ and attribute.attacl is not null and privilege.grantee<>relation.relowner
413
+ union all
414
+ select 'default_acl',owner.rolname||':'||coalesce(namespace.nspname,'')||':'||
415
+ keys.object_type::text,
416
+ pg_catalog.pg_get_userbyid(privilege.grantor)||':'||
417
+ case when privilege.grantee=0 then 'PUBLIC'
418
+ else pg_catalog.pg_get_userbyid(privilege.grantee) end||':'||
419
+ privilege.privilege_type||':'||privilege.is_grantable::text
420
+ from default_acl_keys keys
421
+ join pg_catalog.pg_roles owner on owner.oid=keys.owner_oid
422
+ left join pg_catalog.pg_namespace namespace on namespace.oid=keys.namespace_oid
423
+ left join pg_catalog.pg_default_acl default_acl
424
+ on default_acl.defaclrole=keys.owner_oid
425
+ and default_acl.defaclnamespace=keys.namespace_oid
426
+ and default_acl.defaclobjtype=keys.object_type
427
+ cross join lateral pg_catalog.aclexplode(case when keys.namespace_oid=0 then
428
+ coalesce(default_acl.defaclacl,pg_catalog.acldefault(keys.object_type,keys.owner_oid))
429
+ else coalesce(default_acl.defaclacl,'{}'::pg_catalog.aclitem[]) end) privilege
430
+ where privilege.grantee<>keys.owner_oid
431
+ union all
432
+ select 'attestation_function',procedure.oid::regprocedure::text,
433
+ pg_catalog.pg_get_userbyid(procedure.proowner)||':'||
434
+ pg_catalog.pg_get_functiondef(procedure.oid)
435
+ from pg_catalog.pg_proc procedure
436
+ where procedure.oid=
437
+ 'agent_bridge.portable_archive_attestation_definition()'::regprocedure
438
+ )
439
+ select string_agg(kind||E'\x1f'||identity||E'\x1f'||definition,E'\x1e'
440
+ order by kind,identity,definition) from catalog_objects
441
+ $$;
442
+
443
+ create or replace function agent_bridge.portable_archive_ready()
444
+ returns boolean language sql stable security definer set search_path = '' as $$
445
+ with names as (select
446
+ ('agent_bridge_archive_operator_'||substr(md5(current_database()),1,16))::name archive_role,
447
+ (select pg_catalog.pg_get_userbyid(nspowner)::name from pg_catalog.pg_namespace
448
+ where nspname='agent_bridge') schema_owner
449
+ ), latest_registry as (
450
+ select distinct on (event.member_role) event.member_role,event.action
451
+ from agent_bridge.archive_membership_events event order by event.member_role,event.sequence desc
452
+ ), active_registry as (
453
+ select member_role from latest_registry where action='register'
454
+ ), expected_memberships as (
455
+ select names.archive_role granted_role,names.schema_owner member_role,
456
+ true admin_option,true inherit_option,true set_option from names
457
+ union all select names.archive_role,registry.member_role,false,true,true
458
+ from active_registry registry cross join names
459
+ ), raw_memberships as (
460
+ select granted.rolname::name granted_role,member.rolname::name member_role,
461
+ membership.admin_option,
462
+ coalesce((to_jsonb(membership)->>'inherit_option')::boolean,true) inherit_option,
463
+ coalesce((to_jsonb(membership)->>'set_option')::boolean,true) set_option,
464
+ membership.grantor,member.oid member_oid
465
+ from pg_catalog.pg_auth_members membership
466
+ join pg_catalog.pg_roles granted on granted.oid=membership.roleid
467
+ join pg_catalog.pg_roles member on member.oid=membership.member
468
+ where granted.rolname=(select archive_role from names)
469
+ ), actual_memberships as (
470
+ select membership.granted_role,membership.member_role,
471
+ bool_or(membership.admin_option) admin_option,
472
+ bool_or(membership.inherit_option) inherit_option,
473
+ bool_or(membership.set_option) set_option,
474
+ bool_and(case when membership.member_role=names.schema_owner then
475
+ (membership.grantor=10 and membership.admin_option
476
+ and membership.inherit_option=membership.set_option)
477
+ or (membership.grantor=membership.member_oid
478
+ and membership.inherit_option and membership.set_option)
479
+ else membership.grantor=(select oid from pg_catalog.pg_roles where rolname=names.schema_owner)
480
+ and not membership.admin_option
481
+ and membership.inherit_option and membership.set_option end) grants_valid
482
+ from raw_memberships membership cross join names
483
+ group by membership.granted_role,membership.member_role
484
+ )
485
+ select current_setting('server_version_num')::integer/10000=any(array[15,16,17,18])
486
+ and exists(select 1 from pg_catalog.pg_roles role,names where role.rolname=names.archive_role
487
+ and not role.rolcanlogin and not role.rolsuper and not role.rolcreatedb
488
+ and not role.rolcreaterole and not role.rolreplication and not role.rolbypassrls)
489
+ and (select count(*)=1 and bool_and(
490
+ attestation.catalog_definition=agent_bridge.portable_archive_attestation_definition()
491
+ ) from agent_bridge.portable_archive_attestations attestation
492
+ where attestation.name='portable-archive-v4')
493
+ and not exists(
494
+ (select granted_role,member_role,admin_option,inherit_option,set_option from actual_memberships
495
+ except select granted_role,member_role,admin_option,inherit_option,set_option from expected_memberships)
496
+ union all
497
+ (select granted_role,member_role,admin_option,inherit_option,set_option from expected_memberships
498
+ except select granted_role,member_role,admin_option,inherit_option,set_option from actual_memberships)
499
+ )
500
+ and not exists(select 1 from actual_memberships membership
501
+ where not membership.grants_valid)
502
+ and not exists(select 1 from active_registry registry
503
+ left join pg_catalog.pg_roles role on role.rolname=registry.member_role
504
+ where role.oid is null or not role.rolcanlogin or role.rolsuper or role.rolcreaterole
505
+ or role.rolcreatedb or role.rolreplication or role.rolbypassrls)
506
+ and not exists(select 1 from active_registry registry
507
+ join pg_catalog.pg_roles inherited on inherited.rolname<>registry.member_role
508
+ cross join names
509
+ where pg_catalog.pg_has_role(registry.member_role,inherited.rolname,'MEMBER')
510
+ and inherited.rolname<>names.archive_role)
511
+ and not exists(select 1 from active_registry registry cross join pg_catalog.pg_roles candidate,names
512
+ where candidate.rolname not in (registry.member_role,names.schema_owner)
513
+ and not candidate.rolsuper
514
+ and pg_catalog.pg_has_role(candidate.rolname,registry.member_role,'MEMBER'))
515
+ and has_schema_privilege((select archive_role from names),'agent_bridge','USAGE')
516
+ and not has_schema_privilege((select archive_role from names),'agent_bridge','CREATE')
517
+ and not exists(select 1 from pg_catalog.pg_class relation
518
+ join pg_catalog.pg_namespace namespace on namespace.oid=relation.relnamespace
519
+ where namespace.nspname='agent_bridge' and relation.relkind in ('r','p','v','m','f')
520
+ and has_table_privilege((select archive_role from names),relation.oid,
521
+ 'SELECT,INSERT,UPDATE,DELETE,TRUNCATE,REFERENCES,TRIGGER'))
522
+ and not exists(select 1 from pg_catalog.pg_class sequence_record
523
+ join pg_catalog.pg_namespace namespace on namespace.oid=sequence_record.relnamespace
524
+ where namespace.nspname='agent_bridge'
525
+ and case when sequence_record.relkind='S' then has_sequence_privilege(
526
+ (select archive_role from names),sequence_record.oid,'USAGE,SELECT,UPDATE'
527
+ ) else false end)
528
+ and not exists(select 1 from pg_catalog.pg_proc procedure
529
+ join pg_catalog.pg_namespace namespace on namespace.oid=procedure.pronamespace
530
+ where namespace.nspname='agent_bridge' and has_function_privilege('public',procedure.oid,'EXECUTE'))
531
+ and not exists(select 1 from pg_catalog.pg_proc procedure
532
+ join pg_catalog.pg_namespace namespace on namespace.oid=procedure.pronamespace
533
+ where namespace.nspname='agent_bridge'
534
+ and has_function_privilege((select archive_role from names),procedure.oid,'EXECUTE')
535
+ and procedure.oid not in (
536
+ 'agent_bridge.archive_begin_operation(uuid,text,text,character,bigint,bigint)'::regprocedure,
537
+ 'agent_bridge.archive_authorize_transaction(uuid,text,text,character)'::regprocedure,
538
+ 'agent_bridge.archive_close_transaction_authorization(uuid)'::regprocedure,
539
+ 'agent_bridge.archive_export_messages(uuid,text,timestamp with time zone,uuid,integer)'::regprocedure,
540
+ 'agent_bridge.archive_export_receipts(uuid,text,timestamp with time zone,uuid,text,integer)'::regprocedure,
541
+ 'agent_bridge.archive_import_messages(uuid,text,character,bigint,jsonb)'::regprocedure,
542
+ 'agent_bridge.archive_import_receipts(uuid,text,character,bigint,jsonb)'::regprocedure,
543
+ 'agent_bridge.archive_complete_export(uuid,text,character,bigint,bigint,timestamp with time zone,text)'::regprocedure,
544
+ 'agent_bridge.archive_reconcile_export(uuid,text,character,bigint,bigint,timestamp with time zone)'::regprocedure,
545
+ 'agent_bridge.archive_complete_import(uuid,text,boolean)'::regprocedure,
546
+ 'agent_bridge.archive_abandon_operation(uuid,text,text)'::regprocedure,
547
+ 'agent_bridge.portable_archive_ready()'::regprocedure
548
+ ))
549
+ and has_function_privilege((select archive_role from names),
550
+ 'agent_bridge.archive_begin_operation(uuid,text,text,character,bigint,bigint)','EXECUTE')
551
+ and has_function_privilege((select archive_role from names),
552
+ 'agent_bridge.archive_authorize_transaction(uuid,text,text,character)','EXECUTE')
553
+ and has_function_privilege((select archive_role from names),
554
+ 'agent_bridge.archive_close_transaction_authorization(uuid)','EXECUTE')
555
+ and has_function_privilege((select archive_role from names),
556
+ 'agent_bridge.archive_export_messages(uuid,text,timestamp with time zone,uuid,integer)','EXECUTE')
557
+ and has_function_privilege((select archive_role from names),
558
+ 'agent_bridge.archive_export_receipts(uuid,text,timestamp with time zone,uuid,text,integer)','EXECUTE')
559
+ and has_function_privilege((select archive_role from names),
560
+ 'agent_bridge.archive_import_messages(uuid,text,character,bigint,jsonb)','EXECUTE')
561
+ and has_function_privilege((select archive_role from names),
562
+ 'agent_bridge.archive_import_receipts(uuid,text,character,bigint,jsonb)','EXECUTE')
563
+ and has_function_privilege((select archive_role from names),
564
+ 'agent_bridge.archive_complete_export(uuid,text,character,bigint,bigint,timestamp with time zone,text)','EXECUTE')
565
+ and has_function_privilege((select archive_role from names),
566
+ 'agent_bridge.archive_reconcile_export(uuid,text,character,bigint,bigint,timestamp with time zone)','EXECUTE')
567
+ and has_function_privilege((select archive_role from names),
568
+ 'agent_bridge.archive_complete_import(uuid,text,boolean)','EXECUTE')
569
+ and has_function_privilege((select archive_role from names),
570
+ 'agent_bridge.archive_abandon_operation(uuid,text,text)','EXECUTE')
571
+ and has_function_privilege((select archive_role from names),
572
+ 'agent_bridge.portable_archive_ready()','EXECUTE')
573
+ $$;
574
+
575
+ create or replace function agent_bridge.owner_control_plane_ready()
576
+ returns boolean language sql stable security definer set search_path = '' as $$
577
+ with names as (select
578
+ ('agent_bridge_control_owner_'||substr(md5(current_database()),1,16))::name owner_role,
579
+ ('agent_bridge_control_operator_'||substr(md5(current_database()),1,16))::name operator_role,
580
+ ('agent_bridge_control_auditor_'||substr(md5(current_database()),1,16))::name auditor_role,
581
+ (select pg_catalog.pg_get_userbyid(nspowner)::name from pg_catalog.pg_namespace where nspname='agent_bridge') schema_owner
582
+ ), latest_registry as (
583
+ select distinct on (event.member_role,event.control_role) event.member_role,event.control_role,event.action
584
+ from agent_bridge.control_membership_events event
585
+ order by event.member_role,event.control_role,event.sequence desc
586
+ ), active_registry as (
587
+ select member_role,control_role from latest_registry where action='register'
588
+ ), expected_memberships as (
589
+ select names.owner_role granted_role,names.schema_owner member_role,
590
+ true admin_option,true inherit_option,true set_option from names
591
+ union all select names.operator_role,names.schema_owner,true,true,true from names
592
+ union all select names.auditor_role,names.schema_owner,true,true,true from names
593
+ union all select case registry.control_role when 'operator' then names.operator_role else names.auditor_role end,
594
+ registry.member_role,false,true,true from active_registry registry cross join names
595
+ ), raw_memberships as (
596
+ select granted.rolname::name granted_role,member.rolname::name member_role,
597
+ membership.admin_option,
598
+ coalesce((to_jsonb(membership)->>'inherit_option')::boolean,true) inherit_option,
599
+ coalesce((to_jsonb(membership)->>'set_option')::boolean,true) set_option,
600
+ membership.grantor,member.oid member_oid
601
+ from pg_catalog.pg_auth_members membership
602
+ join pg_catalog.pg_roles granted on granted.oid=membership.roleid
603
+ join pg_catalog.pg_roles member on member.oid=membership.member
604
+ where granted.rolname in ((select owner_role from names),(select operator_role from names),(select auditor_role from names))
605
+ ), actual_memberships as (
606
+ select membership.granted_role,membership.member_role,
607
+ bool_or(membership.admin_option) admin_option,
608
+ bool_or(membership.inherit_option) inherit_option,
609
+ bool_or(membership.set_option) set_option,
610
+ bool_and(case when membership.member_role=names.schema_owner then
611
+ (membership.grantor=10 and membership.admin_option
612
+ and membership.inherit_option=membership.set_option)
613
+ or (membership.grantor=membership.member_oid
614
+ and membership.inherit_option and membership.set_option)
615
+ else membership.grantor=(select oid from pg_catalog.pg_roles where rolname=names.schema_owner)
616
+ and not membership.admin_option
617
+ and membership.inherit_option and membership.set_option end) grants_valid
618
+ from raw_memberships membership cross join names
619
+ group by membership.granted_role,membership.member_role
620
+ ), authority_closure as (
621
+ select control_role.granted_role,candidate.rolname::name member_role
622
+ from names cross join lateral(values(names.owner_role),(names.operator_role),(names.auditor_role)) control_role(granted_role)
623
+ cross join pg_catalog.pg_roles candidate
624
+ where candidate.rolname not in(names.owner_role,names.operator_role,names.auditor_role)
625
+ and(not candidate.rolsuper or candidate.rolname=names.schema_owner)
626
+ and pg_catalog.pg_has_role(candidate.rolname,control_role.granted_role,'MEMBER')
627
+ ) select
628
+ current_setting('server_version_num')::integer/10000=any(array[15,16,17,18])
629
+ and(select count(*)=1 and bool_and(catalog_definition=agent_bridge.owner_control_attestation_definition())
630
+ from agent_bridge.owner_control_attestations where name='owner-control-v7')
631
+ and not exists(
632
+ (select granted_role,member_role,admin_option,inherit_option,set_option from actual_memberships
633
+ except select granted_role,member_role,admin_option,inherit_option,set_option from expected_memberships)
634
+ union all(select granted_role,member_role,admin_option,inherit_option,set_option from expected_memberships
635
+ except select granted_role,member_role,admin_option,inherit_option,set_option from actual_memberships)
636
+ )
637
+ and not exists(select 1 from actual_memberships where not grants_valid)
638
+ and not exists(select 1 from active_registry registry left join pg_catalog.pg_roles role_record on role_record.rolname=registry.member_role
639
+ where role_record.oid is null or not role_record.rolcanlogin or role_record.rolsuper or role_record.rolcreaterole
640
+ or role_record.rolcreatedb or role_record.rolreplication or role_record.rolbypassrls)
641
+ and not exists(
642
+ (select granted_role,member_role from authority_closure except select granted_role,member_role from expected_memberships)
643
+ union all(select granted_role,member_role from expected_memberships except select granted_role,member_role from authority_closure)
644
+ )
645
+ and not exists(select 1 from active_registry registry join pg_catalog.pg_roles inherited on inherited.rolname<>registry.member_role
646
+ where pg_catalog.pg_has_role(registry.member_role,inherited.rolname,'MEMBER') and not exists(
647
+ select 1 from active_registry permitted cross join names where permitted.member_role=registry.member_role
648
+ and inherited.rolname=case permitted.control_role when 'operator' then names.operator_role else names.auditor_role end
649
+ ))
650
+ and not exists(select 1 from active_registry registry cross join pg_catalog.pg_roles candidate,names
651
+ where candidate.rolname not in(registry.member_role,names.schema_owner) and not candidate.rolsuper
652
+ and pg_catalog.pg_has_role(candidate.rolname,registry.member_role,'MEMBER'))
653
+ $$;
654
+
655
+ select set_config(
656
+ 'role','agent_bridge_control_owner_'||substr(md5(current_database()),1,16),false
657
+ );
658
+ do $owner_attestation$
659
+ begin
660
+ insert into agent_bridge.owner_control_attestations(name,catalog_definition)
661
+ values('owner-control-v7',agent_bridge.owner_control_attestation_definition());
662
+ exception when others then
663
+ raise exception 'managed authority compatibility owner attestation append failed: %',sqlerrm;
664
+ end
665
+ $owner_attestation$;
666
+ reset role;
667
+
668
+ do $archive_attestation$
669
+ begin
670
+ insert into agent_bridge.portable_archive_attestations(name,catalog_definition)
671
+ values('portable-archive-v4',agent_bridge.portable_archive_attestation_definition());
672
+ exception when others then
673
+ raise exception 'managed authority compatibility archive attestation append failed: %',sqlerrm;
674
+ end
675
+ $archive_attestation$;
676
+
677
+ do $final_readiness$
678
+ begin
679
+ if not agent_bridge.security_schema_ready() then
680
+ raise exception 'managed authority compatibility final security readiness validation failed';
681
+ elsif not agent_bridge.owner_control_plane_ready() then
682
+ raise exception 'managed authority compatibility final owner readiness validation failed';
683
+ elsif not agent_bridge.gateway_authority_ready() then
684
+ raise exception 'managed authority compatibility final gateway readiness validation failed';
685
+ elsif not agent_bridge.endpoint_migration_challenge_ready() then
686
+ raise exception 'managed authority compatibility final endpoint readiness validation failed';
687
+ elsif not agent_bridge.portable_archive_ready() then
688
+ raise exception 'managed authority compatibility final archive readiness validation failed';
689
+ end if;
690
+ exception when others then
691
+ raise exception 'managed authority compatibility final readiness execution failed: %',sqlerrm;
692
+ end
693
+ $final_readiness$;
694
+
695
+ insert into agent_bridge.schema_migrations(version,name,checksum)
696
+ values(20,'managed_authority_compat','__AGENT_BRIDGE_MIGRATION_CHECKSUM__');
697
+
698
+ commit;