fix(sandbox): add managed loopback proxy#1501
Conversation
|
@ericksoa I see this maps back to something for Discord in NemoClaw but can you expand on the requirement a bit more and the use case? |
|
Good question. The OpenShell requirement here is not Discord-specific; Discord/OpenClaw is just the first concrete client that exposed the gap. The generic use case is: a sandboxed app or SDK needs to use an HTTP CONNECT proxy, but the app will only accept a loopback proxy URL such as The Discord case is a good example because OpenClaw's Discord Gateway client ignores So the intended OpenShell contract is:
That gives clients with strict localhost proxy requirements a standard OpenShell affordance, while keeping the security boundary and protocol handling in one place. |
|
For the concrete downstream context, the dependent NemoClaw PR is NVIDIA/NemoClaw#4005: NVIDIA/NemoClaw#4005 That PR consumes this OpenShell affordance by preferring |
|
Ok, understood on the use case. So the listener is placed on the sandbox loopback but then after The better impl is to keep only the loopback listener in the sandbox network namespace and then hand the accepted client socket back to code that's running in the supervisor network namesapce before DNS, policy handling, cred rewrite and upstream dialing. |
|
Thanks, agreed. I updated the PR to encode that model directly:
I also added a focused E2E proof: it starts a host-side test server, applies a policy allowing that host/port through the proxy, verifies a direct sandbox socket to the same target is refused, then verifies CONNECT through The downstream consumer remains NVIDIA/NemoClaw#4005. |
Summary
OPENSHELL_LOOPBACK_PROXY_URL.setns(), binds127.0.0.1:<port>, accepts client sockets, and hands accepted sockets out.HTTP_PROXY/HTTPS_PROXYbehavior unchanged for ordinary proxy-aware clients, and keep the implementation generic with no Discord-specific routing or credential logic.Feedback Addressed
crates/openshell-sandbox/src/proxy.rs: sandbox-netns acceptor vs. supervisor dispatcher.e2e/rust/tests/loopback_proxy_netns.rsto prove the boundary behavior: a direct sandbox socket to the host-side target is rejected, while CONNECT throughOPENSHELL_LOOPBACK_PROXY_URLreaches the same target successfully.Validation
cargo fmt --all -- --checkrustfmt --edition 2024 --check e2e/rust/tests/loopback_proxy_netns.rsgit diff --checkcargo check -p openshell-sandboxcargo clippy -p openshell-core -p openshell-sandbox --all-targets -- -D warningscargo clippy --manifest-path e2e/rust/Cargo.toml --features e2e-docker --test loopback_proxy_netns -- -D warningscargo test -p openshell-sandbox apply_loopback_proxy_env_exposes_managed_url_without_changing_proxy_vars --libcargo test -p openshell-sandbox websocket --libcargo test -p openshell-sandbox --test websocket_upgradeDOCKER_HOST=unix://$HOME/.colima/default/docker.sock TMPDIR=<workspace tmp> PREBUILT_AUTO_STAGE=0 OPENSHELL_E2E_DOCKER_TEST=loopback_proxy_netns bash e2e/rust/e2e-docker.shDOCKER_HOST=unix://$HOME/.colima/default/docker.sock TMPDIR=<workspace tmp> PREBUILT_AUTO_STAGE=0 OPENSHELL_E2E_DOCKER_TEST=websocket_conformance bash e2e/rust/e2e-docker.shNotes:
cargo fmt --manifest-path e2e/rust/Cargo.toml --all -- --checkcurrently reports pre-existing rustfmt drift across the standalone e2e crate, so the new E2E file was checked directly withrustfmt.zig/cargo-zigbuild; the Colima runs used an existing Linux arm64 supervisor prebuilt from the prior PR head. The new head changes the loopback implementation names/comments and adds the proof test; CI should build the current-head supervisor normally.