1- #-
1+ # -
22# #%L
33# Contrast AI SmartFix
44# %%
2828from src .git_handler import extract_issue_number_from_branch
2929import src .telemetry_handler as telemetry_handler
3030
31- def handle_closed_pr ():
32- """Handles the logic when a pull request is closed without merging."""
33- telemetry_handler .initialize_telemetry ()
34-
35- log ("--- Handling Closed (Unmerged) Contrast AI SmartFix Pull Request ---" )
3631
37- # Get PR event details from environment variables set by GitHub Actions
32+ def _load_github_event () -> dict :
33+ """Load and parse the GitHub event data."""
3834 event_path = os .getenv ("GITHUB_EVENT_PATH" )
3935 if not event_path :
4036 log ("Error: GITHUB_EVENT_PATH not set. Cannot process PR event." , is_error = True )
4137 sys .exit (1 )
4238
4339 try :
4440 with open (event_path , 'r' ) as f :
45- event_data = json .load (f )
41+ return json .load (f )
4642 except Exception as e :
4743 log (f"Error reading or parsing GITHUB_EVENT_PATH file: { e } " , is_error = True )
4844 sys .exit (1 )
4945
46+
47+ def _validate_pr_event (event_data : dict ) -> dict :
48+ """Validate the PR event and return PR data."""
5049 if event_data .get ("action" ) != "closed" :
5150 log ("PR action is not 'closed'. Skipping." )
5251 sys .exit (0 )
@@ -57,20 +56,22 @@ def handle_closed_pr():
5756 sys .exit (0 )
5857
5958 debug_log ("Pull request was closed without merging." )
59+ return pull_request
6060
61- # Get the branch name from the PR
61+
62+ def _extract_remediation_info (pull_request : dict ) -> tuple :
63+ """Extract remediation ID and other info from PR data."""
6264 branch_name = pull_request .get ("head" , {}).get ("ref" )
6365 if not branch_name :
6466 log ("Error: Could not determine branch name from PR." , is_error = True )
6567 sys .exit (1 )
66-
67- debug_log (f"Branch name: { branch_name } " )
6868
69+ debug_log (f"Branch name: { branch_name } " )
6970 labels = pull_request .get ("labels" , [])
7071
7172 # Extract remediation ID from branch name or PR labels
7273 remediation_id = None
73-
74+
7475 # Check if this is a branch created by external agent (e.g., GitHub Copilot)
7576 if branch_name .startswith ("copilot/fix" ):
7677 debug_log ("Branch appears to be created by external agent. Extracting remediation ID from PR labels." )
@@ -87,21 +88,21 @@ def handle_closed_pr():
8788 # Use original method for branches created by SmartFix
8889 remediation_id = extract_remediation_id_from_branch (branch_name )
8990 telemetry_handler .update_telemetry ("additionalAttributes.codingAgent" , "INTERNAL-SMARTFIX" )
90-
91+
9192 if not remediation_id :
9293 if branch_name .startswith ("copilot/fix" ):
9394 log (f"Error: Could not extract remediation ID from PR labels for external agent branch: { branch_name } " , is_error = True )
9495 else :
9596 log (f"Error: Could not extract remediation ID from branch name: { branch_name } " , is_error = True )
96- # If we can't find the remediation ID, we can't proceed
9797 sys .exit (1 )
98-
99- debug_log (f"Extracted Remediation ID: { remediation_id } " )
100- telemetry_handler .update_telemetry ("additionalAttributes.remediationId" , remediation_id )
101-
102- # Try to extract vulnerability UUID from PR labels
98+
99+ return remediation_id , labels
100+
101+
102+ def _extract_vulnerability_info (labels : list ) -> str :
103+ """Extract vulnerability UUID from PR labels."""
103104 vuln_uuid = "unknown"
104-
105+
105106 for label in labels :
106107 label_name = label .get ("name" , "" )
107108 if label_name .startswith ("contrast-vuln-id:VULN-" ):
@@ -111,16 +112,16 @@ def handle_closed_pr():
111112 if vuln_uuid and vuln_uuid != "unknown" :
112113 debug_log (f"Extracted Vulnerability UUID from PR label: { vuln_uuid } " )
113114 break
114- telemetry_handler .update_telemetry ("vulnInfo.vulnId" , vuln_uuid )
115- telemetry_handler .update_telemetry ("vulnInfo.vulnRule" , "unknown" )
116-
115+
117116 if vuln_uuid == "unknown" :
118117 debug_log ("Could not extract vulnerability UUID from PR labels. Telemetry may be incomplete." )
119118
120-
121- # Notify the Remediation backend service about the closed PR
119+ return vuln_uuid
120+
121+
122+ def _notify_remediation_service (remediation_id : str ):
123+ """Notify the Remediation backend service about the closed PR."""
122124 log (f"Notifying Remediation service about closed PR for remediation { remediation_id } ..." )
123- # Get config instance using the canonical OO approach
124125 config = get_config ()
125126 remediation_notified = contrast_api .notify_remediation_pr_closed (
126127 remediation_id = remediation_id ,
@@ -130,16 +131,42 @@ def handle_closed_pr():
130131 contrast_auth_key = config .CONTRAST_AUTHORIZATION_KEY ,
131132 contrast_api_key = config .CONTRAST_API_KEY
132133 )
133-
134+
134135 if remediation_notified :
135136 log (f"Successfully notified Remediation service about closed PR for remediation { remediation_id } ." )
136137 else :
137138 log (f"Failed to notify Remediation service about closed PR for remediation { remediation_id } ." , is_error = True )
138139
140+
141+ def handle_closed_pr ():
142+ """Handles the logic when a pull request is closed without merging."""
143+ telemetry_handler .initialize_telemetry ()
144+
145+ log ("--- Handling Closed (Unmerged) Contrast AI SmartFix Pull Request ---" )
146+
147+ # Load and validate GitHub event data
148+ event_data = _load_github_event ()
149+ pull_request = _validate_pr_event (event_data )
150+
151+ # Extract remediation and vulnerability information
152+ remediation_id , labels = _extract_remediation_info (pull_request )
153+ vuln_uuid = _extract_vulnerability_info (labels )
154+
155+ # Update telemetry with extracted information
156+ debug_log (f"Extracted Remediation ID: { remediation_id } " )
157+ telemetry_handler .update_telemetry ("additionalAttributes.remediationId" , remediation_id )
158+ telemetry_handler .update_telemetry ("vulnInfo.vulnId" , vuln_uuid )
159+ telemetry_handler .update_telemetry ("vulnInfo.vulnRule" , "unknown" )
160+
161+ # Notify the Remediation backend service
162+ _notify_remediation_service (remediation_id )
163+
164+ # Complete telemetry and finish
139165 telemetry_handler .update_telemetry ("additionalAttributes.prStatus" , "CLOSED" )
140166 contrast_api .send_telemetry_data ()
141-
167+
142168 log ("--- Closed Contrast AI SmartFix Pull Request Handling Complete ---" )
143169
170+
144171if __name__ == "__main__" :
145172 handle_closed_pr ()
0 commit comments