mirror of
https://github.com/wirenboard/agent-vm.git
synced 2026-07-10 00:14:30 +00:00
- Replace custom X-Proxy-Token with standard Proxy-Authorization (Basic auth) - Remove anthropic-beta header injection (client handles it) - Replace dummy .credentials.json with CLAUDE_CODE_OAUTH_TOKEN env var - Add AI_HTTPS_PROXY/AI_SSL_CERT_FILE for per-rule upstream proxy routing (only rules with use_proxy:true route through it; GitHub goes direct) - Always emit api.anthropic.com rule so mitmproxy intercepts even without CLAUDE_VM_PROXY_ACCESS_TOKEN (needed for upstream proxy routing) - Add BLOCKED_DOMAINS support to mitmproxy addon (blocks datadoghq.com) - Remove obsolete standalone proxies (claude-vm-proxy.py, github-git-proxy.py, github-mcp-proxy.py) and their tests - Update README with current proxy architecture Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
58 lines
1.9 KiB
Python
58 lines
1.9 KiB
Python
"""
|
|
mitmproxy addon for agent VMs.
|
|
|
|
Intercepts HTTPS requests to configured domains and forwards them as plain
|
|
HTTP to the host-side credential proxy, which injects real auth tokens.
|
|
|
|
Requests to non-configured domains pass through to the real upstream unchanged.
|
|
|
|
Usage:
|
|
CREDENTIAL_PROXY_HOST=host.lima.internal \
|
|
CREDENTIAL_PROXY_PORT=12345 \
|
|
CREDENTIAL_PROXY_DOMAINS=api.anthropic.com,github.com,api.github.com \
|
|
mitmdump -s mitmproxy-addon.py
|
|
"""
|
|
|
|
import base64
|
|
import os
|
|
from mitmproxy import http
|
|
|
|
PROXY_HOST = os.environ.get("CREDENTIAL_PROXY_HOST", "host.lima.internal")
|
|
PROXY_PORT = int(os.environ.get("CREDENTIAL_PROXY_PORT", "0"))
|
|
PROXY_SECRET = os.environ.get("CREDENTIAL_PROXY_SECRET", "")
|
|
PROXY_DOMAINS = set(
|
|
d.strip()
|
|
for d in os.environ.get("CREDENTIAL_PROXY_DOMAINS", "").split(",")
|
|
if d.strip()
|
|
)
|
|
BLOCKED_DOMAINS = set(
|
|
d.strip()
|
|
for d in os.environ.get("BLOCKED_DOMAINS", "").split(",")
|
|
if d.strip()
|
|
)
|
|
|
|
|
|
def request(flow: http.HTTPFlow) -> None:
|
|
# Block requests to blacklisted domains
|
|
if flow.request.host in BLOCKED_DOMAINS:
|
|
flow.response = http.Response.make(403, b"Blocked by proxy policy")
|
|
return
|
|
|
|
# Only redirect configured domains to the credential proxy
|
|
if flow.request.host not in PROXY_DOMAINS:
|
|
return
|
|
|
|
# Add original destination info as headers
|
|
flow.request.headers["X-Original-Host"] = flow.request.host
|
|
flow.request.headers["X-Original-Port"] = str(flow.request.port)
|
|
flow.request.headers["X-Original-Scheme"] = flow.request.scheme
|
|
|
|
# Add shared secret for cross-VM isolation (standard proxy auth)
|
|
if PROXY_SECRET:
|
|
creds = base64.b64encode(f"_:{PROXY_SECRET}".encode()).decode()
|
|
flow.request.headers["Proxy-Authorization"] = f"Basic {creds}"
|
|
|
|
# Redirect to host-side credential proxy over plain HTTP
|
|
flow.request.scheme = "http"
|
|
flow.request.host = PROXY_HOST
|
|
flow.request.port = PROXY_PORT
|