Skip to content

Jira webhook: stop mis-mitigating findings on non-"done" issues#14716

Open
paulOsinski wants to merge 6 commits intoDefectDojo:bugfixfrom
paulOsinski:jira-racecondition
Open

Jira webhook: stop mis-mitigating findings on non-"done" issues#14716
paulOsinski wants to merge 6 commits intoDefectDojo:bugfixfrom
paulOsinski:jira-racecondition

Conversation

@paulOsinski
Copy link
Copy Markdown
Contributor

@paulOsinski paulOsinski commented Apr 21, 2026

users see findings auto-mitigated immediately after reopening via
either the UI or API. Looking at finding pghistory we see the pattern:

12:32:48 active=True is_mitigated=False source=None ← user reopens
12:32:51 active=False is_mitigated=True source=jira_webhook ← ricochet

mitigated_by is always the system "JIRA" user, set only from one place:
process_resolution_from_jira's "Mitigated by default" branch.

Root cause

Two independent issues compound:

  1. Self-inflicted race in update_jira_issue. When DefectDojo
    pushes an update to a linked Jira issue, it does
    issue.update(...) first (priority, description, labels) and then
    push_status_to_jira(...) (the transition). Each API call fires its
    own jira:issue_updated webhook. The first webhook, fired by
    issue.update, sees the pre-transition state - for a reopen, that
    means the issue is still resolved from the previous close. Our
    webhook handler then mitigates the linked finding. The second
    webhook, post-transition, would try to reopen the finding, but for
    grouped findings that reopen is (deliberately) gated behind
    DD_JIRA_WEBHOOK_ALLOW_FINDING_GROUP_REOPEN=False, so the ricochet
    is irreversible.

  2. Fragile "resolved" check in the webhook handler. The handler
    treated any non-null resolution as "the Jira issue is closed",
    which also mis-fires for Jira configurations that set a default
    resolution on open issues ("Unresolved"), or workflows whose Reopen
    transition does not clear the resolution field.

Fix

  1. Reorder update_jira_issue so the status transition runs before
    other field updates. Webhooks fired during our own sync now see a
    consistent post-transition state.
  2. In process_resolution_from_jira, require both resolution AND
    statusCategory.key == "done" before mitigating. Extract the
    statusCategory from the webhook payload in webhook() and pass it
    through.

Tests

Three new tests covering status categories new, indeterminate, and
done, all with a non-null resolution value - regression-locking the
guard against the "open but resolved" state.

Backward compatibility

status_category_key is a keyword-only optional argument on
process_resolution_from_jira. When not supplied, behavior is
identical to before the change.

The two PRs address mirror-image failure modes of the same underlying problem (resolution is an unreliable signal; statusCategory is canonical):

The two PRs touch disjoint functions in helper.py and should merge without conflict in either order. Neither subsumes the other: #14611 alone leaves the webhook ricochet in this PR's summary intact; this PR alone leaves the "Jira hides resolution field" setups in #14347 still broken.

@paulOsinski paulOsinski changed the base branch from master to bugfix April 21, 2026 20:08
@dryrunsecurity
Copy link
Copy Markdown

dryrunsecurity Bot commented Apr 21, 2026

DryRun Security

This pull request modifies sensitive files under dojo/jira_link (helper.py and views.py), triggering multiple "Configured Codepaths Edit" errors indicating edits to protected paths; reviewers should verify the changes and update .dryrunsecurity.yaml if these authors/edits are intended.

🔴 Configured Codepaths Edit in dojo/jira_link/helper.py (drs_c487c9d0)
Vulnerability Configured Codepaths Edit
Description Sensitive edits detected for this file. Sensitive file paths and allowed authors can be configured in .dryrunsecurity.yaml.
🔴 Configured Codepaths Edit in dojo/jira_link/views.py (drs_710cd8f5)
Vulnerability Configured Codepaths Edit
Description Sensitive edits detected for this file. Sensitive file paths and allowed authors can be configured in .dryrunsecurity.yaml.
🔴 Configured Codepaths Edit in dojo/jira_link/helper.py (drs_392d9117)
Vulnerability Configured Codepaths Edit
Description Sensitive edits detected for this file. Sensitive file paths and allowed authors can be configured in .dryrunsecurity.yaml.
🔴 Configured Codepaths Edit in dojo/jira_link/helper.py (drs_ab0df7f6)
Vulnerability Configured Codepaths Edit
Description Sensitive edits detected for this file. Sensitive file paths and allowed authors can be configured in .dryrunsecurity.yaml.

We've notified @mtesauro.


Comment to provide feedback on these findings.

Report false positive: @dryrunsecurity fp [FINDING ID] [FEEDBACK]
Report low-impact: @dryrunsecurity nit [FINDING ID] [FEEDBACK]

Example: @dryrunsecurity fp drs_90eda195 This code is not user-facing

All finding details can be found in the DryRun Security Dashboard.

Copy link
Copy Markdown
Member

@valentijnscholten valentijnscholten left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes sesnse. Can you look at #14611? I think the statusCategory itself could be used to determine the state, even if there is no resolution.

Comment thread dojo/jira_link/helper.py Outdated
paulOsinski and others added 2 commits April 22, 2026 16:42
Co-authored-by: valentijnscholten <valentijnscholten@gmail.com>
@paulOsinski
Copy link
Copy Markdown
Contributor Author

@valentijnscholten to fix ruff:

  • dropped the backward-compat if status_category_key is None branch entirely
  • updated the only other caller of process_resolution_from_jira (the jira_status_reconciliation management command) to extract and pass status_category_key alongside the resolution fields, so every caller is on the statusCategory-based path

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants