Skip to content

Commit

Permalink
Implement Nancy Parser (DefectDojo#9801)
Browse files Browse the repository at this point in the history
* [sc-4916] first commit, nancy parser

* remanged __init__.py

* removed unused import

* invalid has field

* unittests

* unittests

* doc file name

* Update dojo/tools/nancy/parser.py

Co-authored-by: Charles Neill <1749665+cneill@users.noreply.github.com>

* Update dojo/tools/nancy/parser.py

Co-authored-by: Charles Neill <1749665+cneill@users.noreply.github.com>

* Update settings.dist.py

missing comma

* conflict

---------

Co-authored-by: Charles Neill <1749665+cneill@users.noreply.github.com>
  • Loading branch information
2 people authored and manuel-sommer committed Mar 27, 2024
1 parent f83d9e5 commit 3fb829f
Show file tree
Hide file tree
Showing 8 changed files with 1,007 additions and 1 deletion.
19 changes: 19 additions & 0 deletions docs/content/en/integrations/parsers/file/nancy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
title: "Nancy Scan"
toc_hide: true
---

Nancy output file (go list -json -deps ./... | nancy sleuth > nancy.json) can be imported in JSON format.


### File Types
This parser expects a JSON file.

### Command Used To Generate Output
- \`go list -json -deps ./... | nancy sleuth > nancy.json\`

### Sample Scan Data
Sample Nancy scans can be found [here](https://github.com/DefectDojo/django-DefectDojo/tree/master/unittests/scans/nancy).

### Link To Tool
See Nancy on GitHub: https://github.com/sonatype-nexus-community/nancy
4 changes: 3 additions & 1 deletion dojo/settings/settings.dist.py
Original file line number Diff line number Diff line change
Expand Up @@ -1246,7 +1246,8 @@ def saml2_attrib_map_format(dict):
'MobSF Scan': ['title', 'description', 'severity'],
'OSV Scan': ['title', 'description', 'severity'],
'Snyk Code Scan': ['vuln_id_from_tool', 'file_path'],
'Wiz Scan': ['title', 'description', 'severity'],
'Nancy Scan': ['title', 'vuln_id_from_tool'],
'Wiz Scan': ['title', 'description', 'severity']
}

# Override the hardcoded settings here via the env var
Expand Down Expand Up @@ -1427,6 +1428,7 @@ def saml2_attrib_map_format(dict):
'Solar Appscreener Scan': DEDUPE_ALGO_HASH_CODE,
'Gitleaks Scan': DEDUPE_ALGO_HASH_CODE,
'pip-audit Scan': DEDUPE_ALGO_HASH_CODE,
'Nancy Scan': DEDUPE_ALGO_HASH_CODE,
'Edgescan Scan': DEDUPE_ALGO_UNIQUE_ID_FROM_TOOL,
'Bugcrowd API Import': DEDUPE_ALGO_UNIQUE_ID_FROM_TOOL,
'Rubocop Scan': DEDUPE_ALGO_HASH_CODE,
Expand Down
Empty file added dojo/tools/nancy/__init.py__
Empty file.
85 changes: 85 additions & 0 deletions dojo/tools/nancy/parser.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import json

from cvss.cvss3 import CVSS3
from dojo.models import Finding


class NancyParser(object):
def get_scan_types(self):
return ["Nancy Scan"]

def get_label_for_scan_types(self, scan_type):
return scan_type # no custom label for now

def get_description_for_scan_types(self, scan_type):
return ("Nancy output file (go list -json -deps ./... | nancy sleuth > "
" nancy.json) can be imported in JSON format.")

def requires_file(self, scan_type):
"""Return boolean indicating if parser requires a file to process."""
return True

def get_findings(self, scan_file, test):
"""Return the collection of Findings ingested."""
data = json.load(scan_file)
findings = None

if "vulnerable" in data:
findings = self.get_items(data["vulnerable"], test)
else:
raise ValueError("Invalid format, unable to parse json.")

return findings

def get_items(self, vulnerable, test):
findings = []
for vuln in vulnerable:
finding = None
severity = 'Info'
# the tool does not define severity, however it
# provides CVSSv3 vector which will calculate
# severity dynamically on save()
references = []
if vuln['Vulnerabilities']:
comp_name = vuln['Coordinates'].split(':')[1].split('@')[0]
comp_version = vuln['Coordinates'].split(':')[1].split('@')[1]

references.append(vuln['Reference'])

for associated_vuln in vuln['Vulnerabilities']:
# create the finding object(s)
references.append(associated_vuln['Reference'])
vulnerability_ids = [associated_vuln['Cve']]
finding = Finding(
title=associated_vuln['Title'],
description=associated_vuln['Description'],
test=test,
severity=severity,
component_name=comp_name,
component_version=comp_version,
false_p=False,
duplicate=False,
out_of_scope=False,
static_finding=True,
dynamic_finding=False,
vuln_id_from_tool=associated_vuln["Id"],
cve=associated_vuln['Cve'],
references="\n".join(references),
)

finding.unsaved_vulnerability_ids = vulnerability_ids

# CVSSv3 vector
if associated_vuln['CvssVector']:
finding.cvssv3 = CVSS3(
associated_vuln['CvssVector']).clean_vector()

# do we have a CWE?
if associated_vuln['Title'].startswith('CWE-'):
cwe = (associated_vuln['Title']
.split(':')[0].split('-')[1])
finding.cwe = int(cwe)

findings.append(finding)

return findings
Loading

0 comments on commit 3fb829f

Please sign in to comment.