fix: align dev artifact catalog identity

This commit is contained in:
HWLAB Code Queue
2026-05-21 17:54:01 +00:00
parent 1a2efd4915
commit ef35856bb0
13 changed files with 1138 additions and 185 deletions
+92
View File
@@ -48,6 +48,7 @@ const requiredDevDeployApplyValidationCommands = [
const requiredPreflightValidationCommands = [
"node --check scripts/dev-gate-preflight.mjs",
"node --check scripts/src/dev-gate-preflight.mjs",
"node --check scripts/refresh-artifact-catalog.mjs",
"node scripts/dev-gate-preflight.mjs"
];
const requiredSmokeCommand = "node scripts/m1-contract-smoke.mjs";
@@ -627,6 +628,94 @@ function assertDevDeployApplyReport(report, label) {
}
}
function assertShaOrNotPublished(value, label) {
assertString(value, label);
assert.ok(
value === "not_published" || /^sha256:[a-f0-9]{64}$/.test(value),
`${label} must be not_published or a sha256 digest`
);
}
function assertArtifactIdentity(identity, label, target) {
assertObject(identity, label);
for (const field of [
"source",
"deployManifest",
"artifactCatalog",
"services",
"serviceCommitIds",
"matchesSource",
"publishVerified",
"refreshCommands"
]) {
assert.ok(Object.hasOwn(identity, field), `${label} missing ${field}`);
}
assertObject(identity.source, `${label}.source`);
assert.equal(identity.source.ref, target.ref, `${label}.source.ref`);
assert.equal(identity.source.commitId, target.commitId, `${label}.source.commitId`);
assert.equal(identity.source.shortCommitId, target.shortCommitId, `${label}.source.shortCommitId`);
assertObject(identity.deployManifest, `${label}.deployManifest`);
assert.equal(identity.deployManifest.path, "deploy/deploy.json", `${label}.deployManifest.path`);
assert.match(identity.deployManifest.commitId, /^[a-f0-9]{7,40}$/, `${label}.deployManifest.commitId`);
assert.equal(typeof identity.deployManifest.matchesSource, "boolean", `${label}.deployManifest.matchesSource`);
assertObject(identity.artifactCatalog, `${label}.artifactCatalog`);
assert.equal(identity.artifactCatalog.path, "deploy/artifact-catalog.dev.json", `${label}.artifactCatalog.path`);
assert.match(identity.artifactCatalog.commitId, /^[a-f0-9]{7,40}$/, `${label}.artifactCatalog.commitId`);
assert.ok(["contract-skeleton", "published"].includes(identity.artifactCatalog.artifactState), `${label}.artifactCatalog.artifactState`);
assert.equal(typeof identity.artifactCatalog.ciPublished, "boolean", `${label}.artifactCatalog.ciPublished`);
assert.equal(typeof identity.artifactCatalog.registryVerified, "boolean", `${label}.artifactCatalog.registryVerified`);
assertString(identity.artifactCatalog.provenance, `${label}.artifactCatalog.provenance`);
assert.equal(typeof identity.artifactCatalog.matchesSource, "boolean", `${label}.artifactCatalog.matchesSource`);
assertObject(identity.artifactCatalog.digestCounts, `${label}.artifactCatalog.digestCounts`);
for (const field of ["sha256", "notPublished", "invalid"]) {
assert.equal(typeof identity.artifactCatalog.digestCounts[field], "number", `${label}.artifactCatalog.digestCounts.${field}`);
}
assertArray(identity.services, `${label}.services`);
assert.ok(identity.services.length >= 1, `${label}.services must not be empty`);
assertUnique(identity.services.map((service) => service.serviceId), `${label}.services`);
for (const [index, service] of identity.services.entries()) {
const serviceLabel = `${label}.services[${index}]`;
assertObject(service, serviceLabel);
for (const field of ["serviceId", "commitId", "matchesSource", "image", "imageTag", "digest", "publishState"]) {
assert.ok(Object.hasOwn(service, field), `${serviceLabel} missing ${field}`);
}
assertString(service.serviceId, `${serviceLabel}.serviceId`);
assert.match(service.commitId, /^[a-f0-9]{7,40}$/, `${serviceLabel}.commitId`);
assert.equal(typeof service.matchesSource, "boolean", `${serviceLabel}.matchesSource`);
assertString(service.image, `${serviceLabel}.image`);
assertString(service.imageTag, `${serviceLabel}.imageTag`);
assertShaOrNotPublished(service.digest, `${serviceLabel}.digest`);
assert.ok(["skeleton-only", "published"].includes(service.publishState), `${serviceLabel}.publishState`);
}
assertStringArray(identity.serviceCommitIds, `${label}.serviceCommitIds`, { minLength: 1 });
assert.equal(typeof identity.matchesSource, "boolean", `${label}.matchesSource`);
assert.equal(typeof identity.publishVerified, "boolean", `${label}.publishVerified`);
assertObject(identity.refreshCommands, `${label}.refreshCommands`);
assert.equal(
identity.refreshCommands.blocked,
`node scripts/refresh-artifact-catalog.mjs --target-ref ${target.ref} --blocked`,
`${label}.refreshCommands.blocked`
);
assert.equal(
identity.refreshCommands.published,
`node scripts/refresh-artifact-catalog.mjs --target-ref ${target.ref} --publish-report reports/dev-gate/dev-artifacts.json`,
`${label}.refreshCommands.published`
);
if (identity.publishVerified) {
assert.equal(identity.artifactCatalog.ciPublished, true, `${label}.artifactCatalog.ciPublished`);
assert.equal(identity.artifactCatalog.registryVerified, true, `${label}.artifactCatalog.registryVerified`);
assert.equal(identity.artifactCatalog.digestCounts.sha256, identity.services.length, `${label}.artifactCatalog.digestCounts.sha256`);
assert.equal(identity.artifactCatalog.digestCounts.notPublished, 0, `${label}.artifactCatalog.digestCounts.notPublished`);
assert.equal(identity.artifactCatalog.digestCounts.invalid, 0, `${label}.artifactCatalog.digestCounts.invalid`);
}
}
async function validateDevEdgeReport(report, label) {
for (const field of [
"$schema",
@@ -892,6 +981,7 @@ async function validatePreflightReport(relativePath, report) {
"prodDisabled",
"forbiddenActions",
"validationCommands",
"artifactIdentity",
"conclusion",
"checks",
"blockers"
@@ -933,6 +1023,8 @@ async function validatePreflightReport(relativePath, report) {
);
}
assertArtifactIdentity(report.artifactIdentity, `${label}.artifactIdentity`, report.target);
assertArray(report.checks, `${label}.checks`);
assert.ok(report.checks.length >= 1, `${label}.checks must not be empty`);
assertUnique(report.checks.map((check) => check.id), `${label}.checks`);