@opengeni/db 3.2.0-canary.0 → 3.4.0-canary.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/canonical-human-identities.js +3 -3
- package/dist/{chunk-SIBYBA2D.js → chunk-6DPJA36C.js} +30 -11
- package/dist/chunk-6DPJA36C.js.map +1 -0
- package/dist/{chunk-KRLPEMLH.js → chunk-C2AFP7SB.js} +184 -6
- package/dist/chunk-C2AFP7SB.js.map +1 -0
- package/dist/{chunk-AZHW7R5V.js → chunk-H7MXYG7R.js} +12 -8
- package/dist/chunk-H7MXYG7R.js.map +1 -0
- package/dist/{chunk-2PRS4J5Q.js → chunk-HY3F5Q4E.js} +3 -3
- package/dist/{chunk-NAB6FKFN.js → chunk-O6FTELKH.js} +3 -3
- package/dist/{chunk-UZNXG44K.js → chunk-PYMY3AJW.js} +324 -8
- package/dist/chunk-PYMY3AJW.js.map +1 -0
- package/dist/{chunk-6HMM2R5T.js → chunk-TRBOWUG3.js} +98 -4
- package/dist/chunk-TRBOWUG3.js.map +1 -0
- package/dist/{chunk-E6CLMKEE.js → chunk-V3TRUXFJ.js} +2 -2
- package/dist/{chunk-2EH4WRHL.js → chunk-ZWRIPCTR.js} +2 -2
- package/dist/editable-artifact-durable-export.js +2 -2
- package/dist/editable-artifacts.js +3 -3
- package/dist/governed-learning-activation.d.ts +16 -0
- package/dist/index.d.ts +108 -7
- package/dist/index.js +3605 -1417
- package/dist/index.js.map +1 -1
- package/dist/insights-model-bundle.d.ts +30 -0
- package/dist/insights-usage-bundle.d.ts +32 -0
- package/dist/insights.d.ts +10 -2
- package/dist/lossless-json.d.ts +1 -1
- package/dist/managed-user-setup.d.ts +82 -0
- package/dist/memory-domain.d.ts +2 -2
- package/dist/migrate.d.ts +3 -1
- package/dist/migrate.js +1 -1
- package/dist/new-session-drafts.d.ts +4 -4
- package/dist/organization-membership-lifecycle.d.ts +60 -1
- package/dist/pr-review.d.ts +44 -3
- package/dist/provision-roles.js +1 -1
- package/dist/runtime-posture.d.ts +12 -7
- package/dist/schema.d.ts +839 -101
- package/dist/schema.js +9 -1
- package/dist/session-background-commands.js +3 -3
- package/dist/session-tenancy.d.ts +12 -1
- package/dist/session-tenancy.js +3 -3
- package/dist/video-generation.js +3 -3
- package/drizzle/0348_named_signup_and_user_setup.sql +838 -0
- package/drizzle/0349_greenfield_session_tenancy_activation.sql +792 -0
- package/drizzle/0350_organization_shared_workspace_administration.sql +889 -0
- package/drizzle/0351_organization_user_setup_delivery.sql +978 -0
- package/drizzle/0352_session_variable_set_attachments.sql +1661 -0
- package/drizzle/0353_automatic_session_title_policy_fence.sql +476 -0
- package/drizzle/0354_automatic_session_title_quarantine_index.sql +9 -0
- package/drizzle/0355_automatic_session_title_quarantine.sql +92 -0
- package/drizzle/0356_set_based_insights_session_visibility.sql +237 -0
- package/drizzle/0357_rig_platform_base_only.sql +44 -0
- package/drizzle/0358_pr_review_managed_github_app.sql +108 -0
- package/drizzle/0359_insights_force_rls_read_capability.sql +936 -0
- package/drizzle/0360_organization_identity_confirmation_prompt.sql +103 -0
- package/drizzle/0361_remember_knowledge_memory_materialization.sql +249 -0
- package/package.json +6 -6
- package/src/database.ts +12 -8
- package/src/governed-learning-activation.ts +74 -2
- package/src/index.ts +879 -92
- package/src/insights-model-bundle.ts +681 -0
- package/src/insights-usage-bundle.ts +240 -0
- package/src/insights.ts +265 -152
- package/src/lossless-json.ts +2 -1
- package/src/managed-user-setup.ts +316 -0
- package/src/memory-domain.ts +3 -3
- package/src/migrate.ts +38 -14
- package/src/new-session-drafts.ts +22 -15
- package/src/organization-membership-lifecycle.ts +253 -1
- package/src/pr-review.ts +449 -6
- package/src/provision-roles.ts +92 -0
- package/src/runtime-posture.ts +247 -4
- package/src/schema.ts +210 -4
- package/src/session-tenancy.ts +120 -2
- package/dist/chunk-6HMM2R5T.js.map +0 -1
- package/dist/chunk-AZHW7R5V.js.map +0 -1
- package/dist/chunk-KRLPEMLH.js.map +0 -1
- package/dist/chunk-SIBYBA2D.js.map +0 -1
- package/dist/chunk-UZNXG44K.js.map +0 -1
- /package/dist/{chunk-2PRS4J5Q.js.map → chunk-HY3F5Q4E.js.map} +0 -0
- /package/dist/{chunk-NAB6FKFN.js.map → chunk-O6FTELKH.js.map} +0 -0
- /package/dist/{chunk-E6CLMKEE.js.map → chunk-V3TRUXFJ.js.map} +0 -0
- /package/dist/{chunk-2EH4WRHL.js.map → chunk-ZWRIPCTR.js.map} +0 -0
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
-- deployment-mode: rolling
|
|
2
|
+
-- Insights scans model_call_facts and usage_events across thousands of rows.
|
|
3
|
+
-- Their ordinary restrictive policies deliberately call
|
|
4
|
+
-- session_reference_visible() for each row, which is correct for point reads
|
|
5
|
+
-- but makes analytical scans execute one nested sessions lookup per fact. Keep
|
|
6
|
+
-- those table policies unchanged for every ordinary caller. These two bounded
|
|
7
|
+
-- read-only functions reproduce the same account/workspace/subject visibility
|
|
8
|
+
-- rule inside one set-based join and expose no data outside the existing fact
|
|
9
|
+
-- shapes. Only roles that already SELECT both fact tables receive EXECUTE.
|
|
10
|
+
DO $set_based_insights_session_visibility_functions$
|
|
11
|
+
DECLARE
|
|
12
|
+
data_schema text := pg_catalog.current_schema();
|
|
13
|
+
BEGIN
|
|
14
|
+
EXECUTE pg_catalog.format($ddl$
|
|
15
|
+
CREATE OR REPLACE FUNCTION opengeni_private.visible_workspace_insights_model_call_facts(
|
|
16
|
+
p_workspace_id uuid,
|
|
17
|
+
p_since timestamp with time zone,
|
|
18
|
+
p_until timestamp with time zone
|
|
19
|
+
) RETURNS SETOF %1$I.model_call_facts
|
|
20
|
+
LANGUAGE plpgsql
|
|
21
|
+
STABLE
|
|
22
|
+
SECURITY DEFINER
|
|
23
|
+
SET search_path = pg_catalog, %1$I, opengeni_private, pg_temp
|
|
24
|
+
AS $function$
|
|
25
|
+
DECLARE
|
|
26
|
+
context_account_id uuid;
|
|
27
|
+
context_workspace_id uuid;
|
|
28
|
+
context_subject_id text;
|
|
29
|
+
BEGIN
|
|
30
|
+
PERFORM opengeni_private.session_variable_set_attachments_protocol_v1_active();
|
|
31
|
+
BEGIN
|
|
32
|
+
context_account_id := nullif(
|
|
33
|
+
pg_catalog.current_setting('opengeni.account_id', true), ''
|
|
34
|
+
)::uuid;
|
|
35
|
+
context_workspace_id := nullif(
|
|
36
|
+
pg_catalog.current_setting('opengeni.workspace_id', true), ''
|
|
37
|
+
)::uuid;
|
|
38
|
+
EXCEPTION WHEN invalid_text_representation THEN
|
|
39
|
+
RAISE EXCEPTION 'Insights RLS context is malformed'
|
|
40
|
+
USING ERRCODE = '42501';
|
|
41
|
+
END;
|
|
42
|
+
context_subject_id := nullif(
|
|
43
|
+
pg_catalog.current_setting('opengeni.subject_id', true), ''
|
|
44
|
+
);
|
|
45
|
+
IF context_account_id IS NULL
|
|
46
|
+
OR context_workspace_id IS NULL
|
|
47
|
+
OR context_workspace_id <> p_workspace_id
|
|
48
|
+
THEN
|
|
49
|
+
RAISE EXCEPTION 'Insights RLS context does not match the requested workspace'
|
|
50
|
+
USING ERRCODE = '42501';
|
|
51
|
+
END IF;
|
|
52
|
+
IF p_since IS NULL
|
|
53
|
+
OR p_until IS NULL
|
|
54
|
+
OR p_until <= p_since
|
|
55
|
+
OR (
|
|
56
|
+
p_until <> 'infinity'::timestamp with time zone
|
|
57
|
+
AND p_until - p_since > interval '370 days'
|
|
58
|
+
)
|
|
59
|
+
OR (
|
|
60
|
+
p_until = 'infinity'::timestamp with time zone
|
|
61
|
+
AND p_since < CURRENT_TIMESTAMP - interval '370 days'
|
|
62
|
+
)
|
|
63
|
+
THEN
|
|
64
|
+
RAISE EXCEPTION 'Insights fact window must be positive and at most 370 days'
|
|
65
|
+
USING ERRCODE = '22023';
|
|
66
|
+
END IF;
|
|
67
|
+
|
|
68
|
+
RETURN QUERY
|
|
69
|
+
SELECT fact.*
|
|
70
|
+
FROM %1$I.model_call_facts fact
|
|
71
|
+
INNER JOIN %1$I.sessions session_row
|
|
72
|
+
ON session_row.account_id = fact.account_id
|
|
73
|
+
AND session_row.workspace_id = fact.workspace_id
|
|
74
|
+
AND session_row.id = fact.session_id
|
|
75
|
+
WHERE fact.account_id = context_account_id
|
|
76
|
+
AND fact.workspace_id = p_workspace_id
|
|
77
|
+
AND fact.occurred_at >= p_since
|
|
78
|
+
AND fact.occurred_at < p_until
|
|
79
|
+
AND (
|
|
80
|
+
context_subject_id IS NULL
|
|
81
|
+
OR session_row.visibility = 'workspace_shared'
|
|
82
|
+
OR %1$I.session_private_actor_visible(
|
|
83
|
+
session_row.account_id,
|
|
84
|
+
session_row.workspace_id,
|
|
85
|
+
session_row.owner_organization_membership_id,
|
|
86
|
+
session_row.owner_subject_id
|
|
87
|
+
)
|
|
88
|
+
);
|
|
89
|
+
END
|
|
90
|
+
$function$;
|
|
91
|
+
$ddl$, data_schema);
|
|
92
|
+
|
|
93
|
+
EXECUTE pg_catalog.format($ddl$
|
|
94
|
+
CREATE OR REPLACE FUNCTION opengeni_private.visible_workspace_insights_usage_events(
|
|
95
|
+
p_workspace_id uuid,
|
|
96
|
+
p_since timestamp with time zone,
|
|
97
|
+
p_until timestamp with time zone
|
|
98
|
+
) RETURNS SETOF %1$I.usage_events
|
|
99
|
+
LANGUAGE plpgsql
|
|
100
|
+
STABLE
|
|
101
|
+
SECURITY DEFINER
|
|
102
|
+
SET search_path = pg_catalog, %1$I, opengeni_private, pg_temp
|
|
103
|
+
AS $function$
|
|
104
|
+
DECLARE
|
|
105
|
+
context_account_id uuid;
|
|
106
|
+
context_workspace_id uuid;
|
|
107
|
+
context_subject_id text;
|
|
108
|
+
BEGIN
|
|
109
|
+
PERFORM opengeni_private.session_variable_set_attachments_protocol_v1_active();
|
|
110
|
+
BEGIN
|
|
111
|
+
context_account_id := nullif(
|
|
112
|
+
pg_catalog.current_setting('opengeni.account_id', true), ''
|
|
113
|
+
)::uuid;
|
|
114
|
+
context_workspace_id := nullif(
|
|
115
|
+
pg_catalog.current_setting('opengeni.workspace_id', true), ''
|
|
116
|
+
)::uuid;
|
|
117
|
+
EXCEPTION WHEN invalid_text_representation THEN
|
|
118
|
+
RAISE EXCEPTION 'Insights RLS context is malformed'
|
|
119
|
+
USING ERRCODE = '42501';
|
|
120
|
+
END;
|
|
121
|
+
context_subject_id := nullif(
|
|
122
|
+
pg_catalog.current_setting('opengeni.subject_id', true), ''
|
|
123
|
+
);
|
|
124
|
+
IF context_account_id IS NULL
|
|
125
|
+
OR context_workspace_id IS NULL
|
|
126
|
+
OR context_workspace_id <> p_workspace_id
|
|
127
|
+
THEN
|
|
128
|
+
RAISE EXCEPTION 'Insights RLS context does not match the requested workspace'
|
|
129
|
+
USING ERRCODE = '42501';
|
|
130
|
+
END IF;
|
|
131
|
+
IF p_since IS NULL
|
|
132
|
+
OR p_until IS NULL
|
|
133
|
+
OR p_until <= p_since
|
|
134
|
+
OR (
|
|
135
|
+
p_until <> 'infinity'::timestamp with time zone
|
|
136
|
+
AND p_until - p_since > interval '370 days'
|
|
137
|
+
)
|
|
138
|
+
OR (
|
|
139
|
+
p_until = 'infinity'::timestamp with time zone
|
|
140
|
+
AND p_since < CURRENT_TIMESTAMP - interval '370 days'
|
|
141
|
+
)
|
|
142
|
+
THEN
|
|
143
|
+
RAISE EXCEPTION 'Insights fact window must be positive and at most 370 days'
|
|
144
|
+
USING ERRCODE = '22023';
|
|
145
|
+
END IF;
|
|
146
|
+
|
|
147
|
+
RETURN QUERY
|
|
148
|
+
SELECT usage_row.*
|
|
149
|
+
FROM %1$I.usage_events usage_row
|
|
150
|
+
LEFT JOIN %1$I.sessions session_row
|
|
151
|
+
ON session_row.account_id = usage_row.account_id
|
|
152
|
+
AND session_row.workspace_id = usage_row.workspace_id
|
|
153
|
+
AND session_row.id = usage_row.session_id
|
|
154
|
+
WHERE usage_row.account_id = context_account_id
|
|
155
|
+
AND usage_row.workspace_id = p_workspace_id
|
|
156
|
+
AND usage_row.occurred_at >= p_since
|
|
157
|
+
AND usage_row.occurred_at < p_until
|
|
158
|
+
AND (
|
|
159
|
+
usage_row.session_id IS NULL
|
|
160
|
+
OR (
|
|
161
|
+
session_row.id IS NOT NULL
|
|
162
|
+
AND (
|
|
163
|
+
context_subject_id IS NULL
|
|
164
|
+
OR session_row.visibility = 'workspace_shared'
|
|
165
|
+
OR %1$I.session_private_actor_visible(
|
|
166
|
+
session_row.account_id,
|
|
167
|
+
session_row.workspace_id,
|
|
168
|
+
session_row.owner_organization_membership_id,
|
|
169
|
+
session_row.owner_subject_id
|
|
170
|
+
)
|
|
171
|
+
)
|
|
172
|
+
)
|
|
173
|
+
);
|
|
174
|
+
END
|
|
175
|
+
$function$;
|
|
176
|
+
$ddl$, data_schema);
|
|
177
|
+
END
|
|
178
|
+
$set_based_insights_session_visibility_functions$;
|
|
179
|
+
|
|
180
|
+
REVOKE ALL ON FUNCTION
|
|
181
|
+
opengeni_private.visible_workspace_insights_model_call_facts(
|
|
182
|
+
uuid, timestamp with time zone, timestamp with time zone
|
|
183
|
+
)
|
|
184
|
+
FROM PUBLIC;
|
|
185
|
+
REVOKE ALL ON FUNCTION
|
|
186
|
+
opengeni_private.visible_workspace_insights_usage_events(
|
|
187
|
+
uuid, timestamp with time zone, timestamp with time zone
|
|
188
|
+
)
|
|
189
|
+
FROM PUBLIC;
|
|
190
|
+
|
|
191
|
+
-- Rolling compatibility is limited to the explicitly configured application
|
|
192
|
+
-- roles. Do not infer application authority from fact-table SELECT: operator,
|
|
193
|
+
-- export, or reporting roles may intentionally lack sessions/private-schema
|
|
194
|
+
-- access even when they can inspect these fact tables through ordinary RLS.
|
|
195
|
+
DO $set_based_insights_session_visibility_grants$
|
|
196
|
+
DECLARE
|
|
197
|
+
data_schema text := pg_catalog.current_schema();
|
|
198
|
+
role_name text;
|
|
199
|
+
BEGIN
|
|
200
|
+
FOR role_name IN
|
|
201
|
+
SELECT role_row.rolname
|
|
202
|
+
FROM pg_catalog.jsonb_array_elements_text(
|
|
203
|
+
pg_catalog.current_setting('opengeni.migration_application_roles')::jsonb
|
|
204
|
+
) configured(value)
|
|
205
|
+
INNER JOIN pg_catalog.pg_roles role_row
|
|
206
|
+
ON role_row.rolname = configured.value
|
|
207
|
+
WHERE pg_catalog.has_table_privilege(
|
|
208
|
+
role_row.rolname,
|
|
209
|
+
pg_catalog.format('%I.model_call_facts', data_schema),
|
|
210
|
+
'SELECT'
|
|
211
|
+
)
|
|
212
|
+
AND pg_catalog.has_table_privilege(
|
|
213
|
+
role_row.rolname,
|
|
214
|
+
pg_catalog.format('%I.usage_events', data_schema),
|
|
215
|
+
'SELECT'
|
|
216
|
+
)
|
|
217
|
+
ORDER BY role_row.rolname COLLATE "C"
|
|
218
|
+
LOOP
|
|
219
|
+
EXECUTE pg_catalog.format(
|
|
220
|
+
'GRANT USAGE ON SCHEMA opengeni_private TO %I',
|
|
221
|
+
role_name
|
|
222
|
+
);
|
|
223
|
+
EXECUTE pg_catalog.format(
|
|
224
|
+
'GRANT EXECUTE ON FUNCTION '
|
|
225
|
+
|| 'opengeni_private.visible_workspace_insights_model_call_facts('
|
|
226
|
+
|| 'uuid, timestamp with time zone, timestamp with time zone) TO %I',
|
|
227
|
+
role_name
|
|
228
|
+
);
|
|
229
|
+
EXECUTE pg_catalog.format(
|
|
230
|
+
'GRANT EXECUTE ON FUNCTION '
|
|
231
|
+
|| 'opengeni_private.visible_workspace_insights_usage_events('
|
|
232
|
+
|| 'uuid, timestamp with time zone, timestamp with time zone) TO %I',
|
|
233
|
+
role_name
|
|
234
|
+
);
|
|
235
|
+
END LOOP;
|
|
236
|
+
END
|
|
237
|
+
$set_based_insights_session_visibility_grants$;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
-- deployment-mode: maintenance
|
|
2
|
+
-- Rig definitions may customize setup and checks, but the deployment owns the
|
|
3
|
+
-- sandbox base image. Preserve historical image-bearing rows for audit and
|
|
4
|
+
-- harmless active/provider metadata updates while rejecting every new image
|
|
5
|
+
-- override at the storage boundary.
|
|
6
|
+
|
|
7
|
+
SET LOCAL lock_timeout = '5s';
|
|
8
|
+
|
|
9
|
+
CREATE OR REPLACE FUNCTION opengeni_private.enforce_rig_platform_base_only_v1()
|
|
10
|
+
RETURNS trigger
|
|
11
|
+
LANGUAGE plpgsql
|
|
12
|
+
SET search_path = pg_catalog
|
|
13
|
+
AS $function$
|
|
14
|
+
BEGIN
|
|
15
|
+
IF TG_OP = 'INSERT' AND NEW.image IS NOT NULL THEN
|
|
16
|
+
RAISE EXCEPTION
|
|
17
|
+
'Rig image overrides are unsupported; Rigs use the deployment platform sandbox image'
|
|
18
|
+
USING ERRCODE = '23514',
|
|
19
|
+
CONSTRAINT = 'rig_versions_platform_base_only';
|
|
20
|
+
END IF;
|
|
21
|
+
|
|
22
|
+
IF TG_OP = 'UPDATE'
|
|
23
|
+
AND NEW.image IS NOT NULL
|
|
24
|
+
AND NEW.image IS DISTINCT FROM OLD.image
|
|
25
|
+
THEN
|
|
26
|
+
RAISE EXCEPTION
|
|
27
|
+
'Rig image overrides are unsupported; Rigs use the deployment platform sandbox image'
|
|
28
|
+
USING ERRCODE = '23514',
|
|
29
|
+
CONSTRAINT = 'rig_versions_platform_base_only';
|
|
30
|
+
END IF;
|
|
31
|
+
|
|
32
|
+
RETURN NEW;
|
|
33
|
+
END
|
|
34
|
+
$function$;
|
|
35
|
+
|
|
36
|
+
REVOKE ALL ON FUNCTION opengeni_private.enforce_rig_platform_base_only_v1() FROM PUBLIC;
|
|
37
|
+
|
|
38
|
+
CREATE TRIGGER rig_versions_platform_base_only
|
|
39
|
+
BEFORE INSERT OR UPDATE OF image ON rig_versions
|
|
40
|
+
FOR EACH ROW
|
|
41
|
+
EXECUTE FUNCTION opengeni_private.enforce_rig_platform_base_only_v1();
|
|
42
|
+
|
|
43
|
+
COMMENT ON COLUMN rig_versions.image IS
|
|
44
|
+
'Legacy audit field only. Runtime ignores it and new non-null values are rejected.';
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
-- deployment-mode: rolling
|
|
2
|
+
-- A deployment-owned, least-privilege GitHub App can be installed through the
|
|
3
|
+
-- same owner-proof browser flow as the platform App. Workspace registrations
|
|
4
|
+
-- reference that managed identity rather than copying its private key. The
|
|
5
|
+
-- credential-free route table resolves an already-authenticated GitHub
|
|
6
|
+
-- delivery to one exact Pack source and repository binding.
|
|
7
|
+
|
|
8
|
+
SET LOCAL lock_timeout = '5s';
|
|
9
|
+
SET LOCAL statement_timeout = '10min';
|
|
10
|
+
|
|
11
|
+
ALTER TABLE pr_review_app_registrations
|
|
12
|
+
ADD COLUMN installation_id text,
|
|
13
|
+
ADD COLUMN provider_account_login text,
|
|
14
|
+
ADD COLUMN provider_account_type text,
|
|
15
|
+
ADD COLUMN github_actor_id text,
|
|
16
|
+
ADD COLUMN authority_kind text,
|
|
17
|
+
ADD COLUMN authority_checked_at timestamptz,
|
|
18
|
+
ADD COLUMN authority_expires_at timestamptz,
|
|
19
|
+
ADD COLUMN authority_nonce text;
|
|
20
|
+
|
|
21
|
+
ALTER TABLE pr_review_app_registrations
|
|
22
|
+
DROP CONSTRAINT pr_review_app_registrations_credential_chk;
|
|
23
|
+
|
|
24
|
+
ALTER TABLE pr_review_app_registrations
|
|
25
|
+
ADD CONSTRAINT pr_review_app_registrations_credential_chk CHECK (
|
|
26
|
+
(provider = 'github' AND credential_kind = 'github_app'
|
|
27
|
+
AND credential_encrypted IS NOT NULL AND app_id IS NOT NULL
|
|
28
|
+
AND installation_id IS NULL)
|
|
29
|
+
OR
|
|
30
|
+
(provider = 'github' AND credential_kind = 'managed_github_app'
|
|
31
|
+
AND credential_encrypted IS NULL AND app_id IS NOT NULL
|
|
32
|
+
AND installation_id IS NOT NULL
|
|
33
|
+
AND provider_account_type IN ('User', 'Organization')
|
|
34
|
+
AND github_actor_id ~ '^[1-9][0-9]*$'
|
|
35
|
+
AND authority_kind IN ('personal_owner', 'organization_owner')
|
|
36
|
+
AND authority_checked_at IS NOT NULL
|
|
37
|
+
AND authority_expires_at IS NOT NULL
|
|
38
|
+
AND authority_expires_at > authority_checked_at
|
|
39
|
+
AND octet_length(authority_nonce) BETWEEN 16 AND 256)
|
|
40
|
+
OR
|
|
41
|
+
(provider IN ('gitlab', 'azure_devops') AND credential_kind = 'provider_token'
|
|
42
|
+
AND credential_encrypted IS NOT NULL AND installation_id IS NULL)
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
CREATE UNIQUE INDEX pr_review_managed_github_workspace_installation_uq
|
|
46
|
+
ON pr_review_app_registrations (workspace_id, installation_id)
|
|
47
|
+
WHERE credential_kind = 'managed_github_app';
|
|
48
|
+
|
|
49
|
+
CREATE UNIQUE INDEX pr_review_managed_github_authority_nonce_uq
|
|
50
|
+
ON pr_review_app_registrations (authority_nonce)
|
|
51
|
+
WHERE authority_nonce IS NOT NULL;
|
|
52
|
+
|
|
53
|
+
-- Append-only consumption receipts keep every successful OAuth state
|
|
54
|
+
-- single-use even after the registration advances to a newer authority proof.
|
|
55
|
+
CREATE TABLE pr_review_managed_github_authority_nonces (
|
|
56
|
+
authority_nonce text PRIMARY KEY,
|
|
57
|
+
account_id uuid NOT NULL REFERENCES managed_accounts(id) ON DELETE CASCADE,
|
|
58
|
+
workspace_id uuid NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
|
|
59
|
+
installation_id text NOT NULL,
|
|
60
|
+
authority_expires_at timestamptz NOT NULL,
|
|
61
|
+
consumed_at timestamptz NOT NULL DEFAULT clock_timestamp(),
|
|
62
|
+
CONSTRAINT pr_review_managed_github_authority_nonces_workspace_account_fk
|
|
63
|
+
FOREIGN KEY (workspace_id, account_id)
|
|
64
|
+
REFERENCES workspaces(id, account_id) ON DELETE CASCADE,
|
|
65
|
+
CONSTRAINT pr_review_managed_github_authority_nonces_identity_chk CHECK (
|
|
66
|
+
octet_length(authority_nonce) BETWEEN 16 AND 256
|
|
67
|
+
AND installation_id ~ '^[1-9][0-9]*$'
|
|
68
|
+
AND authority_expires_at > consumed_at
|
|
69
|
+
)
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
ALTER TABLE pr_review_managed_github_authority_nonces ENABLE ROW LEVEL SECURITY;
|
|
73
|
+
ALTER TABLE pr_review_managed_github_authority_nonces FORCE ROW LEVEL SECURITY;
|
|
74
|
+
CREATE POLICY pr_review_managed_github_authority_nonces_tenant
|
|
75
|
+
ON pr_review_managed_github_authority_nonces
|
|
76
|
+
USING (opengeni_private.workspace_rls_visible(account_id, workspace_id))
|
|
77
|
+
WITH CHECK (opengeni_private.workspace_rls_visible(account_id, workspace_id));
|
|
78
|
+
|
|
79
|
+
-- Credential-free global routing only. The shared webhook secret is verified
|
|
80
|
+
-- over the bounded raw body before these provider ids are parsed or resolved;
|
|
81
|
+
-- the FORCE-RLS source, trigger, Pack installation, and binding remain the
|
|
82
|
+
-- acceptance and dispatch authorities.
|
|
83
|
+
CREATE TABLE pr_review_managed_github_routes (
|
|
84
|
+
binding_id uuid PRIMARY KEY REFERENCES pr_review_repository_bindings(id) ON DELETE CASCADE,
|
|
85
|
+
account_id uuid NOT NULL REFERENCES managed_accounts(id) ON DELETE CASCADE,
|
|
86
|
+
workspace_id uuid NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
|
|
87
|
+
registration_id uuid NOT NULL,
|
|
88
|
+
source_id uuid NOT NULL,
|
|
89
|
+
installation_id text NOT NULL,
|
|
90
|
+
provider_repository_id text NOT NULL,
|
|
91
|
+
created_at timestamptz NOT NULL DEFAULT now(),
|
|
92
|
+
CONSTRAINT pr_review_managed_github_routes_workspace_account_fk
|
|
93
|
+
FOREIGN KEY (workspace_id, account_id)
|
|
94
|
+
REFERENCES workspaces(id, account_id) ON DELETE CASCADE,
|
|
95
|
+
CONSTRAINT pr_review_managed_github_routes_registration_fk
|
|
96
|
+
FOREIGN KEY (workspace_id, registration_id)
|
|
97
|
+
REFERENCES pr_review_app_registrations(workspace_id, id) ON DELETE CASCADE,
|
|
98
|
+
CONSTRAINT pr_review_managed_github_routes_source_fk
|
|
99
|
+
FOREIGN KEY (workspace_id, source_id)
|
|
100
|
+
REFERENCES automation_sources(workspace_id, id) ON DELETE CASCADE,
|
|
101
|
+
CONSTRAINT pr_review_managed_github_routes_identity_chk CHECK (
|
|
102
|
+
installation_id ~ '^[1-9][0-9]*$'
|
|
103
|
+
AND provider_repository_id ~ '^[1-9][0-9]*$'
|
|
104
|
+
)
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
CREATE UNIQUE INDEX pr_review_managed_github_route_identity_uq
|
|
108
|
+
ON pr_review_managed_github_routes (installation_id, provider_repository_id);
|