Skip to content

Fail closed on unavailable capture process identities - #854

Merged
coneilen merged 1 commit into
scgopi:mainfrom
coneilen:coneilen-identity-acquisition-guard
Oct 17, 2026
Merged

coneilen merged 1 commit into
scgopi:mainfrom
coneilen:coneilen-identity-acquisition-guard

Conversation

@coneilen

Copy link
Copy Markdown
Collaborator

Summary

Refs #849. Fail closed with typed evidence when a Windows capture process's Handle or Id is unavailable, before native Snapshot argument binding. Preserve strict identity, ownership, kernel-exit and EOF requirements without attributing either historical occurrence to a proven disposal or exit race.

Changes

  • Add shared explicit Handle/Id acquisition, independently retaining getter failures and distinguishing actually acquired PID evidence from expected PID context. Reject null, invalid and mismatched values without inventing an identity.
  • Route capture snapshot entry points through that boundary, retain primary and secondary launch/rollback failures, and use retained PID evidence or UNAVAILABLE in failure formatting. Unavailable cleanup remains pending/unproven and cannot authorize a kill or a genuinely-gone conclusion.
  • Add seven registered self-process/synthetic identity contracts, preserving the prior 88 real-seed cases and original 59-case inventory. Ordinary and real-seed expectations are now 92 and 95; update the exact capture caller count and related documentation.

Test plan

RED: pwsh -NoProfile -NonInteractive -File D:\gi49m1\attempt2\Invoke-IdentityRed.ps1 -> exit 1; 3 executed, 1 valid-self passed, 2 typed-contract failures on unchanged 206a; actual Get-CapProcessIdentity Snapshot binder: Cannot convert null to type "System.IntPtr".
GREEN: pwsh -NoProfile -NonInteractive -File Tools\windows\Tests\UiCaptureDriver.Tests.ps1 -IdentityContractOnly -ScratchRoot D:\gi49m1\serial-identity\suite -> exit 0; 7 unique executed, 7 passed, 0 failed, including the same two actual unavailable-object cases and valid-self control.
REGRESSION: pwsh -NoProfile -File D:\gi49m1\Invoke-849IdentityQualification.ps1 -RunRoot D:\gi49 -ExpectedControllerSha256 3760D662667FF1B46D056422EF6A874123C14AE6B6528FB7B5EBF6FA234843EE -RuntimeDeadlineUtc '2026-10-17T04:34:05.1636709+00:00' -OuterDeadlineUtc '2026-10-17T05:01:04.0842125Z' -> exit 0; 95 unique executed, 95 passed, 0 failed; original 88 and original 59 preserved, job 0/0/0 before Close, both actual EOFs.

Actual RED and scope. Fresh not-started and disposed wrappers for the RED host's own process reached the actual unchanged Get-CapProcessIdentity:1610 Snapshot binder, before the C# method body. Getter probes ran after the fault, not before it. Adapted Handle/Id reads returned null; explicit getters retained their InvalidOperationException. The valid self control established a live kernel/CIM generation. Controlled disposal is not evidence that either historical #849 occurrence was caused by disposal. The historical local conhost and CI compiler-discovery occurrences remain two observed events with an unknown denominator and unobserved getter/exit ordering.

Serial focused regression. These three fresh hosts ran strictly serially, each completing with its positive report before the next started:

pwsh -NoProfile -NonInteractive -File Tools\windows\Tests\UiCaptureDriver.Tests.ps1 -IdentityContractOnly -ScratchRoot D:\gi49m1\serial-identity\suite
# exit 0; 7/7; 04:00:59.6977522Z to 04:01:07.6009419Z
pwsh -NoProfile -NonInteractive -File Tools\windows\Tests\UiCaptureDriver.Tests.ps1 -SelectorRefusalContractOnly -ScratchRoot D:\gi49m1\serial-selector\suite
# exit 0; 13/13; 04:01:25.5483227Z to 04:01:44.9872506Z
pwsh -NoProfile -NonInteractive -File Tools\windows\Tests\UiCaptureDriver.Tests.ps1 -FixtureContractOnly -JournalTimingContractOnly -JournalFirstOpenContractOnly -JournalObservationContractOnly -ScratchRoot D:\gi49m1\serial-journal\suite
# exit 0; 5/5; 04:01:57.9733315Z to 04:02:12.1361749Z

Preserved failed attempts, not a rerun-to-green claim. Initial parallel focused hosts on module 03533F1EE9B2F2584692E6A6C2D7D0C387C310F6A579772C981629028EB38C50 / tests 682E3EAE0F370C9020DE40CC882A539029BDE32CCB62EBD61CB800375C9FAFFF passed 7/7, 13/13 and 5/5. A later parallel round on final module 1CC3A3E844433C34919942A88B2224A792787AD105F37EC76D8EC54B301CDF34 / tests DEC19578183875CA7146F696CD569E8EAE131DC8065EE39587499776CF8C1796 passed identity 7/7 but failed selector 12/13 and setup 4/5. The retained selector error was the existing reserved-worker-deadline exception rather than the asserted terminal-timeout wording; the journal hit its unchanged 1000 ms deadline after seven Opens, before an expected eighth. Protected source and assertions were unchanged. One explicitly admitted serial diagnostic then passed on that identical final source. This does not prove parallel execution caused the elapsed gaps.

The first private RED attempt had a report-schema harness failure and produced no accepted RED report; the accepted RED is attempt2 above. A coordinator-provided historical receipt basename typo, an out-of-range private-controller source read, and the file-only seal's null console projection are retained tooling/display failures, not native passing evidence. The persisted seal JSON, actual exit and retained reports provide the evidence. No failure log was overwritten.

Contained qualification. The one admitted full run precompiled both actual C fixtures before the added suite job, bound all 14 artifacts, retained the exact kill-on-close-only helper, assigned the gated generation before targets, and completed all 95 cases. All 33 release records were checked, including 10 clean/expected-failure final proofs and 10 canonical-LAST worker stdout bindings. Both real zmx phases ran in each of the three real cases. Eight frozen control sources were rehashed after the run, with the native helper checked separately as the ninth current pin. There was no owned vctip exemption, cleanup-as-green fallback, in-suite native fixture compilation fallback, or new native rerun.

The retained COMPLETE journals contain 95 concrete bound publications in total, not a fixed historical 96. In real-seed-normal, the current terminal sequence is 24 versus prior 25: the second before-phase cmd member was first journaled at cleanup rather than at both readiness and cleanup. Readiness still requires at least one daemon and one cmd and journals every returned member; cleanup journals every member. Both runs retain 13 final generation-bound entries and every required stage. Why the earlier readiness census differed is unobserved. The new unavailable-access path propagates failure; it does not silently skip a required publication.

Independent source review. One fresh claude-sonnet-5.5, HIGH, background reviewer 7cff3a13-1558-42a2-b6ef-e6472fc5eeab accepted the delta. Its initial response disclosed an unread test-diff tail; the same reviewer completed that tail and confirmed all five diffs were fully read, retaining ACCEPT. This was one review, not a replacement/rejection chain. The reviewer performed static reads only, not tests, source hashing or independent inventory counting. Saved UTF-8/LF response copies are not claimed to be raw reviewer-event bytes.

Preservation and limits. Native Snapshot/PInvoke source, selector/journal function text and worker wait behavior are unchanged. PID, creation, image, parent/session, current-CIM, ownership, kernel-exit, attempt/deadline and both-EOF gates remain strict. Unavailable properties or absent CIM never prove death. No macOS test, product GUI, keyboard, screenshot, accessibility, parity or live B evidence is claimed. New-head Windows 2022 and Windows 2025 required checks, no-real-JournalUnavailable/no-#846-shape gates, and a separately authorized live B lease remain future requirements.

Retained evidence. Actual RED: D:\gi49m1\attempt2\red-report.json SHA CE2B6FDF503598EACE0ED403420F9F7DD7829D8AB6921E3EE575AD1C15F1F7FB. Full report: D:\gi49\suite\report.json SHA 2DB4CA42AD0FBB30EC20DE5BA0911C8887742547D87F2CA3CE6871FF9365573B. Owner file-only seal: D:\gi49m1\full-file-only-seal.json SHA 8476E85EB7AA8D9242BD600D49E422E1DE56C235EB14A87D536F80FD601B392F. Root retained proof SHA 35F3671ADAE823177CBB99071603A1781ECD5E6E7DF6B2F6E9A1DBBB271D321B. Initial/follow-up review copy SHAs A115076C1817C6EE56CE073BFE0DE8B6A5FCA58364D00386F25B272A5F6C3F6A / F8301CF1F9D5C6DA3C0496E1343F9B191470264EF0A62E653F0C9A0A2D3E5FA7.

The canonical commit message carries exactly one DCO sign-off, one Copilot App co-author and one CLI session trailer. The admitted git commit -F path omitted -s to avoid duplicating the already-present sign-off. make test and make check were not run on this Windows host; their checklist items remain unchecked.

Checklist

  • I have read the Contributing Guidelines
  • I have signed off my commits (git commit -s) per the DCO
  • Tests pass locally (make test)
  • Code follows the existing style (make check)
  • I added the test/contract before the implementation and observed the intended RED failure

Refuse unavailable Process Handle/Id with typed evidence before native
Snapshot binding, preserve strict ownership checks, and retain primary
and rollback failures without re-reading unavailable properties.

Refs scgopi#849

Signed-off-by: Colin Neilens <coneilen@microsoft.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 7b4629f5-b061-46dd-99f7-9c2cf0ef4132
@coneilen
coneilen marked this pull request as ready for review October 17, 2026 05:14
@coneilen
coneilen merged commit 02a504b into scgopi:main Oct 17, 2026
25 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant