From b557d7be07071e43ba2e490b2cde83cfc4ae2b57 Mon Sep 17 00:00:00 2001 From: Dan D'Avella Date: Thu, 5 Sep 2024 17:06:58 -0400 Subject: [PATCH] Fix sonar metadata (#824) * Fix issue name and finding ID in Sonar metadata * Update fixed findings with metadata from ToolRule * Hardening suggestions for codemodder-python / fix-sonar-metadata (#825) Use Assignment Expression (Walrus) In Conditional Co-authored-by: pixeebot[bot] <104101892+pixeebot[bot]@users.noreply.github.com> --------- Co-authored-by: pixeebot[bot] <104101892+pixeebot[bot]@users.noreply.github.com> --- src/codemodder/codemods/base_codemod.py | 4 +++ src/codemodder/context.py | 8 +++++- .../utils/update_finding_metadata.py | 26 +++++++++++++++++++ src/core_codemods/sonar/results.py | 9 +++++-- 4 files changed, 44 insertions(+), 3 deletions(-) create mode 100644 src/codemodder/utils/update_finding_metadata.py diff --git a/src/codemodder/codemods/base_codemod.py b/src/codemodder/codemods/base_codemod.py index caf0271c..cb338b2d 100644 --- a/src/codemodder/codemods/base_codemod.py +++ b/src/codemodder/codemods/base_codemod.py @@ -131,6 +131,10 @@ def detection_tool(self) -> DetectionTool | None: name=self._metadata.tool.name, ) + @property + def detection_tool_rules(self) -> list[ToolRule]: + return self._metadata.tool.rules if self._metadata.tool else [] + @cached_property def docs_module(self) -> Traversable: return importlib.resources.files(self.docs_module_path) diff --git a/src/codemodder/context.py b/src/codemodder/context.py index 97260d67..8d70947a 100644 --- a/src/codemodder/context.py +++ b/src/codemodder/context.py @@ -25,6 +25,7 @@ from codemodder.registry import CodemodRegistry from codemodder.result import ResultSet from codemodder.utils.timer import Timer +from codemodder.utils.update_finding_metadata import update_finding_metadata if TYPE_CHECKING: from openai import OpenAI @@ -180,6 +181,11 @@ def process_results(self, codemod_id: str, results: Iterator[FileContext]): def compile_results(self, codemods: list[BaseCodemod]) -> list[CodeTFResult]: results = [] for codemod in codemods: + changesets = update_finding_metadata( + codemod.detection_tool_rules, + self.get_changesets(codemod.id), + ) + result = CodeTFResult( codemod=codemod.id, summary=codemod.summary, @@ -188,7 +194,7 @@ def compile_results(self, codemods: list[BaseCodemod]) -> list[CodeTFResult]: references=codemod.references, properties={}, failedFiles=[str(file) for file in self.get_failures(codemod.id)], - changeset=self.get_changesets(codemod.id), + changeset=changesets, unfixedFindings=self.get_unfixed_findings(codemod.id), ) diff --git a/src/codemodder/utils/update_finding_metadata.py b/src/codemodder/utils/update_finding_metadata.py new file mode 100644 index 00000000..99e9338b --- /dev/null +++ b/src/codemodder/utils/update_finding_metadata.py @@ -0,0 +1,26 @@ +from __future__ import annotations + +import typing + +if typing.TYPE_CHECKING: + from codemodder.codemods.base_codemod import ToolRule + +from codemodder.codetf import ChangeSet + + +def update_finding_metadata( + tool_rules: list[ToolRule], + changesets: list[ChangeSet], +) -> list[ChangeSet]: + if not (tool_rule_map := {rule.id: (rule.name, rule.url) for rule in tool_rules}): + return changesets + + for changeset in changesets: + for change in changeset.changes: + for finding in change.findings or []: + if finding.id in tool_rule_map: + finding.rule.name = tool_rule_map[finding.id][0] + finding.rule.url = tool_rule_map[finding.id][1] + + # TODO: eventually make this functional and return a new list + return changesets diff --git a/src/core_codemods/sonar/results.py b/src/core_codemods/sonar/results.py index aec28b78..8a03b2ff 100644 --- a/src/core_codemods/sonar/results.py +++ b/src/core_codemods/sonar/results.py @@ -49,8 +49,13 @@ def from_result(cls, result: dict) -> Self: for flow in result.get("flows", []) ] + finding_id = result.get("key", rule_id) + + # Both issues and hotspots have a `message` key + name = result.get("message", None) or rule_id + return cls( - finding_id=rule_id, + finding_id=finding_id, rule_id=rule_id, locations=locations, codeflows=all_flows, @@ -58,7 +63,7 @@ def from_result(cls, result: dict) -> Self: id=rule_id, rule=Rule( id=rule_id, - name=rule_id, + name=name, url=sonar_url_from_id(rule_id), ), ),