43 lines
1.8 KiB
TypeScript
43 lines
1.8 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import { test } from "bun:test";
|
|
|
|
import { createOpenFgaAuthorizer } from "./openfga-authorization.ts";
|
|
|
|
test("OpenFGA shadow mode is normalized to enforce and denies without a tuple", async () => {
|
|
const calls: Array<{ path: string; method: string }> = [];
|
|
const authorizer = createOpenFgaAuthorizer({
|
|
env: { HWLAB_OPENFGA_MODE: "shadow", HWLAB_OPENFGA_API_URL: "http://openfga.test" },
|
|
fetchImpl: async (url: string | URL, init: RequestInit = {}) => {
|
|
const parsed = new URL(String(url));
|
|
calls.push({ path: parsed.pathname, method: init.method ?? "GET" });
|
|
if (parsed.pathname === "/healthz") return jsonResponse({}, 200);
|
|
if (parsed.pathname === "/stores") return jsonResponse({ id: "store-shadow" }, 201);
|
|
if (parsed.pathname === "/stores/store-shadow/authorization-models") return jsonResponse({ authorization_model_id: "model-shadow" }, 201);
|
|
if (parsed.pathname === "/stores/store-shadow/check") return jsonResponse({ allowed: false }, 200);
|
|
return jsonResponse({ error: "unexpected path" }, 404);
|
|
}
|
|
});
|
|
|
|
const decision = await authorizer.check({
|
|
actor: { id: "usr_shadow", role: "user" },
|
|
relation: "can_use",
|
|
object: "tool:hwpod"
|
|
});
|
|
|
|
assert.equal(decision.mode, "enforce");
|
|
assert.equal(decision.allowed, false);
|
|
assert.equal(decision.fgaAllowed, false);
|
|
assert.equal(decision.decisionSource, "openfga");
|
|
assert.deepEqual(calls.map((call) => call.path), [
|
|
"/healthz",
|
|
"/stores",
|
|
"/stores/store-shadow/authorization-models",
|
|
"/stores/store-shadow/check",
|
|
"/stores/store-shadow/check"
|
|
]);
|
|
});
|
|
|
|
function jsonResponse(body: unknown, status: number) {
|
|
return new Response(JSON.stringify(body), { status, headers: { "content-type": "application/json" } });
|
|
}
|