Skip to content

Commit 2591fd3

Browse files
LogicmnZeke Tierkelvalentijnscholten
authored
Split Github Vulnerability Scan into separate SCA & SAST parsers (#12773)
* Refactor GithubVulnerability parser and add GithubSAST parser * More GithubVulnerability and GithubSAST parser improvements * Add documentation * Add tests, update docs, and add hash code fields * Fix Github vulnerability parser unit test * Unit tests and parser tweaks * Rm files pushed by mistake * Revert certain removals from unit test * Add EPSS field population and update unit tests * Removed some unnecessary comments and formatting * Ruff formatting * Fix unit tests * Ruff formatting * Fix unit test * Github Vulnerability parser and docs tweaks, and upgrade instructions * Politeness * Fix dependabot update pr link parsing * Backwards compatability * Revert 2.49 docs change and add 2.51 * Add 2.51 upgrade doc * Smol 2.51 upgrade doc fix * Move imports to top * Ruff lint fix --------- Co-authored-by: Zeke Tierkel <zeketierkel@Zekes-MacBook-Pro.local> Co-authored-by: valentijnscholten <valentijnscholten@gmail.com>
1 parent 0d7f0e0 commit 2591fd3

File tree

15 files changed

+647
-245
lines changed

15 files changed

+647
-245
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
title: "Github SAST Scan"
3+
toc_hide: true
4+
---
5+
Import findings in JSON format from Github Code Scanning REST API:
6+
<https://docs.github.com/en/rest/code-scanning/code-scanning>
7+
8+
### Sample Scan Data
9+
Sample Github SAST scans can be found [here](https://github.com/DefectDojo/django-DefectDojo/tree/master/unittests/scans/github_sast).

docs/content/en/connecting_your_tools/parsers/file/github_vulnerability.md

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
title: "Github Vulnerability"
2+
title: "Github Vulnerability Scan"
33
toc_hide: true
44
---
55
Import findings from Github vulnerability scan (GraphQL Query):
@@ -15,6 +15,8 @@ vulnerabilityAlerts (RepositoryVulnerabilityAlert object)
1515
+ createdAt (optional)
1616
+ vulnerableManifestPath
1717
+ state (optional)
18+
+ dependabotUpdate (DependabotUpdate object) (optional)
19+
+ pullRequest (PullRequest object) (optional)
1820
+ securityVulnerability (SecurityVulnerability object)
1921
+ severity (CRITICAL/HIGH/LOW/MODERATE)
2022
+ package (optional)
@@ -27,10 +29,17 @@ vulnerabilityAlerts (RepositoryVulnerabilityAlert object)
2729
+ value
2830
+ references (optional)
2931
+ url (optional)
30-
+ cvss (optional)
32+
+ cvss (optional - deprecated, use cvssSeverities instead)
3133
+ score (optional)
3234
+ vectorString (optional)
35+
+ cvssSeverities (optional)
36+
+ cvssV3 (CVSS object) (optional)
37+
+ score (optional)
38+
+ vectorString (optional)
3339
+ cwes (optional)
40+
+ epss (EPSS object) (optional)
41+
+ percentage (optional)
42+
+ percentile (optional)
3443
```
3544

3645
References:

docs/content/en/open_source/upgrading/2.51.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,13 @@ The following Helm chart values have been modified in this release:
4848
- **Enhanced probe configuration for Celery**: Added support for customizing liveness, readiness, and startup probes in both Celery beat and worker deployments.
4949
- **Enhanced environment variable management**: All deployments now include `extraEnv` support for adding custom environment variables. For backwards compatibility, `.Values.extraEnv` can be used to inject common environment variables to all workloads.
5050

51+
## GitHub Scan Type and Parser Updates
52+
The Github Vulnerability scan type and parser has been split into two disctinct scan types:
53+
- [Github Vulnerability](https://github.com/DefectDojo/django-DefectDojo/blob/master/docs/content/en/connecting_your_tools/parsers/file/github_vulnerability.md) (original)
54+
- [Github SAST](https://github.com/DefectDojo/django-DefectDojo/blob/master/docs/content/en/connecting_your_tools/parsers/file/github_sast.md)
55+
56+
The original Github Vulnerability scan type will continue to accept SCA vulnerabilities uploaded in GitHub's GraphQL format, as it has always done. It will also continue to accept SAST uploads, however we recommend upgrading to the new Github SAST scan type for uploading these types of vulnerabilities going forward. This new scan type will accept the raw JSON response from [GitHub's REST API for code scanning alerts](https://docs.github.com/en/rest/code-scanning/code-scanning). Sample Github SAST scan data can be found [here](https://github.com/DefectDojo/django-DefectDojo/tree/master/unittests/scans/github_sast).
57+
5158
### Other changes
5259

5360
- **Celery pod annotations**: Now we can add annotations to Celery beat/worker pods separately.

dojo/settings/settings.dist.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1337,6 +1337,7 @@ def saml2_attrib_map_format(din):
13371337
"JFrog Xray On Demand Binary Scan": ["title", "component_name", "component_version"],
13381338
"Scout Suite Scan": ["file_path", "vuln_id_from_tool"], # for now we use file_path as there is no attribute for "service"
13391339
"Meterian Scan": ["cwe", "component_name", "component_version", "description", "severity"],
1340+
"Github SAST Scan": ["vuln_id_from_tool", "severity", "file_path", "line"],
13401341
"Github Vulnerability Scan": ["title", "severity", "component_name", "vulnerability_ids", "file_path"],
13411342
"Github Secrets Detection Report": ["title", "file_path", "line"],
13421343
"Solar Appscreener Scan": ["title", "file_path", "line", "severity"],
@@ -1583,6 +1584,7 @@ def saml2_attrib_map_format(din):
15831584
"Scout Suite Scan": DEDUPE_ALGO_HASH_CODE,
15841585
"AWS Security Hub Scan": DEDUPE_ALGO_UNIQUE_ID_FROM_TOOL,
15851586
"Meterian Scan": DEDUPE_ALGO_HASH_CODE,
1587+
"Github SAST Scan": DEDUPE_ALGO_HASH_CODE,
15861588
"Github Vulnerability Scan": DEDUPE_ALGO_HASH_CODE,
15871589
"Github Secrets Detection Report": DEDUPE_ALGO_HASH_CODE,
15881590
"Cloudsploit Scan": DEDUPE_ALGO_HASH_CODE,

dojo/tools/github_sast/__init__.py

Whitespace-only changes.

dojo/tools/github_sast/parser.py

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import json
2+
from urllib.parse import urlparse
3+
4+
from dojo.models import Finding
5+
6+
7+
class GithubSASTParser:
8+
def get_scan_types(self):
9+
return ["Github SAST Scan"]
10+
11+
def get_label_for_scan_types(self, scan_type):
12+
return scan_type
13+
14+
def get_description_for_scan_types(self, scan_type):
15+
return "GitHub SAST report file can be imported in JSON format."
16+
17+
def get_findings(self, filename, test):
18+
data = json.load(filename)
19+
if not isinstance(data, list):
20+
error_msg = "Invalid SAST report format, expected a JSON list of alerts."
21+
raise TypeError(error_msg)
22+
23+
findings = []
24+
for vuln in data:
25+
rule = vuln.get("rule", {})
26+
inst = vuln.get("most_recent_instance", {})
27+
loc = inst.get("location", {})
28+
html_url = vuln.get("html_url")
29+
rule_id = rule.get("id")
30+
title = f"{rule.get('description')} ({rule_id})"
31+
severity = rule.get("security_severity_level", "Info").title()
32+
active = vuln.get("state") == "open"
33+
34+
# Build description with context
35+
desc_lines = []
36+
if html_url:
37+
desc_lines.append(f"GitHub Alert: [{html_url}]({html_url})")
38+
owner = repo = None
39+
commit_sha = inst.get("commit_sha")
40+
if html_url:
41+
parsed = urlparse(html_url)
42+
parts = parsed.path.strip("/").split("/")
43+
# URL is /<owner>/<repo>/security/... so parts[0]=owner, parts[1]=repo
44+
if len(parts) >= 2:
45+
owner, repo = parts[0], parts[1]
46+
if owner and repo and commit_sha and loc.get("path") and loc.get("start_line"):
47+
file_link = (
48+
f"{parsed.scheme}://{parsed.netloc}/"
49+
f"{owner}/{repo}/blob/{commit_sha}/"
50+
f"{loc['path']}#L{loc['start_line']}"
51+
)
52+
desc_lines.append(f"Location: [{loc['path']}:{loc['start_line']}]({file_link})")
53+
elif loc.get("path") and loc.get("start_line"):
54+
# fallback if something is missing
55+
desc_lines.append(f"Location: {loc['path']}:{loc['start_line']}")
56+
msg = inst.get("message", {}).get("text")
57+
if msg:
58+
desc_lines.append(f"Message: {msg}")
59+
if severity:
60+
desc_lines.append(f"Rule Severity: {severity}")
61+
if rule.get("full_description"):
62+
desc_lines.append(f"Description: {rule.get('full_description')}")
63+
description = "\n".join(desc_lines)
64+
65+
finding = Finding(
66+
title=title,
67+
test=test,
68+
description=description,
69+
severity=severity,
70+
active=active,
71+
static_finding=True,
72+
dynamic_finding=False,
73+
vuln_id_from_tool=rule_id,
74+
)
75+
76+
# File path & line
77+
finding.file_path = loc.get("path")
78+
finding.line = loc.get("start_line")
79+
80+
if html_url:
81+
finding.url = html_url
82+
83+
findings.append(finding)
84+
return findings

0 commit comments

Comments
 (0)