diff --git a/docs/plans/2026-08-04-authz-permissions-implementation.md b/docs/plans/2026-08-04-authz-permissions-implementation.md index 21c8903a..50fb10b7 100644 --- a/docs/plans/2026-08-04-authz-permissions-implementation.md +++ b/docs/plans/2026-08-04-authz-permissions-implementation.md @@ -1536,7 +1536,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, permission: string): boolean { if (granted.has("*") || granted.has(permission)) return true; for (let at = permission.indexOf(":"); at !== -1; at = permission.indexOf(":", at + 1)) { @@ -2408,6 +2414,8 @@ describe("@wrnexus/authz exports", () => { "createAuthzResolver", "expandRoles", "permissionMatches", + "scopeKey", + "safeRecord", "deniedBy", "authzMiddleware", "can",