Technical documentation for AI coding agents working on this project.
Type: Python 3.13 daemon Purpose: MITM proxy that removes cleans security headers from HTTP responses to help development and testing. Primary library: mitmproxy 11.0+ Package manager: uv (native mode, not uv pip) Build system: hatchling
devrelay/
├── __init__.py # Exports: COEPRemoverAddon, COOPRemoverAddon, CORPInserterAddon, CORSInserterForWebhooksAddon,
│ # CORSPreflightForWebhooksAddon, CSPRemoverAddon
├── addons.py # All addon classes (CSP, COEP, COOP, CORP, and CORS handling)
├── proxy.py # Server configuration and startup
└── cli.py # CLI entry point with argparse
tests/ # pytest test suite
├── test_addons.py # Tests for all addons (CSP, COEP, COOP, CORP, and CORS)
├── test_proxy.py # ProxyServer tests
└── test_devrelay.py # CLI tests
Type: async server wrapper Test file: tests/test_proxy.py Configuration:
- Default listen: 127.0.0.1:8080
- TLS: 1.2+
- Protocols: HTTP/1.x, HTTP/2, HTTP/3, WebSocket
- Cert dir: ~/.mitmproxy
- Loads CSPRemoverAddon, COEPRemoverAddon, COOPRemoverAddon, CORPInserterAddon, CORSInserterForWebhooksAddon, and CORSPreflightForWebhooksAddon
Type: mitmproxy addon class
Entry points: response(self, flow: http.HTTPFlow) -> None
Test file: tests/test_addons.py
Test class: TestCSPRemoverAddon Behavior:
- Intercepts all HTTP responses
- Removes headers (case-insensitive):
content-security-policycontent-security-policy-report-only
- Preserves all other headers
- Handles None responses gracefully
Test class: TestCOEPRemoverAddon Behavior:
- Intercepts all HTTP responses
- Removes headers (case-insensitive):
cross-origin-embedder-policycross-origin-embedder-policy-report-only
- Preserves all other headers
- Handles None responses gracefully
Test class: TestCOOPRemoverAddon Behavior:
- Intercepts all HTTP responses
- Removes headers (case-insensitive):
cross-origin-opener-policycross-origin-opener-policy-report-only
- Preserves all other headers
- Handles None responses gracefully
Test class: TestCORPInserterAddon Behavior:
- Intercepts HTTP responses to mutation requests (POST, PUT, PATCH, DELETE)
- Only processes successful responses (1XX or 2XX status codes)
- Adds header:
Cross-Origin-Resource-Policy: cross-origin - Preserves all other headers
- Handles None responses gracefully
- Ignores GET and other non-mutation methods
- Ignores 3XX, 4XX, and 5XX status codes
Test class: TestCORSInserterForWebhooksAddon Behavior:
- Intercepts HTTP responses to mutation requests (POST, PUT, PATCH, DELETE)
- Only processes successful responses (1XX or 2XX status codes)
- Adds permissive CORS headers:
Access-Control-Allow-Origin: *Access-Control-Allow-Methods: GET, POST, PUT, PATCH, DELETE, OPTIONS, HEADAccess-Control-Allow-Headers: *Access-Control-Max-Age: 86400Access-Control-Expose-Headers: *
- Preserves all other headers
- Handles None responses gracefully
- Ignores GET and other non-mutation methods
- Ignores 3XX, 4XX, and 5XX status codes
Test class: TestCORSPreflightForWebhooksAddon Behavior:
- Intercepts OPTIONS requests that returned 405 Method Not Allowed
- Rewrites response to 204 No Content
- Adds permissive CORS headers:
Access-Control-Allow-Origin: *Access-Control-Allow-Methods: GET, POST, PUT, PATCH, DELETE, OPTIONS, HEADAccess-Control-Allow-Headers: *Access-Control-Max-Age: 86400Access-Control-Expose-Headers: *
- Clears response body
- Ignores non-OPTIONS requests and non-405 responses
Entry point: main() -> int
Script entry: devrelay (configured in pyproject.toml)
Framework: argparse
Class: DevRelayCLI
Arguments:
--host(str, default: 127.0.0.1)--port(int, default: 8080)--confdir(Path, default: None -> ~/.mitmproxy)
The make dev command automatically installs pre-commit hooks that run on git commit to check for:
- Secrets and credentials (gitleaks)
- Trailing whitespace
- End-of-file fixers
- Code formatting (black in check mode)
- Markdown linting (pymarkdownlnt in check mode)
Testing: pytest with asyncio support Type checking: pyright in strict mode Code style: black and pymarkdownlint
make format
make lint
make lintmd
make typecheck
make test
make check # All of the above- Modify
devrelay/addons.py - Implement new methods or modify
response()in the relevant addon class - Add corresponding tests in
tests/test_addons.py - Run
make checkto verify
- Update
ProxyServer.__init__()orstart()indevrelay/proxy.py - Add tests in
tests/test_proxy.py - Update CLI args in
devrelay/cli.pyif needed - Update README.md if user-facing
- Edit
pyproject.tomldependencies or optional-dependencies - Run
make devto install
Pattern: use mitmproxy.test.tflow for creating test flows
from mitmproxy.test import tflow
flow = tflow.tflow(resp=True) # Creates flow with response
flow.response.headers["Header-Name"] = "value"Requirements:
- All new code must have tests
- Coverage should not decrease
- Use type hints in all test functions
- Edit
devrelay/addons.py-> add tocsp_headerslist in CSPRemoverAddon - Add test in
tests/test_addons.pyin TestCSPRemoverAddon class - Run
make check(not justmake test)
- Edit
devrelay/cli.py-> add to argparse in DevRelayCLI class - Pass to ProxyServer constructor
- Update ProxyServer to accept parameter
- Add tests in
tests/test_devrelay.py - Update README.md
- Run
make checkto ensure 100% coverage
BEFORE FINISHING ANY TASK:
- Run
make check - Ensure 0 errors, 0 warnings (except external lib warnings)
- Verify 100% line AND branch coverage
- All checks must pass (format, lint, typecheck, test)
- Type hints are required (strict mode via pyright)
- All public APIs must have docstrings
- Tests are required for ALL new code
- Use
uvcommands, notpipdirectly - Virtual environment is at
.venv/ - Don't modify certificate handling (security critical)
- Follow existing code patterns and structure
The project enforces:
fail_under = 100in coverage configtypeCheckingMode = "strict"in pyrightflake8with max-line-length=120pymarkdownlntwith MD013 enabled (line_length=120, code blocks exempt)blackformatting with line-length=120 must not change files
If make check fails, your task is incomplete. Fix all issues.