@opengeni/db 0.4.0 → 0.6.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/LICENSE +190 -0
- package/dist/{chunk-T2U4H4Z2.js → chunk-ZIUCA2IO.js} +150 -5
- package/dist/chunk-ZIUCA2IO.js.map +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1161 -21
- package/dist/index.js.map +1 -1
- package/dist/provision-roles.d.ts +286 -5
- package/dist/{schema-DuRsrmzD.d.ts → schema-Dsz6UHNv.d.ts} +2391 -854
- package/dist/schema.d.ts +1 -1
- package/dist/schema.js +11 -1
- package/drizzle/0038_enrollment_desktop_unavailable_reason.sql +18 -0
- package/drizzle/0038_observability_counts.sql +32 -0
- package/drizzle/0039_connections.sql +62 -0
- package/drizzle/0039_session_mcp_require_approval.sql +7 -0
- package/drizzle/0040_schema_agnostic_opengeni_app_grants.sql +36 -0
- package/drizzle/0041_knowledge_layer.sql +73 -0
- package/drizzle/0042_integration_oauth_state.sql +56 -0
- package/drizzle/0043_integrations_catalog_imports.sql +104 -0
- package/drizzle/0043_toolspace_call_budget.sql +14 -0
- package/package.json +5 -10
- package/src/connection-token-resolver.ts +481 -0
- package/src/event-payload-sanitizer.ts +23 -0
- package/src/index.ts +1086 -23
- package/src/schema.ts +150 -2
- package/dist/chunk-T2U4H4Z2.js.map +0 -1
package/dist/schema.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import 'drizzle-orm';
|
|
2
2
|
import 'drizzle-orm/pg-core';
|
|
3
|
-
export { i as agentRunStates, j as apiKeys, k as auditEvents, l as billingCustomers, m as capabilityCatalogItems, n as capabilityInstallations, o as codexRotationSettings, p as codexSubscriptionCredentials, q as
|
|
3
|
+
export { i as agentRunStates, j as apiKeys, k as auditEvents, l as billingCustomers, m as capabilityCatalogItems, n as capabilityInstallations, o as codexRotationSettings, p as codexSubscriptionCredentials, q as connections, r as creditLedgerEntries, t as deviceEnrollmentRequests, d as deviceEnrollmentStatusValues, u as documentBases, v as documentChunks, w as documents, a as enrollmentExposureValues, e as enrollmentOsValues, b as enrollmentStatusValues, x as enrollments, y as fileUploads, z as files, A as githubInstallations, B as importBatches, C as integrationOauthClients, D as integrationOauthStateNonces, E as knowledgeMemories, F as machineMetricsLatest, G as machineMetricsSeries, H as managedAccounts, I as packInstallations, c as sandboxKindValues, J as sandboxLeaseHolders, K as sandboxLeaseLivenessValues, L as sandboxLeases, M as sandboxPtySessions, N as sandboxSessionEnvelopes, O as sandboxes, P as scheduledTaskRuns, Q as scheduledTasks, R as sessionEvents, S as sessionGoals, T as sessionHistoryItems, U as sessionMcpServers, f as sessionRecordingCodecValues, g as sessionRecordingModeValues, h as sessionRecordingStateValues, V as sessionRecordings, W as sessionTurns, X as sessions, Y as socialConnections, Z as socialPosts, _ as stripeWebhookEvents, $ as usageEvents, a0 as workspaceEnvironmentVariables, a1 as workspaceEnvironments, a2 as workspaceMemberships, a3 as workspacePacks, a4 as workspaces } from './schema-Dsz6UHNv.js';
|
package/dist/schema.js
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
capabilityInstallations,
|
|
8
8
|
codexRotationSettings,
|
|
9
9
|
codexSubscriptionCredentials,
|
|
10
|
+
connections,
|
|
10
11
|
creditLedgerEntries,
|
|
11
12
|
deviceEnrollmentRequests,
|
|
12
13
|
deviceEnrollmentStatusValues,
|
|
@@ -20,6 +21,10 @@ import {
|
|
|
20
21
|
fileUploads,
|
|
21
22
|
files,
|
|
22
23
|
githubInstallations,
|
|
24
|
+
importBatches,
|
|
25
|
+
integrationOauthClients,
|
|
26
|
+
integrationOauthStateNonces,
|
|
27
|
+
knowledgeMemories,
|
|
23
28
|
machineMetricsLatest,
|
|
24
29
|
machineMetricsSeries,
|
|
25
30
|
managedAccounts,
|
|
@@ -52,7 +57,7 @@ import {
|
|
|
52
57
|
workspaceMemberships,
|
|
53
58
|
workspacePacks,
|
|
54
59
|
workspaces
|
|
55
|
-
} from "./chunk-
|
|
60
|
+
} from "./chunk-ZIUCA2IO.js";
|
|
56
61
|
import "./chunk-PZ5AY32C.js";
|
|
57
62
|
export {
|
|
58
63
|
agentRunStates,
|
|
@@ -63,6 +68,7 @@ export {
|
|
|
63
68
|
capabilityInstallations,
|
|
64
69
|
codexRotationSettings,
|
|
65
70
|
codexSubscriptionCredentials,
|
|
71
|
+
connections,
|
|
66
72
|
creditLedgerEntries,
|
|
67
73
|
deviceEnrollmentRequests,
|
|
68
74
|
deviceEnrollmentStatusValues,
|
|
@@ -76,6 +82,10 @@ export {
|
|
|
76
82
|
fileUploads,
|
|
77
83
|
files,
|
|
78
84
|
githubInstallations,
|
|
85
|
+
importBatches,
|
|
86
|
+
integrationOauthClients,
|
|
87
|
+
integrationOauthStateNonces,
|
|
88
|
+
knowledgeMemories,
|
|
79
89
|
machineMetricsLatest,
|
|
80
90
|
machineMetricsSeries,
|
|
81
91
|
managedAccounts,
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
-- Server-visible "display present but capture not granted" state.
|
|
2
|
+
--
|
|
3
|
+
-- A machine can have a display it cannot CAPTURE (macOS Screen Recording / TCC not
|
|
4
|
+
-- granted). The agent's connect Hello now reports has_display=false AND a human,
|
|
5
|
+
-- actionable reason for that case; persist the reason alongside has_display so the
|
|
6
|
+
-- Machines dashboard / VM picker can surface "display: capture not granted" instead
|
|
7
|
+
-- of a bare display_unavailable — the state must be VISIBLE server-side, not just in
|
|
8
|
+
-- a local agent log. NULL means capture is permitted OR the machine is genuinely
|
|
9
|
+
-- headless, so every existing row keeps its historical semantics with no backfill.
|
|
10
|
+
ALTER TABLE "enrollments"
|
|
11
|
+
ADD COLUMN IF NOT EXISTS "desktop_unavailable_reason" text;
|
|
12
|
+
|
|
13
|
+
DO $$
|
|
14
|
+
BEGIN
|
|
15
|
+
IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'opengeni_app') THEN
|
|
16
|
+
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO opengeni_app;
|
|
17
|
+
END IF;
|
|
18
|
+
END $$;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
-- 0038_observability_counts.sql
|
|
2
|
+
-- Cross-workspace aggregate reads for Prometheus gauges. These mirror the
|
|
3
|
+
-- sandbox reaper's SECURITY DEFINER pattern so workers can refresh global
|
|
4
|
+
-- process metrics without disabling FORCE RLS on workspace-scoped tables.
|
|
5
|
+
|
|
6
|
+
CREATE OR REPLACE FUNCTION opengeni_private.count_queued_turns()
|
|
7
|
+
RETURNS bigint
|
|
8
|
+
LANGUAGE sql
|
|
9
|
+
SECURITY DEFINER
|
|
10
|
+
AS $$
|
|
11
|
+
SELECT count(*)::bigint
|
|
12
|
+
FROM session_turns
|
|
13
|
+
WHERE status = 'queued';
|
|
14
|
+
$$;
|
|
15
|
+
|
|
16
|
+
CREATE OR REPLACE FUNCTION opengeni_private.count_sandbox_leases_by_liveness()
|
|
17
|
+
RETURNS TABLE (liveness text, count bigint)
|
|
18
|
+
LANGUAGE sql
|
|
19
|
+
SECURITY DEFINER
|
|
20
|
+
AS $$
|
|
21
|
+
SELECT L.liveness, count(*)::bigint
|
|
22
|
+
FROM sandbox_leases L
|
|
23
|
+
GROUP BY L.liveness;
|
|
24
|
+
$$;
|
|
25
|
+
|
|
26
|
+
DO $$
|
|
27
|
+
BEGIN
|
|
28
|
+
IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'opengeni_app') THEN
|
|
29
|
+
GRANT EXECUTE ON FUNCTION opengeni_private.count_queued_turns() TO opengeni_app;
|
|
30
|
+
GRANT EXECUTE ON FUNCTION opengeni_private.count_sandbox_leases_by_liveness() TO opengeni_app;
|
|
31
|
+
END IF;
|
|
32
|
+
END $$;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
CREATE TABLE IF NOT EXISTS "connections" (
|
|
2
|
+
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
|
3
|
+
"account_id" uuid NOT NULL REFERENCES "managed_accounts"("id") ON DELETE CASCADE,
|
|
4
|
+
"workspace_id" uuid NOT NULL REFERENCES "workspaces"("id") ON DELETE CASCADE,
|
|
5
|
+
"subject_id" text,
|
|
6
|
+
"provider_domain" text NOT NULL,
|
|
7
|
+
"kind" text NOT NULL,
|
|
8
|
+
"status" text NOT NULL DEFAULT 'active',
|
|
9
|
+
"credential_encrypted" text NOT NULL,
|
|
10
|
+
"granted_scopes" jsonb NOT NULL DEFAULT '[]'::jsonb,
|
|
11
|
+
"expires_at" timestamptz,
|
|
12
|
+
"last_refresh_at" timestamptz,
|
|
13
|
+
"last_used_at" timestamptz,
|
|
14
|
+
"last_error" text,
|
|
15
|
+
"version" integer NOT NULL DEFAULT 1,
|
|
16
|
+
"metadata" jsonb NOT NULL DEFAULT '{}'::jsonb,
|
|
17
|
+
"created_by_subject_id" text,
|
|
18
|
+
"updated_by_subject_id" text,
|
|
19
|
+
"created_at" timestamptz NOT NULL DEFAULT now(),
|
|
20
|
+
"updated_at" timestamptz NOT NULL DEFAULT now(),
|
|
21
|
+
CONSTRAINT "connections_kind_chk"
|
|
22
|
+
CHECK ("kind" IN ('oauth2', 'api_key', 'app_install', 'delegated')),
|
|
23
|
+
CONSTRAINT "connections_status_chk"
|
|
24
|
+
CHECK ("status" IN ('active', 'needs_reauth', 'revoked', 'error')),
|
|
25
|
+
CONSTRAINT "connections_granted_scopes_array_chk"
|
|
26
|
+
CHECK (jsonb_typeof("granted_scopes") = 'array'),
|
|
27
|
+
CONSTRAINT "connections_metadata_object_chk"
|
|
28
|
+
CHECK (jsonb_typeof("metadata") = 'object'),
|
|
29
|
+
CONSTRAINT "connections_version_positive_chk"
|
|
30
|
+
CHECK ("version" > 0)
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
CREATE INDEX IF NOT EXISTS "connections_workspace_provider_status_idx"
|
|
34
|
+
ON "connections" ("workspace_id", "provider_domain", "status");
|
|
35
|
+
CREATE INDEX IF NOT EXISTS "connections_workspace_subject_provider_idx"
|
|
36
|
+
ON "connections" ("workspace_id", "subject_id", "provider_domain");
|
|
37
|
+
CREATE INDEX IF NOT EXISTS "connections_workspace_kind_idx"
|
|
38
|
+
ON "connections" ("workspace_id", "kind");
|
|
39
|
+
CREATE INDEX IF NOT EXISTS "connections_workspace_expires_idx"
|
|
40
|
+
ON "connections" ("workspace_id", "expires_at");
|
|
41
|
+
|
|
42
|
+
ALTER TABLE "connections" ENABLE ROW LEVEL SECURITY;
|
|
43
|
+
ALTER TABLE "connections" FORCE ROW LEVEL SECURITY;
|
|
44
|
+
DO $$
|
|
45
|
+
BEGIN
|
|
46
|
+
IF EXISTS (
|
|
47
|
+
SELECT 1 FROM pg_policies
|
|
48
|
+
WHERE schemaname = current_schema() AND tablename = 'connections' AND policyname = 'workspace_isolation'
|
|
49
|
+
) THEN
|
|
50
|
+
DROP POLICY workspace_isolation ON "connections";
|
|
51
|
+
END IF;
|
|
52
|
+
END $$;
|
|
53
|
+
CREATE POLICY workspace_isolation ON "connections"
|
|
54
|
+
USING (opengeni_private.workspace_rls_visible(account_id, workspace_id))
|
|
55
|
+
WITH CHECK (opengeni_private.workspace_rls_visible(account_id, workspace_id));
|
|
56
|
+
|
|
57
|
+
DO $$
|
|
58
|
+
BEGIN
|
|
59
|
+
IF EXISTS (SELECT FROM pg_roles WHERE rolname = 'opengeni_app') THEN
|
|
60
|
+
GRANT SELECT, INSERT, UPDATE, DELETE ON "connections" TO opengeni_app;
|
|
61
|
+
END IF;
|
|
62
|
+
END $$;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
-- 0039_session_mcp_require_approval.sql
|
|
2
|
+
-- Per-session-MCP-server human-approval policy. jsonb holds either `true`
|
|
3
|
+
-- (every tool of the server requires approval) or a JSON array of UNPREFIXED
|
|
4
|
+
-- tool names (only those require it). NULL / absent = auto-run (the historical
|
|
5
|
+
-- default), so this is additive and backfill-free.
|
|
6
|
+
|
|
7
|
+
ALTER TABLE "session_mcp_servers" ADD COLUMN IF NOT EXISTS "require_approval" jsonb;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
-- Correct historical opengeni_app grant blocks that hardcoded `public`.
|
|
2
|
+
-- Embedded hosts run migrations with search_path pointed at their dedicated
|
|
3
|
+
-- data schema, so grants must target current_schema().
|
|
4
|
+
|
|
5
|
+
DO $$
|
|
6
|
+
DECLARE
|
|
7
|
+
target_schema text := current_schema();
|
|
8
|
+
owner_role text := current_user;
|
|
9
|
+
app_role text := 'opengeni_app';
|
|
10
|
+
BEGIN
|
|
11
|
+
IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = app_role) THEN
|
|
12
|
+
EXECUTE format('GRANT USAGE ON SCHEMA %I TO %I', target_schema, app_role);
|
|
13
|
+
EXECUTE format(
|
|
14
|
+
'GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA %I TO %I',
|
|
15
|
+
target_schema,
|
|
16
|
+
app_role
|
|
17
|
+
);
|
|
18
|
+
EXECUTE format(
|
|
19
|
+
'GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA %I TO %I',
|
|
20
|
+
target_schema,
|
|
21
|
+
app_role
|
|
22
|
+
);
|
|
23
|
+
EXECUTE format(
|
|
24
|
+
'ALTER DEFAULT PRIVILEGES FOR ROLE %I IN SCHEMA %I GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO %I',
|
|
25
|
+
owner_role,
|
|
26
|
+
target_schema,
|
|
27
|
+
app_role
|
|
28
|
+
);
|
|
29
|
+
EXECUTE format(
|
|
30
|
+
'ALTER DEFAULT PRIVILEGES FOR ROLE %I IN SCHEMA %I GRANT USAGE, SELECT ON SEQUENCES TO %I',
|
|
31
|
+
owner_role,
|
|
32
|
+
target_schema,
|
|
33
|
+
app_role
|
|
34
|
+
);
|
|
35
|
+
END IF;
|
|
36
|
+
END $$;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
ALTER TABLE "documents" ADD COLUMN IF NOT EXISTS "source_kind" text NOT NULL DEFAULT 'manual_upload';
|
|
2
|
+
ALTER TABLE "documents" ADD COLUMN IF NOT EXISTS "source_uri" text;
|
|
3
|
+
ALTER TABLE "documents" ADD COLUMN IF NOT EXISTS "source_external_id" text;
|
|
4
|
+
ALTER TABLE "documents" ADD COLUMN IF NOT EXISTS "source_title" text;
|
|
5
|
+
ALTER TABLE "documents" ADD COLUMN IF NOT EXISTS "source_author" text;
|
|
6
|
+
ALTER TABLE "documents" ADD COLUMN IF NOT EXISTS "source_created_at" timestamptz;
|
|
7
|
+
ALTER TABLE "documents" ADD COLUMN IF NOT EXISTS "source_updated_at" timestamptz;
|
|
8
|
+
ALTER TABLE "documents" ADD COLUMN IF NOT EXISTS "source_version" text;
|
|
9
|
+
ALTER TABLE "documents" ADD COLUMN IF NOT EXISTS "acl_tags" jsonb NOT NULL DEFAULT '[]'::jsonb;
|
|
10
|
+
|
|
11
|
+
CREATE INDEX IF NOT EXISTS "documents_workspace_source_kind_idx" ON "documents" ("workspace_id", "source_kind");
|
|
12
|
+
CREATE INDEX IF NOT EXISTS "documents_workspace_source_external_id_idx" ON "documents" ("workspace_id", "source_external_id");
|
|
13
|
+
CREATE INDEX IF NOT EXISTS "documents_acl_tags_idx" ON "documents" USING gin ("acl_tags");
|
|
14
|
+
CREATE INDEX IF NOT EXISTS "document_chunks_text_fts_idx" ON "document_chunks" USING gin (to_tsvector('simple', "text"));
|
|
15
|
+
|
|
16
|
+
CREATE TABLE IF NOT EXISTS "knowledge_memories" (
|
|
17
|
+
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
|
18
|
+
"account_id" uuid NOT NULL REFERENCES "managed_accounts"("id") ON DELETE CASCADE,
|
|
19
|
+
"workspace_id" uuid NOT NULL REFERENCES "workspaces"("id") ON DELETE CASCADE,
|
|
20
|
+
"status" text NOT NULL DEFAULT 'proposed',
|
|
21
|
+
"kind" text NOT NULL DEFAULT 'semantic',
|
|
22
|
+
"scope" text NOT NULL DEFAULT 'workspace',
|
|
23
|
+
"text" text NOT NULL,
|
|
24
|
+
"source_refs" jsonb NOT NULL DEFAULT '[]'::jsonb,
|
|
25
|
+
"confidence" integer NOT NULL DEFAULT 50,
|
|
26
|
+
"metadata" jsonb NOT NULL DEFAULT '{}'::jsonb,
|
|
27
|
+
"created_by_session_id" uuid REFERENCES "sessions"("id") ON DELETE SET NULL,
|
|
28
|
+
"reviewed_by" text,
|
|
29
|
+
"reviewed_at" timestamptz,
|
|
30
|
+
"created_at" timestamptz NOT NULL DEFAULT now(),
|
|
31
|
+
"updated_at" timestamptz NOT NULL DEFAULT now()
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
DO $$
|
|
35
|
+
BEGIN
|
|
36
|
+
IF NOT EXISTS (
|
|
37
|
+
SELECT 1 FROM pg_constraint WHERE conname = 'knowledge_memories_workspace_account_fk'
|
|
38
|
+
) THEN
|
|
39
|
+
ALTER TABLE "knowledge_memories" ADD CONSTRAINT "knowledge_memories_workspace_account_fk"
|
|
40
|
+
FOREIGN KEY ("workspace_id", "account_id") REFERENCES "workspaces"("id", "account_id") ON DELETE CASCADE;
|
|
41
|
+
END IF;
|
|
42
|
+
END $$;
|
|
43
|
+
|
|
44
|
+
CREATE INDEX IF NOT EXISTS "knowledge_memories_workspace_status_idx" ON "knowledge_memories" ("workspace_id", "status", "updated_at");
|
|
45
|
+
CREATE INDEX IF NOT EXISTS "knowledge_memories_workspace_kind_idx" ON "knowledge_memories" ("workspace_id", "kind");
|
|
46
|
+
CREATE INDEX IF NOT EXISTS "knowledge_memories_workspace_scope_idx" ON "knowledge_memories" ("workspace_id", "scope");
|
|
47
|
+
CREATE INDEX IF NOT EXISTS "knowledge_memories_workspace_created_by_session_idx" ON "knowledge_memories" ("workspace_id", "created_by_session_id");
|
|
48
|
+
CREATE INDEX IF NOT EXISTS "knowledge_memories_text_fts_idx" ON "knowledge_memories" USING gin (to_tsvector('simple', "text"));
|
|
49
|
+
|
|
50
|
+
ALTER TABLE "knowledge_memories" ENABLE ROW LEVEL SECURITY;
|
|
51
|
+
ALTER TABLE "knowledge_memories" FORCE ROW LEVEL SECURITY;
|
|
52
|
+
DO $$
|
|
53
|
+
BEGIN
|
|
54
|
+
IF EXISTS (
|
|
55
|
+
SELECT 1 FROM pg_policies
|
|
56
|
+
WHERE schemaname = current_schema() AND tablename = 'knowledge_memories' AND policyname = 'workspace_isolation'
|
|
57
|
+
) THEN
|
|
58
|
+
DROP POLICY workspace_isolation ON "knowledge_memories";
|
|
59
|
+
END IF;
|
|
60
|
+
END $$;
|
|
61
|
+
CREATE POLICY workspace_isolation ON "knowledge_memories"
|
|
62
|
+
USING (opengeni_private.workspace_rls_visible(account_id, workspace_id))
|
|
63
|
+
WITH CHECK (opengeni_private.workspace_rls_visible(account_id, workspace_id));
|
|
64
|
+
|
|
65
|
+
DO $$
|
|
66
|
+
BEGIN
|
|
67
|
+
IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'opengeni_app') THEN
|
|
68
|
+
EXECUTE format(
|
|
69
|
+
'GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA %I TO opengeni_app',
|
|
70
|
+
current_schema()
|
|
71
|
+
);
|
|
72
|
+
END IF;
|
|
73
|
+
END $$;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
CREATE TABLE IF NOT EXISTS "integration_oauth_clients" (
|
|
2
|
+
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
|
3
|
+
"issuer" text NOT NULL,
|
|
4
|
+
"authorization_server" text NOT NULL,
|
|
5
|
+
"client_id" text NOT NULL,
|
|
6
|
+
"client_secret_encrypted" text,
|
|
7
|
+
"token_endpoint_auth_method" text NOT NULL DEFAULT 'none',
|
|
8
|
+
"metadata" jsonb NOT NULL DEFAULT '{}'::jsonb,
|
|
9
|
+
"created_at" timestamptz NOT NULL DEFAULT now(),
|
|
10
|
+
"updated_at" timestamptz NOT NULL DEFAULT now(),
|
|
11
|
+
CONSTRAINT "integration_oauth_clients_metadata_object_chk"
|
|
12
|
+
CHECK (jsonb_typeof("metadata") = 'object')
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
CREATE UNIQUE INDEX IF NOT EXISTS "integration_oauth_clients_issuer_idx"
|
|
16
|
+
ON "integration_oauth_clients" ("issuer");
|
|
17
|
+
CREATE INDEX IF NOT EXISTS "integration_oauth_clients_as_idx"
|
|
18
|
+
ON "integration_oauth_clients" ("authorization_server");
|
|
19
|
+
|
|
20
|
+
CREATE TABLE IF NOT EXISTS "integration_oauth_state_nonces" (
|
|
21
|
+
"nonce" text PRIMARY KEY NOT NULL,
|
|
22
|
+
"account_id" uuid NOT NULL REFERENCES "managed_accounts"("id") ON DELETE CASCADE,
|
|
23
|
+
"workspace_id" uuid NOT NULL REFERENCES "workspaces"("id") ON DELETE CASCADE,
|
|
24
|
+
"subject_id" text NOT NULL,
|
|
25
|
+
"expires_at" timestamptz NOT NULL,
|
|
26
|
+
"used_at" timestamptz NOT NULL DEFAULT now(),
|
|
27
|
+
"created_at" timestamptz NOT NULL DEFAULT now()
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
CREATE INDEX IF NOT EXISTS "integration_oauth_state_nonces_workspace_idx"
|
|
31
|
+
ON "integration_oauth_state_nonces" ("workspace_id");
|
|
32
|
+
CREATE INDEX IF NOT EXISTS "integration_oauth_state_nonces_expires_idx"
|
|
33
|
+
ON "integration_oauth_state_nonces" ("expires_at");
|
|
34
|
+
|
|
35
|
+
ALTER TABLE "integration_oauth_state_nonces" ENABLE ROW LEVEL SECURITY;
|
|
36
|
+
ALTER TABLE "integration_oauth_state_nonces" FORCE ROW LEVEL SECURITY;
|
|
37
|
+
DO $$
|
|
38
|
+
BEGIN
|
|
39
|
+
IF EXISTS (
|
|
40
|
+
SELECT 1 FROM pg_policies
|
|
41
|
+
WHERE schemaname = current_schema() AND tablename = 'integration_oauth_state_nonces' AND policyname = 'workspace_isolation'
|
|
42
|
+
) THEN
|
|
43
|
+
DROP POLICY workspace_isolation ON "integration_oauth_state_nonces";
|
|
44
|
+
END IF;
|
|
45
|
+
END $$;
|
|
46
|
+
CREATE POLICY workspace_isolation ON "integration_oauth_state_nonces"
|
|
47
|
+
USING (opengeni_private.workspace_rls_visible(account_id, workspace_id))
|
|
48
|
+
WITH CHECK (opengeni_private.workspace_rls_visible(account_id, workspace_id));
|
|
49
|
+
|
|
50
|
+
DO $$
|
|
51
|
+
BEGIN
|
|
52
|
+
IF EXISTS (SELECT FROM pg_roles WHERE rolname = 'opengeni_app') THEN
|
|
53
|
+
GRANT SELECT, INSERT, UPDATE, DELETE ON "integration_oauth_clients" TO opengeni_app;
|
|
54
|
+
GRANT SELECT, INSERT, UPDATE, DELETE ON "integration_oauth_state_nonces" TO opengeni_app;
|
|
55
|
+
END IF;
|
|
56
|
+
END $$;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
CREATE TABLE IF NOT EXISTS "import_batches" (
|
|
2
|
+
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
|
3
|
+
"source" text NOT NULL,
|
|
4
|
+
"snapshot_date" timestamptz NOT NULL,
|
|
5
|
+
"snapshot_ref" text,
|
|
6
|
+
"attribution_note" text NOT NULL,
|
|
7
|
+
"imported_count" integer NOT NULL DEFAULT 0,
|
|
8
|
+
"skipped_count" integer NOT NULL DEFAULT 0,
|
|
9
|
+
"quarantined_count" integer NOT NULL DEFAULT 0,
|
|
10
|
+
"logo_failure_count" integer NOT NULL DEFAULT 0,
|
|
11
|
+
"stale_count" integer NOT NULL DEFAULT 0,
|
|
12
|
+
"details" jsonb NOT NULL DEFAULT '{}'::jsonb,
|
|
13
|
+
"created_at" timestamptz NOT NULL DEFAULT now(),
|
|
14
|
+
"updated_at" timestamptz NOT NULL DEFAULT now()
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
CREATE INDEX IF NOT EXISTS "import_batches_source_snapshot_idx" ON "import_batches" ("source", "snapshot_date");
|
|
18
|
+
CREATE INDEX IF NOT EXISTS "import_batches_created_at_idx" ON "import_batches" ("created_at");
|
|
19
|
+
|
|
20
|
+
ALTER TABLE "import_batches" ENABLE ROW LEVEL SECURITY;
|
|
21
|
+
ALTER TABLE "import_batches" FORCE ROW LEVEL SECURITY;
|
|
22
|
+
DO $$
|
|
23
|
+
BEGIN
|
|
24
|
+
IF EXISTS (
|
|
25
|
+
SELECT 1 FROM pg_policies
|
|
26
|
+
WHERE schemaname = current_schema() AND tablename = 'import_batches' AND policyname = 'global_catalog_import_batches'
|
|
27
|
+
) THEN
|
|
28
|
+
DROP POLICY global_catalog_import_batches ON "import_batches";
|
|
29
|
+
END IF;
|
|
30
|
+
END $$;
|
|
31
|
+
CREATE POLICY global_catalog_import_batches ON "import_batches"
|
|
32
|
+
USING (true)
|
|
33
|
+
WITH CHECK (true);
|
|
34
|
+
|
|
35
|
+
ALTER TABLE "capability_catalog_items" ALTER COLUMN "account_id" DROP NOT NULL;
|
|
36
|
+
ALTER TABLE "capability_catalog_items" ALTER COLUMN "workspace_id" DROP NOT NULL;
|
|
37
|
+
ALTER TABLE "capability_catalog_items" ADD COLUMN IF NOT EXISTS "provider_domain" text;
|
|
38
|
+
ALTER TABLE "capability_catalog_items" ADD COLUMN IF NOT EXISTS "surface_type" text;
|
|
39
|
+
ALTER TABLE "capability_catalog_items" ADD COLUMN IF NOT EXISTS "transport" text;
|
|
40
|
+
ALTER TABLE "capability_catalog_items" ADD COLUMN IF NOT EXISTS "mcp_url" text;
|
|
41
|
+
ALTER TABLE "capability_catalog_items" ADD COLUMN IF NOT EXISTS "auth_kind" text;
|
|
42
|
+
ALTER TABLE "capability_catalog_items" ADD COLUMN IF NOT EXISTS "credential_facts" jsonb NOT NULL DEFAULT '[]'::jsonb;
|
|
43
|
+
ALTER TABLE "capability_catalog_items" ADD COLUMN IF NOT EXISTS "tier" text;
|
|
44
|
+
ALTER TABLE "capability_catalog_items" ADD COLUMN IF NOT EXISTS "provenance" text;
|
|
45
|
+
ALTER TABLE "capability_catalog_items" ADD COLUMN IF NOT EXISTS "logo_asset_path" text;
|
|
46
|
+
ALTER TABLE "capability_catalog_items" ADD COLUMN IF NOT EXISTS "import_batch_id" uuid REFERENCES "import_batches"("id") ON DELETE SET NULL;
|
|
47
|
+
ALTER TABLE "capability_catalog_items" ADD COLUMN IF NOT EXISTS "stale" boolean NOT NULL DEFAULT false;
|
|
48
|
+
ALTER TABLE "capability_catalog_items" ADD COLUMN IF NOT EXISTS "stale_at" timestamptz;
|
|
49
|
+
|
|
50
|
+
DO $$
|
|
51
|
+
BEGIN
|
|
52
|
+
IF NOT EXISTS (
|
|
53
|
+
SELECT 1 FROM pg_constraint WHERE conname = 'capability_catalog_items_registry_global_ck'
|
|
54
|
+
) THEN
|
|
55
|
+
ALTER TABLE "capability_catalog_items" ADD CONSTRAINT "capability_catalog_items_registry_global_ck"
|
|
56
|
+
CHECK (
|
|
57
|
+
"source" <> 'registry'
|
|
58
|
+
OR (
|
|
59
|
+
"account_id" IS NULL
|
|
60
|
+
AND "workspace_id" IS NULL
|
|
61
|
+
AND "kind" = 'mcp'
|
|
62
|
+
AND "provider_domain" IS NOT NULL
|
|
63
|
+
AND "mcp_url" IS NOT NULL
|
|
64
|
+
)
|
|
65
|
+
);
|
|
66
|
+
END IF;
|
|
67
|
+
END $$;
|
|
68
|
+
|
|
69
|
+
CREATE UNIQUE INDEX IF NOT EXISTS "capability_catalog_items_registry_surface_idx"
|
|
70
|
+
ON "capability_catalog_items" ("source", "provider_domain", "mcp_url");
|
|
71
|
+
CREATE UNIQUE INDEX IF NOT EXISTS "capability_catalog_items_global_capability_idx"
|
|
72
|
+
ON "capability_catalog_items" ("id") WHERE "workspace_id" IS NULL;
|
|
73
|
+
CREATE INDEX IF NOT EXISTS "capability_catalog_items_provider_domain_idx" ON "capability_catalog_items" ("provider_domain");
|
|
74
|
+
CREATE INDEX IF NOT EXISTS "capability_catalog_items_import_batch_idx" ON "capability_catalog_items" ("import_batch_id");
|
|
75
|
+
CREATE INDEX IF NOT EXISTS "capability_catalog_items_source_stale_idx" ON "capability_catalog_items" ("source", "stale");
|
|
76
|
+
|
|
77
|
+
DO $$
|
|
78
|
+
BEGIN
|
|
79
|
+
IF EXISTS (
|
|
80
|
+
SELECT 1 FROM pg_policies
|
|
81
|
+
WHERE schemaname = current_schema() AND tablename = 'capability_catalog_items' AND policyname = 'workspace_isolation'
|
|
82
|
+
) THEN
|
|
83
|
+
DROP POLICY workspace_isolation ON "capability_catalog_items";
|
|
84
|
+
END IF;
|
|
85
|
+
END $$;
|
|
86
|
+
CREATE POLICY workspace_isolation ON "capability_catalog_items"
|
|
87
|
+
USING (
|
|
88
|
+
("account_id" IS NULL AND "workspace_id" IS NULL)
|
|
89
|
+
OR opengeni_private.workspace_rls_visible(account_id, workspace_id)
|
|
90
|
+
)
|
|
91
|
+
WITH CHECK (
|
|
92
|
+
("account_id" IS NULL AND "workspace_id" IS NULL)
|
|
93
|
+
OR opengeni_private.workspace_rls_visible(account_id, workspace_id)
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
DO $$
|
|
97
|
+
BEGIN
|
|
98
|
+
IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'opengeni_app') THEN
|
|
99
|
+
EXECUTE format(
|
|
100
|
+
'GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA %I TO opengeni_app',
|
|
101
|
+
current_schema()
|
|
102
|
+
);
|
|
103
|
+
END IF;
|
|
104
|
+
END $$;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
-- Per-turn toolspace call budget counter. The previous enforcement read the
|
|
2
|
+
-- count of `agent.toolCall.created` toolspace events then compared against the
|
|
3
|
+
-- limit before appending the next event (read-then-append TOCTOU): concurrent
|
|
4
|
+
-- tools/call requests all observed a stale count and all passed. This column
|
|
5
|
+
-- makes the budget a single atomic reservation:
|
|
6
|
+
-- UPDATE session_turns SET toolspace_call_count = toolspace_call_count + 1
|
|
7
|
+
-- WHERE id = $turn AND toolspace_call_count < $limit RETURNING toolspace_call_count
|
|
8
|
+
-- Concurrent reservations serialize on the row lock, so exactly `limit` succeed.
|
|
9
|
+
--
|
|
10
|
+
-- opengeni_app already holds table-level DML on session_turns (migration 0040
|
|
11
|
+
-- grants ON ALL TABLES + default privileges); a new column inherits those
|
|
12
|
+
-- grants, so no additional GRANT block is required.
|
|
13
|
+
ALTER TABLE "session_turns"
|
|
14
|
+
ADD COLUMN IF NOT EXISTS "toolspace_call_count" integer NOT NULL DEFAULT 0;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opengeni/db",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "OpenGeni persistence: Drizzle schema, RLS-scoped query layer, the SQL migration runner, and role provisioning.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -48,19 +48,14 @@
|
|
|
48
48
|
"migrate": "bun src/migrate.ts",
|
|
49
49
|
"provision-roles": "bun src/provision-roles.ts",
|
|
50
50
|
"typecheck": "tsc --noEmit",
|
|
51
|
-
"build": "tsup"
|
|
51
|
+
"build": "tsup",
|
|
52
|
+
"prepublishOnly": "bash ../../scripts/prepublish-guard"
|
|
52
53
|
},
|
|
53
54
|
"dependencies": {
|
|
54
55
|
"@opengeni/codex": "^0.2.1",
|
|
55
|
-
"@opengeni/config": "^0.
|
|
56
|
-
"@opengeni/contracts": "^0.
|
|
56
|
+
"@opengeni/config": "^0.3.0",
|
|
57
|
+
"@opengeni/contracts": "^0.9.0",
|
|
57
58
|
"drizzle-orm": "^0.45.2",
|
|
58
59
|
"postgres": "^3.4.7"
|
|
59
|
-
},
|
|
60
|
-
"devDependencies": {
|
|
61
|
-
"@opengeni/testing": "workspace:*",
|
|
62
|
-
"drizzle-kit": "^0.31.8",
|
|
63
|
-
"tsup": "^8.5.0",
|
|
64
|
-
"typescript": "^6.0.3"
|
|
65
60
|
}
|
|
66
61
|
}
|