Skip to content

Conversation

@dbarzin
Copy link
Owner

@dbarzin dbarzin commented Nov 15, 2025

Summary by CodeRabbit

  • Performance Improvements

    • Faster list views via optimized queries and eager-loading.
    • Authorization checks now use caching to reduce database load; cache refreshes when roles/permissions change.
  • Changes

    • Authentication now stores enriched role/permission data in the session.
    • Global authorization layer respects session-stored permissions for quicker allow/deny decisions.
  • Chores

    • Version bumped to 2025.11.15.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 15, 2025

Walkthrough

Eager-loading and query ordering were added to several admin controllers; a LoginController authenticated hook stores roles/permissions in session; permission→roles mappings are cached with invalidation on role/permission changes; a Gate::before hook checks session permissions; small formatting and version bumps applied.

Changes

Cohort / File(s) Summary
Query optimization (controllers)
app/Http/Controllers/Admin/SubnetworkController.php, app/Http/Controllers/Admin/DataProcessingController.php
Replace collection sorting with query-level ordering and add eager loading via with(...) for related models.
Authentication enrichment
app/Http/Controllers/Auth/LoginController.php
Add protected authenticated(Request $request, User $user): void hook that loadMissing('roles.permissions') and writes auth_role_ids and auth_permissions to session; comments added in LDAP login path.
Permission caching & gate checks
app/Http/Middleware/AuthGates.php, app/Providers/AuthServiceProvider.php
Implement Cache::rememberForever('permissions_roles_map') for permission→role mappings and refactor gate check to use collection ops; add Gate::before hook to auto-authorize abilities found in session permissions.
Cache invalidation (models & controller)
app/Models/Permission.php, app/Models/Role.php, app/Http/Controllers/Admin/RolesController.php
Add booted() model hooks to Permission and Role to Cache::forget('permissions_roles_map') on save/delete; call Cache::forget('permissions_roles_map') after syncing permissions in RolesController.
Formatting & version bump
app/Http/Kernel.php, package.json, version.txt
Inserted blank-line whitespace in Kernel.php web middleware group; bumped version strings from 2025.11.13 to 2025.11.15 in package.json and version.txt.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant LoginCtrl as LoginController
    participant DB as Database
    participant Cache
    participant AuthProv as AuthServiceProvider
    participant AuthGates

    User->>LoginCtrl: Submit credentials
    LoginCtrl->>DB: Validate / find user
    DB-->>LoginCtrl: User model
    LoginCtrl->>LoginCtrl: sendLoginResponse()
    LoginCtrl->>DB: loadMissing(roles.permissions)
    DB-->>LoginCtrl: Roles & permissions
    LoginCtrl->>User: set session (`auth_role_ids`, `auth_permissions`)

    User->>AuthProv: Request action (Gate::authorize)
    AuthProv->>AuthProv: Gate::before checks session permissions
    alt permission in session
        AuthProv-->>User: Authorized (true)
    else
        AuthProv->>AuthGates: Evaluate gate
        AuthGates->>Cache: rememberForever('permissions_roles_map')
        alt cache hit
            Cache-->>AuthGates: permission→roles map
        else cache miss
            AuthGates->>DB: Fetch roles with permissions
            DB-->>AuthGates: roles & permissions
            AuthGates->>Cache: store map
        end
        AuthGates-->>AuthProv: Allow/deny
        AuthProv-->>User: Result
    end

    Note right of Cache: Model events / RolesController call Cache::forget on changes
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Review cache key shape and map structure in AuthGates to ensure permission title keys and role ID arrays match checks.
  • Verify session payload (auth_role_ids, auth_permissions) shapes and types consumed by Gate::before.
  • Confirm model booted() listeners and RolesController cache forget cover all mutation paths (save/delete/sync).
  • Validate the eager-loading changes do not introduce unintended N+1 queries in different call sites.

Poem

🐰
I hopped through code with glee,
Caching roles beneath a tree,
Gates now check what sessions show,
Models clear when changes blow,
Version bumped — a tidy spree!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 30.77% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The title 'implement user cache + code review' is vague and overly broad. It does not clearly specify what caching is being implemented or what code review changes are included. Revise the title to be more specific and descriptive, such as 'Implement permission roles caching and optimize query eager loading' or similar, to clearly convey the main changes.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch dev

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between bed927d and a063a15.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (3)
  • app/Http/Controllers/Admin/RolesController.php (3 hunks)
  • package.json (1 hunks)
  • version.txt (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • app/Http/Controllers/Admin/RolesController.php
  • version.txt
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (1)
package.json (1)

15-15: Version bump is appropriate.

The version number is updated to match today's date, consistent with the project's date-based versioning scheme (YYYY.MM.DD). Ensure that version.txt or other version tracking files are kept in sync.


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

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

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🧹 Nitpick comments (3)
app/Http/Middleware/UseCachedAuthUser.php (1)

12-12: Consider translating comments to English for consistency.

The French comment reduces code consistency in an English codebase.

app/Http/Controllers/Auth/LoginController.php (1)

33-39: Consider translating French comments to English.

For codebase consistency, consider translating the French comments to English.

Also applies to: 48-49, 169-170

app/Http/Middleware/AuthGates.php (1)

38-41: Approve: Collection operations are more idiomatic.

The refactor from count(array_intersect(...)) to ->pluck('id')->intersect($roles)->isNotEmpty() is a good improvement. Collection operations are more readable and align with Laravel best practices.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between 6635482 and f34fc49.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (9)
  • app/Http/Controllers/Admin/SubnetworkController.php (1 hunks)
  • app/Http/Controllers/Auth/LoginController.php (2 hunks)
  • app/Http/Kernel.php (1 hunks)
  • app/Http/Middleware/AuthGates.php (1 hunks)
  • app/Http/Middleware/UseCachedAuthUser.php (1 hunks)
  • app/Models/Permission.php (2 hunks)
  • app/Models/Role.php (2 hunks)
  • package.json (1 hunks)
  • version.txt (1 hunks)
🧰 Additional context used
🪛 PHPMD (2.15.0)
app/Http/Controllers/Auth/LoginController.php

40-40: Avoid unused parameters such as '$request'. (undefined)

(UnusedFormalParameter)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (7)
app/Http/Controllers/Admin/SubnetworkController.php (1)

22-25: LGTM! Excellent performance optimization.

The change from all()->sortBy('name') to query builder with eager loading and database-level sorting effectively reduces N+1 queries and improves performance by leveraging the database for sorting.

version.txt (1)

1-1: LGTM!

Standard version bump.

package.json (1)

15-15: LGTM!

Version bump is consistent with version.txt.

app/Models/Permission.php (1)

32-41: Verify cache invalidation triggers for pivot changes.

Similar to the Role model, ensure that when permissions are attached/detached from roles via pivot operations ($permission->roles()->attach(), sync(), etc.), the cache is properly invalidated. The saved event may not fire for pivot-only changes.

app/Http/Kernel.php (1)

29-31: LGTM! Proper middleware placement.

The middleware is correctly positioned after StartSession (so session data is available) and before ShareErrorsFromSession and AuthGates (so the cached user is available for error context and authorization checks).

app/Http/Middleware/AuthGates.php (2)

6-9: LGTM: Imports are correctly used.

The new imports (User, Auth, Cache) are all properly utilized in the caching implementation and Gate definitions.


36-42: No issues found—roles are properly eager-loaded and cached.

The code is correctly designed to avoid N+1 queries:

  • LoginController::authenticated() eagerly loads roles via loadMissing(['roles:id,title', 'roles.permissions:id,title'])
  • The enriched user is stored in session
  • UseCachedAuthUser middleware runs before AuthGates and restores the cached user with loaded relationships
  • When $user->roles is accessed in the Gate callback (line 38), the collection is already in memory—no database query occurs

The collection operations (pluck, intersect, isNotEmpty) are safe and idiomatic for this cached user context.

Comment on lines 40 to 51
protected function authenticated(Request $request, $user): void
{
/** @var \App\Models\User $user */
$user->loadMissing([
'roles:id,title',
'roles.permissions:id,title',
]);

// Optionnel : mettre l'utilisateur enrichi en session
// (utile si tu ajoutes ensuite un middleware qui fait Auth::setUser(session('auth_user')))
session(['auth_user' => $user]);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

Verify User model serialization for session storage.

The authenticated hook correctly eager loads relationships to reduce N+1 queries. However, storing Eloquent models with loaded relationships in the session can be problematic:

  1. Serialization concerns: Eloquent models may not serialize/unserialize cleanly, especially with relationships.
  2. Session size: Storing the full user object with relationships increases session payload.
  3. Stale data: The cached user won't reflect changes made in other requests until the next login.

The cache invalidation in Permission/Role models won't affect already-stored session users.

Consider running the following to verify serialization behavior:


🏁 Script executed:

#!/bin/bash
# Check if User model has custom serialization methods
ast-grep --pattern 'class User $$$' | head -20
rg -n -A5 'function __sleep|function __wakeup|function __serialize|function __unserialize' app/Models/User.php

Length of output: 1104


I need to gather more information to verify the serialization concerns. Let me inspect the User model relationships and session configuration.


🏁 Script executed:

#!/bin/bash
# Find roles relationship in User model
rg -n -A10 'function roles|public function roles|protected function roles' app/Models/User.php

# Check session configuration
cat config/session.php | head -50

# Check if there's any session middleware or custom serialization
rg -rn 'Session|serialize|unserialize' config/ | grep -v node_modules | head -20

Length of output: 2575


I need to verify whether storing Eloquent models with relationships in sessions is actually problematic in modern Laravel. Let me search for documentation on this.


🌐 Web query:

Laravel Eloquent model serialization session storage file driver

💡 Result:

Short answer: don’t store full Eloquent model instances in the session file driver — store the model ID (or a small DTO/array) and re-retrieve the model on request. Storing models directly causes large session payloads, stale data, and (with file sessions) slower disk I/O and potential unserialize issues. [1][2][3]

Why and practical guidance

  • File driver stores serialized session payloads under storage/framework/sessions; Laravel serializes the PHP data when writing and unserializes when reading, so any object you put into session is serialized to disk. Large or complex models bloat those files and slow every request for that session. [1][2]
  • Serialization vs restoration: Laravel’s SerializesModels / SerializesAndRestoresModelIdentifiers behavior is used for queued jobs (it serializes model identifiers and re-fetches on unserialize). Plainly placing a Model in session does not automatically get that safe ID-based behavior unless you explicitly implement it. Prefer storing the model key and re-querying (e.g., session(['user_id' => $user->id]); $user = User::find(session('user_id'))). [3][4]
  • Performance & safety: large sessions increase disk I/O and memory per request; file sessions don’t scale across multiple servers unless shared storage; unserialize requires the class to exist and can cause subtle errors after code changes. Use Redis/DB for larger session needs. [1][2][5]

Quick recommendations

  • Store primitive identifiers (IDs) or small arrays of attributes in session. Rehydrate with a fresh DB query when needed. [3][4]
  • If you must preserve an object-like shape, store a compact array/DTO (only the fields needed) rather than the full model.
  • For cross-server scaling or heavy session usage, switch from file to Redis or database sessions. [1][2]
  • If you’re serializing models intentionally (e.g., for jobs), use Laravel’s SerializesModels/SerializesAndRestoresModelIdentifiers to serialize IDs and restore on unserialize. [3][4]

Sources

  • Laravel Session documentation (file/database/redis drivers, storage path). [1][2]
  • Explanation of SerializesModels / model identifier serialization used by jobs. [3][4]
  • Best-practice notes about session size and storing models (community/docs). [5]

Would you like example code showing a safe pattern (store id + rehydrate) or how to convert an Eloquent model to a small DTO for the session?


Store user ID in session instead of full model; re-fetch on request.

Storing the complete Eloquent model with loaded relationships in the session is a documented anti-pattern in Laravel. File driver stores serialized session payloads under storage/framework/sessions; large or complex models bloat those files and slow every request for that session. Additionally, plainly placing a Model in session does not automatically get safe ID-based behavior; prefer storing the model key and re-querying.

Recommended fix:

protected function authenticated(Request $request, $user): void
{
    session(['user_id' => $user->id]);
}

Then re-fetch the user with relationships in a middleware or when needed:

$user = Auth::user()->load(['roles:id,title', 'roles.permissions:id,title']);

This eliminates session bloat, prevents stale data, and ensures fresh data from the database on each request.

🧰 Tools
🪛 PHPMD (2.15.0)

40-40: Avoid unused parameters such as '$request'. (undefined)

(UnusedFormalParameter)

🤖 Prompt for AI Agents
In app/Http/Controllers/Auth/LoginController.php around lines 40–51, the
authenticated() method stores the full Eloquent User model (with loaded
relations) into session which bloats session storage and is an anti-pattern;
instead store only the user primary key (e.g., user_id) in session and remove
the session(['auth_user' => $user]) call, then ensure any middleware or later
request-side logic re-fetches the user and eager-loads needed relationships via
a fresh query or Auth::user()->load([...]) when needed.

Comment on lines +16 to +18
// ⚠️ Ici, Auth::user() ne doit plus taper la DB
// grâce à ton middleware UseCachedAuthUser placé AVANT dans Kernel.php
$user = Auth::user();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

Verify middleware ordering in Kernel.php.

The implementation relies on UseCachedAuthUser middleware being executed before AuthGates to avoid database hits when calling Auth::user(). Please confirm that the middleware stack in Kernel.php properly orders these middlewares.


🏁 Script executed:

#!/bin/bash
# Description: Verify middleware ordering in Kernel.php

# Check the middleware stack to ensure UseCachedAuthUser comes before AuthGates
rg -n -A10 -B5 "UseCachedAuthUser|AuthGates" app/Http/Kernel.php

Length of output: 1337


Add UseCachedAuthUser middleware to the 'api' middleware group.

The 'web' middleware group correctly orders UseCachedAuthUser (line 30) before AuthGates (line 35). However, the 'api' middleware group includes AuthGates (line 22) without UseCachedAuthUser, meaning API requests will still query the database when Auth::user() is called. Add UseCachedAuthUser to the 'api' group to ensure consistent caching behavior:

'api' => [
    'throttle:60,1',
    'bindings',
    \App\Http\Middleware\UseCachedAuthUser::class,  // Add this
    \App\Http\Middleware\AuthGates::class,
],
🤖 Prompt for AI Agents
In app/Http/Middleware/AuthGates.php around lines 16-18 Auth::user() is being
called and relies on the UseCachedAuthUser middleware to avoid DB hits; update
app/Http/Kernel.php and add \App\Http\Middleware\UseCachedAuthUser::class into
the 'api' middleware group immediately before
\App\Http\Middleware\AuthGates::class so API requests run the caching middleware
first and Auth::user() no longer queries the database.

$roles = Role::with('permissions')->get();
$permissionsArray = [];
// 🧠 On met en cache le mapping permission → [roles_ids]
$permissionsArray = Cache::rememberForever('permissions_roles_map', function () {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Consider namespacing the cache key.

The cache key 'permissions_roles_map' is not namespaced or prefixed, which could cause conflicts if:

  • Multiple Laravel applications share the same cache store
  • The application uses multi-tenancy

Consider using a prefixed key like config('app.name') . ':permissions_roles_map' or leveraging Laravel's cache tagging (if supported by your cache driver).

-            $permissionsArray = Cache::rememberForever('permissions_roles_map', function () {
+            $permissionsArray = Cache::rememberForever(config('app.name') . ':permissions_roles_map', function () {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
$permissionsArray = Cache::rememberForever('permissions_roles_map', function () {
$permissionsArray = Cache::rememberForever(config('app.name') . ':permissions_roles_map', function () {
🤖 Prompt for AI Agents
In app/Http/Middleware/AuthGates.php around line 22 the cache key
'permissions_roles_map' is global and can collide across apps/tenants; change
the key to be namespaced (for example prefix with config('app.name') or the
current tenant identifier) or use Cache tags when supported by the driver.
Update the Cache::rememberForever call to build a namespaced key (e.g.
config('app.name').':permissions_roles_map' or
tenant()->id.':permissions_roles_map') or replace rememberForever with tagged
cache usage (Cache::tags(...)->rememberForever(...)) so keys are isolated.

Comment on lines +22 to +33
$permissionsArray = Cache::rememberForever('permissions_roles_map', function () {
$roles = Role::with('permissions')->get();
$map = [];

foreach ($roles as $role) {
foreach ($role->permissions as $permissions) {
$permissionsArray[$permissions->title][] = $role->id;
foreach ($roles as $role) {
foreach ($role->permissions as $permission) {
$map[$permission->title][] = $role->id;
}
}
}

return $map;
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

Verify cache invalidation and memory usage.

The implementation uses Cache::rememberForever(), which relies on explicit invalidation. Please confirm:

  1. Cache invalidation: The Permission and Role models properly invalidate the 'permissions_roles_map' cache in their model hooks when changes occur.
  2. Memory usage: Loading all roles with their permissions into memory (line 23) could be problematic if the system has thousands of roles/permissions. Verify this is acceptable for your expected data scale.

🏁 Script executed:

#!/bin/bash
# Description: Verify cache invalidation hooks in Permission and Role models

# Check Permission model for cache invalidation
echo "=== Permission Model Cache Invalidation ==="
rg -n -A15 "booted|saved|deleted" app/Models/Permission.php | rg -A10 "permissions_roles_map"

# Check Role model for cache invalidation
echo "=== Role Model Cache Invalidation ==="
rg -n -A15 "booted|saved|deleted" app/Models/Role.php | rg -A10 "permissions_roles_map"

# Count total roles and permissions to assess memory impact
echo "=== Database Scale Check ==="
cat << 'PYTHON_EOF' | python
import subprocess
import json

# This is a rough estimate - actual query would need database access
print("Note: Cannot query database in sandbox. Please manually verify:")
print("1. SELECT COUNT(*) FROM roles;")
print("2. SELECT COUNT(*) FROM permissions;")
print("3. Consider memory impact if counts exceed 1000+ each")
PYTHON_EOF

Length of output: 935


I need to verify more comprehensively whether cache invalidation covers all mutation scenarios and check for any edge cases with permission/role relationship changes.

</script>

🏁 Script executed:

#!/bin/bash
# Get complete booted method from Permission model
echo "=== Complete Permission Model Booted Method ==="
rg -n -A30 "function booted|static function booted" app/Models/Permission.php

# Get complete booted method from Role model
echo "=== Complete Role Model Booted Method ==="
rg -n -A30 "function booted|static function booted" app/Models/Role.php

# Check for any pivot/relationship table cache invalidation for permission attachments
echo "=== Role Permissions Relationship Definition ==="
rg -n -B2 -A10 "permissions\(\)" app/Models/Role.php

# Check if there are any permission attachment/detachment listeners
echo "=== Permission Sync/Attach/Detach Listeners ==="
rg -n "synced|attached|detached" app/Models/Role.php

Length of output: 432


🏁 Script executed:

#!/bin/bash
# Get complete booted method from Permission model
echo "=== Complete Permission Model Booted Method ==="
rg -n -A30 "function booted|static function booted" app/Models/Permission.php

# Get complete booted method from Role model
echo "=== Complete Role Model Booted Method ==="
rg -n -A30 "function booted|static function booted" app/Models/Role.php

# Check for any pivot/relationship table cache invalidation for permission attachments
echo "=== Role Permissions Relationship Definition ==="
rg -n -B2 -A10 "permissions\(\)" app/Models/Role.php

# Check if there are any permission attachment/detachment listeners
echo "=== Permission Sync/Attach/Detach Listeners ==="
rg -n "synced|attached|detached" app/Models/Role.php

Length of output: 1465



🏁 Script executed:

#!/bin/bash
# Check if there are relationship/pivot event listeners in the codebase
echo "=== Search for BelongsToMany event listeners (pivotAttached, pivotDetached, synced) ==="
rg -n "pivotAttached|pivotDetached|pivotUpdated|syncing|synced" app/ --type=php

# Check if AuthGates middleware has any additional cache handling
echo "=== AuthGates middleware complete implementation ==="
cat app/Http/Middleware/AuthGates.php

# Check for any observers that might handle relationship changes
echo "=== Search for Observer pattern usage ==="
rg -n "Observer|observe" app/Models/ --type=php

Length of output: 1788


Critical cache invalidation gap: BelongsToMany relationship changes are not invalidating the cache.

The Permission and Role models correctly invalidate the cache when records are directly modified via saved() and deleted() hooks. However, when permissions are attached/detached/synced to roles—e.g., $role->permissions()->attach(), ->detach(), or ->sync()—the cache remains stale since these operations bypass model events.

Impact: Users may retain outdated permission mappings, creating security and data consistency issues. The cached permissions_roles_map persists indefinitely until explicitly invalidated, but relationship mutations are unmonitored.

Required: Add relationship event listeners (using pivotAttached, pivotDetached, or pivot observer hooks) to both models to invalidate the cache when role-permission associations change.

🤖 Prompt for AI Agents
In app/Http/Middleware/AuthGates.php around lines 22–33 the cached
permissions_roles_map is built but relationship changes (role↔permission
attach/detach/sync) never invalidate it; update the Role and Permission models
to listen for pivot/relationship events (pivotAttached, pivotDetached,
pivotSynced or the equivalent relation events in your Laravel version) inside
their booted() methods and call Cache::forget('permissions_roles_map') (or the
same cache key used here) whenever an attachment/detachment/sync occurs so the
map is cleared and rebuilt on next access.

Comment on lines 10 to 15
public function handle($request, Closure $next)
{
// ⚠️ NE PAS APPELER Auth::user() / Auth::check(), ça déclencherait la requête SQL
if (session()->has('auth_user')) {
Auth::setUser(session('auth_user'));
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Add type validation before Auth::setUser() to prevent runtime errors.

The middleware directly passes session data to Auth::setUser() without verifying it's a valid User instance. If the session is corrupted or contains unexpected data, this could cause runtime errors.

Apply this diff to add type safety:

-    public function handle($request, Closure $next)
+    public function handle($request, Closure $next): mixed
     {
-        // ⚠️ NE PAS APPELER Auth::user() / Auth::check(), ça déclencherait la requête SQL
-        if (session()->has('auth_user')) {
-            Auth::setUser(session('auth_user'));
+        // Warning: Do not call Auth::user() / Auth::check() as it triggers SQL queries
+        $cachedUser = session('auth_user');
+        if ($cachedUser instanceof \App\Models\User) {
+            Auth::setUser($cachedUser);
         }
 
         return $next($request);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public function handle($request, Closure $next)
{
// ⚠️ NE PAS APPELER Auth::user() / Auth::check(), ça déclencherait la requête SQL
if (session()->has('auth_user')) {
Auth::setUser(session('auth_user'));
}
public function handle($request, Closure $next): mixed
{
// Warning: Do not call Auth::user() / Auth::check() as it triggers SQL queries
$cachedUser = session('auth_user');
if ($cachedUser instanceof \App\Models\User) {
Auth::setUser($cachedUser);
}
return $next($request);
}
🤖 Prompt for AI Agents
In app/Http/Middleware/UseCachedAuthUser.php around lines 10 to 15, the
middleware reads session('auth_user') and passes it directly to Auth::setUser(),
which can throw if the session contains unexpected data; before calling
Auth::setUser() validate the session value is the expected user object
(preferably instanceof Illuminate\Contracts\Auth\Authenticatable or your
App\Models\User), and only call setUser when that check passes; if it is an
array or contains an id, resolve a proper User model (e.g., fetch by id) or
otherwise skip/forget the session key to avoid runtime errors.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
app/Http/Controllers/Auth/LoginController.php (1)

40-53: Remove unused $request parameter and address integration issue with UseCachedAuthUser middleware.

  1. Unused parameter: The $request parameter is not used in this method. While Laravel's authenticated() hook signature allows it, consider removing it for clarity:

    -protected function authenticated(Request $request, User $user): void
    +protected function authenticated(User $user): void
  2. Integration issue (see UseCachedAuthUser middleware review): This method populates auth_role_ids and auth_permissions but not auth_user, breaking the middleware that expects it. Ensure the caching strategy is consistent across files.

The eager loading and session data extraction logic is correct and will improve performance by avoiding N+1 queries.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between f34fc49 and fc01e45.

📒 Files selected for processing (5)
  • app/Http/Controllers/Admin/DataProcessingController.php (1 hunks)
  • app/Http/Controllers/Auth/LoginController.php (2 hunks)
  • app/Http/Kernel.php (1 hunks)
  • app/Http/Middleware/UseCachedAuthUser.php (1 hunks)
  • app/Providers/AuthServiceProvider.php (2 hunks)
✅ Files skipped from review due to trivial changes (1)
  • app/Http/Kernel.php
🧰 Additional context used
🪛 PHPMD (2.15.0)
app/Http/Controllers/Auth/LoginController.php

40-40: Avoid unused parameters such as '$request'. (undefined)

(UnusedFormalParameter)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (4)
app/Http/Controllers/Admin/DataProcessingController.php (1)

22-25: Eager loading optimization is correct.

The added with('processes', 'informations', 'applications') is necessary and correctly prevents N+1 queries. The index view actively iterates over all three relationships (lines 72, 80, and 88) to display linked records, confirming this optimization will improve performance.

app/Providers/AuthServiceProvider.php (2)

6-6: LGTM!

The Gate facade import is appropriate for the new authorization hook.


25-41: <!-- [scratchpad_start]
[task verify_session_configuration 2/2]
[observations]

  • .env.example contains only SESSION_DRIVER=file — no mention of SESSION_SECURE_COOKIE
  • config/session.php line 169: 'secure' => env('SESSION_SECURE_COOKIE') has NO default value
  • config/session.php line 182: 'http_only' => true — properly set
  • config/session.php line 197: 'same_site' => 'lax' — properly set
  • Gate::before() implementation uses session('auth_permissions', []) with strict in_array comparison
  • Returns null to delegate to other gates/policies (correct behavior)
  • No docker deployment docs mention session configuration

[analysis]

  • SESSION_SECURE_COOKIE lacks default AND is undocumented in .env.example — this is a configuration gap
  • In development/testing environments without explicit SESSION_SECURE_COOKIE, sessions won't have secure flag (only affects HTTPS)
  • http_only and same_site settings are properly hardened
  • Permission staleness is actual design trade-off: permissions cached at login, won't update until next session
  • Original review concerns are VALID and well-founded

[done]

  • Verification confirms both architectural concerns are legitimate
  • Session security configuration has a documentation/default gap
  • Permission staleness is acknowledged design decision requiring documentation

Verify session security configuration and document permission staleness behavior.

The Gate::before hook correctly implements session-based permission caching. Verification confirms two valid architectural considerations:

  1. Session security gap: SESSION_SECURE_COOKIE has no default value in config/session.php and is absent from .env.example. While http_only and same_site are properly configured, ensure your production .env explicitly sets SESSION_SECURE_COOKIE=true (or false only for non-HTTPS environments).

  2. Permission staleness: Permissions remain cached for the entire session lifetime. Revoked permissions won't take effect until user re-login. Document this behavior if real-time permission revocation is a business requirement.

app/Http/Controllers/Auth/LoginController.php (1)

171-172: LGTM!

The clarifying comments effectively document the authentication flow and the relationship between manual login and the authenticated() hook.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between fc01e45 and bed927d.

📒 Files selected for processing (1)
  • app/Http/Controllers/Admin/RolesController.php (2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (1)
app/Http/Controllers/Admin/RolesController.php (1)

13-13: LGTM!

The Cache facade import is correctly added to support the cache invalidation functionality.

@dbarzin dbarzin merged commit c51a145 into master Nov 15, 2025
6 checks passed
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.

2 participants