Skip to content

Commit 87cff15

Browse files
committed
fix(parser): support V3_FEATURE_LOCATIONS in Alert Logic parser
The Endpoint model is deprecated and raises NotImplementedError when V3_FEATURE_LOCATIONS is enabled. Build LocationData URL locations in that mode and fall back to Endpoint otherwise, matching the established parser migration pattern (e.g. Qualys VMDR). Endpoint tests now read via the get_unsaved_locations helper so they pass under both settings. Authored by T. Walker - DefectDojo
1 parent c80ca61 commit 87cff15

2 files changed

Lines changed: 34 additions & 25 deletions

File tree

dojo/tools/alertlogic/parser.py

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import csv
22
import io
33

4+
from django.conf import settings
5+
46
from dojo.models import Endpoint, Finding
7+
from dojo.tools.locations import LocationData
58

69
SEVERITY_MAPPING = {
710
"Info": "Info",
@@ -67,12 +70,11 @@ def get_findings(self, filename, test):
6770
if cve:
6871
finding.unsaved_vulnerability_ids = [cve]
6972

70-
endpoints = _build_endpoints(
73+
_add_locations(
74+
finding,
7175
row.get("IP Address"),
7276
row.get("Protocol/Port"),
7377
)
74-
if endpoints:
75-
finding.unsaved_endpoints = endpoints
7678

7779
tags = _build_tags(row)
7880
if tags:
@@ -124,22 +126,26 @@ def _parse_cvss(value):
124126
return None
125127

126128

127-
def _build_endpoints(ip_field, protoport_field):
129+
def _add_locations(finding, ip_field, protoport_field):
128130
if not ip_field:
129-
return []
131+
return
130132
protocol, port = _parse_proto_port(protoport_field)
131-
endpoints = []
132133
for raw_host in ip_field.split(","):
133134
host = raw_host.strip()
134135
if not host:
135136
continue
136-
kwargs = {"host": host}
137-
if protocol:
138-
kwargs["protocol"] = protocol
139-
if port:
140-
kwargs["port"] = port
141-
endpoints.append(Endpoint(**kwargs))
142-
return endpoints
137+
if settings.V3_FEATURE_LOCATIONS:
138+
finding.unsaved_locations.append(
139+
LocationData.url(host=host, protocol=protocol or "", port=port),
140+
)
141+
else:
142+
# TODO: Delete this after the move to Locations
143+
kwargs = {"host": host}
144+
if protocol:
145+
kwargs["protocol"] = protocol
146+
if port:
147+
kwargs["port"] = port
148+
finding.unsaved_endpoints.append(Endpoint(**kwargs))
143149

144150

145151
def _parse_proto_port(value):

unittests/tools/test_alertlogic_parser.py

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -97,36 +97,39 @@ def test_unique_id_from_tool(self):
9797
def test_endpoint_single_ipv4(self):
9898
# Row 0 has a single IPv4 address
9999
finding = self._findings("many_vulns.csv")[0]
100-
self.assertEqual(1, len(finding.unsaved_endpoints))
101-
endpoint = finding.unsaved_endpoints[0]
100+
endpoints = self.get_unsaved_locations(finding)
101+
self.assertEqual(1, len(endpoints))
102+
endpoint = endpoints[0]
102103
self.assertEqual("192.0.2.20", endpoint.host)
103104
self.assertEqual("tcp", endpoint.protocol)
104105
self.assertEqual(8080, endpoint.port)
105106

106107
def test_endpoint_multi_ipv4_and_ipv6(self):
107108
# Row 1: "198.51.100.30, fe80::250:56ff:fe96:b97"
108109
finding = self._findings("many_vulns.csv")[1]
109-
self.assertEqual(2, len(finding.unsaved_endpoints))
110-
hosts = {ep.host for ep in finding.unsaved_endpoints}
110+
endpoints = self.get_unsaved_locations(finding)
111+
self.assertEqual(2, len(endpoints))
112+
hosts = {ep.host for ep in endpoints}
111113
self.assertEqual({"198.51.100.30", "fe80::250:56ff:fe96:b97"}, hosts)
112114

113115
def test_endpoint_ipv6_only(self):
114116
# Row 6 has IPv6-only address
115117
finding = self._findings("many_vulns.csv")[6]
116-
self.assertEqual(1, len(finding.unsaved_endpoints))
117-
self.assertEqual("2001:db8::1:80", finding.unsaved_endpoints[0].host)
118+
endpoints = self.get_unsaved_locations(finding)
119+
self.assertEqual(1, len(endpoints))
120+
self.assertEqual("2001:db8::1:80", endpoints[0].host)
118121

119122
def test_endpoint_port_zero_is_omitted(self):
120123
# Row 2 has Protocol/Port "TCP/0" — port should not be set
121124
finding = self._findings("many_vulns.csv")[2]
122-
self.assertEqual(1, len(finding.unsaved_endpoints))
123-
self.assertIsNone(finding.unsaved_endpoints[0].port)
125+
endpoints = self.get_unsaved_locations(finding)
126+
self.assertEqual(1, len(endpoints))
127+
self.assertIsNone(endpoints[0].port)
124128

125129
def test_endpoint_clean_succeeds(self):
126-
# Hard guardrail: every endpoint must pass clean()
127-
for finding in self._findings("many_vulns.csv"):
128-
for endpoint in finding.unsaved_endpoints or []:
129-
endpoint.clean()
130+
# Hard guardrail: every endpoint/location must pass clean()
131+
# (get_unsaved_locations cleans each entry internally)
132+
self.validate_locations(self._findings("many_vulns.csv"))
130133

131134
def test_cve_present(self):
132135
# Row 0 has CVE-2021-44228 (Log4Shell)

0 commit comments

Comments
 (0)