Warning
This documentation is actively being updated as the project evolves and may not be complete in all areas.
jumpstarter-driver-mitmproxy¶
A Jumpstarter driver for mitmproxy — bringing HTTP(S) interception, backend mocking, and traffic recording to Hardware-in-the-Loop testing.
What it does¶
This driver manages a mitmdump or mitmweb process on the Jumpstarter exporter host, providing your pytest HiL tests with:
Backend mocking — Return deterministic JSON responses for any API endpoint, with hot-reloadable definitions, wildcard path matching, conditional rules, sequences, templates, and custom addons
SSL/TLS interception — Inspect and modify HTTPS traffic from your DUT, with easy CA certificate retrieval for DUT provisioning
Traffic recording & replay — Capture a “golden” session against real servers, then replay it offline in CI
Request capture — Record every request the DUT makes and assert on them in your tests
Browser-based UI — Launch
mitmwebfor interactive traffic inspection, with TCP port forwarding through the Jumpstarter tunnelScenario files — Load complete mock configurations from YAML or JSON, swap between test scenarios instantly
Full CLI — Control the proxy interactively from
jmp shellsessions
Installation¶
# On both the exporter host and test client
pip install --extra-index-url https://pkg.jumpstarter.dev/simple \
jumpstarter-driver-mitmproxy
Or build from source:
uv build
pip install dist/jumpstarter_driver_mitmproxy-*.whl
Exporter Configuration¶
# /etc/jumpstarter/exporters/my-bench.yaml
export:
proxy:
type: jumpstarter_driver_mitmproxy.driver.MitmproxyDriver
config:
listen:
host: "0.0.0.0"
port: 8080 # Proxy port (DUT connects here)
web:
host: "0.0.0.0"
port: 8081 # mitmweb browser UI port
directories:
data: /opt/jumpstarter/mitmproxy
ssl_insecure: true # Skip upstream cert verification
# Auto-load a scenario on startup (relative to mocks dir)
# mock_scenario: happy-path.yaml
# Inline mock definitions (overlaid on scenario)
# mocks:
# GET /api/v1/health:
# status: 200
# body: {ok: true}
Configuration Reference¶
Parameter |
Description |
Type |
Default |
|---|---|---|---|
|
Proxy listener bind address |
str |
|
|
Proxy listener port |
int |
|
|
mitmweb UI bind address |
str |
|
|
mitmweb UI port |
int |
|
|
Base data directory |
str |
|
|
mitmproxy config/certs dir |
str |
|
|
Recorded flow files dir |
str |
|
|
Custom addon scripts dir |
str |
|
|
Mock definitions dir |
str |
|
|
Files to serve from mocks |
str |
|
|
Skip upstream SSL verification |
bool |
|
|
Scenario file to auto-load on startup |
str |
|
|
Inline mock endpoint definitions |
dict |
|
See examples/exporter.yaml in the package source for a full exporter config with DUT Link, serial, and video drivers.
Modes¶
Mode |
Description |
|---|---|
|
Intercept traffic, return mock responses |
|
Transparent proxy, log only |
|
Capture all traffic to a binary flow file |
|
Serve responses from a previously recorded flow |
Add web_ui=True (Python) or --web-ui (CLI) to any mode for the mitmweb browser interface.
CLI Commands¶
During a jmp shell session, control the proxy with j proxy <command>:
Lifecycle¶
j proxy start # start in mock mode (default)
j proxy start -m passthrough # start in passthrough mode
j proxy start -m mock -w # start with mitmweb UI
j proxy start -m record # start recording traffic
j proxy start -m replay --replay-file capture_20260213.bin
j proxy stop # stop the proxy
j proxy restart # restart with same config
j proxy restart -m passthrough # restart with new mode
j proxy status # show proxy status
Mock Management¶
j proxy mock list # list configured mocks
j proxy mock clear # remove all mocks
j proxy mock load happy-path.yaml # load a scenario file
j proxy mock load my-capture/ # load a saved capture directory
Traffic Capture¶
j proxy capture list # show captured requests
j proxy capture clear # clear captured requests
j proxy capture save ./my-capture # export as scenario to directory
j proxy capture save -f '/api/v1/*' ./my-capture # with path filter
j proxy capture save --exclude-mocked ./my-capture
Flow Files¶
j proxy flow list # list recorded flow files
j proxy flow save capture_20260101.bin # download to current directory
j proxy flow save capture_20260101.bin /tmp/my.bin # download to specific path
Web UI & Certificates¶
j proxy web # forward mitmweb UI to localhost:8081
j proxy web --port 9090 # forward to a custom port
j proxy cert # download CA cert to ./mitmproxy-ca-cert.pem
j proxy cert /tmp/ca.pem # download to a specific path
Python API¶
Basic Usage¶
def test_device_status(client):
proxy = client.proxy
# Start with web UI for debugging
proxy.start(mode="mock", web_ui=True)
# Mock a backend endpoint
proxy.set_mock(
"GET", "/api/v1/status",
body={"id": "device-001", "status": "active"},
)
# ... interact with DUT ...
proxy.stop()
Context Managers¶
Context managers ensure clean teardown even if the test fails:
def test_firmware_update(client):
proxy = client.proxy
with proxy.session(mode="mock", web_ui=True):
with proxy.mock_endpoint(
"GET", "/api/v1/updates/check",
body={"update_available": True, "version": "2.6.0"},
):
# DUT will see the mocked update
trigger_update_check(client)
assert_update_dialog_shown(client)
# Mock auto-removed here
# Proxy auto-stopped here
Available context managers:
Context Manager |
Description |
|---|---|
|
Start/stop the proxy |
|
Temporary mock endpoint |
|
Load/clear a scenario file |
|
Temporary conditional mock |
|
Record traffic to a flow file |
|
Capture and assert on requests |
Request Capture¶
Verify that the DUT is making the right API calls:
def test_telemetry_sent(client):
proxy = client.proxy
with proxy.capture() as cap:
# ... DUT sends telemetry through the proxy ...
cap.wait_for_request("POST", "/api/v1/telemetry", timeout=10)
# After the block, cap.requests is a frozen snapshot
assert len(cap.requests) >= 1
cap.assert_request_made("POST", "/api/v1/telemetry")
Advanced Mocking¶
Conditional responses¶
Return different responses based on request headers, body, or query params:
proxy.set_mock_conditional("POST", "/api/auth", [
{
"match": {"body_json": {"username": "admin", "password": "secret"}},
"status": 200,
"body": {"token": "mock-token-001"},
},
{"status": 401, "body": {"error": "unauthorized"}},
])
Response sequences¶
Return different responses on successive calls:
proxy.set_mock_sequence("GET", "/api/v1/auth/token", [
{"status": 200, "body": {"token": "aaa"}, "repeat": 3},
{"status": 401, "body": {"error": "expired"}, "repeat": 1},
{"status": 200, "body": {"token": "bbb"}},
])
Dynamic templates¶
Responses with per-request dynamic values:
proxy.set_mock_template("GET", "/api/v1/weather", {
"temp_f": "{{random_int(60, 95)}}",
"condition": "{{random_choice('sunny', 'rain')}}",
"timestamp": "{{now_iso}}",
"request_id": "{{uuid}}",
})
Simulated latency¶
proxy.set_mock_with_latency(
"GET", "/api/v1/status",
body={"status": "online"},
latency_ms=3000,
)
File serving¶
proxy.set_mock_file(
"GET", "/api/v1/downloads/firmware.bin",
"firmware/test.bin",
content_type="application/octet-stream",
)
Custom addon scripts¶
proxy.set_mock_addon(
"GET", "/streaming/audio/channel/*",
"hls_audio_stream",
addon_config={"segment_duration_s": 6},
)
State Store¶
Share state between tests and conditional mock rules:
proxy.set_state("auth_token", "mock-token-001")
proxy.set_state("retries", 3)
token = proxy.get_state("auth_token") # "mock-token-001"
all_state = proxy.get_all_state() # {"auth_token": "...", "retries": 3}
proxy.clear_state()
SSL/TLS Setup¶
For HTTPS interception, the mitmproxy CA certificate must be installed on the DUT. The certificate is generated the first time the proxy starts.
From the CLI¶
j proxy cert # writes ./mitmproxy-ca-cert.pem
j proxy cert /tmp/ca.pem # custom output path
From Python¶
# Get the PEM certificate contents
pem = proxy.get_ca_cert()
# Write to a local file
from pathlib import Path
Path("/tmp/mitmproxy-ca.pem").write_text(pem)
# Or push directly to the DUT via serial/ssh/adb
dut.write_file("/etc/ssl/certs/mitmproxy-ca.pem", pem)
Exporter-side path¶
If you need the path on the exporter host itself (for provisioning scripts that run locally):
cert_path = proxy.get_ca_cert_path()
# -> /opt/jumpstarter/mitmproxy/conf/mitmproxy-ca-cert.pem
Mock Scenarios¶
Create YAML or JSON files with endpoint definitions:
# scenarios/happy-path.yaml
endpoints:
GET /api/v1/status:
status: 200
body:
id: device-001
status: active
firmware_version: "2.5.1"
POST /api/v1/telemetry/upload:
status: 202
body:
accepted: true
GET /api/v1/search*: # wildcard prefix match
status: 200
body:
results: []
Load from CLI or Python:
j proxy mock load happy-path.yaml
j proxy mock load my-capture/ # directory from 'capture save'
proxy.load_mock_scenario("happy-path.yaml")
# Or with automatic cleanup:
with proxy.mock_scenario("happy-path.yaml"):
run_tests()
See examples/scenarios/ in the package source for complete scenario examples including conditional rules, templates, and sequences.
Web UI Port Forwarding¶
The mitmweb UI runs on the exporter host and is not directly reachable from the test client. The web command tunnels it through the Jumpstarter gRPC transport:
j proxy start -m mock -w # start with web UI on the exporter
j proxy web # tunnel to localhost:8081
j proxy web --port 9090 # use a custom local port
Then open http://localhost:8081 in your browser to inspect traffic in real time.
Container Deployment¶
podman build -t jumpstarter-mitmproxy:latest .
podman run --rm -it --privileged \
-v /dev:/dev \
-v /etc/jumpstarter:/etc/jumpstarter:Z \
-p 8080:8080 -p 8081:8081 \
jumpstarter-mitmproxy:latest \
jmp exporter start my-bench
License¶
Apache-2.0