add authz enforcement layer - #60
Closed
aberoham wants to merge 2 commits into
Closed
Conversation
v3 didn't have permission enforcement yet -- this adds it. Hapi onPreHandler plugin reads route metadata and runs checks before handlers execute, rather than scattering permission calls inside each one. authz.js is the engine (checkPermission, group tree walks, delegation lookups). authz-plugin.js wires it into Hapi's request lifecycle. All routes annotated with what they need. Delegation routes now cap submitted permissions by the caller's own permissions at write time, which matches how v2 does it. Unit tests for the Authz class and integration tests via server.inject() included. v2 xt permission tests (14_permissions, 20_permission) should still pass -- 4892/4892 last run. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- scope directly delegated record collections to the delegated rows instead of exposing every record in the zone - v2 writes root perm rows with uid=0; treat those like NULL - rebuild authorization ancestry when a group subtree moves - cap what a caller may grant or revoke, including explicit-row transitions and usable-nameserver edits; deny self-permission writes - revalidate sessions against live user/group/session rows and idle expiry before trusting credentials - rebuild record rows on type change so stale rdata columns clear; reuse deleted permission rows rather than accumulating duplicates
There was a problem hiding this comment.
Pull request overview
Adds centralized authorization enforcement, live session validation, delegation management, permission capping, and scoped resource access.
Changes:
- Introduces the Authz engine and Hapi enforcement plugin.
- Adds delegation routes and permission-aware resource handlers.
- Updates persistence logic and adds extensive authorization tests.
Reviewed changes
Copilot reviewed 33 out of 33 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
lib/authz.js |
Implements authorization rules. |
lib/authz-plugin.js |
Enforces route permissions and sessions. |
lib/authz.test.js |
Tests authorization behavior. |
lib/delegation.js |
Implements delegation persistence. |
lib/group/store/mysql.js |
Rebuilds group ancestry after moves. |
lib/group/test/index.js |
Tests group ancestry rebuilding. |
lib/permission/store/mysql.js |
Handles permission lookup, reuse, and updates. |
lib/permission/test/index.js |
Tests legacy and reused permissions. |
lib/session/store/mysql.js |
Supports distinct sessions and access timestamps. |
lib/session/test/index.js |
Tests concurrent login sessions. |
lib/user/store/mysql.js |
Fixes user creation and permission ownership. |
lib/user/test/index.js |
Tests user creation behavior. |
lib/zone/store/mysql.js |
Adds delegated zone query scopes. |
lib/zone_record/store/mysql.js |
Adds record scopes and type-change cleanup. |
lib/zone_record/test/index.js |
Tests record type changes. |
routes/authz.test.js |
Adds end-to-end authorization tests. |
routes/delegation.js |
Adds delegation HTTP endpoints. |
routes/group.js |
Secures group routes and permission updates. |
routes/group.test.js |
Updates authorized group fixtures. |
routes/index.js |
Registers authorization and delegation routes. |
routes/nameserver.js |
Secures nameserver routes. |
routes/nameserver.test.js |
Adds nameserver permission fixtures. |
routes/permission.js |
Secures permission CRUD operations. |
routes/permission.test.js |
Tests self-permission restrictions. |
routes/session.js |
Returns effective permissions with sessions. |
routes/session.test.js |
Tests revoked-session rejection. |
routes/test/permissions.js |
Provides route-test permission fixtures. |
routes/user.js |
Secures user and permission mutations. |
routes/user.test.js |
Adds user permission fixtures. |
routes/zone.js |
Secures and scopes zone operations. |
routes/zone.test.js |
Updates zone authorization fixtures. |
routes/zone_record.js |
Secures and scopes record operations. |
routes/zone_record.test.js |
Adds record permission fixtures. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
+211
to
+213
| request.payload = Authz.capPermissions(userPerm, request.payload, existingPerm) | ||
|
|
||
| const hasPermFields = Object.keys(request.payload).some((field) => PERM_FIELDS.has(field)) |
Comment on lines
+102
to
+116
| if ( | ||
| permCfg.targetCreateResource | ||
| && request.payload?.zid !== undefined | ||
| && await changesTarget(request, resource, action, objectId) | ||
| ) { | ||
| const target = await resolveTargetGroup(request, permCfg.targetCreateResource) | ||
| const targetResult = await Authz.checkPermission( | ||
| credentials, | ||
| permCfg.targetCreateResource, | ||
| 'create', | ||
| undefined, | ||
| { targetGroupId: target?.gid, targetZoneId: target?.zid }, | ||
| ) | ||
| if (!targetResult.allowed) return respond(targetResult, h) | ||
| } |
Comment on lines
+169
to
+173
| await Mysql.execute('START TRANSACTION') | ||
| try { | ||
| const r = await update() | ||
| await this.rebuildSubgroups(id) | ||
| await Mysql.execute('COMMIT') |
Comment on lines
+21
to
+22
| if (request.auth.isAuthenticated && !isLogin) { | ||
| const credentials = await Authz.getCurrentCredentials(request.auth.credentials) |
Comment on lines
+14
to
+18
| const G_ROOT = { | ||
| id: 4200, | ||
| parent_gid: 0, | ||
| name: 'authz-root', | ||
| } |
This was referenced Aug 24, 2026
aberoham
marked this pull request as ready for review
August 25, 2026 20:47
Contributor
Author
|
Superseded by #61, which contains this work rewritten across the store layer plus the fixes from its copilot review (self permission edits, cross-zone record moves, session activity refresh). |
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.
Spent Saturday side-eyeing Ox Alpha Free in a goal loop, a new preview model from GLM, checked by ChatGPT-5.6 Sol and Claude Fable. Here's where it got to:
v3 didn't enforce permissions yet -- now it does. A Hapi
onPreHandlerplugin readsapp.permissionmetadata off route configs and runs the check before the handler fires. Keeps authz centralized instead of scattered across handlers, which is how v2'sverify_obj_usage()worked conceptually.The main pieces:
lib/authz.js, the engine -- group tree ownership, delegation access in both directions (record delegations grant zone read; zone edits resolve through delegated records), per-resource permission checks. Mirrors v2'scheck_permission()flow.lib/authz-plugin.js-- wires it together, plus session revalidation against live user/group/session rows and idle expiry on every authenticated requestroutes/delegation.js-- extracted; caps submitted permissions by the caller's own at write timeSecond pass (review fixes):
Test coverage: unit tests for the Authz class against real MySQL, integration tests via
server.inject()through the full Hapi stack -- 486 tests, 485 passing, 1 skipped (pre-existing install-path test). All three v2 xt suites pass clean through the REST bridge: 5796/5796 across 14_permissions.t, 16_delegation.t, 20_permission.t.Known gap:
sql/10_nt_perm.sqlstill lacks a db uniqueness constraint on permission rows. Select/reuse logic stops sequential duplicates but simultaneous creates across instances could race; fixing it right needs a migration reconciling legacy NULL/0 rows first.