@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.
- package/dist/automations.d.ts +0 -2
- package/dist/canonical-human-identities.d.ts +4 -0
- package/dist/canonical-human-identities.js +3 -3
- package/dist/capability-components.d.ts +5 -13
- package/dist/capability-integrations.d.ts +23 -8
- package/dist/capability-reconciliation.d.ts +5 -0
- package/dist/capability-reconciliation.js +21 -0
- package/dist/capability-reconciliation.js.map +1 -0
- package/dist/{chunk-6T2GGYWE.js → chunk-4UJCXBR2.js} +4 -5800
- package/dist/chunk-4UJCXBR2.js.map +1 -0
- package/dist/{chunk-MWMXWHJD.js → chunk-7JCDSMX2.js} +2 -2
- package/dist/chunk-AJA2ZIUW.js +219 -0
- package/dist/chunk-AJA2ZIUW.js.map +1 -0
- package/dist/chunk-CDAT6EKW.js +247 -0
- package/dist/chunk-CDAT6EKW.js.map +1 -0
- package/dist/{chunk-DPONPYJD.js → chunk-CJI6G254.js} +70 -18
- package/dist/chunk-CJI6G254.js.map +1 -0
- package/dist/chunk-G32NVMRJ.js +276 -0
- package/dist/chunk-G32NVMRJ.js.map +1 -0
- package/dist/chunk-GABXCG3N.js +5811 -0
- package/dist/chunk-GABXCG3N.js.map +1 -0
- package/dist/{chunk-ERKVSPDX.js → chunk-LVY33EWL.js} +3 -3
- package/dist/{chunk-45CP2YKY.js → chunk-MAMBI2HR.js} +9 -3
- package/dist/{chunk-45CP2YKY.js.map → chunk-MAMBI2HR.js.map} +1 -1
- package/dist/{chunk-F73UKJY6.js → chunk-MN5PZMEK.js} +91 -108
- package/dist/chunk-MN5PZMEK.js.map +1 -0
- package/dist/chunk-PJI4MUZ7.js +131 -0
- package/dist/chunk-PJI4MUZ7.js.map +1 -0
- package/dist/{chunk-T6BWIGWJ.js → chunk-RIYHP2WU.js} +2 -2
- package/dist/{chunk-7HMK3B45.js → chunk-RL2MUXM3.js} +16 -7
- package/dist/chunk-RL2MUXM3.js.map +1 -0
- package/dist/{chunk-HQDVI2DB.js → chunk-SYKHLPTK.js} +4 -3
- package/dist/{chunk-HQDVI2DB.js.map → chunk-SYKHLPTK.js.map} +1 -1
- package/dist/{chunk-T6YLHJLS.js → chunk-XIXVVBW2.js} +198 -51
- package/dist/chunk-XIXVVBW2.js.map +1 -0
- package/dist/chunk-ZPJ6V2VG.js +156 -0
- package/dist/chunk-ZPJ6V2VG.js.map +1 -0
- package/dist/codex-capacity-recovery.d.ts +12 -0
- package/dist/codex-failure-eligibility.d.ts +9 -0
- package/dist/company-profile-schema.d.ts +4 -2
- package/dist/connect-attempts.d.ts +15 -0
- package/dist/connect-attempts.js +25 -0
- package/dist/connect-attempts.js.map +1 -0
- package/dist/connection-authority.d.ts +7 -63
- package/dist/connection-refresh-lock.d.ts +4 -0
- package/dist/connection-token-resolver.d.ts +8 -43
- package/dist/database-timing.d.ts +10 -0
- package/dist/database.d.ts +4 -0
- package/dist/editable-artifact-durable-export.js +2 -2
- package/dist/editable-artifacts.d.ts +9 -0
- package/dist/editable-artifacts.js +7 -5
- package/dist/index.d.ts +447 -78
- package/dist/index.js +12705 -12872
- package/dist/index.js.map +1 -1
- package/dist/insights-usage-bundle.d.ts +3 -0
- package/dist/integration-bindings.d.ts +1 -1
- package/dist/integration-facets.d.ts +18 -1
- package/dist/knowledge-entries-schema.d.ts +2 -0
- package/dist/knowledge-entries.d.ts +1 -0
- package/dist/knowledge-indexing.d.ts +1 -0
- package/dist/live-session-attempt.d.ts +35 -137
- package/dist/managed-auth-session-sets.js +3 -3
- package/dist/mcp-account-bindings.d.ts +4 -0
- package/dist/mcp-oauth.d.ts +11 -0
- package/dist/mcp-operations.js +2 -2
- package/dist/migrate.js +1 -1
- package/dist/organization-integration-policy.d.ts +51 -0
- package/dist/organization-integration-policy.js +18 -0
- package/dist/organization-integration-policy.js.map +1 -0
- package/dist/organization-usage.d.ts +20 -0
- package/dist/plugin-packages.d.ts +9 -12
- package/dist/pr-review.d.ts +0 -11
- package/dist/preference-registry-schema.d.ts +17 -0
- package/dist/provision-roles.js +1 -1
- package/dist/retained-provider-commands.d.ts +124 -6
- package/dist/retained-provider-commands.js +29 -97
- package/dist/retained-provider-commands.js.map +1 -1
- package/dist/retired-session-create-metadata.d.ts +4 -0
- package/dist/runtime-posture.d.ts +7 -5
- package/dist/schema.d.ts +876 -656
- package/dist/schema.js +5 -7
- package/dist/session-admission-block.d.ts +32 -0
- package/dist/session-attempt-writers.d.ts +4 -0
- package/dist/session-background-commands.js +5 -4
- package/dist/session-command-output.js +8 -126
- package/dist/session-command-output.js.map +1 -1
- package/dist/session-control.d.ts +5 -1
- package/dist/session-event-slices.d.ts +10 -0
- package/dist/session-event-slices.js +8 -222
- package/dist/session-event-slices.js.map +1 -1
- package/dist/session-file-attachments.d.ts +28 -0
- package/dist/session-goal-reports.d.ts +43 -0
- package/dist/session-mcp-approval.d.ts +4 -0
- package/dist/session-mcp-credential-rotation.js +5 -4
- package/dist/session-mcp-credential-rotation.js.map +1 -1
- package/dist/session-message-search.d.ts +22 -0
- package/dist/session-queue-commands.d.ts +2 -6
- package/dist/session-retry.d.ts +36 -0
- package/dist/session-tenancy.js +3 -3
- package/dist/skill-source-release-impact.d.ts +18 -0
- package/dist/skill-source-release.d.ts +9 -0
- package/dist/skills.d.ts +7 -1
- package/dist/user-resource-authority.d.ts +0 -8
- package/dist/video-generation.js +3 -3
- package/dist/workspace-tool-defaults.js +5 -4
- package/dist/workspace-tool-defaults.js.map +1 -1
- package/drizzle/0468_knowledge_relationship_projection.sql +30 -0
- package/drizzle/0469_knowledge_source_discovery.sql +85 -0
- package/drizzle/0470_organization_integration_policy.sql +151 -0
- package/drizzle/0471_usage_events_account_recent_index.sql +4 -0
- package/drizzle/0472_usage_events_workspace_recent_index.sql +4 -0
- package/drizzle/0473_organization_usage_analytical_capability.sql +237 -0
- package/drizzle/0474_goal_report_requirements.sql +156 -0
- package/drizzle/0475_session_event_history_statistics.sql +15 -0
- package/drizzle/0476_session_event_history_policy_planning.sql +29 -0
- package/drizzle/0477_managed_sign_in_methods.sql +303 -0
- package/drizzle/0478_sender_owned_connections.sql +2772 -0
- package/drizzle/0479_connection_create_idempotency.sql +16 -0
- package/drizzle/0480_private_session_organization_key_administration.sql +154 -0
- package/drizzle/0481_personal_connection_visibility_cleanup.sql +45 -0
- package/drizzle/0482_remove_packs.sql +417 -0
- package/drizzle/0483_preclaim_admission_block.sql +85 -0
- package/drizzle/0484_insights_usage_projection.sql +211 -0
- package/drizzle/0485_inherited_mcp_approval_policies.sql +6 -0
- package/drizzle/0486_reasoning_configuration_message_forks.sql +35 -0
- package/drizzle/0487_skill_catalog_message_forks.sql +26 -0
- package/drizzle/0488_permanent_skill_removal.sql +207 -0
- package/drizzle/0489_modal_command_byte_offsets.sql +17 -0
- package/drizzle/0490_periodic_capture_attempt_cadence.sql +6 -0
- package/drizzle/0491_warm_capture_holder_reclamation.sql +57 -0
- package/drizzle/0492_codex_accepted_source_authority.sql +249 -0
- package/drizzle/0493_stopping_command_error_containment.sql +58 -0
- package/drizzle/0494_mcp_account_bindings.sql +334 -0
- package/drizzle/0495_consented_sandbox_recovery.sql +220 -0
- package/drizzle/0496_supervised_command_settlement.sql +386 -0
- package/drizzle/0497_modal_inventory_owner_read_capability.sql +112 -0
- package/drizzle/0498_enrollment_membership_fence.sql +87 -0
- package/drizzle/0499_session_attachment_access.sql +224 -0
- package/drizzle/0500_session_execution_epoch.sql +37 -0
- package/drizzle/0501_session_sharing_execution.sql +591 -0
- package/drizzle/0502_active_message_boundary_forks.sql +30 -0
- package/package.json +17 -5
- package/src/automations.ts +17 -73
- package/src/canonical-human-identities.ts +17 -5
- package/src/capability-components.ts +7 -24
- package/src/capability-integrations.ts +301 -21
- package/src/capability-reconciliation.ts +19 -0
- package/src/codex-capacity-recovery.ts +47 -0
- package/src/codex-failure-eligibility.ts +93 -0
- package/src/connect-attempts.ts +49 -18
- package/src/connection-authority.ts +12 -158
- package/src/connection-refresh-lock.ts +22 -0
- package/src/connection-token-resolver.ts +58 -530
- package/src/database-timing.ts +43 -0
- package/src/database.ts +61 -26
- package/src/editable-artifacts.ts +1 -1
- package/src/index.ts +3578 -1273
- package/src/insights-model-bundle.ts +19 -7
- package/src/insights-usage-bundle.ts +16 -19
- package/src/integration-bindings.ts +2 -7
- package/src/integration-facets.ts +73 -6
- package/src/knowledge-entries.ts +8 -1
- package/src/live-session-attempt.ts +0 -22
- package/src/mcp-account-bindings.ts +12 -0
- package/src/mcp-oauth.ts +26 -0
- package/src/organization-integration-policy.ts +235 -0
- package/src/organization-usage.ts +83 -0
- package/src/plugin-packages.ts +226 -42
- package/src/pr-review.ts +7 -69
- package/src/preference-registry-schema.ts +1 -0
- package/src/provision-roles.ts +50 -37
- package/src/retained-provider-commands.ts +286 -9
- package/src/retired-session-create-metadata.ts +16 -0
- package/src/runtime-posture.ts +217 -13
- package/src/schema.ts +104 -120
- package/src/session-admission-block.ts +29 -0
- package/src/session-attempt-writers.ts +48 -0
- package/src/session-control.ts +21 -5
- package/src/session-event-slices.ts +76 -26
- package/src/session-file-attachments.ts +66 -0
- package/src/session-goal-reports.ts +255 -0
- package/src/session-mcp-approval.ts +30 -0
- package/src/session-message-search.ts +348 -0
- package/src/session-queue-commands.ts +60 -36
- package/src/session-retry.ts +319 -0
- package/src/skill-config-migration.ts +11 -2
- package/src/skill-source-release-impact.ts +33 -0
- package/src/skill-source-release.ts +67 -26
- package/src/skills.ts +44 -6
- package/src/user-resource-authority.ts +0 -56
- package/dist/chunk-6T2GGYWE.js.map +0 -1
- package/dist/chunk-7HMK3B45.js.map +0 -1
- package/dist/chunk-DPONPYJD.js.map +0 -1
- package/dist/chunk-F73UKJY6.js.map +0 -1
- package/dist/chunk-T6YLHJLS.js.map +0 -1
- package/dist/host-mcp-binding-match.d.ts +0 -5
- package/dist/host-mcp-bindings.d.ts +0 -79
- package/dist/host-mcp-resolvers.d.ts +0 -47
- package/dist/host-mcp-task-authority.d.ts +0 -43
- package/dist/host-selection-identity.d.ts +0 -6
- package/dist/pack-components.d.ts +0 -83
- package/dist/pack-installations.d.ts +0 -86
- package/src/host-mcp-binding-match.ts +0 -34
- package/src/host-mcp-bindings.ts +0 -777
- package/src/host-mcp-resolvers.ts +0 -266
- package/src/host-mcp-task-authority.ts +0 -384
- package/src/host-selection-identity.ts +0 -29
- package/src/pack-components.ts +0 -980
- package/src/pack-installations.ts +0 -950
- /package/dist/{chunk-MWMXWHJD.js.map → chunk-7JCDSMX2.js.map} +0 -0
- /package/dist/{chunk-ERKVSPDX.js.map → chunk-LVY33EWL.js.map} +0 -0
- /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;
|