@rebasepro/server-postgres 0.15.0 → 0.16.0
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/PostgresBackendDriver.d.ts +1 -1
- package/dist/PostgresBootstrapper.d.ts +0 -11
- package/dist/auth/services.d.ts +2 -2
- package/dist/{auth-users-columns-JJ8ngvy5.js → auth-users-columns-CgyPWQ18.js} +3 -3
- package/dist/auth-users-columns-CgyPWQ18.js.map +1 -0
- package/dist/backup/backup-logic.d.ts +20 -0
- package/dist/backup/backup-service.d.ts +6 -0
- package/dist/backup/retention.d.ts +11 -0
- package/dist/{backup-service-czK-OAuG.js → backup-service-BZoixhVl.js} +56 -11
- package/dist/backup-service-BZoixhVl.js.map +1 -0
- package/dist/collections-schema-version-BMeu3cgv.js +81 -0
- package/dist/collections-schema-version-BMeu3cgv.js.map +1 -0
- package/dist/{ensure-collection-policies-D5PtQLyR.js → ensure-collection-policies-BVFb2olB.js} +4 -3
- package/dist/ensure-collection-policies-BVFb2olB.js.map +1 -0
- package/dist/{ensure-collection-tables-BHUjQ-z4.js → ensure-collection-tables-BY1pHRD_.js} +2 -2
- package/dist/{ensure-collection-tables-BHUjQ-z4.js.map → ensure-collection-tables-BY1pHRD_.js.map} +1 -1
- package/dist/index.es.js +65 -21
- package/dist/index.es.js.map +1 -1
- package/dist/{rls-enforcement-BDBfuTD4.js → rls-enforcement-Ch0T6OwW.js} +7 -7
- package/dist/rls-enforcement-Ch0T6OwW.js.map +1 -0
- package/dist/schema/collections-schema-version.d.ts +32 -0
- package/dist/security/policy-drift.d.ts +2 -2
- package/dist/security/rls-enforcement.d.ts +6 -6
- package/dist/services/realtimeService.d.ts +3 -1
- package/dist/src-BBFsDaeA.js.map +1 -1
- package/dist/websocket-BVgDVO-V.js.map +1 -1
- package/package.json +6 -6
- package/src/PostgresAdapter.ts +14 -0
- package/src/PostgresBackendDriver.ts +3 -3
- package/src/PostgresBootstrapper.ts +82 -12
- package/src/auth/services.ts +2 -2
- package/src/backup/backup-cli.ts +49 -12
- package/src/backup/backup-logic.ts +31 -0
- package/src/backup/backup-service.ts +42 -8
- package/src/backup/pg-tools.ts +12 -1
- package/src/backup/retention.ts +11 -0
- package/src/schema/collections-schema-version.ts +103 -0
- package/src/security/policy-drift.test.ts +25 -6
- package/src/security/policy-drift.ts +14 -6
- package/src/security/rls-enforcement.ts +7 -7
- package/src/services/realtimeService.ts +9 -1
- package/dist/auth-users-columns-JJ8ngvy5.js.map +0 -1
- package/dist/backup-service-czK-OAuG.js.map +0 -1
- package/dist/ensure-collection-policies-D5PtQLyR.js.map +0 -1
- package/dist/rls-enforcement-BDBfuTD4.js.map +0 -1
|
@@ -30,7 +30,7 @@ import { logger } from "@rebasepro/server";
|
|
|
30
30
|
* that driver with `withAuth(SERVICE_IDENTITY)`, so it arrives as user
|
|
31
31
|
* context above — `rebase_user`, `app.uid = 'service'`, policies evaluated —
|
|
32
32
|
* and clears the default policies through their admin arm rather than the
|
|
33
|
-
* `
|
|
33
|
+
* `rebase.uid() IS NULL` one.
|
|
34
34
|
*
|
|
35
35
|
* This module provides the three pieces:
|
|
36
36
|
*
|
|
@@ -40,7 +40,7 @@ import { logger } from "@rebasepro/server";
|
|
|
40
40
|
* SELECT/INSERT/UPDATE/DELETE grants (+ default privileges so future
|
|
41
41
|
* tables stay covered).
|
|
42
42
|
* 3. {@link applyAuthContext} — per-transaction: set the `app.*` GUCs the
|
|
43
|
-
* policies read (`
|
|
43
|
+
* policies read (`rebase.uid()` etc.) and `SET LOCAL ROLE rebase_user` so
|
|
44
44
|
* RLS binds. Transaction-scoped, so it composes with poolers.
|
|
45
45
|
*
|
|
46
46
|
* Provisioning runs from the framework's own bootstrap/migrate (which already
|
|
@@ -271,7 +271,7 @@ export async function ensureAppRole(run: RawSqlRunner, schemas: string[]): Promi
|
|
|
271
271
|
|
|
272
272
|
/**
|
|
273
273
|
* Apply the authenticated context to a transaction: the `app.*` GUCs that RLS
|
|
274
|
-
* policies read via `
|
|
274
|
+
* policies read via `rebase.uid()` / `rebase.roles()` / `rebase.jwt()`, and — when
|
|
275
275
|
* `userRole` is set — `SET LOCAL ROLE` so RLS binds every statement in this
|
|
276
276
|
* transaction (reads *and* writes).
|
|
277
277
|
*
|
|
@@ -283,13 +283,13 @@ export async function ensureAppRole(run: RawSqlRunner, schemas: string[]): Promi
|
|
|
283
283
|
*
|
|
284
284
|
* SECURITY: this function is only ever called on the **user** path (the server
|
|
285
285
|
* context uses the base/owner driver and never calls it). The default policies
|
|
286
|
-
* treat `
|
|
286
|
+
* treat `rebase.uid() IS NULL` as the trusted server context, and `rebase.uid()`
|
|
287
287
|
* is `NULLIF(current_setting('app.uid'), '')` — so an EMPTY user id would
|
|
288
288
|
* be read as NULL and silently escalate a user request to server privileges.
|
|
289
289
|
* Coerce empty/blank ids to `ANONYMOUS_USER_ID` here, at the single chokepoint,
|
|
290
290
|
* rather than trusting every caller (e.g. realtime subscription auth) to do it.
|
|
291
291
|
* That sentinel is exported from `@rebasepro/types` because it leaks into rule
|
|
292
|
-
* semantics: it is why `
|
|
292
|
+
* semantics: it is why `rebase.uid() IS NOT NULL` is true for anonymous requests.
|
|
293
293
|
*/
|
|
294
294
|
export async function applyAuthContext(tx: SqlTx, auth: AuthContext, userRole?: string): Promise<void> {
|
|
295
295
|
const uid = typeof auth.uid === "string" && auth.uid.trim() !== "" ? auth.uid : ANONYMOUS_USER_ID;
|
|
@@ -322,7 +322,7 @@ const FOREIGN_CONVENTION_ROLES: Record<string, string> = {
|
|
|
322
322
|
|
|
323
323
|
/**
|
|
324
324
|
* Warn about rules that read as "signed-in users only" but admit anonymous
|
|
325
|
-
* callers — `
|
|
325
|
+
* callers — `rebase.uid() IS NOT NULL`, or a comparison against another
|
|
326
326
|
* platform's magic user id such as `'anon'`.
|
|
327
327
|
*
|
|
328
328
|
* The sibling of {@link validatePolicyPgRoles}, for the more dangerous spelling
|
|
@@ -486,7 +486,7 @@ export async function validatePolicyPgRoles(
|
|
|
486
486
|
: "no such role exists in this database";
|
|
487
487
|
const platform = FOREIGN_CONVENTION_ROLES[role];
|
|
488
488
|
const hint = platform
|
|
489
|
-
? `"${role}" is a ${platform} convention, not a PostgreSQL role. Application roles belong in \`roles: ["${role === "service_role" ? "admin" : role}"]\`, which is checked inside the policy via
|
|
489
|
+
? `"${role}" is a ${platform} convention, not a PostgreSQL role. Application roles belong in \`roles: ["${role === "service_role" ? "admin" : role}"]\`, which is checked inside the policy via rebase.roles().`
|
|
490
490
|
: `Either grant it (GRANT ${role} TO ${requestRole}) or drop \`pgRoles\` so the policy targets \`public\`.`;
|
|
491
491
|
|
|
492
492
|
problems.push(
|
|
@@ -1782,9 +1782,17 @@ roles: activeAuth.roles },
|
|
|
1782
1782
|
* inert, no schema is created, and broadcast keeps its original
|
|
1783
1783
|
* fire-and-forget path.
|
|
1784
1784
|
*/
|
|
1785
|
-
async configureChannelHistory(
|
|
1785
|
+
async configureChannelHistory(
|
|
1786
|
+
rules: ChannelRetentionRule[] | undefined,
|
|
1787
|
+
options?: { provision?: boolean }
|
|
1788
|
+
): Promise<void> {
|
|
1789
|
+
// The store is built in every process, whether or not this one creates
|
|
1790
|
+
// the tables: retaining a message is what a process does when it
|
|
1791
|
+
// *publishes* to a retained channel, and a function handler publishes as
|
|
1792
|
+
// readily as a websocket client does. Only the DDL is owned.
|
|
1786
1793
|
this.channelHistory = new ChannelHistoryStore(this.db, rules ?? []);
|
|
1787
1794
|
if (!this.channelHistory.enabled) return;
|
|
1795
|
+
if (options?.provision === false) return;
|
|
1788
1796
|
await this.channelHistory.ensureTables();
|
|
1789
1797
|
}
|
|
1790
1798
|
|