diff --git a/.github/scripts/sigilix_sarif_contract.py b/.github/scripts/sigilix_sarif_contract.py index 5ecf29b..0ab7dfb 100644 --- a/.github/scripts/sigilix_sarif_contract.py +++ b/.github/scripts/sigilix_sarif_contract.py @@ -282,6 +282,11 @@ def _sanitize_run_results(run): } # OpenGrep runs the same rulesets as Semgrep → reuse the patterns. _RULE_CLASS_PATTERNS["opengrep"] = _RULE_CLASS_PATTERNS["semgrep"] +# Dedicated secret scanners only ever report hardcoded secrets, so every result +# maps to `hardcoded-secret` (`.+` = any non-empty ruleId). The exactly-one-class +# guard keeps this collision-safe. +_RULE_CLASS_PATTERNS["gitleaks"] = [(re.compile(r".+"), "hardcoded-secret")] +_RULE_CLASS_PATTERNS["trufflehog"] = [(re.compile(r".+"), "hardcoded-secret")] def stamp_rule_classes(run, tool_id): diff --git a/.github/scripts/sigilix_sarif_test.py b/.github/scripts/sigilix_sarif_test.py index fda8111..b7dbdb9 100644 --- a/.github/scripts/sigilix_sarif_test.py +++ b/.github/scripts/sigilix_sarif_test.py @@ -977,6 +977,12 @@ def test_collision_safe_unset_when_two_classes_match(self): # A contrived ruleId hitting two patterns → exactly-one guard leaves it unset. self.assertIsNone(self._run("sql-injection-and-ssrf-combo")) + def test_secret_scanners_map_to_hardcoded_secret(self): + for tool in ("gitleaks", "trufflehog"): + run = {"tool": {"driver": {}}, "results": [{"ruleId": "aws-access-token", "properties": {}}]} + stamp_rule_classes(run, tool) + self.assertEqual(run["results"][0]["properties"]["sigilixRuleClass"], "hardcoded-secret") + def test_unknown_tool_id_strips_only(self): run = {"tool": {"driver": {}}, "results": [{"ruleId": "dangerous-exec", "properties": {"sigilixRuleClass": "x"}}]} stamp_rule_classes(run, "eslint") # no patterns for eslint → strip only