Skip to content

Commit 08b9a60

Browse files
paulOsinskiMaffooch
authored andcommitted
fix ruff
1 parent 9cd9f2d commit 08b9a60

2 files changed

Lines changed: 33 additions & 15 deletions

File tree

dojo/jira/helper.py

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1911,12 +1911,14 @@ def process_resolution_from_jira(
19111911
"""Processes the resolution field in the JIRA issue and updated the finding in Defect Dojo accordingly"""
19121912
import dojo.risk_acceptance.helper as ra_helper # noqa: PLC0415 import error
19131913
status_changed = False
1914-
# A Jira issue is treated as "resolved" (i.e. the linked finding should be
1915-
# mitigated / risk-accepted / false-positive'd) only when BOTH a non-null
1916-
# resolution is present AND the issue's statusCategory is "done". Jira's
1917-
# statusCategory.key is the canonical closure signal (always one of
1918-
# "new", "indeterminate", "done"), and checking it alongside the
1919-
# resolution field prevents several real-world bugs:
1914+
# A Jira issue is treated as "resolved" (the linked finding should be
1915+
# mitigated / risk-accepted / false-positive'd) when the issue's
1916+
# statusCategory.key is "done". Jira's statusCategory is the canonical
1917+
# closure signal (one of "new", "indeterminate", "done", "undefined"),
1918+
# always returned by the API, and does not depend on per-workflow
1919+
# resolution-field hygiene.
1920+
#
1921+
# Relying on statusCategory prevents real-world bugs:
19201922
# 1. Workflows where reopen transitions do not clear the resolution -
19211923
# the issue ends up in an "open but resolved" state and every
19221924
# webhook event for the issue would otherwise mis-mitigate the
@@ -1929,14 +1931,11 @@ def process_resolution_from_jira(
19291931
# and the first webhook sees the pre-transition (still-resolved)
19301932
# state even though the intended final state is reopened.
19311933
#
1932-
# status_category_key is keyword-only and optional to preserve backward
1933-
# compatibility with any caller that has not yet been updated to extract
1934-
# it from the webhook payload; when it is None we fall back to the
1935-
# historical resolution-only behavior.
1936-
if status_category_key is None:
1937-
resolved = resolution_id is not None
1938-
else:
1939-
resolved = status_category_key == "done"
1934+
# The resolution value (when present) is still used downstream to
1935+
# classify "done" issues as risk-accepted, false-positive, or the
1936+
# default mitigated category (see jira_instance.accepted_resolutions
1937+
# and .false_positive_resolutions below).
1938+
resolved = status_category_key == "done"
19401939
jira_instance = get_jira_instance(finding)
19411940

19421941
if resolved:

dojo/management/commands/jira_status_reconciliation.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,13 @@ def _reconcile_findings(mode, product_obj, engagement_obj, timestamp, dryrun, me
102102
resolution = issue_from_jira.fields.resolution if issue_from_jira.fields.resolution and issue_from_jira.fields.resolution != "None" else None
103103
resolution_id = resolution.id if resolution else None
104104
resolution_name = resolution.name if resolution else None
105+
# statusCategory.key is the canonical "is this issue done" signal
106+
# that process_resolution_from_jira uses to decide whether to mitigate.
107+
status_category_key = getattr(
108+
getattr(getattr(issue_from_jira.fields, "status", None), "statusCategory", None),
109+
"key",
110+
None,
111+
)
105112

106113
# convert from str to datetime
107114
issue_from_jira.fields.updated = parse_datetime(issue_from_jira.fields.updated)
@@ -175,7 +182,11 @@ def _reconcile_findings(mode, product_obj, engagement_obj, timestamp, dryrun, me
175182
if action == "import_status_from_jira":
176183
message_action = "deactivating" if find.active else "reactivating"
177184

178-
status_changed = jira_helper.process_resolution_from_jira(find, resolution_id, resolution_name, assignee_name, issue_from_jira.fields.updated, find.jira_issue) if not dryrun else "dryrun"
185+
status_changed = jira_helper.process_resolution_from_jira(
186+
find, resolution_id, resolution_name, assignee_name,
187+
issue_from_jira.fields.updated, find.jira_issue,
188+
status_category_key=status_category_key,
189+
) if not dryrun else "dryrun"
179190
if status_changed:
180191
message = f"{find.jira_issue.jira_key}; {settings.SITE_URL}/finding/{find.id};{find.status()};{resolution_name};{flag1};{flag2};{flag3};{find.jira_issue.jira_change};{issue_from_jira.fields.updated};{find.last_status_update};{issue_from_jira.fields.updated};{find.last_reviewed};{issue_from_jira.fields.updated};{message_action} finding in defectdojo;{status_changed}"
181192
messages.append(message)
@@ -264,6 +275,13 @@ def _reconcile_finding_groups(mode, product_obj, engagement_obj, timestamp, dryr
264275
resolution = issue_from_jira.fields.resolution if issue_from_jira.fields.resolution and issue_from_jira.fields.resolution != "None" else None
265276
resolution_id = resolution.id if resolution else None
266277
resolution_name = resolution.name if resolution else None
278+
# statusCategory.key is the canonical "is this issue done" signal
279+
# that process_resolution_from_jira uses to decide whether to mitigate.
280+
status_category_key = getattr(
281+
getattr(getattr(issue_from_jira.fields, "status", None), "statusCategory", None),
282+
"key",
283+
None,
284+
)
267285

268286
# convert from str to datetime
269287
issue_from_jira.fields.updated = parse_datetime(issue_from_jira.fields.updated)
@@ -335,6 +353,7 @@ def _reconcile_finding_groups(mode, product_obj, engagement_obj, timestamp, dryr
335353
find, resolution_id, resolution_name, assignee_name,
336354
issue_from_jira.fields.updated, finding_group.jira_issue,
337355
finding_group=finding_group,
356+
status_category_key=status_category_key,
338357
)
339358
else:
340359
status_changed = "dryrun"

0 commit comments

Comments
 (0)