Skip to content

Add guarded WPR captureDenials fallback - #813

Merged
Richie Gomez (richiemsft) merged 54 commits into
mainfrom
v2-wpr-capture-fallback
Aug 17, 2026
Merged

Add guarded WPR captureDenials fallback#813
Richie Gomez (richiemsft) merged 54 commits into
mainfrom
v2-wpr-capture-fallback

Conversation

@richiemsft

@richiemsft Richie Gomez (richiemsft) commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

📖 Description

Adds a secure processContainer.captureDenials fallback for Windows hosts where the complete native PSEC plus V2 Learning Mode capability set cannot honor the requested policy.

Native capture remains preferred when PSEC, V2 Learning Mode, and request-specific capabilities are available. Otherwise MXC selects the highest compatible legacy containment tier—SBOX, AppContainer+BFS, or AppContainer+DACL—and pairs it with the guarded WPR capture session. Proxy and least-privilege policies that PSEC cannot represent route to the compatible legacy path rather than weakening policy.

MXC uses a privilege-separated, brokered elevation model. The main executor and public plm.exe process remain unelevated, and a session-scoped UAC-elevated helper is launched only when privileged guarded WPR capture is required. The helper performs a fixed set of WPR control and analysis operations and returns bounded results over an authenticated named pipe.

The guarded fallback builds on the PLM architecture refactored in #760 rather than introducing a separate capture or decoding stack. It reuses PLM's asInvoker front end, retained elevated guardian, embedded WPR profile, protected scratch and recovery state, authenticated bounded control channel, and learning_mode_windows::EtlDenialAnalyzer canonical decoder. This PR extends that foundation with sandbox job/process-handle attachment, exact descendant lifetime tracking, and a bounded analysis response that feeds the same canonical DenialsDocument output as native capture.

The guarded path:

  • Uses the same canonical denial analyzer and DenialsDocument output as native captureDenials.
  • Supports block collection through learningModeLogging and allow/audit collection through permissiveLearningMode.
  • Starts WPR before the suspended sandbox root resumes.
  • Authenticates the unelevated owner and duplicates its sandbox job and root-process handles.
  • Opens, job-validates, and retains a handle for every descendant reported by the job completion port.
  • Filters host-wide WPR denial events using exact process creation/exit times from those retained handles, preventing PID reuse from expanding capture scope.
  • Checks ordered job notifications and TotalProcesses accounting, with a 4096-generation bound.
  • Gives the tracker worker independent owned job and completion-port handles. Shutdown posts a sentinel and joins the worker; if bounded waits expire, the guardian fail-stops rather than detaching or releasing handles still in use.
  • Keeps raw ETL in protected elevated scratch and returns only bounded canonical denial data.
  • Preserves a protected recovery marker on uncertain guardian or pipe failure without issuing blind host-wide WPR cancellation.
  • Stops and discards owned traces on definite launch, tracking, or analysis failures.

Runtime resolution locates plm.exe relative to wxc-exec.exe or the loaded mxc_ffi module rather than the caller's working directory. Before elevation, MXC opens the helper with sharing that denies replacement, resolves the pinned object to a stable local DOS path, verifies Authenticode against the pinned handle, requires the embedded signer organization to be Microsoft Corporation, and validates the owner and DACL of the containing directory and its ancestors. The pinned handle remains open across ShellExecuteExW, and the resolved path is launched, preventing file replacement and path-alias check/launch races. The elevated child restricts runtime DLL resolution to System32 and fails closed if that hardening cannot be applied.

Windows artifact packaging, ESRP signing/verification, and SDK package assertions are defined in #834. Unsigned local helpers and helpers in user-writable locations are intentionally rejected, so guarded-WPR end-to-end execution requires a signed packaged plm.exe in a protected directory. This also applies to Rust SDK source consumers whose module-relative lookup resolves beside a locally compiled executable; native PSEC capture remains available when supported.

🔗 References

🔍 Validation

  • cargo fmt --all -- --check
  • cargo test -p plm --lib -p mxc_engine — 218 passed, 1 ignored.
  • cargo clippy -p plm -p mxc_engine --all-targets -- -D warnings
  • Release builds of wxc-exec.exe and plm.exe.
  • Windows VM: native PSEC/V2 block capture produced canonical denial output.
  • Windows VM guarded fallback:
    • Guarded SBOX block and allow capture passed.
    • Forty short-lived descendants completed without an attestation race.
    • Nonzero sandbox exit code 23 was preserved.
    • A 4100-process workload failed closed at the 4096-generation bound.
    • Successful and bounded-failure paths left no WPR recording, recovery marker, PLM process, or incomplete denial output.
  • The runtime signature gate requires an official signed artifact from Package and sign PLM with Windows binaries #834 for signing-dependent VM validation; unofficial PR artifacts are intentionally unsigned and rejected.

✅ Checklist

📋 Issue Type

  • Bug fix
  • Feature
  • Task

Richie Gomez (richiemsft) and others added 23 commits August 7, 2026 13:21
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 52e48fee-23e1-4b05-803c-522812fcdda2
Forward audit workload exit codes, avoid policy previews from truncated analysis, and retain the legacy current-directory exclusion in the temporary adjusted-config adapter.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 52e48fee-23e1-4b05-803c-522812fcdda2
Store newly added PLM files with repository-standard LF endings so whitespace validation reports the actual content cleanly.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 52e48fee-23e1-4b05-803c-522812fcdda2
Normalize non-verbatim Win32 output aliases during collision checks and keep metadata-only READ_CONTROL denials from producing content-access grants.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 52e48fee-23e1-4b05-803c-522812fcdda2
Compare existing outputs by filesystem identity, fail closed when identity cannot be examined, normalize default-stream aliases, and preserve canonical workload self-access filtering.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 52e48fee-23e1-4b05-803c-522812fcdda2
Use Windows ordinal Unicode case comparison for output collision checks and discard partial capability matches from malformed DACL records.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 52e48fee-23e1-4b05-803c-522812fcdda2
Compare complete paths when both self-access operands use the same namespace, and only use volume-relative matching for mixed DOS and device paths.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 52e48fee-23e1-4b05-803c-522812fcdda2
Inspect missing leaves without following reparse points so dangling links remain unexaminable, and make unknown identity dominate an absent counterpart during collision checks.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 52e48fee-23e1-4b05-803c-522812fcdda2
Keep the PLM collision hardening in the Windows resolver without changing Unix filesystem-object semantics or tests.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 52e48fee-23e1-4b05-803c-522812fcdda2
Pass the workload exit code using Clap's equals syntax so timeout and error values such as -1 reach plm stop without being parsed as options. Add regression coverage for positive and negative exit codes.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 52e48fee-23e1-4b05-803c-522812fcdda2
Run the public PLM process under the caller token and elevate only authenticated fixed WPR control operations. Transfer ETL data over bounded local pipes, use protected ProgramData scratch storage, and retain a guarded elevated start child for owner-death cleanup and explicit post-stop disarm.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 52e48fee-23e1-4b05-803c-522812fcdda2
Record the asInvoker public helper, restricted self-elevation, authenticated pipe transfer, protected scratch storage, and guarded lifecycle in the repository Copilot instructions.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 52e48fee-23e1-4b05-803c-522812fcdda2
Preserve abandoned mutex ownership, disarm guarded capture immediately after ETL transfer, and normalize case-insensitive verbatim UNC paths.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 52e48fee-23e1-4b05-803c-522812fcdda2
Keep live WPR control in-process while wxc-exec owns the singleton, then run public PLM only for existing-trace analysis.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 52e48fee-23e1-4b05-803c-522812fcdda2
Add a dedicated stopped protocol frame so guarded cleanup is disabled before ETL handling, including failure-safe guardian termination.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 52e48fee-23e1-4b05-803c-522812fcdda2
Retain one elevated guardian for singleton, WPR start, stop, and cleanup. Fail closed on stale or uncertain recovery without cancelling unverified WPR sessions.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 52e48fee-23e1-4b05-803c-522812fcdda2
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 4eff3ee2-323c-494d-99b9-f7b54e495216
Use a post-authentication readiness handshake and PeekNamedPipe polling so empty connected pipes are not mistaken for disconnects. Store default audit artifacts under the caller's local app-data directory so protected installations remain writable.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 4eff3ee2-323c-494d-99b9-f7b54e495216
Use protected working directories for elevated PLM and WPR processes, and restore a bounded audit-analysis watchdog with concurrent output draining and process termination.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 4eff3ee2-323c-494d-99b9-f7b54e495216
Fail closed on uncertain WPR teardown, bound control output draining, restore path validation, and document the final recovery model.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 4eff3ee2-323c-494d-99b9-f7b54e495216
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 4eff3ee2-323c-494d-99b9-f7b54e495216
Track sandbox process lifetimes and add a bounded elevated protocol that returns process-scoped denial analysis without exposing host-wide ETL.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 4eff3ee2-323c-494d-99b9-f7b54e495216
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 4eff3ee2-323c-494d-99b9-f7b54e495216
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
There may be pipelines that require an authorized user to comment /azp run to run.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 4eff3ee2-323c-494d-99b9-f7b54e495216
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 4eff3ee2-323c-494d-99b9-f7b54e495216
@richiemsft
Richie Gomez (richiemsft) changed the base branch from refactor-plm-canonical-analyzer to main August 11, 2026 23:57
@richiemsft
Richie Gomez (richiemsft) marked this pull request as ready for review August 11, 2026 23:58
@richiemsft
Richie Gomez (richiemsft) requested a review from a team as a code owner August 11, 2026 23:58
Copilot AI balanced review requested due to automatic review settings August 11, 2026 23:58

Copilot AI commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Copilot resolve the merge conflicts in this pull request

Resolved the conflicts with current main in merge commit 1d0831d.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 30 out of 32 changed files in this pull request and generated 2 comments.

Suppressed comments (1)

docs/learning-mode/capabilities.md:139

  • The unchanged validation paragraph immediately below still says build 26657.1002 “is rejected,” contradicting this new fallback behavior and the updated OS-support document, which says that build uses legacy containment. Update this block so it distinguishes rejection of native capture from fallback of the overall request.
> **Host selection.** MXC prefers native capture on a feature-enabled Windows
> build exposing the complete official V2 API set:
> `StartLearningModeTrace`, `StopLearningModeTrace`,
> `CloseLearningModeTrace`, `CreateProcessSecurityEnvironment`,
> `QueryProcessSecurityEnvironmentSupport`, and
> `CloseProcessSecurityEnvironment`. When that set is unavailable or cannot
> fully honor the requested policy, MXC retains the highest compatible legacy
> containment tier (SBOX, AppContainer+BFS, or AppContainer+DACL) and pairs it
> with the guarded WPR capture provider. Unsupported hosts return
> `backend_unavailable` only when neither path can preserve the full policy.

Comment thread src/backends/appcontainer/common/src/appcontainer_runner.rs Outdated
Comment thread src/backends/appcontainer/common/src/base_container_runner.rs Outdated
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 4eff3ee2-323c-494d-99b9-f7b54e495216
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 4eff3ee2-323c-494d-99b9-f7b54e495216
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 4eff3ee2-323c-494d-99b9-f7b54e495216
Copilot AI review requested due to automatic review settings August 13, 2026 23:48

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 30 out of 32 changed files in this pull request and generated no new comments.

Suppressed comments (1)

src/backends/appcontainer/common/src/appcontainer_runner.rs:1825

  • Returning here permanently skips run_teardown(). Prepared does not clean these policies on drop (NetworkManager::drop only balances Winsock, and FileSystemBfsManager has no Drop), so any job-query error or five-second drain timeout leaves the run's firewall/BFS configuration installed. Preserve the enforcement ordering, but after resolving guarded-capture ownership ensure the last job handle is closed/reaped and then execute policy cleanup rather than abandoning it.
        if let Err(error) = self.kill() {
            capture_output::write_stderr_line_best_effort(format_args!(
                "failed to terminate sandbox job during drop: {error}"
            ));
            self.release_guarded_capture_after_termination_failure();
            return;

@richiemsft

Copy link
Copy Markdown
Contributor Author

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

@MGudgin Gudge (MGudgin) left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

I re-resolved this review against base b960cf5 and head 2463a29; the merge-base exactly matches the PR base, and the local/GitHub diffs are line-for-line equivalent apart from abbreviated index hashes.

I am requesting changes primarily because:

  • the new asynchronous process attestation can fail the whole sandbox when a descendant exits before the tracker opens it;
  • the security-sensitive attach/resume/discard/release failure orchestration has no runtime regression coverage;
  • a wedged guardian can block an embedding process for roughly 40 minutes before aborting it; and
  • strict job-drain failures now affect non-capture ProcessContainer runs too.

Verified clean, with receipts

  • The exact process-lifetime model records creation/exit times, enforces the 4096-generation bound, and has consumer-side PID-reuse tests.
  • Manifest changes add only in-tree workspace dependencies and existing Windows API feature gates; there are no new third-party dependencies or unrelated lockfile drift.
  • New security-sensitive modules and dependencies are Windows-gated; shared protocol/lifetime types remain portable and non-Windows paths remain fail-closed.

Body-only findings

Medium (documentation) - PLM's new production role is undocumented. README.md and src/host/plm/readme.md are byte-identical between base and head and still describe PLM strictly as an --audit developer workflow. This PR newly makes PLM the automatic production fallback for processContainer.captureDenials, so those existing statements become false because of this change. Please update both overviews.

Medium (testability) - the new job tracker has no deterministic event seam. JobProcessTracker and ProcessTrackerState are new, but directly consume live completion-port and process APIs. Extracting an injectable job-event/handle-resolver seam would allow deterministic testing of delayed notifications, rapid exits, and process-open failures. This is not independently a merge blocker, but it compounds the missing runtime coverage noted inline.

Low (maintainability) - legacy dispatcher wrappers have no production callers. The old dispatch_with_fallback and spawn_with_fallback wrappers now only delegate to the capture-aware entrypoints, and their remaining workspace callers are tests. Consider keeping one run and one spawn entrypoint that accept an optional guarded-capture factory.

Verified pre-existing or withdrawn - not attributed to this PR

  • Global\Mxc_Plm_Audit test isolation is byte-identical at base and head.
  • run_guarded_stop replacing an original error when writing the pipe response fails is byte-identical at base and head.
  • SDK packaging, ESRP signing, and package assertions are explicitly deferred to #834.
  • The original performance claims about retained process handles, 64 MB allocation, and polling were withdrawn: handle retention is a deliberate PID-reuse control, 64 MB is a validated cap rather than an eager allocation, and the cited polling was largely pre-existing.

Comment thread src/host/plm/src/elevated.rs
Comment thread src/backends/appcontainer/common/src/appcontainer_runner.rs
Comment thread src/core/mxc_engine/src/guarded_capture.rs Outdated
Comment thread src/backends/appcontainer/common/src/job_object.rs
Comment thread src/backends/appcontainer/common/src/base_container_runner.rs
Comment thread src/host/plm/src/elevated.rs Outdated
Comment thread src/backends/learning_mode/windows/src/etl_decode.rs
Comment thread src/backends/appcontainer/common/src/capture_output.rs
Comment thread src/backends/appcontainer/common/src/dispatcher.rs Outdated
Comment thread src/backends/appcontainer/common/src/dispatcher.rs Outdated
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 4eff3ee2-323c-494d-99b9-f7b54e495216
Copilot AI review requested due to automatic review settings August 14, 2026 23:19

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 31 out of 33 changed files in this pull request and generated 2 comments.

Comment thread src/core/mxc_engine/src/guarded_capture.rs
Comment thread src/host/plm/src/elevated.rs Outdated
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 4eff3ee2-323c-494d-99b9-f7b54e495216

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 34 out of 36 changed files in this pull request and generated no new comments.

Suppressed comments (2)

src/core/mxc_engine/src/guarded_capture.rs:238

  • The new fallback is wired into execution, but the public backend probe still derives CaptureDenials solely from BaseContainerRunner::is_capture_denials_usable() (src/core/mxc_engine/src/probe.rs:73-75), which only tests native PSEC/V2. On exactly the legacy hosts enabled by this change, available_backends() therefore reports that capture is unsupported even when the trusted guarded-WPR path is usable. Update the probe to include guarded fallback availability (compatible legacy tier plus a co-located binary passing the trust gate), so SDK consumers do not incorrectly disable the feature.
pub fn factory_for_request(
    request: &wxc_common::models::ExecutionRequest,
) -> Option<std::sync::Arc<dyn GuardedCaptureFactory>> {
    if request.policy.capture_denials.is_some() {
        Some(std::sync::Arc::new(PlmGuardedCaptureFactory))

docs/learning-mode/capabilities.md:144

  • This fallback description is contradicted immediately below by the retained statement that build 26657.1002 “is rejected.” The updated OS-support document says that build uses legacy containment instead of native capture, so this page now gives conflicting host behavior. Update the validation note to say the earlier native contract routes to guarded legacy capture (when that path is available).
> `CloseProcessSecurityEnvironment`. When that set is unavailable or cannot
> fully honor the requested policy, MXC retains the highest compatible legacy
> containment tier (SBOX, AppContainer+BFS, or AppContainer+DACL) and pairs it
> with the guarded WPR capture provider. Unsupported hosts return
> `backend_unavailable` only when neither path can preserve the full policy.

Comment thread src/host/plm/src/trust.rs Fixed
Comment thread src/host/plm/src/trust.rs Fixed
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 4eff3ee2-323c-494d-99b9-f7b54e495216

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 34 out of 36 changed files in this pull request and generated no new comments.

Suppressed comments (3)

src/host/plm/src/elevated.rs:638

  • Attestation races bypass the advertised 4096-generation bound: only successfully retained processes are counted at line 653, while every failed attestation increments this counter and can add another entry to unattested_active. A sandbox that rapidly creates short-lived children can therefore drive unbounded tracker state and continue well past 4096 generations. Count every observed NEW_PROCESS generation (including races and the root) toward the limit and trigger the existing terminal tracker-failure path once it is exceeded.
    src/backends/appcontainer/common/src/appcontainer_runner.rs:1168
  • Permanent guarded-provider failures (missing/untrusted plm.exe, missing WPR) reach this branch as an ordinary WxcError::Process, and spawn() later converts that to a default-phase ScriptResponse, so SDK callers receive backend_error. The updated support contract says an unavailable helper/provider returns backend_unavailable. Preserve a typed failure classification from the factory so prerequisite failures map to FailurePhase::BackendUnavailable, while transient failures such as UAC cancellation can remain launch errors.
                    Err(e) => {
                        // No active trace exists yet -- terminate the
                        // still-suspended child now, before it is ever
                        // resumed, so nothing runs unobserved.
                        job.terminate_and_wait(u32::MAX)

src/backends/appcontainer/common/src/base_container_runner.rs:2184

  • All guarded-session start failures are labeled LaunchFailed here, including deterministic host-prerequisite failures such as a missing/untrusted plm.exe or absent WPR. These consequently become backend_error, contradicting the documented backend_unavailable result when the guarded helper is unavailable. Carry a typed start error from the factory and map permanent provider/prerequisite failures to FailurePhase::BackendUnavailable, retaining LaunchFailed for transient cases such as UAC cancellation or singleton contention.
                    return Err(ScriptResponse {
                        failure_phase: FailurePhase::LaunchFailed,
                        ..ScriptResponse::error(&message)

Comment thread src/host/plm/src/trust.rs Fixed
Comment thread src/host/plm/src/trust.rs Fixed
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 4eff3ee2-323c-494d-99b9-f7b54e495216

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 34 out of 36 changed files in this pull request and generated no new comments.

Suppressed comments (3)

src/backends/appcontainer/common/src/appcontainer_runner.rs:1168

  • Guardian startup failures are flattened to WxcError::Process, and spawn() then wraps them with ScriptResponse::error (FailurePhase::None). Consequently a missing, unsigned, or untrusted plm.exe is exposed by mxc_engine::map_spawn_error as backend_error, even though the updated contract says an unavailable guarded helper is backend_unavailable. Preserve a typed BackendUnavailable result for helper discovery/trust failures while retaining launch errors for transient startup failures.
                    Err(e) => {
                        // No active trace exists yet -- terminate the
                        // still-suspended child now, before it is ever
                        // resumed, so nothing runs unobserved.
                        job.terminate_and_wait(u32::MAX)

src/backends/appcontainer/common/src/base_container_runner.rs:2185

  • This classifies every guarded-WPR start failure as LaunchFailed, including deterministic prerequisite failures such as missing or rejected plm.exe. Those cases will never succeed on retry and the updated documentation specifies backend_unavailable; preserve that phase for helper discovery/signature/trust failures, while reserving LaunchFailed for transient failures such as UAC cancellation or singleton contention.
                    return Err(ScriptResponse {
                        failure_phase: FailurePhase::LaunchFailed,
                        ..ScriptResponse::error(&message)
                    });

docs/learning-mode/capabilities.md:144

  • The immediately following paragraph still says build 26657.1002 “is rejected,” contradicting this newly documented fallback and the updated OS-version guide, which says that build uses legacy containment. Clarify that only its earlier native contract is rejected and guarded WPR is selected instead.
> `CloseProcessSecurityEnvironment`. When that set is unavailable or cannot
> fully honor the requested policy, MXC retains the highest compatible legacy
> containment tier (SBOX, AppContainer+BFS, or AppContainer+DACL) and pairs it
> with the guarded WPR capture provider. Unsupported hosts return
> `backend_unavailable` only when neither path can preserve the full policy.

@richiemsft

Copy link
Copy Markdown
Contributor Author

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

@MGudgin Gudge (MGudgin) left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verified the review updates through 4a27b4e.

  • 14 original findings are addressed.
  • The three partially addressed items and remaining Low legacy-wrapper item are accepted as non-blocking.
  • The newly identified non-ASCII trust-path normalization issue is also accepted as non-blocking for this approval.
  • cargo fmt --all -- --check passed.
  • 675 affected crate tests passed with 0 failures and 1 ignored.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Copilot-Instructions PR modifies Copilot instruction files (.github/copilot-instructions.md or .github/instructions/)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants