from __future__ import annotations import json import base64 import ssl import sys import tempfile import unittest from pathlib import Path ROOT = Path(__file__).resolve().parents[3] sys.path.insert(0, str(ROOT / "Brain" / "src")) from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey from jsonschema import Draft202012Validator from yovision_brain.integration.machine_identity import ( KeyRecord, MachineIdentityError, Registry, ReplayStore, Signer, TransportPolicy, Verifier, load_registry, bearer_token, ) class ContractFilesTest(unittest.TestCase): def test_closed_claim_and_registry_schemas(self) -> None: claims = json.loads((ROOT / "contracts/machine-identity/v1/machine-token.schema.json").read_text(encoding="utf-8")) registry = json.loads((ROOT / "contracts/machine-identity/v1/principal-registry.schema.json").read_text(encoding="utf-8")) transport = json.loads((ROOT / "contracts/transport/v1/transport-policy.schema.json").read_text(encoding="utf-8")) Draft202012Validator.check_schema(claims) Draft202012Validator.check_schema(registry) Draft202012Validator.check_schema(transport) self.assertFalse(claims["additionalProperties"]) self.assertEqual(claims["properties"]["ver"]["const"], "yovision.machine-identity/v1") self.assertEqual(claims["properties"]["scope"]["items"]["enum"], [ "source-config:write", "runtime-status:write", "events:ingest", "evidence:read" ]) self.assertFalse(registry["additionalProperties"]) self.assertEqual(transport["properties"]["verify_certificate"]["const"], True) self.assertEqual(transport["properties"]["verify_hostname"]["const"], True) vector = json.loads((ROOT / "contracts/tests/machine-identity-v1/cross-language-vector.json").read_text(encoding="utf-8")) claims_object = json.loads(base64.urlsafe_b64decode(vector["token"].split(".")[1] + "==")) Draft202012Validator(claims).validate(claims_object) Draft202012Validator(transport).validate({ "version": "yovision.transport/v1", "tls_min_version": "1.2", "verify_certificate": True, "verify_hostname": True, "connect_timeout_ms": 1000, "response_header_timeout_ms": 1000, "request_timeout_ms": 5000, "max_request_bytes": 1048576, }) def test_brain_dependency_is_frozen(self) -> None: pyproject = (ROOT / "Brain/pyproject.toml").read_text(encoding="utf-8") self.assertIn('dependencies = ["cryptography==50.0.1"]', pyproject) def test_contract_documents_fail_closed(self) -> None: identity = (ROOT / "contracts/machine-identity/v1/README.md").read_text(encoding="utf-8") transport = (ROOT / "contracts/transport/v1/README.md").read_text(encoding="utf-8") for required in ("300 seconds", "30 seconds", "24 hours", "jti", "revoked", "browser token"): self.assertIn(required, identity) for required in ("TLS 1.2", "hostname verification", "query-string credentials", "disables the connector"): self.assertIn(required, transport) def test_python_verifies_cross_language_vector(self) -> None: vector = json.loads((ROOT / "contracts/tests/machine-identity-v1/cross-language-vector.json").read_text(encoding="utf-8")) raw_key = base64.urlsafe_b64decode(vector["public_key_base64url"] + "=") from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey registry = Registry([KeyRecord("yv:brain:vector", "brain-vector-0001", Ed25519PublicKey.from_public_bytes(raw_key), vector["audience"], frozenset({vector["required_scope"]}))]) verifier = Verifier(registry, ReplayStore(), clock=lambda: vector["now"]) claims = verifier.verify(vector["token"], vector["audience"], vector["required_scope"], vector["method"], vector["path"], base64.b64decode(vector["body_base64"])) self.assertEqual(claims.iss, "yv:brain:vector") class BrainAdapterTest(unittest.TestCase): def setUp(self) -> None: self.now = 1_800_000_000 self.private = Ed25519PrivateKey.generate() self.record = KeyRecord( principal="yv:brain:node-a", key_id="brain-key-0001", public_key=self.private.public_key(), audience="yovision-sense", scopes=frozenset({"runtime-status:write"}), ) self.registry = Registry([self.record]) self.signer = Signer("yv:brain:node-a", "brain-key-0001", self.private, clock=lambda: self.now) def mint(self, body: bytes = b"{}") -> str: return self.signer.mint("yovision-sense", ["runtime-status:write"], "POST", "/machine/v1/runtime-status", body) def verify(self, token: str, body: bytes = b"{}", **changes: str): verifier = Verifier(self.registry, changes.pop("replay", ReplayStore()), clock=lambda: int(changes.pop("now", self.now))) return verifier.verify( token, changes.pop("audience", "yovision-sense"), changes.pop("scope", "runtime-status:write"), changes.pop("method", "POST"), changes.pop("path", "/machine/v1/runtime-status"), body, ) def assert_code(self, code: str, callback) -> None: with self.assertRaises(MachineIdentityError) as caught: callback() self.assertEqual(caught.exception.code, code) self.assertEqual(str(caught.exception), code) def test_valid_token_and_replay_rejection(self) -> None: token = self.mint() replay = ReplayStore() first = Verifier(self.registry, replay, clock=lambda: self.now) claims = first.verify(token, "yovision-sense", "runtime-status:write", "POST", "/machine/v1/runtime-status", b"{}") self.assertEqual(claims.iss, "yv:brain:node-a") self.assert_code("machine_token_replayed", lambda: first.verify(token, "yovision-sense", "runtime-status:write", "POST", "/machine/v1/runtime-status", b"{}")) def test_bearer_token_has_no_cookie_or_query_fallback(self) -> None: self.assertEqual(bearer_token("Bearer compact.token.value"), "compact.token.value") for value in ("", "compact.token.value", "Bearer", "Bearer one two", "Cookie compact.token.value"): self.assert_code("machine_token_missing", lambda value=value: bearer_token(value)) def test_wrong_audience_scope_body_and_expiry(self) -> None: self.assert_code("machine_audience_denied", lambda: self.verify(self.mint(), audience="yovision-bell")) self.assert_code("machine_scope_denied", lambda: self.verify(self.mint(), scope="events:ingest")) self.assert_code("machine_token_invalid", lambda: self.verify(self.mint(), body=b"changed")) self.assert_code("machine_token_expired", lambda: self.verify(self.mint(), now=str(self.now + 361))) def test_tampering_revocation_and_rotation(self) -> None: token = self.mint() parts = token.split(".") tampered = f"{parts[0]}.{parts[1][:-1]}A.{parts[2]}" self.assert_code("machine_token_invalid", lambda: self.verify(tampered)) self.assertTrue(self.registry.revoke("brain-key-0001")) self.assert_code("machine_identity_revoked", lambda: self.verify(self.mint())) new_private = Ed25519PrivateKey.generate() overlap = Registry([ self.record, KeyRecord("yv:brain:node-a", "brain-key-0002", new_private.public_key(), "yovision-sense", frozenset({"runtime-status:write"})), ]) new_signer = Signer("yv:brain:node-a", "brain-key-0002", new_private, clock=lambda: self.now) verifier = Verifier(overlap, ReplayStore(), clock=lambda: self.now) verifier.verify(self.mint(), "yovision-sense", "runtime-status:write", "POST", "/machine/v1/runtime-status", b"{}") verifier.verify(new_signer.mint("yovision-sense", ["runtime-status:write"], "POST", "/machine/v1/runtime-status", b"{}"), "yovision-sense", "runtime-status:write", "POST", "/machine/v1/runtime-status", b"{}") def test_transport_policy_requires_verified_tls(self) -> None: policy = TransportPolicy("1.2", True, True, 1000, 1000, 2000, 1024) context = policy.ssl_context() self.assertGreaterEqual(context.minimum_version, ssl.TLSVersion.TLSv1_2) self.assertTrue(context.check_hostname) self.assertEqual(context.verify_mode, ssl.CERT_REQUIRED) with self.assertRaises(ValueError): TransportPolicy("1.1", True, True, 1000, 1000, 2000, 1024).validate() with self.assertRaises(ValueError): TransportPolicy("1.2", True, False, 1000, 1000, 2000, 1024).validate() def test_loads_external_public_registry_and_rejects_wrong_audience(self) -> None: from cryptography.hazmat.primitives import serialization raw_public = self.private.public_key().public_bytes(serialization.Encoding.Raw, serialization.PublicFormat.Raw) document = { "version": "yovision.machine-principal-registry/v1", "audience": "yovision-sense", "principals": [{ "principal_id": "yv:brain:node-a", "enabled": True, "keys": [{"kid": "brain-key-0001", "public_key_base64url": base64.urlsafe_b64encode(raw_public).rstrip(b"=").decode(), "status": "active", "scopes": ["runtime-status:write"]}], }], } with tempfile.TemporaryDirectory() as directory: path = Path(directory) / "principals.json" path.write_text(json.dumps(document), encoding="utf-8") registry = load_registry(path, "yovision-sense") self.assertIsNotNone(registry.lookup("brain-key-0001")) with self.assertRaises(ValueError): load_registry(path, "yovision-bell") if __name__ == "__main__": unittest.main(verbosity=2)