Some checks failed
PR Fast Feedback / fast-feedback (pull_request) Failing after 5m7s
Added jobs, controllers, and PDF generation logic for management report runtime as defined in Spec 379. Includes artifact migrations, payload builders, and testing coverage.
98 lines
4.1 KiB
PHP
98 lines
4.1 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Services\Evidence\Sources;
|
|
|
|
use App\Models\Finding;
|
|
use App\Models\ManagedEnvironment;
|
|
use App\Models\OperationRun;
|
|
use App\Services\Evidence\Contracts\EvidenceSourceProvider;
|
|
use App\Support\Evidence\EvidenceCompletenessState;
|
|
use App\Support\OperationCatalog;
|
|
use App\Support\OperationRunOutcome;
|
|
use App\Support\OperationRunStatus;
|
|
use App\Support\OperationRunType;
|
|
|
|
final class BaselineDriftPostureSource implements EvidenceSourceProvider
|
|
{
|
|
public function key(): string
|
|
{
|
|
return 'baseline_drift_posture';
|
|
}
|
|
|
|
public function collect(ManagedEnvironment $tenant): array
|
|
{
|
|
$findings = Finding::query()
|
|
->where('managed_environment_id', (int) $tenant->getKey())
|
|
->where('finding_type', Finding::FINDING_TYPE_DRIFT)
|
|
->latest('updated_at')
|
|
->get();
|
|
|
|
$latestCompareRun = $this->latestBaselineCompareRun($tenant);
|
|
$latestCompareAt = $latestCompareRun?->completed_at
|
|
?? $latestCompareRun?->updated_at
|
|
?? $latestCompareRun?->created_at;
|
|
$latest = $findings->max('updated_at') ?? $findings->max('created_at') ?? $latestCompareAt;
|
|
$isStale = $latest !== null && $latest->lt(now()->subDays(30));
|
|
|
|
$state = match (true) {
|
|
$isStale => EvidenceCompletenessState::Stale->value,
|
|
$latestCompareRun instanceof OperationRun => $this->stateForCompareRun($latestCompareRun),
|
|
$findings->isEmpty() => EvidenceCompletenessState::Missing->value,
|
|
default => EvidenceCompletenessState::Complete->value,
|
|
};
|
|
|
|
return [
|
|
'dimension_key' => $this->key(),
|
|
'state' => $state,
|
|
'required' => true,
|
|
'source_kind' => 'model_summary',
|
|
'source_record_type' => Finding::class,
|
|
'source_record_id' => null,
|
|
'source_fingerprint' => $findings->max('fingerprint'),
|
|
'measured_at' => $latest,
|
|
'freshness_at' => $latest,
|
|
'summary_payload' => [
|
|
'drift_count' => $findings->count(),
|
|
'open_drift_count' => $findings->filter(fn (Finding $finding): bool => $finding->hasOpenStatus())->count(),
|
|
'latest_compare_run_id' => $latestCompareRun instanceof OperationRun ? (int) $latestCompareRun->getKey() : null,
|
|
'latest_compare_outcome' => $latestCompareRun instanceof OperationRun ? (string) $latestCompareRun->outcome : null,
|
|
'latest_compare_completed_at' => $latestCompareRun?->completed_at?->toIso8601String(),
|
|
],
|
|
'fingerprint_payload' => [
|
|
'latest' => $latest?->format(DATE_ATOM),
|
|
'count' => $findings->count(),
|
|
'latest_compare_run_id' => $latestCompareRun instanceof OperationRun ? (int) $latestCompareRun->getKey() : null,
|
|
'latest_compare_outcome' => $latestCompareRun instanceof OperationRun ? (string) $latestCompareRun->outcome : null,
|
|
'latest_compare_completed_at' => $latestCompareRun?->completed_at?->toIso8601String(),
|
|
],
|
|
'sort_order' => 40,
|
|
];
|
|
}
|
|
|
|
private function latestBaselineCompareRun(ManagedEnvironment $tenant): ?OperationRun
|
|
{
|
|
return OperationRun::query()
|
|
->where('managed_environment_id', (int) $tenant->getKey())
|
|
->whereIn('type', OperationCatalog::rawValuesForCanonical(OperationRunType::BaselineCompare->value))
|
|
->latest('completed_at')
|
|
->latest('updated_at')
|
|
->latest('id')
|
|
->first();
|
|
}
|
|
|
|
private function stateForCompareRun(OperationRun $operationRun): string
|
|
{
|
|
if ((string) $operationRun->status !== OperationRunStatus::Completed->value) {
|
|
return EvidenceCompletenessState::Missing->value;
|
|
}
|
|
|
|
return match ((string) $operationRun->outcome) {
|
|
OperationRunOutcome::Succeeded->value => EvidenceCompletenessState::Complete->value,
|
|
OperationRunOutcome::PartiallySucceeded->value => EvidenceCompletenessState::Partial->value,
|
|
default => EvidenceCompletenessState::Missing->value,
|
|
};
|
|
}
|
|
}
|