Skip to main content

mitmproxy Driver

A Jumpstarter driver for mitmproxy - bringing HTTP(S) interception, backend mocking, and traffic recording to Hardware-in-the-Loop testing.

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 mitmweb for interactive traffic inspection, with TCP port forwarding through the Jumpstarter tunnel
  • Scenario files - Load complete mock configurations from YAML or JSON, swap between test scenarios instantly
  • Full CLI - Control the proxy interactively from jmp shell sessions

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

Configuration

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
listen.host Proxy listener bind address str 0.0.0.0
listen.port Proxy listener port int 8080
web.host mitmweb UI bind address str 0.0.0.0
web.port mitmweb UI port int 8081
directories.data Base data directory str /opt/jumpstarter/mitmproxy
directories.conf mitmproxy config/certs dir str {data}/conf
directories.flows Recorded flow files dir str {data}/flows
directories.addons Custom addon scripts dir str {data}/addons
directories.mocks Mock definitions dir str {data}/mock-responses
directories.files Files to serve from mocks str {data}/mock-files
ssl_insecure Skip upstream SSL verification bool true
mock_scenario Scenario file to auto-load on startup str ""
mocks 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.

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

Usage

Modes

Mode Description
mock Intercept traffic, return mock responses
passthrough Transparent proxy, log only
record Capture all traffic to a binary flow file
replay 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

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.

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
proxy.session(mode, web_ui) Start/stop the proxy
proxy.mock_endpoint(method, path, ...) Temporary mock endpoint
proxy.mock_scenario(file) Load/clear a scenario file
proxy.mock_conditional(method, path, rules) Temporary conditional mock
proxy.recording() Record traffic to a flow file
proxy.capture() 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()

API Reference

.. autoclass:: jumpstarter_driver_mitmproxy.driver.MitmproxyDriver()

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

Release files for jumpstarter-driver-mitmproxy 0.9.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for jumpstarter-driver-mitmproxy 0.9.0
File Size Uploaded
jumpstarter_driver_mitmproxy-0.9.0.tar.gz 78.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for jumpstarter-driver-mitmproxy 0.9.0
File Interpreter ABI Platform
jumpstarter_driver_mitmproxy-0.9.0-py3-none-any.whl Python 3 none any Details

Total release size: 139.6 kB

Release files / jumpstarter_driver_mitmproxy-0.9.0.tar.gz

Download URL jumpstarter_driver_mitmproxy-0.9.0.tar.gz
Size 78.3 kB
Tags Source
SHA-256 checksum
How to use checksums
45b60028b45ad65d986142a965733d320f685ebf404fd7383a30961fd4f23b2b
BLAKE2b-256 checksum
How to use checksums
e9fd5ad73a7f9d4bef7af3a8add6f429ed87ab75d41ae10fe917767efb99d2ab
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.8.22

Release files / jumpstarter_driver_mitmproxy-0.9.0-py3-none-any.whl

Download URL jumpstarter_driver_mitmproxy-0.9.0-py3-none-any.whl
Size 61.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b5208387ef500cad2f6990c58dd3af6142fe3d8c746d460fac21f66cfd534d06
BLAKE2b-256 checksum
How to use checksums
eda818e3256528e864bc5d7443c77c472c43322027bf3d751ec2a02e6b130635
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.8.22

Release history Release notifications | RSS feed

This release

0.9.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page