Skip to content

Commit 5efaa30

Browse files
committed
Ruff: Add and fix RUF015
1 parent f95315d commit 5efaa30

File tree

16 files changed

+64
-49
lines changed

16 files changed

+64
-49
lines changed

dojo/reports/widgets.py

Lines changed: 30 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
)
2020
from dojo.forms import CustomReportOptionsForm
2121
from dojo.models import Endpoint, Finding
22-
from dojo.utils import get_page_items, get_system_setting, get_words_for_field
22+
from dojo.utils import first_elem, get_page_items, get_system_setting, get_words_for_field
2323

2424
"""
2525
Widgets are content sections that can be included on reports. The report builder will allow any number of widgets
@@ -371,10 +371,12 @@ def report_widget_factory(json_data=None, request=None, user=None, *, finding_no
371371
widgets = json.loads(json_data)
372372

373373
for idx, widget in enumerate(widgets):
374-
if list(widget.keys())[0] == "page-break":
375-
selected_widgets[list(widget.keys())[0] + "-" + str(idx)] = PageBreak()
374+
first_widget_keys = first_elem(widget.keys())
376375

377-
if list(widget.keys())[0] == "endpoint-list":
376+
if first_widget_keys == "page-break":
377+
selected_widgets[first_widget_keys + "-" + str(idx)] = PageBreak()
378+
379+
if first_widget_keys == "endpoint-list":
378380
endpoints = Endpoint.objects.filter(finding__active=True,
379381
finding__false_p=False,
380382
finding__duplicate=False,
@@ -386,7 +388,7 @@ def report_widget_factory(json_data=None, request=None, user=None, *, finding_no
386388
endpoints = endpoints.distinct()
387389

388390
d = QueryDict(mutable=True)
389-
for item in widget.get(list(widget.keys())[0]):
391+
for item in widget.get(first_widget_keys):
390392
if item["name"] in d:
391393
d.appendlist(item["name"], item["value"])
392394
else:
@@ -400,12 +402,12 @@ def report_widget_factory(json_data=None, request=None, user=None, *, finding_no
400402
endpoints = EndpointList(request=request, endpoints=endpoints, finding_notes=finding_notes,
401403
finding_images=finding_images, host=host, user_id=user_id)
402404

403-
selected_widgets[list(widget.keys())[0] + "-" + str(idx)] = endpoints
405+
selected_widgets[first_widget_keys + "-" + str(idx)] = endpoints
404406

405-
if list(widget.keys())[0] == "finding-list":
407+
if first_widget_keys == "finding-list":
406408
findings = Finding.objects.all()
407409
d = QueryDict(mutable=True)
408-
for item in widget.get(list(widget.keys())[0]):
410+
for item in widget.get(first_widget_keys):
409411
if item["name"] in d:
410412
d.appendlist(item["name"], item["value"])
411413
else:
@@ -414,47 +416,47 @@ def report_widget_factory(json_data=None, request=None, user=None, *, finding_no
414416
filter_class = ReportFindingFilterWithoutObjectLookups if filter_string_matching else ReportFindingFilter
415417
findings = filter_class(d, queryset=findings)
416418
user_id = user.id if user is not None else None
417-
selected_widgets[list(widget.keys())[0] + "-" + str(idx)] = FindingList(request=request, findings=findings,
419+
selected_widgets[first_widget_keys + "-" + str(idx)] = FindingList(request=request, findings=findings,
418420
finding_notes=finding_notes,
419421
finding_images=finding_images,
420422
host=host, user_id=user_id)
421423

422-
if list(widget.keys())[0] == "custom-content":
424+
if first_widget_keys == "custom-content":
423425
wysiwyg_content = WYSIWYGContent(request=request)
424426
wysiwyg_content.heading = \
425-
next((item for item in widget.get(list(widget.keys())[0]) if item["name"] == "heading"), None)["value"]
427+
next((item for item in widget.get(first_widget_keys) if item["name"] == "heading"), None)["value"]
426428
wysiwyg_content.content = \
427-
next((item for item in widget.get(list(widget.keys())[0]) if item["name"] == "hidden_content"), None)["value"]
429+
next((item for item in widget.get(first_widget_keys) if item["name"] == "hidden_content"), None)["value"]
428430
wysiwyg_content.page_break_after = \
429-
next((item for item in widget.get(list(widget.keys())[0]) if item["name"] == "page_break_after"),
431+
next((item for item in widget.get(first_widget_keys) if item["name"] == "page_break_after"),
430432
{"value": False})["value"]
431-
selected_widgets[list(widget.keys())[0] + "-" + str(idx)] = wysiwyg_content
432-
if list(widget.keys())[0] == "report-options":
433+
selected_widgets[first_widget_keys + "-" + str(idx)] = wysiwyg_content
434+
if first_widget_keys == "report-options":
433435
options = ReportOptions(request=request)
434436
options.include_finding_notes = \
435-
next((item for item in widget.get(list(widget.keys())[0]) if item["name"] == "include_finding_notes"), None)[
437+
next((item for item in widget.get(first_widget_keys) if item["name"] == "include_finding_notes"), None)[
436438
"value"]
437439
options.include_finding_images = \
438-
next((item for item in widget.get(list(widget.keys())[0]) if item["name"] == "include_finding_images"), None)[
440+
next((item for item in widget.get(first_widget_keys) if item["name"] == "include_finding_images"), None)[
439441
"value"]
440442
options.report_type = \
441-
next((item for item in widget.get(list(widget.keys())[0]) if item["name"] == "report_type"), None)["value"]
443+
next((item for item in widget.get(first_widget_keys) if item["name"] == "report_type"), None)["value"]
442444
options.report_name = \
443-
next((item for item in widget.get(list(widget.keys())[0]) if item["name"] == "report_name"), None)["value"]
444-
selected_widgets[list(widget.keys())[0]] = options
445-
if list(widget.keys())[0] == "table-of-contents":
445+
next((item for item in widget.get(first_widget_keys) if item["name"] == "report_name"), None)["value"]
446+
selected_widgets[first_widget_keys] = options
447+
if first_widget_keys == "table-of-contents":
446448
toc = TableOfContents(request=request)
447-
toc.heading = next((item for item in widget.get(list(widget.keys())[0]) if item["name"] == "heading"), None)[
449+
toc.heading = next((item for item in widget.get(first_widget_keys) if item["name"] == "heading"), None)[
448450
"value"]
449-
selected_widgets[list(widget.keys())[0]] = toc
450-
if list(widget.keys())[0] == "cover-page":
451+
selected_widgets[first_widget_keys] = toc
452+
if first_widget_keys == "cover-page":
451453
cover_page = CoverPage(request=request)
452-
cover_page.heading = next((item for item in widget.get(list(widget.keys())[0]) if item["name"] == "heading"), None)[
454+
cover_page.heading = next((item for item in widget.get(first_widget_keys) if item["name"] == "heading"), None)[
453455
"value"]
454456
cover_page.sub_heading = \
455-
next((item for item in widget.get(list(widget.keys())[0]) if item["name"] == "sub_heading"), None)["value"]
457+
next((item for item in widget.get(first_widget_keys) if item["name"] == "sub_heading"), None)["value"]
456458
cover_page.meta_info = \
457-
next((item for item in widget.get(list(widget.keys())[0]) if item["name"] == "meta_info"), None)["value"]
458-
selected_widgets[list(widget.keys())[0]] = cover_page
459+
next((item for item in widget.get(first_widget_keys) if item["name"] == "meta_info"), None)["value"]
460+
selected_widgets[first_widget_keys] = cover_page
459461

460462
return selected_widgets

dojo/tools/api_cobalt/api_client.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import requests
22
from django.conf import settings
33

4+
from dojo.utils import first_elem
5+
46

57
class CobaltAPI:
68

@@ -90,7 +92,7 @@ def test_connection(self):
9092
orgs = filter(
9193
lambda org: org["resource"]["token"] == self.org_token, data,
9294
)
93-
org = list(orgs)[0]
95+
org = first_elem(orgs)
9496
org_name = org["resource"]["name"]
9597
return f'You have access to the "{org_name}" organization'
9698
msg = (

dojo/tools/burp_enterprise/parser.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from lxml import etree, html
55

66
from dojo.models import Endpoint, Finding
7+
from dojo.utils import first_elem
78

89
logger = logging.getLogger(__name__)
910

@@ -117,7 +118,7 @@ def _get_content(self, container: etree.Element):
117118
if stripped_text is not None:
118119
value += stripped_text + "\n"
119120
elif stripped_text.isspace():
120-
value = list(elem.itertext())[0]
121+
value = first_elem(elem.itertext())
121122
elif elem.tag == "div" or elem.tag == "span":
122123
value = elem.text_content().strip().replace("\n", "") + "\n"
123124
else:

dojo/tools/hadolint/parser.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ def get_items(self, tree, test):
3030
)
3131
items[unique_key] = item
3232

33-
return items.values()
33+
return list(items.values())
3434

3535

3636
def get_item(vulnerability, test):

dojo/tools/harbor_vulnerability/parser.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import json
33

44
from dojo.models import Finding
5+
from dojo.utils import first_elem
56

67

78
class HarborVulnerabilityParser:
@@ -32,7 +33,7 @@ def get_findings(self, filename, test):
3233
vulnerability = data["vulnerabilities"]
3334
# To be compatible with update in version
3435
with contextlib.suppress(KeyError, StopIteration, TypeError):
35-
vulnerability = data[next(iter(data.keys()))]["vulnerabilities"]
36+
vulnerability = data[first_elem(data.keys())]["vulnerabilities"]
3637

3738
# Early exit if empty
3839
if "vulnerability" not in locals() or vulnerability is None:

dojo/tools/sarif/parser.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
from dojo.models import Finding
1010
from dojo.tools.parser_test import ParserTest
11+
from dojo.utils import first_elem
1112

1213
logger = logging.getLogger(__name__)
1314

@@ -460,7 +461,7 @@ def get_items_from_result(result, rules, artifacts, run_date):
460461
# compare it
461462
if result.get("fingerprints"):
462463
hashes = get_fingerprints_hashes(result["fingerprints"])
463-
first_item = next(iter(hashes.items()))
464+
first_item = first_elem(hashes.items())
464465
finding.unique_id_from_tool = first_item[1]["value"]
465466
elif result.get("partialFingerprints"):
466467
# for this one we keep an order to have id that could be compared

dojo/tools/sonarqube/soprasteria_html.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import logging
22

33
from dojo.tools.sonarqube.soprasteria_helper import SonarQubeSoprasteriaHelper
4+
from dojo.utils import first_elem
45

56
logger = logging.getLogger(__name__)
67

@@ -23,13 +24,13 @@ def get_items(self, tree, test, mode):
2324
rulesDic = {}
2425
for rule in rules_table:
2526
rule_properties = list(rule.iter("td"))
26-
rule_name = list(rule_properties[0].iter("a"))[0].text.strip()
27-
rule_details = list(rule_properties[1].iter("details"))[0]
27+
rule_name = first_elem(rule_properties[0].iter("a")).text.strip()
28+
rule_details = first_elem(rule_properties[1].iter("details"))
2829
rulesDic[rule_name] = rule_details
2930

3031
for vuln in vulnerabilities_table:
3132
vuln_properties = list(vuln.iter("td"))
32-
rule_key = list(vuln_properties[0].iter("a"))[0].text
33+
rule_key = first_elem(vuln_properties[0].iter("a")).text
3334
vuln_rule_name = rule_key and rule_key.strip()
3435
vuln_severity = SonarQubeSoprasteriaHelper().convert_sonar_severity(
3536
vuln_properties[1].text and vuln_properties[1].text.strip(),

dojo/tools/trufflehog/parser.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import json
33

44
from dojo.models import Finding
5+
from dojo.utils import first_elem
56

67

78
class TruffleHogParser:
@@ -112,7 +113,7 @@ def get_findings_v3(self, data, test):
112113
source = {}
113114
source_data = {}
114115
if metadata:
115-
source = list(metadata.keys())[0]
116+
source = first_elem(metadata.keys())
116117
source_data = metadata.get(source)
117118

118119
file = source_data.get("file", "")

dojo/tools/veracode_sca/parser.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from django.utils import timezone
1010

1111
from dojo.models import Finding
12+
from dojo.utils import first_elem
1213

1314

1415
class VeracodeScaParser:
@@ -159,7 +160,7 @@ def get_findings_csv(self, file, test):
159160
issueId = row.get("Issue ID", None)
160161
if not issueId:
161162
# Workaround for possible encoding issue
162-
issueId = list(row.values())[0]
163+
issueId = first_elem(row.values())
163164
library = row.get("Library", None)
164165
if row.get("Package manager") == "MAVEN" and row.get(
165166
"Coordinate 2",

dojo/utils.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ def match_finding_to_existing_findings(finding, product=None, engagement=None, t
176176

177177
deduplicationLogger.debug(
178178
"Matching finding %i:%s to existing findings in %s %s using %s as deduplication algorithm.",
179-
finding.id, finding.title, custom_filter_type, list(custom_filter.values())[0], deduplication_algorithm,
179+
finding.id, finding.title, custom_filter_type, first_elem(custom_filter.values()), deduplication_algorithm,
180180
)
181181

182182
if deduplication_algorithm == "hash_code":
@@ -2701,3 +2701,9 @@ def generate_file_response_from_file_path(
27012701
response["Content-Disposition"] = f'attachment; filename="{full_file_name}"'
27022702
response["Content-Length"] = file_size
27032703
return response
2704+
2705+
2706+
def first_elem(x):
2707+
# This function is workaround for using of `list(...)[0]`.
2708+
# RUF015 recommends to use `next(iter(x))` but it is harder for reading in regular code
2709+
return next(iter(x))

ruff.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,6 @@ ignore = [
9797
"SIM102",
9898
"SIM115",
9999
"RUF012",
100-
"RUF015",
101100
"D205",
102101
"FIX002", # TODOs need some love but we will probably not get of them
103102
"D211", # `one-blank-line-before-class` (D203) and `no-blank-line-before-class` (D211) are incompatible.

tests/import_scanner_test.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
from selenium.webdriver.common.by import By
1414
from selenium.webdriver.support.ui import Select
1515

16+
from dojo.utils import first_elem
17+
1618
dir_path = Path(os.path.realpath(__file__)).parent
1719

1820
logger = logging.getLogger(__name__)
@@ -171,7 +173,7 @@ def test_engagement_import_scan_result(self):
171173
found_matches[index] = matches[0]
172174

173175
if len(found_matches) == 1:
174-
index = list(found_matches.keys())[0]
176+
index = first_elem(found_matches.keys())
175177
scan_map[test] = options_text[index]
176178
elif len(found_matches) > 1:
177179
index = list(found_matches.values()).index(temp_test)

unittests/tools/test_blackduck_parser.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ def test_blackduck_csv_parser_has_many_findings(self):
2222
parser = BlackduckParser()
2323
findings = parser.get_findings(testfile, Test())
2424
self.assertEqual(24, len(findings))
25-
findings = list(findings)
2625
self.assertEqual(1, len(findings[10].unsaved_vulnerability_ids))
2726
self.assertEqual("CVE-2007-3386", findings[10].unsaved_vulnerability_ids[0])
2827
self.assertEqual(findings[4].component_name, "Apache Tomcat")
@@ -34,7 +33,6 @@ def test_blackduck_csv_parser_new_format_has_many_findings(self):
3433
testfile = get_unit_tests_scans_path("blackduck") / "many_vulns_new_format.csv"
3534
parser = BlackduckParser()
3635
findings = parser.get_findings(testfile, Test())
37-
findings = list(findings)
3836
self.assertEqual(9, len(findings))
3937
self.assertEqual(findings[0].component_name, "kryo")
4038
self.assertEqual(findings[2].component_name, "jackson-databind")

unittests/tools/test_hadolint_parser.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ def test_parse_file_with_one_dockerfile(self):
1111
findings = parser.get_findings(testfile, Test())
1212
testfile.close()
1313
self.assertEqual(4, len(findings))
14-
finding = list(findings)[0]
14+
finding = findings[0]
1515
self.assertEqual(finding.line, 9)
1616
self.assertEqual(finding.file_path, "django-DefectDojo\\Dockerfile.django")
1717

unittests/tools/test_intsights_parser.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ def test_intsights_parser_with_one_critical_vuln_has_one_findings_json(
1212

1313
self.assertEqual(1, len(findings))
1414

15-
finding = list(findings)[0]
15+
finding = findings[0]
1616

1717
self.assertEqual(
1818
"5c80dbf83b4a3900078b6be6",
@@ -32,7 +32,7 @@ def test_intsights_parser_with_one_critical_vuln_has_one_findings_csv(
3232
findings = parser.get_findings(testfile, Test())
3333
self.assertEqual(1, len(findings))
3434

35-
finding = list(findings)[0]
35+
finding = findings[0]
3636

3737
self.assertEqual(
3838
"mn7xy83finmmth4ja363rci9",

unittests/tools/test_mend_parser.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ def test_parse_file_with_one_vuln_has_one_findings(self):
1616
parser = MendParser()
1717
findings = parser.get_findings(testfile, Test())
1818
self.assertEqual(1, len(findings))
19-
finding = list(findings)[0]
19+
finding = findings[0]
2020
self.assertEqual(1, len(finding.unsaved_vulnerability_ids))
2121
self.assertEqual("CVE-2019-9658", finding.unsaved_vulnerability_ids[0])
2222
self.assertEqual("CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N", finding.cvssv3)
@@ -41,7 +41,7 @@ def test_parse_file_with_one_sca_vuln_finding(self):
4141
parser = MendParser()
4242
findings = parser.get_findings(testfile, Test())
4343
self.assertEqual(1, len(findings))
44-
finding = list(findings)[0]
44+
finding = findings[0]
4545
self.assertEqual("**Locations Found**: D:\\MendRepo\\test-product\\test-project\\test-project-subcomponent\\path\\to\\the\\Java\\commons-codec-1.6_donotuse.jar", finding.steps_to_reproduce)
4646
self.assertEqual("WS-2019-0379 | commons-codec-1.6.jar", finding.title)
4747

@@ -56,7 +56,7 @@ def test_parse_file_with_one_vuln_has_one_findings_platform(self):
5656
parser = MendParser()
5757
findings = parser.get_findings(testfile, Test())
5858
self.assertEqual(1, len(findings))
59-
finding = list(findings)[0]
59+
finding = findings[0]
6060
self.assertEqual(1, len(finding.unsaved_vulnerability_ids))
6161
self.assertEqual("CVE-2024-51744", finding.unsaved_vulnerability_ids[0])
6262
self.assertEqual("CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:L/I:N/A:N", finding.cvssv3)

0 commit comments

Comments
 (0)