@stratum-hq/db-adapters 1.4.0 → 1.5.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/README.md +17 -8
- package/dist/adapters/drizzle.d.ts +3 -2
- package/dist/adapters/drizzle.d.ts.map +1 -1
- package/dist/adapters/drizzle.js +3 -2
- package/dist/adapters/drizzle.js.map +1 -1
- package/dist/adapters/sequelize.d.ts +3 -2
- package/dist/adapters/sequelize.d.ts.map +1 -1
- package/dist/adapters/sequelize.js +3 -2
- package/dist/adapters/sequelize.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -1
- package/dist/index.js.map +1 -1
- package/dist/rls/manager.d.ts +6 -0
- package/dist/rls/manager.d.ts.map +1 -1
- package/dist/rls/manager.js +10 -5
- package/dist/rls/manager.js.map +1 -1
- package/dist/rls/policy-check.d.ts +40 -3
- package/dist/rls/policy-check.d.ts.map +1 -1
- package/dist/rls/policy-check.js +89 -12
- package/dist/rls/policy-check.js.map +1 -1
- package/dist/rls/session.d.ts +5 -0
- package/dist/rls/session.d.ts.map +1 -1
- package/dist/rls/session.js +11 -0
- package/dist/rls/session.js.map +1 -1
- package/dist/schema/manager.js +1 -1
- package/dist/schema/manager.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -42,6 +42,8 @@ const tenantPrisma = prismaWithTenant(prisma, () => getTenantContext().tenant_id
|
|
|
42
42
|
const orders = await tenantPrisma.order.findMany();
|
|
43
43
|
```
|
|
44
44
|
|
|
45
|
+
The Sequelize wrapper scopes its `query()` method only. Model methods such as `Order.findAll()` do not go through it and run without a tenant.
|
|
46
|
+
|
|
45
47
|
## RLS & Migration Helpers
|
|
46
48
|
|
|
47
49
|
```typescript
|
|
@@ -64,7 +66,9 @@ try {
|
|
|
64
66
|
- Restrictive policies can only narrow access, so they may check anything.
|
|
65
67
|
- An existing `tenant_isolation` policy must be permissive, apply to all commands, and apply to `PUBLIC` (no `TO` clause), like the one `createPolicy` generates and every policy Stratum ships.
|
|
66
68
|
|
|
67
|
-
The check recognizes the form Stratum generates, with the operands in either order, with casts, ANDed with other conditions, or ORed with Stratum's `app.bypass_rls` bypass. A policy that isolates correctly but is written in another form is also refused; replace it with the generated form. This is a breaking change for callers that relied on the old skip, shipped in a minor release.
|
|
69
|
+
The check recognizes the form Stratum generates, with the operands in either order, with casts, ANDed with other conditions, or ORed with Stratum's `app.bypass_rls` bypass, directly or through `stratum_legacy_bypass()` (migration 032). A policy that isolates correctly but is written in another form is also refused; replace it with the generated form. This is a breaking change for callers that relied on the old skip, shipped in a minor release.
|
|
70
|
+
|
|
71
|
+
A permissive policy named `stratum_control_plane` is accepted only when it applies to exactly the control role of migration 032 (`stratum_control` by default; pass `{ controlRole }` to `createPolicy` for another name). A policy that checks `app.bypass_rls` directly still passes in 1.x, but `createPolicy` emits a `STRATUM_GUC_BYPASS_POLICY` process warning for it: the control role, which PostgreSQL role membership decides, replaces it. 2.0 refuses such policies.
|
|
68
72
|
|
|
69
73
|
`isRLSEnabled` reports on the table that the name resolves to through the `search_path`, not on a table with the same name in another schema.
|
|
70
74
|
|
|
@@ -116,19 +120,24 @@ npm install @electric-sql/pglite
|
|
|
116
120
|
```
|
|
117
121
|
|
|
118
122
|
```typescript
|
|
119
|
-
import { Stratum } from "@stratum-hq/lib";
|
|
123
|
+
import { Stratum, bootstrapRolesSql } from "@stratum-hq/lib";
|
|
120
124
|
import { withTenantContext } from "@stratum-hq/db-adapters";
|
|
121
125
|
import { createPglitePool, createRestrictedPool } from "@stratum-hq/db-adapters/pglite";
|
|
122
126
|
|
|
123
127
|
// In-memory database. Pass PGlite options, such as { dataDir: "idb://my-db" }, to keep data.
|
|
124
|
-
|
|
125
|
-
|
|
128
|
+
// The library runs on adminPool (the PGlite superuser). Row-level security applies
|
|
129
|
+
// only to a role that is not a superuser, so the application uses a restricted pool.
|
|
130
|
+
const adminPool = await createPglitePool();
|
|
131
|
+
const appPool = await createRestrictedPool(adminPool);
|
|
132
|
+
const stratum = new Stratum({ adminPool, pool: appPool, autoMigrate: true });
|
|
126
133
|
await stratum.initialize();
|
|
127
134
|
|
|
128
|
-
|
|
135
|
+
// Limit the application role to reading the Stratum tables, as in production,
|
|
136
|
+
// and close the legacy app.bypass_rls path (migration 032).
|
|
137
|
+
await adminPool.query(bootstrapRolesSql({ appRole: "stratum_app" }));
|
|
138
|
+
await adminPool.query("UPDATE stratum_security SET legacy_guc_bypass = false");
|
|
129
139
|
|
|
130
|
-
|
|
131
|
-
const appPool = await createRestrictedPool(pool);
|
|
140
|
+
const acme = await stratum.createTenant({ name: "Acme", slug: "acme" });
|
|
132
141
|
await withTenantContext(appPool, acme.id, (client) => client.query("SELECT * FROM config_entries"));
|
|
133
142
|
```
|
|
134
143
|
|
|
@@ -138,7 +147,7 @@ await withTenantContext(appPool, acme.id, (client) => client.query("SELECT * FRO
|
|
|
138
147
|
- When you pass your own instance, load `ltree` and `uuid_ossp` yourself. `pool.end()` does not close your instance.
|
|
139
148
|
- `pool.pglite` is the PGlite instance.
|
|
140
149
|
|
|
141
|
-
`createRestrictedPool(pool, { role? })` creates the role `stratum_app` (or the name you give) with `NOSUPERUSER NOBYPASSRLS`. It grants the role read and write access to every table and sequence in the `public` schema. Default privileges extend the grants to tables that the superuser creates later. The returned pool runs every query as that role.
|
|
150
|
+
`createRestrictedPool(pool, { role? })` creates the role `stratum_app` (or the name you give) with `NOSUPERUSER NOBYPASSRLS`. It grants the role read and write access to every table and sequence in the `public` schema. Default privileges extend the grants to tables that the superuser creates later. The returned pool runs every query as that role. `bootstrapRolesSql({ appRole })` from `@stratum-hq/lib` narrows those grants on the Stratum tables to the recommended read-only set; `Stratum.initialize()` warns about the wider grants until you run it.
|
|
142
151
|
|
|
143
152
|
The restricted role is a test and demo convenience, not a security boundary: any query can leave it with `RESET ROLE`.
|
|
144
153
|
|
|
@@ -14,8 +14,9 @@ export declare class DrizzleAdapter extends BaseAdapter {
|
|
|
14
14
|
* on the same connection.
|
|
15
15
|
*
|
|
16
16
|
* contextFn should return the current tenant ID (e.g. from AsyncLocalStorage).
|
|
17
|
-
* When contextFn returns an empty string
|
|
18
|
-
*
|
|
17
|
+
* When contextFn returns an empty string, `transaction()` and `execute()`
|
|
18
|
+
* throw instead of running. Use the unwrapped Drizzle instance for system or
|
|
19
|
+
* admin queries that run without a tenant.
|
|
19
20
|
*/
|
|
20
21
|
withTenant<D extends DrizzleLike>(db: D, contextFn: () => string): Pick<D, "execute" | "transaction">;
|
|
21
22
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"drizzle.d.ts","sourceRoot":"","sources":["../../src/adapters/drizzle.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,MAAM,IAAI,CAAC;AAIpB,MAAM,WAAW,WAAW;IAC1B,OAAO,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1C,WAAW,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CACjE;AAQD,qBAAa,cAAe,SAAQ,WAAW;gBACjC,IAAI,EAAE,EAAE,CAAC,IAAI;IAIzB
|
|
1
|
+
{"version":3,"file":"drizzle.d.ts","sourceRoot":"","sources":["../../src/adapters/drizzle.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,MAAM,IAAI,CAAC;AAIpB,MAAM,WAAW,WAAW;IAC1B,OAAO,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1C,WAAW,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CACjE;AAQD,qBAAa,cAAe,SAAQ,WAAW;gBACjC,IAAI,EAAE,EAAE,CAAC,IAAI;IAIzB;;;;;;;;;;;OAWG;IACH,UAAU,CAAC,CAAC,SAAS,WAAW,EAC9B,EAAE,EAAE,CAAC,EACL,SAAS,EAAE,MAAM,MAAM,GACtB,IAAI,CAAC,CAAC,EAAE,SAAS,GAAG,aAAa,CAAC;CAsCtC;AAGD,wBAAgB,UAAU,CAAC,CAAC,SAAS,WAAW,EAC9C,EAAE,EAAE,CAAC,EACL,SAAS,EAAE,MAAM,MAAM,EACvB,IAAI,EAAE,EAAE,CAAC,IAAI,GACZ,IAAI,CAAC,CAAC,EAAE,SAAS,GAAG,aAAa,CAAC,CAGpC;AAED,4CAA4C;AAC5C,eAAO,MAAM,eAAe,mBAAa,CAAC"}
|
package/dist/adapters/drizzle.js
CHANGED
|
@@ -20,8 +20,9 @@ class DrizzleAdapter extends base_adapter_js_1.BaseAdapter {
|
|
|
20
20
|
* on the same connection.
|
|
21
21
|
*
|
|
22
22
|
* contextFn should return the current tenant ID (e.g. from AsyncLocalStorage).
|
|
23
|
-
* When contextFn returns an empty string
|
|
24
|
-
*
|
|
23
|
+
* When contextFn returns an empty string, `transaction()` and `execute()`
|
|
24
|
+
* throw instead of running. Use the unwrapped Drizzle instance for system or
|
|
25
|
+
* admin queries that run without a tenant.
|
|
25
26
|
*/
|
|
26
27
|
withTenant(db, contextFn) {
|
|
27
28
|
const original = db;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"drizzle.js","sourceRoot":"","sources":["../../src/adapters/drizzle.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"drizzle.js","sourceRoot":"","sources":["../../src/adapters/drizzle.ts"],"names":[],"mappings":";;;AA6EA,gCAOC;AApFD,wDAAiD;AAUjD,gFAAgF;AAChF,KAAK,UAAU,eAAe,CAAC,EAAe,EAAE,QAAgB;IAC9D,MAAM,EAAE,GAAG,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAC;IAC5C,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,CAAA,8CAA8C,QAAQ,SAAS,CAAC,CAAC;AACvF,CAAC;AAED,MAAa,cAAe,SAAQ,6BAAW;IAC7C,YAAY,IAAa;QACvB,KAAK,CAAC,IAAI,CAAC,CAAC;IACd,CAAC;IAED;;;;;;;;;;;OAWG;IACH,UAAU,CACR,EAAK,EACL,SAAuB;QAEvB,MAAM,QAAQ,GAAG,EAAE,CAAC;QAEpB,MAAM,kBAAkB,GAAG,KAAK,EAAK,EAAmC,EAAc,EAAE;YACtF,MAAM,QAAQ,GAAG,SAAS,EAAE,CAAC;YAC7B,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,MAAM,IAAI,KAAK,CACb,sDAAsD;oBACtD,yDAAyD,CAC1D,CAAC;YACJ,CAAC;YACD,OAAO,QAAQ,CAAC,WAAW,CAAC,KAAK,EAAE,EAAe,EAAE,EAAE;gBACpD,MAAM,eAAe,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;gBACpC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;YAChB,CAAC,CAAC,CAAC;QACL,CAAC,CAAC;QAEF,MAAM,cAAc,GAAG,KAAK,EAAE,KAAc,EAAoB,EAAE;YAChE,MAAM,QAAQ,GAAG,SAAS,EAAE,CAAC;YAC7B,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,MAAM,IAAI,KAAK,CACb,sDAAsD;oBACtD,yDAAyD,CAC1D,CAAC;YACJ,CAAC;YACD,OAAO,QAAQ,CAAC,WAAW,CAAC,KAAK,EAAE,EAAe,EAAE,EAAE;gBACpD,MAAM,eAAe,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;gBACpC,OAAO,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;YAC3B,CAAC,CAAC,CAAC;QACL,CAAC,CAAC;QAEF,qEAAqE;QACrE,mDAAmD;QACnD,OAAO;YACL,OAAO,EAAE,cAAc;YACvB,WAAW,EAAE,kBAAkB;SACiB,CAAC;IACrD,CAAC;CACF;AA1DD,wCA0DC;AAED,+DAA+D;AAC/D,SAAgB,UAAU,CACxB,EAAK,EACL,SAAuB,EACvB,IAAa;IAEb,MAAM,OAAO,GAAG,IAAI,cAAc,CAAC,IAAI,CAAC,CAAC;IACzC,OAAO,OAAO,CAAC,UAAU,CAAC,EAAE,EAAE,SAAS,CAAC,CAAC;AAC3C,CAAC;AAED,4CAA4C;AAC/B,QAAA,eAAe,GAAG,UAAU,CAAC"}
|
|
@@ -15,8 +15,9 @@ export declare class SequelizeAdapter extends BaseAdapter {
|
|
|
15
15
|
* connection-pool hops.
|
|
16
16
|
*
|
|
17
17
|
* contextFn should return the current tenant ID (e.g. from AsyncLocalStorage).
|
|
18
|
-
* When contextFn returns an empty string
|
|
19
|
-
*
|
|
18
|
+
* When contextFn returns an empty string, `query()` throws instead of
|
|
19
|
+
* running the query. Use the unwrapped Sequelize instance for system or
|
|
20
|
+
* admin queries that run without a tenant.
|
|
20
21
|
*/
|
|
21
22
|
withTenantScope(sequelize: SequelizeLike, contextFn: () => string): SequelizeLike;
|
|
22
23
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sequelize.d.ts","sourceRoot":"","sources":["../../src/adapters/sequelize.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,MAAM,IAAI,CAAC;AAIpB,UAAU,aAAa;IACrB,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACxE,WAAW,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAC3D,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CACnF;AAED,qBAAa,gBAAiB,SAAQ,WAAW;gBACnC,IAAI,EAAE,EAAE,CAAC,IAAI;IAIzB
|
|
1
|
+
{"version":3,"file":"sequelize.d.ts","sourceRoot":"","sources":["../../src/adapters/sequelize.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,MAAM,IAAI,CAAC;AAIpB,UAAU,aAAa;IACrB,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACxE,WAAW,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAC3D,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CACnF;AAED,qBAAa,gBAAiB,SAAQ,WAAW;gBACnC,IAAI,EAAE,EAAE,CAAC,IAAI;IAIzB;;;;;;;;;;;OAWG;IACH,eAAe,CAAC,SAAS,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,MAAM,GAAG,aAAa;CA0BlF;AAGD,wBAAgB,eAAe,CAC7B,SAAS,EAAE,aAAa,EACxB,SAAS,EAAE,MAAM,MAAM,EACvB,IAAI,EAAE,EAAE,CAAC,IAAI,GACZ,aAAa,CAGf"}
|
|
@@ -15,8 +15,9 @@ class SequelizeAdapter extends base_adapter_js_1.BaseAdapter {
|
|
|
15
15
|
* connection-pool hops.
|
|
16
16
|
*
|
|
17
17
|
* contextFn should return the current tenant ID (e.g. from AsyncLocalStorage).
|
|
18
|
-
* When contextFn returns an empty string
|
|
19
|
-
*
|
|
18
|
+
* When contextFn returns an empty string, `query()` throws instead of
|
|
19
|
+
* running the query. Use the unwrapped Sequelize instance for system or
|
|
20
|
+
* admin queries that run without a tenant.
|
|
20
21
|
*/
|
|
21
22
|
withTenantScope(sequelize, contextFn) {
|
|
22
23
|
const original = sequelize;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sequelize.js","sourceRoot":"","sources":["../../src/adapters/sequelize.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"sequelize.js","sourceRoot":"","sources":["../../src/adapters/sequelize.ts"],"names":[],"mappings":";;;AAyDA,0CAOC;AAhED,wDAAiD;AAWjD,MAAa,gBAAiB,SAAQ,6BAAW;IAC/C,YAAY,IAAa;QACvB,KAAK,CAAC,IAAI,CAAC,CAAC;IACd,CAAC;IAED;;;;;;;;;;;OAWG;IACH,eAAe,CAAC,SAAwB,EAAE,SAAuB;QAC/D,MAAM,QAAQ,GAAG,SAAS,CAAC;QAE3B,MAAM,YAAY,GAAG,KAAK,EAAE,GAAW,EAAE,OAAiC,EAAE,EAAE;YAC5E,MAAM,QAAQ,GAAG,SAAS,EAAE,CAAC;YAC7B,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,MAAM,IAAI,KAAK,CACb,sDAAsD;oBACtD,yDAAyD,CAC1D,CAAC;YACJ,CAAC;YACD,OAAO,QAAQ,CAAC,WAAW,CAAC,KAAK,EAAE,CAAU,EAAE,EAAE;gBAC/C,MAAM,QAAQ,CAAC,KAAK,CAClB,sDAAsD,EACtD,EAAE,IAAI,EAAE,CAAC,QAAQ,CAAC,EAAE,WAAW,EAAE,CAAC,EAA6B,CAChE,CAAC;gBACF,OAAO,QAAQ,CAAC,KAAK,CAAC,GAAG,EAAE,EAAE,GAAG,OAAO,EAAE,WAAW,EAAE,CAAC,EAA6B,CAAC,CAAC;YACxF,CAAC,CAAC,CAAC;QACL,CAAC,CAAC;QAEF,OAAO;YACL,KAAK,EAAE,YAAY;YACnB,WAAW,EAAE,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC;YAChD,OAAO,EAAE,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC;SACzC,CAAC;IACJ,CAAC;CACF;AA3CD,4CA2CC;AAED,sEAAsE;AACtE,SAAgB,eAAe,CAC7B,SAAwB,EACxB,SAAuB,EACvB,IAAa;IAEb,MAAM,OAAO,GAAG,IAAI,gBAAgB,CAAC,IAAI,CAAC,CAAC;IAC3C,OAAO,OAAO,CAAC,eAAe,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;AACvD,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -6,6 +6,8 @@ export type { SchemaAdapterOptions } from "./adapters/schema-raw.js";
|
|
|
6
6
|
export { SchemaPrismaAdapter, withSchemaTenant, } from "./adapters/schema-prisma.js";
|
|
7
7
|
export { createPolicy, dropPolicy, enableRLS, disableRLS, isRLSEnabled, } from "./rls/manager.js";
|
|
8
8
|
export type { CreatePolicyOptions } from "./rls/manager.js";
|
|
9
|
+
export { tablePolicyIssues, tablePolicyWarnings, permissivePolicyIssue, isControlPlanePolicy, DEFAULT_CONTROL_ROLE, } from "./rls/policy-check.js";
|
|
10
|
+
export type { PolicyRow } from "./rls/policy-check.js";
|
|
9
11
|
export { setTenantContext, resetTenantContext, withTenantContext, withRlsBypass, getCurrentTenantId, } from "./rls/session.js";
|
|
10
12
|
export type { TenantScope, TenantContextOptions } from "./rls/session.js";
|
|
11
13
|
export { createSchema, dropSchema, schemaExists, listTenantSchemas, replicateTableToSchema, tenantSchemaName, } from "./schema/manager.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,UAAU,IAAI,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACrF,OAAO,EACL,gBAAgB,EAChB,sBAAsB,GACvB,MAAM,0BAA0B,CAAC;AAClC,YAAY,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AACrE,OAAO,EACL,mBAAmB,EACnB,gBAAgB,GACjB,MAAM,6BAA6B,CAAC;AAErC,OAAO,EACL,YAAY,EACZ,UAAU,EACV,SAAS,EACT,UAAU,EACV,YAAY,GACb,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,UAAU,IAAI,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACrF,OAAO,EACL,gBAAgB,EAChB,sBAAsB,GACvB,MAAM,0BAA0B,CAAC;AAClC,YAAY,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AACrE,OAAO,EACL,mBAAmB,EACnB,gBAAgB,GACjB,MAAM,6BAA6B,CAAC;AAErC,OAAO,EACL,YAAY,EACZ,UAAU,EACV,SAAS,EACT,UAAU,EACV,YAAY,GACb,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAC5D,OAAO,EACL,iBAAiB,EACjB,mBAAmB,EACnB,qBAAqB,EACrB,oBAAoB,EACpB,oBAAoB,GACrB,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAEvD,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,iBAAiB,EACjB,aAAa,EACb,kBAAkB,GACnB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EAAE,WAAW,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAE1E,OAAO,EACL,YAAY,EACZ,UAAU,EACV,YAAY,EACZ,iBAAiB,EACjB,sBAAsB,EACtB,gBAAgB,GACjB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,mBAAmB,EACnB,eAAe,EACf,oBAAoB,GACrB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,eAAe,EACf,SAAS,IAAI,qBAAqB,EAClC,qBAAqB,EACrB,YAAY,GACb,MAAM,wBAAwB,CAAC;AAGhC,OAAO,EACL,eAAe,EACf,cAAc,EACd,cAAc,EACd,YAAY,GACb,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,YAAY,EAAE,0BAA0B,EAAE,MAAM,4BAA4B,CAAC;AAE7E,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,EAAE,gBAAgB,EAAE,eAAe,IAAI,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AACxG,OAAO,EACL,cAAc,EACd,UAAU,IAAI,iBAAiB,EAC/B,eAAe,IAAI,sBAAsB,GAC1C,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.drizzleWithTenantScope = exports.drizzleWithTenant = exports.DrizzleAdapter = exports.sequelizeWithTenantScope = exports.SequelizeAdapter = exports.DatabasePrismaAdapter = exports.DatabaseRawAdapter = exports.DatabasePoolManager = exports.dropDatabase = exports.createDatabase = exports.databaseExists = exports.getDatabaseName = exports.migrateTable = exports.createIsolationPolicy = exports.enableRLSForMigration = exports.addTenantColumn = exports.getCurrentSearchPath = exports.resetSearchPath = exports.setSchemaSearchPath = exports.tenantSchemaName = exports.replicateTableToSchema = exports.listTenantSchemas = exports.schemaExists = exports.dropSchema = exports.createSchema = exports.getCurrentTenantId = exports.withRlsBypass = exports.withTenantContext = exports.resetTenantContext = exports.setTenantContext = exports.isRLSEnabled = exports.disableRLS = exports.enableRLS = exports.dropPolicy = exports.createPolicy = exports.withSchemaTenant = exports.SchemaPrismaAdapter = exports.createSchemaTenantPool = exports.SchemaRawAdapter = exports.prismaWithTenant = exports.PrismaAdapter = exports.createTenantPool = exports.RawAdapter = exports.BaseAdapter = void 0;
|
|
3
|
+
exports.drizzleWithTenantScope = exports.drizzleWithTenant = exports.DrizzleAdapter = exports.sequelizeWithTenantScope = exports.SequelizeAdapter = exports.DatabasePrismaAdapter = exports.DatabaseRawAdapter = exports.DatabasePoolManager = exports.dropDatabase = exports.createDatabase = exports.databaseExists = exports.getDatabaseName = exports.migrateTable = exports.createIsolationPolicy = exports.enableRLSForMigration = exports.addTenantColumn = exports.getCurrentSearchPath = exports.resetSearchPath = exports.setSchemaSearchPath = exports.tenantSchemaName = exports.replicateTableToSchema = exports.listTenantSchemas = exports.schemaExists = exports.dropSchema = exports.createSchema = exports.getCurrentTenantId = exports.withRlsBypass = exports.withTenantContext = exports.resetTenantContext = exports.setTenantContext = exports.DEFAULT_CONTROL_ROLE = exports.isControlPlanePolicy = exports.permissivePolicyIssue = exports.tablePolicyWarnings = exports.tablePolicyIssues = exports.isRLSEnabled = exports.disableRLS = exports.enableRLS = exports.dropPolicy = exports.createPolicy = exports.withSchemaTenant = exports.SchemaPrismaAdapter = exports.createSchemaTenantPool = exports.SchemaRawAdapter = exports.prismaWithTenant = exports.PrismaAdapter = exports.createTenantPool = exports.RawAdapter = exports.BaseAdapter = void 0;
|
|
4
4
|
var base_adapter_js_1 = require("./base-adapter.js");
|
|
5
5
|
Object.defineProperty(exports, "BaseAdapter", { enumerable: true, get: function () { return base_adapter_js_1.BaseAdapter; } });
|
|
6
6
|
var raw_js_1 = require("./adapters/raw.js");
|
|
@@ -21,6 +21,12 @@ Object.defineProperty(exports, "dropPolicy", { enumerable: true, get: function (
|
|
|
21
21
|
Object.defineProperty(exports, "enableRLS", { enumerable: true, get: function () { return manager_js_1.enableRLS; } });
|
|
22
22
|
Object.defineProperty(exports, "disableRLS", { enumerable: true, get: function () { return manager_js_1.disableRLS; } });
|
|
23
23
|
Object.defineProperty(exports, "isRLSEnabled", { enumerable: true, get: function () { return manager_js_1.isRLSEnabled; } });
|
|
24
|
+
var policy_check_js_1 = require("./rls/policy-check.js");
|
|
25
|
+
Object.defineProperty(exports, "tablePolicyIssues", { enumerable: true, get: function () { return policy_check_js_1.tablePolicyIssues; } });
|
|
26
|
+
Object.defineProperty(exports, "tablePolicyWarnings", { enumerable: true, get: function () { return policy_check_js_1.tablePolicyWarnings; } });
|
|
27
|
+
Object.defineProperty(exports, "permissivePolicyIssue", { enumerable: true, get: function () { return policy_check_js_1.permissivePolicyIssue; } });
|
|
28
|
+
Object.defineProperty(exports, "isControlPlanePolicy", { enumerable: true, get: function () { return policy_check_js_1.isControlPlanePolicy; } });
|
|
29
|
+
Object.defineProperty(exports, "DEFAULT_CONTROL_ROLE", { enumerable: true, get: function () { return policy_check_js_1.DEFAULT_CONTROL_ROLE; } });
|
|
24
30
|
var session_js_1 = require("./rls/session.js");
|
|
25
31
|
Object.defineProperty(exports, "setTenantContext", { enumerable: true, get: function () { return session_js_1.setTenantContext; } });
|
|
26
32
|
Object.defineProperty(exports, "resetTenantContext", { enumerable: true, get: function () { return session_js_1.resetTenantContext; } });
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,qDAAgD;AAAvC,8GAAA,WAAW,OAAA;AAEpB,4CAAiE;AAAxD,oGAAA,UAAU,OAAA;AAAE,0GAAA,gBAAgB,OAAA;AACrC,kDAAqF;AAA5E,0GAAA,aAAa,OAAA;AAAE,6GAAA,UAAU,OAAoB;AACtD,0DAGkC;AAFhC,iHAAA,gBAAgB,OAAA;AAChB,uHAAA,sBAAsB,OAAA;AAGxB,gEAGqC;AAFnC,uHAAA,mBAAmB,OAAA;AACnB,oHAAA,gBAAgB,OAAA;AAGlB,+CAM0B;AALxB,0GAAA,YAAY,OAAA;AACZ,wGAAA,UAAU,OAAA;AACV,uGAAA,SAAS,OAAA;AACT,wGAAA,UAAU,OAAA;AACV,0GAAA,YAAY,OAAA;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,qDAAgD;AAAvC,8GAAA,WAAW,OAAA;AAEpB,4CAAiE;AAAxD,oGAAA,UAAU,OAAA;AAAE,0GAAA,gBAAgB,OAAA;AACrC,kDAAqF;AAA5E,0GAAA,aAAa,OAAA;AAAE,6GAAA,UAAU,OAAoB;AACtD,0DAGkC;AAFhC,iHAAA,gBAAgB,OAAA;AAChB,uHAAA,sBAAsB,OAAA;AAGxB,gEAGqC;AAFnC,uHAAA,mBAAmB,OAAA;AACnB,oHAAA,gBAAgB,OAAA;AAGlB,+CAM0B;AALxB,0GAAA,YAAY,OAAA;AACZ,wGAAA,UAAU,OAAA;AACV,uGAAA,SAAS,OAAA;AACT,wGAAA,UAAU,OAAA;AACV,0GAAA,YAAY,OAAA;AAGd,yDAM+B;AAL7B,oHAAA,iBAAiB,OAAA;AACjB,sHAAA,mBAAmB,OAAA;AACnB,wHAAA,qBAAqB,OAAA;AACrB,uHAAA,oBAAoB,OAAA;AACpB,uHAAA,oBAAoB,OAAA;AAItB,+CAM0B;AALxB,8GAAA,gBAAgB,OAAA;AAChB,gHAAA,kBAAkB,OAAA;AAClB,+GAAA,iBAAiB,OAAA;AACjB,2GAAA,aAAa,OAAA;AACb,gHAAA,kBAAkB,OAAA;AAIpB,kDAO6B;AAN3B,0GAAA,YAAY,OAAA;AACZ,wGAAA,UAAU,OAAA;AACV,0GAAA,YAAY,OAAA;AACZ,+GAAA,iBAAiB,OAAA;AACjB,oHAAA,sBAAsB,OAAA;AACtB,8GAAA,gBAAgB,OAAA;AAGlB,kDAI6B;AAH3B,iHAAA,mBAAmB,OAAA;AACnB,6GAAA,eAAe,OAAA;AACf,kHAAA,oBAAoB,OAAA;AAGtB,+DAKgC;AAJ9B,uHAAA,eAAe,OAAA;AACf,6HAAA,SAAS,OAAyB;AAClC,6HAAA,qBAAqB,OAAA;AACrB,oHAAA,YAAY,OAAA;AAGd,0BAA0B;AAC1B,oDAK+B;AAJ7B,6GAAA,eAAe,OAAA;AACf,4GAAA,cAAc,OAAA;AACd,4GAAA,cAAc,OAAA;AACd,0GAAA,YAAY,OAAA;AAGd,8DAAiE;AAAxD,sHAAA,mBAAmB,OAAA;AAG5B,8DAAgE;AAAvD,qHAAA,kBAAkB,OAAA;AAC3B,oEAAsE;AAA7D,2HAAA,qBAAqB,OAAA;AAC9B,wDAAwG;AAA/F,gHAAA,gBAAgB,OAAA;AAAE,wHAAA,eAAe,OAA4B;AACtE,oDAI+B;AAH7B,4GAAA,cAAc,OAAA;AACd,+GAAA,UAAU,OAAqB;AAC/B,oHAAA,eAAe,OAA0B"}
|
package/dist/rls/manager.d.ts
CHANGED
|
@@ -12,6 +12,12 @@ export interface CreatePolicyOptions {
|
|
|
12
12
|
* migration 031 of @stratum-hq/lib. Default false.
|
|
13
13
|
*/
|
|
14
14
|
subtreeRead?: boolean;
|
|
15
|
+
/**
|
|
16
|
+
* The control role of migration 032 (default `stratum_control`). An
|
|
17
|
+
* existing stratum_control_plane policy is accepted only when it applies to
|
|
18
|
+
* exactly this role.
|
|
19
|
+
*/
|
|
20
|
+
controlRole?: string;
|
|
15
21
|
}
|
|
16
22
|
/**
|
|
17
23
|
* Throws when the database has no stratum_subtree_tenant_ids() function. The
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/rls/manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AAKpB;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,QAEuC,CAAC;AAExE,MAAM,WAAW,mBAAmB;IAClC;;;;OAIG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/rls/manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AAKpB;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,QAEuC,CAAC;AAExE,MAAM,WAAW,mBAAmB;IAClC;;;;OAIG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;GAIG;AACH,wBAAsB,qBAAqB,CAAC,MAAM,EAAE,EAAE,CAAC,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAUhF;AAUD,wBAAsB,YAAY,CAChC,MAAM,EAAE,EAAE,CAAC,UAAU,EACrB,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,IAAI,CAAC,CA+Cf;AAED,wBAAsB,UAAU,CAC9B,MAAM,EAAE,EAAE,CAAC,UAAU,EACrB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CAIf;AAED,wBAAsB,SAAS,CAC7B,MAAM,EAAE,EAAE,CAAC,UAAU,EACrB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CAIf;AAED,wBAAsB,UAAU,CAC9B,MAAM,EAAE,EAAE,CAAC,UAAU,EACrB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CAIf;AAED,wBAAsB,YAAY,CAChC,MAAM,EAAE,EAAE,CAAC,UAAU,EACrB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,OAAO,CAAC,CAWlB"}
|
package/dist/rls/manager.js
CHANGED
|
@@ -41,23 +41,28 @@ async function createPolicy(client, tableName, options = {}) {
|
|
|
41
41
|
await assertSubtreeFunction(client);
|
|
42
42
|
}
|
|
43
43
|
// Read every policy on the table that the name resolves to, in whichever
|
|
44
|
-
// schema that is.
|
|
44
|
+
// schema that is. The caller's search path stays as it is (this may run in
|
|
45
|
+
// the caller's transaction), so every comparison here has an exact
|
|
46
|
+
// pg_catalog operator: the regclass lookups are cast to oid. PostgreSQL ORs permissive policies together, so each one
|
|
45
47
|
// must filter by tenant, and a policy's name proves nothing.
|
|
46
48
|
// Each row also carries the schema of the tenants table, the only schema
|
|
47
49
|
// that may qualify the subtree function (migration 031 creates it there).
|
|
48
50
|
const existing = await client.query(`SELECT p.policyname, p.permissive, p.cmd, p.qual, p.with_check, p.roles::text[] AS roles,
|
|
49
51
|
(SELECT tn.nspname FROM pg_class tc JOIN pg_namespace tn ON tn.oid = tc.relnamespace
|
|
50
|
-
WHERE tc.oid = to_regclass('tenants')) AS tenants_schema
|
|
52
|
+
WHERE tc.oid = pg_catalog.to_regclass('tenants')::pg_catalog.oid) AS tenants_schema
|
|
51
53
|
FROM pg_policies p
|
|
52
54
|
JOIN pg_class c ON c.relname = p.tablename
|
|
53
55
|
JOIN pg_namespace n ON n.oid = c.relnamespace AND n.nspname = p.schemaname
|
|
54
|
-
WHERE c.oid = to_regclass($1)`, [safe]);
|
|
55
|
-
const issues = (0, policy_check_js_1.tablePolicyIssues)(existing.rows, existing.rows[0]?.tenants_schema ?? undefined);
|
|
56
|
+
WHERE c.oid = pg_catalog.to_regclass($1::pg_catalog.text)::pg_catalog.oid`, [safe]);
|
|
57
|
+
const issues = (0, policy_check_js_1.tablePolicyIssues)(existing.rows, existing.rows[0]?.tenants_schema ?? undefined, options.controlRole);
|
|
56
58
|
if (issues.length > 0) {
|
|
57
59
|
throw new Error(`[stratum] Table ${safe} has row-level security policies that do not isolate it by tenant: ` +
|
|
58
60
|
`${issues.join("; ")} (expected ${TENANT_FILTER}). ` +
|
|
59
61
|
`Drop or correct those policies, then call createPolicy again.`);
|
|
60
62
|
}
|
|
63
|
+
for (const warning of (0, policy_check_js_1.tablePolicyWarnings)(existing.rows)) {
|
|
64
|
+
process.emitWarning(`[stratum] Table ${safe}: ${warning}`, { code: "STRATUM_GUC_BYPASS_POLICY" });
|
|
65
|
+
}
|
|
61
66
|
if (!existing.rows.some((p) => p.policyname === "tenant_isolation")) {
|
|
62
67
|
// Cannot use parameterized queries inside DO blocks or for DDL identifiers.
|
|
63
68
|
// Table name is validated via allowlist regex above.
|
|
@@ -85,7 +90,7 @@ async function disableRLS(client, tableName) {
|
|
|
85
90
|
async function isRLSEnabled(client, tableName) {
|
|
86
91
|
const safe = validateTableName(tableName);
|
|
87
92
|
// The table the name resolves to, in whichever schema that is.
|
|
88
|
-
const res = await client.query(`SELECT relrowsecurity FROM pg_class WHERE oid = to_regclass($1)`, [safe]);
|
|
93
|
+
const res = await client.query(`SELECT relrowsecurity FROM pg_catalog.pg_class WHERE oid = pg_catalog.to_regclass($1::pg_catalog.text)::pg_catalog.oid`, [safe]);
|
|
89
94
|
if (res.rows.length === 0) {
|
|
90
95
|
return false;
|
|
91
96
|
}
|
package/dist/rls/manager.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/rls/manager.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/rls/manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -23,6 +23,14 @@
|
|
|
23
23
|
* Stratum's administrative bypass. Anything else is reported as not filtering
|
|
24
24
|
* by tenant, so an unusual but correct policy is refused, never accepted.
|
|
25
25
|
*
|
|
26
|
+
* It recognises the legacy bypass of migration 032, `(SELECT
|
|
27
|
+
* stratum_legacy_bypass()) OR <tenant match>`, like the older direct check of
|
|
28
|
+
* app.bypass_rls. A policy named stratum_control_plane counts as isolating
|
|
29
|
+
* only when it applies to exactly the control role (default stratum_control):
|
|
30
|
+
* that role is the library's own, and a session cannot join it by setting
|
|
31
|
+
* anything. tablePolicyWarnings flags every policy that still checks
|
|
32
|
+
* app.bypass_rls directly; 2.0 will refuse those.
|
|
33
|
+
*
|
|
26
34
|
* It also recognises the subtree read of migration 031: the
|
|
27
35
|
* stratum_subtree_tenant_ids() match ANDed with the app.tenant_scope =
|
|
28
36
|
* 'subtree' check. That form counts only in the USING clause of a SELECT
|
|
@@ -42,13 +50,42 @@ export interface PolicyRow {
|
|
|
42
50
|
/** The roles the policy applies to; ["public"] for PUBLIC. */
|
|
43
51
|
roles: string[];
|
|
44
52
|
}
|
|
53
|
+
/** The default control role of migration 032. */
|
|
54
|
+
export declare const DEFAULT_CONTROL_ROLE = "stratum_control";
|
|
55
|
+
/**
|
|
56
|
+
* Why one permissive policy lets rows of other tenants through, or null when
|
|
57
|
+
* it filters by tenant for every command it covers. Shared with the policy
|
|
58
|
+
* checks of `@stratum-hq/cli`, so both apply the same expression rules.
|
|
59
|
+
*
|
|
60
|
+
* @param functionSchema - As for {@link tablePolicyIssues}.
|
|
61
|
+
*/
|
|
62
|
+
export declare function permissivePolicyIssue(p: Pick<PolicyRow, "policyname" | "cmd" | "qual" | "with_check">, functionSchema?: string): string | null;
|
|
63
|
+
/**
|
|
64
|
+
* True for the stratum_control_plane policy of migration 032 when it is
|
|
65
|
+
* permissive and applies to exactly `controlRole`. Only that role's members
|
|
66
|
+
* can use it, whatever it admits.
|
|
67
|
+
*/
|
|
68
|
+
export declare function isControlPlanePolicy(p: Pick<PolicyRow, "policyname" | "permissive"> & {
|
|
69
|
+
roles?: string[];
|
|
70
|
+
}, controlRole?: string): boolean;
|
|
45
71
|
/**
|
|
46
72
|
* Every reason the table's policies do not isolate it by tenant. Empty when
|
|
47
73
|
* they do, or when the table has no policies.
|
|
48
74
|
*
|
|
49
75
|
* @param functionSchema - The schema of Stratum's tenants table, the only
|
|
50
|
-
* schema that may qualify stratum_subtree_tenant_ids()
|
|
51
|
-
* undefined, only the unqualified
|
|
76
|
+
* schema that may qualify stratum_subtree_tenant_ids() and
|
|
77
|
+
* stratum_legacy_bypass(). When it is undefined, only the unqualified
|
|
78
|
+
* functions count.
|
|
79
|
+
* @param controlRole - The control role of migration 032. A policy named
|
|
80
|
+
* stratum_control_plane that applies to exactly this role is accepted.
|
|
81
|
+
*/
|
|
82
|
+
export declare function tablePolicyIssues(policies: PolicyRow[], functionSchema?: string, controlRole?: string): string[];
|
|
83
|
+
/**
|
|
84
|
+
* The policies that admit the app.bypass_rls setting directly. A session that
|
|
85
|
+
* can run SQL can set it, so such a policy holds only against a client that
|
|
86
|
+
* never sets it. The legacy form of migration 032 is not flagged: it admits
|
|
87
|
+
* the setting only while the stratum_security switch is on, which only the
|
|
88
|
+
* control role can change.
|
|
52
89
|
*/
|
|
53
|
-
export declare function
|
|
90
|
+
export declare function tablePolicyWarnings(policies: PolicyRow[]): string[];
|
|
54
91
|
//# sourceMappingURL=policy-check.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"policy-check.d.ts","sourceRoot":"","sources":["../../src/rls/policy-check.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"policy-check.d.ts","sourceRoot":"","sources":["../../src/rls/policy-check.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAEH,8BAA8B;AAC9B,MAAM,WAAW,SAAS;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,qCAAqC;IACrC,UAAU,EAAE,MAAM,CAAC;IACnB,uDAAuD;IACvD,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,8DAA8D;IAC9D,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAcD,iDAAiD;AACjD,eAAO,MAAM,oBAAoB,oBAAoB,CAAC;AA4LtD;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,CAAC,EAAE,IAAI,CAAC,SAAS,EAAE,YAAY,GAAG,KAAK,GAAG,MAAM,GAAG,YAAY,CAAC,EAChE,cAAc,CAAC,EAAE,MAAM,GACtB,MAAM,GAAG,IAAI,CAEf;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,CAAC,EAAE,IAAI,CAAC,SAAS,EAAE,YAAY,GAAG,YAAY,CAAC,GAAG;IAAE,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,EACtE,WAAW,GAAE,MAA6B,GACzC,OAAO,CAOT;AAiBD;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,SAAS,EAAE,EACrB,cAAc,CAAC,EAAE,MAAM,EACvB,WAAW,GAAE,MAA6B,GACzC,MAAM,EAAE,CAsBV;AAID;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,SAAS,EAAE,GAAG,MAAM,EAAE,CAanE"}
|
package/dist/rls/policy-check.js
CHANGED
|
@@ -24,6 +24,14 @@
|
|
|
24
24
|
* Stratum's administrative bypass. Anything else is reported as not filtering
|
|
25
25
|
* by tenant, so an unusual but correct policy is refused, never accepted.
|
|
26
26
|
*
|
|
27
|
+
* It recognises the legacy bypass of migration 032, `(SELECT
|
|
28
|
+
* stratum_legacy_bypass()) OR <tenant match>`, like the older direct check of
|
|
29
|
+
* app.bypass_rls. A policy named stratum_control_plane counts as isolating
|
|
30
|
+
* only when it applies to exactly the control role (default stratum_control):
|
|
31
|
+
* that role is the library's own, and a session cannot join it by setting
|
|
32
|
+
* anything. tablePolicyWarnings flags every policy that still checks
|
|
33
|
+
* app.bypass_rls directly; 2.0 will refuse those.
|
|
34
|
+
*
|
|
27
35
|
* It also recognises the subtree read of migration 031: the
|
|
28
36
|
* stratum_subtree_tenant_ids() match ANDed with the app.tenant_scope =
|
|
29
37
|
* 'subtree' check. That form counts only in the USING clause of a SELECT
|
|
@@ -32,7 +40,11 @@
|
|
|
32
40
|
* descendant.
|
|
33
41
|
*/
|
|
34
42
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
43
|
+
exports.DEFAULT_CONTROL_ROLE = void 0;
|
|
44
|
+
exports.permissivePolicyIssue = permissivePolicyIssue;
|
|
45
|
+
exports.isControlPlanePolicy = isControlPlanePolicy;
|
|
35
46
|
exports.tablePolicyIssues = tablePolicyIssues;
|
|
47
|
+
exports.tablePolicyWarnings = tablePolicyWarnings;
|
|
36
48
|
/** The session setting that holds the current tenant (see rls/session.ts). */
|
|
37
49
|
const TENANT_SETTING = "app.current_tenant_id";
|
|
38
50
|
/** The setting Stratum's own policies admit for administrative access. */
|
|
@@ -41,6 +53,12 @@ const BYPASS_SETTING = "app.bypass_rls";
|
|
|
41
53
|
const SCOPE_SETTING = "app.tenant_scope";
|
|
42
54
|
/** The function that returns the current tenant and its descendants (migration 031). */
|
|
43
55
|
const SUBTREE_FUNCTION = "stratum_subtree_tenant_ids";
|
|
56
|
+
/** The function of migration 032 that gates the legacy bypass behind stratum_security. */
|
|
57
|
+
const LEGACY_FUNCTION = "stratum_legacy_bypass";
|
|
58
|
+
/** The policy of migration 032 that admits the control role. */
|
|
59
|
+
const CONTROL_POLICY = "stratum_control_plane";
|
|
60
|
+
/** The default control role of migration 032. */
|
|
61
|
+
exports.DEFAULT_CONTROL_ROLE = "stratum_control";
|
|
44
62
|
/** Drops whitespace and casts, lower-cases, and keeps string literals intact. */
|
|
45
63
|
function normalize(expr) {
|
|
46
64
|
let out = "";
|
|
@@ -142,6 +160,14 @@ function subtreeMatch(functionSchema) {
|
|
|
142
160
|
const qualifier = functionSchema === undefined ? "" : `(?:${escapeRegExp(quoteIdent(functionSchema).toLowerCase())}\\.)?`;
|
|
143
161
|
return new RegExp(`^tenant_id=anyselect${qualifier}${SUBTREE_FUNCTION}(?:as${SUBTREE_FUNCTION})?$`);
|
|
144
162
|
}
|
|
163
|
+
/**
|
|
164
|
+
* (SELECT stratum_legacy_bypass()) after normalize and flatten, with the same
|
|
165
|
+
* rule for a schema qualifier as the subtree function.
|
|
166
|
+
*/
|
|
167
|
+
function legacyMatch(functionSchema) {
|
|
168
|
+
const qualifier = functionSchema === undefined ? "" : `(?:${escapeRegExp(quoteIdent(functionSchema).toLowerCase())}\\.)?`;
|
|
169
|
+
return new RegExp(`^select${qualifier}${LEGACY_FUNCTION}(?:as${LEGACY_FUNCTION})?$`);
|
|
170
|
+
}
|
|
145
171
|
function escapeRegExp(text) {
|
|
146
172
|
return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
147
173
|
}
|
|
@@ -154,17 +180,19 @@ function quoteIdent(name) {
|
|
|
154
180
|
* `subtree` matches the subtree function call that may appear in the
|
|
155
181
|
* expression, or is null where the subtree read is not allowed.
|
|
156
182
|
*/
|
|
157
|
-
function filtersByTenant(expr, subtree) {
|
|
183
|
+
function filtersByTenant(expr, subtree, legacy) {
|
|
158
184
|
const e = stripOuterParens(expr);
|
|
159
185
|
const disjuncts = splitTopLevel(e, "or");
|
|
160
186
|
if (disjuncts.length > 1) {
|
|
161
|
-
// Every branch must be safe; Stratum's administrative bypass
|
|
162
|
-
|
|
163
|
-
|
|
187
|
+
// Every branch must be safe; Stratum's administrative bypass, direct or
|
|
188
|
+
// through the legacy function of migration 032, is one of them.
|
|
189
|
+
const isBypass = (d) => BYPASS_MATCH.test(flatten(d)) || legacy.test(flatten(d));
|
|
190
|
+
return (disjuncts.every((d) => isBypass(d) || filtersByTenant(d, subtree, legacy)) &&
|
|
191
|
+
disjuncts.some((d) => !isBypass(d)));
|
|
164
192
|
}
|
|
165
193
|
const conjuncts = splitTopLevel(e, "and");
|
|
166
194
|
if (conjuncts.length > 1) {
|
|
167
|
-
if (conjuncts.some((c) => filtersByTenant(c, subtree)))
|
|
195
|
+
if (conjuncts.some((c) => filtersByTenant(c, subtree, legacy)))
|
|
168
196
|
return true;
|
|
169
197
|
// The subtree read of migration 031: the descendants of the current
|
|
170
198
|
// tenant, only when the session opted in with app.tenant_scope.
|
|
@@ -179,24 +207,45 @@ function oneLine(expr) {
|
|
|
179
207
|
return expr === null ? "none" : expr.replace(/\s+/g, " ");
|
|
180
208
|
}
|
|
181
209
|
/** Why one permissive policy lets rows of other tenants through, or null. */
|
|
182
|
-
function permissiveIssue(p, subtree) {
|
|
210
|
+
function permissiveIssue(p, subtree, legacy) {
|
|
183
211
|
const name = `policy "${oneLine(p.policyname)}" (${p.cmd})`;
|
|
184
212
|
// INSERT policies have only WITH CHECK; SELECT and DELETE only USING. For
|
|
185
213
|
// ALL and UPDATE a missing WITH CHECK means PostgreSQL reuses USING.
|
|
186
214
|
if (p.cmd !== "INSERT") {
|
|
187
215
|
// Only a SELECT policy may widen to the subtree: in any other policy the
|
|
188
216
|
// same USING clause would let UPDATE or DELETE reach a descendant's rows.
|
|
189
|
-
if (p.qual === null || !filtersByTenant(normalize(p.qual), p.cmd === "SELECT" ? subtree : null)) {
|
|
217
|
+
if (p.qual === null || !filtersByTenant(normalize(p.qual), p.cmd === "SELECT" ? subtree : null, legacy)) {
|
|
190
218
|
return `${name} USING (${oneLine(p.qual)}) does not filter by tenant`;
|
|
191
219
|
}
|
|
192
220
|
}
|
|
193
221
|
if (p.cmd === "INSERT" || p.with_check !== null) {
|
|
194
|
-
if (p.with_check === null || !filtersByTenant(normalize(p.with_check), null)) {
|
|
222
|
+
if (p.with_check === null || !filtersByTenant(normalize(p.with_check), null, legacy)) {
|
|
195
223
|
return `${name} WITH CHECK (${oneLine(p.with_check)}) does not filter by tenant`;
|
|
196
224
|
}
|
|
197
225
|
}
|
|
198
226
|
return null;
|
|
199
227
|
}
|
|
228
|
+
/**
|
|
229
|
+
* Why one permissive policy lets rows of other tenants through, or null when
|
|
230
|
+
* it filters by tenant for every command it covers. Shared with the policy
|
|
231
|
+
* checks of `@stratum-hq/cli`, so both apply the same expression rules.
|
|
232
|
+
*
|
|
233
|
+
* @param functionSchema - As for {@link tablePolicyIssues}.
|
|
234
|
+
*/
|
|
235
|
+
function permissivePolicyIssue(p, functionSchema) {
|
|
236
|
+
return permissiveIssue(p, subtreeMatch(functionSchema), legacyMatch(functionSchema));
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* True for the stratum_control_plane policy of migration 032 when it is
|
|
240
|
+
* permissive and applies to exactly `controlRole`. Only that role's members
|
|
241
|
+
* can use it, whatever it admits.
|
|
242
|
+
*/
|
|
243
|
+
function isControlPlanePolicy(p, controlRole = exports.DEFAULT_CONTROL_ROLE) {
|
|
244
|
+
return (p.policyname === CONTROL_POLICY &&
|
|
245
|
+
p.permissive === "PERMISSIVE" &&
|
|
246
|
+
p.roles?.length === 1 &&
|
|
247
|
+
p.roles[0] === controlRole);
|
|
248
|
+
}
|
|
200
249
|
/** Why the tenant_isolation policy is not the shape createPolicy generates, or null. */
|
|
201
250
|
function tenantIsolationShapeIssue(p) {
|
|
202
251
|
const name = `policy "${oneLine(p.policyname)}"`;
|
|
@@ -216,13 +265,21 @@ function tenantIsolationShapeIssue(p) {
|
|
|
216
265
|
* they do, or when the table has no policies.
|
|
217
266
|
*
|
|
218
267
|
* @param functionSchema - The schema of Stratum's tenants table, the only
|
|
219
|
-
* schema that may qualify stratum_subtree_tenant_ids()
|
|
220
|
-
* undefined, only the unqualified
|
|
268
|
+
* schema that may qualify stratum_subtree_tenant_ids() and
|
|
269
|
+
* stratum_legacy_bypass(). When it is undefined, only the unqualified
|
|
270
|
+
* functions count.
|
|
271
|
+
* @param controlRole - The control role of migration 032. A policy named
|
|
272
|
+
* stratum_control_plane that applies to exactly this role is accepted.
|
|
221
273
|
*/
|
|
222
|
-
function tablePolicyIssues(policies, functionSchema) {
|
|
274
|
+
function tablePolicyIssues(policies, functionSchema, controlRole = exports.DEFAULT_CONTROL_ROLE) {
|
|
223
275
|
const subtree = subtreeMatch(functionSchema);
|
|
276
|
+
const legacy = legacyMatch(functionSchema);
|
|
224
277
|
const issues = [];
|
|
225
278
|
for (const p of policies) {
|
|
279
|
+
if (isControlPlanePolicy(p, controlRole)) {
|
|
280
|
+
// Only the library's own role can use it, whatever it admits.
|
|
281
|
+
continue;
|
|
282
|
+
}
|
|
226
283
|
if (p.policyname === "tenant_isolation") {
|
|
227
284
|
const shape = tenantIsolationShapeIssue(p);
|
|
228
285
|
if (shape !== null) {
|
|
@@ -231,11 +288,31 @@ function tablePolicyIssues(policies, functionSchema) {
|
|
|
231
288
|
}
|
|
232
289
|
}
|
|
233
290
|
if (p.permissive === "PERMISSIVE") {
|
|
234
|
-
const issue = permissiveIssue(p, subtree);
|
|
291
|
+
const issue = permissiveIssue(p, subtree, legacy);
|
|
235
292
|
if (issue !== null)
|
|
236
293
|
issues.push(issue);
|
|
237
294
|
}
|
|
238
295
|
}
|
|
239
296
|
return issues;
|
|
240
297
|
}
|
|
298
|
+
const DIRECT_BYPASS = `current_setting'${BYPASS_SETTING.replace(".", "\\.")}'`;
|
|
299
|
+
/**
|
|
300
|
+
* The policies that admit the app.bypass_rls setting directly. A session that
|
|
301
|
+
* can run SQL can set it, so such a policy holds only against a client that
|
|
302
|
+
* never sets it. The legacy form of migration 032 is not flagged: it admits
|
|
303
|
+
* the setting only while the stratum_security switch is on, which only the
|
|
304
|
+
* control role can change.
|
|
305
|
+
*/
|
|
306
|
+
function tablePolicyWarnings(policies) {
|
|
307
|
+
const direct = new RegExp(DIRECT_BYPASS);
|
|
308
|
+
const warnings = [];
|
|
309
|
+
for (const p of policies) {
|
|
310
|
+
const exprs = [p.qual, p.with_check].filter((e) => e !== null);
|
|
311
|
+
if (exprs.some((e) => direct.test(flatten(normalize(e))))) {
|
|
312
|
+
warnings.push(`policy "${oneLine(p.policyname)}" admits app.bypass_rls directly. ` +
|
|
313
|
+
`Use the control role of migration 032, which PostgreSQL role membership decides, instead.`);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
return warnings;
|
|
317
|
+
}
|
|
241
318
|
//# sourceMappingURL=policy-check.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"policy-check.js","sourceRoot":"","sources":["../../src/rls/policy-check.ts"],"names":[],"mappings":";AAAA
|
|
1
|
+
{"version":3,"file":"policy-check.js","sourceRoot":"","sources":["../../src/rls/policy-check.ts"],"names":[],"mappings":"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"}
|
package/dist/rls/session.d.ts
CHANGED
|
@@ -30,6 +30,11 @@ export declare function resetTenantContext(client: pg.PoolClient): Promise<void>
|
|
|
30
30
|
*/
|
|
31
31
|
export declare function withTenantContext<T>(pool: pg.Pool, tenantId: string, fn: (client: pg.PoolClient) => Promise<T>, options?: TenantContextOptions): Promise<T>;
|
|
32
32
|
/**
|
|
33
|
+
* @deprecated Since 1.8 the library reaches across tenants through the control
|
|
34
|
+
* role of migration 032 (Stratum's `adminPool`), not through this setting.
|
|
35
|
+
* Removed in 2.0. Once the stratum_security legacy switch is off, the setting
|
|
36
|
+
* opens nothing, so this helper sees only what the pool's role sees.
|
|
37
|
+
*
|
|
33
38
|
* Runs `fn` inside a transaction with the RLS bypass flag set, so control-plane
|
|
34
39
|
* / system operations that legitimately span tenant boundaries (provisioning,
|
|
35
40
|
* cascade ops, ancestry reads) can see and write all rows.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/rls/session.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AAEpB;;;;;;;;GAQG;AACH,MAAM,MAAM,WAAW,GAAG,OAAO,GAAG,SAAS,CAAC;AAE9C,MAAM,WAAW,oBAAoB;IACnC,uCAAuC;IACvC,KAAK,CAAC,EAAE,WAAW,CAAC;CACrB;AAaD;;;;;GAKG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,EAAE,CAAC,UAAU,EACrB,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,IAAI,CAAC,CAKf;AAED,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,EAAE,CAAC,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAI7E;AAED;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CAAC,CAAC,EACvC,IAAI,EAAE,EAAE,CAAC,IAAI,EACb,QAAQ,EAAE,MAAM,EAChB,EAAE,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,UAAU,KAAK,OAAO,CAAC,CAAC,CAAC,EACzC,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,CAAC,CAAC,CAgBZ;
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/rls/session.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AAEpB;;;;;;;;GAQG;AACH,MAAM,MAAM,WAAW,GAAG,OAAO,GAAG,SAAS,CAAC;AAE9C,MAAM,WAAW,oBAAoB;IACnC,uCAAuC;IACvC,KAAK,CAAC,EAAE,WAAW,CAAC;CACrB;AAaD;;;;;GAKG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,EAAE,CAAC,UAAU,EACrB,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,IAAI,CAAC,CAKf;AAED,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,EAAE,CAAC,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAI7E;AAED;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CAAC,CAAC,EACvC,IAAI,EAAE,EAAE,CAAC,IAAI,EACb,QAAQ,EAAE,MAAM,EAChB,EAAE,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,UAAU,KAAK,OAAO,CAAC,CAAC,CAAC,EACzC,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,CAAC,CAAC,CAgBZ;AAID;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,aAAa,CAAC,CAAC,EACnC,IAAI,EAAE,EAAE,CAAC,IAAI,EACb,EAAE,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,UAAU,KAAK,OAAO,CAAC,CAAC,CAAC,GACxC,OAAO,CAAC,CAAC,CAAC,CAsBZ;AAED,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,EAAE,CAAC,UAAU,GACpB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAMxB"}
|
package/dist/rls/session.js
CHANGED
|
@@ -51,7 +51,13 @@ async function withTenantContext(pool, tenantId, fn, options = {}) {
|
|
|
51
51
|
client.release();
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
|
+
let warnedRlsBypass = false;
|
|
54
55
|
/**
|
|
56
|
+
* @deprecated Since 1.8 the library reaches across tenants through the control
|
|
57
|
+
* role of migration 032 (Stratum's `adminPool`), not through this setting.
|
|
58
|
+
* Removed in 2.0. Once the stratum_security legacy switch is off, the setting
|
|
59
|
+
* opens nothing, so this helper sees only what the pool's role sees.
|
|
60
|
+
*
|
|
55
61
|
* Runs `fn` inside a transaction with the RLS bypass flag set, so control-plane
|
|
56
62
|
* / system operations that legitimately span tenant boundaries (provisioning,
|
|
57
63
|
* cascade ops, ancestry reads) can see and write all rows.
|
|
@@ -65,6 +71,11 @@ async function withTenantContext(pool, tenantId, fn, options = {}) {
|
|
|
65
71
|
* access. Tenant-scoped work should use `withTenantContext` instead.
|
|
66
72
|
*/
|
|
67
73
|
async function withRlsBypass(pool, fn) {
|
|
74
|
+
if (!warnedRlsBypass) {
|
|
75
|
+
warnedRlsBypass = true;
|
|
76
|
+
process.emitWarning("withRlsBypass is deprecated and will be removed in 2.0. Run cross-tenant work on a pool whose " +
|
|
77
|
+
"login is a member of the Stratum control role (migration 032) instead.", { type: "DeprecationWarning", code: "STRATUM_WITH_RLS_BYPASS" });
|
|
78
|
+
}
|
|
68
79
|
const client = await pool.connect();
|
|
69
80
|
try {
|
|
70
81
|
await client.query("BEGIN");
|
package/dist/rls/session.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/rls/session.ts"],"names":[],"mappings":";;AAmCA,4CASC;AAED,gDAIC;AASD,8CAqBC;
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/rls/session.ts"],"names":[],"mappings":"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"}
|
package/dist/schema/manager.js
CHANGED
|
@@ -46,7 +46,7 @@ async function schemaExists(client, tenantSlug) {
|
|
|
46
46
|
return parseInt(res.rows[0].count, 10) > 0;
|
|
47
47
|
}
|
|
48
48
|
async function listTenantSchemas(client) {
|
|
49
|
-
const res = await client.query(`SELECT nspname FROM pg_namespace WHERE nspname
|
|
49
|
+
const res = await client.query(`SELECT nspname FROM pg_namespace WHERE nspname OPERATOR(pg_catalog.~~) 'tenant_%' ORDER BY nspname`);
|
|
50
50
|
return res.rows.map((r) => r.nspname);
|
|
51
51
|
}
|
|
52
52
|
async function replicateTableToSchema(client, tableName, schemaName) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/schema/manager.ts"],"names":[],"mappings":";;AAGA,gDAKC;AAaD,4CAQC;AAED,oCAQC;AAED,gCAMC;AAED,oCAUC;AAED,8CAOC;AAED,wDAUC;AA9ED,yFAAyF;AACzF,SAAgB,kBAAkB,CAAC,UAAkB;IACnD,IAAI,CAAC,0BAA0B,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;QACjD,MAAM,IAAI,KAAK,CAAC,wBAAwB,UAAU,EAAE,CAAC,CAAC;IACxD,CAAC;IACD,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,wFAAwF;AACxF,SAAS,iBAAiB,CAAC,SAAiB;IAC1C,IAAI,CAAC,0BAA0B,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;QAChD,MAAM,IAAI,KAAK,CAAC,uBAAuB,SAAS,EAAE,CAAC,CAAC;IACtD,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,yEAAyE;AACzE,MAAM,oBAAoB,GAAG,EAAE,CAAC;AAEhC,SAAgB,gBAAgB,CAAC,UAAkB;IACjD,MAAM,UAAU,GAAG,UAAU,UAAU,EAAE,CAAC;IAC1C,IAAI,MAAM,CAAC,UAAU,CAAC,UAAU,CAAC,GAAG,oBAAoB,EAAE,CAAC;QACzD,MAAM,IAAI,KAAK,CACb,gCAAgC,UAAU,aAAa,oBAAoB,QAAQ,CACpF,CAAC;IACJ,CAAC;IACD,OAAO,UAAU,CAAC;AACpB,CAAC;AAEM,KAAK,UAAU,YAAY,CAChC,MAAqB,EACrB,UAAkB;IAElB,MAAM,UAAU,GAAG,kBAAkB,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC,CAAC;IACpE,0EAA0E;IAC1E,+CAA+C;IAC/C,MAAM,MAAM,CAAC,KAAK,CAAC,iBAAiB,UAAU,EAAE,CAAC,CAAC;AACpD,CAAC;AAEM,KAAK,UAAU,UAAU,CAC9B,MAAqB,EACrB,UAAkB;IAElB,MAAM,UAAU,GAAG,kBAAkB,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC,CAAC;IACpE,MAAM,MAAM,CAAC,KAAK,CAAC,yBAAyB,UAAU,UAAU,CAAC,CAAC;AACpE,CAAC;AAEM,KAAK,UAAU,YAAY,CAChC,MAAqB,EACrB,UAAkB;IAElB,MAAM,UAAU,GAAG,gBAAgB,CAAC,UAAU,CAAC,CAAC;IAChD,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,KAAK,CAC5B,sDAAsD,EACtD,CAAC,UAAU,CAAC,CACb,CAAC;IACF,OAAO,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC;AAC7C,CAAC;AAEM,KAAK,UAAU,iBAAiB,CACrC,MAAqB;IAErB,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,KAAK,CAC5B,
|
|
1
|
+
{"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/schema/manager.ts"],"names":[],"mappings":";;AAGA,gDAKC;AAaD,4CAQC;AAED,oCAQC;AAED,gCAMC;AAED,oCAUC;AAED,8CAOC;AAED,wDAUC;AA9ED,yFAAyF;AACzF,SAAgB,kBAAkB,CAAC,UAAkB;IACnD,IAAI,CAAC,0BAA0B,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;QACjD,MAAM,IAAI,KAAK,CAAC,wBAAwB,UAAU,EAAE,CAAC,CAAC;IACxD,CAAC;IACD,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,wFAAwF;AACxF,SAAS,iBAAiB,CAAC,SAAiB;IAC1C,IAAI,CAAC,0BAA0B,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;QAChD,MAAM,IAAI,KAAK,CAAC,uBAAuB,SAAS,EAAE,CAAC,CAAC;IACtD,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,yEAAyE;AACzE,MAAM,oBAAoB,GAAG,EAAE,CAAC;AAEhC,SAAgB,gBAAgB,CAAC,UAAkB;IACjD,MAAM,UAAU,GAAG,UAAU,UAAU,EAAE,CAAC;IAC1C,IAAI,MAAM,CAAC,UAAU,CAAC,UAAU,CAAC,GAAG,oBAAoB,EAAE,CAAC;QACzD,MAAM,IAAI,KAAK,CACb,gCAAgC,UAAU,aAAa,oBAAoB,QAAQ,CACpF,CAAC;IACJ,CAAC;IACD,OAAO,UAAU,CAAC;AACpB,CAAC;AAEM,KAAK,UAAU,YAAY,CAChC,MAAqB,EACrB,UAAkB;IAElB,MAAM,UAAU,GAAG,kBAAkB,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC,CAAC;IACpE,0EAA0E;IAC1E,+CAA+C;IAC/C,MAAM,MAAM,CAAC,KAAK,CAAC,iBAAiB,UAAU,EAAE,CAAC,CAAC;AACpD,CAAC;AAEM,KAAK,UAAU,UAAU,CAC9B,MAAqB,EACrB,UAAkB;IAElB,MAAM,UAAU,GAAG,kBAAkB,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC,CAAC;IACpE,MAAM,MAAM,CAAC,KAAK,CAAC,yBAAyB,UAAU,UAAU,CAAC,CAAC;AACpE,CAAC;AAEM,KAAK,UAAU,YAAY,CAChC,MAAqB,EACrB,UAAkB;IAElB,MAAM,UAAU,GAAG,gBAAgB,CAAC,UAAU,CAAC,CAAC;IAChD,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,KAAK,CAC5B,sDAAsD,EACtD,CAAC,UAAU,CAAC,CACb,CAAC;IACF,OAAO,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC;AAC7C,CAAC;AAEM,KAAK,UAAU,iBAAiB,CACrC,MAAqB;IAErB,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,KAAK,CAC5B,oGAAoG,CACrG,CAAC;IACF,OAAO,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;AACxC,CAAC;AAEM,KAAK,UAAU,sBAAsB,CAC1C,MAAqB,EACrB,SAAiB,EACjB,UAAkB;IAElB,MAAM,SAAS,GAAG,iBAAiB,CAAC,SAAS,CAAC,CAAC;IAC/C,MAAM,UAAU,GAAG,kBAAkB,CAAC,UAAU,CAAC,CAAC;IAClD,MAAM,MAAM,CAAC,KAAK,CAChB,8BAA8B,UAAU,IAAI,SAAS,iBAAiB,SAAS,iBAAiB,CACjG,CAAC;AACJ,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stratum-hq/db-adapters",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"description": "Multi-tenant PostgreSQL row-level security for pg, Prisma, Drizzle, and Sequelize, plus schema-per-tenant and database-per-tenant isolation",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"multi-tenancy",
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"registry": "https://registry.npmjs.org/"
|
|
55
55
|
},
|
|
56
56
|
"dependencies": {
|
|
57
|
-
"@stratum-hq/core": "^1.
|
|
57
|
+
"@stratum-hq/core": "^1.6.0",
|
|
58
58
|
"pg": "^8.11.0"
|
|
59
59
|
},
|
|
60
60
|
"peerDependencies": {
|