a11oy / __tests__ /compliance /compliance_reject.test.ts
betterwithage's picture
sync(space): complete build context — fix BUILD_ERROR (CTO)
518343a verified
Raw
History Blame
5.3 kB
/**
* compliance_reject.test.ts
* Doctrine v6 R3 — Vertical Governance Receipts
* 10 REJECT cases: malformed or non-compliant policy documents are correctly
* rejected by schema validation.
*
* Each test constructs a deliberately invalid policy object and asserts that
* AJV validation returns false (the schema rejects it).
*
* Test framework: Jest / ts-jest
* Run: npx jest tests/compliance/compliance_reject.test.ts
*/
import Ajv from "ajv";
import addFormats from "ajv-formats";
import * as fs from "fs";
import * as path from "path";
const SCHEMA_PATH = path.resolve(__dirname, "../../a11oy-knowledge.schema.json");
function buildValidator() {
const ajv = new Ajv({ allErrors: true, strict: false });
addFormats(ajv);
const schema = JSON.parse(fs.readFileSync(SCHEMA_PATH, "utf8"));
return ajv.compile(schema);
}
// ── Minimal valid base object (used as mutation seed) ─────────────────────────
function basePolicy(): any {
return {
schema_version: "1.0.0",
vertical: "healthcare",
regime: "HIPAA/HITECH",
effective_date: "2025-07-01",
jurisdiction: "US-Federal",
meta: {
title: "Healthcare AI Governance Policy — HIPAA Alignment",
description: "Maps HIPAA provisions to Doctrine v6 axes for AI systems processing PHI.",
authority: "45 CFR Parts 160, 162, 164",
receipt_chain_required: true,
merkle_root_algorithm: "SHA3-256",
},
regulatory_clauses: Array.from({ length: 8 }, (_, i) => ({
clause_id: `CLAUSE-${i + 1}`,
title: `Test clause ${i + 1}`,
citation: `45 CFR § 164.${i + 100}`,
full_ref: `Full reference for test clause ${i + 1} with adequate detail`,
lambda_axes: [
{ axis: "Λ3", label: "Privacy", weight: 0.9, enforcement: "mandatory", rationale: "Test rationale for this axis mapping with sufficient length." },
],
})),
compliance_thresholds: {
minimum_lambda_coverage: 6,
mandatory_axes: ["Λ3", "Λ6", "Λ7"],
receipt_retention_days: 2555,
},
receipt_chain: {
algorithm: "SHA3-256",
chaining: "merkle_dag",
quorum: "2-of-3",
nodes: ["primary", "backup", "audit"],
},
};
}
describe("Compliance REJECT — invalid policy documents rejected", () => {
const validate = buildValidator();
// REJECT-001: Missing required top-level field (schema_version)
test("REJECT-001: missing schema_version is rejected", () => {
const p = basePolicy();
delete p.schema_version;
expect(validate(p)).toBe(false);
});
// REJECT-002: Invalid vertical enum value
test("REJECT-002: unknown vertical 'blockchain' is rejected", () => {
const p = basePolicy();
p.vertical = "blockchain";
expect(validate(p)).toBe(false);
});
// REJECT-003: effective_date format violation (not ISO 8601 YYYY-MM-DD)
test("REJECT-003: effective_date '07/01/2025' (MM/DD/YYYY) is rejected", () => {
const p = basePolicy();
p.effective_date = "07/01/2025";
expect(validate(p)).toBe(false);
});
// REJECT-004: regulatory_clauses count below minimum (< 8)
test("REJECT-004: fewer than 8 regulatory_clauses is rejected", () => {
const p = basePolicy();
p.regulatory_clauses = p.regulatory_clauses.slice(0, 5);
expect(validate(p)).toBe(false);
});
// REJECT-005: regulatory_clauses count above maximum (> 12)
test("REJECT-005: more than 12 regulatory_clauses is rejected", () => {
const p = basePolicy();
const extra = Array.from({ length: 5 }, (_, i) => ({
clause_id: `EXTRA-${i}`,
title: `Extra clause ${i}`,
citation: `45 CFR § 999.${i}`,
full_ref: `Full reference for extra clause ${i} with adequate length`,
lambda_axes: [
{ axis: "Λ1", label: "Transparency", weight: 0.5, enforcement: "recommended", rationale: "Extra rationale for testing purposes." },
],
}));
p.regulatory_clauses = [...p.regulatory_clauses, ...extra];
expect(validate(p)).toBe(false);
});
// REJECT-006: Invalid Λ-axis identifier (not in enum)
test("REJECT-006: lambda axis 'Λ11' (out of range) is rejected", () => {
const p = basePolicy();
p.regulatory_clauses[0].lambda_axes[0].axis = "Λ11";
expect(validate(p)).toBe(false);
});
// REJECT-007: weight out of range (> 1.0)
test("REJECT-007: lambda weight 1.5 (> 1.0) is rejected", () => {
const p = basePolicy();
p.regulatory_clauses[0].lambda_axes[0].weight = 1.5;
expect(validate(p)).toBe(false);
});
// REJECT-008: invalid receipt chain algorithm
test("REJECT-008: receipt chain algorithm 'MD5' is rejected", () => {
const p = basePolicy();
p.receipt_chain.algorithm = "MD5";
expect(validate(p)).toBe(false);
});
// REJECT-009: receipt_retention_days below minimum (< 365)
test("REJECT-009: receipt_retention_days 30 (< 365) is rejected", () => {
const p = basePolicy();
p.compliance_thresholds.receipt_retention_days = 30;
expect(validate(p)).toBe(false);
});
// REJECT-010: quorum string not matching N-of-M pattern
test("REJECT-010: quorum 'majority' (not N-of-M format) is rejected", () => {
const p = basePolicy();
p.receipt_chain.quorum = "majority";
expect(validate(p)).toBe(false);
});
});