chore: initialize from frontend template 4dc033c
This commit is contained in:
@@ -0,0 +1,237 @@
|
||||
import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
|
||||
import { tmpdir } from "node:os";
|
||||
import path from "node:path";
|
||||
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
|
||||
import { generateArtifactSchemas } from "../../scripts/generate-artifact-schemas.ts";
|
||||
import { assertMatchesJsonSchema } from "../../scripts/lib/json-schema.ts";
|
||||
|
||||
const temporaryDirectories: string[] = [];
|
||||
|
||||
async function temporaryDirectory(): Promise<string> {
|
||||
const directory = await mkdtemp(path.join(tmpdir(), "artifact-schemas-"));
|
||||
temporaryDirectories.push(directory);
|
||||
return directory;
|
||||
}
|
||||
|
||||
afterEach(async () => {
|
||||
await Promise.all(
|
||||
temporaryDirectories.splice(0).map((directory) =>
|
||||
rm(directory, { force: true, recursive: true }),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
async function json(path: string): Promise<unknown> {
|
||||
return JSON.parse(await readFile(path, "utf8")) as unknown;
|
||||
}
|
||||
|
||||
describe("checked-in JSON Schema execution", () => {
|
||||
it("accepts a build manifest and rejects undeclared output fields", async () => {
|
||||
const schema = await json("schemas/artifacts/build-manifest.schema.json");
|
||||
const manifest = {
|
||||
schemaVersion: 1,
|
||||
buildId: "build-1",
|
||||
commitSha: "commit-1",
|
||||
releaseId: "release-1",
|
||||
moduleInventoryHash: "inventory-hash",
|
||||
generatedAt: "2026-08-01T00:00:00.000Z",
|
||||
buildContext: {
|
||||
nodeVersion: "v24.11.0",
|
||||
packageManagerVersion: "11.17.0",
|
||||
runnerImage: "test-runner",
|
||||
sourceDateEpoch: null,
|
||||
},
|
||||
outputs: {
|
||||
directory: "dist",
|
||||
viteManifest: "dist/.vite/manifest.json",
|
||||
moduleInventory: "artifacts/quality/vite-module-inventory.json",
|
||||
routeChunks: { home: "assets/home.js" },
|
||||
runtimeConfigSchema: "dist/runtime-config.schema.json",
|
||||
},
|
||||
};
|
||||
|
||||
expect(() =>
|
||||
assertMatchesJsonSchema(schema, manifest, "build manifest"),
|
||||
).not.toThrow();
|
||||
expect(() =>
|
||||
assertMatchesJsonSchema(
|
||||
schema,
|
||||
{ ...manifest, undocumented: true },
|
||||
"build manifest",
|
||||
),
|
||||
).toThrow(/checked-in JSON Schema/u);
|
||||
});
|
||||
|
||||
it("resolves local schema definitions in the recipe catalog", async () => {
|
||||
const [schema, catalog] = await Promise.all([
|
||||
json("schemas/config/frontend-capability-recipes.schema.json"),
|
||||
json("config/recipes/frontend-capability-recipes.json"),
|
||||
]);
|
||||
|
||||
expect(() =>
|
||||
assertMatchesJsonSchema(schema, catalog, "optional recipe catalog"),
|
||||
).not.toThrow();
|
||||
});
|
||||
|
||||
it("generates deterministic draft 2020-12 artifact schemas and detects drift", async () => {
|
||||
const root = await temporaryDirectory();
|
||||
await generateArtifactSchemas({ root });
|
||||
const generatedPath = path.join(
|
||||
root,
|
||||
"schemas/artifacts/dependency-inventory.schema.json",
|
||||
);
|
||||
const generated = await readFile(generatedPath, "utf8");
|
||||
expect(generated.endsWith("\n")).toBe(true);
|
||||
expect(JSON.parse(generated)).toMatchObject({
|
||||
$schema: "https://json-schema.org/draft/2020-12/schema",
|
||||
type: "object",
|
||||
additionalProperties: false,
|
||||
});
|
||||
|
||||
await generateArtifactSchemas({ root, check: true });
|
||||
await writeFile(generatedPath, `${generated.trimEnd()} \n`, "utf8");
|
||||
|
||||
await expect(
|
||||
generateArtifactSchemas({ root, check: true }),
|
||||
).rejects.toThrow(/dependency-inventory\.schema\.json/u);
|
||||
});
|
||||
|
||||
it.each([
|
||||
{
|
||||
name: "dependency inventory",
|
||||
path: "schemas/artifacts/dependency-inventory.schema.json",
|
||||
value: {
|
||||
schemaVersion: 2,
|
||||
packageManager: "pnpm@11.17.0",
|
||||
lockfileSha256: "a".repeat(64),
|
||||
dependencyCount: 1,
|
||||
directDependencyCount: 1,
|
||||
dependencies: [
|
||||
{
|
||||
name: "zod",
|
||||
version: "4.4.3",
|
||||
direct: true,
|
||||
scope: "production",
|
||||
optional: false,
|
||||
license: "MIT",
|
||||
integrity: `sha512-${"a".repeat(86)}`,
|
||||
dependencies: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "registry snapshot",
|
||||
path: "schemas/artifacts/registry-snapshot.schema.json",
|
||||
value: {
|
||||
schemaVersion: 2,
|
||||
generatedAt: "2026-08-01T00:00:00.000Z",
|
||||
baselineDigest: "b".repeat(64),
|
||||
currentDigest: "c".repeat(64),
|
||||
compatibility: { impact: "none", changes: [] },
|
||||
failures: [],
|
||||
registries: Array.from({ length: 11 }, (_, index) => ({
|
||||
registryId: `registry-${index}`,
|
||||
owner: "platform",
|
||||
source: `src/registry-${index}.ts`,
|
||||
rowCount: 0,
|
||||
contract: {},
|
||||
rows: {},
|
||||
})),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "supply-chain verification",
|
||||
path: "schemas/artifacts/supply-chain-verification.schema.json",
|
||||
value: {
|
||||
schemaVersion: 1,
|
||||
localStatus: "PASS",
|
||||
promotionStatus: "FAIL_UNVERIFIED",
|
||||
lockfileSha256: "d".repeat(64),
|
||||
sourceSetSha256: "e".repeat(64),
|
||||
distSha256: "f".repeat(64),
|
||||
sbomSha256: "0".repeat(64),
|
||||
dependencyDiff: {
|
||||
added: [],
|
||||
removed: [],
|
||||
changed: [],
|
||||
upgrades: [],
|
||||
},
|
||||
highRiskReview: [],
|
||||
vulnerabilityStatus: "FAIL_UNVERIFIED",
|
||||
provenanceAttestationStatus: "FAIL_UNVERIFIED",
|
||||
failures: [],
|
||||
},
|
||||
},
|
||||
])("accepts $name and rejects undeclared top-level fields", async (fixture) => {
|
||||
const schema = await json(fixture.path);
|
||||
|
||||
expect(() =>
|
||||
assertMatchesJsonSchema(schema, fixture.value, fixture.name),
|
||||
).not.toThrow();
|
||||
expect(() =>
|
||||
assertMatchesJsonSchema(
|
||||
schema,
|
||||
{ ...fixture.value, undocumented: true },
|
||||
fixture.name,
|
||||
),
|
||||
).toThrow(/checked-in JSON Schema/u);
|
||||
if (fixture.name === "dependency inventory") {
|
||||
const dependency = fixture.value.dependencies?.[0];
|
||||
if (dependency === undefined) {
|
||||
throw new TypeError("dependency inventory fixture is incomplete");
|
||||
}
|
||||
expect(() =>
|
||||
assertMatchesJsonSchema(
|
||||
schema,
|
||||
{
|
||||
...fixture.value,
|
||||
dependencies: [
|
||||
{
|
||||
...dependency,
|
||||
undocumented: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
fixture.name,
|
||||
),
|
||||
).toThrow(/checked-in JSON Schema/u);
|
||||
expect(() =>
|
||||
assertMatchesJsonSchema(
|
||||
schema,
|
||||
{
|
||||
...fixture.value,
|
||||
dependencyCount: 0,
|
||||
directDependencyCount: 0,
|
||||
dependencies: [],
|
||||
},
|
||||
fixture.name,
|
||||
),
|
||||
).toThrow(/checked-in JSON Schema/u);
|
||||
}
|
||||
if (fixture.name === "registry snapshot") {
|
||||
expect(() =>
|
||||
assertMatchesJsonSchema(
|
||||
schema,
|
||||
{ ...fixture.value, failures: [], registries: [] },
|
||||
fixture.name,
|
||||
),
|
||||
).toThrow(/checked-in JSON Schema/u);
|
||||
expect(() =>
|
||||
assertMatchesJsonSchema(
|
||||
schema,
|
||||
{
|
||||
...fixture.value,
|
||||
baselineDigest: null,
|
||||
compatibility: { impact: "not-evaluated", changes: [] },
|
||||
failures: ["missing registry source"],
|
||||
registries: [],
|
||||
},
|
||||
fixture.name,
|
||||
),
|
||||
).not.toThrow();
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user