Skip to content

🎉 Add Xeol parser #12816 #12846

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: bugfix
Choose a base branch
from
Open
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
19 changes: 19 additions & 0 deletions docs/content/en/connecting_your_tools/parsers/file/xeol.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
title: "Xeol Parser"
toc_hide: true
---
Import JSON reports of Xeolscans.

### Parser
You can find the parser [here](https://github.com/xeol-io/xeol).

### Severity
The severity of a EOL detected findings is as follows:
- Critical: The component is already 8 weeks end of life
- High: The component is already 6 weeks end of life
- Medium: The component is already 4 weeks end of life
- Low: The component is already 2 weeks end of life
- Info: The component is not yet end of life, but was included in the Xeol report

### Sample Scan Data
Sample kube-bench Scanner scans can be found [here](https://github.com/DefectDojo/django-DefectDojo/tree/master/unittests/scans/xeol).
1 change: 1 addition & 0 deletions dojo/tools/xeol/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
__author__ = "manuel-sommer"
95 changes: 95 additions & 0 deletions dojo/tools/xeol/parser.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import json
from datetime import datetime, timedelta

from dojo.models import Finding


class XeolParser:
def get_scan_types(self):
return ["Xeol Parser"]

def get_label_for_scan_types(self, scan_type):
return "Xeol Parser"

def get_description_for_scan_types(self, scan_type):
return "Import JSON report"

def get_findings(self, file, test):
findings = []
data = json.load(file)

if not isinstance(data, dict) or "matches" not in data:
return findings

for match in data["matches"]:
cycle = match.get("Cycle", {})
artifact = match.get("artifact", {})

title = f"{cycle.get('ProductName', 'Unknown Product')} EOL Information"

description_lines = [
f"**Product Name:** {cycle.get('ProductName', 'N/A')}",
f"**Release Cycle:** {cycle.get('ReleaseCycle', 'N/A')}",
f"**EOL Date:** {cycle.get('Eol', 'N/A')}",
f"**Latest Release Date:** {cycle.get('LatestReleaseDate', 'N/A')}",
f"**Release Date:** {cycle.get('ReleaseDate', 'N/A')}",
f"**Artifact Name:** {artifact.get('name', 'N/A')}",
f"**Artifact Version:** {artifact.get('version', 'N/A')}",
f"**Artifact Type:** {artifact.get('type', 'N/A')}",
f"**Licenses:** {', '.join(artifact.get('licenses', [])) if artifact.get('licenses') else 'N/A'}",
f"**Package URL:** {artifact.get('purl', 'N/A')}",
f"**CPEs:** {', '.join(artifact.get('cpes', [])) if artifact.get('cpes') else 'N/A'}",
]

locations = artifact.get("locations", [])
if locations:
location_info = [
f"Path: {loc.get('path', '')}, LayerID: {loc.get('layerID', '')}"
for loc in locations
]
description_lines.append("**Locations:**\n" + "\n".join(location_info))

metadata = artifact.get("metadata", {})
if isinstance(metadata, dict) and "files" in metadata:
file_paths = [f.get("path", "") for f in metadata["files"] if "path" in f]
if file_paths:
description_lines.append("**Files:**\n" + "\n".join(file_paths))

description = "\n".join(description_lines)

# Determine severity based on EOL date
severity = "Info"
eol_str = cycle.get("Eol", "")
try:
eol_date = datetime.strptime(eol_str, "%Y-%m-%d")
now = datetime.now()
if eol_date < now:
delta = now - eol_date
if delta <= timedelta(weeks=2):
severity = "Low"
elif delta <= timedelta(weeks=4):
severity = "Medium"
elif delta <= timedelta(weeks=6):
severity = "High"
else:
severity = "Critical"
except Exception:
severity = "Info"

finding = Finding(
title=title,
test=test,
severity=severity,
description=description,
component_name=artifact.get("name", ""),
component_version=artifact.get("version", ""),
static_finding=True,
dynamic_finding=False,
nb_occurences=1,
cwe=672,
references=cycle.get("ProductPermalink", "") + "\n[www.xeol.io/explorer](https://www.xeol.io/explorer)",
)

findings.append(finding)

return findings
Loading