Keep an audit log of who did what, and how they came in

Written from model events, spatie's role events and panel sign-ins, only for
what a person did, with secrets masked; pruned after a year.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-01 10:08:01 +02:00
parent 9bdbf834f6
commit 1fe1e67773
18 changed files with 744 additions and 1 deletions

View File

@@ -13,6 +13,7 @@ use App\Http\Controllers\Api\PublicApi\V1\SiteController;
use App\Http\Controllers\Api\PublicApi\V1\TelemetryController;
use App\Http\Controllers\Api\V1\ApiTokenController;
use App\Http\Controllers\Api\V1\ApplicationController as AdminApplicationController;
use App\Http\Controllers\Api\V1\AuditController;
use App\Http\Controllers\Api\V1\BatchController;
use App\Http\Controllers\Api\V1\CallController;
use App\Http\Controllers\Api\V1\CategoryController;
@@ -267,6 +268,9 @@ Route::prefix('v1')->name('api.v1.')->group(function () {
Route::post('webhooks/{webhook}/ping', [WebhookController::class, 'ping'])->name('webhooks.ping');
Route::post('webhook-deliveries/{delivery}/redeliver', [WebhookController::class, 'redeliver'])->name('webhook-deliveries.redeliver');
// Who did what, from where.
Route::get('audit', [AuditController::class, 'index'])->name('audit');
// The panel's health screen, and what is left to translate.
Route::get('health', [HealthController::class, 'index'])->name('health');
Route::get('translations/pending', [HealthController::class, 'translations'])->name('translations.pending');

View File

@@ -2,6 +2,7 @@
declare(strict_types=1);
use App\Models\AuditLog;
use Illuminate\Support\Facades\Schedule;
/*
@@ -44,3 +45,10 @@ Schedule::command('repos:sync')
})
->withoutOverlapping()
->runInBackground();
// Old audit entries: they name people and the addresses they worked from, so
// they are kept for `audit.retention_days` and no longer.
Schedule::command('model:prune', ['--model' => [AuditLog::class]])
->daily()
->withoutOverlapping()
->runInBackground();