diff --git a/src/lib/PostgresMetaRoles.ts b/src/lib/PostgresMetaRoles.ts index 24fb03d5..f55fb4a9 100644 --- a/src/lib/PostgresMetaRoles.ts +++ b/src/lib/PostgresMetaRoles.ts @@ -1,5 +1,4 @@ import { ident, literal } from 'pg-format' -import { DEFAULT_ROLES } from './constants.js' import { rolesSql } from './sql/index.js' import { PostgresMetaResult, @@ -42,8 +41,16 @@ FROM roles WHERE true` - if (includeDefaultRoles) { - sql += ` AND name NOT IN (${DEFAULT_ROLES.map(literal).join(',')})` + if (!includeDefaultRoles) { + // All default/predefined roles start with pg_: https://www.postgresql.org/docs/15/predefined-roles.html + // The pg_ prefix is also reserved: + // + // ``` + // postgres=# create role pg_mytmp; + // ERROR: role name "pg_mytmp" is reserved + // DETAIL: Role names starting with "pg_" are reserved. + // ``` + sql += ` AND NOT pg_catalog.starts_with(name, 'pg_')` } if (limit) { sql += ` LIMIT ${limit}` diff --git a/src/lib/constants.ts b/src/lib/constants.ts index 8b51c721..6262b3e4 100644 --- a/src/lib/constants.ts +++ b/src/lib/constants.ts @@ -1,14 +1,3 @@ -export const DEFAULT_ROLES = [ - 'pg_execute_server_program', - 'pg_monitor', - 'pg_read_all_settings', - 'pg_read_all_stats', - 'pg_read_server_files', - 'pg_signal_backend', - 'pg_stat_scan_tables', - 'pg_write_server_files', -] - export const DEFAULT_SYSTEM_SCHEMAS = [ 'information_schema', 'pg_catalog', diff --git a/test/lib/roles.ts b/test/lib/roles.ts index 048e70d9..ebacfaf3 100644 --- a/test/lib/roles.ts +++ b/test/lib/roles.ts @@ -3,7 +3,7 @@ import { pgMeta } from './utils' test('list', async () => { const res = await pgMeta.roles.list() - const role: any = res.data?.find(({ name }) => name === 'postgres') + let role = res.data?.find(({ name }) => name === 'postgres') expect(role).toMatchInlineSnapshot( { active_connections: expect.any(Number), id: expect.any(Number) }, @@ -26,6 +26,43 @@ test('list', async () => { } ` ) + + // pg_monitor is a predefined role. `includeDefaultRoles` defaults to false, + // so it shouldn't be included in the result. + role = res.data?.find(({ name }) => name === 'pg_monitor') + + expect(role).toMatchInlineSnapshot(`undefined`) +}) + +test('list w/ default roles', async () => { + const res = await pgMeta.roles.list({ includeDefaultRoles: true }) + + const role = res.data?.find(({ name }) => name === 'pg_monitor') + + expect(role).toMatchInlineSnapshot( + { + active_connections: expect.any(Number), + id: expect.any(Number), + }, + ` + { + "active_connections": Any, + "can_bypass_rls": false, + "can_create_db": false, + "can_create_role": false, + "can_login": false, + "config": null, + "connection_limit": 100, + "id": Any, + "inherit_role": true, + "is_replication_role": false, + "is_superuser": false, + "name": "pg_monitor", + "password": "********", + "valid_until": null, + } + ` + ) }) test('retrieve, create, update, delete', async () => {