latest('id')->with('user:id,name,username')->first(); $reports = SecurityReport::query() ->with('user:id,name,username') ->latest('id') ->paginate(20) ->through(fn (SecurityReport $report): array => $this->mapListItem($report)); return Inertia::render('Admin/System/SecurityReportIndex', [ 'latest' => $latest ? $this->mapDetail($latest) : null, 'reports' => $reports, 'canRunScan' => true, ])->rootView('moderation'); } public function show(SecurityReport $securityReport): Response { abort_unless((bool) config('security-report.enabled', true), 404); $securityReport->load('user:id,name,username'); return Inertia::render('Admin/System/SecurityReportShow', [ 'report' => $this->mapDetail($securityReport), ])->rootView('moderation'); } public function run(Request $request): RedirectResponse { abort_unless((bool) config('security-report.enabled', true), 404); RunSecurityReportScanJob::dispatch($request->user()?->id); return redirect() ->route('admin.system.security-report.index') ->with('success', 'Security scan has been queued.'); } /** * @return array */ private function mapListItem(SecurityReport $report): array { return [ 'id' => (int) $report->id, 'status' => (string) $report->status, 'risk_label' => (string) $report->risk_label, 'finished_at' => optional($report->finished_at)?->toIso8601String(), 'total_critical' => (int) $report->total_critical, 'total_high' => (int) $report->total_high, 'total_medium' => (int) $report->total_medium, 'total_low' => (int) $report->total_low, 'composer_outdated_count' => (int) $report->composer_outdated_count, 'npm_outdated_count' => (int) $report->npm_outdated_count, 'show_url' => route('admin.system.security-report.show', ['securityReport' => $report]), 'triggered_by' => (string) ($report->triggered_by ?? ''), 'user' => $report->user ? [ 'id' => (int) $report->user->id, 'name' => (string) $report->user->name, 'username' => (string) ($report->user->username ?? ''), ] : null, ]; } /** * @return array */ private function mapDetail(SecurityReport $report): array { return [ 'id' => (int) $report->id, 'status' => (string) $report->status, 'risk_label' => (string) $report->risk_label, 'started_at' => optional($report->started_at)?->toIso8601String(), 'finished_at' => optional($report->finished_at)?->toIso8601String(), 'composer_critical' => (int) $report->composer_critical, 'composer_high' => (int) $report->composer_high, 'composer_medium' => (int) $report->composer_medium, 'composer_low' => (int) $report->composer_low, 'composer_unknown' => (int) $report->composer_unknown, 'npm_critical' => (int) $report->npm_critical, 'npm_high' => (int) $report->npm_high, 'npm_moderate' => (int) $report->npm_moderate, 'npm_low' => (int) $report->npm_low, 'npm_info' => (int) $report->npm_info, 'npm_unknown' => (int) $report->npm_unknown, 'total_critical' => (int) $report->total_critical, 'total_high' => (int) $report->total_high, 'total_medium' => (int) $report->total_medium, 'total_low' => (int) $report->total_low, 'total_unknown' => (int) $report->total_unknown, 'composer_outdated_count' => (int) $report->composer_outdated_count, 'npm_outdated_count' => (int) $report->npm_outdated_count, 'summary' => $report->summary ?? [], 'triggered_by' => (string) ($report->triggered_by ?? ''), 'error_message' => (string) ($report->error_message ?? ''), 'show_url' => route('admin.system.security-report.show', ['securityReport' => $report]), 'index_url' => route('admin.system.security-report.index'), 'composer_audit' => $report->composer_audit, 'composer_outdated' => $report->composer_outdated, 'npm_audit' => $report->npm_audit, 'npm_outdated' => $report->npm_outdated, 'composer_advisories' => $report->composerAdvisories(), 'npm_vulnerabilities' => $report->npmVulnerabilities(), 'user' => $report->user ? [ 'id' => (int) $report->user->id, 'name' => (string) $report->user->name, 'username' => (string) ($report->user->username ?? ''), ] : null, ]; } }