fix(authz): strengthen permissionMatches warning, complete export coverage

Move the "don't gate on permissionsFor() with permissionMatches" warning
onto permissionMatches itself so it's visible via autocomplete, not just
on AuthzResolver.permissionsFor. Round out exports.test.ts to cover
scopeKey, safeRecord, and AUTHZ_LOCALS_KEY, closing the gap where
dropping either export from index.ts would not fail the test.
This commit is contained in:
2026-08-04 19:38:07 +05:30
parent e05ddc7aa5
commit 703baa1ead
2 changed files with 13 additions and 1 deletions
+7 -1
View File
@@ -54,7 +54,13 @@ export function expandRoles(catalog: AuthzCatalog, roles: readonly string[]): Se
return out;
}
/** Exact match, root wildcard, or a namespace wildcard at any depth. */
/**
* Exact match, root wildcard, or a namespace wildcard at any depth.
*
* Do NOT gate access by matching against `permissionsFor()`'s result — that set
* cannot represent a narrow deny beneath a broad grant, so the composition
* returns true where `decide()` refuses. Use `decide()` / `can()` instead.
*/
export function permissionMatches(granted: Set<string>, permission: string): boolean {
if (granted.has("*") || granted.has(permission)) return true;
for (let at = permission.indexOf(":"); at !== -1; at = permission.indexOf(":", at + 1)) {
+6
View File
@@ -43,8 +43,14 @@ describe("@wrnexus/authz exports", () => {
"decideFor",
"guardPermission",
"filterCan",
"scopeKey",
"safeRecord",
]) {
expect(typeof (authz as Record<string, unknown>)[name]).toBe("function");
}
});
test("exports the locals key used to reach the per-request resolver", () => {
expect(typeof (authz as Record<string, unknown>).AUTHZ_LOCALS_KEY).toBe("string");
});
});