Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
---
title: "ReversingLabs Spectra Assure"
toc_hide: true
---

# ReversingLabs Spectra Assure Parser

The Spectra Assure platform is a set of [ReversingLabs](https://www.reversinglabs.com/) solutions primarily designed for software assurance and software supply chain security use-cases.
Spectra Assure products analyze compiled software packages, their components and third-party dependencies to detect exposures, reduce vulnerabilities, and eliminate threats before reaching production.

Every Spectra Assure analysis (software scan) produces a set of reports and the overall CI status (pass or fail) for the analyzed software package.
The reports are created in multiple different formats, with different level of detail and scope of information about the analysis results.
The official documentation describes all [supported report formats](https://docs.secure.software/concepts/analysis-reports) in Spectra Assure.

**The primary purpose of this parser is extracting known vulnerabilities (CVEs) that are present in the `components` and `dependencies` sections of the `rl-json` report.**

### File Types

The parser accepts only `report.rl.json` files (the Spectra Assure [rl-json report](https://docs.secure.software/concepts/analysis-reports#rl-json)).

You can find instructions for exporting the `rl-json` report in the documentation of the Spectra Assure product you're using.

- [Spectra Assure CLI](https://docs.secure.software/cli/commands/report).
- [Spectra Assure Portal](https://docs.secure.software/api-reference/#tag/Version/operation/getVersionReport).
- [docker:rl-scanner](https://hub.docker.com/r/reversinglabs/rl-scanner).
- [docker:rl-scanner-cloud](https://hub.docker.com/r/reversinglabs/rl-scanner-cloud).


### Total Fields in Reversinglabs Spectra Assure rl-json

For the specification of the `rl-json` report, consult the official Spectra Assure documentation:

- [rl-json report schema](https://docs.secure.software/cli/rl-json-schema)
- [Analysis reports: rl-json](https://docs.secure.software/concepts/analysis-reports#rl-json).


### Field Mapping Details

#### Title

##### Component

For a component, the title includes:

- the CVE
- the type: `Component`
- the `purl` of the `Component` if present; otherwise name and version


##### Dependency

For a dependency, the title includes:

- the CVE
- the type: `Dependency`
- the `purl` of the `Dependency` if present; otherwise name and version

#### Description

##### Component

For a component, the description repeats the information from the [title](#title) and includes the SHA256 hash of the component.

The SHA256 is included because sometimes a file scan may have multiple items with the same name and version, but with different hashes.
Typically this happens with multi-language Windows installer packages.


##### Dependency

For a dependency, the description repeats the information from the [title](#title) and includes the component path, `component-name` and `component-hash`.
For duplicates, the description includes an additional line showing the title and component of each duplicate.

#### Vulnerabilities

For vulnerabilities, the following information is retrieved:

- the CVE unique ID
- CVSS version
- CVSS base score

From the CVSS base score, we map the severity into:

- Info
- Low
- Medium
- High
- Critical

If no mapping is matched, the default severity is `Info`.

##### Notes

- Currently, no endpoints are created.
- Deduplication is done with sha256 if the title.
- On detecting a duplicate dependency, we increment the number of occurrences. Components have no duplicates, so the number of occurrences is always 1.
- We extract the scan date, the Spectra Assure scanner version, and set a static scanner name.

### Sample Scan Data or Unit Tests

- [Sample Scan Data Folder](https://github.com/DefectDojo/django-DefectDojo/tree/master/unittests/scans/reversinglabs_spectraassure)

### Link To Tool

- [Spectra Assure Cli](https://docs.secure.software/cli/)
- [Spectra Assure Portal](https://docs.secure.software/portal/)
- [docker:rl-scanner](https://docs.secure.software/cli/integrations/docker-image)
- [docker:rl-scanner-cloud](https://docs.secure.software/portal/docker-image)
Empty file.
122 changes: 122 additions & 0 deletions dojo/tools/reversinglabs_spectraassure/parser.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# noqa: RUF100
import hashlib
import logging
from typing import Any

from dojo.models import Finding
from dojo.tools.reversinglabs_spectraassure.rlJsonInfo import RlJsonInfo
from dojo.tools.reversinglabs_spectraassure.rlJsonInfo.cve_info_node import CveInfoNode

logger = logging.getLogger(__name__)

SCAN_TYPE = "ReversingLabs Spectra Assure"

"""
The actual parsing is done by `RlJsonInfo` and it stores data as a collection of `CveInfoNode`
A `CveInfoNode` matches a dd.Finding more closely and makes the collection of Findings easy.

"""


class ReversinglabsSpectraassureParser:

# --------------------------------------------
# This class MUST have an empty constructor or no constructor

def _find_duplicate(self, key: str) -> Finding | None:
logger.debug("")

if key in self._duplicates:
return self._duplicates

return None

def _make_hash(
self,
data: str,
) -> str:
# Calculate SHA-256 hash
d = data.encode()
return hashlib.sha256(d).hexdigest()

def _one_finding(
self,
*,
node: CveInfoNode,
test: Any,
) -> Finding:
logger.debug("%s", node)

key = self._make_hash(node.title + " " + node.component_file_path)
cve = node.cve
finding = Finding(
date=node.scan_date,
title=node.title,
description=node.title + " " + node.description + "\n",
cve=cve,
cvssv3_score=node.score,
severity=node.score_severity,
vuln_id_from_tool=node.vuln_id_from_tool,
file_path=node.component_file_path,
component_name=node.component_name,
component_version=node.component_version,
nb_occurences=1,
hash_code=key, # sha256 on title
references=None, # future: urls
active=True, # this is the DefectDojo active field, nothing to do with node.active field
test=test,
static_finding=True,
dynamic_finding=False,
)
finding.unsaved_vulnerability_ids = [cve]
finding.unsaved_tags = node.tags
finding.impact = node.impact

return finding

# --------------------------------------------
# PUBLIC
def get_scan_types(self) -> list[str]:
return [SCAN_TYPE]

def get_label_for_scan_types(self, scan_type: str) -> str:
return scan_type

def get_description_for_scan_types(self, scan_type: str) -> str:
if scan_type == SCAN_TYPE:
return "Import the SpectraAssure report.rl.json file."
return f"Unknown Scan Type; {scan_type}"

def get_findings(
self,
file: Any,
test: Any,
) -> list[Finding]:
# ------------------------------------
rl_json_info_instance = RlJsonInfo(file_handle=file)
rl_json_info_instance.get_cve_active_all()

self._findings: list[Finding] = []
self._duplicates: dict[str, Finding] = {}

for cve_info_node_instance in rl_json_info_instance.get_results_list():
finding = self._one_finding(
node=cve_info_node_instance,
test=test,
)
if finding is None:
continue

key = finding.hash_code
if key not in self._duplicates:
self._findings.append(finding)
self._duplicates[key] = finding
continue

dup = self._duplicates[key]
if dup:
dup.description += finding.description
dup.nb_occurences += 1

# ------------------------------------
return self._findings
Loading
Loading