feat: add dependency-free permission-expression evaluator - #362
Merged
Lakes41 merged 1 commit intoAug 26, 2026
Merged
Conversation
Adds @guildpass/permission-expression, a pure evaluator for a constrained boolean permission-expression AST (permission/all/any/not). - Runtime-validates untrusted input against the AST grammar, rejecting malformed nodes and enforcing configurable max depth / max node count before any evaluation happens, bounding pathological and cyclic input. - No eval, no Function constructor, no dynamic code execution. - Deterministic, side-effect free evaluation with an explain mode that reports which leaves caused a denial. - No knowledge of memberships, Prisma, Fastify or Redis. Closes Adamantine-guild#348
Contributor
Author
|
@Lakes41 PR is ready for review — closes #348. All acceptance criteria are met: typed discriminated-union AST (permission/all/any/not), runtime validation with configurable maxDepth/maxNodes limits, deterministic side-effect-free evaluation with explain mode, no eval/Function usage, zero dependencies. |
Contributor
Author
Contributor
Author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Implements a dependency-free, pure evaluator for compound boolean permission expressions, as an isolated primitive independent of the broader GuildPass policy engine.
Adds
@guildpass/permission-expressionwith:permission(leaf),all,any,not.parsePermissionExpression(input, limits?)— validates untrusted runtime input (not just compile-time-typed input) against the grammar: rejects unknown node types, non-object nodes, empty/non-string permission values, and non-arraychildren. Enforces configurablemaxDepthandmaxNodeslimits, checked before recursing into children, so oversized fan-out or cyclic/self-referential input is rejected with bounded work instead of exhausting memory or the call stack.evaluatePermissionExpression(expression, grantedPermissions, { limits?, explain? })— pure, deterministic, side-effect free. Accepts aSet, array, or any iterable of granted permission strings. Noeval, noFunctionconstructor, no dynamic code execution.explain: truereturns the specific leaves responsible for a denial, including throughnot(the granted-but-forbidden leaf that triggered the negation).allis vacuously true; emptyanyis vacuously false — both explicitly defined and unit tested.Linked Issue
Closes #348
Type of Change
Changes Made
packages/permission-expression/src/index.ts— AST types,parsePermissionExpression,evaluatePermissionExpression,PermissionExpressionError.packages/permission-expression/src/index.test.ts— 36 unit tests: leaf checks,all/any/notsemantics, empty-collection semantics, nested combinations, malformed-input rejection, depth/node-count limits (including a 200k-wide fan-out and a self-referential cyclic node), and explain mode.packages/permission-expression/package.json,tsconfig.json— package scaffolding matching existing packages (quorum-engine,rate-limit).pnpm-lock.yaml— workspace registration for the new package.Test Evidence
Full workspace (
pnpm typecheck,pnpm build,pnpm test) also verified green across all existing packages andapps/api— no regressions.General Checklist
pnpm typecheckpassespnpm buildpassespnpm testpasses — all tests green.env.exampleupdated (N/A — no new env vars)Additional Notes
Deliberately scoped to stay independent of the wider policy engine: no membership lookups, database queries, or access API. Callers supply a set of granted permissions and an expression and receive a result.