"""Adapter: opengrep --json normalized to Finding[]. Same JSON schema as semgrep (opengrep is a semgrep fork).""" from __future__ import annotations import json import re from scripts.manifest import Finding _SEVERITY = {"ERROR": "high", "WARNING": "medium", "INFO": "low"} _CWE_RE = re.compile(r"(CWE-\d+)") _LOCAL_RULES_MARKER = "scripts.rules." def _clean_rule_id(check_id: str) -> str: if _LOCAL_RULES_MARKER in check_id: return check_id.rsplit(_LOCAL_RULES_MARKER, 1)[-1] return check_id def _cwe(meta: dict) -> str | None: raw = meta.get("cwe") if isinstance(raw, list) and raw: m = _CWE_RE.search(str(raw[0])) return m.group(1) if m else None if isinstance(raw, str): m = _CWE_RE.search(raw) return m.group(1) if m else None return None def parse_opengrep_output(stdout: str) -> list[Finding]: try: payload = json.loads(stdout) except json.JSONDecodeError: return [] out: list[Finding] = [] for r in payload.get("results", []): extra = r.get("extra", {}) metadata = extra.get("metadata", {}) out.append(Finding( tool="opengrep", rule_id=_clean_rule_id(r.get("check_id", "")), severity=_SEVERITY.get(extra.get("severity", ""), "medium"), file=r.get("path", ""), line=r.get("start", {}).get("line", 0), end_line=r.get("end", {}).get("line", r.get("start", {}).get("line", 0)), message=extra.get("message", ""), cwe=_cwe(metadata), )) return out