- Implemented PolicyDslValidator with command-line options for strict mode and JSON output. - Created PolicySchemaExporter to generate JSON schemas for policy-related models. - Developed PolicySimulationSmoke tool to validate policy simulations against expected outcomes. - Added project files and necessary dependencies for each tool. - Ensured proper error handling and usage instructions across tools.
		
			
				
	
	
		
			233 lines
		
	
	
		
			9.4 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			233 lines
		
	
	
		
			9.4 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
from __future__ import annotations
 | 
						|
 | 
						|
import json
 | 
						|
import tempfile
 | 
						|
import unittest
 | 
						|
from collections import OrderedDict
 | 
						|
from pathlib import Path
 | 
						|
import sys
 | 
						|
 | 
						|
sys.path.append(str(Path(__file__).resolve().parent))
 | 
						|
 | 
						|
from build_release import write_manifest  # type: ignore import-not-found
 | 
						|
from verify_release import VerificationError, compute_sha256, verify_release
 | 
						|
 | 
						|
 | 
						|
class VerifyReleaseTests(unittest.TestCase):
 | 
						|
    def setUp(self) -> None:
 | 
						|
        self._temp = tempfile.TemporaryDirectory()
 | 
						|
        self.base_path = Path(self._temp.name)
 | 
						|
        self.out_dir = self.base_path / "out"
 | 
						|
        self.release_dir = self.out_dir / "release"
 | 
						|
        self.release_dir.mkdir(parents=True, exist_ok=True)
 | 
						|
 | 
						|
    def tearDown(self) -> None:
 | 
						|
        self._temp.cleanup()
 | 
						|
 | 
						|
    def _relative_to_out(self, path: Path) -> str:
 | 
						|
        return path.relative_to(self.out_dir).as_posix()
 | 
						|
 | 
						|
    def _write_json(self, path: Path, payload: dict[str, object]) -> None:
 | 
						|
        path.parent.mkdir(parents=True, exist_ok=True)
 | 
						|
        with path.open("w", encoding="utf-8") as handle:
 | 
						|
            json.dump(payload, handle, indent=2)
 | 
						|
            handle.write("\n")
 | 
						|
 | 
						|
    def _create_sample_release(self) -> None:
 | 
						|
        sbom_path = self.release_dir / "artifacts/sboms/sample.cyclonedx.json"
 | 
						|
        sbom_path.parent.mkdir(parents=True, exist_ok=True)
 | 
						|
        sbom_path.write_text('{"bomFormat":"CycloneDX","specVersion":"1.5"}\n', encoding="utf-8")
 | 
						|
        sbom_sha = compute_sha256(sbom_path)
 | 
						|
 | 
						|
        provenance_path = self.release_dir / "artifacts/provenance/sample.provenance.json"
 | 
						|
        self._write_json(
 | 
						|
            provenance_path,
 | 
						|
            {
 | 
						|
                "buildDefinition": {"buildType": "https://example/build", "externalParameters": {}},
 | 
						|
                "runDetails": {"builder": {"id": "https://example/ci"}},
 | 
						|
            },
 | 
						|
        )
 | 
						|
        provenance_sha = compute_sha256(provenance_path)
 | 
						|
 | 
						|
        signature_path = self.release_dir / "artifacts/signatures/sample.signature"
 | 
						|
        signature_path.parent.mkdir(parents=True, exist_ok=True)
 | 
						|
        signature_path.write_text("signature-data\n", encoding="utf-8")
 | 
						|
        signature_sha = compute_sha256(signature_path)
 | 
						|
 | 
						|
        metadata_path = self.release_dir / "artifacts/metadata/sample.metadata.json"
 | 
						|
        self._write_json(metadata_path, {"digest": "sha256:1234"})
 | 
						|
        metadata_sha = compute_sha256(metadata_path)
 | 
						|
 | 
						|
        chart_path = self.release_dir / "helm/stellaops-1.0.0.tgz"
 | 
						|
        chart_path.parent.mkdir(parents=True, exist_ok=True)
 | 
						|
        chart_path.write_bytes(b"helm-chart-data")
 | 
						|
        chart_sha = compute_sha256(chart_path)
 | 
						|
 | 
						|
        compose_path = self.release_dir.parent / "deploy/compose/docker-compose.dev.yaml"
 | 
						|
        compose_path.parent.mkdir(parents=True, exist_ok=True)
 | 
						|
        compose_path.write_text("services: {}\n", encoding="utf-8")
 | 
						|
        compose_sha = compute_sha256(compose_path)
 | 
						|
 | 
						|
        debug_file = self.release_dir / "debug/.build-id/ab/cdef.debug"
 | 
						|
        debug_file.parent.mkdir(parents=True, exist_ok=True)
 | 
						|
        debug_file.write_bytes(b"\x7fELFDEBUGDATA")
 | 
						|
        debug_sha = compute_sha256(debug_file)
 | 
						|
 | 
						|
        debug_manifest_path = self.release_dir / "debug/debug-manifest.json"
 | 
						|
        debug_manifest = OrderedDict(
 | 
						|
            (
 | 
						|
                ("generatedAt", "2025-10-26T00:00:00Z"),
 | 
						|
                ("version", "1.0.0"),
 | 
						|
                ("channel", "edge"),
 | 
						|
                (
 | 
						|
                    "artifacts",
 | 
						|
                    [
 | 
						|
                        OrderedDict(
 | 
						|
                            (
 | 
						|
                                ("buildId", "abcdef1234"),
 | 
						|
                                ("platform", "linux/amd64"),
 | 
						|
                                ("debugPath", "debug/.build-id/ab/cdef.debug"),
 | 
						|
                                ("sha256", debug_sha),
 | 
						|
                                ("size", debug_file.stat().st_size),
 | 
						|
                                ("components", ["sample"]),
 | 
						|
                                ("images", ["registry.example/sample@sha256:feedface"]),
 | 
						|
                                ("sources", ["app/sample.dll"]),
 | 
						|
                            )
 | 
						|
                        )
 | 
						|
                    ],
 | 
						|
                ),
 | 
						|
            )
 | 
						|
        )
 | 
						|
        self._write_json(debug_manifest_path, debug_manifest)
 | 
						|
        debug_manifest_sha = compute_sha256(debug_manifest_path)
 | 
						|
        (debug_manifest_path.with_suffix(debug_manifest_path.suffix + ".sha256")).write_text(
 | 
						|
            f"{debug_manifest_sha}  {debug_manifest_path.name}\n", encoding="utf-8"
 | 
						|
        )
 | 
						|
 | 
						|
        manifest = OrderedDict(
 | 
						|
            (
 | 
						|
                (
 | 
						|
                    "release",
 | 
						|
                    OrderedDict(
 | 
						|
                        (
 | 
						|
                            ("version", "1.0.0"),
 | 
						|
                            ("channel", "edge"),
 | 
						|
                            ("date", "2025-10-26T00:00:00Z"),
 | 
						|
                            ("calendar", "2025.10"),
 | 
						|
                        )
 | 
						|
                    ),
 | 
						|
                ),
 | 
						|
                (
 | 
						|
                    "components",
 | 
						|
                    [
 | 
						|
                        OrderedDict(
 | 
						|
                            (
 | 
						|
                                ("name", "sample"),
 | 
						|
                                ("image", "registry.example/sample@sha256:feedface"),
 | 
						|
                                ("tags", ["registry.example/sample:1.0.0"]),
 | 
						|
                                (
 | 
						|
                                    "sbom",
 | 
						|
                                    OrderedDict(
 | 
						|
                                        (
 | 
						|
                                            ("path", self._relative_to_out(sbom_path)),
 | 
						|
                                            ("sha256", sbom_sha),
 | 
						|
                                        )
 | 
						|
                                    ),
 | 
						|
                                ),
 | 
						|
                                (
 | 
						|
                                    "provenance",
 | 
						|
                                    OrderedDict(
 | 
						|
                                        (
 | 
						|
                                            ("path", self._relative_to_out(provenance_path)),
 | 
						|
                                            ("sha256", provenance_sha),
 | 
						|
                                        )
 | 
						|
                                    ),
 | 
						|
                                ),
 | 
						|
                                (
 | 
						|
                                    "signature",
 | 
						|
                                    OrderedDict(
 | 
						|
                                        (
 | 
						|
                                            ("path", self._relative_to_out(signature_path)),
 | 
						|
                                            ("sha256", signature_sha),
 | 
						|
                                            ("ref", "sigstore://example"),
 | 
						|
                                            ("tlogUploaded", True),
 | 
						|
                                        )
 | 
						|
                                    ),
 | 
						|
                                ),
 | 
						|
                                (
 | 
						|
                                    "metadata",
 | 
						|
                                    OrderedDict(
 | 
						|
                                        (
 | 
						|
                                            ("path", self._relative_to_out(metadata_path)),
 | 
						|
                                            ("sha256", metadata_sha),
 | 
						|
                                        )
 | 
						|
                                    ),
 | 
						|
                                ),
 | 
						|
                            )
 | 
						|
                        )
 | 
						|
                    ],
 | 
						|
                ),
 | 
						|
                (
 | 
						|
                    "charts",
 | 
						|
                    [
 | 
						|
                        OrderedDict(
 | 
						|
                            (
 | 
						|
                                ("name", "stellaops"),
 | 
						|
                                ("version", "1.0.0"),
 | 
						|
                                ("path", self._relative_to_out(chart_path)),
 | 
						|
                                ("sha256", chart_sha),
 | 
						|
                            )
 | 
						|
                        )
 | 
						|
                    ],
 | 
						|
                ),
 | 
						|
                (
 | 
						|
                    "compose",
 | 
						|
                    [
 | 
						|
                        OrderedDict(
 | 
						|
                            (
 | 
						|
                                ("name", "docker-compose.dev.yaml"),
 | 
						|
                                ("path", compose_path.relative_to(self.out_dir).as_posix()),
 | 
						|
                                ("sha256", compose_sha),
 | 
						|
                            )
 | 
						|
                        )
 | 
						|
                    ],
 | 
						|
                ),
 | 
						|
                (
 | 
						|
                    "debugStore",
 | 
						|
                    OrderedDict(
 | 
						|
                        (
 | 
						|
                            ("manifest", "debug/debug-manifest.json"),
 | 
						|
                            ("sha256", debug_manifest_sha),
 | 
						|
                            ("entries", 1),
 | 
						|
                            ("platforms", ["linux/amd64"]),
 | 
						|
                            ("directory", "debug/.build-id"),
 | 
						|
                        )
 | 
						|
                    ),
 | 
						|
                ),
 | 
						|
            )
 | 
						|
        )
 | 
						|
        write_manifest(manifest, self.release_dir)
 | 
						|
 | 
						|
    def test_verify_release_success(self) -> None:
 | 
						|
        self._create_sample_release()
 | 
						|
        # Should not raise
 | 
						|
        verify_release(self.release_dir)
 | 
						|
 | 
						|
    def test_verify_release_detects_sha_mismatch(self) -> None:
 | 
						|
        self._create_sample_release()
 | 
						|
        tampered = self.release_dir / "artifacts/sboms/sample.cyclonedx.json"
 | 
						|
        tampered.write_text("tampered\n", encoding="utf-8")
 | 
						|
        with self.assertRaises(VerificationError):
 | 
						|
            verify_release(self.release_dir)
 | 
						|
 | 
						|
    def test_verify_release_detects_missing_debug_file(self) -> None:
 | 
						|
        self._create_sample_release()
 | 
						|
        debug_file = self.release_dir / "debug/.build-id/ab/cdef.debug"
 | 
						|
        debug_file.unlink()
 | 
						|
        with self.assertRaises(VerificationError):
 | 
						|
            verify_release(self.release_dir)
 | 
						|
 | 
						|
 | 
						|
if __name__ == "__main__":
 | 
						|
    unittest.main()
 |