Repository navigation
ProcessContainer: let an identity-less proxy run under PSEC 1.0 - #1373
Carlos Alexandro Becker (caarlos0) wants to merge 4 commits into
Conversation
An unpackaged, non-AppContainer proxy had to send `network.ingress.hostLoopback: "allow"`. That value raises the request to PSEC contract 1.1 with ingress support, so a host whose BaseContainer reports only PSEC 1.0 could not use `runtimeConfig.networkProxy` at all. The parser refused the `"deny"` spelling, and the capability that authorizes the loopback connection was granted only beside `"allow"`, so no caller could reach its proxy on such a host. The grant belongs to the proxy identity, not to the host-loopback setting. `networkLoopback` and the reserved `MXC-Loopback` peer now follow `identity_less_proxy`: a proxy with no `allowedProxyPeer`. `hostLoopback` keeps its own meaning -- `"allow"` additionally requests the bidirectional contract and its PSEC 1.1 host requirement, while `"deny"` keeps the configured endpoint alone under the PSEC 1.0 capability mapping. WFP endpoint scoping is unchanged in both, so the client still reaches only the proxy. The posture an identity-scoped proxy must keep is untouched: `hostLoopback: "allow"` beside `allowedProxyPeer` is still refused, and every proxy still requires `ingress.default: "allow"`. The bidirectional half does not work today in any case: on Windows build 26691.1002, host-to-container listener connections time out in proxy mode, as docs/process-container/networking.md records. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>
There was a problem hiding this comment.
Warning
Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.
Copilot review overview
Review effort: Lite
Findings: 1
Open (1)
What changed in this PR
Enables an identity-less ProcessContainer proxy to run on hosts limited to PSEC 1.0 by decoupling loopback authorization from network.ingress.hostLoopback, while preserving the stricter identity-scoped behavior and updating docs/tests accordingly.
Changes:
- Allow identity-less proxies (
runtimeConfig.networkProxywithoutallowedProxyPeer) to use eitherhostLoopback: "allow"or"deny"; keep identity-scoped proxy requiringhostLoopback: "deny". - Grant
networkLoopbackcapability + reservedMXC-Loopbackpeer based on “identity-less proxy” detection (proxy enabled + no peer), not onhostLoopback. - Update documentation and the PowerShell harness assertion to validate that the PSEC 1.0-shaped config actually reaches the proxy endpoint.
| File | Description |
|---|---|
| tests/scripts/run_processcontainer_network_proxy_test.ps1 | Updates the P8e harness to assert reachability for identity-less proxy with hostLoopback=deny. |
| src/core/wxc_common/src/network_parser.rs | Loosens proxy policy validation for identity-less proxies; adds targeted unit tests. |
| src/core/wxc_common/src/config_parser.rs | Updates schema parsing tests to accept identity-less proxy with denied host loopback. |
| src/backends/process_container/common/src/base_container_helpers/tests.rs | Adds tests asserting PSEC 1.0 mapping behavior for identity-less proxies and no-loopback leakage without proxy. |
| src/backends/process_container/common/src/base_container_helpers.rs | Introduces identity_less_proxy() and uses it to add loopback capability/peer for identity-less proxies. |
| docs/schema.md | Updates schema prose to reflect hostLoopback meaning for identity-less proxies. |
| docs/sandbox-policy/0.8.0/networking/networking.md | Updates sandbox policy docs for PSEC 1.0 vs 1.1 behavior with identity-less proxies. |
| docs/process-container/os-version-support.md | Documents PSEC 1.0 host behavior for identity-less proxy posture. |
| docs/process-container/networking.md | Updates ProcessContainer networking docs to reflect the new semantics and PSEC version constraints. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Preserve main's non-blank allowedProxyPeer requirement and the PR's identity-less PSEC 1.0 proxy support. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: d20acabb-2367-4261-b346-2d7ed8995896 Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>
There was a problem hiding this comment.
Warning
Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.
Copilot review overview
Review effort: Lite
Findings: 1
Open (1)
Resolved since last review (1)
Carlos Alexandro Becker (caarlos0)
left a comment
There was a problem hiding this comment.
Automated review by Copilot of 573e0f7. No confirmed production-code defect found; two follow-ups concern coverage and conflicting documentation. The independent premise check confirms a real parser/version-selection dead end for identity-less proxies on PSEC 1.0 hosts.
No local builds or tests were run, as requested; build status is assumed green, not independently verified. Actual PSEC 1.0 endpoint confinement remains unverified. The capability-order complaint has no current nondeterministic mechanism and does not need a change.
This is a comment-only review because the authenticated reviewer is also the PR author.
| $noLoopback = Invoke-NetRun -Name 'net-proxy-identityless-no-loopback' -ConfigPath $cfgNoLoopback | ||
| Record-Result -Phase 'P8e' -Name 'identity-less proxy without hostLoopback=allow is rejected' ` | ||
| -Pass (Test-WasRejected $noLoopback) ` | ||
| -Detail "exit=$($noLoopback.Result.ExitCode); timedOut=$($noLoopback.Result.TimedOut); doc requires hostLoopback=allow when allowedProxyPeer is omitted" | ||
| Record-Result -Phase 'P8e' -Name 'identity-less proxy with hostLoopback=deny reaches the proxy endpoint' ` | ||
| -Pass ($noLoopback.Verdict -eq 'REACHED') ` | ||
| -Detail ("verdict=$($noLoopback.Verdict); endpoint=127.0.0.1:$port; " + | ||
| 'this shape carries the proxy on a host without PSEC 1.1 ingress support') |
There was a problem hiding this comment.
[P2] Check endpoint rejection with the new denied-loopback configuration. On a PSEC 1.0-only host, the earlier hostLoopback=allow workload cannot start, so lines 142-154 skip the direct-egress assertion. This new case then checks only REACHED. The Rust IPv4/IPv6 rejection tests also require PSEC 1.1 and use allow. Thus the new configuration has no test that would detect access to another endpoint, even if this assertion passes.
Reuse assert_proxy_endpoint_only with hostLoopback=deny and PSEC 1.0-compatible gating. Require success at the configured proxy and access denial at another live IPv4/IPv6 listener; keep launch failure distinct from denial. Run that case on an identified PSEC 1.0 host. This is a coverage gap, not a confirmed bypass.
Address endpoint-rejection feedback by reusing the live IPv4/IPv6 listener checks with hostLoopback=deny and PSEC 1.0 gating. Preserve explicit access-denied checks and launch failure diagnostics. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: d20acabb-2367-4261-b346-2d7ed8995896 Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>
Address setup-guidance feedback across the shared policy, schema, backend and OS-version guides. Distinguish the PSEC 1.1 ingress prerequisite from the identical proxy capability/peer mapping, and retain the documented inbound limitation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: d20acabb-2367-4261-b346-2d7ed8995896 Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>
Carlos Alexandro Becker (caarlos0)
left a comment
There was a problem hiding this comment.
Automated incremental review by Copilot of 573e0f7..8701818: no new findings.
The documentation finding is addressed and its thread is resolved. The P2 code-coverage gap is also addressed: the new test uses the real backend with hostLoopback=deny, gates on PSEC 1.0 rather than 1.1 ingress, and requires proxy success plus WSAEACCES at other live IPv4 and IPv6 endpoints. Launch failure cannot count as denial.
I am leaving P2 open for the remaining target-host evidence, consistent with its latest reply: a non-skipped run on an identified PSEC 1.0-only Windows host has not been supplied. No local builds or tests were run, as requested. This is a comment-only review because the authenticated reviewer is also the PR author.
There was a problem hiding this comment.
Warning
Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.
Copilot review overview
Review effort: Lite
Findings: 2
Open (3)
Resolved since last review (1)
Branden Bonaby (bbonaby)
left a comment
There was a problem hiding this comment.
I'm not sure this is what we want. Machines that have PSEC 1.0 will be updated with 1.1 this month and will get the changes regardless. Making them "deny" is actually still not accurate because they can talk to anyone on the localhost at that port. So, saying it's denied isn't really accurate.
In the allowedProxyPeer case when they give us an appcontainer profile name or package family name the OS will actually do a check that the thing the container is attempting to communicate with on the loopback is the actual allowedProxyPeer they gave us. We can't do that in the uncontained proxy case, so that's why they need to opt into this "no security guarantee other than only loopback network traffic allowed at this port".
This new case that you're adding, gives consumers a false sense of security that deny in this case means anything. It would be better to update how allow works in this case to account for machines that may be on the older PSEC 1.0. I would prefer to keep deny to mean the consumer has a stronger security guarantee, and allow host loopback to mean they've opted into this less security networking mode.
|
superseded by #1406 |


📖 Description
An unpackaged, non-AppContainer proxy previously required
network.ingress.hostLoopback: "allow". That setting requires PSEC 1.1 withingress support, so an identity-less proxy could not run on a PSEC 1.0-only host.
This change accepts
hostLoopback: "deny"for an identity-less proxy and grantsnetworkLoopbackand the reservedMXC-Loopbackpeer based on proxy identity,not the host-loopback setting. The configured proxy endpoint remains unchanged.
hostLoopback"allow""deny"Both settings serialize the same proxy capability and peer and omit native
ingress.
"deny"does not remove a separately encoded bidirectional grant.Other features, such as enumeration-only filesystem grants, can still require
PSEC 1.1.
Unchanged: identity-scoped proxies require a non-blank
allowedProxyPeerand
hostLoopback: "deny". Every ProcessContainer proxy requiresingress.default: "allow". Identity-less proxies must omitallowedProxyPeer.WFP endpoint scoping is unchanged; no AppContainer fallback is added.
Limitations: the backend guide records that proxy-mode host-to-container
connections time out on Windows build 26691.1002. Requesting
"allow"does notmake that direction work. The denied-loopback path still needs native
confinement evidence from an identified PSEC 1.0-only host.
Merged
mainthrough 298bb39 in 573e0f7 without discarding upstream'sblank-peer rejection. Follow-up commits a893cc8 and 8701818 add denied-loopback
IPv4/IPv6 confinement coverage and correct the remaining setup guidance.
🔗 References
proxy on a PSEC 1.0-only host.
BackendCapability::IngressHostLoopbackAllow, which distinguisheshosts that support the ingress prerequisite.
docs/process-container/networking.md,docs/process-container/os-version-support.md,docs/schema.md, anddocs/sandbox-policy/0.8.0/networking/networking.md.🔍 Validation
Original validation reported before the merge, on a Windows host with PSEC 1.1
ingress support:
cargo test -p wxc_common --libcargo test -p process_container_common --libcargo fmt --all --checkThe original report identifies
base_container_helpers::tests::runtime_proxy_preserves_allowed_host_to_container_loopbackas a pre-existing failure (
os error 10060), reproduced on the parent commit.That native comparison has not been repeated from the current macOS environment.
Follow-up validation on macOS:
cd src && cargo fmt --all -- --checkgit diff --checkgit diff --cached origin/main --checkcargo test -p process_container_common --lib runtime_proxy_with_denied_host_loopback_confines_ipv4_and_ipv6 -- --nocapture(fromsrc/)Local builds, Rust tests, and Clippy were deferred because system load exceeded
the local validation limit. The PowerShell backend harness was not run on macOS.
New coverage:
runtime_proxy_with_denied_host_loopback_confines_ipv4_and_ipv6: reuses theexisting live-listener helper with
hostLoopback: "deny"and PSEC 1.0 gating.It requires a successful proxy connection and WSAEACCES (
10013) from anotherlive IPv4/IPv6 listener. Launch failure, timeout, refusal, and unexpected
success do not count as policy denial. Existing PSEC 1.1 cases remain intact.
The P8e harness case checks that the denied-loopback request reaches the proxy.
The new Rust native test adds the missing endpoint-rejection coverage.
Pending: run that test on an identified PSEC 1.0-only Windows host and record
its build, PSEC support, and result. A skipped test is not confinement evidence;
the corresponding review thread remains unresolved.
✅ Checklist
Cargo.lock, thedependency-feed-checkcheck passes (see docs/pull-requests.md)📋 Issue Type
GitHub Actions runs the PR validation build automatically. The ADO pipeline
(
MXC-PR-Build) is the Azure version of the PR pipeline, kept in parity with the GitHubActions build; it runs on merge to
main, and Microsoft reviewers with write access can trigger iton a PR with
/azp run. See docs/pull-requests.md.If the
dependency-feed-checkcheck fails on a new dependency, the crate must be added tothe feed before the PR can pass. See docs/pull-requests.md
for the steps.
Microsoft Reviewers: Open in CodeFlow