@creatornader/agent-bridge 0.2.0 → 0.3.1
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 +86 -4
- package/README.md +567 -55
- package/ROADMAP.md +114 -0
- package/SECURITY.md +90 -0
- package/SKILL.md +68 -2
- package/bin/agent-bridge +2 -2
- package/clients/claude-desktop.json +3 -1
- package/dist/archive.d.ts +163 -0
- package/dist/archive.js +50 -0
- package/dist/archive.js.map +1 -0
- package/dist/bridge-domain-CBX3IVqC.d.ts +153 -0
- package/dist/{bridge-service-CfqMcMAn.d.ts → bridge-service-hX1ZQp4W.d.ts} +15 -5
- package/dist/bridge-store-DPVSCwfs.d.ts +102 -0
- package/dist/bridge.d.ts +76 -17
- package/dist/bridge.js +52 -24
- package/dist/chunk-2DFNOLMO.js +618 -0
- package/dist/chunk-2DFNOLMO.js.map +1 -0
- package/dist/{chunk-KVR4JBRF.js → chunk-2EVLG3YA.js} +2 -2
- package/dist/{chunk-KVR4JBRF.js.map → chunk-2EVLG3YA.js.map} +1 -1
- package/dist/chunk-45BZGB77.js +709 -0
- package/dist/chunk-45BZGB77.js.map +1 -0
- package/dist/chunk-4VB44KJU.js +230 -0
- package/dist/chunk-4VB44KJU.js.map +1 -0
- package/dist/chunk-5GMB3A77.js +1013 -0
- package/dist/chunk-5GMB3A77.js.map +1 -0
- package/dist/chunk-A6W4QALF.js +1258 -0
- package/dist/chunk-A6W4QALF.js.map +1 -0
- package/dist/chunk-BZLMF5O5.js +328 -0
- package/dist/chunk-BZLMF5O5.js.map +1 -0
- package/dist/{chunk-AXL2I7FH.js → chunk-CEXBMOI5.js} +240 -79
- package/dist/chunk-CEXBMOI5.js.map +1 -0
- package/dist/chunk-GADH244D.js +527 -0
- package/dist/chunk-GADH244D.js.map +1 -0
- package/dist/chunk-MBPZXTJA.js +2428 -0
- package/dist/chunk-MBPZXTJA.js.map +1 -0
- package/dist/chunk-NCO7RLBM.js +146 -0
- package/dist/chunk-NCO7RLBM.js.map +1 -0
- package/dist/chunk-Q6PPMXJC.js +1050 -0
- package/dist/chunk-Q6PPMXJC.js.map +1 -0
- package/dist/{chunk-4KAOBC5X.js → chunk-SPSMZOCJ.js} +190 -165
- package/dist/chunk-SPSMZOCJ.js.map +1 -0
- package/dist/chunk-UAHMP6GC.js +54 -0
- package/dist/chunk-UAHMP6GC.js.map +1 -0
- package/dist/{chunk-YD6YJATN.js → chunk-VOQIDTCJ.js} +4 -2
- package/dist/chunk-VOQIDTCJ.js.map +1 -0
- package/dist/chunk-WAI2IYIQ.js +554 -0
- package/dist/chunk-WAI2IYIQ.js.map +1 -0
- package/dist/cli.d.ts +2 -1
- package/dist/cli.js +3555 -214
- package/dist/cli.js.map +1 -1
- package/dist/client-config.d.ts +1 -1
- package/dist/client-config.js +1 -1
- package/dist/client-runtime.d.ts +10 -6
- package/dist/client-runtime.js +9 -6
- package/dist/contracts/generate.d.ts +2 -0
- package/dist/contracts/generate.js +247 -0
- package/dist/contracts/generate.js.map +1 -0
- package/dist/dr.d.ts +324 -0
- package/dist/dr.js +124 -0
- package/dist/dr.js.map +1 -0
- package/dist/gateway-CggQ8vTC.d.ts +78 -0
- package/dist/gateway-main.js +190 -8
- package/dist/gateway-main.js.map +1 -1
- package/dist/gateway.d.ts +4 -3
- package/dist/gateway.js +4 -3
- package/dist/index.js +11 -8
- package/dist/index.js.map +1 -1
- package/dist/postgres-bridge-store-Bfd3hRId.d.ts +49 -0
- package/dist/server.d.ts +3 -2
- package/dist/server.js +13 -8
- package/dist/sqlite.d.ts +94 -12
- package/dist/sqlite.js +7 -4
- package/docs/architecture-v2.md +394 -0
- package/docs/decisions/0001-protocol-layers-and-acknowledgment-semantics.md +85 -0
- package/docs/decisions/0002-canonical-operation-contract-registry.md +46 -0
- package/docs/decisions/0003-host-adapters-and-consumer-instance-keys.md +88 -0
- package/docs/ecosystem.md +86 -0
- package/docs/postmortems/2026-07-08-wrapper-source-drift.md +82 -0
- package/docs/troubleshooting.md +89 -0
- package/llms.txt +107 -6
- package/openapi/agent-bridge-v2.openapi.json +9610 -0
- package/package.json +24 -4
- package/schemas/agent-bridge-v2.capabilities.json +1829 -0
- package/schemas/agent-bridge-v2.mcp.json +2074 -0
- package/schemas/agent-bridge-v2.schema.json +4560 -0
- package/sql/migrations/008_message_projects.sql +36 -0
- package/sql/migrations/009_mailbox_query_indexes.sql +28 -0
- package/sql/migrations/010_publisher_delivery_policy.sql +210 -0
- package/sql/migrations/011_credential_security.sql +875 -0
- package/sql/migrations/012_request_authority.sql +177 -0
- package/sql/migrations/013_row_isolation.sql +495 -0
- package/sql/migrations/014_owner_control_plane.sql +1641 -0
- package/sql/migrations/015_portable_archives.sql +1813 -0
- package/sql/migrations/016_native_dr_fence.sql +1005 -0
- package/bin/CLAUDE.md +0 -11
- package/dist/bridge-domain-BcnBeHOn.d.ts +0 -97
- package/dist/bridge-store-BuGjxTn4.d.ts +0 -61
- package/dist/chunk-4KAOBC5X.js.map +0 -1
- package/dist/chunk-6MAZ6YLZ.js +0 -146
- package/dist/chunk-6MAZ6YLZ.js.map +0 -1
- package/dist/chunk-AXL2I7FH.js.map +0 -1
- package/dist/chunk-BV6W4AJK.js +0 -211
- package/dist/chunk-BV6W4AJK.js.map +0 -1
- package/dist/chunk-CKSKUBDQ.js +0 -153
- package/dist/chunk-CKSKUBDQ.js.map +0 -1
- package/dist/chunk-JOUBDRYX.js +0 -272
- package/dist/chunk-JOUBDRYX.js.map +0 -1
- package/dist/chunk-JTC5YURG.js +0 -49
- package/dist/chunk-JTC5YURG.js.map +0 -1
- package/dist/chunk-O26W5QHS.js +0 -409
- package/dist/chunk-O26W5QHS.js.map +0 -1
- package/dist/chunk-WEULPMUY.js +0 -988
- package/dist/chunk-WEULPMUY.js.map +0 -1
- package/dist/chunk-YD6YJATN.js.map +0 -1
- package/dist/gateway-BULozv3K.d.ts +0 -54
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
begin;
|
|
2
|
+
|
|
3
|
+
select pg_advisory_xact_lock(1646705660);
|
|
4
|
+
|
|
5
|
+
create table agent_bridge.request_authorities (
|
|
6
|
+
backend_pid integer not null,
|
|
7
|
+
transaction_id xid8 not null,
|
|
8
|
+
request_id uuid not null,
|
|
9
|
+
credential_id uuid not null,
|
|
10
|
+
workspace_id text not null,
|
|
11
|
+
principal text not null,
|
|
12
|
+
scopes text[] not null,
|
|
13
|
+
opened_session_user name not null,
|
|
14
|
+
opened_at timestamptz not null default clock_timestamp(),
|
|
15
|
+
primary key (backend_pid, transaction_id),
|
|
16
|
+
unique (request_id)
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
revoke all on agent_bridge.request_authorities from public;
|
|
20
|
+
|
|
21
|
+
create or replace function agent_bridge.resolve_credential_hash(credential_hash text)
|
|
22
|
+
returns table(credential_id uuid, workspace_id text, principal text, scopes text[])
|
|
23
|
+
language sql volatile security definer set search_path = '' as $$
|
|
24
|
+
select credential.id,credential.workspace_id,agent.principal,credential.scopes
|
|
25
|
+
from agent_bridge.credentials credential
|
|
26
|
+
join agent_bridge.agents agent on agent.id=credential.agent_id and agent.workspace_id=credential.workspace_id
|
|
27
|
+
join agent_bridge.workspaces workspace on workspace.id=credential.workspace_id
|
|
28
|
+
where credential_hash ~ '^[0-9a-f]{64}$'
|
|
29
|
+
and credential.token_hash=credential_hash::character(64)
|
|
30
|
+
and credential.revoked_at is null
|
|
31
|
+
and (credential.expires_at is null or credential.expires_at>clock_timestamp())
|
|
32
|
+
and (not exists (select 1 from agent_bridge.credentials successor where successor.replaces_credential_id=credential.id)
|
|
33
|
+
or credential.expiry_grace_until>clock_timestamp())
|
|
34
|
+
and agent.disabled_at is null and workspace.disabled_at is null
|
|
35
|
+
limit 1
|
|
36
|
+
$$;
|
|
37
|
+
|
|
38
|
+
create or replace function agent_bridge.open_request_authority(
|
|
39
|
+
requested_credential_id uuid,
|
|
40
|
+
credential_hash text,
|
|
41
|
+
requested_request_id uuid
|
|
42
|
+
) returns table(credential_id uuid, workspace_id text, principal text, scopes text[])
|
|
43
|
+
language plpgsql security definer set search_path = '' as $$
|
|
44
|
+
declare
|
|
45
|
+
runtime_role name := ('agent_bridge_runtime_' || substr(pg_catalog.md5(pg_catalog.current_database()),1,16))::name;
|
|
46
|
+
authority_credential_id uuid;
|
|
47
|
+
authority_workspace_id text;
|
|
48
|
+
authority_principal text;
|
|
49
|
+
authority_scopes text[];
|
|
50
|
+
request_time timestamptz := clock_timestamp();
|
|
51
|
+
begin
|
|
52
|
+
if not pg_catalog.pg_has_role(session_user,runtime_role,'MEMBER')
|
|
53
|
+
or credential_hash !~ '^[0-9a-f]{64}$' then
|
|
54
|
+
raise exception using errcode='42501',message='request authority is restricted to the runtime login';
|
|
55
|
+
end if;
|
|
56
|
+
|
|
57
|
+
select credential.id,credential.workspace_id,agent.principal,credential.scopes
|
|
58
|
+
into authority_credential_id,authority_workspace_id,authority_principal,authority_scopes
|
|
59
|
+
from agent_bridge.credentials credential
|
|
60
|
+
join agent_bridge.agents agent on agent.id=credential.agent_id and agent.workspace_id=credential.workspace_id
|
|
61
|
+
join agent_bridge.workspaces workspace on workspace.id=credential.workspace_id
|
|
62
|
+
where credential.id=requested_credential_id
|
|
63
|
+
and credential.token_hash=credential_hash::character(64)
|
|
64
|
+
and credential.revoked_at is null
|
|
65
|
+
and (credential.expires_at is null or credential.expires_at>request_time)
|
|
66
|
+
and (not exists (select 1 from agent_bridge.credentials successor where successor.replaces_credential_id=credential.id)
|
|
67
|
+
or credential.expiry_grace_until>request_time)
|
|
68
|
+
and agent.disabled_at is null and workspace.disabled_at is null
|
|
69
|
+
for share of credential,agent,workspace;
|
|
70
|
+
|
|
71
|
+
if not found then return; end if;
|
|
72
|
+
|
|
73
|
+
insert into agent_bridge.request_authorities(
|
|
74
|
+
backend_pid,transaction_id,request_id,credential_id,workspace_id,principal,scopes,opened_session_user
|
|
75
|
+
) values (
|
|
76
|
+
pg_catalog.pg_backend_pid(),pg_catalog.pg_current_xact_id(),requested_request_id,
|
|
77
|
+
authority_credential_id,authority_workspace_id,authority_principal,authority_scopes,session_user
|
|
78
|
+
);
|
|
79
|
+
credential_id := authority_credential_id;
|
|
80
|
+
workspace_id := authority_workspace_id;
|
|
81
|
+
principal := authority_principal;
|
|
82
|
+
scopes := authority_scopes;
|
|
83
|
+
return next;
|
|
84
|
+
end
|
|
85
|
+
$$;
|
|
86
|
+
|
|
87
|
+
create or replace function agent_bridge.active_request_authority()
|
|
88
|
+
returns agent_bridge.request_authorities
|
|
89
|
+
language sql volatile security definer set search_path = '' as $$
|
|
90
|
+
select authority
|
|
91
|
+
from agent_bridge.request_authorities authority
|
|
92
|
+
where authority.backend_pid=pg_catalog.pg_backend_pid()
|
|
93
|
+
and authority.transaction_id=pg_catalog.pg_current_xact_id_if_assigned()
|
|
94
|
+
and authority.opened_session_user=session_user
|
|
95
|
+
$$;
|
|
96
|
+
|
|
97
|
+
create or replace function agent_bridge.assert_active_request_credential(requested_credential_id uuid)
|
|
98
|
+
returns agent_bridge.request_authorities
|
|
99
|
+
language plpgsql volatile security definer set search_path = '' as $$
|
|
100
|
+
declare authority agent_bridge.request_authorities%rowtype;
|
|
101
|
+
begin
|
|
102
|
+
select * into authority from agent_bridge.active_request_authority();
|
|
103
|
+
if not found or authority.credential_id is distinct from requested_credential_id then
|
|
104
|
+
raise exception using errcode='28000',message='active request authority is required';
|
|
105
|
+
end if;
|
|
106
|
+
return authority;
|
|
107
|
+
end
|
|
108
|
+
$$;
|
|
109
|
+
|
|
110
|
+
create or replace function agent_bridge.close_request_authority() returns void
|
|
111
|
+
language plpgsql volatile security definer set search_path = '' as $$
|
|
112
|
+
declare authority agent_bridge.request_authorities%rowtype;
|
|
113
|
+
begin
|
|
114
|
+
select * into authority from agent_bridge.active_request_authority();
|
|
115
|
+
if not found then
|
|
116
|
+
raise exception using errcode='28000',message='active request authority is required';
|
|
117
|
+
end if;
|
|
118
|
+
delete from agent_bridge.request_authorities
|
|
119
|
+
where backend_pid=authority.backend_pid and transaction_id=authority.transaction_id;
|
|
120
|
+
end
|
|
121
|
+
$$;
|
|
122
|
+
|
|
123
|
+
alter function agent_bridge.record_scope_denial(uuid,text,uuid) rename to record_scope_denial_unbound_011;
|
|
124
|
+
alter function agent_bridge.consume_rate_limit(uuid,text,uuid) rename to consume_rate_limit_unbound_011;
|
|
125
|
+
|
|
126
|
+
create function agent_bridge.record_scope_denial(uuid,text,uuid) returns void
|
|
127
|
+
language plpgsql security definer set search_path = '' as $$
|
|
128
|
+
begin
|
|
129
|
+
perform agent_bridge.assert_active_request_credential($1);
|
|
130
|
+
perform agent_bridge.record_scope_denial_unbound_011($1,$2,$3);
|
|
131
|
+
end
|
|
132
|
+
$$;
|
|
133
|
+
|
|
134
|
+
create function agent_bridge.consume_rate_limit(uuid,text,uuid)
|
|
135
|
+
returns table(allowed boolean,limit_value integer,remaining_value integer,retry_after_seconds numeric,denied_policy_id text)
|
|
136
|
+
language plpgsql security definer set search_path = '' as $$
|
|
137
|
+
begin
|
|
138
|
+
perform agent_bridge.assert_active_request_credential($1);
|
|
139
|
+
return query select * from agent_bridge.consume_rate_limit_unbound_011($1,$2,$3);
|
|
140
|
+
end
|
|
141
|
+
$$;
|
|
142
|
+
|
|
143
|
+
revoke all on function agent_bridge.open_request_authority(uuid,text,uuid) from public;
|
|
144
|
+
revoke all on function agent_bridge.resolve_credential_hash(text) from public;
|
|
145
|
+
revoke all on function agent_bridge.active_request_authority() from public;
|
|
146
|
+
revoke all on function agent_bridge.assert_active_request_credential(uuid) from public;
|
|
147
|
+
revoke all on function agent_bridge.close_request_authority() from public;
|
|
148
|
+
revoke all on function agent_bridge.record_scope_denial_unbound_011(uuid,text,uuid) from public;
|
|
149
|
+
revoke all on function agent_bridge.consume_rate_limit_unbound_011(uuid,text,uuid) from public;
|
|
150
|
+
revoke all on function agent_bridge.record_scope_denial(uuid,text,uuid) from public;
|
|
151
|
+
revoke all on function agent_bridge.consume_rate_limit(uuid,text,uuid) from public;
|
|
152
|
+
|
|
153
|
+
do $roles$
|
|
154
|
+
declare
|
|
155
|
+
runtime_role text := 'agent_bridge_runtime_' || substr(md5(current_database()),1,16);
|
|
156
|
+
role_name text;
|
|
157
|
+
begin
|
|
158
|
+
foreach role_name in array array[runtime_role,'anon','authenticated'] loop
|
|
159
|
+
if exists (select 1 from pg_roles where rolname=role_name) then
|
|
160
|
+
execute format('revoke all on function agent_bridge.record_scope_denial_unbound_011(uuid,text,uuid) from %I',role_name);
|
|
161
|
+
execute format('revoke all on function agent_bridge.consume_rate_limit_unbound_011(uuid,text,uuid) from %I',role_name);
|
|
162
|
+
end if;
|
|
163
|
+
end loop;
|
|
164
|
+
execute format('revoke select on agent_bridge.credentials,agent_bridge.agents,agent_bridge.workspaces from %I',runtime_role);
|
|
165
|
+
execute format('revoke all on agent_bridge.request_authorities from %I',runtime_role);
|
|
166
|
+
execute format('grant execute on function agent_bridge.open_request_authority(uuid,text,uuid) to %I',runtime_role);
|
|
167
|
+
execute format('grant execute on function agent_bridge.resolve_credential_hash(text) to %I',runtime_role);
|
|
168
|
+
execute format('grant execute on function agent_bridge.close_request_authority() to %I',runtime_role);
|
|
169
|
+
execute format('grant execute on function agent_bridge.record_scope_denial(uuid,text,uuid) to %I',runtime_role);
|
|
170
|
+
execute format('grant execute on function agent_bridge.consume_rate_limit(uuid,text,uuid) to %I',runtime_role);
|
|
171
|
+
end
|
|
172
|
+
$roles$;
|
|
173
|
+
|
|
174
|
+
insert into agent_bridge.schema_migrations(version,name,checksum)
|
|
175
|
+
values (12,'request_authority','__AGENT_BRIDGE_MIGRATION_CHECKSUM__');
|
|
176
|
+
|
|
177
|
+
commit;
|
|
@@ -0,0 +1,495 @@
|
|
|
1
|
+
begin;
|
|
2
|
+
|
|
3
|
+
select pg_advisory_xact_lock(1646705660);
|
|
4
|
+
|
|
5
|
+
do $roles$
|
|
6
|
+
declare
|
|
7
|
+
suffix text := substr(md5(current_database()),1,16);
|
|
8
|
+
data_owner text := 'agent_bridge_data_owner_' || suffix;
|
|
9
|
+
context_reader text := 'agent_bridge_context_reader_' || suffix;
|
|
10
|
+
event_writer text := 'agent_bridge_event_writer_' || suffix;
|
|
11
|
+
role_name text;
|
|
12
|
+
begin
|
|
13
|
+
foreach role_name in array array[data_owner,context_reader,event_writer] loop
|
|
14
|
+
if not exists (select 1 from pg_roles where rolname=role_name) then
|
|
15
|
+
execute format(
|
|
16
|
+
'create role %I nologin nosuperuser nocreatedb nocreaterole noreplication nobypassrls',
|
|
17
|
+
role_name
|
|
18
|
+
);
|
|
19
|
+
end if;
|
|
20
|
+
execute format(
|
|
21
|
+
'alter role %I nologin nosuperuser nocreatedb nocreaterole noreplication nobypassrls',
|
|
22
|
+
role_name
|
|
23
|
+
);
|
|
24
|
+
execute format('grant %I to %I with admin option',role_name,current_user);
|
|
25
|
+
end loop;
|
|
26
|
+
end
|
|
27
|
+
$roles$;
|
|
28
|
+
|
|
29
|
+
alter table agent_bridge.messages
|
|
30
|
+
add constraint messages_workspace_id_source_unique unique(workspace,id,source);
|
|
31
|
+
|
|
32
|
+
alter table agent_bridge.deliveries add column publisher text;
|
|
33
|
+
update agent_bridge.deliveries delivery
|
|
34
|
+
set publisher=message.source
|
|
35
|
+
from agent_bridge.messages message
|
|
36
|
+
where message.workspace=delivery.workspace and message.id=delivery.message_id;
|
|
37
|
+
alter table agent_bridge.deliveries alter column publisher set not null;
|
|
38
|
+
alter table agent_bridge.deliveries
|
|
39
|
+
add constraint deliveries_publisher_message_fk
|
|
40
|
+
foreign key(workspace,message_id,publisher)
|
|
41
|
+
references agent_bridge.messages(workspace,id,source) on delete cascade,
|
|
42
|
+
add constraint deliveries_event_identity_unique
|
|
43
|
+
unique(workspace,id,message_id,publisher);
|
|
44
|
+
|
|
45
|
+
alter table agent_bridge.delivery_events add column publisher text;
|
|
46
|
+
update agent_bridge.delivery_events event
|
|
47
|
+
set publisher=delivery.publisher
|
|
48
|
+
from agent_bridge.deliveries delivery
|
|
49
|
+
where delivery.workspace=event.workspace
|
|
50
|
+
and delivery.id=event.delivery_id
|
|
51
|
+
and delivery.message_id=event.message_id;
|
|
52
|
+
alter table agent_bridge.delivery_events alter column publisher set not null;
|
|
53
|
+
alter table agent_bridge.delivery_events
|
|
54
|
+
add constraint delivery_events_delivery_publisher_fk
|
|
55
|
+
foreign key(workspace,delivery_id,message_id,publisher)
|
|
56
|
+
references agent_bridge.deliveries(workspace,id,message_id,publisher) on delete cascade;
|
|
57
|
+
|
|
58
|
+
create table agent_bridge.row_isolation_attestations (
|
|
59
|
+
name text primary key,
|
|
60
|
+
catalog_definition text not null,
|
|
61
|
+
attested_at timestamptz not null default now(),
|
|
62
|
+
constraint row_isolation_attestation_name check(name='domain-v1')
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
create or replace function agent_bridge.reject_delivery_identity_mutation() returns trigger
|
|
66
|
+
language plpgsql set search_path = '' as $$
|
|
67
|
+
begin
|
|
68
|
+
if old.id is distinct from new.id
|
|
69
|
+
or old.message_id is distinct from new.message_id
|
|
70
|
+
or old.workspace is distinct from new.workspace
|
|
71
|
+
or old.recipient is distinct from new.recipient
|
|
72
|
+
or old.publisher is distinct from new.publisher
|
|
73
|
+
or old.created_at is distinct from new.created_at then
|
|
74
|
+
raise exception 'delivery identity is immutable';
|
|
75
|
+
end if;
|
|
76
|
+
return new;
|
|
77
|
+
end
|
|
78
|
+
$$;
|
|
79
|
+
revoke all on function agent_bridge.reject_delivery_identity_mutation() from public;
|
|
80
|
+
drop trigger if exists deliveries_identity_immutable on agent_bridge.deliveries;
|
|
81
|
+
create trigger deliveries_identity_immutable
|
|
82
|
+
before update on agent_bridge.deliveries
|
|
83
|
+
for each row execute function agent_bridge.reject_delivery_identity_mutation();
|
|
84
|
+
|
|
85
|
+
create or replace function agent_bridge.enforce_delivery_actor_role() returns trigger
|
|
86
|
+
language plpgsql set search_path = '' as $$
|
|
87
|
+
declare
|
|
88
|
+
data_owner name := ('agent_bridge_data_owner_' || substr(pg_catalog.md5(pg_catalog.current_database()),1,16))::name;
|
|
89
|
+
writes_event boolean;
|
|
90
|
+
principal text;
|
|
91
|
+
begin
|
|
92
|
+
if pg_catalog.pg_has_role(current_user,data_owner,'MEMBER') then
|
|
93
|
+
return new;
|
|
94
|
+
end if;
|
|
95
|
+
principal := agent_bridge.current_request_principal();
|
|
96
|
+
if tg_op='INSERT' then
|
|
97
|
+
if principal is distinct from new.publisher then
|
|
98
|
+
raise exception 'only the delivery publisher may create delivery state';
|
|
99
|
+
end if;
|
|
100
|
+
if new.state<>'pending' or new.attempt<>0 or new.cycle_attempt<>0
|
|
101
|
+
or new.requeue_count<>0 or new.lease_token is not null
|
|
102
|
+
or new.lease_owner is not null or new.lease_expires_at is not null
|
|
103
|
+
or new.last_error is not null or new.last_action<>'created'
|
|
104
|
+
or new.last_actor is distinct from principal then
|
|
105
|
+
raise exception 'publisher delivery creation must use canonical initial state';
|
|
106
|
+
end if;
|
|
107
|
+
return new;
|
|
108
|
+
end if;
|
|
109
|
+
writes_event := old.state is distinct from new.state
|
|
110
|
+
or old.attempt is distinct from new.attempt
|
|
111
|
+
or old.cycle_attempt is distinct from new.cycle_attempt
|
|
112
|
+
or old.requeue_count is distinct from new.requeue_count
|
|
113
|
+
or old.last_action is distinct from new.last_action;
|
|
114
|
+
if not writes_event then
|
|
115
|
+
if principal is distinct from old.recipient then
|
|
116
|
+
raise exception 'only the delivery recipient may update lease state';
|
|
117
|
+
end if;
|
|
118
|
+
if old.last_actor is distinct from new.last_actor then
|
|
119
|
+
raise exception 'delivery actor may change only with an audited transition';
|
|
120
|
+
end if;
|
|
121
|
+
return new;
|
|
122
|
+
end if;
|
|
123
|
+
if new.state='cancelled' or new.last_action='cancel' then
|
|
124
|
+
if principal is distinct from old.publisher then
|
|
125
|
+
raise exception 'only the delivery publisher may cancel';
|
|
126
|
+
end if;
|
|
127
|
+
if old.state not in ('pending','retrying','claimed')
|
|
128
|
+
or new.state<>'cancelled' or new.last_action<>'cancel' then
|
|
129
|
+
raise exception 'publisher cancel requires a cancellation transition';
|
|
130
|
+
end if;
|
|
131
|
+
if new.last_actor is distinct from principal then
|
|
132
|
+
raise exception 'publisher delivery actor must match request authority';
|
|
133
|
+
end if;
|
|
134
|
+
elsif (old.state in ('dead','cancelled') and new.state='pending')
|
|
135
|
+
or new.last_action='requeue' then
|
|
136
|
+
if principal is distinct from old.publisher then
|
|
137
|
+
raise exception 'only the delivery publisher may requeue';
|
|
138
|
+
end if;
|
|
139
|
+
if old.state not in ('dead','cancelled')
|
|
140
|
+
or new.state<>'pending' or new.last_action<>'requeue' then
|
|
141
|
+
raise exception 'publisher requeue requires a terminal-to-pending transition';
|
|
142
|
+
end if;
|
|
143
|
+
if new.last_actor is distinct from principal then
|
|
144
|
+
raise exception 'publisher delivery actor must match request authority';
|
|
145
|
+
end if;
|
|
146
|
+
elsif principal is distinct from old.recipient then
|
|
147
|
+
raise exception 'only the delivery recipient may update delivery state';
|
|
148
|
+
elsif new.last_action in ('message_expired','lease_expired') then
|
|
149
|
+
if new.last_actor is distinct from 'agent-bridge' then
|
|
150
|
+
raise exception 'system delivery actor is invalid';
|
|
151
|
+
end if;
|
|
152
|
+
elsif new.last_action='attempts_exhausted' then
|
|
153
|
+
if new.last_actor is distinct from 'agent-bridge'
|
|
154
|
+
and new.last_actor is distinct from principal then
|
|
155
|
+
raise exception 'exhausted delivery actor must match request authority or system';
|
|
156
|
+
end if;
|
|
157
|
+
elsif new.last_actor is distinct from principal then
|
|
158
|
+
raise exception 'recipient delivery actor must match request authority';
|
|
159
|
+
end if;
|
|
160
|
+
return new;
|
|
161
|
+
end
|
|
162
|
+
$$;
|
|
163
|
+
revoke all on function agent_bridge.enforce_delivery_actor_role() from public;
|
|
164
|
+
drop trigger if exists deliveries_actor_role on agent_bridge.deliveries;
|
|
165
|
+
create trigger deliveries_actor_role
|
|
166
|
+
before insert or update on agent_bridge.deliveries
|
|
167
|
+
for each row execute function agent_bridge.enforce_delivery_actor_role();
|
|
168
|
+
|
|
169
|
+
create or replace function agent_bridge.reject_delivery_event_mutation() returns trigger
|
|
170
|
+
language plpgsql set search_path = '' as $$
|
|
171
|
+
begin
|
|
172
|
+
raise exception 'delivery events are append-only';
|
|
173
|
+
end
|
|
174
|
+
$$;
|
|
175
|
+
revoke all on function agent_bridge.reject_delivery_event_mutation() from public;
|
|
176
|
+
drop trigger if exists delivery_events_append_only on agent_bridge.delivery_events;
|
|
177
|
+
create trigger delivery_events_append_only
|
|
178
|
+
before update or delete or truncate on agent_bridge.delivery_events
|
|
179
|
+
for each statement execute function agent_bridge.reject_delivery_event_mutation();
|
|
180
|
+
|
|
181
|
+
create or replace function agent_bridge.record_delivery_event() returns trigger
|
|
182
|
+
language plpgsql security definer set search_path = '' as $$
|
|
183
|
+
begin
|
|
184
|
+
if tg_op = 'INSERT'
|
|
185
|
+
or old.state is distinct from new.state
|
|
186
|
+
or old.attempt is distinct from new.attempt
|
|
187
|
+
or old.cycle_attempt is distinct from new.cycle_attempt
|
|
188
|
+
or old.requeue_count is distinct from new.requeue_count
|
|
189
|
+
or old.last_action is distinct from new.last_action then
|
|
190
|
+
insert into agent_bridge.delivery_events (
|
|
191
|
+
delivery_id,message_id,workspace,publisher,recipient,from_state,to_state,
|
|
192
|
+
attempt,cycle_attempt,requeue_count,lease_owner,error,actor,action
|
|
193
|
+
) values (
|
|
194
|
+
new.id,new.message_id,new.workspace,new.publisher,new.recipient,
|
|
195
|
+
case when tg_op='INSERT' then null else old.state end,
|
|
196
|
+
new.state,new.attempt,new.cycle_attempt,new.requeue_count,
|
|
197
|
+
new.lease_owner,new.last_error,coalesce(new.last_actor,new.recipient),new.last_action
|
|
198
|
+
);
|
|
199
|
+
end if;
|
|
200
|
+
return new;
|
|
201
|
+
end
|
|
202
|
+
$$;
|
|
203
|
+
|
|
204
|
+
create or replace function agent_bridge.current_request_workspace() returns text
|
|
205
|
+
language sql stable security definer set search_path = '' as $$
|
|
206
|
+
select authority.workspace_id
|
|
207
|
+
from agent_bridge.request_authorities authority
|
|
208
|
+
where pg_catalog.pg_has_role(
|
|
209
|
+
session_user,
|
|
210
|
+
('agent_bridge_runtime_' || substr(pg_catalog.md5(pg_catalog.current_database()),1,16))::name,
|
|
211
|
+
'MEMBER'
|
|
212
|
+
)
|
|
213
|
+
and authority.backend_pid=pg_catalog.pg_backend_pid()
|
|
214
|
+
and authority.transaction_id=pg_catalog.pg_current_xact_id_if_assigned()
|
|
215
|
+
and authority.opened_session_user=session_user
|
|
216
|
+
$$;
|
|
217
|
+
|
|
218
|
+
create or replace function agent_bridge.current_request_principal() returns text
|
|
219
|
+
language sql stable security definer set search_path = '' as $$
|
|
220
|
+
select authority.principal
|
|
221
|
+
from agent_bridge.request_authorities authority
|
|
222
|
+
where pg_catalog.pg_has_role(
|
|
223
|
+
session_user,
|
|
224
|
+
('agent_bridge_runtime_' || substr(pg_catalog.md5(pg_catalog.current_database()),1,16))::name,
|
|
225
|
+
'MEMBER'
|
|
226
|
+
)
|
|
227
|
+
and authority.backend_pid=pg_catalog.pg_backend_pid()
|
|
228
|
+
and authority.transaction_id=pg_catalog.pg_current_xact_id_if_assigned()
|
|
229
|
+
and authority.opened_session_user=session_user
|
|
230
|
+
$$;
|
|
231
|
+
|
|
232
|
+
create or replace function agent_bridge.row_isolation_catalog_definition() returns text
|
|
233
|
+
language sql stable set search_path = '' as $$
|
|
234
|
+
with domain_tables(table_name) as (
|
|
235
|
+
values ('messages'),('receipts'),('deliveries'),('delivery_events'),('agent_instances')
|
|
236
|
+
), catalog_objects(kind,identity,definition) as (
|
|
237
|
+
select 'policy',relation.relname || '.' || policy.polname,
|
|
238
|
+
policy.polcmd::text || ':' || policy.polpermissive::text || ':' ||
|
|
239
|
+
coalesce(pg_catalog.pg_get_expr(policy.polqual,policy.polrelid),'') || ':' ||
|
|
240
|
+
coalesce(pg_catalog.pg_get_expr(policy.polwithcheck,policy.polrelid),'')
|
|
241
|
+
from pg_catalog.pg_policy policy
|
|
242
|
+
join pg_catalog.pg_class relation on relation.oid=policy.polrelid
|
|
243
|
+
join pg_catalog.pg_namespace namespace on namespace.oid=relation.relnamespace
|
|
244
|
+
where namespace.nspname='agent_bridge'
|
|
245
|
+
and relation.relname in (select table_name from domain_tables)
|
|
246
|
+
union all
|
|
247
|
+
select 'constraint',constraint_record.conrelid::regclass::text || '.' || constraint_record.conname,
|
|
248
|
+
pg_catalog.pg_get_constraintdef(constraint_record.oid,true)
|
|
249
|
+
from pg_catalog.pg_constraint constraint_record
|
|
250
|
+
join pg_catalog.pg_class constraint_relation on constraint_relation.oid=constraint_record.conrelid
|
|
251
|
+
join pg_catalog.pg_namespace constraint_namespace on constraint_namespace.oid=constraint_relation.relnamespace
|
|
252
|
+
where constraint_namespace.nspname='agent_bridge'
|
|
253
|
+
and constraint_relation.relname in (
|
|
254
|
+
select table_name from domain_tables
|
|
255
|
+
union all select 'row_isolation_attestations'
|
|
256
|
+
)
|
|
257
|
+
union all
|
|
258
|
+
select 'trigger',trigger.tgrelid::regclass::text || '.' || trigger.tgname,
|
|
259
|
+
pg_catalog.pg_get_triggerdef(trigger.oid,true)
|
|
260
|
+
from pg_catalog.pg_trigger trigger
|
|
261
|
+
join pg_catalog.pg_class trigger_relation on trigger_relation.oid=trigger.tgrelid
|
|
262
|
+
join pg_catalog.pg_namespace trigger_namespace on trigger_namespace.oid=trigger_relation.relnamespace
|
|
263
|
+
where not trigger.tgisinternal
|
|
264
|
+
and trigger_namespace.nspname='agent_bridge'
|
|
265
|
+
and trigger_relation.relname in (select table_name from domain_tables)
|
|
266
|
+
union all
|
|
267
|
+
select 'function',procedure.oid::regprocedure::text,
|
|
268
|
+
pg_catalog.pg_get_userbyid(procedure.proowner) || ':' ||
|
|
269
|
+
pg_catalog.pg_get_functiondef(procedure.oid)
|
|
270
|
+
from pg_catalog.pg_proc procedure
|
|
271
|
+
join pg_catalog.pg_namespace namespace on namespace.oid=procedure.pronamespace
|
|
272
|
+
where namespace.nspname='agent_bridge' and procedure.proname in (
|
|
273
|
+
'current_request_workspace','current_request_principal','record_delivery_event',
|
|
274
|
+
'reject_delivery_identity_mutation','enforce_delivery_actor_role',
|
|
275
|
+
'reject_delivery_event_mutation','row_isolation_catalog_definition'
|
|
276
|
+
)
|
|
277
|
+
)
|
|
278
|
+
select string_agg(kind || E'\x1f' || identity || E'\x1f' || definition,E'\x1e'
|
|
279
|
+
order by kind,identity)
|
|
280
|
+
from catalog_objects
|
|
281
|
+
$$;
|
|
282
|
+
|
|
283
|
+
revoke all on function agent_bridge.current_request_workspace() from public;
|
|
284
|
+
revoke all on function agent_bridge.current_request_principal() from public;
|
|
285
|
+
revoke all on function agent_bridge.row_isolation_catalog_definition() from public;
|
|
286
|
+
|
|
287
|
+
do $owners$
|
|
288
|
+
declare
|
|
289
|
+
suffix text := substr(md5(current_database()),1,16);
|
|
290
|
+
data_owner text := 'agent_bridge_data_owner_' || suffix;
|
|
291
|
+
context_reader text := 'agent_bridge_context_reader_' || suffix;
|
|
292
|
+
event_writer text := 'agent_bridge_event_writer_' || suffix;
|
|
293
|
+
table_name text;
|
|
294
|
+
begin
|
|
295
|
+
execute format('grant usage on schema agent_bridge to %I',data_owner);
|
|
296
|
+
foreach table_name in array array[
|
|
297
|
+
'messages','receipts','deliveries','delivery_events','agent_instances'
|
|
298
|
+
] loop
|
|
299
|
+
execute format('alter table agent_bridge.%I owner to %I',table_name,data_owner);
|
|
300
|
+
end loop;
|
|
301
|
+
execute format('alter function agent_bridge.current_request_workspace() owner to %I',context_reader);
|
|
302
|
+
execute format('alter function agent_bridge.current_request_principal() owner to %I',context_reader);
|
|
303
|
+
execute format('alter function agent_bridge.record_delivery_event() owner to %I',event_writer);
|
|
304
|
+
execute format('grant usage on schema agent_bridge to %I',context_reader);
|
|
305
|
+
execute format('grant select on agent_bridge.request_authorities to %I',context_reader);
|
|
306
|
+
execute format('grant usage on schema agent_bridge to %I',event_writer);
|
|
307
|
+
execute format('grant insert on agent_bridge.delivery_events to %I',event_writer);
|
|
308
|
+
execute format('grant usage on sequence agent_bridge.delivery_events_sequence_seq to %I',event_writer);
|
|
309
|
+
end
|
|
310
|
+
$owners$;
|
|
311
|
+
|
|
312
|
+
revoke execute on all functions in schema agent_bridge from public;
|
|
313
|
+
|
|
314
|
+
alter table agent_bridge.messages enable row level security;
|
|
315
|
+
alter table agent_bridge.messages force row level security;
|
|
316
|
+
alter table agent_bridge.receipts enable row level security;
|
|
317
|
+
alter table agent_bridge.receipts force row level security;
|
|
318
|
+
alter table agent_bridge.deliveries enable row level security;
|
|
319
|
+
alter table agent_bridge.deliveries force row level security;
|
|
320
|
+
alter table agent_bridge.delivery_events enable row level security;
|
|
321
|
+
alter table agent_bridge.delivery_events force row level security;
|
|
322
|
+
alter table agent_bridge.agent_instances enable row level security;
|
|
323
|
+
alter table agent_bridge.agent_instances force row level security;
|
|
324
|
+
|
|
325
|
+
do $policies$
|
|
326
|
+
declare
|
|
327
|
+
suffix text := substr(md5(current_database()),1,16);
|
|
328
|
+
runtime_role text := 'agent_bridge_runtime_' || suffix;
|
|
329
|
+
data_owner text := 'agent_bridge_data_owner_' || suffix;
|
|
330
|
+
event_writer text := 'agent_bridge_event_writer_' || suffix;
|
|
331
|
+
table_name text;
|
|
332
|
+
begin
|
|
333
|
+
foreach table_name in array array[
|
|
334
|
+
'messages','receipts','deliveries','delivery_events','agent_instances'
|
|
335
|
+
] loop
|
|
336
|
+
execute format(
|
|
337
|
+
'create policy %I on agent_bridge.%I for all to %I using (true) with check (true)',
|
|
338
|
+
table_name || '_owner_all',table_name,data_owner
|
|
339
|
+
);
|
|
340
|
+
end loop;
|
|
341
|
+
|
|
342
|
+
execute format($policy$
|
|
343
|
+
create policy messages_runtime_select on agent_bridge.messages
|
|
344
|
+
for select to %I using (
|
|
345
|
+
workspace=(select agent_bridge.current_request_workspace())
|
|
346
|
+
and (
|
|
347
|
+
source=(select agent_bridge.current_request_principal())
|
|
348
|
+
or targets='[]'::jsonb
|
|
349
|
+
or targets ? (select agent_bridge.current_request_principal())
|
|
350
|
+
)
|
|
351
|
+
)$policy$,runtime_role);
|
|
352
|
+
execute format($policy$
|
|
353
|
+
create policy messages_runtime_insert on agent_bridge.messages
|
|
354
|
+
for insert to %I with check (
|
|
355
|
+
workspace=(select agent_bridge.current_request_workspace())
|
|
356
|
+
and source=(select agent_bridge.current_request_principal())
|
|
357
|
+
)$policy$,runtime_role);
|
|
358
|
+
|
|
359
|
+
execute format($policy$
|
|
360
|
+
create policy receipts_runtime_select on agent_bridge.receipts
|
|
361
|
+
for select to %I using (
|
|
362
|
+
workspace=(select agent_bridge.current_request_workspace())
|
|
363
|
+
and principal=(select agent_bridge.current_request_principal())
|
|
364
|
+
)$policy$,runtime_role);
|
|
365
|
+
execute format($policy$
|
|
366
|
+
create policy receipts_runtime_insert on agent_bridge.receipts
|
|
367
|
+
for insert to %I with check (
|
|
368
|
+
workspace=(select agent_bridge.current_request_workspace())
|
|
369
|
+
and principal=(select agent_bridge.current_request_principal())
|
|
370
|
+
)$policy$,runtime_role);
|
|
371
|
+
|
|
372
|
+
execute format($policy$
|
|
373
|
+
create policy deliveries_runtime_select on agent_bridge.deliveries
|
|
374
|
+
for select to %I using (
|
|
375
|
+
workspace=(select agent_bridge.current_request_workspace())
|
|
376
|
+
and (
|
|
377
|
+
recipient=(select agent_bridge.current_request_principal())
|
|
378
|
+
or publisher=(select agent_bridge.current_request_principal())
|
|
379
|
+
)
|
|
380
|
+
)$policy$,runtime_role);
|
|
381
|
+
execute format($policy$
|
|
382
|
+
create policy deliveries_runtime_insert on agent_bridge.deliveries
|
|
383
|
+
for insert to %I with check (
|
|
384
|
+
workspace=(select agent_bridge.current_request_workspace())
|
|
385
|
+
and publisher=(select agent_bridge.current_request_principal())
|
|
386
|
+
)$policy$,runtime_role);
|
|
387
|
+
execute format($policy$
|
|
388
|
+
create policy deliveries_runtime_update on agent_bridge.deliveries
|
|
389
|
+
for update to %I using (
|
|
390
|
+
workspace=(select agent_bridge.current_request_workspace())
|
|
391
|
+
and (
|
|
392
|
+
recipient=(select agent_bridge.current_request_principal())
|
|
393
|
+
or publisher=(select agent_bridge.current_request_principal())
|
|
394
|
+
)
|
|
395
|
+
) with check (
|
|
396
|
+
workspace=(select agent_bridge.current_request_workspace())
|
|
397
|
+
and (
|
|
398
|
+
recipient=(select agent_bridge.current_request_principal())
|
|
399
|
+
or publisher=(select agent_bridge.current_request_principal())
|
|
400
|
+
)
|
|
401
|
+
)$policy$,runtime_role);
|
|
402
|
+
|
|
403
|
+
execute format($policy$
|
|
404
|
+
create policy delivery_events_runtime_select on agent_bridge.delivery_events
|
|
405
|
+
for select to %I using (
|
|
406
|
+
workspace=(select agent_bridge.current_request_workspace())
|
|
407
|
+
and (
|
|
408
|
+
recipient=(select agent_bridge.current_request_principal())
|
|
409
|
+
or publisher=(select agent_bridge.current_request_principal())
|
|
410
|
+
)
|
|
411
|
+
)$policy$,runtime_role);
|
|
412
|
+
execute format(
|
|
413
|
+
'create policy delivery_events_writer_insert on agent_bridge.delivery_events for insert to %I with check (true)',
|
|
414
|
+
event_writer
|
|
415
|
+
);
|
|
416
|
+
|
|
417
|
+
execute format($policy$
|
|
418
|
+
create policy agent_instances_runtime_select on agent_bridge.agent_instances
|
|
419
|
+
for select to %I using (
|
|
420
|
+
workspace=(select agent_bridge.current_request_workspace())
|
|
421
|
+
)$policy$,runtime_role);
|
|
422
|
+
execute format($policy$
|
|
423
|
+
create policy agent_instances_runtime_insert on agent_bridge.agent_instances
|
|
424
|
+
for insert to %I with check (
|
|
425
|
+
workspace=(select agent_bridge.current_request_workspace())
|
|
426
|
+
and agent=(select agent_bridge.current_request_principal())
|
|
427
|
+
)$policy$,runtime_role);
|
|
428
|
+
execute format($policy$
|
|
429
|
+
create policy agent_instances_runtime_update on agent_bridge.agent_instances
|
|
430
|
+
for update to %I using (
|
|
431
|
+
workspace=(select agent_bridge.current_request_workspace())
|
|
432
|
+
and agent=(select agent_bridge.current_request_principal())
|
|
433
|
+
) with check (
|
|
434
|
+
workspace=(select agent_bridge.current_request_workspace())
|
|
435
|
+
and agent=(select agent_bridge.current_request_principal())
|
|
436
|
+
)$policy$,runtime_role);
|
|
437
|
+
execute format($policy$
|
|
438
|
+
create policy agent_instances_runtime_delete on agent_bridge.agent_instances
|
|
439
|
+
for delete to %I using (
|
|
440
|
+
workspace=(select agent_bridge.current_request_workspace())
|
|
441
|
+
and (
|
|
442
|
+
agent=(select agent_bridge.current_request_principal())
|
|
443
|
+
or lease_expires_at<=now()
|
|
444
|
+
)
|
|
445
|
+
)$policy$,runtime_role);
|
|
446
|
+
end
|
|
447
|
+
$policies$;
|
|
448
|
+
|
|
449
|
+
do $grants$
|
|
450
|
+
declare
|
|
451
|
+
suffix text := substr(md5(current_database()),1,16);
|
|
452
|
+
runtime_role text := 'agent_bridge_runtime_' || suffix;
|
|
453
|
+
data_owner text := 'agent_bridge_data_owner_' || suffix;
|
|
454
|
+
context_reader text := 'agent_bridge_context_reader_' || suffix;
|
|
455
|
+
event_writer text := 'agent_bridge_event_writer_' || suffix;
|
|
456
|
+
role_name text;
|
|
457
|
+
begin
|
|
458
|
+
execute format('revoke %I,%I,%I from %I',data_owner,context_reader,event_writer,runtime_role);
|
|
459
|
+
execute format(
|
|
460
|
+
'revoke all on agent_bridge.messages,agent_bridge.receipts,agent_bridge.deliveries,agent_bridge.delivery_events,agent_bridge.agent_instances from %I',
|
|
461
|
+
runtime_role
|
|
462
|
+
);
|
|
463
|
+
execute format('grant select,insert on agent_bridge.messages,agent_bridge.receipts to %I',runtime_role);
|
|
464
|
+
execute format('grant select,insert,update on agent_bridge.deliveries to %I',runtime_role);
|
|
465
|
+
execute format('grant select on agent_bridge.delivery_events to %I',runtime_role);
|
|
466
|
+
execute format('grant select,insert,update,delete on agent_bridge.agent_instances to %I',runtime_role);
|
|
467
|
+
execute format('grant select on agent_bridge.row_isolation_attestations to %I',runtime_role);
|
|
468
|
+
execute format('revoke all on all sequences in schema agent_bridge from %I',runtime_role);
|
|
469
|
+
revoke all on sequence agent_bridge.messages_sequence_seq from public;
|
|
470
|
+
revoke all on sequence agent_bridge.delivery_events_sequence_seq from public;
|
|
471
|
+
execute format('grant usage on sequence agent_bridge.messages_sequence_seq to %I',runtime_role);
|
|
472
|
+
execute format('grant execute on function agent_bridge.current_request_workspace() to %I',runtime_role);
|
|
473
|
+
execute format('grant execute on function agent_bridge.current_request_principal() to %I',runtime_role);
|
|
474
|
+
execute format('grant execute on function agent_bridge.row_isolation_catalog_definition() to %I',runtime_role);
|
|
475
|
+
execute format('revoke all on function agent_bridge.record_delivery_event() from %I',runtime_role);
|
|
476
|
+
execute format('revoke all on function agent_bridge.reject_delivery_identity_mutation() from %I',runtime_role);
|
|
477
|
+
execute format('revoke all on function agent_bridge.reject_delivery_event_mutation() from %I',runtime_role);
|
|
478
|
+
execute format('revoke all on function agent_bridge.enforce_delivery_actor_role() from %I',runtime_role);
|
|
479
|
+
foreach role_name in array array['anon','authenticated'] loop
|
|
480
|
+
if exists (select 1 from pg_roles where rolname=role_name) then
|
|
481
|
+
execute format('revoke all on function agent_bridge.current_request_workspace() from %I',role_name);
|
|
482
|
+
execute format('revoke all on function agent_bridge.current_request_principal() from %I',role_name);
|
|
483
|
+
execute format('revoke all on function agent_bridge.record_delivery_event() from %I',role_name);
|
|
484
|
+
end if;
|
|
485
|
+
end loop;
|
|
486
|
+
end
|
|
487
|
+
$grants$;
|
|
488
|
+
|
|
489
|
+
insert into agent_bridge.row_isolation_attestations(name,catalog_definition)
|
|
490
|
+
values ('domain-v1',agent_bridge.row_isolation_catalog_definition());
|
|
491
|
+
|
|
492
|
+
insert into agent_bridge.schema_migrations(version,name,checksum)
|
|
493
|
+
values (13,'row_isolation','__AGENT_BRIDGE_MIGRATION_CHECKSUM__');
|
|
494
|
+
|
|
495
|
+
commit;
|