Files
pikasTech-unidesk/scripts/src/pipeline-provenance.ts
T

54 lines
2.5 KiB
TypeScript

export const pipelineProvenanceAnnotationKeys = {
configRef: "unidesk.ai/owning-config-ref",
effectiveConfigSha256: "unidesk.ai/effective-config-sha256",
renderer: "unidesk.ai/source-artifact-renderer",
mode: "unidesk.ai/source-artifact-mode",
} as const;
export interface PipelineProvenanceContract {
readonly configRef: string;
readonly effectiveConfigSha256: string;
readonly renderer: string;
readonly mode: string;
}
export function pipelineProvenanceAnnotations(provenance: PipelineProvenanceContract): Record<string, string> {
return {
[pipelineProvenanceAnnotationKeys.configRef]: provenance.configRef,
[pipelineProvenanceAnnotationKeys.effectiveConfigSha256]: provenance.effectiveConfigSha256,
[pipelineProvenanceAnnotationKeys.renderer]: provenance.renderer,
[pipelineProvenanceAnnotationKeys.mode]: provenance.mode,
};
}
export function withPipelineProvenanceAnnotations(
manifest: Record<string, unknown>,
provenance: PipelineProvenanceContract,
): Record<string, unknown> {
const next = structuredClone(manifest);
const metadata = asRecord(next.metadata, "manifest.metadata");
const annotations = metadata.annotations === undefined ? {} : asRecord(metadata.annotations, "manifest.metadata.annotations");
metadata.annotations = { ...annotations, ...pipelineProvenanceAnnotations(provenance) };
return next;
}
export function pipelineProvenanceFromManifest(manifest: Record<string, unknown>): PipelineProvenanceContract | null {
const metadata = isRecord(manifest.metadata) ? manifest.metadata : {};
const annotations = isRecord(metadata.annotations) ? metadata.annotations : {};
const configRef = annotations[pipelineProvenanceAnnotationKeys.configRef];
const effectiveConfigSha256 = annotations[pipelineProvenanceAnnotationKeys.effectiveConfigSha256];
const renderer = annotations[pipelineProvenanceAnnotationKeys.renderer];
const mode = annotations[pipelineProvenanceAnnotationKeys.mode];
if ([configRef, effectiveConfigSha256, renderer, mode].some((value) => typeof value !== "string" || value.length === 0)) return null;
return { configRef, effectiveConfigSha256, renderer, mode } as PipelineProvenanceContract;
}
function asRecord(value: unknown, path: string): Record<string, unknown> {
if (!isRecord(value)) throw new Error(`${path} must be an object`);
return value;
}
function isRecord(value: unknown): value is Record<string, unknown> {
return value !== null && typeof value === "object" && !Array.isArray(value);
}