#!/usr/bin/env node // Responsibility: apply the YAML-owned HWLAB Pipeline provenance contract during the normal control-plane postprocess. import { readFileSync, writeFileSync } from "node:fs"; import { createRequire } from "node:module"; const require = createRequire(`${process.cwd()}/package.json`); const YAML = require("yaml"); export function applyHwlabPipelineProvenance(manifest, annotations, expectedKeys) { if (!isRecord(manifest) || manifest.kind !== "Pipeline") return false; const entries = isRecord(annotations) ? Object.entries(annotations) : []; const actualKeys = entries.map(([key]) => key).sort(); const sortedExpectedKeys = Array.isArray(expectedKeys) ? [...expectedKeys].sort() : []; if (JSON.stringify(actualKeys) !== JSON.stringify(sortedExpectedKeys) || entries.some(([, value]) => typeof value !== "string" || value.length === 0)) { throw new Error("overlay.pipelineProvenanceAnnotations must match the shared four-key contract"); } manifest.metadata = isRecord(manifest.metadata) ? manifest.metadata : {}; manifest.metadata.annotations = { ...(isRecord(manifest.metadata.annotations) ? manifest.metadata.annotations : {}), ...annotations }; return true; } export function postprocessHwlabPipelineProvenance({ pipelinePath, overlay, expectedKeys }) { const documents = YAML.parseAllDocuments(readFileSync(pipelinePath, "utf8")); const manifests = documents.map((document) => document.toJS()).filter((document) => document !== null); const changed = manifests.filter((manifest) => applyHwlabPipelineProvenance(manifest, overlay.pipelineProvenanceAnnotations, expectedKeys)); if (changed.length !== 1) throw new Error(`expected exactly one Pipeline in ${pipelinePath}; observed ${changed.length}`); writeFileSync(pipelinePath, `${manifests.map((manifest) => YAML.stringify(manifest).trimEnd()).join("\n---\n")}\n`); return { pipelinePath, pipelineName: changed[0]?.metadata?.name ?? null, annotationCount: expectedKeys.length }; } function isRecord(value) { return value !== null && typeof value === "object" && !Array.isArray(value); } function requiredArgument(name) { const index = process.argv.indexOf(name); const value = index === -1 ? undefined : process.argv[index + 1]; if (typeof value !== "string" || value.length === 0 || value.startsWith("--")) throw new Error(`${name} is required`); return value; } function decodedJsonEnv(name) { const encoded = process.env[name]; if (typeof encoded !== "string" || encoded.length === 0) throw new Error(`${name} is required`); return JSON.parse(Buffer.from(encoded, "base64").toString("utf8")); } if (process.argv.includes("--pipeline")) { const result = postprocessHwlabPipelineProvenance({ pipelinePath: requiredArgument("--pipeline"), overlay: decodedJsonEnv("UNIDESK_RUNTIME_GITOPS_OVERLAY_B64"), expectedKeys: decodedJsonEnv("UNIDESK_PIPELINE_PROVENANCE_KEYS_B64"), }); console.error(JSON.stringify({ event: "unidesk-runtime-pipeline-provenance", ok: true, ...result })); }