wirenboard-agent-vm/mitmproxy-addon.py
Evgeny Boger 90c5687cdc Unified credential proxy: Proxy-Authorization, per-rule upstream proxy, blocked domains
- 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>
2026-03-07 03:02:30 +03:00

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