Files
bot-bottle/tests/unit/test_egress_entrypoint.py
T
didericis c07ebca867
lint / lint (push) Successful in 1m54s
test / unit (pull_request) Successful in 58s
test / integration (pull_request) Successful in 18s
test / coverage (pull_request) Failing after 1m3s
feat(backend): remove smolmachines; firecracker is the Linux default
Delete the smolmachines backend (the whole bot_bottle/backend/smolmachines
package and its tests). It had fatal Linux issues (TSI networking under
sustained use, exec-channel contention, no SIGWINCH) and is superseded by
the Firecracker backend (issue #342).

Backend selection now:
- default is macos-container on macOS, firecracker on KVM-capable Linux
  hosts, and docker as the last resort (was smolmachines).
- firecracker is selected on a KVM host even when the `firecracker`
  binary isn't installed, so start routes through its preflight and
  prints an install pointer (same UX as require_container), instead of
  silently falling back. Split is_host_capable() (Linux + KVM) out of
  is_available() (adds the binary check) to drive this.

Retarget the cross-backend tests (parity, print-parity, prepare,
workspace, freezer, selection) from smolmachines to firecracker rather
than dropping the coverage. Remove docker.util.image_id/save, which only
smolmachines used. Update README/AGENTS/example bottles and stale
comments; historical docs/prds are left as a point-in-time record.

BREAKING: BOT_BOTTLE_BACKEND=smolmachines now errors as unknown.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WBMWTEtQdJ4W5UrWuLHCck
2026-07-11 13:24:47 -04:00

99 lines
3.3 KiB
Python

"""Unit: egress_entrypoint.sh argv construction (PRD 0023 chunk 3).
The egress entrypoint is a small POSIX-sh script that builds
the mitmdump argv from env vars. A VM backend (e.g. firecracker)
controls egress's bind address via EGRESS_LISTEN_HOST; the
docker backend leaves it unset and gets mitmdump's default
(all interfaces).
We can't easily unit-test a shell script as Python, but we can
run it under `sh -x` with mitmdump stubbed to print its argv,
which is exactly what these tests do."""
from __future__ import annotations
import os
import subprocess
import tempfile
import unittest
from pathlib import Path
_SCRIPT = (
Path(__file__).resolve().parent.parent.parent
/ "bot_bottle" / "egress_entrypoint.sh"
)
def _run_entrypoint(env: dict[str, str]) -> str:
"""Run egress_entrypoint.sh with a stubbed mitmdump that
prints its argv. Returns the argv as a single string.
The script uses `exec mitmdump ...`. We shim by prepending a
fake `mitmdump` to PATH; the shim writes its argv to stdout
and exits 0."""
with tempfile.TemporaryDirectory() as tmp:
shim_dir = Path(tmp)
shim = shim_dir / "mitmdump"
shim.write_text(
"#!/bin/sh\n"
'printf "%s\\n" "$@"\n'
)
shim.chmod(0o755)
run_env = {
"PATH": f"{shim_dir}:{os.environ['PATH']}",
# cat needs to find ca-certificates.crt for the
# trust-bundle branch; we don't test that path here.
**env,
}
result = subprocess.run(
["sh", str(_SCRIPT)],
capture_output=True, text=True, env=run_env,
check=True,
)
return result.stdout
class TestEgressEntrypointArgv(unittest.TestCase):
def test_default_mode_regular_no_listen_host(self):
# No env set: --mode regular@9099 + no --listen-host.
argv = _run_entrypoint({})
self.assertIn("--mode\nregular@9099", argv)
self.assertNotIn("--listen-host", argv)
# Confdir always present.
self.assertIn(
"--set\nconfdir=/home/mitmproxy/.mitmproxy",
argv,
)
def test_listen_host_127_0_0_1_emits_flag(self):
# A VM backend sets EGRESS_LISTEN_HOST=127.0.0.1
# to scope egress to localhost inside the bundle.
argv = _run_entrypoint({"EGRESS_LISTEN_HOST": "127.0.0.1"})
self.assertIn("--listen-host\n127.0.0.1", argv)
def test_listen_host_unset_emits_no_flag(self):
# Docker backend leaves it unset and gets mitmdump's
# default bind address (all interfaces).
argv = _run_entrypoint({"EGRESS_LISTEN_HOST": ""})
self.assertNotIn("--listen-host", argv)
def test_upstream_mode_combined_with_listen_host(self):
# VM-backend mode also sets EGRESS_UPSTREAM_PROXY so
# both flags should compose correctly.
argv = _run_entrypoint({
"EGRESS_UPSTREAM_PROXY": "http://192.168.50.2:8888",
"EGRESS_LISTEN_HOST": "127.0.0.1",
})
self.assertIn("--mode\nupstream:http://192.168.50.2:8888", argv)
self.assertIn("--listen-port\n9099", argv)
self.assertIn("--listen-host\n127.0.0.1", argv)
def test_addon_always_loaded(self):
argv = _run_entrypoint({})
self.assertIn("-s\n/app/egress_addon.py", argv)
if __name__ == "__main__":
unittest.main()