@opengeni/db 0.14.3 → 0.17.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-Y5WZZVQK.js → chunk-SK7YYHBI.js} +5 -2
- package/dist/chunk-SK7YYHBI.js.map +1 -0
- package/dist/{chunk-ELMUCYZF.js → chunk-T6RSJT6C.js} +202 -43
- package/dist/chunk-T6RSJT6C.js.map +1 -0
- package/dist/chunk-TLAC622R.js +4990 -0
- package/dist/chunk-TLAC622R.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 +6374 -10
- package/dist/index.js +8075 -2776
- 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 -6489
- 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 +25330 -3
- package/dist/schema.js +31 -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-artifacts.d.ts +62 -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 +1 -1
- 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/drizzle/0149_workspace_artifacts.sql +348 -0
- package/drizzle/0150_slack_task_interactions.sql +344 -0
- package/package.json +6 -6
- package/src/index.ts +5766 -275
- 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 +47 -27
- package/src/schema.ts +875 -19
- package/src/session-queue-commands.ts +39 -6
- package/src/workspace-artifacts.ts +751 -0
- package/dist/chunk-DW24CKCT.js +0 -4046
- package/dist/chunk-DW24CKCT.js.map +0 -1
- package/dist/chunk-ELMUCYZF.js.map +0 -1
- package/dist/chunk-Y5WZZVQK.js.map +0 -1
- package/dist/schema-DhkRhcuQ.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,10 +84,18 @@ 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",
|
|
89
|
+
"slack_bot_user_links",
|
|
90
|
+
"slack_interaction_inbox",
|
|
91
|
+
"slack_interaction_progress_deliveries",
|
|
92
|
+
"slack_interactions",
|
|
77
93
|
"social_connections",
|
|
78
94
|
"social_posts",
|
|
79
95
|
"usage_events",
|
|
96
|
+
"workspace_artifact_events",
|
|
97
|
+
"workspace_artifact_versions",
|
|
98
|
+
"workspace_artifacts",
|
|
80
99
|
"workspace_captures",
|
|
81
100
|
"workspace_control_events",
|
|
82
101
|
"workspace_inference_controls",
|
|
@@ -150,11 +169,13 @@ export const RUNTIME_FULL_DML_TABLES = [
|
|
|
150
169
|
"machine_metrics_latest",
|
|
151
170
|
"machine_metrics_series",
|
|
152
171
|
"managed_accounts",
|
|
172
|
+
"model_call_facts",
|
|
153
173
|
"new_session_drafts",
|
|
154
174
|
"pack_installations",
|
|
155
175
|
"rig_changes",
|
|
156
176
|
"rig_versions",
|
|
157
177
|
"rigs",
|
|
178
|
+
"sandbox_checkpoint_artifacts",
|
|
158
179
|
"sandbox_lease_holders",
|
|
159
180
|
"sandbox_leases",
|
|
160
181
|
"sandbox_pty_sessions",
|
|
@@ -182,11 +203,17 @@ export const RUNTIME_FULL_DML_TABLES = [
|
|
|
182
203
|
"session_turns",
|
|
183
204
|
"session_workflow_wake_outbox",
|
|
184
205
|
"sessions",
|
|
206
|
+
"slack_bot_delete_operations",
|
|
185
207
|
"slack_bot_post_operations",
|
|
208
|
+
"slack_bot_user_links",
|
|
209
|
+
"slack_interaction_inbox",
|
|
210
|
+
"slack_interaction_progress_deliveries",
|
|
211
|
+
"slack_interactions",
|
|
186
212
|
"social_connections",
|
|
187
213
|
"social_posts",
|
|
188
214
|
"stripe_webhook_events",
|
|
189
215
|
"usage_events",
|
|
216
|
+
"workspace_artifacts",
|
|
190
217
|
"workspace_captures",
|
|
191
218
|
"workspace_control_events",
|
|
192
219
|
"workspace_inference_controls",
|
|
@@ -200,12 +227,20 @@ export const RUNTIME_FULL_DML_TABLES = [
|
|
|
200
227
|
"workspaces",
|
|
201
228
|
] as const;
|
|
202
229
|
|
|
203
|
-
/** Configuration
|
|
204
|
-
export const RUNTIME_READ_ONLY_TABLES = [
|
|
230
|
+
/** Configuration and lifecycle-owned audit rows are read-only at runtime. */
|
|
231
|
+
export const RUNTIME_READ_ONLY_TABLES = [
|
|
232
|
+
"nested_agent_depth_configuration",
|
|
233
|
+
"preference_registry_events",
|
|
234
|
+
"preference_registry_snapshots",
|
|
235
|
+
] as const;
|
|
205
236
|
|
|
206
237
|
/** Append-only evidence/revision tables are insertable and queryable, never mutable. */
|
|
207
238
|
export const RUNTIME_READ_INSERT_TABLES = [
|
|
239
|
+
"preference_registry_preferences",
|
|
240
|
+
"preference_registry_revisions",
|
|
208
241
|
"session_spawn_denials",
|
|
242
|
+
"workspace_artifact_events",
|
|
243
|
+
"workspace_artifact_versions",
|
|
209
244
|
"workspace_instruction_policy_activation_events",
|
|
210
245
|
"workspace_instruction_policy_revisions",
|
|
211
246
|
] as const;
|
|
@@ -299,6 +334,7 @@ export type RuntimeRoutinePosture = {
|
|
|
299
334
|
|
|
300
335
|
export type RuntimeDatabasePosture = {
|
|
301
336
|
identity: RuntimeDatabaseIdentity;
|
|
337
|
+
/** Privilege-bearing role relationships; exact PG16+ management-only grants are excluded. */
|
|
302
338
|
memberships: string[];
|
|
303
339
|
schemas: RuntimeSchemaPosture[];
|
|
304
340
|
ownedSchemas: string[];
|
|
@@ -418,30 +454,10 @@ export async function inspectRuntimeDatabasePosture(
|
|
|
418
454
|
};
|
|
419
455
|
}
|
|
420
456
|
|
|
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);
|
|
457
|
+
const relationshipRows = resultRows<RoleRelationshipCatalogRow>(
|
|
458
|
+
await tx.execute(sql.raw(roleRelationshipsCatalogQuery("current_user"))),
|
|
459
|
+
);
|
|
460
|
+
const memberships = classifyRoleRelationships(relationshipRows).unsafeRelationships;
|
|
445
461
|
|
|
446
462
|
const schemas = resultRows<{
|
|
447
463
|
name: string;
|
|
@@ -555,7 +571,11 @@ export async function inspectRuntimeDatabasePosture(
|
|
|
555
571
|
and p.prokind in ('f', 'p')
|
|
556
572
|
order by p.proname, pg_get_function_identity_arguments(p.oid)
|
|
557
573
|
`),
|
|
558
|
-
).map((row) => ({
|
|
574
|
+
).map((row) => ({
|
|
575
|
+
name: row.name,
|
|
576
|
+
owner: row.owner,
|
|
577
|
+
execute: row.can_execute,
|
|
578
|
+
}));
|
|
559
579
|
|
|
560
580
|
return {
|
|
561
581
|
identity: mappedIdentity,
|