Files
pikasTech-unidesk/scripts/native/hwlab/runtime-pipeline-provenance.mjs
T

56 lines
3.0 KiB
JavaScript

#!/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 }));
}