/* RFC-0752: subdomain.validate command handler — validates that DNS CNAME and Workers route for a service subdomain exist and are correctly configured. Returns state: valid | not-registered | mismatched. Exit code 0 for all validation states (not-registered and mismatched are validation results, not errors). Do not create or update records — that is subdomain.register's responsibility. RFC-0752: initial subdomain.validate command handler. RFC-1249: wire werkstatt.commands.validate into packages.check + retire CMD-OUTPUT debt */ import type { KernelCommandInput, KernelCommandResult, KernelRuntimeContext, } from "@warpgogol/werkstatt-engine/kernel"; import { readServicesRegistry, discoverSystems } from "../sternsystem/registry-io.ts"; import { listDnsRecords, listWorkersRoutes } from "../leitstand/adapters/cloudflare-api.ts"; import { flagString, resolveService, resolveZoneId, resolveAccountSubdomain, resolveSubdomainEnv, buildCnameContent, buildRoutePattern, } from "./subdomain-helpers.ts"; import type { SubdomainRecord } from "./subdomain-register.ts"; export interface SubdomainValidateResult { command: "subdomain.validate"; serviceId: string; subdomain: SubdomainRecord; dnsRecord: { exists: boolean; correct: boolean; id: string | null; type: string | null; content: string | null; proxied: boolean | null; }; workersRoute: { exists: boolean; correct: boolean; id: string | null; pattern: string | null; script: string | null; }; state: "valid" | "not-registered" | "mismatched"; } export async function runSubdomainValidate( input: KernelCommandInput, context: KernelRuntimeContext, ): Promise> { const { workspaceRoot } = context; const serviceId = flagString(input, "service"); if (!serviceId) throw new Error("[subdomain.validate] --service is required"); const registry = await readServicesRegistry(workspaceRoot); const service = resolveService(registry, serviceId); if (service.subdomains.length === 0) { throw new Error( `[subdomain.validate] Service '${serviceId}' has no subdomains declared in the registry.`, ); } const env = await resolveSubdomainEnv(); const apiToken = env["CLOUDFLARE_API_TOKEN"]; if (!apiToken) { throw new Error( "[subdomain.validate] CLOUDFLARE_API_TOKEN is not set. " + "Set it in the environment or .env file.", ); } const account = resolveAccountSubdomain(service, env); const subdomain = service.subdomains[0]; const { systems } = await discoverSystems(workspaceRoot); const zoneId = resolveZoneId(systems, subdomain.zone); const expectedCnameContent = buildCnameContent(service.workerName, account); const expectedRoutePattern = buildRoutePattern(subdomain.domain); const existingDnsRecords = await listDnsRecords(zoneId, apiToken, subdomain.domain); const matchingDns = existingDnsRecords.find((r) => r.name === subdomain.domain); const dnsExists = !!matchingDns; const dnsCorrect = dnsExists && matchingDns!.type === "CNAME" && matchingDns!.content === expectedCnameContent && matchingDns!.proxied === true; const existingRoutes = await listWorkersRoutes(zoneId, apiToken); const matchingRoute = existingRoutes.find((r) => r.pattern === expectedRoutePattern); const routeExists = !!matchingRoute; const routeCorrect = routeExists && matchingRoute!.script === service.workerName; const state: SubdomainValidateResult["state"] = dnsCorrect && routeCorrect ? "valid" : !dnsExists && !routeExists ? "not-registered" : "mismatched"; return { data: { command: "subdomain.validate", serviceId, subdomain, dnsRecord: { exists: dnsExists, correct: dnsCorrect, id: matchingDns?.id ?? null, type: matchingDns?.type ?? null, content: matchingDns?.content ?? null, proxied: matchingDns?.proxied ?? null, }, workersRoute: { exists: routeExists, correct: routeCorrect, id: matchingRoute?.id ?? null, pattern: matchingRoute?.pattern ?? null, script: matchingRoute?.script ?? null, }, state, }, exitCode: 0, summary: `[subdomain.validate] ${subdomain.domain}: ${state}`, nextSteps: [], }; }