@rebasepro/server-postgres 0.14.1 → 0.14.2-canary.gca521e9
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/{auth-users-columns-C-FDnL_e.js → auth-users-columns-DLwxDqYb.js} +44 -12
- package/dist/auth-users-columns-DLwxDqYb.js.map +1 -0
- package/dist/{ensure-collection-policies-DoHwhVf8.js → ensure-collection-policies-KzpXpHEL.js} +3 -3
- package/dist/{ensure-collection-policies-DoHwhVf8.js.map → ensure-collection-policies-KzpXpHEL.js.map} +1 -1
- package/dist/{ensure-collection-tables-DT2eq859.js → ensure-collection-tables-Dnb7scJ1.js} +2 -2
- package/dist/{ensure-collection-tables-DT2eq859.js.map → ensure-collection-tables-Dnb7scJ1.js.map} +1 -1
- package/dist/index.es.js +41 -6
- package/dist/index.es.js.map +1 -1
- package/dist/{rls-enforcement-gUNDfm7l.js → rls-enforcement-Kz0NpF8J.js} +2 -2
- package/dist/{rls-enforcement-gUNDfm7l.js.map → rls-enforcement-Kz0NpF8J.js.map} +1 -1
- package/dist/utils/pg-error-utils.d.ts +27 -0
- package/package.json +6 -6
- package/src/services/PersistService.ts +23 -2
- package/src/utils/pg-error-utils.ts +49 -4
- package/dist/auth-users-columns-C-FDnL_e.js.map +0 -1
package/dist/index.es.js
CHANGED
|
@@ -3,10 +3,10 @@ import process from "process";
|
|
|
3
3
|
__createRequire(import.meta.url);
|
|
4
4
|
import { a as guardPoolAgainstDirtyRelease, i as createReadReplicaConnection, n as createDirectDatabaseConnection, o as pinSearchPath, r as createPostgresDatabaseConnection } from "./connection-BuZ97wsr.js";
|
|
5
5
|
import { n as resolveClientListLimit, t as ListLimitError } from "./data_driver-ULAyJEi9.js";
|
|
6
|
-
import { $ as mergeDeep, A as fieldKeyForColumn, B as parseIdValues, C as getJunctionCollectionConfig, D as policyToPostgres, E as getEffectiveSecurityRules, F as getTableVarName, G as updateDateAutoValues, H as createRelationRef, I as resolveCollectionRelations, J as legacyForeignKeyName, K as firstFreeKey, L as buildCompositeId, M as getColumnName, N as getEnumVarName, O as securityRuleToConditions, P as getTableName$1, Q as isPrototypePollutingKey, R as getDeclaredPrimaryKeys, S as resolveStringColumnLength, T as resolveJunctionSpecs, U as createRelationRefWithData, V as sortCollectionsBySlug, W as normalizeToEntityRelation, X as toWireKey, Z as getPolicyNamesForRule, _ as OrderBySpecError, at as isManyToMany, b as CollectionRegistry, et as camelCase, g as buildSdkData, h as visibleColumnProjection, it as hasForeignKeyOnTarget, j as findRelation, l as buildSearchColumnSpec, ot as Vector, q as generateForeignKeyName, r as authUsersColumnSql, s as SEARCH_UNACCENT_FN, t as AUTH_USERS_COLUMNS, tt as toSnakeCase, u as hiddenColumnsOption, v as normalizeDriverOrderBy, w as getJunctionSecurityRules, x as relationalCollections, y as parseOrderBySpecStrict, z as isAddressableId } from "./auth-users-columns-
|
|
6
|
+
import { $ as mergeDeep, A as fieldKeyForColumn, B as parseIdValues, C as getJunctionCollectionConfig, D as policyToPostgres, E as getEffectiveSecurityRules, F as getTableVarName, G as updateDateAutoValues, H as createRelationRef, I as resolveCollectionRelations, J as legacyForeignKeyName, K as firstFreeKey, L as buildCompositeId, M as getColumnName, N as getEnumVarName, O as securityRuleToConditions, P as getTableName$1, Q as isPrototypePollutingKey, R as getDeclaredPrimaryKeys, S as resolveStringColumnLength, T as resolveJunctionSpecs, U as createRelationRefWithData, V as sortCollectionsBySlug, W as normalizeToEntityRelation, X as toWireKey, Z as getPolicyNamesForRule, _ as OrderBySpecError, at as isManyToMany, b as CollectionRegistry, et as camelCase, g as buildSdkData, h as visibleColumnProjection, it as hasForeignKeyOnTarget, j as findRelation, l as buildSearchColumnSpec, ot as Vector, q as generateForeignKeyName, r as authUsersColumnSql, s as SEARCH_UNACCENT_FN, t as AUTH_USERS_COLUMNS, tt as toSnakeCase, u as hiddenColumnsOption, v as normalizeDriverOrderBy, w as getJunctionSecurityRules, x as relationalCollections, y as parseOrderBySpecStrict, z as isAddressableId } from "./auth-users-columns-DLwxDqYb.js";
|
|
7
7
|
import { c as isPostgresCollectionConfig, f as ALL_WHERE_FILTER_OPS, l as isRelationalCollectionConfig } from "./src-DCdn3Val.js";
|
|
8
8
|
import { t as createPostgresWebSocket } from "./websocket-D2jXv0Ds.js";
|
|
9
|
-
import { a as warnOnAnonymousGrants, c as REBASE_USER_ROLE, i as validatePolicyPgRoles, l as revokeInternalTableAccess, n as detectConnectionPosture, o as warnOnLegacyRlsFunctions, r as ensureAppRole, s as warnOnRoleSchemaCollision, t as applyAuthContext, u as revokeInternalTableSql } from "./rls-enforcement-
|
|
9
|
+
import { a as warnOnAnonymousGrants, c as REBASE_USER_ROLE, i as validatePolicyPgRoles, l as revokeInternalTableAccess, n as detectConnectionPosture, o as warnOnLegacyRlsFunctions, r as ensureAppRole, s as warnOnRoleSchemaCollision, t as applyAuthContext, u as revokeInternalTableSql } from "./rls-enforcement-Kz0NpF8J.js";
|
|
10
10
|
import { A as parsePgToolMajor, C as checkToolServerCompatibility, D as parseBackupDestination, E as joinStorageKey, M as serverVersionNumToMajor, N as splitGlobalsStatements, O as parseBackupTimestamp, P as withDatabaseName, S as buildRowSecurityPgOptions, T as globalsFileForDump, _ as buildBackupFilename, a as detectToolMajor, b as buildPgRestoreArgs, c as listBackups, d as resolvePgBinary, f as restoreDump, g as selectBackupsToPrune, h as require_source, i as createDump, j as resolveConnectionString, k as parseDbNameFromUrl, l as preflight, m as validateDump, n as applyGlobals, o as ensureDatabaseExists, p as uploadBackup, s as getServerVersionMajor, t as BackupToolError, u as pruneBackups, v as buildPgDumpArgs, w as diagnoseRowSecurityDumpFailure, x as buildPgRestoreListArgs, y as buildPgDumpallGlobalsArgs } from "./backup-service-BH0Dzo_h.js";
|
|
11
11
|
import { t as RLS_BOOTSTRAP_STATEMENTS } from "./rls-bootstrap-sql-69hYT8nr.js";
|
|
12
12
|
import { Client, Pool } from "pg";
|
|
@@ -3155,6 +3155,37 @@ function isRoleSwitchingPermissionError(error) {
|
|
|
3155
3155
|
return msg.includes("set role") || msg.includes("member of role");
|
|
3156
3156
|
}
|
|
3157
3157
|
/**
|
|
3158
|
+
* Was this `42501` the *caller* being refused by a policy, rather than the
|
|
3159
|
+
* server lacking a privilege?
|
|
3160
|
+
*
|
|
3161
|
+
* Both arrive as `insufficient_privilege`, and they are opposite kinds of
|
|
3162
|
+
* problem. A row-level-security refusal is a working access-control system
|
|
3163
|
+
* doing its job: the caller asked for something their policies do not permit,
|
|
3164
|
+
* which is a 403 and nobody's bug. A missing `GRANT` is the deployment being
|
|
3165
|
+
* wrong — the connection role cannot touch the table at all, no policy is
|
|
3166
|
+
* involved, and nothing the caller changes about the request will help.
|
|
3167
|
+
*
|
|
3168
|
+
* Postgres distinguishes them in the message, so this does too:
|
|
3169
|
+
*
|
|
3170
|
+
* new row violates row-level security policy for table "notes" → the caller
|
|
3171
|
+
* permission denied for table notes → the server
|
|
3172
|
+
*
|
|
3173
|
+
* Only writes reach this. A read that RLS excludes is not an error — the rows
|
|
3174
|
+
* are filtered and the caller gets an empty page — so the erroring case is
|
|
3175
|
+
* specifically an `INSERT`/`UPDATE` whose row fails a policy's `WITH CHECK`.
|
|
3176
|
+
*
|
|
3177
|
+
* Matched on the message because that is the only thing carrying the
|
|
3178
|
+
* distinction; the SQLSTATE is identical either way. Narrow by design: anything
|
|
3179
|
+
* not naming row-level security stays the server's problem, since reporting a
|
|
3180
|
+
* genuine privilege misconfiguration as "forbidden" would send an operator
|
|
3181
|
+
* hunting for a policy bug that does not exist.
|
|
3182
|
+
*/
|
|
3183
|
+
function isRowLevelSecurityDenial(error) {
|
|
3184
|
+
const pgError = extractPgError(error);
|
|
3185
|
+
if (!pgError || pgError.code !== "42501") return false;
|
|
3186
|
+
return pgError.message.toLowerCase().includes("row-level security policy");
|
|
3187
|
+
}
|
|
3188
|
+
/**
|
|
3158
3189
|
* Translate a raw PostgreSQL error into a user-friendly message.
|
|
3159
3190
|
*
|
|
3160
3191
|
* @param pgError - The extracted PostgreSQL error (from {@link extractPgError})
|
|
@@ -3209,8 +3240,11 @@ function pgErrorToFriendlyMessage(pgError, context) {
|
|
|
3209
3240
|
message: `Table not found for "${context}": ${pgMessage}. Check if your schema is up to date (run migrations).${suffix}`,
|
|
3210
3241
|
code
|
|
3211
3242
|
};
|
|
3212
|
-
case "42501": return {
|
|
3213
|
-
message: `
|
|
3243
|
+
case "42501": return pgMessage.toLowerCase().includes("row-level security policy") ? {
|
|
3244
|
+
message: `Not permitted to write this row in "${tableRef}": it does not satisfy the row-level security policy.${suffix}`,
|
|
3245
|
+
code
|
|
3246
|
+
} : {
|
|
3247
|
+
message: `Permission denied on "${tableRef}": the database role this server connects as lacks privileges on it.${suffix}`,
|
|
3214
3248
|
code
|
|
3215
3249
|
};
|
|
3216
3250
|
case "28000": return {
|
|
@@ -4766,6 +4800,7 @@ var PersistService = class {
|
|
|
4766
4800
|
if (pgError) {
|
|
4767
4801
|
const { message, code } = pgErrorToFriendlyMessage(pgError, collectionSlug);
|
|
4768
4802
|
if (/^2[23]/.test(code)) return code === "23505" ? ApiError.conflict(message, `PG_${code}`) : ApiError.badRequest(message, `PG_${code}`);
|
|
4803
|
+
if (isRowLevelSecurityDenial(error)) return ApiError.forbidden(message, "WRITE_DENIED");
|
|
4769
4804
|
return new Error(message);
|
|
4770
4805
|
}
|
|
4771
4806
|
const causeMessage = extractCauseMessage(error);
|
|
@@ -13512,7 +13547,7 @@ function createPostgresBootstrapper(pgConfig) {
|
|
|
13512
13547
|
* proved it can bootstrap with.
|
|
13513
13548
|
*/
|
|
13514
13549
|
async ensureCollectionSchema(collections, driverResult, log) {
|
|
13515
|
-
const { ensureCollectionTables } = await import("./ensure-collection-tables-
|
|
13550
|
+
const { ensureCollectionTables } = await import("./ensure-collection-tables-Dnb7scJ1.js");
|
|
13516
13551
|
const plan = await ensureCollectionTables(provisioningQueryable(driverResult), collections, log);
|
|
13517
13552
|
for (const failure of plan.failures) logger.warn(failure.kind === "comment-column" ? `🔍 [schema] Could not record the search fingerprint on "${failure.target}" — search works, but a later change to the \`search\` block will not be detected: ${failure.error}` : `🔗 [schema] Could not add foreign key "${failure.target}" — the column exists and the collection still serves, but rows are not policed by this constraint: ${failure.error}`);
|
|
13518
13553
|
return { applied: plan.actions.length - plan.failures.length };
|
|
@@ -13533,7 +13568,7 @@ function createPostgresBootstrapper(pgConfig) {
|
|
|
13533
13568
|
* stays RLS-enabled, so it denies rather than leaks.
|
|
13534
13569
|
*/
|
|
13535
13570
|
async ensureCollectionPolicies(collections, driverResult, log) {
|
|
13536
|
-
const { ensureCollectionPolicies } = await import("./ensure-collection-policies-
|
|
13571
|
+
const { ensureCollectionPolicies } = await import("./ensure-collection-policies-KzpXpHEL.js");
|
|
13537
13572
|
const queryable = provisioningQueryable(driverResult);
|
|
13538
13573
|
const outcome = await ensureCollectionPolicies(queryable, collections, log);
|
|
13539
13574
|
for (const skip of outcome.skipped) logger.warn(`🔐 [rls] Policies not applied to "${skip.table}": ${skip.reason}`);
|