Add support for SSL related interactions:

1. Inject SSL related env variables to git clone
2. Force LiteLLM to use aiohttp which honors SSL env. variables, this is done by setting configuration toml as follows:

[litellm]
disable_aiohttp = true
This commit is contained in:
Eyal Sharon 2025-10-13 16:21:24 +03:00
parent b7874e6e5f
commit bf1d1284a0
3 changed files with 68 additions and 4 deletions

View file

@ -33,6 +33,8 @@ class LiteLLMAIHandler(BaseAiHandler):
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

View file

@ -18,7 +18,7 @@ from ..algo.utils import (find_line_number_of_relevant_line_in_file,
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):
@ -561,5 +561,7 @@ class BitbucketServerProvider(GitProvider):
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)

View file

@ -12,6 +12,65 @@ from pr_agent.log import get_logger
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 empty string")
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:
@ -57,12 +116,13 @@ class GitProvider(ABC):
# #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.
ssl_env = get_git_ssl_env()
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