120 lines
9.4 KiB
TypeScript
120 lines
9.4 KiB
TypeScript
/** Catalog observation only. This is neither a control generation issuer nor a
|
|
* readiness/native capability. The caller owns its bounded SQL facade and must
|
|
* run this assertion at the relevant live authority boundary. No default I/O. */
|
|
export interface BandwidthControlRoleSql {
|
|
query(text: string, values?: unknown[]): Promise<{ rows: Record<string, unknown>[] }>
|
|
}
|
|
export interface BandwidthControlRoleExpected { databaseName: string; runtimeRole: string; ownerRole: string }
|
|
export class BandwidthControlRuntimeRoleRefused extends Error {
|
|
readonly code = "BANDWIDTH_CONTROL_RUNTIME_ROLE_REFUSED"
|
|
constructor() { super("Bandwidth control runtime role refused") }
|
|
}
|
|
const TABLES = ["bandwidth_attempts", "bandwidth_node_occupancy", "bandwidth_attempt_events", "bandwidth_source_identity"] as const
|
|
/** Names are parameters; catalog paths, namespace, relations and privilege
|
|
* vocabulary are fixed. ACL-provided privilege names include newer PostgreSQL
|
|
* privileges without sending unsupported names to an older server. */
|
|
export const BANDWIDTH_CONTROL_ROLE_SQL = `WITH
|
|
runtime AS (SELECT r.* FROM pg_catalog.pg_roles r WHERE r.rolname=$2 AND pg_catalog.current_database()::text=$1::text),
|
|
expected_owner AS (SELECT r.oid FROM pg_catalog.pg_roles r WHERE r.rolname=$3),
|
|
control_schema AS (SELECT n.* FROM pg_catalog.pg_namespace n WHERE n.nspname='mmapp_control'),
|
|
required(name,allowed) AS (VALUES
|
|
('bandwidth_attempts',ARRAY['SELECT','INSERT','UPDATE']::text[]),
|
|
('bandwidth_node_occupancy',ARRAY['SELECT','INSERT','DELETE']::text[]),
|
|
('bandwidth_attempt_events',ARRAY['SELECT','INSERT']::text[]),
|
|
('bandwidth_source_identity',ARRAY['SELECT']::text[])),
|
|
relations AS (
|
|
SELECT e.name,e.allowed,c.oid,c.relowner,c.relacl,c.relkind
|
|
FROM required e LEFT JOIN control_schema n ON true
|
|
LEFT JOIN pg_catalog.pg_class c ON c.relnamespace=n.oid AND c.relname=e.name),
|
|
member_roles AS (
|
|
SELECT r.* FROM pg_catalog.pg_roles r CROSS JOIN runtime rt
|
|
WHERE r.oid=rt.oid OR pg_catalog.pg_has_role(rt.oid,r.oid,'MEMBER')),
|
|
permissions AS (
|
|
SELECT r.name,m.oid AS role_oid,
|
|
COALESCE(r.oid IS NOT NULL AND r.relkind IN ('r','p') AND NOT EXISTS (
|
|
SELECT 1 FROM (
|
|
SELECT pg_catalog.unnest(ARRAY['SELECT','INSERT','UPDATE','DELETE','TRUNCATE','REFERENCES','TRIGGER']::text[]) AS privilege
|
|
UNION SELECT a.privilege_type FROM pg_catalog.aclexplode(COALESCE(r.relacl,pg_catalog.acldefault('r',r.relowner))) a
|
|
) p WHERE pg_catalog.has_table_privilege(m.oid,r.oid,p.privilege) IS DISTINCT FROM (p.privilege=ANY(r.allowed))
|
|
),false) AS exact_table,
|
|
COALESCE(EXISTS (
|
|
SELECT 1 FROM (
|
|
SELECT pg_catalog.unnest(ARRAY['SELECT','INSERT','UPDATE','DELETE','TRUNCATE','REFERENCES','TRIGGER']::text[]) AS privilege
|
|
UNION SELECT a.privilege_type FROM pg_catalog.aclexplode(COALESCE(r.relacl,pg_catalog.acldefault('r',r.relowner))) a
|
|
) p WHERE (pg_catalog.has_table_privilege(m.oid,r.oid,p.privilege) AND NOT p.privilege=ANY(r.allowed))
|
|
OR pg_catalog.has_table_privilege(m.oid,r.oid,p.privilege || ' WITH GRANT OPTION')
|
|
) OR EXISTS (
|
|
SELECT 1 FROM pg_catalog.unnest(ARRAY['SELECT','INSERT','UPDATE','REFERENCES']::text[]) p(privilege)
|
|
WHERE (pg_catalog.has_any_column_privilege(m.oid,r.oid,p.privilege) AND NOT p.privilege=ANY(r.allowed))
|
|
OR pg_catalog.has_any_column_privilege(m.oid,r.oid,p.privilege || ' WITH GRANT OPTION')
|
|
),true) AS forbidden
|
|
FROM relations r CROSS JOIN member_roles m)
|
|
SELECT pg_catalog.jsonb_build_object(
|
|
'databaseName',pg_catalog.current_database(),
|
|
'sessionRole',SESSION_USER::text,'currentRole',CURRENT_USER::text,
|
|
'runtimeRoleExists',EXISTS(SELECT 1 FROM runtime),
|
|
'ownerRoleExists',EXISTS(SELECT 1 FROM expected_owner),
|
|
'runtimeFlagsSafe',COALESCE((SELECT NOT (rolsuper OR rolcreaterole OR rolcreatedb OR rolreplication OR rolbypassrls) FROM runtime),false),
|
|
'ownerMembership',COALESCE((SELECT pg_catalog.pg_has_role(rt.oid,o.oid,'MEMBER') FROM runtime rt CROSS JOIN expected_owner o),true),
|
|
'dangerousMembership',EXISTS (
|
|
SELECT 1 FROM member_roles m WHERE m.rolsuper OR m.rolcreaterole OR m.rolcreatedb OR m.rolreplication OR m.rolbypassrls
|
|
OR m.rolname IN ('pg_read_server_files','pg_write_server_files','pg_execute_server_program','pg_read_all_data','pg_write_all_data','pg_maintain','pg_signal_backend','pg_checkpoint','pg_create_subscription','pg_database_owner','pg_use_reserved_connections')
|
|
OR EXISTS(SELECT 1 FROM control_schema n WHERE n.nspowner=m.oid OR pg_catalog.has_schema_privilege(m.oid,n.oid,'CREATE'))
|
|
OR EXISTS(SELECT 1 FROM relations r WHERE r.relowner=m.oid)
|
|
OR EXISTS(SELECT 1 FROM permissions p WHERE p.role_oid=m.oid AND p.forbidden)),
|
|
'schemaExists',EXISTS(SELECT 1 FROM control_schema),
|
|
'schemaOwner',(SELECT o.rolname::text FROM control_schema n JOIN pg_catalog.pg_roles o ON o.oid=n.nspowner),
|
|
'schemaUsage',COALESCE((SELECT pg_catalog.has_schema_privilege(rt.oid,n.oid,'USAGE') FROM runtime rt CROSS JOIN control_schema n),false),
|
|
'schemaCreate',COALESCE((SELECT pg_catalog.has_schema_privilege(rt.oid,n.oid,'CREATE') FROM runtime rt CROSS JOIN control_schema n),true),
|
|
'publicSchemaUsage',EXISTS(SELECT 1 FROM control_schema n CROSS JOIN LATERAL pg_catalog.aclexplode(COALESCE(n.nspacl,pg_catalog.acldefault('n',n.nspowner))) a WHERE a.grantee=0 AND a.privilege_type='USAGE'),
|
|
'publicSchemaCreate',EXISTS(SELECT 1 FROM control_schema n CROSS JOIN LATERAL pg_catalog.aclexplode(COALESCE(n.nspacl,pg_catalog.acldefault('n',n.nspowner))) a WHERE a.grantee=0 AND a.privilege_type='CREATE'),
|
|
'tables',(SELECT pg_catalog.jsonb_agg(pg_catalog.jsonb_build_object(
|
|
'name',r.name,'exists',r.oid IS NOT NULL AND r.relkind IN ('r','p'),
|
|
'ownerRole',o.rolname::text,'ownedByRuntime',COALESCE(r.relowner=rt.oid,true),
|
|
'privilegesExact',COALESCE(p.exact_table AND NOT p.forbidden,false)) ORDER BY r.name COLLATE "C")
|
|
FROM relations r CROSS JOIN runtime rt LEFT JOIN pg_catalog.pg_roles o ON o.oid=r.relowner
|
|
LEFT JOIN permissions p ON p.name=r.name AND p.role_oid=rt.oid)
|
|
) AS observation`
|
|
|
|
function refuse(): never { throw new BandwidthControlRuntimeRoleRefused() }
|
|
const plain = (value: unknown): value is Record<string, unknown> => !!value && typeof value === "object" && Object.getPrototypeOf(value) === Object.prototype
|
|
const label = (value: unknown): value is string => typeof value === "string" && value.trim() === value && value.length > 0 && Buffer.byteLength(value) <= 63 && !/[\x00-\x1f\x7f]/.test(value)
|
|
const exactKeys = (value: Record<string, unknown>, fields: string[]) => Object.keys(value).sort().join(",") === [...fields].sort().join(",")
|
|
|
|
export function captureBandwidthControlRoleExpected(expected: BandwidthControlRoleExpected): BandwidthControlRoleExpected {
|
|
if (!plain(expected) || !exactKeys(expected, ["databaseName", "runtimeRole", "ownerRole"])) refuse()
|
|
const captured = { databaseName: expected.databaseName, runtimeRole: expected.runtimeRole, ownerRole: expected.ownerRole }
|
|
if (!Object.values(captured).every(label) || captured.runtimeRole === captured.ownerRole) refuse()
|
|
return Object.freeze(captured)
|
|
}
|
|
|
|
export async function assertBandwidthControlRuntimeRole(sql: BandwidthControlRoleSql, expected: BandwidthControlRoleExpected, live: () => void): Promise<void> {
|
|
const captured = captureBandwidthControlRoleExpected(expected)
|
|
live()
|
|
let result: { rows: Record<string, unknown>[] }
|
|
try { result = await sql.query(BANDWIDTH_CONTROL_ROLE_SQL, [captured.databaseName, captured.runtimeRole, captured.ownerRole]) }
|
|
catch { live(); refuse() }
|
|
live()
|
|
validateBandwidthControlRuntimeRoleRows(result?.rows, captured)
|
|
}
|
|
|
|
/** Shared pure decoder for standalone and same-statement identity snapshots. */
|
|
export function validateBandwidthControlRuntimeRoleRows(rows: unknown, expected: BandwidthControlRoleExpected): void {
|
|
const captured = captureBandwidthControlRoleExpected(expected)
|
|
if (!Array.isArray(rows) || rows.length !== 1 || !plain(rows[0]) || !exactKeys(rows[0], ["observation"])) refuse()
|
|
const value = rows[0].observation
|
|
if (!plain(value) || !exactKeys(value, ["databaseName","sessionRole","currentRole","runtimeRoleExists","ownerRoleExists","runtimeFlagsSafe","ownerMembership","dangerousMembership","schemaExists","schemaOwner","schemaUsage","schemaCreate","publicSchemaUsage","publicSchemaCreate","tables"])) refuse()
|
|
if (value.databaseName !== captured.databaseName || value.sessionRole !== captured.runtimeRole || value.currentRole !== captured.runtimeRole
|
|
|| value.runtimeRoleExists !== true || value.ownerRoleExists !== true || value.runtimeFlagsSafe !== true
|
|
|| value.ownerMembership !== false || value.dangerousMembership !== false || value.schemaExists !== true || value.schemaOwner !== captured.ownerRole
|
|
|| value.schemaUsage !== true || value.schemaCreate !== false || value.publicSchemaUsage !== false || value.publicSchemaCreate !== false
|
|
|| !Array.isArray(value.tables) || value.tables.length !== TABLES.length) refuse()
|
|
const seen = new Set<string>()
|
|
for (const row of value.tables as unknown[]) {
|
|
if (!plain(row) || !exactKeys(row, ["name","exists","ownerRole","ownedByRuntime","privilegesExact"])
|
|
|| typeof row.name !== "string" || !TABLES.includes(row.name as typeof TABLES[number]) || seen.has(row.name)
|
|
|| row.exists !== true || row.ownerRole !== captured.ownerRole || row.ownedByRuntime !== false || row.privilegesExact !== true) refuse()
|
|
seen.add(row.name as string)
|
|
}
|
|
}
|