feat(authz): add database-backed PermissionStore

Adds dbPermissionStore/ensureAuthzTables/authzMigrationSql, backed by
_wrn_authz_assignment and _wrn_authz_grant tables, plus a ./db subpath
export. Passes the identical 19-test store-conformance suite the memory
adapter passes, including tenant-scope isolation.
This commit is contained in:
2026-08-04 20:22:31 +05:30
parent 218f5e2dd6
commit 3fa3fce5df
6 changed files with 153 additions and 1 deletions
+43
View File
@@ -0,0 +1,43 @@
import type { Dialect } from "@wrnexus/db";
/**
* DDL for the two assignment tables. `scope` holds a tenant id, or the empty
* string for a global assignment, so the unique constraints work on every
* dialect (NULL is not comparable in a UNIQUE index).
*/
export function authzMigrationSql(dialect: Dialect): { up: string; down: string } {
const id =
dialect === "postgres"
? "SERIAL PRIMARY KEY"
: dialect === "mysql"
? "INT AUTO_INCREMENT PRIMARY KEY"
: "INTEGER PRIMARY KEY AUTOINCREMENT";
const timestamp = dialect === "sqlite" ? "TEXT" : "TIMESTAMP";
const now = "CURRENT_TIMESTAMP";
const up = `CREATE TABLE IF NOT EXISTS _wrn_authz_assignment (
id ${id},
subject_id VARCHAR(255) NOT NULL,
scope VARCHAR(255) NOT NULL DEFAULT '',
role VARCHAR(255) NOT NULL,
granted_by VARCHAR(255),
created_at ${timestamp} NOT NULL DEFAULT ${now},
CONSTRAINT _wrn_authz_assignment_unique UNIQUE (subject_id, scope, role)
);
CREATE TABLE IF NOT EXISTS _wrn_authz_grant (
id ${id},
subject_id VARCHAR(255) NOT NULL,
scope VARCHAR(255) NOT NULL DEFAULT '',
permission VARCHAR(255) NOT NULL,
effect VARCHAR(16) NOT NULL,
granted_by VARCHAR(255),
created_at ${timestamp} NOT NULL DEFAULT ${now},
CONSTRAINT _wrn_authz_grant_unique UNIQUE (subject_id, scope, permission)
);`;
const down = `DROP TABLE IF EXISTS _wrn_authz_grant;
DROP TABLE IF EXISTS _wrn_authz_assignment;`;
return { up, down };
}