# SPDX-License-Identifier: MIT
"""Regression closure for independent findings C2/H8/M5/L1 and 21 mutations."""
import copy
import hashlib
import json
import subprocess
import sys
import tempfile
import unittest
from pathlib import Path

ROOT = Path(__file__).resolve().parents[1]
REPO = ROOT.parent
sys.path.insert(0, str(ROOT / "tools"))

from conform import Failure, canonical_bytes, load_json, run_vectors, validate_document


class AuditRegressionTests(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        cls.positive = load_json(ROOT / "vectors/positive.json")
        cls.by_id = {item["id"]: item for item in cls.positive["vectors"]}

    def reject(self, document, terms=None):
        with self.assertRaises(Failure):
            validate_document(document, terms)

    def test_all_21_independently_reported_mutations_are_rejected(self):
        mutations = []

        d = copy.deepcopy(self.by_id["P-ERROR"]["document"])
        d["code"] = "VF3-MADEUP-999"
        mutations.append(("unknown_error_code", d, None))

        d = copy.deepcopy(self.by_id["P-RECEIPT"]["document"])
        d["result"], d["errorCode"] = "accepted", "VF3-PRIVACY-001"
        mutations.append(("accepted_receipt_with_error", d, None))
        d = copy.deepcopy(self.by_id["P-RECEIPT"]["document"])
        d["result"], d["errorCode"] = "rejected", None
        mutations.append(("rejected_receipt_without_error", d, None))

        report = {
            "schema": "vaultfire.v3.open.conformance-report.v1",
            "schemaVersion": "1.0.0",
            "protocolVersion": "3.0.0",
            "implementation": {"name": "fake", "version": "1.0.0", "digest": "0x" + "11" * 32},
            "harnessVersion": "1.0.0",
            "generatedAt": "2026-99-99T99:99:99Z",
            "checks": [{"id": "FAKE", "status": "pass", "evidence": "self assertion"}],
            "summary": {"passed": 1, "failed": 0, "notRun": 0, "conformant": True},
            "truth": {"specificationCompliant": True, "audited": False, "deployed": False, "authorized": False, "endorsed": False},
        }
        mutations.append(("one_check_false_conformance", report, None))
        d = copy.deepcopy(report)
        d["checks"][0]["status"] = "fail"
        d["summary"] = {"passed": 0, "failed": 1, "notRun": 0, "conformant": False}
        d["truth"]["specificationCompliant"] = True
        mutations.append(("failed_report_claims_compliant", d, None))

        d = copy.deepcopy(self.by_id["P-EVIDENCE-SOURCE-ONLY"]["document"])
        d.update({"contract": "0x" + "12" * 20, "runtimeCodeHash": "0x" + "34" * 32, "capabilities": ["0x" + "56" * 32], "observedAt": "2026-99-99T99:99:99Z"})
        d["claims"] = {"sourceSupported": True, "deploymentVerified": True, "authorizationVerified": True, "capabilityVerified": True}
        d["sourceBindings"] = [{"path": "../../etc/passwd", "sha256": "00" * 32}]
        mutations.append(("fabricated_deployment_evidence", d, None))

        for key, value in (
            ("x-biometric-input", "face-template"),
            ("x-profile", "consumer-segmentation"),
            ("x-derived", "sha256:deadbeef"),
            ("x-decision-provenance", {"upstream": "camera-feature-vector"}),
        ):
            d = copy.deepcopy(self.by_id["P-ACCOUNTABILITY"]["document"])
            d["extensions"][key] = value
            mutations.append(("privacy_" + key, d, None))

        for field, value in (("challengeWindow", "0"), ("partnershipType", "0x" + "00" * 32), ("proposalDeadline", "1800003601")):
            d = copy.deepcopy(self.by_id["P-PARTNERSHIP"]["document"])
            d[field] = value
            mutations.append(("partnership_invalid_" + field, d, None))

        d = copy.deepcopy(self.by_id["P-ACCOUNTABILITY"]["document"])
        d["objectiveRuleHash"] = "0x" + "77" * 32
        mutations.append(("accountability_rulehash_not_bound_to_enforcement", d, None))
        d = copy.deepcopy(self.by_id["P-ACCOUNTABILITY"]["document"])
        d["enforcement"]["attesterSetHash"] = "0x" + "77" * 32
        mutations.append(("nonempty_signer_commitment", d, None))
        d = copy.deepcopy(self.by_id["P-ACCOUNTABILITY"]["document"])
        d["enforcement"]["privacyExclusionsHash"] = "0x" + "77" * 32
        mutations.append(("wrong_privacy_exclusion_hash", d, None))

        signed = self.by_id["P-SIGNED-TERMS"]
        d = copy.deepcopy(signed["document"])
        d["domain"]["salt"] = "0x" + "00" * 32
        mutations.append(("unbound_domain_salt", d, signed["terms"]))
        d = copy.deepcopy(signed["document"])
        d["validAfter"], d["validBefore"] = "1", "2"
        mutations.append(("expired_signed_terms", d, signed["terms"]))

        d = copy.deepcopy(self.by_id["P-STATE-PAUSED-EXIT"]["document"])
        d["exitAvailableAt"] = "999999999999999999999"
        mutations.append(("paused_expired_exit_far_future", d, None))
        d = copy.deepcopy(self.by_id["P-STATE-PAUSED-EXIT"]["document"])
        d["principalFunded"] = "0"
        mutations.append(("liability_exceeds_funded_principal", d, None))
        d = copy.deepcopy(self.by_id["P-ERROR"]["document"])
        d["retryable"] = True
        mutations.append(("wrong_retryability", d, None))

        self.assertEqual(len(mutations), 21)
        for name, document, terms in mutations:
            with self.subTest(name):
                self.reject(document, terms)

    def test_C01_self_sufficient_interface_snapshot(self):
        snapshot = load_json(ROOT / "interfaces/canonical-v3-interfaces.v1.json")
        self.assertEqual(len(snapshot["supportedSourceModules"]), 15)
        self.assertEqual({x["sdkName"]: x["signatureCount"] for x in snapshot["sdkDeployments"]}, {"accountabilityBond": 36, "partnershipBond": 55, "governance": 45, "mandateRegistry": 24})
        self.assertEqual(len(snapshot["sdkWriteMethods"]), 4)
        self.assertIn("domainType", snapshot["eip712"])
        self.assertGreater(len(snapshot["stateMachine"]["transitions"]), 0)

    def test_C02_required_checks_cannot_be_caller_selected(self):
        report = load_json(ROOT / "reports/conformance-report.json")
        report["checks"] = report["checks"][:1]
        self.reject(report)

    def test_H01_domain_expiry_and_replay_are_bound(self):
        signed = copy.deepcopy(self.by_id["P-SIGNED-TERMS"]["document"])
        signed["nonceConsumed"] = True
        self.reject(signed, self.by_id["P-SIGNED-TERMS"]["terms"])

    def test_H02_create_constraints_are_semantic(self):
        bond = copy.deepcopy(self.by_id["P-ACCOUNTABILITY"]["document"])
        bond["enforcement"]["maximumSlash"] = str(int(bond["companyStake"]) + 1)
        self.reject(bond)

    def test_H03_privacy_provenance_is_closed(self):
        bond = copy.deepcopy(self.by_id["P-ACCOUNTABILITY"]["document"])
        bond["decisionInputs"][0]["containsSurveillanceData"] = True
        self.reject(bond)

    def test_H04_state_conservation_and_history_are_enforced(self):
        state = copy.deepcopy(self.by_id["P-STATE-PAUSED-EXIT"]["document"])
        state["transitionHistory"][0]["to"] = "Settled"
        self.reject(state)

    def test_H05_evidence_paths_hashes_freshness_and_truth_are_enforced(self):
        evidence = copy.deepcopy(self.by_id["P-EVIDENCE-SOURCE-ONLY"]["document"])
        evidence["validUntil"] = "2026-01-01T00:00:00Z"
        self.reject(evidence)

    def test_H06_optimized_execution_cannot_disable_checker(self):
        self.assertNotIn("assert ", (ROOT / "tools/check.py").read_text("utf-8"))
        run = subprocess.run(
            [sys.executable, "-O", str(ROOT / "tools/check.py")],
            cwd=ROOT,
            text=True,
            capture_output=True,
        )
        package_dirty = bool(
            subprocess.run(
                ["git", "-C", str(REPO), "status", "--porcelain", "--", "LICENSE", "v3-open-spec"],
                text=True,
                capture_output=True,
                check=True,
            ).stdout.strip()
        )
        if package_dirty:
            self.assertEqual(run.returncode, 2, run.stderr)
            self.assertIn('"status": "blocked"', run.stdout)
        else:
            self.assertEqual(run.returncode, 0, run.stderr)
            self.assertIn('"status": "pass"', run.stdout)

        with tempfile.TemporaryDirectory() as directory:
            worktree = Path(directory) / "mutated-exact-commit"
            subprocess.run(
                ["git", "-C", str(REPO), "worktree", "add", "--detach", str(worktree), "HEAD"],
                text=True,
                capture_output=True,
                check=True,
            )
            try:
                report = worktree / "v3-open-spec/reports/conformance-report.json"
                report.write_bytes(report.read_bytes() + b"\n")
                mutated = subprocess.run(
                    [
                        sys.executable,
                        "-O",
                        str(worktree / "v3-open-spec/tools/check.py"),
                    ],
                    cwd=worktree / "v3-open-spec",
                    text=True,
                    capture_output=True,
                )
                self.assertEqual(mutated.returncode, 2, mutated.stderr)
                self.assertIn('"status": "blocked"', mutated.stdout)
            finally:
                subprocess.run(
                    ["git", "-C", str(REPO), "worktree", "remove", "--force", str(worktree)],
                    text=True,
                    capture_output=True,
                    check=True,
                )

    def test_H07_exact_commit_tree_and_source_set_are_bound(self):
        evidence = copy.deepcopy(self.by_id["P-EVIDENCE-SOURCE-ONLY"]["document"])
        evidence["repositoryCommit"] = "0" * 40
        self.reject(evidence)

    def test_H08_complete_surface_counts(self):
        mapping = load_json(ROOT / "mappings/canonical-v3.json")
        self.assertEqual(mapping["counts"], {"supportedSourceModules": 15, "sdkDeployments": 4, "sdkWriteDeployments": 4, "sdkReadRoutes": 11, "generatedV3ApiRoutes": 20})

    def test_M01_receipt_and_error_conditionals(self):
        receipt = copy.deepcopy(self.by_id["P-RECEIPT"]["document"])
        receipt["subjectDigest"] = "0x" + "00" * 32
        self.reject(receipt)

    def test_M02_manifest_is_full_and_package_has_no_symlinks(self):
        listed = {line.split("  ", 1)[1] for line in (ROOT / "ARTIFACTS.sha256").read_text().splitlines()}
        expected = {p.relative_to(ROOT).as_posix() for p in ROOT.rglob("*") if p.is_file() and "__pycache__" not in p.parts and ".pytest_cache" not in p.parts and p.name not in ("ARTIFACTS.sha256","conformance-report.json") and p.suffix not in (".pyc", ".pyo")}
        self.assertEqual(listed - {"../LICENSE"}, expected)
        self.assertFalse(any(path.is_symlink() for path in ROOT.rglob("*")))

    def test_M03_nonfinite_duplicate_and_malformed_inputs_fail_closed(self):
        with tempfile.TemporaryDirectory() as directory:
            nan = Path(directory) / "nan.json"
            nan.write_text('{"x":NaN}')
            with self.assertRaises(Failure):
                load_json(nan)
            duplicate = Path(directory) / "duplicate.json"
            duplicate.write_text('{"x":1,"x":2}')
            with self.assertRaises(Failure):
                load_json(duplicate)
        bundle = {"positive": self.positive, "adversarial": {"vectors": [{"id": "BROKEN", "base": "P-ACCOUNTABILITY", "expectedError": "VF3-INTERNAL-001", "mutation": {"op": "replace", "path": "does.not.exist", "value": 1}}]}}
        result = run_vectors(bundle)
        self.assertEqual(result[-1][1], "fail")
        self.assertIn("VF3-INTERNAL-001", result[-1][2])

    def test_M04_machine_readable_compatibility_and_deprecation(self):
        registry = load_json(ROOT / "registry/compatibility.v1.json")
        self.assertIn("extensions", registry)
        self.assertIn("deprecation", registry)
        self.assertIn("canonicalization", registry)

    def test_M05_adversarial_corpus_is_frozen_not_self_fulfilling(self):
        source = (ROOT / "update_vector_errors.py").read_text("utf-8")
        self.assertNotIn("write_text", source)
        adversarial = load_json(ROOT / "vectors/adversarial.json")
        self.assertGreaterEqual(len(adversarial["vectors"]), 38)

    def test_L01_timestamps_are_strict_and_freshness_is_bounded(self):
        evidence = copy.deepcopy(self.by_id["P-EVIDENCE-SOURCE-ONLY"]["document"])
        evidence["observedAt"] = "2026-99-99T99:99:99Z"
        self.reject(evidence)


if __name__ == "__main__":
    unittest.main()
