Spaces:
Running
Running
File size: 5,300 Bytes
518343a | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 | /**
* 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);
});
});
|