operationRun = $operationRun; } /** * @return array */ public function middleware(): array { return [new TrackOperationRun]; } public function handle( MicrosoftProviderHealthCheck $healthCheck, OperationRunService $runs, ): void { $tenant = Tenant::query()->find($this->tenantId); if (! $tenant instanceof Tenant) { throw new RuntimeException('Tenant not found.'); } $user = User::query()->find($this->userId); if (! $user instanceof User) { throw new RuntimeException('User not found.'); } $connection = ProviderConnection::query() ->where('tenant_id', $tenant->getKey()) ->find($this->providerConnectionId); if (! $connection instanceof ProviderConnection) { throw new RuntimeException('ProviderConnection not found.'); } $result = $healthCheck->check($connection); $this->applyHealthResult($connection, $result); if (! $this->operationRun instanceof OperationRun) { return; } $entraTenantName = $this->resolveEntraTenantName($connection, $result); if ($entraTenantName !== null) { $metadata = is_array($connection->metadata) ? $connection->metadata : []; $metadata['entra_tenant_name'] = $entraTenantName; $connection->update(['metadata' => $metadata]); } $this->updateRunTargetScope($this->operationRun, $connection, $entraTenantName); $report = VerificationReportWriter::write( run: $this->operationRun, checks: [ [ 'key' => 'provider.connection.check', 'title' => 'Provider connection check', 'status' => $result->healthy ? 'pass' : 'fail', 'severity' => $result->healthy ? 'info' : 'critical', 'blocking' => ! $result->healthy, 'reason_code' => $result->healthy ? 'ok' : ($result->reasonCode ?? 'unknown_error'), 'message' => $result->healthy ? 'Connection is healthy.' : ($result->message ?? 'Health check failed.'), 'evidence' => array_values(array_filter([ [ 'kind' => 'provider_connection_id', 'value' => (int) $connection->getKey(), ], [ 'kind' => 'entra_tenant_id', 'value' => (string) $connection->entra_tenant_id, ], is_numeric($result->meta['http_status'] ?? null) ? [ 'kind' => 'http_status', 'value' => (int) $result->meta['http_status'], ] : null, is_string($result->meta['organization_id'] ?? null) ? [ 'kind' => 'organization_id', 'value' => (string) $result->meta['organization_id'], ] : null, ])), 'next_steps' => $result->healthy ? [] : [[ 'label' => 'Review provider connection', 'url' => \App\Filament\Resources\ProviderConnectionResource::getUrl('edit', [ 'record' => (int) $connection->getKey(), ], tenant: $tenant), ]], ], ], identity: [ 'provider_connection_id' => (int) $connection->getKey(), 'entra_tenant_id' => (string) $connection->entra_tenant_id, ], ); if ($result->healthy) { $run = $runs->updateRun( $this->operationRun, status: OperationRunStatus::Completed->value, outcome: OperationRunOutcome::Succeeded->value, ); $this->logVerificationCompletion($tenant, $user, $run, $report); return; } $run = $runs->updateRun( $this->operationRun, status: OperationRunStatus::Completed->value, outcome: OperationRunOutcome::Failed->value, failures: [[ 'code' => 'provider.connection.check.failed', 'reason_code' => $result->reasonCode ?? 'unknown_error', 'message' => $result->message ?? 'Health check failed.', ]], ); $this->logVerificationCompletion($tenant, $user, $run, $report); } private function resolveEntraTenantName(ProviderConnection $connection, HealthResult $result): ?string { $existing = Arr::get(is_array($connection->metadata) ? $connection->metadata : [], 'entra_tenant_name'); if (is_string($existing) && trim($existing) !== '') { return trim($existing); } $candidate = $result->meta['organization_display_name'] ?? null; return is_string($candidate) && trim($candidate) !== '' ? trim($candidate) : null; } private function updateRunTargetScope(OperationRun $run, ProviderConnection $connection, ?string $entraTenantName): void { $context = is_array($run->context) ? $run->context : []; $targetScope = $context['target_scope'] ?? []; $targetScope = is_array($targetScope) ? $targetScope : []; $targetScope['entra_tenant_id'] = $connection->entra_tenant_id; if (is_string($entraTenantName) && $entraTenantName !== '') { $targetScope['entra_tenant_name'] = $entraTenantName; } $context['target_scope'] = $targetScope; $run->update(['context' => $context]); } private function applyHealthResult(ProviderConnection $connection, HealthResult $result): void { $connection->update([ 'status' => $result->status, 'health_status' => $result->healthStatus, 'last_health_check_at' => now(), 'last_error_reason_code' => $result->healthy ? null : $result->reasonCode, 'last_error_message' => $result->healthy ? null : $result->message, ]); } /** * @param array $report */ private function logVerificationCompletion(Tenant $tenant, User $actor, OperationRun $run, array $report): void { $workspace = $tenant->workspace; if (! $workspace) { return; } $counts = $report['summary']['counts'] ?? []; $counts = is_array($counts) ? $counts : []; app(WorkspaceAuditLogger::class)->log( workspace: $workspace, action: AuditActionId::VerificationCompleted->value, context: [ 'metadata' => [ 'operation_run_id' => (int) $run->getKey(), 'counts' => $counts, ], ], actor: $actor, status: $run->outcome === OperationRunOutcome::Succeeded->value ? 'success' : 'failed', resourceType: 'operation_run', resourceId: (string) $run->getKey(), ); } }