11import logging
2+ from contextlib import suppress
23
34from dateutil .relativedelta import relativedelta
45from django .core .exceptions import PermissionDenied
89import dojo .jira_link .helper as jira_helper
910from dojo .celery import app
1011from dojo .jira_link .helper import escape_for_jira
11- from dojo .models import Finding , Risk_Acceptance , System_Settings
12+ from dojo .models import Dojo_User , Finding , Notes , Risk_Acceptance , System_Settings
1213from dojo .notifications .helper import create_notification
1314from dojo .utils import get_full_url , get_system_setting
1415
@@ -102,7 +103,7 @@ def delete(eng, risk_acceptance):
102103 risk_acceptance .delete ()
103104
104105
105- def remove_finding_from_risk_acceptance (risk_acceptance , finding ) :
106+ def remove_finding_from_risk_acceptance (user : Dojo_User , risk_acceptance : Risk_Acceptance , finding : Finding ) -> None :
106107 logger .debug ("removing finding %i from risk acceptance %i" , finding .id , risk_acceptance .id )
107108 risk_acceptance .accepted_findings .remove (finding )
108109 finding .active = True
@@ -112,9 +113,20 @@ def remove_finding_from_risk_acceptance(risk_acceptance, finding):
112113 finding .save (dedupe_option = False )
113114 # best effort jira integration, no status changes
114115 post_jira_comments (risk_acceptance , [finding ], unaccepted_message_creator )
116+ # Add a note to reflect that the finding was removed from the risk acceptance
117+ if user is not None :
118+ finding .notes .add (Notes .objects .create (
119+ entry = (
120+ f"{ Dojo_User .generate_full_name (user )} ({ user .id } ) removed this finding from the risk acceptance: "
121+ f'"{ risk_acceptance .name } " ({ get_view_risk_acceptance (risk_acceptance )} )'
122+ ),
123+ author = user ,
124+ ))
115125
126+ return None
116127
117- def add_findings_to_risk_acceptance (risk_acceptance , findings ):
128+
129+ def add_findings_to_risk_acceptance (user : Dojo_User , risk_acceptance : Risk_Acceptance , findings : list [Finding ]) -> None :
118130 for finding in findings :
119131 if not finding .duplicate or finding .risk_accepted :
120132 finding .active = False
@@ -123,11 +135,21 @@ def add_findings_to_risk_acceptance(risk_acceptance, findings):
123135 # Update any endpoint statuses on each of the findings
124136 update_endpoint_statuses (finding , accept_risk = True )
125137 risk_acceptance .accepted_findings .add (finding )
138+ # Add a note to reflect that the finding was removed from the risk acceptance
139+ if user is not None :
140+ finding .notes .add (Notes .objects .create (
141+ entry = (
142+ f"{ Dojo_User .generate_full_name (user )} ({ user .id } ) added this finding to the risk acceptance: "
143+ f'"{ risk_acceptance .name } " ({ get_view_risk_acceptance (risk_acceptance )} )'
144+ ),
145+ author = user ,
146+ ))
126147 risk_acceptance .save ()
127-
128148 # best effort jira integration, no status changes
129149 post_jira_comments (risk_acceptance , findings , accepted_message_creator )
130150
151+ return None
152+
131153
132154@app .task
133155def expiration_handler (* args , ** kwargs ):
@@ -174,6 +196,16 @@ def expiration_handler(*args, **kwargs):
174196 risk_acceptance .save ()
175197
176198
199+ def get_view_risk_acceptance (risk_acceptance : Risk_Acceptance ) -> str :
200+ """Return the full qualified URL of the view risk acceptance page."""
201+ # Suppressing this error because it does not happen under most circumstances that a risk acceptance does not have engagement
202+ with suppress (AttributeError ):
203+ get_full_url (
204+ reverse ("view_risk_acceptance" , args = (risk_acceptance .engagement .id , risk_acceptance .id )),
205+ )
206+ return ""
207+
208+
177209def expiration_message_creator (risk_acceptance , heads_up_days = 0 ):
178210 return "Risk acceptance [({})|{}] with {} findings has expired" .format (
179211 escape_for_jira (risk_acceptance .name ),
@@ -267,7 +299,7 @@ def prefetch_for_expiration(risk_acceptances):
267299 )
268300
269301
270- def simple_risk_accept (finding , perform_save = True ):
302+ def simple_risk_accept (user : Dojo_User , finding : Finding , perform_save = True ) -> None :
271303 if not finding .test .engagement .product .enable_simple_risk_acceptance :
272304 raise PermissionDenied
273305
@@ -282,9 +314,15 @@ def simple_risk_accept(finding, perform_save=True):
282314 # post_jira_comment might reload from database so see unaccepted finding. but the comment
283315 # only contains some text so that's ok
284316 post_jira_comment (finding , accepted_message_creator )
317+ # Add a note to reflect that the finding was removed from the risk acceptance
318+ if user is not None :
319+ finding .notes .add (Notes .objects .create (
320+ entry = (f"{ Dojo_User .generate_full_name (user )} ({ user .id } ) has risk accepted this finding" ),
321+ author = user ,
322+ ))
285323
286324
287- def risk_unaccept (finding , perform_save = True ):
325+ def risk_unaccept (user : Dojo_User , finding : Finding , perform_save = True ) -> None :
288326 logger .debug ("unaccepting finding %i:%s if it is currently risk accepted" , finding .id , finding )
289327 if finding .risk_accepted :
290328 logger .debug ("unaccepting finding %i:%s" , finding .id , finding )
@@ -302,6 +340,12 @@ def risk_unaccept(finding, perform_save=True):
302340 # post_jira_comment might reload from database so see unaccepted finding. but the comment
303341 # only contains some text so that's ok
304342 post_jira_comment (finding , unaccepted_message_creator )
343+ # Add a note to reflect that the finding was removed from the risk acceptance
344+ if user is not None :
345+ finding .notes .add (Notes .objects .create (
346+ entry = (f"{ Dojo_User .generate_full_name (user )} ({ user .id } ) removed a risk exception from this finding" ),
347+ author = user ,
348+ ))
305349
306350
307351def remove_from_any_risk_acceptance (finding ):
0 commit comments