@opengeni/db 5.0.1 → 6.0.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 (212) hide show
  1. package/dist/automations.d.ts +0 -2
  2. package/dist/canonical-human-identities.d.ts +4 -0
  3. package/dist/canonical-human-identities.js +3 -3
  4. package/dist/capability-components.d.ts +5 -13
  5. package/dist/capability-integrations.d.ts +23 -8
  6. package/dist/capability-reconciliation.d.ts +5 -0
  7. package/dist/capability-reconciliation.js +21 -0
  8. package/dist/capability-reconciliation.js.map +1 -0
  9. package/dist/{chunk-6T2GGYWE.js → chunk-4UJCXBR2.js} +4 -5800
  10. package/dist/chunk-4UJCXBR2.js.map +1 -0
  11. package/dist/{chunk-MWMXWHJD.js → chunk-7JCDSMX2.js} +2 -2
  12. package/dist/chunk-AJA2ZIUW.js +219 -0
  13. package/dist/chunk-AJA2ZIUW.js.map +1 -0
  14. package/dist/chunk-CDAT6EKW.js +247 -0
  15. package/dist/chunk-CDAT6EKW.js.map +1 -0
  16. package/dist/{chunk-DPONPYJD.js → chunk-CJI6G254.js} +70 -18
  17. package/dist/chunk-CJI6G254.js.map +1 -0
  18. package/dist/chunk-G32NVMRJ.js +276 -0
  19. package/dist/chunk-G32NVMRJ.js.map +1 -0
  20. package/dist/chunk-GABXCG3N.js +5811 -0
  21. package/dist/chunk-GABXCG3N.js.map +1 -0
  22. package/dist/{chunk-ERKVSPDX.js → chunk-LVY33EWL.js} +3 -3
  23. package/dist/{chunk-45CP2YKY.js → chunk-MAMBI2HR.js} +9 -3
  24. package/dist/{chunk-45CP2YKY.js.map → chunk-MAMBI2HR.js.map} +1 -1
  25. package/dist/{chunk-F73UKJY6.js → chunk-MN5PZMEK.js} +91 -108
  26. package/dist/chunk-MN5PZMEK.js.map +1 -0
  27. package/dist/chunk-PJI4MUZ7.js +131 -0
  28. package/dist/chunk-PJI4MUZ7.js.map +1 -0
  29. package/dist/{chunk-T6BWIGWJ.js → chunk-RIYHP2WU.js} +2 -2
  30. package/dist/{chunk-7HMK3B45.js → chunk-RL2MUXM3.js} +16 -7
  31. package/dist/chunk-RL2MUXM3.js.map +1 -0
  32. package/dist/{chunk-HQDVI2DB.js → chunk-SYKHLPTK.js} +4 -3
  33. package/dist/{chunk-HQDVI2DB.js.map → chunk-SYKHLPTK.js.map} +1 -1
  34. package/dist/{chunk-T6YLHJLS.js → chunk-XIXVVBW2.js} +198 -51
  35. package/dist/chunk-XIXVVBW2.js.map +1 -0
  36. package/dist/chunk-ZPJ6V2VG.js +156 -0
  37. package/dist/chunk-ZPJ6V2VG.js.map +1 -0
  38. package/dist/codex-capacity-recovery.d.ts +12 -0
  39. package/dist/codex-failure-eligibility.d.ts +9 -0
  40. package/dist/company-profile-schema.d.ts +4 -2
  41. package/dist/connect-attempts.d.ts +15 -0
  42. package/dist/connect-attempts.js +25 -0
  43. package/dist/connect-attempts.js.map +1 -0
  44. package/dist/connection-authority.d.ts +7 -63
  45. package/dist/connection-refresh-lock.d.ts +4 -0
  46. package/dist/connection-token-resolver.d.ts +8 -43
  47. package/dist/database-timing.d.ts +10 -0
  48. package/dist/database.d.ts +4 -0
  49. package/dist/editable-artifact-durable-export.js +2 -2
  50. package/dist/editable-artifacts.d.ts +9 -0
  51. package/dist/editable-artifacts.js +7 -5
  52. package/dist/index.d.ts +447 -78
  53. package/dist/index.js +12705 -12872
  54. package/dist/index.js.map +1 -1
  55. package/dist/insights-usage-bundle.d.ts +3 -0
  56. package/dist/integration-bindings.d.ts +1 -1
  57. package/dist/integration-facets.d.ts +18 -1
  58. package/dist/knowledge-entries-schema.d.ts +2 -0
  59. package/dist/knowledge-entries.d.ts +1 -0
  60. package/dist/knowledge-indexing.d.ts +1 -0
  61. package/dist/live-session-attempt.d.ts +35 -137
  62. package/dist/managed-auth-session-sets.js +3 -3
  63. package/dist/mcp-account-bindings.d.ts +4 -0
  64. package/dist/mcp-oauth.d.ts +11 -0
  65. package/dist/mcp-operations.js +2 -2
  66. package/dist/migrate.js +1 -1
  67. package/dist/organization-integration-policy.d.ts +51 -0
  68. package/dist/organization-integration-policy.js +18 -0
  69. package/dist/organization-integration-policy.js.map +1 -0
  70. package/dist/organization-usage.d.ts +20 -0
  71. package/dist/plugin-packages.d.ts +9 -12
  72. package/dist/pr-review.d.ts +0 -11
  73. package/dist/preference-registry-schema.d.ts +17 -0
  74. package/dist/provision-roles.js +1 -1
  75. package/dist/retained-provider-commands.d.ts +124 -6
  76. package/dist/retained-provider-commands.js +29 -97
  77. package/dist/retained-provider-commands.js.map +1 -1
  78. package/dist/retired-session-create-metadata.d.ts +4 -0
  79. package/dist/runtime-posture.d.ts +7 -5
  80. package/dist/schema.d.ts +876 -656
  81. package/dist/schema.js +5 -7
  82. package/dist/session-admission-block.d.ts +32 -0
  83. package/dist/session-attempt-writers.d.ts +4 -0
  84. package/dist/session-background-commands.js +5 -4
  85. package/dist/session-command-output.js +8 -126
  86. package/dist/session-command-output.js.map +1 -1
  87. package/dist/session-control.d.ts +5 -1
  88. package/dist/session-event-slices.d.ts +10 -0
  89. package/dist/session-event-slices.js +8 -222
  90. package/dist/session-event-slices.js.map +1 -1
  91. package/dist/session-file-attachments.d.ts +28 -0
  92. package/dist/session-goal-reports.d.ts +43 -0
  93. package/dist/session-mcp-approval.d.ts +4 -0
  94. package/dist/session-mcp-credential-rotation.js +5 -4
  95. package/dist/session-mcp-credential-rotation.js.map +1 -1
  96. package/dist/session-message-search.d.ts +22 -0
  97. package/dist/session-queue-commands.d.ts +2 -6
  98. package/dist/session-retry.d.ts +36 -0
  99. package/dist/session-tenancy.js +3 -3
  100. package/dist/skill-source-release-impact.d.ts +18 -0
  101. package/dist/skill-source-release.d.ts +9 -0
  102. package/dist/skills.d.ts +7 -1
  103. package/dist/user-resource-authority.d.ts +0 -8
  104. package/dist/video-generation.js +3 -3
  105. package/dist/workspace-tool-defaults.js +5 -4
  106. package/dist/workspace-tool-defaults.js.map +1 -1
  107. package/drizzle/0468_knowledge_relationship_projection.sql +30 -0
  108. package/drizzle/0469_knowledge_source_discovery.sql +85 -0
  109. package/drizzle/0470_organization_integration_policy.sql +151 -0
  110. package/drizzle/0471_usage_events_account_recent_index.sql +4 -0
  111. package/drizzle/0472_usage_events_workspace_recent_index.sql +4 -0
  112. package/drizzle/0473_organization_usage_analytical_capability.sql +237 -0
  113. package/drizzle/0474_goal_report_requirements.sql +156 -0
  114. package/drizzle/0475_session_event_history_statistics.sql +15 -0
  115. package/drizzle/0476_session_event_history_policy_planning.sql +29 -0
  116. package/drizzle/0477_managed_sign_in_methods.sql +303 -0
  117. package/drizzle/0478_sender_owned_connections.sql +2772 -0
  118. package/drizzle/0479_connection_create_idempotency.sql +16 -0
  119. package/drizzle/0480_private_session_organization_key_administration.sql +154 -0
  120. package/drizzle/0481_personal_connection_visibility_cleanup.sql +45 -0
  121. package/drizzle/0482_remove_packs.sql +417 -0
  122. package/drizzle/0483_preclaim_admission_block.sql +85 -0
  123. package/drizzle/0484_insights_usage_projection.sql +211 -0
  124. package/drizzle/0485_inherited_mcp_approval_policies.sql +6 -0
  125. package/drizzle/0486_reasoning_configuration_message_forks.sql +35 -0
  126. package/drizzle/0487_skill_catalog_message_forks.sql +26 -0
  127. package/drizzle/0488_permanent_skill_removal.sql +207 -0
  128. package/drizzle/0489_modal_command_byte_offsets.sql +17 -0
  129. package/drizzle/0490_periodic_capture_attempt_cadence.sql +6 -0
  130. package/drizzle/0491_warm_capture_holder_reclamation.sql +57 -0
  131. package/drizzle/0492_codex_accepted_source_authority.sql +249 -0
  132. package/drizzle/0493_stopping_command_error_containment.sql +58 -0
  133. package/drizzle/0494_mcp_account_bindings.sql +334 -0
  134. package/drizzle/0495_consented_sandbox_recovery.sql +220 -0
  135. package/drizzle/0496_supervised_command_settlement.sql +386 -0
  136. package/drizzle/0497_modal_inventory_owner_read_capability.sql +112 -0
  137. package/drizzle/0498_enrollment_membership_fence.sql +87 -0
  138. package/drizzle/0499_session_attachment_access.sql +224 -0
  139. package/drizzle/0500_session_execution_epoch.sql +37 -0
  140. package/drizzle/0501_session_sharing_execution.sql +591 -0
  141. package/drizzle/0502_active_message_boundary_forks.sql +30 -0
  142. package/package.json +17 -5
  143. package/src/automations.ts +17 -73
  144. package/src/canonical-human-identities.ts +17 -5
  145. package/src/capability-components.ts +7 -24
  146. package/src/capability-integrations.ts +301 -21
  147. package/src/capability-reconciliation.ts +19 -0
  148. package/src/codex-capacity-recovery.ts +47 -0
  149. package/src/codex-failure-eligibility.ts +93 -0
  150. package/src/connect-attempts.ts +49 -18
  151. package/src/connection-authority.ts +12 -158
  152. package/src/connection-refresh-lock.ts +22 -0
  153. package/src/connection-token-resolver.ts +58 -530
  154. package/src/database-timing.ts +43 -0
  155. package/src/database.ts +61 -26
  156. package/src/editable-artifacts.ts +1 -1
  157. package/src/index.ts +3578 -1273
  158. package/src/insights-model-bundle.ts +19 -7
  159. package/src/insights-usage-bundle.ts +16 -19
  160. package/src/integration-bindings.ts +2 -7
  161. package/src/integration-facets.ts +73 -6
  162. package/src/knowledge-entries.ts +8 -1
  163. package/src/live-session-attempt.ts +0 -22
  164. package/src/mcp-account-bindings.ts +12 -0
  165. package/src/mcp-oauth.ts +26 -0
  166. package/src/organization-integration-policy.ts +235 -0
  167. package/src/organization-usage.ts +83 -0
  168. package/src/plugin-packages.ts +226 -42
  169. package/src/pr-review.ts +7 -69
  170. package/src/preference-registry-schema.ts +1 -0
  171. package/src/provision-roles.ts +50 -37
  172. package/src/retained-provider-commands.ts +286 -9
  173. package/src/retired-session-create-metadata.ts +16 -0
  174. package/src/runtime-posture.ts +217 -13
  175. package/src/schema.ts +104 -120
  176. package/src/session-admission-block.ts +29 -0
  177. package/src/session-attempt-writers.ts +48 -0
  178. package/src/session-control.ts +21 -5
  179. package/src/session-event-slices.ts +76 -26
  180. package/src/session-file-attachments.ts +66 -0
  181. package/src/session-goal-reports.ts +255 -0
  182. package/src/session-mcp-approval.ts +30 -0
  183. package/src/session-message-search.ts +348 -0
  184. package/src/session-queue-commands.ts +60 -36
  185. package/src/session-retry.ts +319 -0
  186. package/src/skill-config-migration.ts +11 -2
  187. package/src/skill-source-release-impact.ts +33 -0
  188. package/src/skill-source-release.ts +67 -26
  189. package/src/skills.ts +44 -6
  190. package/src/user-resource-authority.ts +0 -56
  191. package/dist/chunk-6T2GGYWE.js.map +0 -1
  192. package/dist/chunk-7HMK3B45.js.map +0 -1
  193. package/dist/chunk-DPONPYJD.js.map +0 -1
  194. package/dist/chunk-F73UKJY6.js.map +0 -1
  195. package/dist/chunk-T6YLHJLS.js.map +0 -1
  196. package/dist/host-mcp-binding-match.d.ts +0 -5
  197. package/dist/host-mcp-bindings.d.ts +0 -79
  198. package/dist/host-mcp-resolvers.d.ts +0 -47
  199. package/dist/host-mcp-task-authority.d.ts +0 -43
  200. package/dist/host-selection-identity.d.ts +0 -6
  201. package/dist/pack-components.d.ts +0 -83
  202. package/dist/pack-installations.d.ts +0 -86
  203. package/src/host-mcp-binding-match.ts +0 -34
  204. package/src/host-mcp-bindings.ts +0 -777
  205. package/src/host-mcp-resolvers.ts +0 -266
  206. package/src/host-mcp-task-authority.ts +0 -384
  207. package/src/host-selection-identity.ts +0 -29
  208. package/src/pack-components.ts +0 -980
  209. package/src/pack-installations.ts +0 -950
  210. /package/dist/{chunk-MWMXWHJD.js.map → chunk-7JCDSMX2.js.map} +0 -0
  211. /package/dist/{chunk-ERKVSPDX.js.map → chunk-LVY33EWL.js.map} +0 -0
  212. /package/dist/{chunk-T6BWIGWJ.js.map → chunk-RIYHP2WU.js.map} +0 -0
@@ -0,0 +1,57 @@
1
+ -- deployment-mode: rolling
2
+ -- Logical turn closure may precede its already-admitted workspace capture.
3
+ -- Do not reclaim that sole warm holder and escalate the capture into a drain
4
+ -- while its original bounded deadline is still open. This grants no execution
5
+ -- authority and does not extend the deadline or change dead-worker recovery.
6
+ SET LOCAL lock_timeout = '5s';
7
+ SET LOCAL statement_timeout = '10min';
8
+
9
+ DO $warm_capture_holder_reclamation$
10
+ DECLARE
11
+ definition text;
12
+ patched text;
13
+ lease_schema text;
14
+ anchor constant text := E' AND stale.kind = ''turn''\n AND (';
15
+ replacement text;
16
+ occurrences integer;
17
+ BEGIN
18
+ SELECT namespace.nspname INTO lease_schema
19
+ FROM pg_catalog.pg_class relation
20
+ JOIN pg_catalog.pg_namespace namespace ON namespace.oid = relation.relnamespace
21
+ WHERE relation.oid = 'sandbox_leases'::regclass;
22
+ SELECT pg_catalog.pg_get_functiondef(
23
+ 'opengeni_private.reap_sandbox_leases(bigint,bigint,bigint,bigint)'::regprocedure
24
+ ) INTO definition;
25
+ IF definition IS NULL OR lease_schema IS NULL
26
+ OR pg_catalog.strpos(definition, pg_catalog.format('%I.sandbox_lease_holders', lease_schema)) = 0
27
+ THEN
28
+ RAISE EXCEPTION '0491 warm capture reaper prerequisite drift' USING ERRCODE = '55000';
29
+ END IF;
30
+ replacement := E' AND stale.kind = ''turn''\n'
31
+ || E' -- 0491 bounded warm capture holder; not execution authority.\n'
32
+ || E' AND NOT EXISTS (\n'
33
+ || pg_catalog.format(E' SELECT 1 FROM %I.sandbox_leases capture_lease\n', lease_schema)
34
+ || E' WHERE capture_lease.id = stale.lease_id\n'
35
+ || E' AND capture_lease.liveness = ''warm''\n'
36
+ || E' AND capture_lease.archive_capture_id IS NOT NULL\n'
37
+ || E' AND capture_lease.archive_capture_published_at IS NULL\n'
38
+ || E' AND capture_lease.archive_capture_deadline_at > pg_catalog.now()\n'
39
+ || E' )\n AND (';
40
+ IF pg_catalog.strpos(definition, '0491 bounded warm capture holder') > 0 THEN
41
+ IF pg_catalog.strpos(definition, replacement) = 0 THEN
42
+ RAISE EXCEPTION '0491 warm capture reaper replay drift' USING ERRCODE = '55000';
43
+ END IF;
44
+ ELSE
45
+ occurrences := (pg_catalog.length(definition)
46
+ - pg_catalog.length(pg_catalog.replace(definition, anchor, ''))) / pg_catalog.length(anchor);
47
+ IF occurrences <> 1 THEN
48
+ RAISE EXCEPTION '0491 warm capture reaper anchor drift' USING ERRCODE = '55000';
49
+ END IF;
50
+ patched := pg_catalog.replace(definition, anchor, replacement);
51
+ EXECUTE patched;
52
+ END IF;
53
+ END
54
+ $warm_capture_holder_reclamation$;
55
+
56
+ RESET statement_timeout;
57
+ RESET lock_timeout;
@@ -0,0 +1,249 @@
1
+ -- deployment-mode: maintenance
2
+ -- Add exact-turn source authorization without broadening ordinary workspace reads.
3
+ -- Stop every old/new API and worker process before applying this migration;
4
+ -- never restart a pre-0492 binary. Accepted turns survive through recovery.
5
+ SET LOCAL lock_timeout = '5s';
6
+ SET LOCAL statement_timeout = '10min';
7
+
8
+ CREATE FUNCTION pg_temp.assert_codex_source_runtime_drain() RETURNS void
9
+ LANGUAGE plpgsql AS $drain$
10
+ DECLARE
11
+ configured_roles_text text := nullif(current_setting('opengeni.migration_application_roles', true), '');
12
+ configured_roles jsonb;
13
+ BEGIN
14
+ IF configured_roles_text IS NULL THEN
15
+ RAISE EXCEPTION '0492 Codex source activation requires an explicit application database role list'
16
+ USING ERRCODE = '55000';
17
+ END IF;
18
+ BEGIN
19
+ configured_roles := configured_roles_text::jsonb;
20
+ EXCEPTION WHEN OTHERS THEN
21
+ RAISE EXCEPTION '0492 Codex source activation received a malformed application database role list'
22
+ USING ERRCODE = '55000';
23
+ END;
24
+ IF jsonb_typeof(configured_roles) <> 'array' THEN
25
+ RAISE EXCEPTION '0492 Codex source activation requires an application role array'
26
+ USING ERRCODE = '55000';
27
+ END IF;
28
+ IF jsonb_array_length(configured_roles) NOT BETWEEN 1 AND 16
29
+ OR EXISTS (
30
+ SELECT 1 FROM jsonb_array_elements(configured_roles) roles(value)
31
+ WHERE jsonb_typeof(value) <> 'string' OR btrim(value #>> '{}') = ''
32
+ OR octet_length(value #>> '{}') > 63
33
+ ) OR (SELECT count(*) FROM jsonb_array_elements_text(configured_roles))
34
+ <> (SELECT count(DISTINCT value) FROM jsonb_array_elements_text(configured_roles) roles(value))
35
+ THEN
36
+ RAISE EXCEPTION '0492 Codex source activation received an invalid application database role list'
37
+ USING ERRCODE = '55000';
38
+ END IF;
39
+ IF EXISTS (
40
+ SELECT 1 FROM pg_stat_activity activity
41
+ JOIN jsonb_array_elements_text(configured_roles) roles(role_name) ON roles.role_name = activity.usename
42
+ WHERE activity.datname = current_database() AND activity.pid <> pg_backend_pid()
43
+ ) THEN
44
+ RAISE EXCEPTION '0492 Codex source activation requires all configured OpenGeni application database sessions to be stopped'
45
+ USING ERRCODE = '55000';
46
+ END IF;
47
+ END
48
+ $drain$;
49
+ SELECT pg_temp.assert_codex_source_runtime_drain();
50
+
51
+ -- Sidecar authority for turns accepted before their first source-bearing policy.
52
+ -- Source changes never edit conversation/turn metadata or session ordering.
53
+ CREATE TABLE codex_turn_source_bindings (
54
+ turn_id uuid PRIMARY KEY,
55
+ account_id uuid NOT NULL REFERENCES managed_accounts(id) ON DELETE CASCADE,
56
+ workspace_id uuid NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
57
+ source text NOT NULL CHECK (source IN ('workspace', 'organization', 'disabled')),
58
+ created_at timestamptz NOT NULL DEFAULT now(),
59
+ FOREIGN KEY (workspace_id, turn_id) REFERENCES session_turns(workspace_id, id) ON DELETE CASCADE,
60
+ FOREIGN KEY (workspace_id, account_id) REFERENCES workspaces(id, account_id) ON DELETE CASCADE
61
+ );
62
+ ALTER TABLE codex_turn_source_bindings ENABLE ROW LEVEL SECURITY;
63
+ ALTER TABLE codex_turn_source_bindings FORCE ROW LEVEL SECURITY;
64
+ CREATE POLICY workspace_isolation ON codex_turn_source_bindings
65
+ FOR SELECT USING (opengeni_private.workspace_rls_visible(account_id, workspace_id));
66
+ REVOKE ALL ON codex_turn_source_bindings FROM PUBLIC;
67
+
68
+ DO $accepted_codex_source$
69
+ DECLARE
70
+ data_schema text := current_schema();
71
+ definition text;
72
+ patched text;
73
+ role_name text;
74
+ BEGIN
75
+ -- Even accidental runtime INSERT grants cannot forge a receipt. Only the
76
+ -- migration-owner definer may insert; no role receives UPDATE/DELETE policies.
77
+ EXECUTE format('CREATE POLICY capture_insert ON %I.codex_turn_source_bindings '
78
+ 'FOR INSERT WITH CHECK (current_user = %L AND '
79
+ 'opengeni_private.workspace_rls_visible(account_id, workspace_id))', data_schema, current_user);
80
+ FOR role_name IN
81
+ SELECT DISTINCT role_row.rolname FROM pg_class relation
82
+ CROSS JOIN LATERAL aclexplode(coalesce(relation.relacl, acldefault('r', relation.relowner))) privilege
83
+ JOIN pg_roles role_row ON role_row.oid = privilege.grantee
84
+ WHERE relation.oid = 'codex_turn_source_bindings'::regclass
85
+ AND privilege.grantee <> relation.relowner
86
+ LOOP
87
+ EXECUTE format('REVOKE ALL ON %I.codex_turn_source_bindings FROM %I', data_schema, role_name);
88
+ END LOOP;
89
+ EXECUTE format($ddl$
90
+ CREATE FUNCTION %1$I.capture_legacy_codex_turn_sources(
91
+ p_account_id uuid, p_workspace_id uuid
92
+ ) RETURNS void
93
+ LANGUAGE plpgsql SECURITY DEFINER
94
+ SET search_path = pg_catalog, %1$I, pg_temp
95
+ AS $function$
96
+ DECLARE
97
+ accepted_source text;
98
+ previous_subject text := current_setting('opengeni.subject_id', true);
99
+ BEGIN
100
+ IF p_account_id IS NULL OR p_workspace_id IS NULL
101
+ OR p_account_id IS DISTINCT FROM opengeni_private.current_account_id()
102
+ OR p_workspace_id IS DISTINCT FROM opengeni_private.current_workspace_id()
103
+ THEN
104
+ RAISE EXCEPTION 'Codex source capture requires the exact workspace scope'
105
+ USING ERRCODE = '42501';
106
+ END IF;
107
+ -- Use the same lock as admission, allocation, and every source mutation.
108
+ -- Callers cannot choose a source, turn, or subject, even on conflict.
109
+ PERFORM pg_advisory_xact_lock(hashtextextended(
110
+ 'codex-subscription-source:' || p_workspace_id::text, 0));
111
+ accepted_source := %1$I.resolve_workspace_codex_subscription_source(
112
+ p_account_id, p_workspace_id);
113
+ -- Only this fixed, content-free statement may see other actors' turns.
114
+ -- Never substitute an arbitrary subject or expose session content.
115
+ PERFORM set_config('opengeni.subject_id', '', true);
116
+ INSERT INTO %1$I.codex_turn_source_bindings (turn_id, account_id, workspace_id, source)
117
+ SELECT turn.id, turn.account_id, turn.workspace_id, accepted_source
118
+ FROM %1$I.session_turns turn
119
+ JOIN %1$I.sessions session ON session.id = turn.session_id
120
+ AND session.account_id = turn.account_id AND session.workspace_id = turn.workspace_id
121
+ WHERE turn.account_id = p_account_id AND turn.workspace_id = p_workspace_id
122
+ AND turn.model LIKE 'codex/%%'
123
+ AND turn.status IN ('queued', 'running', 'requires_action', 'recovering', 'waiting_capacity')
124
+ AND turn.metadata #>> '{codexCredentialPolicySnapshotV1,source}' IS NULL
125
+ ON CONFLICT (turn_id) DO NOTHING;
126
+ PERFORM set_config('opengeni.subject_id', coalesce(previous_subject, ''), true);
127
+ EXCEPTION WHEN OTHERS THEN
128
+ PERFORM set_config('opengeni.subject_id', coalesce(previous_subject, ''), true);
129
+ RAISE;
130
+ END
131
+ $function$;
132
+ REVOKE ALL ON FUNCTION %1$I.capture_legacy_codex_turn_sources(uuid,uuid) FROM PUBLIC;
133
+
134
+ CREATE OR REPLACE FUNCTION opengeni_private.codex_credential_serves_turn(
135
+ p_account_id uuid, p_workspace_id uuid, p_credential_id uuid, p_turn_id uuid
136
+ ) RETURNS boolean
137
+ LANGUAGE plpgsql SECURITY DEFINER
138
+ SET search_path = pg_catalog, %1$I, pg_temp
139
+ AS $function$
140
+ DECLARE accepted_source text;
141
+ BEGIN
142
+ IF p_account_id IS DISTINCT FROM opengeni_private.current_account_id()
143
+ OR p_workspace_id IS DISTINCT FROM opengeni_private.current_workspace_id()
144
+ THEN RETURN false; END IF;
145
+ SELECT coalesce(turn.metadata #>> '{codexCredentialPolicySnapshotV1,source}', binding.source)
146
+ INTO accepted_source
147
+ FROM session_turns turn
148
+ JOIN sessions session ON session.id = turn.session_id
149
+ AND session.workspace_id = turn.workspace_id AND session.account_id = turn.account_id
150
+ LEFT JOIN codex_turn_source_bindings binding ON binding.turn_id = turn.id
151
+ AND binding.account_id = turn.account_id AND binding.workspace_id = turn.workspace_id
152
+ WHERE turn.id = p_turn_id AND turn.account_id = p_account_id
153
+ AND turn.workspace_id = p_workspace_id
154
+ AND turn.model LIKE 'codex/%%'
155
+ AND turn.status IN ('queued', 'running', 'requires_action', 'recovering', 'waiting_capacity');
156
+ IF NOT FOUND THEN RETURN false; END IF;
157
+ -- Before the first cutover a legacy policy can still use current source.
158
+ -- Every source mutation captures its pre-change authority in the sidecar.
159
+ IF accepted_source IS NULL THEN
160
+ RETURN opengeni_private.codex_credential_serves_workspace(
161
+ p_account_id, p_workspace_id, p_credential_id);
162
+ END IF;
163
+ RETURN EXISTS (
164
+ SELECT 1 FROM codex_subscription_credentials credential
165
+ WHERE credential.id = p_credential_id AND credential.account_id = p_account_id
166
+ AND (
167
+ (accepted_source = 'workspace' AND credential.workspace_id = p_workspace_id
168
+ AND credential.authority_scope IN ('workspace', 'user'))
169
+ OR (accepted_source = 'organization' AND credential.organization_id = p_account_id
170
+ AND credential.authority_scope = 'organization'
171
+ AND opengeni_private.codex_organization_scope_visible(p_account_id))
172
+ )
173
+ );
174
+ END
175
+ $function$;
176
+ REVOKE ALL ON FUNCTION opengeni_private.codex_credential_serves_turn(uuid,uuid,uuid,uuid) FROM PUBLIC;
177
+
178
+ CREATE OR REPLACE FUNCTION opengeni_private.enforce_codex_lease_source()
179
+ RETURNS trigger LANGUAGE plpgsql SECURITY DEFINER
180
+ SET search_path = pg_catalog, %1$I, pg_temp
181
+ AS $function$
182
+ BEGIN
183
+ IF NOT opengeni_private.codex_credential_serves_turn(
184
+ NEW.account_id, NEW.workspace_id, NEW.credential_id, NEW.turn_id
185
+ ) THEN
186
+ RAISE EXCEPTION 'Codex credential is outside the accepted turn pool' USING ERRCODE = '23514';
187
+ END IF;
188
+ RETURN NEW;
189
+ END
190
+ $function$;
191
+ $ddl$, data_schema);
192
+
193
+ -- Preserve the complete existing ownership and execution-time count guards.
194
+ SELECT pg_get_functiondef('opengeni_private.codex_organization_live_lease_count(uuid,uuid,uuid)'::regprocedure)
195
+ INTO definition;
196
+ patched := replace(definition,
197
+ E'OR NOT opengeni_private.codex_credential_serves_workspace(\n p_account_id,\n opengeni_private.current_workspace_id(),\n p_credential_id\n )',
198
+ E'OR NOT (CASE WHEN p_exclude_turn_id IS NULL THEN\n opengeni_private.codex_credential_serves_workspace(p_account_id, opengeni_private.current_workspace_id(), p_credential_id)\n ELSE opengeni_private.codex_credential_serves_turn(p_account_id, opengeni_private.current_workspace_id(), p_credential_id, p_exclude_turn_id) END)');
199
+ IF patched = definition THEN
200
+ RAISE EXCEPTION '0492 organization lease count prerequisite drift';
201
+ END IF;
202
+ EXECUTE patched;
203
+ -- Pin every authority lookup in this helper chain, including pre-0492
204
+ -- definitions. An omitted pg_temp is implicitly searched before real tables.
205
+ EXECUTE format('ALTER FUNCTION %I.resolve_workspace_codex_subscription_source(uuid,uuid) SET search_path = pg_catalog, %I, pg_temp', data_schema, data_schema);
206
+ EXECUTE format('ALTER FUNCTION opengeni_private.codex_credential_serves_workspace(uuid,uuid,uuid) SET search_path = pg_catalog, %I, pg_temp', data_schema);
207
+ EXECUTE format('ALTER FUNCTION opengeni_private.codex_organization_live_lease_count(uuid,uuid,uuid) SET search_path = pg_catalog, %I, pg_temp', data_schema);
208
+ EXECUTE format('ALTER FUNCTION opengeni_private.enforce_codex_credential_workspace() SET search_path = pg_catalog, %I, pg_temp', data_schema);
209
+
210
+ SELECT pg_get_functiondef('opengeni_private.enforce_codex_credential_workspace()'::regprocedure)
211
+ INTO definition;
212
+ patched := replace(definition,
213
+ E'IF NOT opengeni_private.codex_credential_serves_workspace(\n NEW.account_id, NEW.workspace_id, candidate\n ) THEN',
214
+ E'IF NOT opengeni_private.codex_credential_serves_workspace(\n NEW.account_id, NEW.workspace_id, candidate\n ) AND NOT opengeni_private.codex_credential_serves_turn(\n NEW.account_id, NEW.workspace_id, candidate, NEW.active_turn_id\n ) THEN');
215
+ IF patched = definition THEN
216
+ RAISE EXCEPTION '0492 session credential guard prerequisite drift';
217
+ END IF;
218
+ EXECUTE patched;
219
+ FOR role_name IN
220
+ SELECT DISTINCT role_row.rolname FROM pg_proc routine
221
+ CROSS JOIN LATERAL aclexplode(coalesce(routine.proacl, acldefault('f', routine.proowner))) privilege
222
+ JOIN pg_roles role_row ON role_row.oid = privilege.grantee
223
+ WHERE routine.oid = 'capture_legacy_codex_turn_sources(uuid,uuid)'::regprocedure
224
+ AND privilege.grantee <> routine.proowner
225
+ LOOP
226
+ EXECUTE format('REVOKE ALL ON FUNCTION %I.capture_legacy_codex_turn_sources(uuid,uuid) FROM %I', data_schema, role_name);
227
+ END LOOP;
228
+ IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'opengeni_app') THEN
229
+ EXECUTE format('REVOKE ALL ON %I.codex_turn_source_bindings FROM opengeni_app', data_schema);
230
+ EXECUTE format('GRANT SELECT ON %I.codex_turn_source_bindings TO opengeni_app', data_schema);
231
+ EXECUTE format('GRANT EXECUTE ON FUNCTION %I.capture_legacy_codex_turn_sources(uuid,uuid) TO opengeni_app', data_schema);
232
+ GRANT EXECUTE ON FUNCTION opengeni_private.codex_credential_serves_turn(uuid,uuid,uuid,uuid) TO opengeni_app;
233
+ END IF;
234
+ END
235
+ $accepted_codex_source$;
236
+
237
+ -- Retargeting an existing lease changes the accepted authority just as surely
238
+ -- as changing its credential; validate both paths at the database boundary.
239
+ DROP TRIGGER codex_credential_leases_source_guard ON codex_credential_leases;
240
+ CREATE TRIGGER codex_credential_leases_source_guard
241
+ BEFORE INSERT OR UPDATE OF account_id, workspace_id, credential_id, turn_id
242
+ ON codex_credential_leases
243
+ FOR EACH ROW EXECUTE FUNCTION opengeni_private.enforce_codex_lease_source();
244
+
245
+ SELECT pg_temp.assert_codex_source_runtime_drain();
246
+ DROP FUNCTION pg_temp.assert_codex_source_runtime_drain();
247
+
248
+ RESET statement_timeout;
249
+ RESET lock_timeout;
@@ -0,0 +1,58 @@
1
+ -- deployment-mode: rolling
2
+ -- Inventory explicit stop requests whose provider observer repeatedly fails.
3
+ -- This is not exit proof: exact workspace enrollment still requires physical
4
+ -- owner quiescence, idle grace, no other holders/admissions and a checkpoint
5
+ -- before provider termination. Ordinary running commands remain excluded.
6
+ SET LOCAL lock_timeout = '5s';
7
+ SET LOCAL statement_timeout = '10min';
8
+
9
+ DO $install$
10
+ DECLARE target_schema text := current_schema();
11
+ BEGIN
12
+ EXECUTE format($definition$
13
+ CREATE OR REPLACE FUNCTION opengeni_private.list_unobservable_command_drain_candidates(p_limit integer)
14
+ RETURNS TABLE(account_id uuid, workspace_id uuid, sandbox_group_id uuid)
15
+ LANGUAGE plpgsql SECURITY DEFINER SET search_path = pg_catalog, %1$I, pg_temp
16
+ AS $body$
17
+ DECLARE inventory_id uuid;
18
+ BEGIN
19
+ IF p_limit < 1 OR p_limit > 100 THEN RAISE EXCEPTION 'invalid drain batch'; END IF;
20
+ inventory_id := opengeni_private.open_session_tenancy_fence_inventory(%1$I.session_tenancy_fence_target_schema());
21
+ RETURN QUERY SELECT lease.account_id, lease.workspace_id, lease.sandbox_group_id
22
+ FROM %1$I.sandbox_leases lease
23
+ WHERE lease.backend = 'modal' AND lease.liveness IN ('warm', 'draining')
24
+ AND (lease.unobservable_command_drain_ids IS NOT NULL OR EXISTS (
25
+ SELECT 1 FROM %1$I.sandbox_retained_processes process
26
+ WHERE process.lease_id = lease.id AND process.state = 'active'
27
+ AND (
28
+ process.last_reconcile_outcome IN (
29
+ 'process_observation_unavailable', 'quarantined_process_observation_unavailable',
30
+ 'provider_binding_missing', 'quarantined_provider_binding_missing',
31
+ 'provider_binding_mismatch', 'quarantined_provider_binding_mismatch'
32
+ )
33
+ OR (
34
+ process.last_reconcile_outcome = 'provider_error'
35
+ AND process.reconcile_attempts >= 5
36
+ AND EXISTS (
37
+ SELECT 1 FROM %1$I.session_background_commands command
38
+ WHERE command.retained_process_id = process.id
39
+ AND command.workspace_id = process.workspace_id
40
+ AND command.session_id = process.session_id
41
+ AND command.provider = 'managed' AND command.state = 'stopping'
42
+ AND command.cancel_requested_at IS NOT NULL
43
+ )
44
+ )
45
+ )
46
+ ))
47
+ ORDER BY lease.unobservable_command_checked_at NULLS FIRST, lease.id LIMIT p_limit;
48
+ PERFORM opengeni_private.close_session_tenancy_fence_inventory(inventory_id);
49
+ EXCEPTION WHEN OTHERS THEN
50
+ PERFORM opengeni_private.close_session_tenancy_fence_inventory(inventory_id);
51
+ RAISE;
52
+ END $body$;
53
+ $definition$, target_schema);
54
+ REVOKE ALL ON FUNCTION opengeni_private.list_unobservable_command_drain_candidates(integer) FROM PUBLIC;
55
+ END $install$;
56
+
57
+ RESET statement_timeout;
58
+ RESET lock_timeout;