src/pqc_lint/reporters/sarif.py
2.8 KB · 84 lines · python Raw
1 """SARIF 2.1.0 reporter - compatible with GitHub code scanning."""
2
3 from __future__ import annotations
4
5 import json
6
7 from pqc_lint.findings import ScanReport, Severity
8 from pqc_lint.reporters.base import Reporter
9 from pqc_lint.rules import RULES
10
11 _SEVERITY_TO_SARIF_LEVEL = {
12 Severity.CRITICAL: "error",
13 Severity.HIGH: "error",
14 Severity.MEDIUM: "warning",
15 Severity.LOW: "note",
16 Severity.INFO: "none",
17 }
18
19
20 class SarifReporter(Reporter):
21 format_name = "sarif"
22
23 def render(self, report: ScanReport) -> str:
24 rules_payload = []
25 for r in RULES:
26 rules_payload.append({
27 "id": r.id,
28 "name": r.title.replace(" ", ""),
29 "shortDescription": {"text": r.title},
30 "fullDescription": {"text": r.message},
31 "helpUri": "https://quantamrkt.com/tools/pqc-lint-action",
32 "help": {"text": r.suggestion or r.message},
33 "defaultConfiguration": {
34 "level": _SEVERITY_TO_SARIF_LEVEL[r.severity],
35 },
36 "properties": {
37 "tags": ["security", "post-quantum", "cryptography"],
38 "cwe": r.cwe or "",
39 "precision": "high",
40 "classical_primitive": r.classical_primitive,
41 },
42 })
43
44 results = []
45 for f in report.findings:
46 results.append({
47 "ruleId": f.rule_id,
48 "level": _SEVERITY_TO_SARIF_LEVEL[f.severity],
49 "message": {"text": f"{f.message} Suggestion: {f.suggestion}"},
50 "locations": [{
51 "physicalLocation": {
52 "artifactLocation": {"uri": f.file},
53 "region": {
54 "startLine": f.line,
55 "startColumn": f.column,
56 "snippet": {"text": f.snippet or ""},
57 },
58 },
59 }],
60 "properties": {
61 "severity": f.severity.value,
62 "cwe": f.cwe or "",
63 "suggestion": f.suggestion,
64 },
65 })
66
67 sarif = {
68 "$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json",
69 "version": "2.1.0",
70 "runs": [{
71 "tool": {
72 "driver": {
73 "name": "pqc-lint",
74 "version": "0.1.0",
75 "informationUri": "https://quantamrkt.com/tools/pqc-lint-action",
76 "rules": rules_payload,
77 },
78 },
79 "results": results,
80 "columnKind": "utf16CodeUnits",
81 }],
82 }
83 return json.dumps(sarif, indent=2)
84