Skip to content

Commit 5b6c9f4

Browse files
Merge pull request #63 from Contrast-Security-OSS/release_candidate_v1_0_9
Release candidate v1 0 9
2 parents 3b479f2 + 1637e49 commit 5b6c9f4

38 files changed

+3878
-749
lines changed

README.md

Lines changed: 9 additions & 347 deletions
Large diffs are not rendered by default.

action.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ inputs:
9090
required: false
9191
default: 'true'
9292
coding_agent:
93-
description: 'Specifies the coding agent to use for generating fixes. Allowed values: SMARTFIX, GITHUB_COPILOT.'
93+
description: 'Specifies the coding agent to use for generating fixes. Allowed values: SMARTFIX, GITHUB_COPILOT, CLAUDE_CODE.'
9494
required: false
9595
default: 'SMARTFIX'
9696

docs/claude_code.md

Lines changed: 274 additions & 0 deletions
Large diffs are not rendered by default.
File renamed without changes.

docs/github_copilot.md

Lines changed: 266 additions & 0 deletions
Large diffs are not rendered by default.

docs/smartfix_coding_agent.md

Lines changed: 333 additions & 0 deletions
Large diffs are not rendered by default.

src/agent_handler.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,8 @@
5252
try:
5353
from google.adk.agents import Agent
5454
from google.adk.artifacts.in_memory_artifact_service import InMemoryArtifactService
55-
from src.extensions.smartfix_litellm import SmartFixLiteLlm
56-
from src.extensions.smartfix_llm_agent import SmartFixLlmAgent
55+
from src.smartfix.extensions.smartfix_litellm import SmartFixLiteLlm
56+
from src.smartfix.extensions.smartfix_llm_agent import SmartFixLlmAgent
5757
from google.adk.runners import Runner
5858
from google.adk.sessions import InMemorySessionService
5959
from google.adk.tools.mcp_tool.mcp_toolset import MCPToolset, StdioServerParameters, StdioConnectionParams

src/closed_handler.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,8 @@ def _extract_remediation_info(pull_request: dict) -> tuple:
7272
# Extract remediation ID from branch name or PR labels
7373
remediation_id = None
7474

75-
# Check if this is a branch created by external agent (e.g., GitHub Copilot)
76-
if branch_name.startswith("copilot/fix"):
75+
# Check if this is a branch created by external agent (e.g., GitHub Copilot or Claude Code)
76+
if branch_name.startswith("copilot/fix") or branch_name.startswith("claude/issue-"):
7777
debug_log("Branch appears to be created by external agent. Extracting remediation ID from PR labels.")
7878
remediation_id = extract_remediation_id_from_labels(labels)
7979
# Extract GitHub issue number from branch name
@@ -83,14 +83,18 @@ def _extract_remediation_info(pull_request: dict) -> tuple:
8383
debug_log(f"Extracted external issue number from branch name: {issue_number}")
8484
else:
8585
debug_log(f"Could not extract issue number from branch name: {branch_name}")
86-
telemetry_handler.update_telemetry("additionalAttributes.codingAgent", "EXTERNAL-COPILOT")
86+
87+
# Set the external coding agent in telemetry based on branch prefix
88+
coding_agent = "EXTERNAL-CLAUDE-CODE" if branch_name.startswith("claude/") else "EXTERNAL-COPILOT"
89+
debug_log(f"Determined external coding agent to be: {coding_agent}")
90+
telemetry_handler.update_telemetry("additionalAttributes.codingAgent", coding_agent)
8791
else:
8892
# Use original method for branches created by SmartFix
8993
remediation_id = extract_remediation_id_from_branch(branch_name)
9094
telemetry_handler.update_telemetry("additionalAttributes.codingAgent", "INTERNAL-SMARTFIX")
9195

9296
if not remediation_id:
93-
if branch_name.startswith("copilot/fix"):
97+
if branch_name.startswith("copilot/fix") or branch_name.startswith("claude/issue-"):
9498
log(f"Error: Could not extract remediation ID from PR labels for external agent branch: {branch_name}", is_error=True)
9599
else:
96100
log(f"Error: Could not extract remediation ID from branch name: {branch_name}", is_error=True)

src/coding_agents.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# -
2+
# #%L
3+
# Contrast AI SmartFix
4+
# %%
5+
# Copyright (C) 2025 Contrast Security, Inc.
6+
# %%
7+
8+
# License: Commercial
9+
# NOTICE: This Software and the patented inventions embodied within may only be
10+
# used as part of Contrast Security's commercial offerings. Even though it is
11+
# made available through public repositories, use of this Software is subject to
12+
# the applicable End User Licensing Agreement found at
13+
# https://www.contrastsecurity.com/enduser-terms-0317a or as otherwise agreed
14+
# between Contrast Security and the End User. The Software may not be reverse
15+
# engineered, modified, repackaged, sold, redistributed or otherwise used in a
16+
# way not consistent with the End User License Agreement.
17+
# #L%
18+
#
19+
20+
from enum import Enum
21+
22+
23+
class CodingAgents(Enum):
24+
SMARTFIX = "SMARTFIX"
25+
GITHUB_COPILOT = "GITHUB_COPILOT"
26+
CLAUDE_CODE = "CLAUDE_CODE"

src/config.py

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import json
2323
from pathlib import Path
2424
from typing import Optional, Any, Dict, List
25+
from src.coding_agents import CodingAgents
2526

2627

2728
def _log_config_message(message: str, is_error: bool = False, is_warning: bool = False):
@@ -65,7 +66,7 @@ def __init__(self, env: Dict[str, str] = os.environ, testing: bool = False):
6566

6667
# --- AI Agent Configuration ---
6768
self.CODING_AGENT = self._get_coding_agent()
68-
is_smartfix_coding_agent = self.CODING_AGENT == "SMARTFIX"
69+
is_smartfix_coding_agent = self.CODING_AGENT == CodingAgents.SMARTFIX.name
6970

7071
default_agent_model = ""
7172
if is_smartfix_coding_agent:
@@ -165,11 +166,19 @@ def _check_contrast_config_values_exist(self):
165166

166167
def _get_coding_agent(self) -> str:
167168
coding_agent = self._get_env_var("CODING_AGENT", required=False, default="SMARTFIX")
168-
valid_agents = ["SMARTFIX", "GITHUB_COPILOT"]
169-
if coding_agent.upper() not in valid_agents:
170-
_log_config_message(f"Warning: Invalid CODING_AGENT '{coding_agent}'. Must be one of {valid_agents}. Defaulting to 'SMARTFIX'.", is_warning=True)
171-
return "SMARTFIX"
172-
return coding_agent.upper()
169+
try:
170+
# Try to convert string to Enum
171+
CodingAgents[coding_agent.upper()]
172+
return coding_agent.upper()
173+
except (KeyError, ValueError):
174+
agent_names = [agent.name for agent in CodingAgents]
175+
default_name = CodingAgents.SMARTFIX.name
176+
_log_config_message(
177+
f"Warning: Invalid CODING_AGENT '{coding_agent}'. Must be one of {agent_names}. "
178+
f"Defaulting to '{default_name}'.",
179+
is_warning=True
180+
)
181+
return CodingAgents.SMARTFIX.name
173182

174183
def _parse_and_validate_severities(self, json_str: Optional[str]) -> List[str]:
175184
default_severities = ["CRITICAL", "HIGH"]

0 commit comments

Comments
 (0)