/** * Services-reachable check. * * For each container service, attempts a low-cost API ping * (Proxmox `/version`, DigitalOcean `/v2/account`). Catches: * * - Service host down or behind a firewall. * - API token revoked or expired. * - Wrong endpoint URL. * * Severity is `drift` rather than `blocked` — a deploy can still * succeed if the operator restarts the service or fixes the * network before retrying. Surfacing here just gives the user * earlier signal than a deploy-time timeout. * * Like `services_credentials`, the audit consumes pre-computed * results so it stays unit-testable without hitting a real API. */ import type { DriftFinding } from './types'; export interface ServiceReachableResult { /** User-facing kebab-case service ID. */ serviceId: string; /** Display name for the finding message. */ name: string; providerName: string; /** True if the API ping succeeded. */ reachable: boolean; /** Short description of failure when `!reachable`. */ message?: string; } export interface ServicesReachableAuditDeps { results: ServiceReachableResult[]; } export async function auditServicesReachable( deps: ServicesReachableAuditDeps, ): Promise { const findings: DriftFinding[] = []; for (const r of deps.results) { if (r.reachable) continue; findings.push({ category: 'services_reachable', severity: 'drift', code: 'service_unreachable', message: `${r.name} (${r.providerName}): API unreachable`, details: r.message, remediation: [ 'Verify the service host is up and the API endpoint is', 'correct. If the API token was rotated, re-set it:', ` celilo service set-credentials ${r.serviceId}`, ].join('\n'), // Diagnostic / interactive — no one-shot fix. actionable: false, subject: r.serviceId, }); } return findings; }