Skip to content

fix(auth): prevent custom permission checks racing policy refresh - #2125

Merged
Eli Bosley (elibosley) merged 3 commits into
mainfrom
fix/casbin-permission-race
Oct 26, 2026
Merged

Eli Bosley (elibosley) merged 3 commits into
mainfrom
fix/casbin-permission-race

Conversation

@elibosley

@elibosley Eli Bosley (elibosley) commented Oct 25, 2026 •

Copy link
Copy Markdown
Member

Custom API keys could fail mixed GraphQL queries with Cannot read properties of undefined (reading '0') inside Casbin. Authentication cleared and rebuilt the shared permission rows while another authorization check was iterating them. This was discovered during post-merge QA of #2123 at 3371fd4.

This uses Casbin’s existing synchronized enforcer to serialize checks with policy mutations. Permission synchronization now removes obsolete grants and adds missing grants, preserving unchanged grants during repeated authentication. Permission changes still apply on the next authentication; no permission cache, schema change or migration is introduced.

Reviewer consideration: authorization checks now share Casbin’s dependency-owned lock. This prevents concurrent policy mutation; unchanged keys avoid policy writes. An in-flight check finishes before revocation, and later checks observe the revoked permission.

Validation: all 366 authentication tests, API type-check, API lint and authorization coverage lint passed locally. Six integration regressions cover 48 concurrent HTTP queries with granted/denied fields, unchanged refreshes, changed permissions, wildcard/empty permissions, a deterministically paused authorization check overlapping policy removal, and lock recovery after a failed check. The deterministic overlap reproduced the exact exception before the fix. Exact-head CI build/test and CodeQL passed; the advisory dependency audit still fails. The packaged plugin from run 40244541250 was installed on a managed Unraid 7.4.0-rc.1 QA VM, and all 32 packaged API dist files matched the downloaded CI payload.

Appliance QA passed 300 real HTTP requests, including 288 requests at concurrency 24 across two distinct GUEST keys. Cases covered stable grants and cross-key denial, actual unavailable Docker/libvirt backends with healthy notification data retained, denied API-key mutation without side effects, revocation and restoration on subsequent requests, empty custom grants with an explicit GUEST role, ADMIN/VIEWER compatibility, and persisted grants/revocations after service restart. Zero Casbin type errors were logged. Observed p95 request latency was 49 ms (diagnostic, not a comparative performance claim).

All five temporary keys were deleted and verified absent through the native CLI. Notification configuration remained byte-for-byte unchanged. Provider rollback completed, and a fresh check confirmed the reservation absent and the capacity available and powered off. PR remains unmerged.

Summary by CodeRabbit

  • Bug Fixes
    • Improved API key permission updates to avoid temporarily clearing all access grants during synchronization.
    • Permission changes are applied more consistently during concurrent requests, while outdated grants are removed and unchanged grants are retained.
    • Updated permissions, including wildcard grants, are reflected in subsequent authorization checks.

Reproduced from PR #2123 post-merge QA at 3371fd4: concurrent custom-permission checks raised a Casbin TypeError when authentication removed rows during enforcement. Use the existing synchronized enforcer and preserve unchanged grants. Cover HTTP concurrency, denial, revocation, and an explicitly held in-flight read.
@coderabbitai

coderabbitai Bot commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review.

Recent review info
Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 37a10a83-a161-4e0d-bfe1-ec6914db8ce8
Commits

Reviewing files that changed from the base of the PR and between 3371fd4 and c014b2f.

Files selected for processing: 4
  • .limetech/ai-review-markers/fix-casbin-permission-race-4f61c40b0160.json
  • api/src/unraid-api/auth/auth.service.ts
  • api/src/unraid-api/auth/casbin/casbin.service.ts
  • api/src/unraid-api/auth/casbin/permission-sync.integration.spec.ts

Included review availability: This review used your included allowance. Your plan provides up to 2 included reviews per hour; 1 remain after this review.

Walkthrough

API key permission synchronization now preserves requested grants, removes stale grants, and adds only missing grants. Casbin initialization uses a synchronized enforcer. New integration tests cover concurrent authorization and permission updates.

Changes

API key authorization

Layer / File(s) Summary
Reconcile API key permissions
api/src/unraid-api/auth/auth.service.ts, .limetech/ai-review-markers/fix-casbin-permission-race-4f61c40b0160.json
Permission synchronization retains requested grants, removes stale grants, and adds only missing grants. A review marker records the final-stage disposition.
Synchronize enforcement and test permission updates
api/src/unraid-api/auth/casbin/casbin.service.ts, api/src/unraid-api/auth/casbin/permission-sync.integration.spec.ts
Casbin initialization now uses a synchronized enforcer. Integration tests cover concurrent GraphQL authorization, changed and wildcard permissions, in-flight checks during removal, and recovery after a failed role lookup.

Priority: Normal

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Bug fix

Possibly related PRs

  • unraid/api#2123: Its mixed GraphQL query scenario exposed the authorization race addressed here.

Suggested reviewers: pujitm

Merge Risk: Minimal · up to c014b

No actionable issue remains identified in the permission-race fix; it is ready for normal merge checks.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 1 functions across 3 files. (1 skipped: 1 … Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title names the main change: it fixes a race in the auth layer where custom permission checks could run during a policy refresh. The changeset supports this. The auth service now syncs permissions…
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Full details: Title check

Explanation

The title names the main change: it fixes a race in the auth layer where custom permission checks could run during a policy refresh. The changeset supports this. The auth service now syncs permissions without deleting all grants first, and the Casbin service uses a synchronized enforcer that serializes checks with policy mutations. The title uses the conventional commit form and stays under 72 characters. It does not name the synchronized enforcer or the permission-preserving sync, but those are secondary details.

Full details: Docstring Coverage

Explanation

Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 1 functions across 3 files. (1 skipped: 1 unsupported.)

Resolution

Write docstrings for the functions missing them to satisfy the coverage threshold.

Finishing Touches: 💡 1
📝 Generate docstrings: 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

A rabbit checks each grant in line,
Keeps the matches, drops the stale.
Casbin guards the checks in time,
While tests run requests without fail.
Fresh permissions take their place,
And carrots wait beside the case.

Comment @coderabbitai help to get the list of available commands.

@linear-code
linear-code Bot marked this pull request as ready for review October 25, 2026 23:28
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 25, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review 🔄 Running since 2026-10-26T00:25:04.933689Z c014b2f Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@codecov

codecov Bot commented Oct 25, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 53.94%. Comparing base (3371fd4) to head (c014b2f).

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2125      +/-   ##
==========================================
+ Coverage   53.90%   53.94%   +0.03%     
==========================================
  Files        1046     1046              
  Lines       73596    73606      +10     
  Branches     8818     8828      +10     
==========================================
+ Hits        39675    39707      +32     
+ Misses      33793    33771      -22     
  Partials      128      128              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions

Copy link
Copy Markdown
Contributor

This plugin has been deployed to Cloudflare R2 and is available for testing.
Download it at this URL:

https://preview.dl.unraid.net/unraid-api/tag/PR2125/dynamix.unraid.net.plg

@elibosley
Eli Bosley (elibosley) marked this pull request as draft October 25, 2026 23:43
@elibosley
Eli Bosley (elibosley) marked this pull request as ready for review October 26, 2026 00:24
@elibosley
Eli Bosley (elibosley) merged commit 05ba1bf into main Oct 26, 2026
13 of 14 checks passed
@elibosley
Eli Bosley (elibosley) deleted the fix/casbin-permission-race branch October 26, 2026 00:25
@github-actions

Copy link
Copy Markdown
Contributor

🔄 PR Merged - Plugin Redirected to Staging

This PR has been merged and the preview plugin has been updated to redirect to the staging version.

For users testing this PR:

  • Your plugin will automatically update to the staging version on the next update check
  • The staging version includes all merged changes from this PR
  • No manual intervention required

Staging URL:

https://preview.dl.unraid.net/unraid-api/dynamix.unraid.net.plg

Thank you for testing! 🚀

Eli Bosley (elibosley) added a commit that referenced this pull request Oct 26, 2026
🤖 I have created a release *beep* *boop*
---


## [4.37.8](v4.37.7...v4.37.8)
(2026-10-26)


### Bug Fixes

* **api:** preserve partial results and accurate notification counts
([#2123](#2123))
([3371fd4](3371fd4))
* **auth:** limit repeated authorization requests
([#2094](#2094))
([e160a4e](e160a4e))
* **auth:** prevent custom permission checks racing policy refresh
([#2125](#2125))
([05ba1bf](05ba1bf))
* **graphql:** bound request size and expanded selections
([#2121](#2121))
([0c60d9d](0c60d9d))
* **graphql:** filter schema metadata requests
([#2095](#2095))
([dcd396e](dcd396e))
* **settings:** omit internal provider values
([#2096](#2096))
([30e8d6a](30e8d6a))
* **updates:** embed internal OS checks on Tools page
([#2020](#2020))
([b95ae92](b95ae92))
* **web:** restore right-side banner fade on legacy headers
([#2126](#2126))
([da7b87d](da7b87d))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Eli Bosley <11823237+elibosley@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant