fix(mxc): harden governed proxy lifecycle (NVBug 6783325) - #3472
prekshivyas wants to merge 2 commits into
Conversation
Qualification before/after summaryNVBug: 6783325 — MXC host-proxy activation/lifecycle does not match explicit policy Before: Explicit allow and deny/no-match policies started a listener and injected proxy variables, but the no-network-policy case incorrectly did the same. Mock lifecycle skipped the real listener and successful startup had no durable log. After: Explicit allow and deny/no-match retain governed proxy startup; the no-network-policy case has no listener, proxy credentials, or proxy environment. Real ARM64 lifecycle proof confirmed listener ownership and cleanup. Results include 94 unit + 57 integration tests, 4,942 Windows ARM64 tests passed with 26 skipped, mock 4/4, and the signed real-MXC matrix passing. Qualification status: Focused scenario PASS; full combined qualification pending. A full two-cycle OpenClaw qualification should run after combining/rebasing this change with #3434. Hosted CI also requires a maintainer |
shailendra-nv
left a comment
There was a problem hiding this comment.
Requesting changes for the two inline findings below. The proxy activation test and startup log are valuable, but the empty-policy gate must not silently change mixed-config egress from loopback-only to unrestricted. Please also align the relay qualification documentation with the new non-proxy configuration. For NVBug 6783325, the PR should be treated as observability/regression hardening: the explicit-policy production path already worked on the base revision, and the original clean-exit reproduction still removes the listener after AgentCompleted.
| policy: Option<&SandboxPolicy>, | ||
| ) -> Result<Option<SocketAddr>, tonic::Status> { | ||
| let configured = configured_egress_addr(config)?; | ||
| Ok(configured.filter(|_| policy_activates_governed_egress(policy))) |
There was a problem hiding this comment.
Filtering the configured proxy address to None changes precedence with the existing pc_network_allow fallback. With egress_proxy=true, pc_network_allow=true, and no network rules, the base used loopback-only governed egress; this revision reaches the fallback that emits egress.default=allow. Preserve default-deny, reject the conflicting configuration, or explicitly document and test this security-sensitive behavior.
There was a problem hiding this comment.
Addressed in 8e79706. The mixed configuration now fails closed during sandbox validation: when egress_proxy = true and pc_network_allow = true, a policy without explicit network rules returns InvalidArgument before lifecycle startup instead of falling through to unrestricted defaultPolicy = "allow". empty_network_policy_rejects_unrestricted_fallback covers that branch. I also run the explicit deny/no-match lifecycle case with pc_network_allow = true; it remains proxy-backed with network.egress.default = deny, so explicit governed policies retain their existing precedence. The full native ARM64 workspace passed: 4,943 passed, 26 skipped.
| egress_proxy_addr = "127.0.0.1:18080" | ||
| # No governed Internet egress is needed. The relay reaches the driver's | ||
| # on-demand loopback listener through privateNetworkClientServer above. | ||
| egress_proxy = false |
There was a problem hiding this comment.
This configuration now disables egress_proxy and relies on privateNetworkClientServer, but companion qualification comments still say mxc-ws-gateway.toml enables the proxy and that the relay connects through it (run-ws-agent-test.ps1, relay.rs, and mxc-ws-agent.rs). Update those references so qualification attributes connectivity to the correct mechanism.
There was a problem hiding this comment.
Addressed in 8e79706. I updated all three named references (run-ws-agent-test.ps1, relay.rs, and mxc-ws-agent.rs) plus clarified mxc-ws-gateway.toml: this qualification path connects directly to the route-selected private-interface relay listener through privateNetworkClientServer; governed egress and the host CONNECT proxy are not involved. The PowerShell parser check and the complete MXC package suite pass.
|
Implemented both requested changes in 8e79706:
Validation after the review update:
I also reframed the title/description as observability and regression hardening, explicitly noting that current-base explicit-policy startup and clean-exit listener removal already worked. |
Signed-off-by: Prekshi Vyas <prekshiv@nvidia.com>
Signed-off-by: Prekshi Vyas <prekshiv@nvidia.com>
119aa9f to
8e79706
Compare
Summary
Observability and regression hardening for NVIDIA NVBug 6783325. An explicit
network_policiesrule activates governed egress, while a policy with no network rules leaves the host listener and proxy environment absent; the lifecycle also emits a successful startup log and the mock path exercises the real host proxy.The headline "explicit policy never starts" symptom no longer reproduces on the current
windowstip: explicit rules already created a real listener and injected proxy variables, and a normally completed one-shot workload removed the listener afterAgentCompleted. The patch makes those contracts durable because the default/no-network-policy case still activated the proxy unconditionally, successful startup was not logged, and the mock lifecycle explicitly skipped listener startup.Base:
fb2980e077288b61ef03a2e6187e162d158526aa(origin/windows, re-fetched immediately before commit).Related Issue
NVIDIA NVBug 6783325. No public GitHub issue required; this is a localized Windows MXC bug fix.
NVBug 6782969 remains separate. This PR does not change policy matching or enforcement and sends no request through the deny/no-match scenario.
Root Cause
egress_proxy = truealone produced a per-sandbox proxy address, MXC loopback redirect, credentials, and proxy environment for every policy, including policies without network rules.start_host_proxy, so tests could observe redirect/env serialization but could not catch a missing host listener or verify cleanup.Changes
egress_proxy + pc_network_allowwhen no explicit network rules exist, preventing a silent unrestricted-egress fallback; explicit mixed policies remain proxy-backed and default-deny.Exact Before/After Evidence
Environment: Yukon Windows 10.0.28000 ARM64, native Rust 1.95.0
aarch64-pc-windows-msvc, signed Microsoftwxc-exec.exe0.8.0 (DDE1C592270E9A659B01DCCAD70362DA7B99FEC114885FA4D625507AA775A503). Workloads printed only presence markers; proxy credentials and values were not logged.Unmodified base, gateway PID 25388:
127.0.0.1:51990; env count 17 withHTTP_PROXY=SET/HTTPS_PROXY=SET; no successful startup log; stop completed in 67 ms and closed the listener.allowed.invalid:443): Ready; listener127.0.0.1:65434; the same proxy env markers; stop/delete cleaned up.127.0.0.1:60489and injected the same 17-variable proxy environment.host_proxyunder mock, and the default case unexpectedly had a proxy address.Patched commit, gateway PID 32012, identical policies/config/workload:
MXC host egress proxy started sandbox=n6783325-allow3 address=127.0.0.1:59127; listener owned by the gateway; env count 17 with both proxy markers; stop completed in 61 ms and the listener was gone after 250 ms.127.0.0.1:50743; listener/env present; stop/delete cleaned up.Security Impact
This narrows exposure: policies without explicit network governance no longer receive a host loopback listener, per-sandbox proxy credential, broad loopback MXC allowance, or proxy environment. A conflicting unrestricted
pc_network_allowfallback is rejected synchronously instead of weakening that boundary. Explicit governed egress remains fail-closed on startup/mapping errors. Provider credential resolution still requires bothegress_proxyand an explicit network policy. No permissions or policy-enforcement rules are broadened.Testing
mise run pre-commitpasses981files).grpcio-toolsfrom source: MSVC rejects upstream/std:c++17plus/std:c11flags.cargo test -p openshell-driver-mxc --target aarch64-pc-windows-msvc: 95 unit + 57 integration tests passed; 12 real-MXC tests ignored by the normal suite.mise run --skip-tools windows:test:arm64: 4,943 passed, 26 skipped, zero failures.cargo fmt --all -- --check,git diff --check, PowerShell parser check: passed.Additional infrastructure notes:
windows:check:arm64reachedz3-sysbut the configured prebuilt Z3 download returned HTTP 403.wxc-execprobe hung; only this PR's queued wrapper was canceled. The direct signed-MXC matrix above completed and is the scenario-specific real-runtime proof.Residual Risk / Platform Limits
Checklist