Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion pr_agent/algo/ai_handlers/litellm_ai_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ def __init__(self):
self.azure = False
self.api_base = None
self.repetition_penalty = None


if get_settings().get("LITELLM.DISABLE_AIOHTTP", False):
litellm.disable_aiohttp_transport = True
if get_settings().get("OPENAI.KEY", None):
openai.api_key = get_settings().openai.key
litellm.openai_key = get_settings().openai.key
Expand Down
6 changes: 4 additions & 2 deletions pr_agent/git_providers/bitbucket_server_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
load_large_diff)
from ..config_loader import get_settings
from ..log import get_logger
from .git_provider import GitProvider
from .git_provider import GitProvider, get_git_ssl_env


class BitbucketServerProvider(GitProvider):
Expand Down Expand Up @@ -561,5 +561,7 @@ def _clone_inner(self, repo_url: str, dest_folder: str, operation_timeout_in_sec
cli_args = shlex.split(f"git clone -c http.extraHeader='Authorization: Bearer {bearer_token}' "
f"--filter=blob:none --depth 1 {repo_url} {dest_folder}")

subprocess.run(cli_args, check=True, # check=True will raise an exception if the command fails
ssl_env = get_git_ssl_env()

subprocess.run(cli_args, env=ssl_env, check=True, # check=True will raise an exception if the command fails
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, timeout=operation_timeout_in_seconds)
70 changes: 69 additions & 1 deletion pr_agent/git_providers/git_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,65 @@

MAX_FILES_ALLOWED_FULL = 50

def get_git_ssl_env() -> dict[str, str]:
"""
Get git SSL configuration arguments for per-command use.
This fixes SSL certificate issues when cloning repos with self-signed certificates.
Returns the current environment with the addition of SSL config changes if any such SSL certificates exist.
"""
ssl_cert_file = os.environ.get('SSL_CERT_FILE')
requests_ca_bundle = os.environ.get('REQUESTS_CA_BUNDLE')
git_ssl_ca_info = os.environ.get('GIT_SSL_CAINFO')

chosen_cert_file = ""

# Try SSL_CERT_FILE first
if ssl_cert_file:
if os.path.exists(ssl_cert_file):
if ((requests_ca_bundle and requests_ca_bundle != ssl_cert_file)
or (git_ssl_ca_info and git_ssl_ca_info != ssl_cert_file)):
get_logger().warning(f"Found mismatch among: SSL_CERT_FILE, REQUESTS_CA_BUNDLE, GIT_SSL_CAINFO. "
f"Using the SSL_CERT_FILE to resolve ambiguity.",
artifact={"ssl_cert_file": ssl_cert_file, "requests_ca_bundle": requests_ca_bundle,
'git_ssl_ca_info': git_ssl_ca_info})
else:
get_logger().info(f"Using SSL certificate bundle for git operations", artifact={"ssl_cert_file": ssl_cert_file})
chosen_cert_file = ssl_cert_file
else:
get_logger().warning("SSL certificate bundle not found for git operations", artifact={"ssl_cert_file": ssl_cert_file})

# Fallback to REQUESTS_CA_BUNDLE
elif requests_ca_bundle:
if os.path.exists(requests_ca_bundle):
if (git_ssl_ca_info and git_ssl_ca_info != requests_ca_bundle):
get_logger().warning(f"Found mismatch between: REQUESTS_CA_BUNDLE, GIT_SSL_CAINFO. "
f"Using the REQUESTS_CA_BUNDLE to resolve ambiguity.",
artifact = {"requests_ca_bundle": requests_ca_bundle, 'git_ssl_ca_info': git_ssl_ca_info})
else:
get_logger().info("Using SSL certificate bundle from REQUESTS_CA_BUNDLE for git operations",
artifact={"requests_ca_bundle": requests_ca_bundle})
chosen_cert_file = requests_ca_bundle
else:
get_logger().warning("requests CA bundle not found for git operations", artifact={"requests_ca_bundle": requests_ca_bundle})

#Fallback to GIT CA:
elif git_ssl_ca_info:
if os.path.exists(git_ssl_ca_info):
get_logger().info("Using git SSL CA info from GIT_SSL_CAINFO for git operations",
artifact={"git_ssl_ca_info": git_ssl_ca_info})
chosen_cert_file = git_ssl_ca_info
else:
get_logger().warning("git SSL CA info not found for git operations", artifact={"git_ssl_ca_info": git_ssl_ca_info})

else:
get_logger().warning("Neither SSL_CERT_FILE nor REQUESTS_CA_BUNDLE nor GIT_SSL_CAINFO are defined, or they are defined but not found. Returning environment without SSL configuration")

returned_env = os.environ.copy()
if chosen_cert_file:
returned_env.update({"GIT_SSL_CAINFO": chosen_cert_file, "REQUESTS_CA_BUNDLE": chosen_cert_file})
return returned_env


class GitProvider(ABC):
@abstractmethod
def is_supported(self, capability: str) -> bool:
Expand Down Expand Up @@ -57,12 +116,21 @@ def _clone_inner(self, repo_url: str, dest_folder: str, operation_timeout_in_sec
# #Repo.clone_from(repo_url, dest_folder)
# , but with throwing an exception upon timeout.
# Note: This can only be used in context that supports using pipes.
try:
ssl_env = get_git_ssl_env()
except Exception as e:
get_logger().exception(
"Failed to prepare SSL environment for git operations, falling back to default env",
artifact={"error": e}
)
ssl_env = os.environ.copy()

subprocess.run([
"git", "clone",
"--filter=blob:none",
"--depth", "1",
repo_url, dest_folder
], check=True, # check=True will raise an exception if the command fails
], env=ssl_env, check=True, # check=True will raise an exception if the command fails
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, timeout=operation_timeout_in_seconds)

CLONE_TIMEOUT_SEC = 20
Expand Down