/* observability.alerts.apply — converge SigNoz backend to the declared alert rules (RFC-0342). Never touch unmanaged objects. Never run in pipelines — ops-only. RFC-0342: initial implementation. */ import type { CheckResult, KernelCommandInput, KernelCommandResult, KernelRuntimeContext, } from "@warpgogol/werkstatt-engine/kernel"; import { diagnosticsResult } from "@warpgogol/werkstatt-shared/checks"; import { createSignozApiClient, type SignozAlertRule, type SignozApplyPlan, type SignozChannel, } from "../signoz-api-client.ts"; import { ALERT_RULES, NOTIFICATION_CHANNELS } from "../alert-rules.ts"; function _stripGeneratedHeader(text: string): string { return text.replace(/^\/\/ GENERATED.*\n/, ""); } function buildPlan( currentRules: SignozAlertRule[], currentChannels: SignozChannel[], ): SignozApplyPlan { const desiredRules = new Map(); for (const rule of ALERT_RULES) { desiredRules.set(rule.id, { ...rule, labels: { ...rule.labels, managed_by: "warpgogol" }, }); } const desiredChannels = new Map(); for (const ch of NOTIFICATION_CHANNELS) { desiredChannels.set(ch.id, { ...ch }); } const currentRuleIds = new Set(currentRules.map((r) => r.id)); const currentChannelIds = new Set(currentChannels.map((c) => c.id)); const rulesToCreate: SignozAlertRule[] = []; const rulesToUpdate: SignozAlertRule[] = []; const rulesToDelete: string[] = []; for (const [id, rule] of desiredRules) { if (!currentRuleIds.has(id)) { rulesToCreate.push(rule); } else { rulesToUpdate.push(rule); } } for (const id of currentRuleIds) { if (!desiredRules.has(id)) rulesToDelete.push(id); } const channelsToCreate: SignozChannel[] = []; const channelsToUpdate: SignozChannel[] = []; const channelsToDelete: string[] = []; for (const [id, ch] of desiredChannels) { if (!currentChannelIds.has(id)) { channelsToCreate.push(ch); } else { channelsToUpdate.push(ch); } } for (const id of currentChannelIds) { if (!desiredChannels.has(id)) channelsToDelete.push(id); } return { rules: { create: rulesToCreate, update: rulesToUpdate, delete: rulesToDelete }, channels: { create: channelsToCreate, update: channelsToUpdate, delete: channelsToDelete }, }; } export async function runObservabilityAlertsApply( input: KernelCommandInput, _context: KernelRuntimeContext, ): Promise> { const dryRun = input.argv.includes("--dry-run"); const apiUrl = process.env["WARPGOGOL_SIGNOZ_API_URL"]; const apiToken = process.env["WARPGOGOL_SIGNOZ_API_TOKEN"]; if (!apiUrl || !apiToken) { return diagnosticsResult("observability.alerts.apply", [ { ruleId: "OBS-ALR-APPLY-ENV", severity: "error", file: "", message: "WARPGOGOL_SIGNOZ_API_URL and WARPGOGOL_SIGNOZ_API_TOKEN must be set to apply alerts.", fixHint: "Set both env vars: WARPGOGOL_SIGNOZ_API_URL=https://observe.warpgogol.com WARPGOGOL_SIGNOZ_API_TOKEN=", }, ]); } const client = createSignozApiClient({ apiUrl, apiToken }); const currentRules = await client.listManagedRules(); const currentChannels = await client.listManagedChannels(); const plan = buildPlan(currentRules, currentChannels); const planSummary = `Rules: ${plan.rules.create.length} create, ${plan.rules.update.length} update, ${plan.rules.delete.length} delete. ` + `Channels: ${plan.channels.create.length} create, ${plan.channels.update.length} update, ${plan.channels.delete.length} delete.`; if (dryRun) { return diagnosticsResult("observability.alerts.apply", [ { ruleId: "OBS-ALR-APPLY-DRY-RUN", severity: "info", file: "", message: `Dry-run plan: ${planSummary}`, fixHint: "Run without --dry-run to apply.", }, ]); } // Apply for (const ch of plan.channels.create) await client.createChannel(ch); for (const ch of plan.channels.update) await client.updateChannel(ch); for (const id of plan.channels.delete) await client.deleteChannel(id); for (const rule of plan.rules.create) await client.createRule(rule); for (const rule of plan.rules.update) await client.updateRule(rule); for (const id of plan.rules.delete) await client.deleteRule(id); // Verify convergence const postRules = await client.listManagedRules(); const postChannels = await client.listManagedChannels(); const postPlan = buildPlan(postRules, postChannels); const converged = postPlan.rules.create.length === 0 && postPlan.rules.update.length === 0 && postPlan.rules.delete.length === 0 && postPlan.channels.create.length === 0 && postPlan.channels.update.length === 0 && postPlan.channels.delete.length === 0; return diagnosticsResult("observability.alerts.apply", [ { ruleId: converged ? "OBS-ALR-APPLY-OK" : "OBS-ALR-APPLY-NOT-CONVERGED", severity: converged ? "info" : "error", file: "", message: converged ? `Applied successfully: ${planSummary}` : `Apply did not converge. Remaining: ${JSON.stringify(postPlan)}`, fixHint: converged ? "" : "Check the SigNoz API for errors and re-run.", }, ]); }