refactor: relocate module from app/Mod/Developer to src/
Move module to standard package structure with namespace change from Mod\Developer to Core\Developer. Updates composer.json autoload configuration accordingly. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
579d88b123
commit
518305142e
36 changed files with 160 additions and 43 deletions
117
changelog/2026/jan/code-review.md
Normal file
117
changelog/2026/jan/code-review.md
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
# Developer Module Review
|
||||
|
||||
**Updated:** 2026-01-21 - Additional improvements: command registration, Horizon notifications, multi-log support
|
||||
|
||||
## Overview
|
||||
|
||||
The Developer module provides administrative developer tools for Hades-tier users (god-mode access). It includes:
|
||||
|
||||
1. **Admin Panel Tools**: Log viewer, route browser, and cache management via Livewire components
|
||||
2. **Remote Server Management**: SSH trait for executing commands on remote servers (used by other modules)
|
||||
3. **Service Provider Overrides**: Custom Horizon and Telescope configuration
|
||||
4. **Device Frames Command**: Artisan command for copying device frame assets
|
||||
5. **Middleware/Listeners**: Icon settings from cookies and Hades cookie on login
|
||||
|
||||
## Production Readiness Score: 95/100 (was 90/100 - Wave 4 improvements applied 2026-01-21)
|
||||
|
||||
The module is production-ready with authorization, rate limiting, audit logging, configurable timeouts, Horizon notification routing, and multi-log file support.
|
||||
|
||||
## Critical Issues (Must Fix)
|
||||
|
||||
- [x] **Server model has no migration**: FIXED - Migration created at `database/migrations/2026_01_21_000001_create_servers_table.php`.
|
||||
|
||||
- [x] **Inconsistent Hades authorization**: FIXED - `DevController` now uses `$user->isHades()` method instead of checking non-existent `account_type` field.
|
||||
|
||||
- [x] **SetHadesCookie uses env() directly**: FIXED - Now uses `config('developer.hades_token')` with config file at `config/developer.php`.
|
||||
|
||||
- [x] **HorizonServiceProvider gate is empty**: FIXED - `viewHorizon` gate now checks `$user->isHades()` for proper authorization.
|
||||
|
||||
- [x] **TelescopeServiceProvider gate emails empty**: FIXED - Telescope gate now checks `$user->isHades()` instead of hardcoded email list.
|
||||
|
||||
- [x] **CopyDeviceFrames command references missing config**: FIXED 2026-01-21 - The config exists at `app/Mod/Web/device-frames.php` and is loaded by Web module as `config('device-frames')`. The command was not registered - now registered in `Developer\Boot.php` via `onConsole()` event handler.
|
||||
|
||||
## Recommended Improvements
|
||||
|
||||
- [x] **Unify authorization pattern**: Created `RequireHades` middleware at `Middleware/RequireHades.php` for consistent authorization. DevController now uses this middleware via routes.
|
||||
|
||||
- [x] **Add route middleware for Hades access**: Created `RequireHades` middleware and applied to API routes group in `Routes/admin.php`.
|
||||
|
||||
- [x] **Move HADES_TOKEN to config**: Already done in prior wave. Config at `config/developer.php` with `'hades_token' => env('HADES_TOKEN')`.
|
||||
|
||||
- [x] **Add rate limiting to API routes**: Added rate limiters in `Boot.php` (`dev-cache-clear`, `dev-logs`, `dev-routes`, `dev-session`) and applied via `throttle:` middleware on routes.
|
||||
|
||||
- [x] **Log clear action should be audited**: `clearLogs()` now logs to Laravel log with user_id, user_email, previous_size_bytes, and IP.
|
||||
|
||||
- [x] **Remove duplicate log reading logic**: Created `LogReaderService` at `Services/LogReaderService.php` with `tailFile()` and `readLogEntries()` methods. Both DevController and Logs component now use this service.
|
||||
|
||||
- [x] **RemoteServerManager timeout is hardcoded**: Added `developer.ssh.connection_timeout` and `developer.ssh.command_timeout` config options. `connect()` and `run()` methods now use config values with fallback defaults.
|
||||
|
||||
- [x] **Services directory is empty**: Now contains `LogReaderService.php`.
|
||||
|
||||
## Missing Features (Future)
|
||||
|
||||
- [ ] **Server CRUD UI**: The Server model exists with full functionality but there's no UI for managing servers.
|
||||
|
||||
- [x] **Horizon/Telescope admin email configuration**: FIXED 2026-01-21 - Added `developer.horizon.*` config options (mail_to, sms_to, slack_webhook, slack_channel) in `config/developer.php`. `HorizonServiceProvider` now reads these values via `configureNotifications()` method.
|
||||
|
||||
- [ ] **Log download/export**: Users can view and clear logs but cannot download them.
|
||||
|
||||
- [ ] **Route testing/inspection**: Route viewer shows routes but doesn't allow clicking to test them.
|
||||
|
||||
- [ ] **Event log viewer**: Activity logs (from Spatie) exist on Server model but no UI to view them.
|
||||
|
||||
- [x] **Multi-log file support**: FIXED 2026-01-21 - Added `getAvailableLogFiles()` to list all log files sorted by date, and `getCurrentLogPath()` to detect daily vs single log channels. LogReaderService now supports reading any log file.
|
||||
|
||||
- [ ] **Database query tool**: Cache, Routes, Logs exist but no database query/inspection tool.
|
||||
|
||||
## Test Coverage Assessment
|
||||
|
||||
**Current Coverage**: Minimal - only one test file exists (`Tests/UseCase/DevToolsBasic.php`)
|
||||
|
||||
**What's tested**:
|
||||
- Logs page renders with correct sections and translations
|
||||
- Routes page renders with table headers
|
||||
- Cache page renders with all cache action cards
|
||||
|
||||
**What's NOT tested**:
|
||||
- DevController API endpoints
|
||||
- Cache clearing actually works
|
||||
- Log filtering functionality
|
||||
- Route filtering/searching
|
||||
- Hades authorization enforcement
|
||||
- RemoteServerManager SSH operations
|
||||
- Server model scopes and methods
|
||||
- SetHadesCookie listener
|
||||
- ApplyIconSettings middleware
|
||||
- CopyDeviceFrames command
|
||||
|
||||
**Test issues**:
|
||||
- Tests create a user but don't set Hades tier, so authorization should fail (but tests pass, indicating auth may not be enforced on page load properly in test environment)
|
||||
|
||||
## Security Concerns
|
||||
|
||||
1. **Authorization bypass potential**: The tests pass without setting Hades tier, suggesting the authorization checks may not be working correctly in all environments.
|
||||
|
||||
2. **Log file disclosure**: While Hades-only, the log viewer shows full log messages which may contain sensitive data like tokens, passwords in queries, etc. Consider redacting sensitive patterns.
|
||||
|
||||
3. **Cache clear is destructive**: No confirmation dialog before clearing caches. Accidental clicks could disrupt the application.
|
||||
|
||||
4. **Session endpoint exposes data**: `/hub/api/dev/session` returns session ID, IP, and user agent - useful for debugging but could be abused.
|
||||
|
||||
5. **RemoteServerManager command injection**: While commands are not directly user-input, the `run()` method accepts raw command strings. Any code using this trait must sanitize inputs.
|
||||
|
||||
6. **Private keys stored encrypted**: Good - Server model uses `'encrypted'` cast for `private_key`. Hidden from serialization.
|
||||
|
||||
## Notes
|
||||
|
||||
1. **Module structure is clean**: Follows the modular monolith pattern correctly with Boot.php as service provider, proper namespace structure, and event-driven admin panel registration.
|
||||
|
||||
2. **Translation support**: Full translation file exists for en_GB locale - good i18n practice.
|
||||
|
||||
3. **Pulse dashboard override**: Custom Pulse dashboard view is registered, allowing control over the metrics shown.
|
||||
|
||||
4. **Livewire components well-structured**: Use attributes (`#[Title]`, `#[Layout]`, `#[Url]`) properly and follow consistent patterns.
|
||||
|
||||
5. **RemoteServerManager is well-designed**: The `withConnection()` pattern with guaranteed cleanup is good. Base64 encoding for file writes prevents injection.
|
||||
|
||||
6. **Dead code concern**: The `DevController` methods overlap with Livewire components. The API routes exist but may not be used by the Livewire views. Consider if both are needed.
|
||||
|
|
@ -16,7 +16,7 @@
|
|||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Mod\\Developer\\": "app/Mod/Developer/"
|
||||
"Core\\Developer\\": "src/"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
|
|
@ -27,7 +27,7 @@
|
|||
"extra": {
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"Mod\\Developer\\Boot"
|
||||
"Core\\Developer\\Boot"
|
||||
]
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mod\Developer;
|
||||
namespace Core\Developer;
|
||||
|
||||
use Core\Events\AdminPanelBooting;
|
||||
use Core\Events\ConsoleBooting;
|
||||
|
|
@ -2,10 +2,10 @@
|
|||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mod\Developer\Concerns;
|
||||
namespace Core\Developer\Concerns;
|
||||
|
||||
use Mod\Developer\Exceptions\SshConnectionException;
|
||||
use Mod\Developer\Models\Server;
|
||||
use Core\Developer\Exceptions\SshConnectionException;
|
||||
use Core\Developer\Models\Server;
|
||||
use Core\Helpers\CommandResult;
|
||||
use phpseclib3\Crypt\PublicKeyLoader;
|
||||
use phpseclib3\Net\SSH2;
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace Mod\Developer\Console\Commands;
|
||||
namespace Core\Developer\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\File;
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace Mod\Developer\Controllers;
|
||||
namespace Core\Developer\Controllers;
|
||||
|
||||
use Core\Front\Controller;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
|
@ -8,7 +8,7 @@ use Illuminate\Http\Request;
|
|||
use Illuminate\Support\Facades\Artisan;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Illuminate\Support\Str;
|
||||
use Mod\Developer\Services\LogReaderService;
|
||||
use Core\Developer\Services\LogReaderService;
|
||||
|
||||
class DevController extends Controller
|
||||
{
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mod\Developer\Data;
|
||||
namespace Core\Developer\Data;
|
||||
|
||||
use Illuminate\Http\Response;
|
||||
use Throwable;
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mod\Developer\Exceptions;
|
||||
namespace Core\Developer\Exceptions;
|
||||
|
||||
use Exception;
|
||||
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mod\Developer\Listeners;
|
||||
namespace Core\Developer\Listeners;
|
||||
|
||||
use Illuminate\Auth\Events\Login;
|
||||
use Illuminate\Support\Facades\Cookie;
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mod\Developer\Middleware;
|
||||
namespace Core\Developer\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mod\Developer\Middleware;
|
||||
namespace Core\Developer\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mod\Developer\Models;
|
||||
namespace Core\Developer\Models;
|
||||
|
||||
use Core\Mod\Tenant\Concerns\BelongsToWorkspace;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mod\Developer\Providers;
|
||||
namespace Core\Developer\Providers;
|
||||
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Laravel\Horizon\Horizon;
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mod\Developer\Providers;
|
||||
namespace Core\Developer\Providers;
|
||||
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
|
|
@ -11,13 +11,13 @@ use Illuminate\Support\Facades\Route;
|
|||
Route::prefix('hub')->name('hub.')->group(function () {
|
||||
// Developer tools (Hades only) - authorization checked in components
|
||||
Route::prefix('dev')->name('dev.')->group(function () {
|
||||
Route::get('/logs', \Mod\Developer\View\Modal\Admin\Logs::class)->name('logs');
|
||||
Route::get('/routes', \Mod\Developer\View\Modal\Admin\Routes::class)->name('routes');
|
||||
Route::get('/cache', \Mod\Developer\View\Modal\Admin\Cache::class)->name('cache');
|
||||
Route::get('/activity', \Mod\Developer\View\Modal\Admin\ActivityLog::class)->name('activity');
|
||||
Route::get('/servers', \Mod\Developer\View\Modal\Admin\Servers::class)->name('servers');
|
||||
Route::get('/database', \Mod\Developer\View\Modal\Admin\Database::class)->name('database');
|
||||
Route::get('/route-inspector', \Mod\Developer\View\Modal\Admin\RouteInspector::class)->name('route-inspector');
|
||||
Route::get('/logs', \Core\Developer\View\Modal\Admin\Logs::class)->name('logs');
|
||||
Route::get('/routes', \Core\Developer\View\Modal\Admin\Routes::class)->name('routes');
|
||||
Route::get('/cache', \Core\Developer\View\Modal\Admin\Cache::class)->name('cache');
|
||||
Route::get('/activity', \Core\Developer\View\Modal\Admin\ActivityLog::class)->name('activity');
|
||||
Route::get('/servers', \Core\Developer\View\Modal\Admin\Servers::class)->name('servers');
|
||||
Route::get('/database', \Core\Developer\View\Modal\Admin\Database::class)->name('database');
|
||||
Route::get('/route-inspector', \Core\Developer\View\Modal\Admin\RouteInspector::class)->name('route-inspector');
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -31,21 +31,21 @@ Route::prefix('hub')->name('hub.')->group(function () {
|
|||
|
||||
Route::prefix('hub/api/dev')
|
||||
->name('hub.api.dev.')
|
||||
->middleware(\Mod\Developer\Middleware\RequireHades::class)
|
||||
->middleware(\Core\Developer\Middleware\RequireHades::class)
|
||||
->group(function () {
|
||||
Route::get('/logs', [\Mod\Developer\Controllers\DevController::class, 'logs'])
|
||||
Route::get('/logs', [\Core\Developer\Controllers\DevController::class, 'logs'])
|
||||
->middleware('throttle:dev-logs')
|
||||
->name('logs');
|
||||
|
||||
Route::get('/routes', [\Mod\Developer\Controllers\DevController::class, 'routes'])
|
||||
Route::get('/routes', [\Core\Developer\Controllers\DevController::class, 'routes'])
|
||||
->middleware('throttle:dev-routes')
|
||||
->name('routes');
|
||||
|
||||
Route::get('/session', [\Mod\Developer\Controllers\DevController::class, 'session'])
|
||||
Route::get('/session', [\Core\Developer\Controllers\DevController::class, 'session'])
|
||||
->middleware('throttle:dev-session')
|
||||
->name('session');
|
||||
|
||||
Route::post('/clear/{type}', [\Mod\Developer\Controllers\DevController::class, 'clear'])
|
||||
Route::post('/clear/{type}', [\Core\Developer\Controllers\DevController::class, 'clear'])
|
||||
->middleware('throttle:dev-cache-clear')
|
||||
->name('clear');
|
||||
});
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mod\Developer\Services;
|
||||
namespace Core\Developer\Services;
|
||||
|
||||
/**
|
||||
* Service for reading and parsing Laravel log files.
|
||||
|
|
@ -2,13 +2,13 @@
|
|||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mod\Developer\Services;
|
||||
namespace Core\Developer\Services;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Routing\Route;
|
||||
use Illuminate\Support\Facades\App;
|
||||
use Illuminate\Support\Facades\Route as RouteFacade;
|
||||
use Mod\Developer\Data\RouteTestResult;
|
||||
use Core\Developer\Data\RouteTestResult;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mod\Developer\View\Modal\Admin;
|
||||
namespace Core\Developer\View\Modal\Admin;
|
||||
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Livewire\Attributes\Computed;
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mod\Developer\View\Modal\Admin;
|
||||
namespace Core\Developer\View\Modal\Admin;
|
||||
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Illuminate\Support\Facades\Artisan;
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mod\Developer\View\Modal\Admin;
|
||||
namespace Core\Developer\View\Modal\Admin;
|
||||
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
|
@ -2,14 +2,14 @@
|
|||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mod\Developer\View\Modal\Admin;
|
||||
namespace Core\Developer\View\Modal\Admin;
|
||||
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Livewire\Attributes\Layout;
|
||||
use Livewire\Attributes\Title;
|
||||
use Livewire\Component;
|
||||
use Mod\Developer\Services\LogReaderService;
|
||||
use Core\Developer\Services\LogReaderService;
|
||||
|
||||
#[Title('Application Logs')]
|
||||
#[Layout('hub::admin.layouts.app')]
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mod\Developer\View\Modal\Admin;
|
||||
namespace Core\Developer\View\Modal\Admin;
|
||||
|
||||
use Flux\Flux;
|
||||
use Illuminate\Contracts\View\View;
|
||||
|
|
@ -12,8 +12,8 @@ use Livewire\Attributes\Layout;
|
|||
use Livewire\Attributes\Title;
|
||||
use Livewire\Attributes\Url;
|
||||
use Livewire\Component;
|
||||
use Mod\Developer\Data\RouteTestResult;
|
||||
use Mod\Developer\Services\RouteTestService;
|
||||
use Core\Developer\Data\RouteTestResult;
|
||||
use Core\Developer\Services\RouteTestService;
|
||||
|
||||
/**
|
||||
* Route Inspector - interactive route testing for developers.
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mod\Developer\View\Modal\Admin;
|
||||
namespace Core\Developer\View\Modal\Admin;
|
||||
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mod\Developer\View\Modal\Admin;
|
||||
namespace Core\Developer\View\Modal\Admin;
|
||||
|
||||
use Flux\Flux;
|
||||
use Illuminate\Contracts\View\View;
|
||||
|
|
@ -11,7 +11,7 @@ use Livewire\Attributes\Computed;
|
|||
use Livewire\Attributes\Layout;
|
||||
use Livewire\Attributes\Title;
|
||||
use Livewire\Component;
|
||||
use Mod\Developer\Models\Server;
|
||||
use Core\Developer\Models\Server;
|
||||
|
||||
#[Title('Server Management')]
|
||||
#[Layout('hub::admin.layouts.app')]
|
||||
Loading…
Add table
Reference in a new issue