@opengeni/db 0.14.0 → 0.16.2
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-ELMUCYZF.js → chunk-4RUK5CON.js} +183 -42
- package/dist/chunk-4RUK5CON.js.map +1 -0
- package/dist/chunk-HZD7KVAR.js +4648 -0
- package/dist/chunk-HZD7KVAR.js.map +1 -0
- package/dist/{chunk-Y5WZZVQK.js → chunk-SK7YYHBI.js} +5 -2
- package/dist/chunk-SK7YYHBI.js.map +1 -0
- package/dist/codex-token-resolver.d.ts +64 -0
- package/dist/connection-token-resolver.d.ts +90 -0
- package/dist/environment-crypto.d.ts +11 -0
- package/dist/event-payload-sanitizer.d.ts +32 -0
- package/dist/index.d.ts +6217 -10
- package/dist/index.js +6992 -2728
- package/dist/index.js.map +1 -1
- package/dist/insights.d.ts +157 -0
- package/dist/memory-domain.d.ts +44 -0
- package/dist/migrate.d.ts +5 -7
- package/dist/migrate.js +1 -1
- package/dist/new-session-drafts.d.ts +49 -0
- package/dist/persistence-errors.d.ts +69 -0
- package/dist/preference-registry-schema.d.ts +1147 -0
- package/dist/preference-registry.d.ts +878 -0
- package/dist/provision-roles.d.ts +4 -6478
- package/dist/provision-roles.js +1 -1
- package/dist/role-relationships.d.ts +35 -0
- package/dist/runtime-posture-cli.d.ts +1 -0
- package/dist/runtime-posture.d.ts +103 -0
- package/dist/schema.d.ts +23533 -3
- package/dist/schema.js +17 -1
- package/dist/session-control.d.ts +331 -0
- package/dist/session-queue-commands.d.ts +186 -0
- package/dist/session-tool-call-settlement.d.ts +32 -0
- package/dist/turn-initiator.d.ts +28 -0
- package/dist/workspace-instruction-policies-schema.d.ts +735 -0
- package/dist/workspace-instruction-policies.d.ts +64 -0
- package/drizzle/0136_unified_session_tool_policy.sql +109 -0
- package/drizzle/0137_preference_registry.sql +1347 -0
- package/drizzle/0138_sandbox_checkpoint_artifacts_and_deadlines.sql +1074 -0
- package/drizzle/0139_codex_provider_artifact_invalidations.sql +51 -0
- package/drizzle/0140_sandbox_restore_and_reaper_fences.sql +276 -0
- package/drizzle/0142_sandbox_archive_capture_gate.sql +80 -0
- package/drizzle/0143_session_codex_compaction_mode.sql +20 -0
- package/drizzle/0144_sandbox_viewer_force_drain_gate.sql +95 -0
- package/drizzle/0145_model_call_facts.sql +96 -0
- package/drizzle/0146_slack_bot_delete_idempotency.sql +105 -0
- package/drizzle/0147_draft_latency_mode.sql +12 -0
- package/drizzle/0148_session_turn_latency_mode.sql +12 -0
- package/package.json +6 -6
- package/src/index.ts +5095 -430
- package/src/insights.ts +837 -0
- package/src/migrate.ts +9 -1
- package/src/new-session-drafts.ts +4 -0
- package/src/preference-registry-schema.ts +170 -0
- package/src/preference-registry.ts +1220 -0
- package/src/provision-roles.ts +95 -22
- package/src/role-relationships.ts +132 -0
- package/src/runtime-posture.ts +28 -26
- package/src/schema.ts +484 -12
- package/src/session-queue-commands.ts +47 -46
- package/dist/chunk-ELMUCYZF.js.map +0 -1
- package/dist/chunk-PQKVUWQW.js +0 -4047
- package/dist/chunk-PQKVUWQW.js.map +0 -1
- package/dist/chunk-Y5WZZVQK.js.map +0 -1
- package/dist/schema-FoPub9yt.d.ts +0 -22666
package/src/provision-roles.ts
CHANGED
|
@@ -5,6 +5,11 @@ import {
|
|
|
5
5
|
RUNTIME_READ_INSERT_TABLES,
|
|
6
6
|
RUNTIME_READ_ONLY_TABLES,
|
|
7
7
|
} from "./runtime-posture";
|
|
8
|
+
import {
|
|
9
|
+
classifyRoleRelationships,
|
|
10
|
+
roleRelationshipsCatalogQuery,
|
|
11
|
+
type RoleRelationshipCatalogRow,
|
|
12
|
+
} from "./role-relationships";
|
|
8
13
|
|
|
9
14
|
export type ProvisionResult = {
|
|
10
15
|
appRole: string | null;
|
|
@@ -106,10 +111,12 @@ export async function provisionRoles(
|
|
|
106
111
|
"OPENGENI_APP_DATABASE_PASSWORD (or appPassword) is required for rlsStrategy 'force'",
|
|
107
112
|
);
|
|
108
113
|
}
|
|
109
|
-
// Ownership and role-graph edges cannot be safely
|
|
110
|
-
// mutate an existing role until an operator has
|
|
111
|
-
// objects/removed memberships; role
|
|
112
|
-
//
|
|
114
|
+
// Ownership and privilege-bearing role-graph edges cannot be safely
|
|
115
|
+
// guessed away. Refuse to mutate an existing role until an operator has
|
|
116
|
+
// explicitly transferred objects/removed those memberships; role
|
|
117
|
+
// attributes and direct grants, however, are deterministic and are
|
|
118
|
+
// converged below on every run. PostgreSQL 16+'s exact non-runtime-bearing
|
|
119
|
+
// creator-management edge is classified separately.
|
|
113
120
|
await assertAppRoleSafeToNormalize(sql, appRole);
|
|
114
121
|
await ensureRestrictedAppLoginRole(sql, appRole, appPassword);
|
|
115
122
|
provisionedAppRole = appRole;
|
|
@@ -190,12 +197,23 @@ BEGIN
|
|
|
190
197
|
${literal(role)},
|
|
191
198
|
${literal(password)}
|
|
192
199
|
);
|
|
193
|
-
|
|
200
|
+
ELSIF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = current_user AND rolsuper) THEN
|
|
194
201
|
EXECUTE format(
|
|
195
202
|
'ALTER ROLE %I WITH LOGIN NOSUPERUSER NOBYPASSRLS NOCREATEROLE NOCREATEDB NOREPLICATION NOINHERIT PASSWORD %L',
|
|
196
203
|
${literal(role)},
|
|
197
204
|
${literal(password)}
|
|
198
205
|
);
|
|
206
|
+
ELSE
|
|
207
|
+
-- PostgreSQL requires elevated attributes merely to name SUPERUSER,
|
|
208
|
+
-- BYPASSRLS, REPLICATION, or CREATEDB in ALTER ROLE, even when setting them
|
|
209
|
+
-- false. The preflight has already proved those protected attributes are
|
|
210
|
+
-- false, so a managed CREATEROLE administrator converges only the
|
|
211
|
+
-- attributes it may change.
|
|
212
|
+
EXECUTE format(
|
|
213
|
+
'ALTER ROLE %I WITH LOGIN NOCREATEROLE NOINHERIT PASSWORD %L',
|
|
214
|
+
${literal(role)},
|
|
215
|
+
${literal(password)}
|
|
216
|
+
);
|
|
199
217
|
END IF;
|
|
200
218
|
END $$;
|
|
201
219
|
`);
|
|
@@ -214,25 +232,47 @@ async function assertAppRoleSafeToNormalize(sql: postgres.Sql, role: string): Pr
|
|
|
214
232
|
return;
|
|
215
233
|
}
|
|
216
234
|
|
|
217
|
-
const
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
235
|
+
const [roleAttributes] = await sql<
|
|
236
|
+
{
|
|
237
|
+
administrator_superuser: boolean;
|
|
238
|
+
app_superuser: boolean;
|
|
239
|
+
app_bypass_rls: boolean;
|
|
240
|
+
app_create_database: boolean;
|
|
241
|
+
app_replication: boolean;
|
|
242
|
+
}[]
|
|
243
|
+
>`
|
|
244
|
+
select
|
|
245
|
+
administrator.rolsuper as administrator_superuser,
|
|
246
|
+
app.rolsuper as app_superuser,
|
|
247
|
+
app.rolbypassrls as app_bypass_rls,
|
|
248
|
+
app.rolcreatedb as app_create_database,
|
|
249
|
+
app.rolreplication as app_replication
|
|
250
|
+
from pg_roles app
|
|
251
|
+
join pg_roles administrator on administrator.rolname = current_user
|
|
252
|
+
where app.rolname = ${role}
|
|
230
253
|
`;
|
|
231
|
-
if (
|
|
254
|
+
if (roleAttributes && !roleAttributes.administrator_superuser) {
|
|
255
|
+
const protectedAttributes = [
|
|
256
|
+
roleAttributes.app_superuser ? "SUPERUSER" : null,
|
|
257
|
+
roleAttributes.app_bypass_rls ? "BYPASSRLS" : null,
|
|
258
|
+
roleAttributes.app_create_database ? "CREATEDB" : null,
|
|
259
|
+
roleAttributes.app_replication ? "REPLICATION" : null,
|
|
260
|
+
].filter((attribute): attribute is string => attribute !== null);
|
|
261
|
+
if (protectedAttributes.length > 0) {
|
|
262
|
+
throw new Error(
|
|
263
|
+
`Refusing to normalize app role ${role}: a non-superuser administrator cannot clear protected attributes (${protectedAttributes.join(", ")})`,
|
|
264
|
+
);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
const relationshipRows = await sql.unsafe<RoleRelationshipCatalogRow[]>(
|
|
269
|
+
roleRelationshipsCatalogQuery("$1"),
|
|
270
|
+
[role],
|
|
271
|
+
);
|
|
272
|
+
const { unsafeRelationships } = classifyRoleRelationships(relationshipRows);
|
|
273
|
+
if (unsafeRelationships.length > 0) {
|
|
232
274
|
throw new Error(
|
|
233
|
-
`Refusing to normalize app role ${role}: remove role relationships first (${
|
|
234
|
-
.map((row) => row.relationship)
|
|
235
|
-
.join(", ")})`,
|
|
275
|
+
`Refusing to normalize app role ${role}: remove privilege-bearing role relationships first (${unsafeRelationships.join(", ")})`,
|
|
236
276
|
);
|
|
237
277
|
}
|
|
238
278
|
|
|
@@ -372,6 +412,39 @@ BEGIN
|
|
|
372
412
|
${literal(role)}
|
|
373
413
|
);
|
|
374
414
|
END IF;
|
|
415
|
+
IF to_regprocedure(
|
|
416
|
+
format(
|
|
417
|
+
'%I.preference_registry_apply_lifecycle(text,uuid,integer,uuid,uuid,text,uuid,text,text)',
|
|
418
|
+
${literal(schema)}
|
|
419
|
+
)
|
|
420
|
+
) IS NOT NULL THEN
|
|
421
|
+
EXECUTE format(
|
|
422
|
+
'GRANT EXECUTE ON FUNCTION %I.preference_registry_apply_lifecycle(text, uuid, integer, uuid, uuid, text, uuid, text, text) TO %I',
|
|
423
|
+
${literal(schema)},
|
|
424
|
+
${literal(role)}
|
|
425
|
+
);
|
|
426
|
+
END IF;
|
|
427
|
+
IF to_regprocedure(
|
|
428
|
+
format('%I.preference_registry_lock_heads(uuid[])', ${literal(schema)})
|
|
429
|
+
) IS NOT NULL THEN
|
|
430
|
+
EXECUTE format(
|
|
431
|
+
'GRANT EXECUTE ON FUNCTION %I.preference_registry_lock_heads(uuid[]) TO %I',
|
|
432
|
+
${literal(schema)},
|
|
433
|
+
${literal(role)}
|
|
434
|
+
);
|
|
435
|
+
END IF;
|
|
436
|
+
IF to_regprocedure(
|
|
437
|
+
format(
|
|
438
|
+
'%I.preference_registry_get_or_create_snapshot(uuid,uuid,uuid,uuid,uuid,integer)',
|
|
439
|
+
${literal(schema)}
|
|
440
|
+
)
|
|
441
|
+
) IS NOT NULL THEN
|
|
442
|
+
EXECUTE format(
|
|
443
|
+
'GRANT EXECUTE ON FUNCTION %I.preference_registry_get_or_create_snapshot(uuid, uuid, uuid, uuid, uuid, integer) TO %I',
|
|
444
|
+
${literal(schema)},
|
|
445
|
+
${literal(role)}
|
|
446
|
+
);
|
|
447
|
+
END IF;
|
|
375
448
|
EXECUTE format('GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA %I TO %I', ${literal(schema)}, ${literal(role)});
|
|
376
449
|
EXECUTE format(
|
|
377
450
|
'ALTER DEFAULT PRIVILEGES FOR ROLE %I IN SCHEMA %I REVOKE ALL PRIVILEGES ON TABLES FROM %I',
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
export type RoleRelationshipDirection = "inherits" | "member";
|
|
2
|
+
|
|
3
|
+
export type RoleRelationshipCatalogRow = {
|
|
4
|
+
relationship: string;
|
|
5
|
+
direction: RoleRelationshipDirection;
|
|
6
|
+
server_version_num: number;
|
|
7
|
+
admin_option: boolean | null;
|
|
8
|
+
inherit_option: boolean | null;
|
|
9
|
+
set_option: boolean | null;
|
|
10
|
+
member_is_superuser: boolean | null;
|
|
11
|
+
member_can_create_role: boolean | null;
|
|
12
|
+
grantor_role: string | null;
|
|
13
|
+
grantor_is_superuser: boolean | null;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export type ClassifiedRoleRelationships = {
|
|
17
|
+
relationships: string[];
|
|
18
|
+
managementOnlyRelationships: string[];
|
|
19
|
+
unsafeRelationships: string[];
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
type RoleTargetExpression = "current_user" | "$1";
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* One PostgreSQL 15-compatible catalog query for both provisioning and runtime
|
|
26
|
+
* posture. PostgreSQL 16 added per-membership INHERIT and SET columns; reading
|
|
27
|
+
* the catalog row through to_jsonb keeps this statement parseable on 15 while
|
|
28
|
+
* leaving the missing options null and therefore fail-closed.
|
|
29
|
+
*/
|
|
30
|
+
export function roleRelationshipsCatalogQuery(targetRole: RoleTargetExpression): string {
|
|
31
|
+
return `
|
|
32
|
+
with recursive target_role(oid, rolname) as (
|
|
33
|
+
select oid, rolname
|
|
34
|
+
from pg_roles
|
|
35
|
+
where rolname = ${targetRole}
|
|
36
|
+
), inherited_roles(oid, rolname) as (
|
|
37
|
+
select parent.oid, parent.rolname
|
|
38
|
+
from pg_auth_members membership
|
|
39
|
+
join target_role target on target.oid = membership.member
|
|
40
|
+
join pg_roles parent on parent.oid = membership.roleid
|
|
41
|
+
union
|
|
42
|
+
select parent.oid, parent.rolname
|
|
43
|
+
from inherited_roles inherited
|
|
44
|
+
join pg_auth_members membership on membership.member = inherited.oid
|
|
45
|
+
join pg_roles parent on parent.oid = membership.roleid
|
|
46
|
+
), relationships as (
|
|
47
|
+
select
|
|
48
|
+
('inherits:' || inherited.rolname)::text as relationship,
|
|
49
|
+
'inherits'::text as direction,
|
|
50
|
+
null::boolean as admin_option,
|
|
51
|
+
null::boolean as inherit_option,
|
|
52
|
+
null::boolean as set_option,
|
|
53
|
+
null::boolean as member_is_superuser,
|
|
54
|
+
null::boolean as member_can_create_role,
|
|
55
|
+
null::text as grantor_role,
|
|
56
|
+
null::boolean as grantor_is_superuser
|
|
57
|
+
from inherited_roles inherited
|
|
58
|
+
union all
|
|
59
|
+
select
|
|
60
|
+
('member:' || member.rolname)::text as relationship,
|
|
61
|
+
'member'::text as direction,
|
|
62
|
+
membership.admin_option,
|
|
63
|
+
case
|
|
64
|
+
when current_setting('server_version_num')::integer >= 160000
|
|
65
|
+
then (to_jsonb(membership) ->> 'inherit_option')::boolean
|
|
66
|
+
else null::boolean
|
|
67
|
+
end as inherit_option,
|
|
68
|
+
case
|
|
69
|
+
when current_setting('server_version_num')::integer >= 160000
|
|
70
|
+
then (to_jsonb(membership) ->> 'set_option')::boolean
|
|
71
|
+
else null::boolean
|
|
72
|
+
end as set_option,
|
|
73
|
+
member.rolsuper as member_is_superuser,
|
|
74
|
+
member.rolcreaterole as member_can_create_role,
|
|
75
|
+
grantor.rolname::text as grantor_role,
|
|
76
|
+
grantor.rolsuper as grantor_is_superuser
|
|
77
|
+
from pg_auth_members membership
|
|
78
|
+
join target_role target on target.oid = membership.roleid
|
|
79
|
+
join pg_roles member on member.oid = membership.member
|
|
80
|
+
left join pg_roles grantor on grantor.oid = membership.grantor
|
|
81
|
+
)
|
|
82
|
+
select
|
|
83
|
+
relationship,
|
|
84
|
+
direction,
|
|
85
|
+
current_setting('server_version_num')::integer as server_version_num,
|
|
86
|
+
admin_option,
|
|
87
|
+
inherit_option,
|
|
88
|
+
set_option,
|
|
89
|
+
member_is_superuser,
|
|
90
|
+
member_can_create_role,
|
|
91
|
+
grantor_role,
|
|
92
|
+
grantor_is_superuser
|
|
93
|
+
from relationships
|
|
94
|
+
order by relationship, direction, grantor_role nulls first
|
|
95
|
+
`;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* PostgreSQL 16+ automatically gives a non-superuser CREATEROLE principal an
|
|
100
|
+
* ADMIN-only grant on a role it creates. The exact edge below permits role
|
|
101
|
+
* management but cannot inherit the app role's privileges or SET ROLE into it.
|
|
102
|
+
*/
|
|
103
|
+
export function isManagementOnlyRoleRelationship(row: RoleRelationshipCatalogRow): boolean {
|
|
104
|
+
return (
|
|
105
|
+
row.direction === "member" &&
|
|
106
|
+
row.server_version_num >= 160000 &&
|
|
107
|
+
row.admin_option === true &&
|
|
108
|
+
row.inherit_option === false &&
|
|
109
|
+
row.set_option === false &&
|
|
110
|
+
row.member_is_superuser === false &&
|
|
111
|
+
row.member_can_create_role === true &&
|
|
112
|
+
row.grantor_is_superuser === true
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function sortedUnique(values: Iterable<string>): string[] {
|
|
117
|
+
return [...new Set(values)].sort((a, b) => a.localeCompare(b));
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/** Classify exact management-only reverse grants while rejecting every other edge. */
|
|
121
|
+
export function classifyRoleRelationships(
|
|
122
|
+
rows: readonly RoleRelationshipCatalogRow[],
|
|
123
|
+
): ClassifiedRoleRelationships {
|
|
124
|
+
const managementOnlyRows = rows.filter(isManagementOnlyRoleRelationship);
|
|
125
|
+
const unsafeRows = rows.filter((row) => !isManagementOnlyRoleRelationship(row));
|
|
126
|
+
|
|
127
|
+
return {
|
|
128
|
+
relationships: sortedUnique(rows.map((row) => row.relationship)),
|
|
129
|
+
managementOnlyRelationships: sortedUnique(managementOnlyRows.map((row) => row.relationship)),
|
|
130
|
+
unsafeRelationships: sortedUnique(unsafeRows.map((row) => row.relationship)),
|
|
131
|
+
};
|
|
132
|
+
}
|
package/src/runtime-posture.ts
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { sql } from "drizzle-orm";
|
|
2
2
|
import type { Database, RlsStrategy } from "./index";
|
|
3
|
+
import {
|
|
4
|
+
classifyRoleRelationships,
|
|
5
|
+
roleRelationshipsCatalogQuery,
|
|
6
|
+
type RoleRelationshipCatalogRow,
|
|
7
|
+
} from "./role-relationships";
|
|
3
8
|
|
|
4
9
|
/**
|
|
5
10
|
* The complete standalone tenant-table contract. Adding or removing a
|
|
@@ -40,11 +45,17 @@ export const FORCE_RLS_TABLES = [
|
|
|
40
45
|
"knowledge_memories",
|
|
41
46
|
"machine_metrics_latest",
|
|
42
47
|
"machine_metrics_series",
|
|
48
|
+
"model_call_facts",
|
|
43
49
|
"new_session_drafts",
|
|
44
50
|
"pack_installations",
|
|
51
|
+
"preference_registry_events",
|
|
52
|
+
"preference_registry_preferences",
|
|
53
|
+
"preference_registry_revisions",
|
|
54
|
+
"preference_registry_snapshots",
|
|
45
55
|
"rig_changes",
|
|
46
56
|
"rig_versions",
|
|
47
57
|
"rigs",
|
|
58
|
+
"sandbox_checkpoint_artifacts",
|
|
48
59
|
"sandbox_lease_holders",
|
|
49
60
|
"sandbox_leases",
|
|
50
61
|
"sandbox_pty_sessions",
|
|
@@ -73,6 +84,7 @@ export const FORCE_RLS_TABLES = [
|
|
|
73
84
|
"session_turns",
|
|
74
85
|
"session_workflow_wake_outbox",
|
|
75
86
|
"sessions",
|
|
87
|
+
"slack_bot_delete_operations",
|
|
76
88
|
"slack_bot_post_operations",
|
|
77
89
|
"social_connections",
|
|
78
90
|
"social_posts",
|
|
@@ -150,11 +162,13 @@ export const RUNTIME_FULL_DML_TABLES = [
|
|
|
150
162
|
"machine_metrics_latest",
|
|
151
163
|
"machine_metrics_series",
|
|
152
164
|
"managed_accounts",
|
|
165
|
+
"model_call_facts",
|
|
153
166
|
"new_session_drafts",
|
|
154
167
|
"pack_installations",
|
|
155
168
|
"rig_changes",
|
|
156
169
|
"rig_versions",
|
|
157
170
|
"rigs",
|
|
171
|
+
"sandbox_checkpoint_artifacts",
|
|
158
172
|
"sandbox_lease_holders",
|
|
159
173
|
"sandbox_leases",
|
|
160
174
|
"sandbox_pty_sessions",
|
|
@@ -182,6 +196,7 @@ export const RUNTIME_FULL_DML_TABLES = [
|
|
|
182
196
|
"session_turns",
|
|
183
197
|
"session_workflow_wake_outbox",
|
|
184
198
|
"sessions",
|
|
199
|
+
"slack_bot_delete_operations",
|
|
185
200
|
"slack_bot_post_operations",
|
|
186
201
|
"social_connections",
|
|
187
202
|
"social_posts",
|
|
@@ -200,11 +215,17 @@ export const RUNTIME_FULL_DML_TABLES = [
|
|
|
200
215
|
"workspaces",
|
|
201
216
|
] as const;
|
|
202
217
|
|
|
203
|
-
/** Configuration
|
|
204
|
-
export const RUNTIME_READ_ONLY_TABLES = [
|
|
218
|
+
/** Configuration and lifecycle-owned audit rows are read-only at runtime. */
|
|
219
|
+
export const RUNTIME_READ_ONLY_TABLES = [
|
|
220
|
+
"nested_agent_depth_configuration",
|
|
221
|
+
"preference_registry_events",
|
|
222
|
+
"preference_registry_snapshots",
|
|
223
|
+
] as const;
|
|
205
224
|
|
|
206
225
|
/** Append-only evidence/revision tables are insertable and queryable, never mutable. */
|
|
207
226
|
export const RUNTIME_READ_INSERT_TABLES = [
|
|
227
|
+
"preference_registry_preferences",
|
|
228
|
+
"preference_registry_revisions",
|
|
208
229
|
"session_spawn_denials",
|
|
209
230
|
"workspace_instruction_policy_activation_events",
|
|
210
231
|
"workspace_instruction_policy_revisions",
|
|
@@ -299,6 +320,7 @@ export type RuntimeRoutinePosture = {
|
|
|
299
320
|
|
|
300
321
|
export type RuntimeDatabasePosture = {
|
|
301
322
|
identity: RuntimeDatabaseIdentity;
|
|
323
|
+
/** Privilege-bearing role relationships; exact PG16+ management-only grants are excluded. */
|
|
302
324
|
memberships: string[];
|
|
303
325
|
schemas: RuntimeSchemaPosture[];
|
|
304
326
|
ownedSchemas: string[];
|
|
@@ -418,30 +440,10 @@ export async function inspectRuntimeDatabasePosture(
|
|
|
418
440
|
};
|
|
419
441
|
}
|
|
420
442
|
|
|
421
|
-
const
|
|
422
|
-
await tx.execute(sql
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
from pg_auth_members membership
|
|
426
|
-
join pg_roles member on member.oid = membership.member
|
|
427
|
-
join pg_roles parent on parent.oid = membership.roleid
|
|
428
|
-
where member.rolname = current_user
|
|
429
|
-
union
|
|
430
|
-
select parent.oid, parent.rolname
|
|
431
|
-
from inherited_roles inherited
|
|
432
|
-
join pg_auth_members membership on membership.member = inherited.oid
|
|
433
|
-
join pg_roles parent on parent.oid = membership.roleid
|
|
434
|
-
)
|
|
435
|
-
select ('inherits:' || rolname)::text as relationship from inherited_roles
|
|
436
|
-
union
|
|
437
|
-
select ('member:' || member.rolname)::text as relationship
|
|
438
|
-
from pg_auth_members membership
|
|
439
|
-
join pg_roles parent on parent.oid = membership.roleid
|
|
440
|
-
join pg_roles member on member.oid = membership.member
|
|
441
|
-
where parent.rolname = current_user
|
|
442
|
-
order by relationship
|
|
443
|
-
`),
|
|
444
|
-
).map((row) => row.relationship);
|
|
443
|
+
const relationshipRows = resultRows<RoleRelationshipCatalogRow>(
|
|
444
|
+
await tx.execute(sql.raw(roleRelationshipsCatalogQuery("current_user"))),
|
|
445
|
+
);
|
|
446
|
+
const memberships = classifyRoleRelationships(relationshipRows).unsafeRelationships;
|
|
445
447
|
|
|
446
448
|
const schemas = resultRows<{
|
|
447
449
|
name: string;
|