Files
coolify/app/Services/ImageScan/VulnerabilityMarkers.php
033f0c84da v4.7 (#12478)
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com>
Co-authored-by: Aditya Tripathi <aditya@climactic.co>
2026-11-06 14:25:02 +01:00

73 lines
2.7 KiB
PHP

<?php
namespace App\Services\ImageScan;
use App\Enums\SecurityStatusType;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection;
/**
* The security marker of lists and canvas cards (spec 15.8), read from the stored security status: "Update now" for
* update_now, "No fix yet" for no_fix, nothing for other statuses. Resources that are not scanned now (see
* `ImageScanPolicyResolver::offState()`) are not_checked and have no marker.
*/
final class VulnerabilityMarkers
{
/** Columns the team page reads for its scans (the search decodes the findings itself). */
public const SCAN_COLUMNS = ['id', 'uuid', 'server_id', 'resource_type', 'resource_id', 'deployment_queue_id', 'image_ref', 'summary', 'candidates', 'builds_image', 'scanned_at'];
private const TEXTS = [
'update_now' => 'Update now',
'no_fix' => 'No fix yet',
];
/**
* The markers of the given resources (applications, services, standalone databases) with a constant number of
* queries. Resources without a marker have no entry.
*
* @param Collection<int, mixed> $resources
* @return array<string, array{status: string, text: string, label: string, tooltip: ?string}> Keyed by `ResourceScans::key()`.
*/
public static function for(Collection $resources): array
{
$resources = $resources->filter(fn ($resource): bool => $resource instanceof Model)->values();
if ($resources->isEmpty() || ! instanceSettings()->is_image_scanning_allowed) {
return [];
}
$markers = [];
foreach (SecurityStatus::storedMany($resources) as $key => $security) {
$marker = self::marker($security);
if ($marker !== null) {
$markers[$key] = $marker;
}
}
return $markers;
}
/**
* The marker of one status. `tooltip` is the primary action sentence of update_now; `label` (the aria-label)
* names the status and the action.
*
* @return array{status: string, text: string, label: string, tooltip: ?string}|null
*/
public static function marker(ResourceSecurity $security): ?array
{
$text = self::TEXTS[$security->status->value] ?? null;
if ($text === null) {
return null;
}
$action = $security->status === SecurityStatusType::UpdateNow ? $security->primary()?->sentence : null;
$action = filled($action) ? $action : null;
return [
'status' => $security->status->value,
'text' => $text,
'label' => 'Security: '.mb_strtolower($text).($action === null ? '' : '. '.$action),
'tooltip' => $action,
];
}
}