From 9665db221c4b0dafcc16d6bbb775330597c37299 Mon Sep 17 00:00:00 2001 From: Dan Dye Date: Wed, 9 Sep 2026 02:24:54 +0000 Subject: [PATCH] feat(soar): enable trust_env in HttpClient session for corporate proxies (#198) - Sets trust_env=True on aiohttp.ClientSession in HttpClient._get_session to honor standard HTTP_PROXY, HTTPS_PROXY, and NO_PROXY environment variables - Adds unit tests in test_http_client.py verifying session proxy environment trust - Documents corporate proxy configuration and SSL CA bundles in usage_guide.md and secops-soar README.md --- docs/usage_guide.md | 37 +++++++++++++++++ server/secops-soar/README.md | 15 +++++++ .../secops_soar_mcp/http_client.py | 2 +- .../tests/unit/test_http_client.py | 40 +++++++++++++++++++ 4 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 server/secops-soar/tests/unit/test_http_client.py diff --git a/docs/usage_guide.md b/docs/usage_guide.md index 40f9f610..a11acf64 100644 --- a/docs/usage_guide.md +++ b/docs/usage_guide.md @@ -275,3 +275,40 @@ If you are not sure which URL to use, try one of these options: 2. Open your browser developer tools, go to the **Network** tab, and navigate to **Cases** in the SOAR UI. Look for a request such as `GetCaseCardsByRequest`, open the **Headers** tab, and copy the base URL from that request. For example: `https://s4i0z.siemplify-soar.com`. After updating `SOAR_URL`, restart your MCP client so it picks up the new environment variable. + +### Corporate Proxy Configuration + +If you are running MCP servers behind an HTTP/HTTPS corporate proxy: + +1. **Configure standard proxy variables**: Set `HTTP_PROXY`, `HTTPS_PROXY`, and optionally `NO_PROXY` in your environment. +2. **Pass proxy variables in MCP client settings**: Ensure your MCP client configuration passes these variables to each server's `env` section: + +```json +{ + "mcpServers": { + "gti": { + "command": "uv", + "args": ["--directory", "/path/to/server/gti/gti_mcp", "run", "server.py"], + "env": { + "VT_APIKEY": "${VT_APIKEY}", + "HTTP_PROXY": "${HTTP_PROXY}", + "HTTPS_PROXY": "${HTTPS_PROXY}" + } + }, + "secops-soar": { + "command": "uv", + "args": ["--directory", "/path/to/server/secops-soar/secops_soar_mcp", "run", "server.py"], + "env": { + "SOAR_URL": "${SOAR_URL}", + "SOAR_APP_KEY": "${SOAR_APP_KEY}", + "HTTP_PROXY": "${HTTP_PROXY}", + "HTTPS_PROXY": "${HTTPS_PROXY}" + } + } + } +} +``` + +3. **Custom SSL/CA Certificates (SSL Decryption/Inspection)**: If your corporate proxy intercepts SSL traffic, point `SSL_CERT_FILE` to your corporate CA certificate bundle. + + diff --git a/server/secops-soar/README.md b/server/secops-soar/README.md index 96c2f7b6..51ab29da 100644 --- a/server/secops-soar/README.md +++ b/server/secops-soar/README.md @@ -133,6 +133,21 @@ Install the certifi CA bundle: `export SSL_CERT_FILE=$(python -m certifi)` (or the PowerShell equivalent `$Env:SSL_CERT_FILE = (python -m certifi)`). +### Corporate Proxy Configuration + +The server automatically honors standard proxy environment variables (`HTTP_PROXY`, `HTTPS_PROXY`, `NO_PROXY`). If running behind a corporate proxy, set these variables in your environment or within your MCP client configuration (`cline_mcp_settings.json`, `claude_desktop_config.json`): + +```json +"env": { + "SOAR_URL": "https://your-soar-instance", + "SOAR_APP_KEY": "your-key", + "HTTP_PROXY": "http://proxy.corp.example.com:8080", + "HTTPS_PROXY": "http://proxy.corp.example.com:8080" +} +``` + +If your corporate proxy performs SSL decryption/inspection, point `SSL_CERT_FILE` to your corporate CA bundle. + See `docs/usage_guide.md` for further details. ## Requirements diff --git a/server/secops-soar/secops_soar_mcp/http_client.py b/server/secops-soar/secops_soar_mcp/http_client.py index 13aa5ed1..0913b40c 100644 --- a/server/secops-soar/secops_soar_mcp/http_client.py +++ b/server/secops-soar/secops_soar_mcp/http_client.py @@ -33,7 +33,7 @@ def __init__(self, base_url: str, app_key: str): def _get_session(self) -> aiohttp.ClientSession: if self._session is None: - self._session = aiohttp.ClientSession() + self._session = aiohttp.ClientSession(trust_env=True) return self._session async def _get_headers(self): diff --git a/server/secops-soar/tests/unit/test_http_client.py b/server/secops-soar/tests/unit/test_http_client.py new file mode 100644 index 00000000..c9cca7f7 --- /dev/null +++ b/server/secops-soar/tests/unit/test_http_client.py @@ -0,0 +1,40 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Unit tests for SecOps SOAR HttpClient session configuration.""" + +from unittest import mock + +import pytest +from secops_soar_mcp.http_client import HttpClient + + +@pytest.mark.asyncio +async def test_http_client_session_trusts_env(): + """Ensure HttpClient initializes ClientSession with trust_env=True for proxies.""" + client = HttpClient("https://example.com", "app-key") + session = client._get_session() + try: + assert session.trust_env is True + finally: + await session.close() + + +def test_http_client_passes_trust_env_to_client_session(): + """Ensure HttpClient explicitly passes trust_env=True to aiohttp.ClientSession.""" + client = HttpClient("https://example.com", "app-key") + with mock.patch("aiohttp.ClientSession") as mock_session_cls: + session = client._get_session() + mock_session_cls.assert_called_once_with(trust_env=True) + assert session == mock_session_cls.return_value