feat(core): add upstream provenance registry validation

This commit is contained in:
2026-09-16 15:34:45 +02:00
committed by Simon
parent 1e3abaf824
commit b885a160bd
@@ -0,0 +1,50 @@
import type { UpstreamCapabilityRecord } from "@siax/c0py-types";
const COPyleft_ISOLATED = new Set(["AGPL-3.0", "AGPL-3.0-only", "AGPL-3.0-or-later"]);
export interface ProvenanceValidationResult {
valid: boolean;
errors: string[];
warnings: string[];
}
export function validateUpstreamCapability(
record: UpstreamCapabilityRecord,
): ProvenanceValidationResult {
const errors: string[] = [];
const warnings: string[] = [];
const source = record.source;
if (!record.capability.trim()) errors.push("capability is required");
if (!record.rationale.trim()) errors.push("rationale is required");
if (record.disposition !== "DROP" && record.tests.length === 0) {
errors.push("at least one verification test is required");
}
if (["CHERRY_PICK", "REFERENCE_ONLY", "REIMPLEMENT"].includes(record.disposition)) {
if (!source.repository) errors.push("source.repository is required");
if (!source.commit) errors.push("source.commit is required");
}
if (record.disposition === "CHERRY_PICK") {
if (!source.sourcePaths?.length) errors.push("source.sourcePaths is required for CHERRY_PICK");
if (!source.license) errors.push("source.license is required for CHERRY_PICK");
}
if (source.license && COPyleft_ISOLATED.has(source.license) && record.disposition === "CHERRY_PICK") {
errors.push("AGPL/copy-left source must remain behind an adapter/service boundary; do not cherry-pick into core");
}
if (source.license && COPyleft_ISOLATED.has(source.license) && record.disposition !== "ADAPTER") {
warnings.push("copyleft source should normally be classified as ADAPTER");
}
return { valid: errors.length === 0, errors, warnings };
}
export function assertUpstreamCapability(record: UpstreamCapabilityRecord): void {
const result = validateUpstreamCapability(record);
if (!result.valid) {
throw new Error(`Invalid upstream capability ${record.id}: ${result.errors.join("; ")}`);
}
}