@creatornader/agent-bridge 0.3.1 → 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 (90) hide show
  1. package/CHANGELOG.md +222 -1
  2. package/README.md +312 -12
  3. package/ROADMAP.md +88 -7
  4. package/SECURITY.md +78 -5
  5. package/SKILL.md +108 -1
  6. package/dist/archive.d.ts +2 -2
  7. package/dist/archive.js +2 -2
  8. package/dist/{bridge-service-hX1ZQp4W.d.ts → bridge-service-CNBKdYXh.d.ts} +2 -1
  9. package/dist/{bridge-store-DPVSCwfs.d.ts → bridge-store-ByJ6CaJk.d.ts} +3 -0
  10. package/dist/bridge.d.ts +25 -8
  11. package/dist/bridge.js +19 -9
  12. package/dist/{chunk-MBPZXTJA.js → chunk-7VJI2MXI.js} +285 -42
  13. package/dist/chunk-7VJI2MXI.js.map +1 -0
  14. package/dist/{chunk-4VB44KJU.js → chunk-AWE3DFZV.js} +3 -2
  15. package/dist/chunk-AWE3DFZV.js.map +1 -0
  16. package/dist/{chunk-GADH244D.js → chunk-E4OWHGUE.js} +16 -5
  17. package/dist/chunk-E4OWHGUE.js.map +1 -0
  18. package/dist/{chunk-NCO7RLBM.js → chunk-GTK4KOED.js} +108 -8
  19. package/dist/chunk-GTK4KOED.js.map +1 -0
  20. package/dist/{chunk-SPSMZOCJ.js → chunk-HUHG7XTB.js} +6 -5
  21. package/dist/chunk-HUHG7XTB.js.map +1 -0
  22. package/dist/{chunk-5GMB3A77.js → chunk-IVG4XWWS.js} +26 -14
  23. package/dist/chunk-IVG4XWWS.js.map +1 -0
  24. package/dist/{chunk-WAI2IYIQ.js → chunk-P635FAN4.js} +50 -7
  25. package/dist/chunk-P635FAN4.js.map +1 -0
  26. package/dist/{chunk-45BZGB77.js → chunk-QNXHDOJ5.js} +218 -24
  27. package/dist/chunk-QNXHDOJ5.js.map +1 -0
  28. package/dist/{chunk-UAHMP6GC.js → chunk-QPC6JHA3.js} +10 -7
  29. package/dist/chunk-QPC6JHA3.js.map +1 -0
  30. package/dist/{chunk-Q6PPMXJC.js → chunk-SN7PIVDF.js} +377 -21
  31. package/dist/chunk-SN7PIVDF.js.map +1 -0
  32. package/dist/{chunk-A6W4QALF.js → chunk-TC6A7GMF.js} +2 -2
  33. package/dist/{chunk-2DFNOLMO.js → chunk-XDNT6ZNZ.js} +9 -6
  34. package/dist/chunk-XDNT6ZNZ.js.map +1 -0
  35. package/dist/{chunk-CEXBMOI5.js → chunk-Z6JP6MYD.js} +2 -2
  36. package/dist/cli.js +5867 -438
  37. package/dist/cli.js.map +1 -1
  38. package/dist/client-runtime.d.ts +4 -2
  39. package/dist/client-runtime.js +7 -7
  40. package/dist/contracts/generate.js +1 -1
  41. package/dist/dr.d.ts +9 -2
  42. package/dist/dr.js +6 -4
  43. package/dist/{gateway-CggQ8vTC.d.ts → gateway-CW-61lvs.d.ts} +27 -3
  44. package/dist/gateway-main.js +71 -7
  45. package/dist/gateway-main.js.map +1 -1
  46. package/dist/gateway.d.ts +3 -3
  47. package/dist/gateway.js +3 -3
  48. package/dist/index.js +8 -8
  49. package/dist/{postgres-bridge-store-Bfd3hRId.d.ts → postgres-bridge-store-C9KG9Z69.d.ts} +1 -1
  50. package/dist/postgres-production-preflight.d.ts +32 -0
  51. package/dist/postgres-production-preflight.js +249 -0
  52. package/dist/postgres-production-preflight.js.map +1 -0
  53. package/dist/server.js +8 -8
  54. package/dist/sqlite-edge-store-CdMIOrho.d.ts +148 -0
  55. package/dist/sqlite.d.ts +19 -80
  56. package/dist/sqlite.js +11 -3
  57. package/docs/architecture-v2.md +292 -15
  58. package/docs/decisions/0004-client-lifecycle-and-endpoint-migration.md +204 -0
  59. package/docs/deployment.md +349 -0
  60. package/docs/troubleshooting.md +23 -0
  61. package/llms.txt +69 -1
  62. package/openapi/agent-bridge-v2.openapi.json +1151 -124
  63. package/package.json +10 -2
  64. package/schemas/agent-bridge-v2.capabilities.json +26 -1
  65. package/schemas/agent-bridge-v2.mcp.json +11 -1
  66. package/schemas/agent-bridge-v2.schema.json +167 -0
  67. package/sql/migrations/007_runtime_role.sql +8 -4
  68. package/sql/migrations/013_row_isolation.sql +71 -8
  69. package/sql/migrations/014_owner_control_plane.sql +124 -31
  70. package/sql/migrations/015_portable_archives.sql +143 -41
  71. package/sql/migrations/016_native_dr_fence.sql +102 -35
  72. package/sql/migrations/017_gateway_authority_binding.sql +99 -0
  73. package/sql/migrations/018_endpoint_migration_challenges.sql +1054 -0
  74. package/sql/migrations/019_endpoint_migration_same_successor.sql +348 -0
  75. package/sql/migrations/020_managed_authority_compat.sql +698 -0
  76. package/sql/migrations/021_native_backup_reader.sql +421 -0
  77. package/sql/setup.sql +1 -3
  78. package/dist/chunk-2DFNOLMO.js.map +0 -1
  79. package/dist/chunk-45BZGB77.js.map +0 -1
  80. package/dist/chunk-4VB44KJU.js.map +0 -1
  81. package/dist/chunk-5GMB3A77.js.map +0 -1
  82. package/dist/chunk-GADH244D.js.map +0 -1
  83. package/dist/chunk-MBPZXTJA.js.map +0 -1
  84. package/dist/chunk-NCO7RLBM.js.map +0 -1
  85. package/dist/chunk-Q6PPMXJC.js.map +0 -1
  86. package/dist/chunk-SPSMZOCJ.js.map +0 -1
  87. package/dist/chunk-UAHMP6GC.js.map +0 -1
  88. package/dist/chunk-WAI2IYIQ.js.map +0 -1
  89. /package/dist/{chunk-A6W4QALF.js.map → chunk-TC6A7GMF.js.map} +0 -0
  90. /package/dist/{chunk-CEXBMOI5.js.map → chunk-Z6JP6MYD.js.map} +0 -0
@@ -0,0 +1,348 @@
1
+ begin;
2
+
3
+ select pg_advisory_xact_lock(1646705660);
4
+
5
+ do $preflight$
6
+ begin
7
+ if not agent_bridge.security_schema_ready() then
8
+ raise exception 'endpoint migration same-successor preflight requires security readiness';
9
+ elsif not agent_bridge.owner_control_plane_ready() then
10
+ raise exception 'endpoint migration same-successor preflight requires owner readiness';
11
+ elsif not agent_bridge.gateway_authority_ready() then
12
+ raise exception 'endpoint migration same-successor preflight requires gateway authority readiness';
13
+ elsif not agent_bridge.endpoint_migration_challenge_ready() then
14
+ raise exception 'endpoint migration same-successor preflight requires endpoint challenge readiness';
15
+ end if;
16
+ end
17
+ $preflight$;
18
+
19
+ alter table agent_bridge.endpoint_migration_challenge_attestations
20
+ drop constraint endpoint_migration_challenge_attestation_name;
21
+ alter table agent_bridge.endpoint_migration_challenge_attestations
22
+ add constraint endpoint_migration_challenge_attestation_name
23
+ check(name in ('endpoint-migration-v1','endpoint-migration-v2'));
24
+
25
+ create or replace function agent_bridge.issue_endpoint_migration_challenge(
26
+ requested_expected_gateway_authority_id uuid,
27
+ requested_verifier_credential_id uuid,
28
+ requested_challenge text
29
+ ) returns table(
30
+ gateway_authority_id uuid,
31
+ issuer_credential_id uuid,
32
+ verifier_credential_id uuid,
33
+ expires_at timestamptz
34
+ )
35
+ language plpgsql security definer set search_path = '' as $$
36
+ declare
37
+ authority agent_bridge.request_authorities%rowtype;
38
+ gateway_id uuid;
39
+ now_time timestamptz := clock_timestamp();
40
+ challenge_commitment char(64);
41
+ existing agent_bridge.endpoint_migration_challenges%rowtype;
42
+ begin
43
+ if requested_challenge is null or requested_challenge !~ '^[0-9a-f]{64}$' then
44
+ raise exception using errcode='22023',message='endpoint migration challenge is invalid';
45
+ end if;
46
+ select * into authority from agent_bridge.active_request_authority();
47
+ if not found or authority.authorized_endpoint_migration_operation is distinct from 'issue_endpoint_migration_challenge' then
48
+ raise exception using errcode='42501',message='endpoint migration issue authorization is required';
49
+ end if;
50
+ select authority_id into strict gateway_id from agent_bridge.gateway_authority where singleton;
51
+ if requested_expected_gateway_authority_id is distinct from gateway_id then
52
+ raise exception using errcode='28000',message='expected gateway authority does not match';
53
+ end if;
54
+ if not agent_bridge.endpoint_migration_challenge_active_credential(
55
+ authority.credential_id,authority.workspace_id,authority.principal
56
+ ) or not agent_bridge.endpoint_migration_challenge_active_credential(
57
+ requested_verifier_credential_id,authority.workspace_id,authority.principal
58
+ ) or not (
59
+ authority.credential_id=requested_verifier_credential_id
60
+ or agent_bridge.endpoint_migration_challenge_direct_lineage(
61
+ authority.credential_id,requested_verifier_credential_id
62
+ )
63
+ ) then
64
+ raise exception using errcode='28000',message='endpoint migration verifier is not an active successor credential';
65
+ end if;
66
+ challenge_commitment := pg_catalog.encode(pg_catalog.sha256(pg_catalog.convert_to(
67
+ 'agent-bridge.endpoint-migration-challenge.v1:'||requested_challenge,'UTF8'
68
+ )),'hex')::character(64);
69
+ perform agent_bridge.cleanup_endpoint_migration_challenges();
70
+ select * into existing from agent_bridge.endpoint_migration_challenges
71
+ where challenge_hash=challenge_commitment for update;
72
+ if found then
73
+ if existing.authority_id=gateway_id
74
+ and existing.workspace_id=authority.workspace_id
75
+ and existing.principal=authority.principal
76
+ and existing.issuer_credential_id=authority.credential_id
77
+ and existing.verifier_credential_id=requested_verifier_credential_id
78
+ and existing.expires_at>now_time
79
+ and existing.consumed_at is null then
80
+ gateway_authority_id := existing.authority_id;
81
+ issuer_credential_id := existing.issuer_credential_id;
82
+ verifier_credential_id := existing.verifier_credential_id;
83
+ expires_at := existing.expires_at;
84
+ return next;
85
+ return;
86
+ end if;
87
+ raise exception using errcode='23505',message='endpoint migration challenge commitment conflicts with an existing challenge';
88
+ end if;
89
+ insert into agent_bridge.endpoint_migration_challenges(
90
+ challenge_hash,authority_id,workspace_id,principal,issuer_credential_id,verifier_credential_id,expires_at
91
+ ) values (
92
+ challenge_commitment,gateway_id,authority.workspace_id,authority.principal,
93
+ authority.credential_id,requested_verifier_credential_id,now_time+interval '60 seconds'
94
+ );
95
+ insert into agent_bridge.endpoint_migration_challenge_events(
96
+ request_id,event_type,outcome,authority_id,workspace_id,principal,issuer_credential_id,verifier_credential_id
97
+ ) values (
98
+ authority.request_id,'issued','succeeded',gateway_id,authority.workspace_id,authority.principal,
99
+ authority.credential_id,requested_verifier_credential_id
100
+ );
101
+ gateway_authority_id := gateway_id;
102
+ issuer_credential_id := authority.credential_id;
103
+ verifier_credential_id := requested_verifier_credential_id;
104
+ expires_at := now_time+interval '60 seconds';
105
+ return next;
106
+ end
107
+ $$;
108
+
109
+ create or replace function agent_bridge.consume_endpoint_migration_challenge(
110
+ requested_expected_gateway_authority_id uuid,
111
+ requested_issuer_credential_id uuid,
112
+ requested_challenge text
113
+ ) returns table(
114
+ gateway_authority_id uuid,
115
+ issuer_credential_id uuid,
116
+ verifier_credential_id uuid,
117
+ expires_at timestamptz,
118
+ consumed boolean
119
+ )
120
+ language plpgsql security definer set search_path = '' as $$
121
+ declare
122
+ authority agent_bridge.request_authorities%rowtype;
123
+ gateway_id uuid;
124
+ challenge agent_bridge.endpoint_migration_challenges%rowtype;
125
+ challenge_commitment char(64);
126
+ begin
127
+ if requested_challenge is null or requested_challenge !~ '^[0-9a-f]{64}$' then
128
+ raise exception using errcode='22023',message='endpoint migration challenge is invalid';
129
+ end if;
130
+ select * into authority from agent_bridge.active_request_authority();
131
+ if not found or authority.authorized_endpoint_migration_operation is distinct from 'consume_endpoint_migration_challenge' then
132
+ raise exception using errcode='42501',message='endpoint migration consume authorization is required';
133
+ end if;
134
+ select authority_id into strict gateway_id from agent_bridge.gateway_authority where singleton;
135
+ if requested_expected_gateway_authority_id is distinct from gateway_id then
136
+ raise exception using errcode='28000',message='expected gateway authority does not match';
137
+ end if;
138
+ challenge_commitment := pg_catalog.encode(pg_catalog.sha256(pg_catalog.convert_to(
139
+ 'agent-bridge.endpoint-migration-challenge.v1:'||requested_challenge,'UTF8'
140
+ )),'hex')::character(64);
141
+ select * into challenge from agent_bridge.endpoint_migration_challenges
142
+ where challenge_hash=challenge_commitment for update;
143
+ if not found then
144
+ gateway_authority_id := gateway_id;
145
+ issuer_credential_id := requested_issuer_credential_id;
146
+ verifier_credential_id := authority.credential_id;
147
+ expires_at := null;
148
+ consumed := false;
149
+ return next;
150
+ return;
151
+ end if;
152
+ gateway_authority_id := challenge.authority_id;
153
+ issuer_credential_id := challenge.issuer_credential_id;
154
+ verifier_credential_id := challenge.verifier_credential_id;
155
+ expires_at := challenge.expires_at;
156
+ consumed := false;
157
+ if challenge.authority_id is distinct from gateway_id
158
+ or challenge.authority_id is distinct from requested_expected_gateway_authority_id
159
+ or challenge.workspace_id is distinct from authority.workspace_id
160
+ or challenge.principal is distinct from authority.principal
161
+ or challenge.issuer_credential_id is distinct from requested_issuer_credential_id
162
+ or challenge.verifier_credential_id is distinct from authority.credential_id
163
+ or challenge.expires_at<=clock_timestamp()
164
+ or challenge.consumed_at is not null
165
+ or not agent_bridge.endpoint_migration_challenge_active_credential(
166
+ challenge.issuer_credential_id,challenge.workspace_id,challenge.principal
167
+ )
168
+ or not agent_bridge.endpoint_migration_challenge_active_credential(
169
+ authority.credential_id,authority.workspace_id,authority.principal
170
+ )
171
+ or not (
172
+ challenge.issuer_credential_id=authority.credential_id
173
+ or agent_bridge.endpoint_migration_challenge_direct_lineage(
174
+ challenge.issuer_credential_id,authority.credential_id
175
+ )
176
+ ) then
177
+ return next;
178
+ return;
179
+ end if;
180
+ update agent_bridge.endpoint_migration_challenges stored
181
+ set consumed_at=clock_timestamp(),consumed_credential_id=authority.credential_id
182
+ where stored.challenge_hash=challenge.challenge_hash and stored.consumed_at is null;
183
+ consumed := found;
184
+ if consumed then
185
+ insert into agent_bridge.endpoint_migration_challenge_events(
186
+ request_id,event_type,outcome,authority_id,workspace_id,principal,issuer_credential_id,verifier_credential_id
187
+ ) values (
188
+ authority.request_id,'consumed','succeeded',challenge.authority_id,
189
+ challenge.workspace_id,challenge.principal,challenge.issuer_credential_id,
190
+ challenge.verifier_credential_id
191
+ );
192
+ end if;
193
+ return next;
194
+ end
195
+ $$;
196
+
197
+ create or replace function agent_bridge.endpoint_migration_challenge_ready()
198
+ returns boolean language sql stable security definer set search_path = '' as $$
199
+ with names as (
200
+ select ('agent_bridge_runtime_'||substr(md5(current_database()),1,16))::name runtime_role
201
+ ) select
202
+ (select count(*)=1 from agent_bridge.endpoint_migration_challenge_attestations where name='endpoint-migration-v1')
203
+ and (select count(*)=1 and bool_and(catalog_definition=agent_bridge.endpoint_migration_challenge_catalog_definition())
204
+ from agent_bridge.endpoint_migration_challenge_attestations where name='endpoint-migration-v2')
205
+ and (select count(*)=1 from agent_bridge.gateway_authority where singleton)
206
+ and not exists(select 1 from pg_catalog.pg_class relation join pg_catalog.pg_namespace namespace on namespace.oid=relation.relnamespace
207
+ where namespace.nspname='agent_bridge' and relation.relname in (
208
+ 'endpoint_migration_challenges','endpoint_migration_challenge_events','endpoint_migration_challenge_attestations'
209
+ ) and (relation.relrowsecurity or relation.relforcerowsecurity))
210
+ and not exists(select 1 from unnest(array[
211
+ 'agent_bridge.endpoint_migration_challenges','agent_bridge.endpoint_migration_challenge_events',
212
+ 'agent_bridge.endpoint_migration_challenge_attestations'
213
+ ]) relation_name cross join unnest(array['SELECT','INSERT','UPDATE','DELETE','TRUNCATE','REFERENCES','TRIGGER']) privilege
214
+ where has_table_privilege('public',relation_name,privilege)
215
+ or has_table_privilege((select runtime_role from names),relation_name,privilege))
216
+ and not exists(select 1 from unnest(array[
217
+ 'agent_bridge.endpoint_migration_challenges','agent_bridge.endpoint_migration_challenge_events',
218
+ 'agent_bridge.endpoint_migration_challenge_attestations'
219
+ ]) relation_name cross join unnest(array['SELECT','INSERT','UPDATE','REFERENCES']) privilege
220
+ where has_any_column_privilege('public',relation_name,privilege)
221
+ or has_any_column_privilege((select runtime_role from names),relation_name,privilege))
222
+ and has_function_privilege((select runtime_role from names),
223
+ 'agent_bridge.issue_endpoint_migration_challenge(uuid,uuid,text)','EXECUTE')
224
+ and has_function_privilege((select runtime_role from names),
225
+ 'agent_bridge.consume_endpoint_migration_challenge(uuid,uuid,text)','EXECUTE')
226
+ and not has_function_privilege('public',
227
+ 'agent_bridge.issue_endpoint_migration_challenge(uuid,uuid,text)','EXECUTE')
228
+ and not has_function_privilege('public',
229
+ 'agent_bridge.consume_endpoint_migration_challenge(uuid,uuid,text)','EXECUTE')
230
+ and not exists(select 1 from pg_catalog.pg_proc procedure join pg_catalog.pg_namespace namespace on namespace.oid=procedure.pronamespace
231
+ where namespace.nspname='agent_bridge' and procedure.proname in (
232
+ 'cleanup_endpoint_migration_challenges','endpoint_migration_challenge_catalog_definition',
233
+ 'endpoint_migration_challenge_ready','guard_endpoint_migration_challenge',
234
+ 'reject_endpoint_migration_challenge_truncate','reject_endpoint_migration_challenge_event_mutation',
235
+ 'reject_endpoint_migration_challenge_attestation_mutation',
236
+ 'endpoint_migration_challenge_active_credential','endpoint_migration_challenge_direct_lineage'
237
+ ) and has_function_privilege((select runtime_role from names),procedure.oid,'EXECUTE'))
238
+ $$;
239
+
240
+ create or replace function agent_bridge.owner_control_plane_ready()
241
+ returns boolean language sql stable security definer set search_path = '' as $$
242
+ with names as (select
243
+ ('agent_bridge_control_owner_'||substr(md5(current_database()),1,16))::name owner_role,
244
+ ('agent_bridge_control_operator_'||substr(md5(current_database()),1,16))::name operator_role,
245
+ ('agent_bridge_control_auditor_'||substr(md5(current_database()),1,16))::name auditor_role,
246
+ (select pg_catalog.pg_get_userbyid(nspowner)::name from pg_catalog.pg_namespace where nspname='agent_bridge') schema_owner
247
+ ), latest_registry as (
248
+ select distinct on (event.member_role,event.control_role) event.member_role,event.control_role,event.action
249
+ from agent_bridge.control_membership_events event
250
+ order by event.member_role,event.control_role,event.sequence desc
251
+ ), active_registry as (
252
+ select member_role,control_role from latest_registry where action='register'
253
+ ), expected_memberships as (
254
+ select names.owner_role granted_role,names.schema_owner member_role,
255
+ true admin_option,true inherit_option,true set_option from names
256
+ union all select names.operator_role,names.schema_owner,true,true,true from names
257
+ union all select names.auditor_role,names.schema_owner,true,true,true from names
258
+ union all select case registry.control_role when 'operator' then names.operator_role else names.auditor_role end,
259
+ registry.member_role,false,true,true from active_registry registry cross join names
260
+ ), raw_memberships as (
261
+ select granted.rolname::name granted_role,member.rolname::name member_role,
262
+ membership.admin_option,
263
+ coalesce((to_jsonb(membership)->>'inherit_option')::boolean,true) inherit_option,
264
+ coalesce((to_jsonb(membership)->>'set_option')::boolean,true) set_option,
265
+ membership.grantor,member.oid member_oid
266
+ from pg_catalog.pg_auth_members membership
267
+ join pg_catalog.pg_roles granted on granted.oid=membership.roleid
268
+ join pg_catalog.pg_roles member on member.oid=membership.member
269
+ where granted.rolname in ((select owner_role from names),(select operator_role from names),(select auditor_role from names))
270
+ ), actual_memberships as (
271
+ select membership.granted_role,membership.member_role,
272
+ bool_or(membership.admin_option) admin_option,
273
+ bool_or(membership.inherit_option) inherit_option,
274
+ bool_or(membership.set_option) set_option,
275
+ bool_and(case when membership.member_role=names.schema_owner then
276
+ (membership.grantor=10 and membership.admin_option
277
+ and membership.inherit_option=membership.set_option)
278
+ or (membership.grantor=membership.member_oid
279
+ and membership.inherit_option and membership.set_option)
280
+ else membership.grantor=(select oid from pg_catalog.pg_roles where rolname=names.schema_owner)
281
+ and not membership.admin_option
282
+ and membership.inherit_option and membership.set_option end) grants_valid
283
+ from raw_memberships membership cross join names
284
+ group by membership.granted_role,membership.member_role
285
+ ), authority_closure as (
286
+ select control_role.granted_role,candidate.rolname::name member_role
287
+ from names cross join lateral(values(names.owner_role),(names.operator_role),(names.auditor_role)) control_role(granted_role)
288
+ cross join pg_catalog.pg_roles candidate
289
+ where candidate.rolname not in(names.owner_role,names.operator_role,names.auditor_role)
290
+ and(not candidate.rolsuper or candidate.rolname=names.schema_owner)
291
+ and pg_catalog.pg_has_role(candidate.rolname,control_role.granted_role,'MEMBER')
292
+ ) select
293
+ current_setting('server_version_num')::integer/10000=any(array[15,16,17,18])
294
+ and(select count(*)=1 and bool_and(catalog_definition=agent_bridge.owner_control_attestation_definition())
295
+ from agent_bridge.owner_control_attestations where name='owner-control-v6')
296
+ and not exists(
297
+ (select granted_role,member_role,admin_option,inherit_option,set_option from actual_memberships
298
+ except select granted_role,member_role,admin_option,inherit_option,set_option from expected_memberships)
299
+ union all(select granted_role,member_role,admin_option,inherit_option,set_option from expected_memberships
300
+ except select granted_role,member_role,admin_option,inherit_option,set_option from actual_memberships)
301
+ )
302
+ and not exists(select 1 from actual_memberships where not grants_valid)
303
+ and not exists(select 1 from active_registry registry left join pg_catalog.pg_roles role_record on role_record.rolname=registry.member_role
304
+ where role_record.oid is null or not role_record.rolcanlogin or role_record.rolsuper or role_record.rolcreaterole
305
+ or role_record.rolcreatedb or role_record.rolreplication or role_record.rolbypassrls)
306
+ and not exists(
307
+ (select granted_role,member_role from authority_closure except select granted_role,member_role from expected_memberships)
308
+ union all(select granted_role,member_role from expected_memberships except select granted_role,member_role from authority_closure)
309
+ )
310
+ and not exists(select 1 from active_registry registry join pg_catalog.pg_roles inherited on inherited.rolname<>registry.member_role
311
+ where pg_catalog.pg_has_role(registry.member_role,inherited.rolname,'MEMBER') and not exists(
312
+ select 1 from active_registry permitted cross join names where permitted.member_role=registry.member_role
313
+ and inherited.rolname=case permitted.control_role when 'operator' then names.operator_role else names.auditor_role end
314
+ ))
315
+ and not exists(select 1 from active_registry registry cross join pg_catalog.pg_roles candidate,names
316
+ where candidate.rolname not in(registry.member_role,names.schema_owner) and not candidate.rolsuper
317
+ and pg_catalog.pg_has_role(candidate.rolname,registry.member_role,'MEMBER'))
318
+ $$;
319
+
320
+ insert into agent_bridge.endpoint_migration_challenge_attestations(name,catalog_definition)
321
+ values('endpoint-migration-v2',agent_bridge.endpoint_migration_challenge_catalog_definition());
322
+ select set_config(
323
+ 'role','agent_bridge_control_owner_'||substr(md5(current_database()),1,16),false
324
+ );
325
+ insert into agent_bridge.owner_control_attestations(name,catalog_definition)
326
+ values('owner-control-v6',agent_bridge.owner_control_attestation_definition());
327
+ reset role;
328
+
329
+ do $final_readiness$
330
+ begin
331
+ if not agent_bridge.security_schema_ready() then
332
+ raise exception 'endpoint migration same-successor final security readiness validation failed';
333
+ elsif not agent_bridge.owner_control_plane_ready() then
334
+ raise exception 'endpoint migration same-successor final owner readiness validation failed';
335
+ elsif not agent_bridge.gateway_authority_ready() then
336
+ raise exception 'endpoint migration same-successor final gateway authority readiness validation failed';
337
+ elsif not agent_bridge.endpoint_migration_challenge_ready() then
338
+ raise exception 'endpoint migration same-successor final endpoint readiness validation failed';
339
+ elsif not agent_bridge.portable_archive_ready() then
340
+ raise exception 'endpoint migration same-successor final portable archive readiness validation failed';
341
+ end if;
342
+ end
343
+ $final_readiness$;
344
+
345
+ insert into agent_bridge.schema_migrations(version,name,checksum)
346
+ values(19,'endpoint_migration_same_successor','__AGENT_BRIDGE_MIGRATION_CHECKSUM__');
347
+
348
+ commit;