You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
test(process-container): realign stale UI policy, captureDenials and clipboard probe tests - #1393
Nightly process-container jobs fail ~114 assertions that encode behavior two merged PRs changed, not product regressions.
[docs/test] Clarify desktopSystemControl policy behavior #1368 established that a permissive UI knob only omits the matching JOB_OBJECT_UILIMIT bit — it never grants the operation. Only the desktopSystemControl docs were updated. The UI policy tests still asserted an undocumented "grant" floor, so it failed wherever the host denied a capability independently. Replaced with a measurement: a permissive baseline learns what is reachable, and only the allow direction is relaxed for what is not. The block direction stays strict everywhere.
Fail unavailable guarded denial capture before sandbox creation #1290 removed the captureDenials fallback — with no capture provider the request now fails before the sandbox exists. P15a asserted the removed behavior; it now detects both providers via wxc-exec --probe and asserts the documented outcome.
The clipboard read probe seeded from the host, but the clipboard is per-window-station, so the seed never reached the contained process. It now seeds the clipboard under test in-process and keeps the seed's owner window alive across the read. Under ui.clipboard=read, only ERROR_ACCESS_DENIED FAILs the test — nothing can legally seed that clipboard, since the only writer is the one the policy blocks. Under ui.clipboard=all, the seeded clipboard must be able to be read and match the seed to PASS.
Docs: propagated the #1368 caveat to clipboard/systemSettings, and noted that the os-version matrix tracks flag availability, not granted behavior.
Hosts that deny a UI capability outright regardless of policy (e.g. clipboard on 23H2/24H2/25H2) are now recorded as skips rather than containment failures, since a host-level denial says nothing about the UILIMIT mapping.
Probe behavior verified standalone (host-seeded, empty, and self-seeded clipboards) and on a prerelease-process-container arm64 host, where all eight P4e clipboard cases now pass — including the blocked control cases that confirm enforcement still surfaces as ERROR_ACCESS_DENIED.
The nightly process-container jobs fail ~114 assertions that encode
behavior two merged PRs changed, not product regressions.
PR #1368 established that a permissive UI knob only omits the
corresponding JOB_OBJECT_UILIMIT bit; it never grants the operation.
That is mechanism-general, but only the desktopSystemControl section was
updated, so the UI policy matrix still asserted an undocumented "grant"
floor and failed wherever the host denies a capability independently.
Replace that assertion with a measurement. Measure-UiGrantable runs a
fully permissive baseline to learn which capabilities are reachable on
this host, and the per-knob cases skip only the allow direction for
capabilities that are not. The block direction stays strict everywhere:
an operation that succeeds under a deny expectation is still a failure.
A baseline that does not report on every tag records a failure and gates
nothing, so coverage is never dropped silently.
Phase 4b now parses INCONCLUSIVE instead of collapsing it to <missing>.
PR #1290 removed the captureDenials fallback: where no capture provider
is available the request fails before the sandbox is created. Detect
both providers via wxc-exec --probe and assert that documented outcome
instead of the removed one. The guarded provider resolves plm.exe next
to the loaded module, so probe it from the debug binary the suites
actually run. Capture assertions that need a live session now skip when
no provider exists.
Propagate the #1368 caveat to the clipboard and systemSettings sections,
and note that the os-version matrix tracks flag availability rather than
granted behavior.
Two failure clusters are deliberately left out of scope and are now
reported honestly rather than as containment defects: the hostLoopback
rejection-detection gap, and the clipboard read probe seeding, which
cannot work from the host because the clipboard is per-window-station.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…nd trip
Requiring a readable round trip to call the read path allowed is a
stronger precondition than some hosts can satisfy. On a prerelease
process-container host both permissive cases failed it for different
reasons: with the write limit set the self-seed is refused and the
container's clipboard is genuinely empty (formats=0, gle=1168), and
without it the seed lands but the data handle comes back unreadable
(formats=4, gle=6).
Neither call was refused. JOB_OBJECT_UILIMIT_READCLIPBOARD denies with
ERROR_ACCESS_DENIED, so treat any other failure as the limit being
absent and report it as such. The clipboard=none and clipboard=write
cases are the standing control for that denial, and both still pass on
the affected host.
INCONCLUSIVE now means only that OpenClipboard itself was denied, which
is an environment denial the harness already skips, so drop the branches
that classified a missing seed.
Also trim the comments added by the two preceding commits.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
READCLIPBOARD reports allowed when GetClipboardData was not refused,
which establishes the UILIMIT mapping but not the read path. Recording
that as a plain PASS named "READCLIPBOARD=allowed" reads as a verified
round trip and drops the probe diag that says otherwise.
Record it as a warn carrying the diag. The run still does not fail: the
mapping under test is correct, and the blocked direction is untouched.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The read probe destroyed the seed's owner window before reading the data
back. This process pumps no messages, so WM_RENDERALLFORMATS and
WM_DESTROYCLIPBOARD go unhandled and the data can become unreadable
while the format list still advertises it -- which is what a
prerelease process-container host reported: formats=4 from a seed that
succeeded, and GetClipboardData failing with ERROR_INVALID_HANDLE.
Return the owner from the seed and destroy it only after the read, so a
single run writes and reads back the same clipboard with the owner
alive throughout. Failure paths still tear it down immediately.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The UI policy matrix dropped each tag's DIAG line unless the result was
a warn or a skip, so a passing case said only "got=blocked" and gave no
record of how the probe reached that verdict. Append the diagnostic to
every recorded detail when the probe emitted one.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
JOB_OBJECT_UILIMIT_READCLIPBOARD denies with ERROR_ACCESS_DENIED, so any
other outcome means the limit did not refuse the call -- which is what a
permissive policy asserts. Warning when the probe additionally could not
read text back held the allow direction to a round trip the policy does
not promise, and under ui.clipboard=read nothing can legally seed that
clipboard: the only writer is the one the policy blocks.
The recorded detail carries the probe diagnostic either way, so the
distinction stays visible without failing to report a green result.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Updates the process-container UI policy and capture-denials tests/probes to distinguish “limit not set” from “capability actually exercisable on this host”, reducing false failures and improving diagnostics.
Changes:
UI policy matrix: measure which UI operations are grantable on the host under a permissive policy and skip allow-direction assertions that are undecidable.
UI mitigations: treat INCONCLUSIVE probe results as “not exercised” and skip those assertions with diagnostics.
Capture-denials: detect native/guarded capture provider availability and skip or assert the correct branch based on host capability; improve clipboard probing robustness and update docs accordingly.
CloseClipboard was resolved optionally while OpenClipboard was called
unconditionally, so an unresolvable CloseClipboard would leave the
clipboard open for the rest of the process. The probe runs several tags
per invocation, so that would break every later clipboard tag in the
same run. Resolve it up front with the other required entry points and
close unconditionally.
Escape the tag before interpolating it into the DIAG match so the
pattern stays an exact tag match.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Scenario A is exclusively the blocked-direction control, but this turns every INCONCLUSIVE verdict into a non-failing skip. That weakens the existing enforcement check and conflicts with the PR's claim that the block direction stays strict; an unexercised limit should keep this assertion red rather than allowing the nightly suite to pass without confinement evidence.
Treat inconclusive baselines as failed measurements
An INCONCLUSIVE baseline is currently recorded as “host denies” because every token other than FAIL maps to $false. For example, a transient OpenClipboard failure emits READCLIPBOARD=INCONCLUSIVE; this then causes later allow-direction assertions to be skipped even though the baseline never established a host denial. Treat inconclusive baseline results as a failed measurement and leave the map empty so subsequent cases remain strict.
Keep block-direction checks strict for inconclusive results
This branch also skips INCONCLUSIVE results when $want is blocked, contradicting the stated invariant that only allow-direction checks are relaxed and block-direction checks remain strict. Restrict this exception to allowed expectations; otherwise an all-bits enforcement regression can become a skip whenever the probe reports an inconclusive precondition.
… is allowed
ui.clipboard=all permits the probe to seed the clipboard it reads, so
accepting "the limit did not refuse the call" left the read path itself
unasserted: a seeded-but-unreadable handle still passed. That is exactly
the ERROR_INVALID_HANDLE failure this branch fixes, which the suite
would not have caught.
Opt the clip-all case into requiring the seeded text to come back. A
refused seed stays a skip, since the WRITECLIPBOARD assertion already
owns that and there is nothing to read. ui.clipboard=read cannot take
this requirement -- the only writer is the one that policy blocks.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The read probe only checked that GetClipboardData returned a non-null
handle, but reported "returned clipboard text" -- claiming more than it
verified. Lock the handle while the clipboard is still open, decode the
UTF-16, and compare it to the seed, so the round trip ui.clipboard=all
requires is an actual content match rather than handle liveness.
Contents are never echoed: on a shared window station they can belong to
the host user, so a mismatch reports only its length.
The verdict is unchanged in every case. A handle that does not match the
seed still means the limit did not refuse the call.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
📖 Description
Nightly process-container jobs fail ~114 assertions that encode behavior two merged PRs changed, not product regressions.
desktopSystemControlpolicy behavior #1368 established that a permissive UI knob only omits the matchingJOB_OBJECT_UILIMITbit — it never grants the operation. Only thedesktopSystemControldocs were updated. The UI policy tests still asserted an undocumented "grant" floor, so it failed wherever the host denied a capability independently. Replaced with a measurement: a permissive baseline learns what is reachable, and only the allow direction is relaxed for what is not. The block direction stays strict everywhere.captureDenialsfallback — with no capture provider the request now fails before the sandbox exists. P15a asserted the removed behavior; it now detects both providers viawxc-exec --probeand asserts the documented outcome.ui.clipboard=read, only ERROR_ACCESS_DENIED FAILs the test — nothing can legally seed that clipboard, since the only writer is the one the policy blocks. Underui.clipboard=all, the seeded clipboard must be able to be read and match the seed to PASS.Docs: propagated the #1368 caveat to
clipboard/systemSettings, and noted that the os-version matrix tracks flag availability, not granted behavior.Hosts that deny a UI capability outright regardless of policy (e.g. clipboard on 23H2/24H2/25H2) are now recorded as skips rather than containment failures, since a host-level denial says nothing about the UILIMIT mapping.
🔗 References
desktopSystemControlpolicy behavior #1368 — the behavior changes these suites had drifted fromhostLoopbackproduct issue🔍 Validation
cargo fmt --all -- --checkcargo clippy -p wxc_ui_probe --all-targets -- -D warningscargo build -p wxc_ui_probetests/scripts/**/*.ps1Probe behavior verified standalone (host-seeded, empty, and self-seeded clipboards) and on a prerelease-process-container arm64 host, where all eight P4e clipboard cases now pass — including the
blockedcontrol cases that confirm enforcement still surfaces asERROR_ACCESS_DENIED.✅ Checklist
Cargo.lock, thedependency-feed-checkcheck passes (see docs/pull-requests.md)📋 Issue Type