#!/usr/bin/env python3 """Behavioral tests for validate_bsp_handoff.py.""" import hashlib import json import os import tempfile from pathlib import Path from unittest.mock import patch import validate_bsp_handoff def main() -> int: with tempfile.TemporaryDirectory() as tmp: root = Path(tmp) output_root = root / "outputs" imgs = output_root / "CV1841CP-BOARD_dualos" / "imgs" / "20260902_1" imgs.mkdir(parents=True) artifact = imgs / "boot.bin" artifact.write_bytes(b"boot") kernel = imgs / "kernel.bin" kernel.write_bytes(b"kernel") rootfs = imgs / "rootfs.bin" rootfs.write_bytes(b"rootfs") project = root / "CV1841CP-BOARD_dualos" partition = project / "configs" / "board" / "partition" / "partition_spinand.xml" partition.parent.mkdir(parents=True) partition.write_text( """ """, encoding="utf-8", ) checks = [] for image in (kernel, rootfs): size = image.stat().st_size checks.append( { "image": image.name, "image_path": str(image), "image_size_bytes": size, "partitions": [ { "label": "BOOT" if image.name == "kernel.bin" else "ROOTFS", "alias": "kernel.A" if image.name == "kernel.bin" else "rootfs.A", "file": image.name, "size_in_kb": 1024, "size_bytes": 1024 * 1024, } ], "effective_partition_size_bytes": 1024 * 1024, "required_margin_bytes": 512 * 1024, "actual_margin_bytes": 1024 * 1024 - size, "passed": True, } ) margin = { "schema_version": 1, "passed": True, "checked_at": "2026-09-02T00:00:00+00:00", "partition_table": str(partition), "partition_table_sha256": hashlib.sha256(partition.read_bytes()).hexdigest(), "required_margin_bytes": 512 * 1024, "checks": checks, } margin_path = project / "doc" / "bsp_adaptation" / "validation" / "image_partition_margin_20260902_1.json" margin_path.parent.mkdir(parents=True) margin_path.write_text(json.dumps(margin), encoding="utf-8") permissions = { "schema_version": 1, "passed": True, "policy": "a+rX", "output_root": str(output_root), "imgs_version_path": str(imgs), } permissions_path = margin_path.parent / "output_permissions_20260902_1.json" permissions_path.write_text(json.dumps(permissions), encoding="utf-8") manifest = root / "psp_handoff.json" payload = { "schema_version": 1, "handoff_type": "bsp-to-psp", "producer": { "project": "CV1841CP-BOARD_dualos", "project_path": str(project), }, "baseline": { "chip": "CV1841CP", "sdk": "cv184x_v6.3.3", "board_build_type": "cv1841cp_wevb_0015a_spinand", }, "build": { "version": "20260902_1", "status": "build_passed", "exit_code": 0, "completion_marker_seen": True, "imgs_version_path": str(imgs), "image_partition_margin_path": str(margin_path), "output_permissions_path": str(permissions_path), }, "artifacts": [ { "relative_path": item.name, "absolute_path": str(item), "size": item.stat().st_size, "sha256": hashlib.sha256(item.read_bytes()).hexdigest(), } for item in (artifact, kernel, rootfs) ], "validation": { "image_partition_margin": margin, "output_permissions": permissions, "hardware": "pending", "owner_acceptance": "pending", "release": "not-authorized", }, } manifest.write_text(json.dumps(payload), encoding="utf-8") for directory in (output_root, output_root / "CV1841CP-BOARD_dualos", imgs.parent, imgs): os.chmod(directory, 0o755) for image in (artifact, kernel, rootfs): os.chmod(image, 0o644) result = validate_bsp_handoff.validate_handoff( manifest, "CV1841CP-BOARD_dualos", "CV1841CP", "cv184x_v6.3.3", "cv1841cp_wevb_0015a_spinand", ) assert result["passed"] is True, result assert result["dependency"]["verified_artifact_count"] == 3 assert result["dependency"]["build_id"] == "20260902_1" assert result["dependency"]["chip"] == "CV1841CP" assert result["dependency"]["image_partition_margin"]["passed"] is True assert result["dependency"]["output_permissions"]["current_check"]["passed"] is True assert result["dependency"]["artifacts"][0]["sha256"] assert result["warnings"] os.chmod(output_root, 0o700) os.chmod(imgs, 0o700) os.chmod(kernel, 0o600) other_build = root / "another-build" other_build.mkdir(mode=0o700) (imgs / "external-link").symlink_to(other_build, target_is_directory=True) readonly = validate_bsp_handoff.validate_handoff(manifest) assert readonly["passed"] is False assert any("共享读取/进入权限" in error for error in readonly["errors"]) assert output_root.stat().st_mode & 0o777 == 0o700 repaired = validate_bsp_handoff.validate_handoff( manifest, expected_project="CV1841CP-BOARD_dualos", repair_output_permissions=True, ) assert repaired["passed"] is True, repaired assert repaired["dependency"]["output_permissions"]["current_check"]["repaired"] is True assert repaired["dependency"]["output_permissions"]["current_check"]["symlinks_skipped"] == 1 assert output_root.stat().st_mode & 0o555 == 0o555 assert other_build.stat().st_mode & 0o777 == 0o700 assert kernel.stat().st_mode & 0o444 == 0o444 assert kernel.stat().st_mode & 0o111 == 0 no_evidence_payload = json.loads(json.dumps(payload)) no_evidence_payload["validation"].pop("output_permissions") no_evidence_manifest = root / "no_permissions_handoff.json" no_evidence_manifest.write_text(json.dumps(no_evidence_payload), encoding="utf-8") no_evidence = validate_bsp_handoff.validate_handoff( no_evidence_manifest, expected_project="CV1841CP-BOARD_dualos", repair_output_permissions=True, ) assert no_evidence["passed"] is False assert any("权限证据" in error for error in no_evidence["errors"]) os.chmod(kernel, 0o600) bad_project = validate_bsp_handoff.validate_handoff( manifest, expected_project="NOT-THE-PROJECT", repair_output_permissions=True, ) assert bad_project["passed"] is False assert kernel.stat().st_mode & 0o444 != 0o444 bad_evidence_payload = json.loads(json.dumps(payload)) bad_evidence_payload["validation"]["output_permissions"]["output_root"] = str(root / "wrong-root") bad_evidence_manifest = root / "bad_permissions_handoff.json" bad_evidence_manifest.write_text(json.dumps(bad_evidence_payload), encoding="utf-8") bad_evidence = validate_bsp_handoff.validate_handoff( bad_evidence_manifest, expected_project="CV1841CP-BOARD_dualos", repair_output_permissions=True, ) assert bad_evidence["passed"] is False assert kernel.stat().st_mode & 0o444 != 0o444 with patch.object(validate_bsp_handoff.os, "chmod", side_effect=PermissionError("denied")): unrepairable = validate_bsp_handoff.validate_handoff( manifest, expected_project="CV1841CP-BOARD_dualos", repair_output_permissions=True, ) assert unrepairable["passed"] is False assert any("无法检查或修复" in error for error in unrepairable["errors"]) os.chmod(kernel, 0o644) missing_margin_payload = json.loads(json.dumps(payload)) missing_margin_payload["validation"].pop("image_partition_margin") missing_margin_payload["build"].pop("image_partition_margin_path") missing_margin_manifest = root / "missing_margin_handoff.json" missing_margin_manifest.write_text( json.dumps(missing_margin_payload), encoding="utf-8" ) missing_margin = validate_bsp_handoff.validate_handoff(missing_margin_manifest) assert missing_margin["passed"] is False assert any("分区余量证据" in error for error in missing_margin["errors"]) artifact.write_bytes(b"tampered") tampered = validate_bsp_handoff.validate_handoff(manifest) assert tampered["passed"] is False assert any("大小不匹配" in error for error in tampered["errors"]) print("BSP handoff consumer tests passed") return 0 if __name__ == "__main__": raise SystemExit(main())