release: 1.0.0

This commit is contained in:
2026-10-02 22:48:16 +02:00
parent e470b670c2
commit a1d6f471e2
30 changed files with 4424 additions and 134 deletions
+36 -6
View File
@@ -5,7 +5,7 @@
[![License: Apache 2.0](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://www.apache.org/licenses/LICENSE-2.0)
[![Node](https://img.shields.io/badge/Node-%3E%3D18-brightgreen.svg)](https://nodejs.org/)
This is the Node.js companion to the [`pgmorbac` PostgreSQL extension](https://git.villains.fr/crudy/pgmorbac). The extension implements the Multi-OrBAC access control model in the database (`morbac` schema); this package wires it into a Fastify backend: permission checks, a PostgREST data proxy, management routes, and the JSON schemas and domain types that go with them.
This is the Node.js companion to the [`pgmorbac` PostgreSQL extension](https://github.com/crudylabs/pgmorbac). The extension implements the Multi-OrBAC access control model in the database (`morbac` schema); this package wires it into a Fastify backend: permission checks, RLS session context, management routes, a PostgREST data proxy, and the migration loader that ships the extension SQL.
> The SQL extension is a separate project under the MIT license. This helper package is Apache-2.0. See [LICENSE](LICENSE) and [NOTICE](NOTICE).
@@ -23,12 +23,14 @@ The package is split into focused entry points so you only pull in what you need
| Import | Purpose |
|--------|---------|
| `@crudy/pgmorbac` | Shared domain types (`DataPermission`, `Org`, `Role`, `Rule`, ...) |
| `@crudy/pgmorbac` | RLS session context and shared domain types |
| `@crudy/pgmorbac/permissions` | `hasPermission`, org-scope resolution, admin checks |
| `@crudy/pgmorbac/proxy` | PostgREST data proxy with per-route permissions |
| `@crudy/pgmorbac/plugin` | Fastify management routes (orgs, roles, rules, users, delegations) |
| `@crudy/pgmorbac/list-query` | PostgREST-style sort/filter/pagination parsing |
| `@crudy/pgmorbac/schemas` | JSON schema response fragments |
| `@crudy/pgmorbac/api` | Domain type definitions |
| `@crudy/pgmorbac/migrations` | Loads the bundled `morbac` extension SQL as migrations |
| `@crudy/pgmorbac/api` | Domain type definitions (`Org`, `Role`, `Rule`, ...) |
## Usage
@@ -46,6 +48,19 @@ app.get('/documents', async (req, reply) => {
});
```
### RLS session context
Run queries under the acting user so `morbac` row-level security policies apply as a second gate behind `hasPermission`. Required for non-`BYPASSRLS` runtime roles.
```ts
import { withMorbacContext } from '@crudy/pgmorbac';
const rows = await withMorbacContext(pool, { userId, orgId }, async (client) => {
const { rows } = await client.query('SELECT * FROM app.orgs');
return rows;
});
```
### Data proxy
Expose an `app`-schema table through the backend with an explicit permission. A path that is never registered does not exist (fail closed).
@@ -59,6 +74,20 @@ proxy.proxyDataRoute(app, 'GET', '/data/documents', 'documents', { activity: 're
Pass `null` as the permission for any-authenticated-user access with no org check. Page size is capped at `MAX_PAGE_LIMIT` (1000); over-large `limit` values are rejected, never silently clamped.
### Migrations
The extension SQL ships inside this package (`sql/pgmorbac--<version>.sql`, plus `sql/upgrades/`). Feed it to your migration runner before your own DDL.
```ts
import { morbacMigrations } from '@crudy/pgmorbac/migrations';
for (const { filename, sql } of morbacMigrations()) {
await runMigration(filename, sql);
}
```
The base script keeps the historical filename `0001_morbac.sql` so `schema_migrations` rows on existing databases stay valid; upgrade scripts follow in version order.
### Management routes
Register CRUD routes for orgs, roles, rules, users, global rules, activities, and delegations. Supply optional hooks for license-limit enforcement and event emission.
@@ -77,12 +106,13 @@ createMgmtRoutes({
- **Deny by default.** Unregistered routes do not exist; unauthorized reads return `404` over `403` to avoid enumeration.
- **Reads are checked too.** List and detail routes require the same permission checks as writes.
- **Allowlisted queries.** Values are parameterized and columns allowlisted; user input is never interpolated.
- **Two gates stacked.** `hasPermission` (application) plus `morbac` RLS (database) when running under a non-`BYPASSRLS` role.
- **Allowlisted queries.** `list-query` parameterizes values and allowlists sortable/filterable columns; user input is never interpolated.
## Related
- [pgmorbac](https://git.villains.fr/crudy/pgmorbac) — the PostgreSQL extension (MIT)
- [Documentation](https://pgmorbac.villains.fr) — model, architecture, integration guides
- [pgmorbac](https://github.com/crudylabs/pgmorbac) — the PostgreSQL extension (MIT)
- [Documentation](https://pgmorbac.crudy.fr) — model, architecture, integration guides
## License