/* RFC-0753: dns.records.schema.validate command handler — schema-only validation of DNS record declaration files. No Cloudflare API calls, no CLOUDFLARE_API_TOKEN needed. Designed for CI pipeline integration (PACKAGES_CHECK_PIPELINE). Do not make live API calls — that is dns.record.validate's responsibility. Do not check record content against live Cloudflare state. RFC-0753: initial dns.records.schema.validate command handler. */ import type { KernelCommandInput, KernelCommandResult, KernelRuntimeContext, } from "@warpgogol/werkstatt-engine/kernel"; import { join } from "node:path"; import { dnsRecordFileSchema } from "@warpgogol/werkstatt-shared/ontology/schemas"; import { flagString } from "./dns-helpers.ts"; import { discoverSystems, resolveCacheClonePath } from "../sternsystem/registry-io.ts"; export interface DnsRecordsSchemaValidateResult { command: "dns.records.schema.validate"; systemId: string | null; files: Array<{ path: string; valid: boolean; errors: string[] | null; }>; state: "valid" | "invalid"; } export async function runDnsRecordsSchemaValidate( input: KernelCommandInput, context: KernelRuntimeContext, ): Promise> { const { workspaceRoot } = context; const systemId = flagString(input, "system"); const files: DnsRecordsSchemaValidateResult["files"] = []; let allValid = true; const filePaths: string[] = []; if (systemId) { const cacheDir = resolveCacheClonePath(workspaceRoot, systemId); const filePath = join(cacheDir, "dns-records.yaml"); filePaths.push(filePath); } else { const { systems } = await discoverSystems(workspaceRoot); for (const sys of systems) { const cacheDir = resolveCacheClonePath(workspaceRoot, sys.id); const filePath = join(cacheDir, "dns-records.yaml"); filePaths.push(filePath); } } for (const filePath of filePaths) { let raw: string; try { raw = await context.io.readFile(filePath); } catch { continue; } try { const { parse } = await import("yaml"); const parsed = parse(raw); dnsRecordFileSchema.parse(parsed); files.push({ path: filePath, valid: true, errors: null }); } catch (err) { allValid = false; const errors: string[] = []; if (err && typeof err === "object" && "issues" in err) { for (const issue of (err as { issues: { message: string; path: (string | number)[] }[] }) .issues) { errors.push(`${issue.path.join(".")}: ${issue.message}`); } } else if (err instanceof Error) { errors.push(err.message); } else { errors.push(String(err)); } files.push({ path: filePath, valid: false, errors }); } } const checkedFiles = files.filter((f) => f !== null); const state: DnsRecordsSchemaValidateResult["state"] = allValid ? "valid" : "invalid"; return { data: { command: "dns.records.schema.validate", systemId: systemId ?? null, files: checkedFiles, state, }, summary: `[dns.records.schema.validate] ${checkedFiles.length} file(s) checked: ${state}`, nextSteps: allValid ? undefined : [ { action: `Fix the schema violations above, then re-run: pnpm exec werkstatt run dns.records.schema.validate`, kind: "required", }, ], ...(allValid ? {} : { exitCode: 1 }), }; }