diff --git a/scripts/f4_linter_linux_provisioning.py b/scripts/f4_linter_linux_provisioning.py index e0eb9e3..406bc96 100644 --- a/scripts/f4_linter_linux_provisioning.py +++ b/scripts/f4_linter_linux_provisioning.py @@ -438,6 +438,34 @@ "release_blocking": False, "blocker_reason": None, }, + ("deb", "checkstyle"): { + "evidence_source": "Debian official package metadata for checkstyle", + "evidence_source_type": "official-distro-metadata", + "evidence_status": "verified-official-source", + "evidence_note": ( + "Verified against official Debian package metadata " + "https://packages.debian.org/checkstyle, source package metadata " + "https://packages.debian.org/source/stable/checkstyle, tracker " + "metadata https://tracker.debian.org/pkg/checkstyle, and manpage " + "metadata https://manpages.debian.org/testing/checkstyle/checkstyle.1.en.html " + "for the existing checkstyle package/executable mapping." + ), + "official_source_name": "Debian Package Search: checkstyle", + "official_source_url": "https://packages.debian.org/checkstyle", + "official_source_kind": "distro-package-index", + "verification_scope": "package-name-and-executable", + "verification_note": ( + "Verified against official Debian package metadata " + "https://packages.debian.org/checkstyle, source package metadata " + "https://packages.debian.org/source/stable/checkstyle, tracker " + "metadata https://tracker.debian.org/pkg/checkstyle, and manpage " + "metadata https://manpages.debian.org/testing/checkstyle/checkstyle.1.en.html: " + "package name checkstyle and executable checkstyle." + ), + "external_verification_required_for_new_mappings": False, + "release_blocking": False, + "blocker_reason": None, + }, } OS_PACKAGE_NAMES: dict[str, dict[str, tuple[str, ...]]] = { diff --git a/tests/packaging/test_f4_linter_linux_provisioning.py b/tests/packaging/test_f4_linter_linux_provisioning.py index ca14a38..0fd7f80 100644 --- a/tests/packaging/test_f4_linter_linux_provisioning.py +++ b/tests/packaging/test_f4_linter_linux_provisioning.py @@ -275,6 +275,7 @@ def test_distro_evidence_scope_is_approved_package_mappings_only( ("deb", "clang-tidy"), ("deb", "cppcheck"), ("deb", "clang-format"), + ("deb", "checkstyle"), ] assert all( record.evidence_source_type == "official-distro-metadata" for record in promoted @@ -379,6 +380,8 @@ def test_existing_os_package_policy_has_approved_distro_mapping_evidence( cppcheck_evidence = _evidence_record(deb_evidence, "cppcheck") clang_format = _mapping_record(deb, "clang-format") clang_format_evidence = _evidence_record(deb_evidence, "clang-format") + checkstyle = _mapping_record(deb, "checkstyle") + checkstyle_evidence = _evidence_record(deb_evidence, "checkstyle") _assert_approved_deb_mapping(yamllint, yamllint_evidence, "yamllint") _assert_official_deb_evidence( @@ -437,14 +440,25 @@ def test_existing_os_package_policy_has_approved_distro_mapping_evidence( "official_source_url": "https://packages.debian.org/clang-format", }, ) + _assert_approved_deb_mapping(checkstyle, checkstyle_evidence, "checkstyle") + _assert_official_deb_evidence( + checkstyle, + checkstyle_evidence, + { + "tool_id": "checkstyle", + "evidence_source": "Debian official package metadata for checkstyle", + "official_source_name": "Debian Package Search: checkstyle", + "official_source_url": "https://packages.debian.org/checkstyle", + }, + ) def test_generated_distro_evidence_preserves_repository_local_baseline( linux_helper: ModuleType, tmp_path: Path, ) -> None: - manifest = _build_manifest(linux_helper, tmp_path, "deb") - evidence = _manifest_distro_evidence(manifest, "checkstyle") + manifest = _build_manifest(linux_helper, tmp_path, "rpm") + evidence = _manifest_distro_evidence(manifest, "yamllint") assert evidence["evidence_source"] == "OS_PACKAGE_NAMES" assert evidence["evidence_source_type"] == "repository-local-policy" @@ -524,13 +538,14 @@ def test_generated_baseline_evidence_records_are_not_promotable( ("deb", "clang-tidy"), ("deb", "cppcheck"), ("deb", "clang-format"), + ("deb", "checkstyle"), ] assert all( linux_helper.linux_distro_mapping_evidence_can_promote(record) is (record in promoted) for record in matrix ) - assert sum(row["can_promote"] is True for row in promotion_matrix) == 5 + assert sum(row["can_promote"] is True for row in promotion_matrix) == 6 assert all( row["promotion_state"] == "baseline-not-promoted" for row in promotion_matrix @@ -541,6 +556,7 @@ def test_generated_baseline_evidence_records_are_not_promotable( ("deb", "clang-tidy"), ("deb", "cppcheck"), ("deb", "clang-format"), + ("deb", "checkstyle"), } ) @@ -549,15 +565,15 @@ def test_complete_synthetic_verified_official_evidence_is_promotable( linux_helper: ModuleType, tmp_path: Path, ) -> None: - manifest = _build_manifest(linux_helper, tmp_path, "deb") + manifest = _build_manifest(linux_helper, tmp_path, "rpm") evidence = _complete_verified_evidence( - _manifest_distro_evidence(manifest, "checkstyle") + _manifest_distro_evidence(manifest, "yamllint") ) assert linux_helper.linux_distro_mapping_evidence_promotion_errors(evidence) == [] assert linux_helper.linux_distro_mapping_evidence_can_promote(evidence) is True - _manifest_tool(manifest, "checkstyle")["distro_mapping"]["evidence"] = evidence + _manifest_tool(manifest, "yamllint")["distro_mapping"]["evidence"] = evidence assert linux_helper.verify_linux_provisioning_manifest(manifest) == [] @@ -617,6 +633,7 @@ def test_docker_helper_distro_mappings_inherit_deb_and_rpm_policy( ("clang-tidy", "clang-tidy"), ("cppcheck", "cppcheck"), ("clang-format", "clang-format"), + ("checkstyle", "checkstyle"), ): _assert_docker_deb_baseline_mapping( _mapping_record(docker_deb, tool_id), @@ -708,7 +725,8 @@ def test_manifest_records_distro_mapping_for_package_manager_tools( tmp_path: Path, ) -> None: manifest = _build_manifest(linux_helper, tmp_path, "deb") - checkstyle = _manifest_tool(manifest, "checkstyle") + rpm_manifest = _build_manifest(linux_helper, tmp_path, "rpm") + rpm_yamllint = _manifest_tool(rpm_manifest, "yamllint") biome = _manifest_tool(manifest, "biome") cargo_clippy = _manifest_tool(manifest, "cargo-clippy") ruff = _manifest_tool(manifest, "ruff") @@ -751,15 +769,22 @@ def test_manifest_records_distro_mapping_for_package_manager_tools( "evidence_source": "Debian official package metadata for clang-format", "official_source_url": "https://packages.debian.org/clang-format", }, + { + "tool_id": "checkstyle", + "package_name": "checkstyle", + "executable_name": "checkstyle", + "evidence_source": "Debian official package metadata for checkstyle", + "official_source_url": "https://packages.debian.org/checkstyle", + }, ): _assert_manifest_official_deb_mapping( _manifest_tool(manifest, expected["tool_id"]), expected, ) - assert checkstyle["distro_mapping"]["evidence"]["evidence_status"] == ( + assert rpm_yamllint["distro_mapping"]["evidence"]["evidence_status"] == ( "current-policy-baseline" ) - assert checkstyle["distro_mapping"]["evidence"]["evidence_source_type"] == ( + assert rpm_yamllint["distro_mapping"]["evidence"]["evidence_source_type"] == ( "repository-local-policy" ) assert biome["distro_mapping"]["mapping_status"] == ( @@ -771,6 +796,7 @@ def test_manifest_records_distro_mapping_for_package_manager_tools( assert "distro_mapping" not in cargo_clippy assert "distro_mapping" not in ruff assert linux_helper.verify_linux_provisioning_manifest(manifest) == [] + assert linux_helper.verify_linux_provisioning_manifest(rpm_manifest) == [] def test_linux_manifest_rejects_invalid_or_non_linux_artifact_ids( @@ -1274,6 +1300,71 @@ def test_manifest_verifier_rejects_deb_clang_format_without_verification_note( ) +@pytest.mark.parametrize( + ("field", "tampered_value", "expected_error"), + ( + ( + "official_source_url", + "https://tracker.debian.org/pkg/checkstyle", + "checkstyle: distro_mapping evidence official_source_url differs", + ), + ( + "official_source_kind", + "upstream-release-page", + "checkstyle: distro_mapping evidence official_source_kind differs", + ), + ( + "verification_scope", + "package-name-only", + "checkstyle: distro_mapping evidence verification_scope differs", + ), + ( + "verified_package_names", + ["wrong-package"], + "checkstyle: distro_mapping evidence verified_package_names differs", + ), + ( + "verified_executable_names", + ["wrong-executable"], + "checkstyle: distro_mapping evidence verified_executable_names differs", + ), + ( + "evidence_source_type", + "repository-local-policy", + "checkstyle: distro_mapping evidence: verified-official-source evidence cannot use repository-local-policy", + ), + ), +) +def test_manifest_verifier_rejects_tampered_deb_checkstyle_official_evidence( + linux_helper: ModuleType, + tmp_path: Path, + field: str, + tampered_value: Any, + expected_error: str, +) -> None: + manifest = _build_manifest(linux_helper, tmp_path, "deb") + _manifest_distro_evidence(manifest, "checkstyle")[field] = tampered_value + + errors = linux_helper.verify_linux_provisioning_manifest(manifest) + + assert any(expected_error in error for error in errors) + + +def test_manifest_verifier_rejects_deb_checkstyle_without_verification_note( + linux_helper: ModuleType, + tmp_path: Path, +) -> None: + manifest = _build_manifest(linux_helper, tmp_path, "deb") + del _manifest_distro_evidence(manifest, "checkstyle")["verification_note"] + + errors = linux_helper.verify_linux_provisioning_manifest(manifest) + + assert any( + "checkstyle: distro_mapping evidence: missing verification_note" in error + for error in errors + ) + + def test_manifest_verifier_rejects_verified_evidence_with_repository_local_source_type( linux_helper: ModuleType, tmp_path: Path, @@ -1396,15 +1487,15 @@ def test_manifest_verifier_rejects_current_baseline_without_external_verificatio linux_helper: ModuleType, tmp_path: Path, ) -> None: - manifest = _build_manifest(linux_helper, tmp_path, "deb") - _manifest_distro_evidence(manifest, "checkstyle")[ + manifest = _build_manifest(linux_helper, tmp_path, "rpm") + _manifest_distro_evidence(manifest, "yamllint")[ "external_verification_required_for_new_mappings" ] = False errors = linux_helper.verify_linux_provisioning_manifest(manifest) assert any( - "checkstyle: distro_mapping evidence: current-policy-baseline evidence must require external verification" + "yamllint: distro_mapping evidence: current-policy-baseline evidence must require external verification" in error for error in errors ) @@ -1414,20 +1505,20 @@ def test_manifest_verifier_rejects_current_baseline_with_official_source_claims( linux_helper: ModuleType, tmp_path: Path, ) -> None: - manifest = _build_manifest(linux_helper, tmp_path, "deb") - evidence = _manifest_distro_evidence(manifest, "checkstyle") + manifest = _build_manifest(linux_helper, tmp_path, "rpm") + evidence = _manifest_distro_evidence(manifest, "yamllint") evidence["official_source_name"] = "synthetic distro package index" evidence["official_source_url"] = "synthetic-official-source" errors = linux_helper.verify_linux_provisioning_manifest(manifest) assert any( - "checkstyle: distro_mapping evidence: current-policy-baseline evidence must not claim official_source_name" + "yamllint: distro_mapping evidence: current-policy-baseline evidence must not claim official_source_name" in error for error in errors ) assert any( - "checkstyle: distro_mapping evidence: current-policy-baseline evidence must not claim official_source_url" + "yamllint: distro_mapping evidence: current-policy-baseline evidence must not claim official_source_url" in error for error in errors ) @@ -1611,6 +1702,22 @@ def test_manifest_verifier_rejects_tampered_deb_clang_format_evidence_record_id( ) +def test_manifest_verifier_rejects_tampered_deb_checkstyle_evidence_record_id( + linux_helper: ModuleType, + tmp_path: Path, +) -> None: + manifest = _build_manifest(linux_helper, tmp_path, "deb") + evidence = _manifest_tool(manifest, "checkstyle")["distro_mapping"]["evidence"] + evidence["evidence_record_id"] = "repository-local-policy:deb:checkstyle" + + errors = linux_helper.verify_linux_provisioning_manifest(manifest) + + assert any( + "checkstyle: distro_mapping evidence evidence_record_id differs" in error + for error in errors + ) + + def test_manifest_verifier_rejects_wrong_docker_evidence_inheritance( linux_helper: ModuleType, tmp_path: Path, @@ -2060,12 +2167,10 @@ def test_release_blocking_provenance_summary_tracks_current_linux_gaps( evidence_summary["evidence_record_count"] == mapping_summary["approved_count"] ) assert evidence_summary["evidence_status_counts"] == { - "current-policy-baseline": evidence_summary["evidence_record_count"] - 5, - "verified-official-source": 5, + "verified-official-source": 6, } assert evidence_summary["evidence_source_type_counts"] == { - "official-distro-metadata": 5, - "repository-local-policy": evidence_summary["evidence_record_count"] - 5, + "official-distro-metadata": 6, } assert ( mapping_summary["evidence_status_counts"] @@ -2075,14 +2180,13 @@ def test_release_blocking_provenance_summary_tracks_current_linux_gaps( promotion_summary["evidence_record_count"] == evidence_summary["evidence_record_count"] ) - assert promotion_summary["promotable_count"] == 5 + assert promotion_summary["promotable_count"] == 6 assert promotion_summary["baseline_not_promoted_count"] == ( - evidence_summary["evidence_record_count"] - 5 + evidence_summary["evidence_record_count"] - 6 ) - assert promotion_summary["verified_official_source_count"] == 5 + assert promotion_summary["verified_official_source_count"] == 6 assert promotion_summary["promotion_state_counts"] == { - "baseline-not-promoted": evidence_summary["evidence_record_count"] - 5, - "verified-official-source": 5, + "verified-official-source": 6, } assert ( docker_summary["mapping_status_counts"]