refactor: adapter 구현중..
This commit is contained in:
@@ -2,6 +2,8 @@ import { z } from "zod";
|
||||
|
||||
export * from "../../src/contracts/release-artifacts.ts";
|
||||
|
||||
import { MANUAL_A11Y_ROUTE_IDS } from "../lib/manual-a11y-evidence.ts";
|
||||
|
||||
const nonEmptyString = z.string().min(1);
|
||||
const timestamp = z.iso.datetime();
|
||||
const sha256 = z.string().regex(/^[a-f0-9]{64}$/u);
|
||||
@@ -85,6 +87,13 @@ export const localEvidenceAssessmentArtifactSchema = z
|
||||
candidate: z
|
||||
.object({ distSha256: sha256, lockfileSha256: sha256, sbomSha256: sha256 })
|
||||
.strict(),
|
||||
secretScan: z
|
||||
.object({
|
||||
policySha256: sha256,
|
||||
sarifSha256: sha256,
|
||||
scanInputSha256: sha256,
|
||||
})
|
||||
.strict(),
|
||||
policyInputs: z.array(assessmentInputRowSchema).min(1).max(256),
|
||||
evidenceInputs: z.array(assessmentInputRowSchema).min(1).max(4_096),
|
||||
checks: z
|
||||
@@ -308,20 +317,162 @@ const outputDigestSchema = z
|
||||
})
|
||||
.strict();
|
||||
|
||||
export const bundlePerformanceArtifactSchema = z
|
||||
const bundleOutputInventoryShape = {
|
||||
schemaVersion: z.literal(1),
|
||||
generatedAt: timestamp,
|
||||
context: z
|
||||
.object({
|
||||
nodeVersion: nonEmptyString,
|
||||
packageManager: nonEmptyString,
|
||||
runnerImage: nonEmptyString,
|
||||
})
|
||||
.strict(),
|
||||
outputs: z.array(outputDigestSchema).min(1),
|
||||
} as const;
|
||||
|
||||
function addUniqueBundleOutputIssues(
|
||||
artifact: Readonly<{ outputs: readonly Readonly<{ path: string }>[] }>,
|
||||
context: z.RefinementCtx,
|
||||
): void {
|
||||
const paths = artifact.outputs.map(({ path }) => path);
|
||||
if (new Set(paths).size !== paths.length) {
|
||||
context.addIssue({
|
||||
code: "custom",
|
||||
path: ["outputs"],
|
||||
message: "output paths must be unique",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export const bundleOutputInventoryArtifactSchema = z
|
||||
.object(bundleOutputInventoryShape)
|
||||
.strict()
|
||||
.superRefine(addUniqueBundleOutputIssues);
|
||||
|
||||
const bundleMeasurementSchema = z
|
||||
.object({ path: nonEmptyString, gzipBytes: z.int().nonnegative() })
|
||||
.strict();
|
||||
const bundleClassificationSchema = z
|
||||
.object({
|
||||
schemaVersion: z.literal(1),
|
||||
generatedAt: timestamp,
|
||||
context: z
|
||||
.object({
|
||||
nodeVersion: nonEmptyString,
|
||||
packageManager: nonEmptyString,
|
||||
runnerImage: nonEmptyString,
|
||||
})
|
||||
.strict(),
|
||||
outputs: z.array(outputDigestSchema).min(1),
|
||||
initialFiles: z.array(nonEmptyString),
|
||||
lazyFiles: z.array(nonEmptyString),
|
||||
missingImports: z.array(nonEmptyString),
|
||||
})
|
||||
.strict();
|
||||
const bundleThresholdsSchema = z
|
||||
.object({
|
||||
initialJsGzipBytes: z.int().positive(),
|
||||
lazyChunkGzipBytes: z.int().positive(),
|
||||
})
|
||||
.strict();
|
||||
const bundleBudgetResultSchema = z
|
||||
.object({
|
||||
initialPassed: z.boolean(),
|
||||
lazyResults: z.array(
|
||||
bundleMeasurementSchema.extend({
|
||||
threshold: z.int().positive(),
|
||||
passed: z.boolean(),
|
||||
}),
|
||||
),
|
||||
passed: z.boolean(),
|
||||
})
|
||||
.strict();
|
||||
|
||||
export const bundlePerformanceArtifactSchema = z
|
||||
.object({
|
||||
...bundleOutputInventoryShape,
|
||||
measurements: z
|
||||
.object({
|
||||
initialJsGzipBytes: z.int().nonnegative(),
|
||||
lazyChunks: z.array(bundleMeasurementSchema),
|
||||
})
|
||||
.strict(),
|
||||
classification: bundleClassificationSchema,
|
||||
missingOutputs: z.array(nonEmptyString),
|
||||
thresholds: bundleThresholdsSchema,
|
||||
results: bundleBudgetResultSchema,
|
||||
fixtures: z.tuple([
|
||||
z.object({ name: z.literal("initial-js-over-budget"), passed: z.boolean() }).strict(),
|
||||
z.object({ name: z.literal("lazy-chunk-over-budget"), passed: z.boolean() }).strict(),
|
||||
]),
|
||||
passed: z.boolean(),
|
||||
})
|
||||
.strict()
|
||||
.superRefine((artifact, context) => {
|
||||
addUniqueBundleOutputIssues(artifact, context);
|
||||
const issue = (path: PropertyKey[], message: string) =>
|
||||
context.addIssue({ code: "custom", path, message });
|
||||
const uniqueSorted = (values: readonly string[]) =>
|
||||
new Set(values).size === values.length &&
|
||||
JSON.stringify(values) === JSON.stringify([...values].sort());
|
||||
for (const [field, values] of [
|
||||
["initialFiles", artifact.classification.initialFiles],
|
||||
["lazyFiles", artifact.classification.lazyFiles],
|
||||
["missingImports", artifact.classification.missingImports],
|
||||
["missingOutputs", artifact.missingOutputs],
|
||||
] as const) {
|
||||
if (!uniqueSorted(values)) {
|
||||
issue(
|
||||
field === "missingOutputs" ? [field] : ["classification", field],
|
||||
"paths must be unique and sorted",
|
||||
);
|
||||
}
|
||||
}
|
||||
const initial = new Set(artifact.classification.initialFiles);
|
||||
if (artifact.classification.lazyFiles.some((file) => initial.has(file))) {
|
||||
issue(["classification"], "initial and lazy files must be disjoint");
|
||||
}
|
||||
const outputs = new Map(
|
||||
artifact.outputs.map((output) => [output.path.replace(/^dist\//u, ""), output]),
|
||||
);
|
||||
const expectedMissing = [
|
||||
...artifact.classification.initialFiles,
|
||||
...artifact.classification.lazyFiles,
|
||||
].filter((file) => !outputs.has(file)).sort();
|
||||
if (JSON.stringify(artifact.missingOutputs) !== JSON.stringify(expectedMissing)) {
|
||||
issue(["missingOutputs"], "must equal classified JavaScript outputs not found in inventory");
|
||||
}
|
||||
const expectedInitialBytes = artifact.classification.initialFiles.reduce(
|
||||
(total, file) => total + (outputs.get(file)?.gzipBytes ?? 0),
|
||||
0,
|
||||
);
|
||||
if (artifact.measurements.initialJsGzipBytes !== expectedInitialBytes) {
|
||||
issue(["measurements", "initialJsGzipBytes"], "must equal classified initial output bytes");
|
||||
}
|
||||
const expectedLazyChunks = artifact.classification.lazyFiles.map((file) => ({
|
||||
path: file,
|
||||
gzipBytes: outputs.get(file)?.gzipBytes ?? 0,
|
||||
}));
|
||||
if (JSON.stringify(artifact.measurements.lazyChunks) !== JSON.stringify(expectedLazyChunks)) {
|
||||
issue(["measurements", "lazyChunks"], "must equal classified lazy output bytes");
|
||||
}
|
||||
const expectedInitialPassed =
|
||||
artifact.measurements.initialJsGzipBytes <= artifact.thresholds.initialJsGzipBytes;
|
||||
if (artifact.results.initialPassed !== expectedInitialPassed) {
|
||||
issue(["results", "initialPassed"], "must agree with initial threshold");
|
||||
}
|
||||
const expectedLazyResults = artifact.measurements.lazyChunks.map((chunk) => ({
|
||||
...chunk,
|
||||
threshold: artifact.thresholds.lazyChunkGzipBytes,
|
||||
passed: chunk.gzipBytes <= artifact.thresholds.lazyChunkGzipBytes,
|
||||
}));
|
||||
if (JSON.stringify(artifact.results.lazyResults) !== JSON.stringify(expectedLazyResults)) {
|
||||
issue(["results", "lazyResults"], "must agree with lazy measurements and threshold");
|
||||
}
|
||||
const expectedBudgetPassed =
|
||||
expectedInitialPassed && expectedLazyResults.every(({ passed }) => passed);
|
||||
if (artifact.results.passed !== expectedBudgetPassed) {
|
||||
issue(["results", "passed"], "must agree with budget results");
|
||||
}
|
||||
const expectedPassed =
|
||||
expectedBudgetPassed &&
|
||||
artifact.fixtures.every(({ passed }) => passed) &&
|
||||
artifact.classification.missingImports.length === 0 &&
|
||||
artifact.missingOutputs.length === 0;
|
||||
if (artifact.passed !== expectedPassed) {
|
||||
issue(["passed"], "must agree with budgets, fixtures, and manifest integrity");
|
||||
}
|
||||
});
|
||||
|
||||
const cyclonedxComponentSchema = z
|
||||
.object({
|
||||
@@ -571,3 +722,694 @@ export const runbookRecordArtifactSchema = z
|
||||
passed: z.boolean(),
|
||||
})
|
||||
.strict();
|
||||
|
||||
const failureList = z.array(nonEmptyString).max(4_096);
|
||||
const sourceOrFixtureMode = z.enum(["source", "negative-fixture"]);
|
||||
const namedBooleanResultSchema = z
|
||||
.object({ id: nonEmptyString, passed: z.boolean() })
|
||||
.strict();
|
||||
|
||||
function addPassedFailureInvariant(
|
||||
artifact: Readonly<{ passed: boolean; failures: readonly string[] }>,
|
||||
context: z.RefinementCtx,
|
||||
): void {
|
||||
if (artifact.passed !== (artifact.failures.length === 0)) {
|
||||
context.addIssue({
|
||||
code: "custom",
|
||||
path: ["passed"],
|
||||
message: "passed must agree with failures",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function addUniqueStringIssues(
|
||||
values: readonly string[],
|
||||
path: PropertyKey[],
|
||||
context: z.RefinementCtx,
|
||||
): void {
|
||||
if (new Set(values).size !== values.length) {
|
||||
context.addIssue({ code: "custom", path, message: "must not contain duplicates" });
|
||||
}
|
||||
}
|
||||
|
||||
export const automatedA11yArtifactSchema = z
|
||||
.object({
|
||||
schemaVersion: z.literal(1),
|
||||
generatedAt: timestamp,
|
||||
scope: z.array(nonEmptyString).min(1).max(128),
|
||||
threshold: z.object({ critical: z.literal(0), serious: z.literal(0) }).strict(),
|
||||
automatedStatus: z.literal("passed"),
|
||||
manualReview: z.literal("see artifacts/tests/a11y-manual/report.json"),
|
||||
})
|
||||
.strict()
|
||||
.superRefine((artifact, context) => {
|
||||
addUniqueStringIssues(artifact.scope, ["scope"], context);
|
||||
if (JSON.stringify(artifact.scope) !== JSON.stringify(MANUAL_A11Y_ROUTE_IDS)) {
|
||||
context.addIssue({ code: "custom", path: ["scope"], message: "must match the installed route registry" });
|
||||
}
|
||||
});
|
||||
|
||||
const manualA11yResultSchema = z
|
||||
.object({
|
||||
routeId: nonEmptyString,
|
||||
path: nonEmptyString,
|
||||
reviewer: z.string().nullable(),
|
||||
reviewedAt: z.string().nullable(),
|
||||
releaseId: z.string().nullable(),
|
||||
failures: failureList,
|
||||
passed: z.boolean(),
|
||||
})
|
||||
.strict()
|
||||
.superRefine((result, context) => {
|
||||
if (result.path !== `artifacts/tests/a11y-manual/${result.routeId}.md`) {
|
||||
context.addIssue({ code: "custom", path: ["path"], message: "path must match routeId" });
|
||||
}
|
||||
const hasIdentity = Boolean(
|
||||
result.reviewer &&
|
||||
result.releaseId &&
|
||||
result.reviewedAt &&
|
||||
Number.isFinite(Date.parse(result.reviewedAt)),
|
||||
);
|
||||
if (result.passed !== (result.failures.length === 0 && hasIdentity)) {
|
||||
context.addIssue({
|
||||
code: "custom",
|
||||
path: ["passed"],
|
||||
message: "passed must agree with failures and review identity",
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
export const manualA11yReportArtifactSchema = z
|
||||
.object({
|
||||
schemaVersion: z.literal(1),
|
||||
generatedAt: timestamp,
|
||||
scope: z.array(nonEmptyString).min(1).max(128),
|
||||
results: z.array(manualA11yResultSchema).min(1).max(128),
|
||||
coherentRelease: z.boolean(),
|
||||
passed: z.boolean(),
|
||||
})
|
||||
.strict()
|
||||
.superRefine((artifact, context) => {
|
||||
const routeIds = artifact.results.map(({ routeId }) => routeId);
|
||||
addUniqueStringIssues(artifact.scope, ["scope"], context);
|
||||
addUniqueStringIssues(routeIds, ["results"], context);
|
||||
if (JSON.stringify(artifact.scope) !== JSON.stringify(MANUAL_A11Y_ROUTE_IDS)) {
|
||||
context.addIssue({ code: "custom", path: ["scope"], message: "must match the installed route registry" });
|
||||
}
|
||||
if (JSON.stringify(routeIds) !== JSON.stringify(artifact.scope)) {
|
||||
context.addIssue({ code: "custom", path: ["results"], message: "result routeIds must match scope" });
|
||||
}
|
||||
const releaseIds = artifact.results.map(({ releaseId }) => releaseId);
|
||||
const coherentRelease =
|
||||
releaseIds.every((releaseId): releaseId is string => Boolean(releaseId)) &&
|
||||
new Set(releaseIds).size === 1;
|
||||
if (artifact.coherentRelease !== coherentRelease) {
|
||||
context.addIssue({ code: "custom", path: ["coherentRelease"], message: "must represent one non-empty releaseId" });
|
||||
}
|
||||
if (
|
||||
artifact.passed !==
|
||||
(coherentRelease && artifact.results.every(({ passed }) => passed))
|
||||
) {
|
||||
context.addIssue({ code: "custom", path: ["passed"], message: "must agree with route results" });
|
||||
}
|
||||
});
|
||||
|
||||
const architectureDependencySchema = z
|
||||
.object({
|
||||
source: nonEmptyString,
|
||||
target: nonEmptyString,
|
||||
specifier: nonEmptyString,
|
||||
kind: z.enum(["local", "external"]),
|
||||
})
|
||||
.strict();
|
||||
const architectureUnresolvedSchema = z
|
||||
.object({ source: nonEmptyString, specifier: nonEmptyString, reason: nonEmptyString })
|
||||
.strict();
|
||||
const architectureViolationSchema = z
|
||||
.object({
|
||||
rule: nonEmptyString,
|
||||
severity: nonEmptyString,
|
||||
source: nonEmptyString,
|
||||
target: nonEmptyString,
|
||||
cycle: z.array(nonEmptyString).optional(),
|
||||
})
|
||||
.strict();
|
||||
const staticImportGraphSchema = z
|
||||
.object({
|
||||
analyzer: z.literal("babel-parser-node-resolver"),
|
||||
modules: z.array(nonEmptyString),
|
||||
dependencies: z.array(architectureDependencySchema),
|
||||
unresolved: z.array(architectureUnresolvedSchema),
|
||||
parseFailures: z.array(
|
||||
z.object({ source: nonEmptyString, reason: nonEmptyString }).strict(),
|
||||
),
|
||||
cycles: z.array(z.array(nonEmptyString).min(1)),
|
||||
violations: z.array(architectureViolationSchema),
|
||||
summary: z
|
||||
.object({
|
||||
modules: z.int().nonnegative(),
|
||||
typescriptModules: z.int().nonnegative(),
|
||||
dependencies: z.int().nonnegative(),
|
||||
localDependencies: z.int().nonnegative(),
|
||||
unresolved: z.int().nonnegative(),
|
||||
parseFailures: z.int().nonnegative(),
|
||||
cycles: z.int().nonnegative(),
|
||||
errors: z.int().nonnegative(),
|
||||
typeScriptOnlyPolicyPassed: z.boolean(),
|
||||
nonTypeScriptExecutableSources: z.int().nonnegative(),
|
||||
})
|
||||
.strict(),
|
||||
fixtureChecks: z
|
||||
.object({ passed: z.boolean(), checks: z.array(nonEmptyString), failures: failureList })
|
||||
.strict(),
|
||||
typeScriptOnlySourcePolicy: z
|
||||
.object({
|
||||
checkedRoots: z.array(nonEmptyString).min(1),
|
||||
exceptionsAllowed: z.literal(false),
|
||||
violations: z.array(nonEmptyString),
|
||||
passed: z.boolean(),
|
||||
})
|
||||
.strict(),
|
||||
})
|
||||
.strict()
|
||||
.superRefine((graph, context) => {
|
||||
const counts = [
|
||||
["modules", graph.modules.length],
|
||||
["dependencies", graph.dependencies.length],
|
||||
["localDependencies", graph.dependencies.filter(({ kind }) => kind === "local").length],
|
||||
["unresolved", graph.unresolved.length],
|
||||
["parseFailures", graph.parseFailures.length],
|
||||
["cycles", graph.cycles.length],
|
||||
["errors", graph.violations.filter(({ severity }) => severity === "error").length],
|
||||
["nonTypeScriptExecutableSources", graph.typeScriptOnlySourcePolicy.violations.length],
|
||||
] as const;
|
||||
for (const [field, expected] of counts) {
|
||||
if (graph.summary[field] !== expected) {
|
||||
context.addIssue({ code: "custom", path: ["summary", field], message: "count does not match evidence rows" });
|
||||
}
|
||||
}
|
||||
if (graph.summary.typescriptModules > graph.summary.modules) {
|
||||
context.addIssue({ code: "custom", path: ["summary", "typescriptModules"], message: "cannot exceed modules" });
|
||||
}
|
||||
if (graph.fixtureChecks.passed !== (graph.fixtureChecks.failures.length === 0)) {
|
||||
context.addIssue({ code: "custom", path: ["fixtureChecks", "passed"], message: "must agree with failures" });
|
||||
}
|
||||
if (
|
||||
graph.typeScriptOnlySourcePolicy.passed !==
|
||||
(graph.typeScriptOnlySourcePolicy.violations.length === 0) ||
|
||||
graph.summary.typeScriptOnlyPolicyPassed !== graph.typeScriptOnlySourcePolicy.passed
|
||||
) {
|
||||
context.addIssue({ code: "custom", path: ["typeScriptOnlySourcePolicy", "passed"], message: "must agree with violations and summary" });
|
||||
}
|
||||
});
|
||||
const dependencyCruiserSummarySchema = z
|
||||
.object({
|
||||
violations: z.array(jsonObject),
|
||||
error: z.int().nonnegative(),
|
||||
warn: z.int().nonnegative(),
|
||||
info: z.int().nonnegative(),
|
||||
ignore: z.int().nonnegative(),
|
||||
totalCruised: z.int().nonnegative(),
|
||||
totalDependenciesCruised: z.int().nonnegative(),
|
||||
})
|
||||
.catchall(z.json());
|
||||
export const architectureDependencyReportArtifactSchema = z.union([
|
||||
z
|
||||
.object({
|
||||
modules: z.array(jsonObject),
|
||||
summary: dependencyCruiserSummarySchema,
|
||||
staticImportGraph: staticImportGraphSchema,
|
||||
})
|
||||
.strict(),
|
||||
z
|
||||
.object({
|
||||
summary: z.object({ errors: z.literal(1) }).strict(),
|
||||
dependencyCruiserOutput: z.string(),
|
||||
staticImportGraph: staticImportGraphSchema,
|
||||
})
|
||||
.strict(),
|
||||
]);
|
||||
|
||||
export const designSystemReportArtifactSchema = z
|
||||
.object({
|
||||
schemaVersion: z.literal(1),
|
||||
mode: sourceOrFixtureMode,
|
||||
checkedTokenCount: z.int().positive(),
|
||||
failures: failureList,
|
||||
passed: z.boolean(),
|
||||
})
|
||||
.strict()
|
||||
.superRefine(addPassedFailureInvariant);
|
||||
|
||||
export const i18nReportArtifactSchema = z
|
||||
.object({
|
||||
schemaVersion: z.literal(1),
|
||||
mode: sourceOrFixtureMode,
|
||||
localeCount: z.int().positive(),
|
||||
messageKeyCount: z.int().positive(),
|
||||
checkedFiles: z.int().nonnegative(),
|
||||
failures: failureList,
|
||||
passed: z.boolean(),
|
||||
})
|
||||
.strict()
|
||||
.superRefine(addPassedFailureInvariant);
|
||||
|
||||
export const diagnosticsReportArtifactSchema = z
|
||||
.object({
|
||||
schemaVersion: z.literal(1),
|
||||
mode: sourceOrFixtureMode,
|
||||
telemetryEventCount: z.int().positive(),
|
||||
diagnosticEventCount: z.int().positive(),
|
||||
checkedFiles: z.int().nonnegative(),
|
||||
failures: failureList,
|
||||
passed: z.boolean(),
|
||||
})
|
||||
.strict()
|
||||
.superRefine(addPassedFailureInvariant);
|
||||
|
||||
export const realtimeBoundariesArtifactSchema = z
|
||||
.object({
|
||||
schemaVersion: z.literal(1),
|
||||
sourceRoot: nonEmptyString,
|
||||
violations: z.array(
|
||||
z
|
||||
.object({
|
||||
ruleId: z.enum([
|
||||
"NATIVE_REALTIME_API_OUTSIDE_ADAPTER",
|
||||
"PRESENTATION_INTERVAL_OWNER",
|
||||
"UNSELECTED_REALTIME_RUNTIME_COMPOSED",
|
||||
]),
|
||||
file: nonEmptyString,
|
||||
line: z.int().positive(),
|
||||
})
|
||||
.strict(),
|
||||
),
|
||||
passed: z.boolean(),
|
||||
})
|
||||
.strict()
|
||||
.superRefine((artifact, context) => {
|
||||
if (artifact.passed !== (artifact.violations.length === 0)) {
|
||||
context.addIssue({ code: "custom", path: ["passed"], message: "must agree with violations" });
|
||||
}
|
||||
const keys = artifact.violations.map(({ ruleId, file, line }) => `${file}\0${line}\0${ruleId}`);
|
||||
addUniqueStringIssues(keys, ["violations"], context);
|
||||
});
|
||||
|
||||
const optionalRecipeBundleOutputSchema = z
|
||||
.object({
|
||||
fileName: nonEmptyString,
|
||||
bytes: z.int().nonnegative(),
|
||||
gzipBytes: z.int().nonnegative(),
|
||||
sha256,
|
||||
})
|
||||
.strict();
|
||||
const optionalRecipeBundleMeasurementSchema = z
|
||||
.object({
|
||||
recipeId: nonEmptyString,
|
||||
sourceRoots: z.array(nonEmptyString).min(1),
|
||||
sourceFileCount: z.int().positive(),
|
||||
toolchain: z
|
||||
.object({
|
||||
bundler: z.literal("vite"),
|
||||
viteVersion: nonEmptyString,
|
||||
mode: z.literal("production"),
|
||||
target: z.literal("es2022"),
|
||||
format: z.literal("es"),
|
||||
minifier: z.literal("esbuild"),
|
||||
treeshake: z.literal(false),
|
||||
compression: z.literal("node-zlib-gzip"),
|
||||
})
|
||||
.strict(),
|
||||
outputs: z.array(optionalRecipeBundleOutputSchema).min(1),
|
||||
bytes: z.int().nonnegative(),
|
||||
gzipBytes: z.int().nonnegative(),
|
||||
bundleBudgetGzipBytes: z.int().positive(),
|
||||
remainingGzipBytes: z.int(),
|
||||
sha256,
|
||||
passed: z.boolean(),
|
||||
})
|
||||
.strict()
|
||||
.superRefine((measurement, context) => {
|
||||
if (measurement.bytes !== measurement.outputs.reduce((total, output) => total + output.bytes, 0)) {
|
||||
context.addIssue({ code: "custom", path: ["bytes"], message: "must equal output bytes" });
|
||||
}
|
||||
if (measurement.gzipBytes !== measurement.outputs.reduce((total, output) => total + output.gzipBytes, 0)) {
|
||||
context.addIssue({ code: "custom", path: ["gzipBytes"], message: "must equal output gzip bytes" });
|
||||
}
|
||||
if (measurement.remainingGzipBytes !== measurement.bundleBudgetGzipBytes - measurement.gzipBytes) {
|
||||
context.addIssue({ code: "custom", path: ["remainingGzipBytes"], message: "must equal budget minus gzip bytes" });
|
||||
}
|
||||
if (measurement.passed !== (measurement.gzipBytes <= measurement.bundleBudgetGzipBytes)) {
|
||||
context.addIssue({ code: "custom", path: ["passed"], message: "must agree with bundle budget" });
|
||||
}
|
||||
});
|
||||
const optionalRecipeReferenceRuntimeSchema = z
|
||||
.object({
|
||||
status: z.literal("AVAILABLE_NOT_COMPOSED"),
|
||||
coveredCapabilities: z.array(nonEmptyString).min(1),
|
||||
sourceRoots: z.array(nonEmptyString).min(1),
|
||||
conformanceScripts: z.array(nonEmptyString).min(1),
|
||||
productionComposition: z.literal(false),
|
||||
})
|
||||
.strict();
|
||||
const optionalRecipeViolationSchema = z
|
||||
.object({ ruleId: nonEmptyString, path: nonEmptyString, detail: nonEmptyString.optional() })
|
||||
.strict();
|
||||
export const optionalRecipesArtifactSchema = z
|
||||
.object({
|
||||
schemaVersion: z.literal(1),
|
||||
decisionId: z.literal("VD-10"),
|
||||
selectedCapabilities: z.array(nonEmptyString).max(0),
|
||||
referenceRuntimes: z.array(
|
||||
z.object({ id: nonEmptyString, referenceRuntime: optionalRecipeReferenceRuntimeSchema }).strict(),
|
||||
).min(1),
|
||||
recipeCount: z.int().nonnegative(),
|
||||
productionRuntimeDependencies: z.array(nonEmptyString).nullable(),
|
||||
referenceRuntimeBundleBudgets: z.array(optionalRecipeBundleMeasurementSchema).min(1),
|
||||
bundleStatus: z.enum(["PASS", "FAIL", "NOT_BUILT"]),
|
||||
violations: z.array(optionalRecipeViolationSchema),
|
||||
passed: z.boolean(),
|
||||
})
|
||||
.strict()
|
||||
.superRefine((artifact, context) => {
|
||||
if (artifact.recipeCount < artifact.referenceRuntimes.length) {
|
||||
context.addIssue({ code: "custom", path: ["recipeCount"], message: "cannot be smaller than reference runtimes" });
|
||||
}
|
||||
if (artifact.passed !== (artifact.violations.length === 0)) {
|
||||
context.addIssue({ code: "custom", path: ["passed"], message: "must agree with violations" });
|
||||
}
|
||||
const runtimeIds = artifact.referenceRuntimes.map(({ id }) => id).sort();
|
||||
const budgetIds = artifact.referenceRuntimeBundleBudgets.map(({ recipeId }) => recipeId).sort();
|
||||
addUniqueStringIssues(runtimeIds, ["referenceRuntimes"], context);
|
||||
addUniqueStringIssues(budgetIds, ["referenceRuntimeBundleBudgets"], context);
|
||||
if (JSON.stringify(runtimeIds) !== JSON.stringify(budgetIds)) {
|
||||
context.addIssue({ code: "custom", path: ["referenceRuntimeBundleBudgets"], message: "must cover every reference runtime" });
|
||||
}
|
||||
});
|
||||
|
||||
const OPTIONAL_RECIPE_FIXTURE_IDS = [
|
||||
"cleanup-omission",
|
||||
"unselected-runtime-dependency",
|
||||
"server-state-policy",
|
||||
"vendor-direct-import",
|
||||
"credential-leak",
|
||||
"server-state-source-duplication",
|
||||
"production-imports-recipe",
|
||||
"reference-runtime-not-composed",
|
||||
"reference-runtime-not-bundled",
|
||||
"reference-runtime-module-not-bundled",
|
||||
"reference-runtime-bundle-over-budget",
|
||||
] as const;
|
||||
const OPTIONAL_RECIPE_BUDGET_FIXTURE_IDS = [
|
||||
"file-transfer",
|
||||
"offline-indexeddb",
|
||||
"realtime",
|
||||
"service-worker-pwa",
|
||||
] as const;
|
||||
export const optionalRecipeFixturesArtifactSchema = z
|
||||
.object({
|
||||
schemaVersion: z.literal(1),
|
||||
results: z.array(
|
||||
namedBooleanResultSchema.extend({ id: z.enum(OPTIONAL_RECIPE_FIXTURE_IDS) }),
|
||||
).length(OPTIONAL_RECIPE_FIXTURE_IDS.length),
|
||||
bundleBudgetFixtures: z.array(
|
||||
z
|
||||
.object({
|
||||
recipeId: z.enum(OPTIONAL_RECIPE_BUDGET_FIXTURE_IDS),
|
||||
gzipBytes: z.int().nonnegative(),
|
||||
fixtureBudgetGzipBytes: z.int().positive(),
|
||||
rejected: z.boolean(),
|
||||
})
|
||||
.strict(),
|
||||
).length(OPTIONAL_RECIPE_BUDGET_FIXTURE_IDS.length),
|
||||
passed: z.boolean(),
|
||||
})
|
||||
.strict()
|
||||
.superRefine((artifact, context) => {
|
||||
addUniqueStringIssues(artifact.results.map(({ id }) => id), ["results"], context);
|
||||
addUniqueStringIssues(artifact.bundleBudgetFixtures.map(({ recipeId }) => recipeId), ["bundleBudgetFixtures"], context);
|
||||
if (artifact.passed !== artifact.results.every(({ passed }) => passed)) {
|
||||
context.addIssue({ code: "custom", path: ["passed"], message: "must agree with fixture results" });
|
||||
}
|
||||
artifact.bundleBudgetFixtures.forEach((fixture, index) => {
|
||||
if (fixture.rejected !== (fixture.gzipBytes > fixture.fixtureBudgetGzipBytes)) {
|
||||
context.addIssue({ code: "custom", path: ["bundleBudgetFixtures", index, "rejected"], message: "must agree with fixture budget" });
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const registryCompatibilityValueSchema = z.union([
|
||||
z.enum(["none", "additive", "behavior-change", "breaking"]),
|
||||
z.boolean(),
|
||||
]);
|
||||
const REGISTRY_COMPATIBILITY_FIXTURE_IDS = [
|
||||
"ordering-only",
|
||||
"row-addition",
|
||||
"behavior-change",
|
||||
"row-removal",
|
||||
"field-type-narrowing",
|
||||
"route-path-change",
|
||||
"registry-contract-narrowing",
|
||||
"breaking-evidence-required",
|
||||
"tampered-baseline-digest",
|
||||
] as const;
|
||||
export const registryCompatibilityFixturesArtifactSchema = z
|
||||
.object({
|
||||
schemaVersion: z.literal(1),
|
||||
results: z.array(
|
||||
z
|
||||
.object({
|
||||
id: z.enum(REGISTRY_COMPATIBILITY_FIXTURE_IDS),
|
||||
expected: registryCompatibilityValueSchema,
|
||||
actual: registryCompatibilityValueSchema,
|
||||
passed: z.boolean(),
|
||||
})
|
||||
.strict(),
|
||||
).length(REGISTRY_COMPATIBILITY_FIXTURE_IDS.length),
|
||||
})
|
||||
.strict()
|
||||
.superRefine((artifact, context) => {
|
||||
addUniqueStringIssues(artifact.results.map(({ id }) => id), ["results"], context);
|
||||
artifact.results.forEach((result, index) => {
|
||||
if (result.passed !== (result.actual === result.expected)) {
|
||||
context.addIssue({ code: "custom", path: ["results", index, "passed"], message: "must agree with expected and actual" });
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const buildDigestSchema = z.union([sha256, z.literal("BUILD_FAILED")]);
|
||||
export const reproducibleBuildArtifactSchema = z
|
||||
.object({
|
||||
schemaVersion: z.literal(1),
|
||||
sourceDateEpoch: z.string().regex(/^\d+$/u),
|
||||
buildId: nonEmptyString,
|
||||
commitSha: nonEmptyString,
|
||||
releaseId: nonEmptyString,
|
||||
runnerImage: nonEmptyString,
|
||||
firstDigest: buildDigestSchema,
|
||||
secondDigest: buildDigestSchema,
|
||||
restored: z.boolean(),
|
||||
status: z.enum(["PASS", "FAIL"]),
|
||||
})
|
||||
.strict()
|
||||
.superRefine((artifact, context) => {
|
||||
const passed =
|
||||
artifact.restored &&
|
||||
artifact.firstDigest !== "BUILD_FAILED" &&
|
||||
artifact.firstDigest === artifact.secondDigest;
|
||||
if ((artifact.status === "PASS") !== passed) {
|
||||
context.addIssue({ code: "custom", path: ["status"], message: "must agree with build digests and restoration" });
|
||||
}
|
||||
});
|
||||
|
||||
const SUPPLY_CHAIN_FIXTURE_IDS = [
|
||||
"transitive-removal-is-real-diff",
|
||||
"tampered-integrity-rejected",
|
||||
"high-risk-self-approval-rejected",
|
||||
"denied-license-rejected",
|
||||
"critical-vulnerability-expired-exception-rejected",
|
||||
"sbom-provenance-mismatch-rejected",
|
||||
"dependency-ordering-deterministic",
|
||||
"baseline-digest-tamper-rejected",
|
||||
"vulnerability-provider-evidence-invalid",
|
||||
] as const;
|
||||
export const supplyChainFixturesArtifactSchema = z
|
||||
.object({
|
||||
schemaVersion: z.literal(1),
|
||||
results: z.array(
|
||||
namedBooleanResultSchema.extend({ id: z.enum(SUPPLY_CHAIN_FIXTURE_IDS) }),
|
||||
).length(SUPPLY_CHAIN_FIXTURE_IDS.length),
|
||||
})
|
||||
.strict()
|
||||
.superRefine((artifact, context) =>
|
||||
addUniqueStringIssues(artifact.results.map(({ id }) => id), ["results"], context)
|
||||
);
|
||||
|
||||
const providerFixtureResultSchema = z
|
||||
.object({ status: z.enum(["PASS", "FAIL_UNVERIFIED"]), failures: failureList })
|
||||
.strict()
|
||||
.superRefine((result, context) => {
|
||||
if ((result.status === "PASS") !== (result.failures.length === 0)) {
|
||||
context.addIssue({ code: "custom", path: ["status"], message: "must agree with failures" });
|
||||
}
|
||||
});
|
||||
export const supplyChainProviderFixturesArtifactSchema = z
|
||||
.object({
|
||||
schemaVersion: z.literal(1),
|
||||
actualDefaultVerifier: providerFixtureResultSchema,
|
||||
fixtures: z
|
||||
.object({
|
||||
absent: providerFixtureResultSchema,
|
||||
validImmutable: providerFixtureResultSchema,
|
||||
wrongDigest: providerFixtureResultSchema,
|
||||
invalidTar: providerFixtureResultSchema,
|
||||
})
|
||||
.strict(),
|
||||
externalTreeCanary: providerFixtureResultSchema,
|
||||
passingFixtureCount: z.int().nonnegative(),
|
||||
status: z.enum(["PASS", "FAIL"]),
|
||||
})
|
||||
.strict()
|
||||
.superRefine((artifact, context) => {
|
||||
const expectedPass =
|
||||
artifact.actualDefaultVerifier.status === "PASS" &&
|
||||
artifact.fixtures.validImmutable.status === "PASS" &&
|
||||
artifact.externalTreeCanary.status === "PASS" &&
|
||||
[artifact.fixtures.absent, artifact.fixtures.wrongDigest, artifact.fixtures.invalidTar]
|
||||
.every(({ status }) => status === "FAIL_UNVERIFIED");
|
||||
if (artifact.passingFixtureCount !== (artifact.fixtures.validImmutable.status === "PASS" ? 1 : 0)) {
|
||||
context.addIssue({ code: "custom", path: ["passingFixtureCount"], message: "must count the passing immutable fixture" });
|
||||
}
|
||||
if ((artifact.status === "PASS") !== expectedPass) {
|
||||
context.addIssue({ code: "custom", path: ["status"], message: "must agree with required fixture outcomes" });
|
||||
}
|
||||
});
|
||||
|
||||
const compatibilityClassificationSchema = z.enum(["additive", "breaking"]);
|
||||
export const compatibilityFixturesArtifactSchema = z
|
||||
.object({
|
||||
schemaVersion: z.literal(1),
|
||||
generatedAt: timestamp,
|
||||
rules: z.array(nonEmptyString).length(5),
|
||||
results: z.array(
|
||||
z
|
||||
.object({
|
||||
family: z.enum(["api", "config", "storage", "release"]),
|
||||
expected: compatibilityClassificationSchema,
|
||||
actual: compatibilityClassificationSchema,
|
||||
passed: z.boolean(),
|
||||
})
|
||||
.strict(),
|
||||
).length(8),
|
||||
})
|
||||
.strict()
|
||||
.superRefine((artifact, context) => {
|
||||
const keys = artifact.results.map(({ family, expected }) => `${family}\0${expected}`);
|
||||
addUniqueStringIssues(keys, ["results"], context);
|
||||
artifact.results.forEach((result, index) => {
|
||||
if (result.passed !== (result.actual === result.expected)) {
|
||||
context.addIssue({ code: "custom", path: ["results", index, "passed"], message: "must agree with expected and actual" });
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
export const documentationReviewArtifactSchema = z
|
||||
.object({
|
||||
schemaVersion: z.literal(1),
|
||||
generatedAt: timestamp,
|
||||
status: z.literal("PASS_SCOPED"),
|
||||
reviewer: z.literal("wiki-diagram-reviewer"),
|
||||
standard: z.literal("rules/diagram-standards.md v2"),
|
||||
evidenceReport: z
|
||||
.object({ repoPath: nonEmptyString, canonicalPath: nonEmptyString, canonicalSha256: sha256 })
|
||||
.strict(),
|
||||
reportDigestValid: z.boolean(),
|
||||
results: z.array(
|
||||
z
|
||||
.object({
|
||||
diagram: z.enum(["overview", "staticDelivery"]),
|
||||
sourcePath: nonEmptyString,
|
||||
sha256,
|
||||
sourceReferenced: z.boolean(),
|
||||
digestReferenced: z.boolean(),
|
||||
reviewer: z.literal("wiki-diagram-reviewer"),
|
||||
score: z.number().min(0).max(100),
|
||||
scorePass: z.boolean(),
|
||||
passed: z.boolean(),
|
||||
})
|
||||
.strict(),
|
||||
).length(2),
|
||||
passed: z.boolean(),
|
||||
})
|
||||
.strict()
|
||||
.superRefine((artifact, context) => {
|
||||
addUniqueStringIssues(artifact.results.map(({ diagram }) => diagram), ["results"], context);
|
||||
artifact.results.forEach((result, index) => {
|
||||
const passed = result.sourceReferenced && result.digestReferenced && result.scorePass;
|
||||
if (result.passed !== passed) {
|
||||
context.addIssue({ code: "custom", path: ["results", index, "passed"], message: "must agree with review evidence" });
|
||||
}
|
||||
});
|
||||
if (artifact.passed !== (artifact.reportDigestValid && artifact.results.every(({ passed }) => passed))) {
|
||||
context.addIssue({ code: "custom", path: ["passed"], message: "must agree with report digest and review results" });
|
||||
}
|
||||
});
|
||||
|
||||
export const hostingHeadersArtifactSchema = z
|
||||
.object({
|
||||
schemaVersion: z.literal(1),
|
||||
generatedAt: timestamp,
|
||||
mode: z.enum(["live", "invalid-live", "fixture"]),
|
||||
baseUrl: z.string().nullable(),
|
||||
providerVerificationRequired: z.boolean(),
|
||||
results: z.array(
|
||||
z
|
||||
.object({
|
||||
surface: nonEmptyString,
|
||||
header: nonEmptyString,
|
||||
expected: z.json(),
|
||||
observed: z.json().optional(),
|
||||
reason: nonEmptyString.optional(),
|
||||
passed: z.boolean(),
|
||||
})
|
||||
.strict(),
|
||||
).min(1),
|
||||
passed: z.boolean(),
|
||||
})
|
||||
.strict()
|
||||
.superRefine((artifact, context) => {
|
||||
const keys = artifact.results.map(({ surface, header }) => `${surface}\0${header}`);
|
||||
addUniqueStringIssues(keys, ["results"], context);
|
||||
const requiredKeys = [
|
||||
...["index", "runtimeConfig", "releaseManifest"].flatMap((surface) =>
|
||||
[
|
||||
"cache-control",
|
||||
"content-type",
|
||||
"content-security-policy",
|
||||
"strict-transport-security",
|
||||
"x-frame-options",
|
||||
"referrer-policy",
|
||||
"x-content-type-options",
|
||||
"permissions-policy",
|
||||
].map((header) => `${surface}\0${header}`)
|
||||
),
|
||||
"hashedAsset\0cache-control",
|
||||
"hashedAsset\0content-type",
|
||||
"sourceMap\0public",
|
||||
"serviceWorker\0enabled",
|
||||
];
|
||||
for (const requiredKey of requiredKeys) {
|
||||
if (!keys.includes(requiredKey)) {
|
||||
context.addIssue({ code: "custom", path: ["results"], message: `missing required probe: ${requiredKey}` });
|
||||
}
|
||||
}
|
||||
if (artifact.providerVerificationRequired !== (artifact.mode !== "live")) {
|
||||
context.addIssue({ code: "custom", path: ["providerVerificationRequired"], message: "must agree with hosting mode" });
|
||||
}
|
||||
if ((artifact.mode === "live") !== (artifact.baseUrl !== null)) {
|
||||
context.addIssue({ code: "custom", path: ["baseUrl"], message: "must be present only for live mode" });
|
||||
}
|
||||
if (artifact.passed !== artifact.results.every(({ passed }) => passed)) {
|
||||
context.addIssue({ code: "custom", path: ["passed"], message: "must agree with probe results" });
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user