diff --git a/tools/sbom-diff-and-risk/src/sbom_diff_risk/policy_parser.py b/tools/sbom-diff-and-risk/src/sbom_diff_risk/policy_parser.py index 189d7fa..ff3751f 100644 --- a/tools/sbom-diff-and-risk/src/sbom_diff_risk/policy_parser.py +++ b/tools/sbom-diff-and-risk/src/sbom_diff_risk/policy_parser.py @@ -1,5 +1,6 @@ from __future__ import annotations +import math from pathlib import Path from typing import Iterable @@ -244,11 +245,11 @@ def _parse_bool(value: object, context: str) -> bool: def _parse_optional_score(value: object, context: str) -> float | None: if value is None: return None - if not isinstance(value, (int, float)): - raise PolicyError(f"Invalid policy schema in {context}: expected a number between 0 and 10.") + if isinstance(value, bool) or not isinstance(value, (int, float)): + raise PolicyError(f"Invalid policy schema in {context}: expected a finite number between 0 and 10.") normalized = float(value) - if normalized < 0 or normalized > 10: - raise PolicyError(f"Invalid policy schema in {context}: expected a number between 0 and 10.") + if not math.isfinite(normalized) or normalized < 0 or normalized > 10: + raise PolicyError(f"Invalid policy schema in {context}: expected a finite number between 0 and 10.") return normalized diff --git a/tools/sbom-diff-and-risk/tests/test_policy_scorecard.py b/tools/sbom-diff-and-risk/tests/test_policy_scorecard.py index 290119c..832a42d 100644 --- a/tools/sbom-diff-and-risk/tests/test_policy_scorecard.py +++ b/tools/sbom-diff-and-risk/tests/test_policy_scorecard.py @@ -36,6 +36,25 @@ def test_policy_parser_accepts_scorecard_v3_policy(tmp_path) -> None: # noqa: A assert policy.minimum_scorecard_score == 7.5 +@pytest.mark.parametrize("raw_score", ["true", ".nan", ".inf", "-.inf"]) +def test_policy_parser_rejects_non_finite_or_boolean_scorecard_threshold(tmp_path, raw_score: str) -> None: # noqa: ANN001 + path = tmp_path / "policy.yml" + path.write_text( + "\n".join( + [ + "version: 3", + "warn_on: [scorecard_below_threshold]", + f"minimum_scorecard_score: {raw_score}", + "", + ] + ), + encoding="utf-8", + ) + + with pytest.raises(PolicyError, match="expected a finite number between 0 and 10"): + load_policy(path) + + def test_policy_parser_rejects_scorecard_keys_in_version_2_policy(tmp_path: Path) -> None: path = tmp_path / "policy.yml" path.write_text("version: 2\nminimum_scorecard_score: 7.0\n", encoding="utf-8")