feat: add authorization bootstrap and HTTP enforcement
Wires Core's identity and authorization domains into apps/api over one shared, validated PostgreSQL pool; adds an explicit, single-use, concurrency-safe platform-owner bootstrap CLI; adds a smallest-possible immutable permission registry with one Core-owned restricted permission (core.authorization.grants.manage); and adds reusable Hono authorization enforcement plus a narrowly scoped /api/v1/grants HTTP API for managing explicit grants only, gated by an exact trusted Origin on every mutation.
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
import { parsePermissionId } from "@ekklesia/contracts";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
CORE_AUTHORIZATION_GRANTS_MANAGE,
|
||||
CORE_PERMISSION_REGISTRY,
|
||||
createPermissionRegistry,
|
||||
PermissionRegistryError,
|
||||
} from "../src/authorization/index.js";
|
||||
|
||||
describe("createPermissionRegistry", () => {
|
||||
it("builds an immutable registry from a fixed declaration list", () => {
|
||||
const id = parsePermissionId("test.example.read");
|
||||
const registry = createPermissionRegistry([
|
||||
{ baseline: "public", description: "An example permission.", id },
|
||||
]);
|
||||
|
||||
expect(registry.has(id)).toBe(true);
|
||||
expect(registry.get(id)).toEqual({
|
||||
baseline: "public",
|
||||
description: "An example permission.",
|
||||
id,
|
||||
});
|
||||
expect(Object.isFrozen(registry)).toBe(true);
|
||||
expect(Object.isFrozen(registry.declarations)).toBe(true);
|
||||
expect(Object.isFrozen(registry.get(id))).toBe(true);
|
||||
});
|
||||
|
||||
it("rejects a duplicate permission id at composition time, not per request", () => {
|
||||
const id = parsePermissionId("test.example.read");
|
||||
expect(() =>
|
||||
createPermissionRegistry([
|
||||
{ baseline: "public", description: "First.", id },
|
||||
{ baseline: "restricted", description: "Second.", id },
|
||||
]),
|
||||
).toThrow(PermissionRegistryError);
|
||||
});
|
||||
|
||||
it("carries the offending permission id on the duplicate-declaration error (a composition-time, developer-facing detail, not a runtime response)", () => {
|
||||
const id = parsePermissionId("test.example.read");
|
||||
let captured: unknown;
|
||||
try {
|
||||
createPermissionRegistry([
|
||||
{ baseline: "public", description: "First.", id },
|
||||
{ baseline: "restricted", description: "Second.", id },
|
||||
]);
|
||||
} catch (error) {
|
||||
captured = error;
|
||||
}
|
||||
expect(captured).toBeInstanceOf(PermissionRegistryError);
|
||||
expect(captured).toMatchObject({
|
||||
code: "PERMISSION_REGISTRY_DUPLICATE_DECLARATION",
|
||||
permissionId: id,
|
||||
});
|
||||
});
|
||||
|
||||
it("treats an unregistered permission the same as a malformed one: get/has both fail closed", () => {
|
||||
const registered = parsePermissionId("test.example.read");
|
||||
const unregistered = parsePermissionId("test.example.unregistered");
|
||||
const registry = createPermissionRegistry([
|
||||
{ baseline: "public", description: "Registered.", id: registered },
|
||||
]);
|
||||
|
||||
expect(registry.has(unregistered)).toBe(false);
|
||||
expect(registry.get(unregistered)).toBeUndefined();
|
||||
});
|
||||
|
||||
it("fails closed for a malformed permission id passed to get/has, without throwing", () => {
|
||||
const registry = createPermissionRegistry([]);
|
||||
|
||||
expect(registry.has("not a valid permission")).toBe(false);
|
||||
expect(registry.get(null)).toBeUndefined();
|
||||
expect(registry.get(undefined)).toBeUndefined();
|
||||
expect(registry.get(42)).toBeUndefined();
|
||||
expect(registry.get("media.*")).toBeUndefined();
|
||||
});
|
||||
|
||||
it("builds an empty registry from an empty list without error", () => {
|
||||
const registry = createPermissionRegistry([]);
|
||||
expect(registry.declarations).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("CORE_PERMISSION_REGISTRY", () => {
|
||||
it("registers exactly core.authorization.grants.manage as restricted", () => {
|
||||
const declaration = CORE_PERMISSION_REGISTRY.get(CORE_AUTHORIZATION_GRANTS_MANAGE);
|
||||
expect(declaration).toBeDefined();
|
||||
expect(declaration?.baseline).toBe("restricted");
|
||||
expect(declaration?.id).toBe("core.authorization.grants.manage");
|
||||
});
|
||||
|
||||
it("contains no other permission in this slice", () => {
|
||||
expect(CORE_PERMISSION_REGISTRY.declarations).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user