sand-boxer/scripts/smoke-bwrap-egress.py
tegwick d477c3b5d9
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
feat: enforce owner allowlisted bwrap HTTPS egress
Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a0726e-5232-73f2-aaca-2c05ceb62efb
2026-09-05 22:08:18 +02:00

89 lines
2.9 KiB
Python

"""Non-secret HTTPS reachability and denied egress proof."""
import json
import tempfile
from pathlib import Path
from sandboxer.extensions.bwrap import BwrapExtension
from sandboxer.models import Profile
PROBE = r"""
import json, os, socket, ssl, urllib.request, urllib.error
from pathlib import Path
proxy = os.environ['HTTPS_PROXY']
# GET without any credential: TLS and a provider HTTP response suffice.
client = urllib.request.build_opener(urllib.request.ProxyHandler({'https': proxy}))
try:
response = client.open('https://api.anthropic.com/', timeout=20)
status = response.status
response.close()
except urllib.error.HTTPError as error:
status = error.code
assert 100 <= status <= 599
try:
client.open('https://example.com/', timeout=5)
except (urllib.error.URLError, OSError):
denied = True
else:
raise AssertionError('undeclared destination reachable')
try:
socket.create_connection(('1.1.1.1',443),timeout=2)
except OSError:
direct_denied = True
else:
raise AssertionError('direct network reachable')
interfaces = Path('/proc/net/dev').read_text().splitlines()[2:]
assert [line.split(':')[0].strip() for line in interfaces] == ['lo']
print(json.dumps({'provider_http_status':status, 'tls_verified':True,
'undeclared_host_denied':denied, 'direct_network_denied':direct_denied}))
"""
def main():
with tempfile.TemporaryDirectory(prefix="sandboxer-egress-proof-") as directory:
extension = BwrapExtension(
{
"base_dir": directory,
"allowed_egress": ["api.anthropic.com:443"],
"ro_binds": ["/usr", "/bin", "/lib", "/lib64", "/etc/ssl/certs"],
}
)
profile = Profile(
id="profile.egress-proof",
version="1",
extension="ext.bwrap",
network={"default": "deny", "egress": ["api.anthropic.com:443"]},
)
handle = extension.provision(profile, {}, "localhost")
try:
extension.wait_ready(handle)
result = extension.execute(
handle,
["python3", "-c", PROBE],
credential_route_refs=[],
execution_context={},
timeout_seconds=40,
max_output_bytes=4096,
)
finally:
teardown = extension.teardown(handle)
assert result["exit_code"] == 0, result
assert teardown["workspace_removed"] == "True"
assert not Path(handle["egress_dir"]).exists()
assert not extension._pid_alive(int(handle["egress_pid"]))
print(
json.dumps(
{
"sandbox_id": handle["sandbox_id"],
"proof": json.loads(result["stdout"]),
"proxy_removed": True,
"workspace_removed": True,
"model_call": False,
},
indent=2,
)
)
if __name__ == "__main__":
main()