@opengeni/db 0.21.0 → 0.22.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-OTJHD33E.js → chunk-BNGEN5QZ.js} +5 -1
- package/dist/chunk-BNGEN5QZ.js.map +1 -0
- package/dist/{chunk-NK2A36KP.js → chunk-CYGFLLMN.js} +150 -1
- package/dist/chunk-CYGFLLMN.js.map +1 -0
- package/dist/index.d.ts +84 -0
- package/dist/index.js +565 -4
- package/dist/index.js.map +1 -1
- package/dist/provision-roles.js +1 -1
- package/dist/runtime-posture.d.ts +2 -2
- package/dist/schema.d.ts +820 -0
- package/dist/schema.js +5 -1
- package/dist/session-control.d.ts +1 -0
- package/drizzle/0155_connector_action_policies.sql +218 -0
- package/package.json +3 -3
- package/src/index.ts +870 -0
- package/src/runtime-posture.ts +4 -0
- package/src/schema.ts +181 -0
- package/src/session-control.ts +3 -0
- package/dist/chunk-NK2A36KP.js.map +0 -1
- package/dist/chunk-OTJHD33E.js.map +0 -1
package/dist/schema.js
CHANGED
|
@@ -12,6 +12,8 @@ import {
|
|
|
12
12
|
codexSubscriptionCredentials,
|
|
13
13
|
composerDrafts,
|
|
14
14
|
connections,
|
|
15
|
+
connectorActionPolicies,
|
|
16
|
+
connectorActionRequests,
|
|
15
17
|
creditLedgerEntries,
|
|
16
18
|
deviceEnrollmentRequests,
|
|
17
19
|
deviceEnrollmentStatusValues,
|
|
@@ -130,7 +132,7 @@ import {
|
|
|
130
132
|
workspaceVariableSetVariables,
|
|
131
133
|
workspaceVariableSets,
|
|
132
134
|
workspaces
|
|
133
|
-
} from "./chunk-
|
|
135
|
+
} from "./chunk-CYGFLLMN.js";
|
|
134
136
|
import "./chunk-PZ5AY32C.js";
|
|
135
137
|
export {
|
|
136
138
|
agentRunStates,
|
|
@@ -146,6 +148,8 @@ export {
|
|
|
146
148
|
codexSubscriptionCredentials,
|
|
147
149
|
composerDrafts,
|
|
148
150
|
connections,
|
|
151
|
+
connectorActionPolicies,
|
|
152
|
+
connectorActionRequests,
|
|
149
153
|
creditLedgerEntries,
|
|
150
154
|
deviceEnrollmentRequests,
|
|
151
155
|
deviceEnrollmentStatusValues,
|
|
@@ -196,6 +196,7 @@ export declare function registerSessionTurnAttemptClaim(db: Database, input: {
|
|
|
196
196
|
temporalActivityId: string;
|
|
197
197
|
verifiedControlRevision: number;
|
|
198
198
|
mcpApprovalPolicies: Record<string, SessionMcpApprovalPolicy>;
|
|
199
|
+
connectorActionPolicies: schema.ConnectorActionPolicySnapshotEntry[];
|
|
199
200
|
}): Promise<typeof schema.sessionTurnAttempts.$inferSelect>;
|
|
200
201
|
/**
|
|
201
202
|
* Close the exact first-class owner while the caller still holds the owning
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
-- deployment-mode: rolling
|
|
2
|
+
-- Attempt-frozen connector action policy and secret-free execution evidence.
|
|
3
|
+
|
|
4
|
+
CREATE TABLE connector_action_policies (
|
|
5
|
+
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
6
|
+
account_id uuid NOT NULL REFERENCES managed_accounts(id) ON DELETE CASCADE,
|
|
7
|
+
workspace_id uuid NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
|
|
8
|
+
connection_id text NOT NULL,
|
|
9
|
+
server_id text NOT NULL,
|
|
10
|
+
tool_name text NOT NULL,
|
|
11
|
+
action_name text NOT NULL,
|
|
12
|
+
policy text NOT NULL,
|
|
13
|
+
version integer NOT NULL DEFAULT 1,
|
|
14
|
+
created_by_subject_id text NOT NULL,
|
|
15
|
+
updated_by_subject_id text NOT NULL,
|
|
16
|
+
created_at timestamptz NOT NULL DEFAULT now(),
|
|
17
|
+
updated_at timestamptz NOT NULL DEFAULT now(),
|
|
18
|
+
CONSTRAINT connector_action_policies_connection_id_chk
|
|
19
|
+
CHECK (octet_length(btrim(connection_id)) BETWEEN 1 AND 512),
|
|
20
|
+
CONSTRAINT connector_action_policies_server_id_chk
|
|
21
|
+
CHECK (octet_length(btrim(server_id)) BETWEEN 1 AND 256),
|
|
22
|
+
CONSTRAINT connector_action_policies_tool_name_chk
|
|
23
|
+
CHECK (octet_length(btrim(tool_name)) BETWEEN 1 AND 512),
|
|
24
|
+
CONSTRAINT connector_action_policies_action_name_chk
|
|
25
|
+
CHECK (octet_length(btrim(action_name)) BETWEEN 1 AND 512),
|
|
26
|
+
CONSTRAINT connector_action_policies_policy_chk
|
|
27
|
+
CHECK (policy IN ('allow', 'ask', 'block')),
|
|
28
|
+
CONSTRAINT connector_action_policies_version_chk CHECK (version > 0),
|
|
29
|
+
CONSTRAINT connector_action_policies_creator_chk
|
|
30
|
+
CHECK (octet_length(btrim(created_by_subject_id)) BETWEEN 1 AND 1024),
|
|
31
|
+
CONSTRAINT connector_action_policies_updater_chk
|
|
32
|
+
CHECK (octet_length(btrim(updated_by_subject_id)) BETWEEN 1 AND 1024),
|
|
33
|
+
CONSTRAINT connector_action_policies_workspace_account_fk
|
|
34
|
+
FOREIGN KEY (workspace_id, account_id)
|
|
35
|
+
REFERENCES workspaces(id, account_id) ON DELETE CASCADE,
|
|
36
|
+
CONSTRAINT connector_action_policies_scope_uq
|
|
37
|
+
UNIQUE (workspace_id, connection_id, server_id, tool_name, action_name)
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
CREATE INDEX connector_action_policies_workspace_connection_idx
|
|
41
|
+
ON connector_action_policies(workspace_id, connection_id, server_id);
|
|
42
|
+
|
|
43
|
+
ALTER TABLE session_turn_attempts
|
|
44
|
+
ADD COLUMN connector_action_policies jsonb NOT NULL DEFAULT '[]'::jsonb,
|
|
45
|
+
ADD CONSTRAINT session_turn_attempts_connector_action_policies_chk
|
|
46
|
+
CHECK (
|
|
47
|
+
jsonb_typeof(connector_action_policies) = 'array'
|
|
48
|
+
AND jsonb_array_length(connector_action_policies) <= 2048
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
CREATE TABLE connector_action_requests (
|
|
52
|
+
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
53
|
+
account_id uuid NOT NULL REFERENCES managed_accounts(id) ON DELETE CASCADE,
|
|
54
|
+
workspace_id uuid NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
|
|
55
|
+
session_id uuid NOT NULL,
|
|
56
|
+
turn_id uuid NOT NULL,
|
|
57
|
+
creation_attempt_id uuid NOT NULL,
|
|
58
|
+
creation_execution_generation integer NOT NULL,
|
|
59
|
+
execution_attempt_id uuid,
|
|
60
|
+
execution_attempt_generation integer,
|
|
61
|
+
approval_id text NOT NULL,
|
|
62
|
+
initiator_kind text NOT NULL,
|
|
63
|
+
initiator_subject_id text NOT NULL,
|
|
64
|
+
connection_id text NOT NULL,
|
|
65
|
+
connection_version integer,
|
|
66
|
+
server_id text NOT NULL,
|
|
67
|
+
tool_name text NOT NULL,
|
|
68
|
+
action_name text NOT NULL,
|
|
69
|
+
-- Snapshot provenance intentionally has no FK: a policy may be changed or
|
|
70
|
+
-- deleted after claim, while the attempt-frozen decision remains executable.
|
|
71
|
+
policy_id uuid,
|
|
72
|
+
policy_version integer,
|
|
73
|
+
policy_source text NOT NULL,
|
|
74
|
+
policy_decision text NOT NULL,
|
|
75
|
+
action_fingerprint text NOT NULL,
|
|
76
|
+
status text NOT NULL,
|
|
77
|
+
decision text,
|
|
78
|
+
decision_by_subject_id text,
|
|
79
|
+
-- Durable provenance UUID; session-event retention must not rewrite a settled
|
|
80
|
+
-- connector decision or trip the immutable-decision trigger.
|
|
81
|
+
decision_event_id uuid,
|
|
82
|
+
decided_at timestamptz,
|
|
83
|
+
execution_started_at timestamptz,
|
|
84
|
+
execution_finished_at timestamptz,
|
|
85
|
+
outcome text,
|
|
86
|
+
created_at timestamptz NOT NULL DEFAULT now(),
|
|
87
|
+
updated_at timestamptz NOT NULL DEFAULT now(),
|
|
88
|
+
CONSTRAINT connector_action_requests_creation_attempt_fk
|
|
89
|
+
FOREIGN KEY (account_id, workspace_id, session_id, turn_id, creation_attempt_id)
|
|
90
|
+
REFERENCES session_turn_attempts(account_id, workspace_id, session_id, turn_id, id)
|
|
91
|
+
ON DELETE CASCADE,
|
|
92
|
+
CONSTRAINT connector_action_requests_execution_attempt_fk
|
|
93
|
+
FOREIGN KEY (account_id, workspace_id, session_id, turn_id, execution_attempt_id)
|
|
94
|
+
REFERENCES session_turn_attempts(account_id, workspace_id, session_id, turn_id, id)
|
|
95
|
+
ON DELETE CASCADE,
|
|
96
|
+
CONSTRAINT connector_action_requests_identity_uq
|
|
97
|
+
UNIQUE (workspace_id, session_id, turn_id, approval_id),
|
|
98
|
+
CONSTRAINT connector_action_requests_creation_generation_chk
|
|
99
|
+
CHECK (creation_execution_generation > 0),
|
|
100
|
+
CONSTRAINT connector_action_requests_execution_attempt_chk
|
|
101
|
+
CHECK (
|
|
102
|
+
(execution_attempt_id IS NULL AND execution_attempt_generation IS NULL)
|
|
103
|
+
OR
|
|
104
|
+
(execution_attempt_id IS NOT NULL AND execution_attempt_generation > 0)
|
|
105
|
+
),
|
|
106
|
+
CONSTRAINT connector_action_requests_approval_id_chk
|
|
107
|
+
CHECK (octet_length(btrim(approval_id)) BETWEEN 1 AND 1024),
|
|
108
|
+
CONSTRAINT connector_action_requests_initiator_kind_chk
|
|
109
|
+
CHECK (initiator_kind IN ('subject', 'service')),
|
|
110
|
+
CONSTRAINT connector_action_requests_initiator_subject_chk
|
|
111
|
+
CHECK (octet_length(btrim(initiator_subject_id)) BETWEEN 1 AND 1024),
|
|
112
|
+
CONSTRAINT connector_action_requests_connection_id_chk
|
|
113
|
+
CHECK (octet_length(btrim(connection_id)) BETWEEN 1 AND 512),
|
|
114
|
+
CONSTRAINT connector_action_requests_connection_version_chk
|
|
115
|
+
CHECK (connection_version IS NULL OR connection_version > 0),
|
|
116
|
+
CONSTRAINT connector_action_requests_server_id_chk
|
|
117
|
+
CHECK (octet_length(btrim(server_id)) BETWEEN 1 AND 256),
|
|
118
|
+
CONSTRAINT connector_action_requests_tool_name_chk
|
|
119
|
+
CHECK (octet_length(btrim(tool_name)) BETWEEN 1 AND 512),
|
|
120
|
+
CONSTRAINT connector_action_requests_action_name_chk
|
|
121
|
+
CHECK (octet_length(btrim(action_name)) BETWEEN 1 AND 512),
|
|
122
|
+
CONSTRAINT connector_action_requests_policy_version_chk
|
|
123
|
+
CHECK (policy_version IS NULL OR policy_version > 0),
|
|
124
|
+
CONSTRAINT connector_action_requests_policy_source_chk
|
|
125
|
+
CHECK (policy_source IN ('explicit', 'ambiguous')),
|
|
126
|
+
CONSTRAINT connector_action_requests_policy_decision_chk
|
|
127
|
+
CHECK (policy_decision IN ('allow', 'ask', 'block')),
|
|
128
|
+
CONSTRAINT connector_action_requests_fingerprint_chk
|
|
129
|
+
CHECK (action_fingerprint ~ '^[0-9a-f]{64}$'),
|
|
130
|
+
CONSTRAINT connector_action_requests_status_chk
|
|
131
|
+
CHECK (status IN (
|
|
132
|
+
'pending', 'approved', 'rejected', 'blocked', 'executing',
|
|
133
|
+
'completed', 'failed', 'uncertain'
|
|
134
|
+
)),
|
|
135
|
+
CONSTRAINT connector_action_requests_decision_chk
|
|
136
|
+
CHECK (decision IS NULL OR decision IN ('approve', 'reject')),
|
|
137
|
+
CONSTRAINT connector_action_requests_decision_consistency_chk
|
|
138
|
+
CHECK (
|
|
139
|
+
(decision IS NULL AND decision_by_subject_id IS NULL AND decision_event_id IS NULL AND decided_at IS NULL)
|
|
140
|
+
OR
|
|
141
|
+
(decision IS NOT NULL AND decision_by_subject_id IS NOT NULL AND decision_event_id IS NOT NULL AND decided_at IS NOT NULL)
|
|
142
|
+
)
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
CREATE INDEX connector_action_requests_attempt_status_idx
|
|
146
|
+
ON connector_action_requests(workspace_id, creation_attempt_id, status);
|
|
147
|
+
CREATE INDEX connector_action_requests_session_created_idx
|
|
148
|
+
ON connector_action_requests(workspace_id, session_id, created_at DESC, id DESC);
|
|
149
|
+
|
|
150
|
+
CREATE OR REPLACE FUNCTION opengeni_private.prevent_connector_action_request_identity_mutation()
|
|
151
|
+
RETURNS trigger
|
|
152
|
+
LANGUAGE plpgsql
|
|
153
|
+
AS $$
|
|
154
|
+
BEGIN
|
|
155
|
+
IF NEW.account_id IS DISTINCT FROM OLD.account_id
|
|
156
|
+
OR NEW.workspace_id IS DISTINCT FROM OLD.workspace_id
|
|
157
|
+
OR NEW.session_id IS DISTINCT FROM OLD.session_id
|
|
158
|
+
OR NEW.turn_id IS DISTINCT FROM OLD.turn_id
|
|
159
|
+
OR NEW.creation_attempt_id IS DISTINCT FROM OLD.creation_attempt_id
|
|
160
|
+
OR NEW.creation_execution_generation IS DISTINCT FROM OLD.creation_execution_generation
|
|
161
|
+
OR NEW.approval_id IS DISTINCT FROM OLD.approval_id
|
|
162
|
+
OR NEW.initiator_kind IS DISTINCT FROM OLD.initiator_kind
|
|
163
|
+
OR NEW.initiator_subject_id IS DISTINCT FROM OLD.initiator_subject_id
|
|
164
|
+
OR NEW.connection_id IS DISTINCT FROM OLD.connection_id
|
|
165
|
+
OR NEW.connection_version IS DISTINCT FROM OLD.connection_version
|
|
166
|
+
OR NEW.server_id IS DISTINCT FROM OLD.server_id
|
|
167
|
+
OR NEW.tool_name IS DISTINCT FROM OLD.tool_name
|
|
168
|
+
OR NEW.action_name IS DISTINCT FROM OLD.action_name
|
|
169
|
+
OR NEW.policy_id IS DISTINCT FROM OLD.policy_id
|
|
170
|
+
OR NEW.policy_version IS DISTINCT FROM OLD.policy_version
|
|
171
|
+
OR NEW.policy_source IS DISTINCT FROM OLD.policy_source
|
|
172
|
+
OR NEW.policy_decision IS DISTINCT FROM OLD.policy_decision
|
|
173
|
+
OR NEW.action_fingerprint IS DISTINCT FROM OLD.action_fingerprint
|
|
174
|
+
THEN
|
|
175
|
+
RAISE EXCEPTION 'connector action request identity is immutable' USING ERRCODE = '23514';
|
|
176
|
+
END IF;
|
|
177
|
+
IF OLD.execution_attempt_id IS NOT NULL AND (
|
|
178
|
+
NEW.execution_attempt_id IS DISTINCT FROM OLD.execution_attempt_id
|
|
179
|
+
OR NEW.execution_attempt_generation IS DISTINCT FROM OLD.execution_attempt_generation
|
|
180
|
+
) THEN
|
|
181
|
+
RAISE EXCEPTION 'connector action execution attempt is immutable' USING ERRCODE = '23514';
|
|
182
|
+
END IF;
|
|
183
|
+
IF OLD.decision IS NOT NULL AND (
|
|
184
|
+
NEW.decision IS DISTINCT FROM OLD.decision
|
|
185
|
+
OR NEW.decision_by_subject_id IS DISTINCT FROM OLD.decision_by_subject_id
|
|
186
|
+
OR NEW.decision_event_id IS DISTINCT FROM OLD.decision_event_id
|
|
187
|
+
OR NEW.decided_at IS DISTINCT FROM OLD.decided_at
|
|
188
|
+
) THEN
|
|
189
|
+
RAISE EXCEPTION 'connector action approval decision is immutable' USING ERRCODE = '23514';
|
|
190
|
+
END IF;
|
|
191
|
+
RETURN NEW;
|
|
192
|
+
END;
|
|
193
|
+
$$;
|
|
194
|
+
|
|
195
|
+
CREATE TRIGGER connector_action_requests_identity_immutable
|
|
196
|
+
BEFORE UPDATE ON connector_action_requests
|
|
197
|
+
FOR EACH ROW
|
|
198
|
+
EXECUTE FUNCTION opengeni_private.prevent_connector_action_request_identity_mutation();
|
|
199
|
+
|
|
200
|
+
ALTER TABLE connector_action_policies ENABLE ROW LEVEL SECURITY;
|
|
201
|
+
ALTER TABLE connector_action_policies FORCE ROW LEVEL SECURITY;
|
|
202
|
+
CREATE POLICY connector_action_policies_workspace_isolation ON connector_action_policies
|
|
203
|
+
USING (opengeni_private.workspace_rls_visible(account_id, workspace_id))
|
|
204
|
+
WITH CHECK (opengeni_private.workspace_rls_visible(account_id, workspace_id));
|
|
205
|
+
|
|
206
|
+
ALTER TABLE connector_action_requests ENABLE ROW LEVEL SECURITY;
|
|
207
|
+
ALTER TABLE connector_action_requests FORCE ROW LEVEL SECURITY;
|
|
208
|
+
CREATE POLICY connector_action_requests_workspace_isolation ON connector_action_requests
|
|
209
|
+
USING (opengeni_private.workspace_rls_visible(account_id, workspace_id))
|
|
210
|
+
WITH CHECK (opengeni_private.workspace_rls_visible(account_id, workspace_id));
|
|
211
|
+
|
|
212
|
+
DO $$
|
|
213
|
+
BEGIN
|
|
214
|
+
IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'opengeni_app') THEN
|
|
215
|
+
GRANT SELECT, INSERT, UPDATE, DELETE ON connector_action_policies TO opengeni_app;
|
|
216
|
+
GRANT SELECT, INSERT, UPDATE, DELETE ON connector_action_requests TO opengeni_app;
|
|
217
|
+
END IF;
|
|
218
|
+
END $$;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opengeni/db",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.22.1",
|
|
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": {
|
|
@@ -51,8 +51,8 @@
|
|
|
51
51
|
},
|
|
52
52
|
"dependencies": {
|
|
53
53
|
"@opengeni/codex": "^0.2.9",
|
|
54
|
-
"@opengeni/config": "^0.
|
|
55
|
-
"@opengeni/contracts": "^0.
|
|
54
|
+
"@opengeni/config": "^0.10.0",
|
|
55
|
+
"@opengeni/contracts": "^0.31.0",
|
|
56
56
|
"@opengeni/network": "^0.1.1",
|
|
57
57
|
"drizzle-orm": "^0.45.2",
|
|
58
58
|
"postgres": "^3.4.7"
|