@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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@creatornader/agent-bridge",
3
- "version": "0.3.1",
3
+ "version": "0.5.0",
4
4
  "description": "Durable, pull-first mailbox and work-delivery control plane for AI agents across runtimes, sessions, and machines.",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -87,13 +87,21 @@
87
87
  "pretest": "npm run build",
88
88
  "test": "vitest run",
89
89
  "test:built": "vitest run",
90
+ "test:postgres:contract": "vitest run test/postgres_integration.test.ts --maxWorkers=1 --hookTimeout=60000",
91
+ "test:postgres:preflight": "node scripts/postgres-preflight.mjs",
92
+ "test:postgres:preflight:full": "node scripts/postgres-preflight.mjs --full",
93
+ "preflight:postgres:production": "npm run build --silent && node dist/postgres-production-preflight.js",
94
+ "preflight:fly": "node scripts/fly-production-preflight.mjs",
95
+ "proof:gateway:production": "node scripts/gateway-production-proof.mjs",
96
+ "test:gateway:production-proof": "vitest run test/gateway-production-proof.test.ts",
97
+ "test:windows:contract": "vitest run test/private-path.test.ts test/windows-native-smoke.test.ts --maxWorkers=1 --testTimeout=180000 -t \"applies and verifies native Windows file and directory ACLs|recovers an (enrollment|client-operation) subsystem lock\" && vitest run test/client-maintenance.test.ts --maxWorkers=1 --testTimeout=180000",
90
98
  "typecheck": "tsc --noEmit",
91
99
  "contracts:generate": "npm run build --silent && npm run contracts:generate:built",
92
100
  "contracts:generate:built": "node dist/contracts/generate.js",
93
101
  "contracts:check": "npm run build --silent && npm run contracts:check:built",
94
102
  "contracts:check:built": "node dist/contracts/generate.js --check",
95
103
  "check": "npm run typecheck && npm run build && npm run contracts:check:built && npm run test:built",
96
- "check:windows": "npm run typecheck && npm run build && npm run contracts:check:built && vitest run --maxWorkers=2 --testTimeout=90000"
104
+ "check:windows": "npm run typecheck && npm run build && npm run contracts:check:built && vitest run --maxWorkers=2 --testTimeout=90000 --exclude test/private-path.test.ts --exclude test/client-maintenance.test.ts --exclude test/cli.test.ts"
97
105
  },
98
106
  "dependencies": {
99
107
  "@modelcontextprotocol/sdk": "^1.12.1",
@@ -88,6 +88,12 @@
88
88
  "legacy-supabase"
89
89
  ]
90
90
  },
91
+ "grantedScopes": {
92
+ "type": "array",
93
+ "items": {
94
+ "type": "string"
95
+ }
96
+ },
91
97
  "operations": {
92
98
  "type": "array",
93
99
  "items": {
@@ -134,6 +140,24 @@
134
140
  "status:read"
135
141
  ]
136
142
  },
143
+ {
144
+ "id": "issue_endpoint_migration_challenge",
145
+ "summary": "Issue a short-lived endpoint migration challenge commitment.",
146
+ "http": {
147
+ "method": "POST",
148
+ "path": "/v2/endpoint-migration-challenges"
149
+ },
150
+ "requiredScopes": []
151
+ },
152
+ {
153
+ "id": "consume_endpoint_migration_challenge",
154
+ "summary": "Consume a short-lived endpoint migration challenge commitment.",
155
+ "http": {
156
+ "method": "POST",
157
+ "path": "/v2/endpoint-migration-challenges/consume"
158
+ },
159
+ "requiredScopes": []
160
+ },
137
161
  {
138
162
  "id": "gateway_metrics",
139
163
  "summary": "Read Prometheus gateway counters.",
@@ -723,7 +747,7 @@
723
747
  },
724
748
  {
725
749
  "id": "claim_delivery",
726
- "summary": "Atomically claim the next targeted delivery.",
750
+ "summary": "Atomically claim the next targeted delivery, or one eligible message when requested.",
727
751
  "mcp": {
728
752
  "name": "claim"
729
753
  },
@@ -735,6 +759,7 @@
735
759
  "command": "claim",
736
760
  "options": [
737
761
  "lease-ms",
762
+ "message-id",
738
763
  "max-attempts"
739
764
  ],
740
765
  "outputSchema": {
@@ -77,6 +77,12 @@
77
77
  "legacy-supabase"
78
78
  ]
79
79
  },
80
+ "grantedScopes": {
81
+ "type": "array",
82
+ "items": {
83
+ "type": "string"
84
+ }
85
+ },
80
86
  "operations": {
81
87
  "type": "array",
82
88
  "items": {
@@ -627,13 +633,17 @@
627
633
  },
628
634
  {
629
635
  "name": "claim",
630
- "description": "Atomically claim the next targeted delivery.",
636
+ "description": "Atomically claim the next targeted delivery, or one eligible message when requested.",
631
637
  "inputSchema": {
632
638
  "type": "object",
633
639
  "properties": {
634
640
  "leaseMs": {
635
641
  "type": "number"
636
642
  },
643
+ "messageId": {
644
+ "type": "string",
645
+ "pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$"
646
+ },
637
647
  "maxAttempts": {
638
648
  "type": "number"
639
649
  }
@@ -338,6 +338,12 @@
338
338
  "legacy-supabase"
339
339
  ]
340
340
  },
341
+ "grantedScopes": {
342
+ "type": "array",
343
+ "items": {
344
+ "type": "string"
345
+ }
346
+ },
341
347
  "operations": {
342
348
  "type": "array",
343
349
  "items": {
@@ -432,6 +438,12 @@
432
438
  "legacy-supabase"
433
439
  ]
434
440
  },
441
+ "grantedScopes": {
442
+ "type": "array",
443
+ "items": {
444
+ "type": "string"
445
+ }
446
+ },
435
447
  "operations": {
436
448
  "type": "array",
437
449
  "items": {
@@ -586,6 +598,12 @@
586
598
  }
587
599
  ]
588
600
  },
601
+ "gatewayAuthorityId": {
602
+ "type": "string"
603
+ },
604
+ "credentialId": {
605
+ "type": "string"
606
+ },
589
607
  "principal": {
590
608
  "type": "object",
591
609
  "required": [
@@ -605,6 +623,111 @@
605
623
  },
606
624
  "additionalProperties": true
607
625
  },
626
+ "issue_endpoint_migration_challengeRequest": {
627
+ "type": "object",
628
+ "required": [
629
+ "challenge",
630
+ "expectedGatewayAuthorityId",
631
+ "verifierCredentialId"
632
+ ],
633
+ "properties": {
634
+ "challenge": {
635
+ "type": "string",
636
+ "pattern": "^[0-9a-f]{64}$"
637
+ },
638
+ "expectedGatewayAuthorityId": {
639
+ "type": "string",
640
+ "pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$"
641
+ },
642
+ "verifierCredentialId": {
643
+ "type": "string",
644
+ "pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$"
645
+ }
646
+ },
647
+ "additionalProperties": false
648
+ },
649
+ "issue_endpoint_migration_challengeResponse": {
650
+ "type": "object",
651
+ "required": [
652
+ "gatewayAuthorityId",
653
+ "issuerCredentialId",
654
+ "verifierCredentialId",
655
+ "expiresAt"
656
+ ],
657
+ "properties": {
658
+ "gatewayAuthorityId": {
659
+ "type": "string"
660
+ },
661
+ "issuerCredentialId": {
662
+ "type": "string"
663
+ },
664
+ "verifierCredentialId": {
665
+ "type": "string"
666
+ },
667
+ "expiresAt": {
668
+ "type": "string"
669
+ }
670
+ },
671
+ "additionalProperties": false
672
+ },
673
+ "consume_endpoint_migration_challengeRequest": {
674
+ "type": "object",
675
+ "required": [
676
+ "challenge",
677
+ "expectedGatewayAuthorityId",
678
+ "issuerCredentialId"
679
+ ],
680
+ "properties": {
681
+ "challenge": {
682
+ "type": "string",
683
+ "pattern": "^[0-9a-f]{64}$"
684
+ },
685
+ "expectedGatewayAuthorityId": {
686
+ "type": "string",
687
+ "pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$"
688
+ },
689
+ "issuerCredentialId": {
690
+ "type": "string",
691
+ "pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$"
692
+ }
693
+ },
694
+ "additionalProperties": false
695
+ },
696
+ "consume_endpoint_migration_challengeResponse": {
697
+ "type": "object",
698
+ "required": [
699
+ "gatewayAuthorityId",
700
+ "issuerCredentialId",
701
+ "verifierCredentialId",
702
+ "expiresAt",
703
+ "consumed"
704
+ ],
705
+ "properties": {
706
+ "gatewayAuthorityId": {
707
+ "type": "string"
708
+ },
709
+ "issuerCredentialId": {
710
+ "type": "string"
711
+ },
712
+ "verifierCredentialId": {
713
+ "type": "string"
714
+ },
715
+ "expiresAt": {
716
+ "anyOf": [
717
+ {
718
+ "type": "string"
719
+ },
720
+ {
721
+ "type": "null"
722
+ }
723
+ ]
724
+ },
725
+ "consumed": {
726
+ "type": "boolean"
727
+ }
728
+ },
729
+ "additionalProperties": false
730
+ },
608
731
  "client_statusRequest": {
609
732
  "type": "object",
610
733
  "properties": {},
@@ -834,6 +957,12 @@
834
957
  }
835
958
  ]
836
959
  },
960
+ "gatewayAuthorityId": {
961
+ "type": "string"
962
+ },
963
+ "credentialId": {
964
+ "type": "string"
965
+ },
837
966
  "principal": {
838
967
  "type": "object",
839
968
  "required": [
@@ -927,6 +1056,7 @@
927
1056
  "idle",
928
1057
  "running",
929
1058
  "backoff",
1059
+ "paused",
930
1060
  "stopped",
931
1061
  "failed"
932
1062
  ]
@@ -936,6 +1066,19 @@
936
1066
  },
937
1067
  "remoteError": {
938
1068
  "type": "string"
1069
+ },
1070
+ "migrationState": {
1071
+ "enum": [
1072
+ "active",
1073
+ "draining",
1074
+ "retired"
1075
+ ]
1076
+ },
1077
+ "migrationOperationId": {
1078
+ "type": "string"
1079
+ },
1080
+ "migrationLeaseExpiresAt": {
1081
+ "type": "string"
939
1082
  }
940
1083
  },
941
1084
  "additionalProperties": true
@@ -1195,6 +1338,12 @@
1195
1338
  }
1196
1339
  ]
1197
1340
  },
1341
+ "gatewayAuthorityId": {
1342
+ "type": "string"
1343
+ },
1344
+ "credentialId": {
1345
+ "type": "string"
1346
+ },
1198
1347
  "principal": {
1199
1348
  "type": "object",
1200
1349
  "required": [
@@ -1288,6 +1437,7 @@
1288
1437
  "idle",
1289
1438
  "running",
1290
1439
  "backoff",
1440
+ "paused",
1291
1441
  "stopped",
1292
1442
  "failed"
1293
1443
  ]
@@ -1297,6 +1447,19 @@
1297
1447
  },
1298
1448
  "remoteError": {
1299
1449
  "type": "string"
1450
+ },
1451
+ "migrationState": {
1452
+ "enum": [
1453
+ "active",
1454
+ "draining",
1455
+ "retired"
1456
+ ]
1457
+ },
1458
+ "migrationOperationId": {
1459
+ "type": "string"
1460
+ },
1461
+ "migrationLeaseExpiresAt": {
1462
+ "type": "string"
1300
1463
  }
1301
1464
  },
1302
1465
  "additionalProperties": true
@@ -2283,6 +2446,10 @@
2283
2446
  "leaseMs": {
2284
2447
  "type": "number"
2285
2448
  },
2449
+ "messageId": {
2450
+ "type": "string",
2451
+ "pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$"
2452
+ },
2286
2453
  "maxAttempts": {
2287
2454
  "type": "number"
2288
2455
  }
@@ -12,10 +12,14 @@ begin
12
12
  role_name
13
13
  );
14
14
  end if;
15
- execute format(
16
- 'alter role %I nologin nosuperuser nocreatedb nocreaterole noreplication nobypassrls',
17
- role_name
18
- );
15
+ if exists (
16
+ select 1 from pg_roles where rolname=role_name and (
17
+ rolcanlogin or not rolinherit or rolsuper or rolcreatedb or rolcreaterole
18
+ or rolreplication or rolbypassrls or rolconnlimit<>-1
19
+ )
20
+ ) then
21
+ raise exception 'Agent Bridge runtime role has unsafe attributes';
22
+ end if;
19
23
  execute format('revoke all on schema agent_bridge from %I', role_name);
20
24
  execute format('revoke all on all tables in schema agent_bridge from %I', role_name);
21
25
  execute format('revoke all on all sequences in schema agent_bridge from %I', role_name);
@@ -17,11 +17,73 @@ begin
17
17
  role_name
18
18
  );
19
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);
20
+ if exists (
21
+ select 1 from pg_roles where rolname=role_name and (
22
+ rolcanlogin or not rolinherit or rolsuper or rolcreatedb or rolcreaterole
23
+ or rolreplication or rolbypassrls or rolconnlimit<>-1
24
+ )
25
+ ) then
26
+ raise exception 'Agent Bridge row-isolation role % has unsafe attributes',role_name;
27
+ end if;
28
+ if current_setting('server_version_num')::integer>=160000 then
29
+ if not exists (
30
+ select 1 from pg_catalog.pg_auth_members membership
31
+ join pg_catalog.pg_roles granted on granted.oid=membership.roleid
32
+ join pg_catalog.pg_roles member on member.oid=membership.member
33
+ where granted.rolname=role_name and member.rolname=current_user
34
+ and membership.admin_option
35
+ ) then
36
+ execute format(
37
+ 'grant %I to %I with admin true,inherit true,set true',role_name,current_user
38
+ );
39
+ elsif not exists (
40
+ select 1 from pg_catalog.pg_auth_members membership
41
+ join pg_catalog.pg_roles granted on granted.oid=membership.roleid
42
+ join pg_catalog.pg_roles member on member.oid=membership.member
43
+ where granted.rolname=role_name and member.rolname=current_user
44
+ and coalesce((to_jsonb(membership)->>'inherit_option')::boolean,true)
45
+ and coalesce((to_jsonb(membership)->>'set_option')::boolean,true)
46
+ ) then
47
+ execute format('grant %I to %I with inherit true,set true',role_name,current_user);
48
+ end if;
49
+ elsif not exists (
50
+ select 1 from pg_catalog.pg_auth_members membership
51
+ join pg_catalog.pg_roles granted on granted.oid=membership.roleid
52
+ join pg_catalog.pg_roles member on member.oid=membership.member
53
+ where granted.rolname=role_name and member.rolname=current_user
54
+ and membership.admin_option
55
+ ) then
56
+ execute format('grant %I to %I with admin option',role_name,current_user);
57
+ end if;
58
+ if not exists (
59
+ select 1 from pg_catalog.pg_auth_members membership
60
+ join pg_catalog.pg_roles granted on granted.oid=membership.roleid
61
+ join pg_catalog.pg_roles member on member.oid=membership.member
62
+ where granted.rolname=role_name and member.rolname=current_user
63
+ and membership.admin_option
64
+ ) or not exists (
65
+ select 1 from pg_catalog.pg_auth_members membership
66
+ join pg_catalog.pg_roles granted on granted.oid=membership.roleid
67
+ join pg_catalog.pg_roles member on member.oid=membership.member
68
+ where granted.rolname=role_name and member.rolname=current_user
69
+ and coalesce((to_jsonb(membership)->>'inherit_option')::boolean,true)
70
+ and coalesce((to_jsonb(membership)->>'set_option')::boolean,true)
71
+ ) or exists (
72
+ select 1 from pg_catalog.pg_auth_members membership
73
+ join pg_catalog.pg_roles granted on granted.oid=membership.roleid
74
+ join pg_catalog.pg_roles member on member.oid=membership.member
75
+ where granted.rolname=role_name and member.rolname=current_user
76
+ and not (
77
+ (membership.grantor=10 and membership.admin_option
78
+ and not coalesce((to_jsonb(membership)->>'inherit_option')::boolean,true)
79
+ and not coalesce((to_jsonb(membership)->>'set_option')::boolean,true))
80
+ or (membership.grantor=member.oid
81
+ and coalesce((to_jsonb(membership)->>'inherit_option')::boolean,true)
82
+ and coalesce((to_jsonb(membership)->>'set_option')::boolean,true))
83
+ )
84
+ ) then
85
+ raise exception 'Agent Bridge row-isolation role % has unsafe owner authority',role_name;
86
+ end if;
25
87
  end loop;
26
88
  end
27
89
  $roles$;
@@ -292,7 +354,8 @@ declare
292
354
  event_writer text := 'agent_bridge_event_writer_' || suffix;
293
355
  table_name text;
294
356
  begin
295
- execute format('grant usage on schema agent_bridge to %I',data_owner);
357
+ execute format('grant usage,create on schema agent_bridge to %I,%I,%I',
358
+ data_owner,context_reader,event_writer);
296
359
  foreach table_name in array array[
297
360
  'messages','receipts','deliveries','delivery_events','agent_instances'
298
361
  ] loop
@@ -301,9 +364,9 @@ begin
301
364
  execute format('alter function agent_bridge.current_request_workspace() owner to %I',context_reader);
302
365
  execute format('alter function agent_bridge.current_request_principal() owner to %I',context_reader);
303
366
  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);
367
+ execute format('revoke create on schema agent_bridge from %I,%I,%I',
368
+ data_owner,context_reader,event_writer);
305
369
  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
370
  execute format('grant insert on agent_bridge.delivery_events to %I',event_writer);
308
371
  execute format('grant usage on sequence agent_bridge.delivery_events_sequence_seq to %I',event_writer);
309
372
  end