/* Unit tests for component contracts covering parseComponentDeclaration; parseResolvedComponentSetV1; computeSetHash — input-order invariance. Not a contract source of truth — the module under test owns the authoritative behavior; fixtures are minimal scaffolding only. RFC-1311: Compass header sweep — declares the component suite's contract for test-file scaffold coverage. */ import { describe, it, expect } from "vitest"; import { parseComponentDeclaration, parseResolvedComponentSetV1 } from "../schemas.ts"; import { computeManifestHash, computeSetHash, verifySetHash, verifySetHashStrict, computeDependencyGraphHash, computeGrantSetHash, computeEffectPolicyHash, computeIsolationPolicyHash, } from "../identity.ts"; import type { ComponentDeclaration, IsolationTier, ResolvedComponentSetV1, ResolvedComponentIdentityV1, } from "@warpgogol/werkstatt-shared/component"; import type { Sha256Digest } from "@warpgogol/werkstatt-shared/fingerprint"; const VALID_SHA = ("sha256:" + "a".repeat(64)) as Sha256Digest; const VALID_SHA_2 = ("sha256:" + "b".repeat(64)) as Sha256Digest; function makeValidManifest(overrides: Partial = {}): ComponentDeclaration { return { schema: "werkstatt/component-declaration@1", componentId: "werkstatt/engine", version: "1.0.0", artifactHash: VALID_SHA, scope: "per-workshop", provides: [{ capability: "werkstatt/kernel", version: "1.0.0", schemaHash: VALID_SHA }], requires: [ { capability: "werkstatt/fingerprint", compatibility: "^1.0.0", schemaHash: VALID_SHA, optional: false, }, ], requestedGrants: [{ scope: "read", resource: "dossier", attenuated: true }], effects: [ { effectClass: "revertible", description: "read-only", recoveryCommand: null, commitMetadata: null, }, ], isolation: { tier: 0, adapterId: null }, resources: [{ kind: "cpu", limit: "100ms", owner: "werkstatt/engine", lifecycle: "process" }], priority: 0, active: true, ...overrides, }; } function makeResolvedIdentity( overrides: Partial = {}, ): ResolvedComponentIdentityV1 { return { componentId: "werkstatt/engine", version: "1.0.0", artifactHash: VALID_SHA, ...overrides, }; } function makeValidSet( overrides: Partial> = {}, ): Omit { return { schema: "werkstatt/resolved-component-set@1", profileId: "site", components: [makeResolvedIdentity()], dependencyGraphHash: VALID_SHA, grantSetHash: VALID_SHA, effectPolicyHash: VALID_SHA, isolationPolicyHash: VALID_SHA, ...overrides, }; } describe("parseComponentDeclaration", () => { it("accepts a valid manifest", () => { const manifest = makeValidManifest(); const result = parseComponentDeclaration(manifest); expect(result.status).toBe("pass"); expect(result.data).not.toBeNull(); expect(result.violations).toHaveLength(0); }); it("rejects unknown schema string", () => { const result = parseComponentDeclaration({ ...makeValidManifest(), schema: "werkstatt/component-manifest@2", }); expect(result.status).toBe("fail"); expect(result.violations.some((v) => v.rule === "COMPONENT-CONTRACT-01")).toBe(true); }); it("rejects unknown field", () => { const result = parseComponentDeclaration({ ...makeValidManifest(), extraField: "bad" }); expect(result.status).toBe("fail"); expect(result.violations.some((v) => v.rule === "COMPONENT-CONTRACT-01")).toBe(true); }); it("rejects invalid componentId (uppercase)", () => { const result = parseComponentDeclaration({ ...makeValidManifest(), componentId: "Werkstatt/Engine", }); expect(result.status).toBe("fail"); }); it("rejects invalid componentId (no namespace)", () => { const result = parseComponentDeclaration({ ...makeValidManifest(), componentId: "engine" }); expect(result.status).toBe("fail"); }); it("rejects invalid version (not semver)", () => { const result = parseComponentDeclaration({ ...makeValidManifest(), version: "latest" }); expect(result.status).toBe("fail"); }); it("rejects invalid artifactHash (not sha256)", () => { const result = parseComponentDeclaration({ ...makeValidManifest(), artifactHash: "abc123" }); expect(result.status).toBe("fail"); }); it("rejects empty provides array", () => { const result = parseComponentDeclaration({ ...makeValidManifest(), provides: [] }); expect(result.status).toBe("fail"); }); it("rejects duplicate provides", () => { const manifest = makeValidManifest({ provides: [ { capability: "werkstatt/kernel", version: "1.0.0", schemaHash: VALID_SHA }, { capability: "werkstatt/kernel", version: "1.0.0", schemaHash: VALID_SHA }, ], }); const result = parseComponentDeclaration(manifest); expect(result.status).toBe("fail"); expect(result.violations.some((v) => v.rule === "COMPONENT-CONTRACT-03")).toBe(true); }); it("rejects Law Kernel reserved grant scope: certify", () => { const manifest = makeValidManifest({ requestedGrants: [{ scope: "certify", resource: "release", attenuated: false }], }); const result = parseComponentDeclaration(manifest); expect(result.status).toBe("fail"); expect(result.violations.some((v) => v.rule === "COMPONENT-CONTRACT-06")).toBe(true); }); it("rejects Law Kernel reserved grant scope: administer", () => { const manifest = makeValidManifest({ requestedGrants: [{ scope: "administer", resource: "system", attenuated: false }], }); const result = parseComponentDeclaration(manifest); expect(result.status).toBe("fail"); expect(result.violations.some((v) => v.rule === "COMPONENT-CONTRACT-06")).toBe(true); }); it("rejects resource owner mismatch", () => { const manifest = makeValidManifest({ resources: [{ kind: "cpu", limit: "100ms", owner: "werkstatt/other", lifecycle: "process" }], }); const result = parseComponentDeclaration(manifest); expect(result.status).toBe("fail"); expect(result.violations.some((v) => v.rule === "COMPONENT-CONTRACT-05")).toBe(true); }); it("rejects unknown effect class", () => { const manifest = makeValidManifest({ effects: [ { effectClass: "magic" as never, description: "x", recoveryCommand: null, commitMetadata: null, }, ], }); const result = parseComponentDeclaration(manifest); expect(result.status).toBe("fail"); }); it("rejects unknown isolation tier", () => { const manifest = makeValidManifest({ isolation: { tier: "partially-trusted" as never, adapterId: null }, }); const result = parseComponentDeclaration(manifest); expect(result.status).toBe("fail"); }); it("rejects null input", () => { const result = parseComponentDeclaration(null); expect(result.status).toBe("fail"); }); it("rejects array input", () => { const result = parseComponentDeclaration([]); expect(result.status).toBe("fail"); }); }); describe("parseResolvedComponentSetV1", () => { it("accepts a valid set", () => { const set = makeValidSet(); const result = parseResolvedComponentSetV1({ ...set, setHash: VALID_SHA }); expect(result.status).toBe("pass"); expect(result.data).not.toBeNull(); }); it("rejects unknown schema", () => { const set = makeValidSet({ schema: "werkstatt/resolved-component-set@2" as never }); const result = parseResolvedComponentSetV1({ ...set, setHash: VALID_SHA }); expect(result.status).toBe("fail"); }); it("rejects unknown field", () => { const set = makeValidSet(); const result = parseResolvedComponentSetV1({ ...set, setHash: VALID_SHA, extra: "bad" }); expect(result.status).toBe("fail"); }); it("rejects empty components", () => { const set = makeValidSet({ components: [] }); const result = parseResolvedComponentSetV1({ ...set, setHash: VALID_SHA }); expect(result.status).toBe("fail"); }); it("rejects duplicate components", () => { const id = makeResolvedIdentity(); const set = makeValidSet({ components: [id, { ...id }] }); const result = parseResolvedComponentSetV1({ ...set, setHash: VALID_SHA }); expect(result.status).toBe("fail"); expect(result.violations.some((v) => v.rule === "COMPONENT-CONTRACT-04")).toBe(true); }); }); describe("computeSetHash — input-order invariance", () => { it("produces identical setHash regardless of component input order", () => { const c1 = makeResolvedIdentity({ componentId: "werkstatt/alpha", version: "1.0.0", artifactHash: VALID_SHA, }); const c2 = makeResolvedIdentity({ componentId: "werkstatt/beta", version: "2.0.0", artifactHash: VALID_SHA_2, }); const setA = makeValidSet({ components: [c1, c2] }); const setB = makeValidSet({ components: [c2, c1] }); expect(computeSetHash(setA)).toBe(computeSetHash(setB)); }); }); describe("computeSetHash — sensitivity", () => { it("changes when component version changes", () => { const c1 = makeResolvedIdentity({ version: "1.0.0" }); const c2 = makeResolvedIdentity({ version: "1.0.1" }); const setA = makeValidSet({ components: [c1] }); const setB = makeValidSet({ components: [c2] }); expect(computeSetHash(setA)).not.toBe(computeSetHash(setB)); }); it("changes when artifactHash changes", () => { const c1 = makeResolvedIdentity({ artifactHash: VALID_SHA }); const c2 = makeResolvedIdentity({ artifactHash: VALID_SHA_2 }); const setA = makeValidSet({ components: [c1] }); const setB = makeValidSet({ components: [c2] }); expect(computeSetHash(setA)).not.toBe(computeSetHash(setB)); }); it("changes when profileId changes", () => { const setA = makeValidSet({ profileId: "site" }); const setB = makeValidSet({ profileId: "phaser-game" }); expect(computeSetHash(setA)).not.toBe(computeSetHash(setB)); }); it("changes when dependencyGraphHash changes", () => { const setA = makeValidSet({ dependencyGraphHash: VALID_SHA }); const setB = makeValidSet({ dependencyGraphHash: VALID_SHA_2 }); expect(computeSetHash(setA)).not.toBe(computeSetHash(setB)); }); it("changes when grantSetHash changes", () => { const setA = makeValidSet({ grantSetHash: VALID_SHA }); const setB = makeValidSet({ grantSetHash: VALID_SHA_2 }); expect(computeSetHash(setA)).not.toBe(computeSetHash(setB)); }); it("changes when effectPolicyHash changes", () => { const setA = makeValidSet({ effectPolicyHash: VALID_SHA }); const setB = makeValidSet({ effectPolicyHash: VALID_SHA_2 }); expect(computeSetHash(setA)).not.toBe(computeSetHash(setB)); }); it("changes when isolationPolicyHash changes", () => { const setA = makeValidSet({ isolationPolicyHash: VALID_SHA }); const setB = makeValidSet({ isolationPolicyHash: VALID_SHA_2 }); expect(computeSetHash(setA)).not.toBe(computeSetHash(setB)); }); it("changes when a component is added", () => { const c1 = makeResolvedIdentity(); const c2 = makeResolvedIdentity({ componentId: "werkstatt/second", version: "1.0.0", artifactHash: VALID_SHA_2, }); const setA = makeValidSet({ components: [c1] }); const setB = makeValidSet({ components: [c1, c2] }); expect(computeSetHash(setA)).not.toBe(computeSetHash(setB)); }); }); describe("verifySetHash", () => { it("returns true when setHash matches recomputed hash", () => { const setWithoutHash = makeValidSet(); const setHash = computeSetHash(setWithoutHash); const set: ResolvedComponentSetV1 = { ...setWithoutHash, setHash }; expect(verifySetHash(set)).toBe(true); }); it("returns false when setHash does not match", () => { const setWithoutHash = makeValidSet(); const set: ResolvedComponentSetV1 = { ...setWithoutHash, setHash: VALID_SHA }; expect(verifySetHash(set)).toBe(false); }); it("verifySetHashStrict returns violation on mismatch", () => { const setWithoutHash = makeValidSet(); const set: ResolvedComponentSetV1 = { ...setWithoutHash, setHash: VALID_SHA }; const result = verifySetHashStrict(set); expect(result.valid).toBe(false); expect(result.violation).not.toBeNull(); expect(result.violation!.rule).toBe("COMPONENT-CONTRACT-07"); }); it("verifySetHashStrict returns null violation on match", () => { const setWithoutHash = makeValidSet(); const setHash = computeSetHash(setWithoutHash); const set: ResolvedComponentSetV1 = { ...setWithoutHash, setHash }; const result = verifySetHashStrict(set); expect(result.valid).toBe(true); expect(result.violation).toBeNull(); }); }); describe("computeManifestHash", () => { it("produces a sha256 digest", () => { const hash = computeManifestHash(makeValidManifest()); expect(hash).toMatch(/^sha256:[0-9a-f]{64}$/); }); it("is deterministic for identical manifests", () => { const m1 = makeValidManifest(); const m2 = makeValidManifest(); expect(computeManifestHash(m1)).toBe(computeManifestHash(m2)); }); it("changes when version changes", () => { expect(computeManifestHash(makeValidManifest({ version: "1.0.0" }))).not.toBe( computeManifestHash(makeValidManifest({ version: "2.0.0" })), ); }); it("is invariant to provides input order", () => { const p1 = { capability: "werkstatt/alpha" as const, version: "1.0.0", schemaHash: VALID_SHA }; const p2 = { capability: "werkstatt/beta" as const, version: "1.0.0", schemaHash: VALID_SHA }; const m1 = makeValidManifest({ provides: [p1, p2] }); const m2 = makeValidManifest({ provides: [p2, p1] }); expect(computeManifestHash(m1)).toBe(computeManifestHash(m2)); }); }); describe("sub-hash functions", () => { it("computeDependencyGraphHash is order-invariant", () => { const edgesA = [ { from: "a", to: "b" }, { from: "b", to: "c" }, ]; const edgesB = [ { from: "b", to: "c" }, { from: "a", to: "b" }, ]; expect(computeDependencyGraphHash(edgesA)).toBe(computeDependencyGraphHash(edgesB)); }); it("computeGrantSetHash is order-invariant", () => { const g1 = { componentId: "a/b", scope: "read", resource: "x", attenuated: true }; const g2 = { componentId: "a/b", scope: "append", resource: "y", attenuated: false }; expect(computeGrantSetHash([g1, g2])).toBe(computeGrantSetHash([g2, g1])); }); it("computeEffectPolicyHash is order-invariant", () => { const e1 = { componentId: "a/b", effectClass: "revertible" }; const e2 = { componentId: "a/b", effectClass: "transactional" }; expect(computeEffectPolicyHash([e1, e2])).toBe(computeEffectPolicyHash([e2, e1])); }); it("computeIsolationPolicyHash is order-invariant", () => { const i1 = { componentId: "a/b", tier: 1 as IsolationTier, adapterId: "wasm" }; const i2 = { componentId: "c/d", tier: 0 as IsolationTier, adapterId: null }; expect(computeIsolationPolicyHash([i1, i2])).toBe(computeIsolationPolicyHash([i2, i1])); }); });