fix(smolmachines): use bridge gateway as TSI proxy host on Linux
On Linux the guest kernel's LOCAL routing table routes all 127.0.0.0/8 to the guest's own loopback interface (priority 0, checked before any main-table route), so TSI never sees connections to the per-bottle loopback alias — the fix_guest_ loopback_routing approach confirmed this at the kernel level. Use the per-bottle docker bridge gateway (192.168.N.1) instead. It is not a loopback address, so the guest routes it via eth0 and TSI intercepts it normally. The TSI allowlist remains a /32 that is distinct from the container IP (192.168.N.2), so direct bypass to egress:9099 is still blocked by TSI. Changes: - Add _proxy_host() helper: returns bundle_gateway on Linux, loopback alias on macOS - Thread proxy_host through _start_bundle, _discover_urls, _launch_vm, and _bundle_launch_spec (publish_host_ip) - Remove _fix_guest_loopback_routing (no longer needed) - Relax proxy-URL assertion in the integration test to accept any http://IP:port (with a comment explaining the difference) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -21,13 +21,14 @@ security properties the design pivot was about:
|
||||
bind-address mitigation is what closes TSI's port-granularity
|
||||
gap.
|
||||
|
||||
Gated on macOS + smolvm + docker + not GITEA_ACTIONS — the
|
||||
Gated on macOS/Linux + smolvm + docker + not GITEA_ACTIONS — the
|
||||
runner can't host libkrun-backed VMs."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import platform
|
||||
import re
|
||||
import shutil
|
||||
import tempfile
|
||||
import unittest
|
||||
@@ -65,8 +66,8 @@ def _minimal_manifest() -> ManifestIndex:
|
||||
|
||||
@skip_unless_docker()
|
||||
@unittest.skipUnless(
|
||||
platform.system() == "Darwin",
|
||||
"smolvm is macOS-only for v1; Linux+KVM path is a future PRD",
|
||||
platform.system() in ("Darwin", "Linux"),
|
||||
"smolvm requires macOS or Linux",
|
||||
)
|
||||
@unittest.skipUnless(
|
||||
_smolvm_available(),
|
||||
@@ -141,7 +142,15 @@ class TestSmolmachinesLaunch(unittest.TestCase):
|
||||
proxies = [line.strip() for line in r.stdout.splitlines()]
|
||||
self.assertEqual(2, len(proxies), proxies)
|
||||
self.assertEqual(proxies[0], proxies[1], proxies)
|
||||
self.assertTrue(proxies[0].startswith("http://127."), proxies[0])
|
||||
# macOS: proxy binds to the per-bottle loopback alias (127.x.x.x) so
|
||||
# TSI can intercept guest connections to it. Linux: the guest kernel
|
||||
# routes 127.0.0.0/8 to its own loopback (TSI never sees those), so
|
||||
# the proxy instead binds to the per-bottle bridge gateway (192.168.x.1)
|
||||
# which routes via eth0 and is intercepted by TSI normally.
|
||||
self.assertRegex(
|
||||
proxies[0], r"^http://\d+\.\d+\.\d+\.\d+:\d+$",
|
||||
"expected proxy URL to be an http://IP:port address",
|
||||
)
|
||||
|
||||
r = self.bottle.exec(
|
||||
"curl -fsS --max-time 20 https://example.com >/dev/null && echo OK"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
exercised against the real binary.
|
||||
|
||||
The full machine-lifecycle round trip (create → start → exec →
|
||||
delete) is gated behind macOS + Darwin platform check and lives
|
||||
delete) is gated behind macOS/Linux platform check and lives
|
||||
in chunk 2d's smoke. This file just verifies `is_available()`
|
||||
correctly reports presence and `_smolvm()` can run a no-op
|
||||
subcommand without errors — enough to flag wrapper drift if
|
||||
@@ -23,8 +23,8 @@ from bot_bottle.backend.smolmachines.smolvm import is_available
|
||||
"skipped under act_runner: smolvm not installed on the runner",
|
||||
)
|
||||
@unittest.skipUnless(
|
||||
platform.system() == "Darwin",
|
||||
"smolvm is macOS-only for v1; Linux+KVM path is a future PRD",
|
||||
platform.system() in ("Darwin", "Linux"),
|
||||
"smolvm requires macOS or Linux",
|
||||
)
|
||||
@unittest.skipUnless(
|
||||
is_available(),
|
||||
|
||||
Reference in New Issue
Block a user