From 360c5492788db7d77cae43185254c43086136ef1 Mon Sep 17 00:00:00 2001 From: Ahmed Allam Date: Mon, 17 Aug 2026 09:08:07 +0000 Subject: [PATCH] reporting: drop per-metric contextual CVSS reasoning, keep the summary --- .../skills/custom/dependency_cve_scanning.md | 4 --- strix/tools/reporting/tool.py | 31 ------------------- tests/test_reporting_fields.py | 4 +-- 3 files changed, 1 insertion(+), 38 deletions(-) diff --git a/strix/skills/custom/dependency_cve_scanning.md b/strix/skills/custom/dependency_cve_scanning.md index 125b92d8..1b9a4536 100644 --- a/strix/skills/custom/dependency_cve_scanning.md +++ b/strix/skills/custom/dependency_cve_scanning.md @@ -288,10 +288,6 @@ only caller of `yaml.load` is `parse_manifest` in `scripts/import.py:88`, which reaches that function, so an attacker must already hold shell access on the job host, and the parsed data is build metadata rather than customer records." -`contextual_cvss_metric_reasoning` is optional and takes one detailed sentence -per metric you adjusted, keyed by the metric name. Use it for the per-metric -detail that does not fit the summary. - Omit all the contextual fields when the published rating already fits, and when the evidence is thin. A contextual score is a claim you must be able to defend, and this adjustment never replaces `advisory_cvss`. diff --git a/strix/tools/reporting/tool.py b/strix/tools/reporting/tool.py index f1255eff..49a082d6 100644 --- a/strix/tools/reporting/tool.py +++ b/strix/tools/reporting/tool.py @@ -782,21 +782,6 @@ def _clean_contextual_cvss_metrics(raw: dict[str, str] | None) -> dict[str, str] return metrics -def _clean_contextual_cvss_metric_reasoning( - raw: dict[str, str] | None, metrics: dict[str, str] -) -> dict[str, str]: - """Keep per-metric justifications that belong to an adjusted metric.""" - if not isinstance(raw, dict): - return {} - detail: dict[str, str] = {} - for key, value in raw.items(): - metric = str(key or "").strip().upper() - text = str(value or "").strip() - if metric in metrics and text: - detail[metric] = text[:_MAX_CONTEXTUAL_REASONING_CHARS] - return detail - - def _build_dependency_metadata( *, package_name: str, @@ -810,7 +795,6 @@ def _build_dependency_metadata( reachability_evidence: str | None = None, contextual_cvss_metrics: dict[str, str] | None = None, contextual_cvss_reasoning: str | None = None, - contextual_cvss_metric_reasoning: dict[str, str] | None = None, ) -> dict[str, Any]: metadata: dict[str, Any] = { "package_name": package_name.strip(), @@ -839,11 +823,6 @@ def _build_dependency_metadata( if cleaned_metrics and reasoning: metadata["contextual_cvss_metrics"] = cleaned_metrics metadata["contextual_cvss_reasoning"] = reasoning[:_MAX_CONTEXTUAL_REASONING_CHARS] - metric_reasoning = _clean_contextual_cvss_metric_reasoning( - contextual_cvss_metric_reasoning, cleaned_metrics - ) - if metric_reasoning: - metadata["contextual_cvss_metric_reasoning"] = metric_reasoning return metadata @@ -917,7 +896,6 @@ async def _do_create_dependency( # noqa: PLR0912 reachability_evidence: str | None = None, contextual_cvss_metrics: dict[str, str] | None = None, contextual_cvss_reasoning: str | None = None, - contextual_cvss_metric_reasoning: dict[str, str] | None = None, agent_id: str | None = None, agent_name: str | None = None, ) -> dict[str, Any]: @@ -1002,7 +980,6 @@ async def _do_create_dependency( # noqa: PLR0912 reachability_evidence=reachability_evidence, contextual_cvss_metrics=contextual_cvss_metrics, contextual_cvss_reasoning=contextual_cvss_reasoning, - contextual_cvss_metric_reasoning=contextual_cvss_metric_reasoning, ) evidence = _build_dependency_evidence( cve=parsed_cve, @@ -1116,7 +1093,6 @@ async def create_dependency_report( reachability_evidence: str | None = None, contextual_cvss_metrics: dict[str, str] | None = None, contextual_cvss_reasoning: str | None = None, - contextual_cvss_metric_reasoning: dict[str, str] | None = None, ) -> str: """File a known-CVE dependency (SCA) finding — one report per CVE x package. @@ -1244,12 +1220,6 @@ async def create_dependency_report( never a generic statement such as "low risk". The user reads this text next to the adjusted score, so an adjustment without it is discarded. - contextual_cvss_metric_reasoning: Optional per-metric detail, as a - mapping of the SAME metric names you set in - ``contextual_cvss_metrics`` to one detailed sentence each - (for example ``{"MAC": "Reaching the parser needs the - --unsafe flag, which deploy/prod.yaml never sets."}``). - Entries for metrics you did not adjust are dropped. """ agent_id, agent_name = _caller_identity(ctx) @@ -1276,7 +1246,6 @@ async def create_dependency_report( reachability_evidence=reachability_evidence, contextual_cvss_metrics=contextual_cvss_metrics, contextual_cvss_reasoning=contextual_cvss_reasoning, - contextual_cvss_metric_reasoning=contextual_cvss_metric_reasoning, agent_id=agent_id, agent_name=agent_name, ) diff --git a/tests/test_reporting_fields.py b/tests/test_reporting_fields.py index d698c904..688c88ec 100644 --- a/tests/test_reporting_fields.py +++ b/tests/test_reporting_fields.py @@ -884,7 +884,6 @@ def test_dep_tool_exposes_contextual_cvss_params() -> None: for field in ( "contextual_cvss_metrics", "contextual_cvss_reasoning", - "contextual_cvss_metric_reasoning", ): assert field in dep_props assert "source-to-sink" in dep_props["contextual_cvss_metrics"]["description"].lower() @@ -914,13 +913,12 @@ async def test_dependency_report_keeps_only_valid_contextual_metrics( manifest_path="package-lock.json", contextual_cvss_metrics={"MAC": "H", "MC": "L", "AV": "N", "MPR": "Z"}, contextual_cvss_reasoning="Only scripts/import.py reaches the sink.", - contextual_cvss_metric_reasoning={"MAC": "Needs a build flag.", "MPR": "dropped"}, ) assert result["success"] is True, result metadata = report_state.vulnerability_reports[0]["dependency_metadata"] assert metadata["contextual_cvss_metrics"] == {"MAC": "H", "MC": "L"} assert metadata["contextual_cvss_reasoning"] == "Only scripts/import.py reaches the sink." - assert metadata["contextual_cvss_metric_reasoning"] == {"MAC": "Needs a build flag."} + assert "contextual_cvss_metric_reasoning" not in metadata @pytest.mark.asyncio