@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.
- package/CHANGELOG.md +222 -1
- package/README.md +312 -12
- package/ROADMAP.md +88 -7
- package/SECURITY.md +78 -5
- package/SKILL.md +108 -1
- package/dist/archive.d.ts +2 -2
- package/dist/archive.js +2 -2
- package/dist/{bridge-service-hX1ZQp4W.d.ts → bridge-service-CNBKdYXh.d.ts} +2 -1
- package/dist/{bridge-store-DPVSCwfs.d.ts → bridge-store-ByJ6CaJk.d.ts} +3 -0
- package/dist/bridge.d.ts +25 -8
- package/dist/bridge.js +19 -9
- package/dist/{chunk-MBPZXTJA.js → chunk-7VJI2MXI.js} +285 -42
- package/dist/chunk-7VJI2MXI.js.map +1 -0
- package/dist/{chunk-4VB44KJU.js → chunk-AWE3DFZV.js} +3 -2
- package/dist/chunk-AWE3DFZV.js.map +1 -0
- package/dist/{chunk-GADH244D.js → chunk-E4OWHGUE.js} +16 -5
- package/dist/chunk-E4OWHGUE.js.map +1 -0
- package/dist/{chunk-NCO7RLBM.js → chunk-GTK4KOED.js} +108 -8
- package/dist/chunk-GTK4KOED.js.map +1 -0
- package/dist/{chunk-SPSMZOCJ.js → chunk-HUHG7XTB.js} +6 -5
- package/dist/chunk-HUHG7XTB.js.map +1 -0
- package/dist/{chunk-5GMB3A77.js → chunk-IVG4XWWS.js} +26 -14
- package/dist/chunk-IVG4XWWS.js.map +1 -0
- package/dist/{chunk-WAI2IYIQ.js → chunk-P635FAN4.js} +50 -7
- package/dist/chunk-P635FAN4.js.map +1 -0
- package/dist/{chunk-45BZGB77.js → chunk-QNXHDOJ5.js} +218 -24
- package/dist/chunk-QNXHDOJ5.js.map +1 -0
- package/dist/{chunk-UAHMP6GC.js → chunk-QPC6JHA3.js} +10 -7
- package/dist/chunk-QPC6JHA3.js.map +1 -0
- package/dist/{chunk-Q6PPMXJC.js → chunk-SN7PIVDF.js} +377 -21
- package/dist/chunk-SN7PIVDF.js.map +1 -0
- package/dist/{chunk-A6W4QALF.js → chunk-TC6A7GMF.js} +2 -2
- package/dist/{chunk-2DFNOLMO.js → chunk-XDNT6ZNZ.js} +9 -6
- package/dist/chunk-XDNT6ZNZ.js.map +1 -0
- package/dist/{chunk-CEXBMOI5.js → chunk-Z6JP6MYD.js} +2 -2
- package/dist/cli.js +5867 -438
- package/dist/cli.js.map +1 -1
- package/dist/client-runtime.d.ts +4 -2
- package/dist/client-runtime.js +7 -7
- package/dist/contracts/generate.js +1 -1
- package/dist/dr.d.ts +9 -2
- package/dist/dr.js +6 -4
- package/dist/{gateway-CggQ8vTC.d.ts → gateway-CW-61lvs.d.ts} +27 -3
- package/dist/gateway-main.js +71 -7
- package/dist/gateway-main.js.map +1 -1
- package/dist/gateway.d.ts +3 -3
- package/dist/gateway.js +3 -3
- package/dist/index.js +8 -8
- package/dist/{postgres-bridge-store-Bfd3hRId.d.ts → postgres-bridge-store-C9KG9Z69.d.ts} +1 -1
- package/dist/postgres-production-preflight.d.ts +32 -0
- package/dist/postgres-production-preflight.js +249 -0
- package/dist/postgres-production-preflight.js.map +1 -0
- package/dist/server.js +8 -8
- package/dist/sqlite-edge-store-CdMIOrho.d.ts +148 -0
- package/dist/sqlite.d.ts +19 -80
- package/dist/sqlite.js +11 -3
- package/docs/architecture-v2.md +292 -15
- package/docs/decisions/0004-client-lifecycle-and-endpoint-migration.md +204 -0
- package/docs/deployment.md +349 -0
- package/docs/troubleshooting.md +23 -0
- package/llms.txt +69 -1
- package/openapi/agent-bridge-v2.openapi.json +1151 -124
- package/package.json +10 -2
- package/schemas/agent-bridge-v2.capabilities.json +26 -1
- package/schemas/agent-bridge-v2.mcp.json +11 -1
- package/schemas/agent-bridge-v2.schema.json +167 -0
- package/sql/migrations/007_runtime_role.sql +8 -4
- package/sql/migrations/013_row_isolation.sql +71 -8
- package/sql/migrations/014_owner_control_plane.sql +124 -31
- package/sql/migrations/015_portable_archives.sql +143 -41
- package/sql/migrations/016_native_dr_fence.sql +102 -35
- package/sql/migrations/017_gateway_authority_binding.sql +99 -0
- package/sql/migrations/018_endpoint_migration_challenges.sql +1054 -0
- package/sql/migrations/019_endpoint_migration_same_successor.sql +348 -0
- package/sql/migrations/020_managed_authority_compat.sql +698 -0
- package/sql/migrations/021_native_backup_reader.sql +421 -0
- package/sql/setup.sql +1 -3
- package/dist/chunk-2DFNOLMO.js.map +0 -1
- package/dist/chunk-45BZGB77.js.map +0 -1
- package/dist/chunk-4VB44KJU.js.map +0 -1
- package/dist/chunk-5GMB3A77.js.map +0 -1
- package/dist/chunk-GADH244D.js.map +0 -1
- package/dist/chunk-MBPZXTJA.js.map +0 -1
- package/dist/chunk-NCO7RLBM.js.map +0 -1
- package/dist/chunk-Q6PPMXJC.js.map +0 -1
- package/dist/chunk-SPSMZOCJ.js.map +0 -1
- package/dist/chunk-UAHMP6GC.js.map +0 -1
- package/dist/chunk-WAI2IYIQ.js.map +0 -1
- /package/dist/{chunk-A6W4QALF.js.map → chunk-TC6A7GMF.js.map} +0 -0
- /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;
|