import contextlib import hashlib import importlib.util import io import json from pathlib import Path import sys import tempfile import unittest from unittest.mock import patch ROOT=Path(__file__).resolve().parents[1] spec=importlib.util.spec_from_file_location('fixture_runner',ROOT/'tests/run_isolated_keycape_native_fixture.py') f=importlib.util.module_from_spec(spec);spec.loader.exec_module(f) class FixturePreparationTests(unittest.TestCase): def test_default_plan_neither_runs_docker_nor_generates_materials(self): output=io.StringIO() with patch.object(sys,'argv',['fixture','--plan']),patch.object(f.s,'run') as run,patch.object(f,'materials') as materials,patch.object(f.s.local,'preflight') as preflight,contextlib.redirect_stdout(output): self.assertEqual(f.main(),0) run.assert_not_called();materials.assert_not_called();preflight.assert_not_called() manifest=json.loads(output.getvalue()) self.assertEqual(manifest['status'],'prepared_not_executed_not_approved') self.assertEqual(manifest['fixed_endpoint'],'unix:///var/run/docker.sock') def test_wrong_reviewed_manifest_hash_stops_before_preflight_or_generation(self): with patch.object(sys,'argv',['fixture','--execute-reviewed-fixture','--expected-manifest-sha256','0'*64]),patch.object(f.s,'run') as run,patch.object(f,'materials') as materials,patch.object(f.s.local,'preflight') as preflight: with self.assertRaises(RuntimeError):f.main() run.assert_not_called();materials.assert_not_called();preflight.assert_not_called() def test_untyped_or_malformed_public_digest_refused(self): for invalid in ('0'*64, 'sha256:'+'A'*64, 'sha256:'+'0'*63, None): with self.subTest(invalid_type=type(invalid).__name__), tempfile.TemporaryDirectory() as temporary: manifest=json.loads(f.MANIFEST.read_text()) first=next(iter(manifest['source_sha256'])) manifest['source_sha256'][first]=invalid path=Path(temporary)/'manifest.json' path.write_text(json.dumps(manifest)) with patch.object(f,'MANIFEST',path), patch.object(f.s,'run') as run: with self.assertRaises(RuntimeError): f.reviewed_manifest(hashlib.sha256(path.read_bytes()).hexdigest()) run.assert_not_called() def test_manifest_binds_current_candidate_and_existing_fixture_factory(self): digest=hashlib.sha256(f.MANIFEST.read_bytes()).hexdigest() manifest=f.reviewed_manifest(digest) self.assertIn('tests/test_identity_bundle.py',manifest['source_sha256']) self.assertIn('tools/bootstrap-recovery/isolated-keycape-session.py',manifest['source_sha256']) self.assertIn('sso-mfa/k8s/privacyidea/key-custody-remote.py',manifest['source_sha256']) if __name__=='__main__':unittest.main()