Phase 3 PR 39 — LiveStackFixture skip-with-reason for elevated shells #38

Merged
dohertj2 merged 2 commits from phase-3-pr39-elevated-shell-skip into v2 2026-04-18 19:31:31 -04:00
Owner

Operationally-confusing failure mode I hit during the PR 38 install workflow: an elevated PowerShell window can't connect to the OtOpcUaGalaxyHost named pipe, even when the user is in the pipe's allow list. The pipe ACL (decision #76 / PipeAcl.cs) explicitly denies Administrators, so the elevated token's Admins group membership trumps the user's allow rule. The probe surfaces it as UnauthorizedAccessException which is technically correct but takes about five steps to diagnose ('the user IS in the allow list, why?').

What changes

LiveStackFixture.InitializeAsync now runs an early Windows-only check via WindowsPrincipal.IsInRole(WindowsBuiltInRole.Administrator) and short-circuits with a SkipReason that names the cause directly:

Test host is running with elevated (Administrators) privileges, but the OtOpcUaGalaxyHost named-pipe ACL explicitly denies Administrators per the IPC security design (decision #76 / PipeAcl.cs). Re-run from a NORMAL (non-admin) PowerShell window — even when your user is already in the pipe's allow list, the elevated token's Admins group membership trumps the allow rule.

The pre-existing ParityFixture (PR 18) already does the same thing for the same reason. LiveStackFixture (PR 37) didn't — this matches it.

Why before the prereq probe

AvevaPrerequisites.CheckAllAsync includes a 2s named-pipe probe that hits the same admin-deny and surfaces UnauthorizedAccessException with no context. Short-circuiting earlier saves the 10-second probe + produces a single actionable line.

Tests

Verified manually from an elevated bash session against the just-installed OtOpcUaGalaxyHost service — skip message reads as quoted above. Proxy.Tests Unit: 17 / 0 unchanged (fixture change is non-breaking; existing tests don't run as admin in normal CI).

Bonus

Gitignored .local/ so per-install secrets (the Galaxy.Host shared-secret file written during the install workflow) don't leak into the repo.

Operationally-confusing failure mode I hit during the PR 38 install workflow: an elevated PowerShell window can't connect to the `OtOpcUaGalaxyHost` named pipe, even when the user is in the pipe's allow list. The pipe ACL (decision #76 / `PipeAcl.cs`) explicitly **denies Administrators**, so the elevated token's Admins group membership trumps the user's allow rule. The probe surfaces it as `UnauthorizedAccessException` which is technically correct but takes about five steps to diagnose ('the user IS in the allow list, why?'). ## What changes `LiveStackFixture.InitializeAsync` now runs an early Windows-only check via `WindowsPrincipal.IsInRole(WindowsBuiltInRole.Administrator)` and short-circuits with a SkipReason that names the cause directly: > Test host is running with elevated (Administrators) privileges, but the OtOpcUaGalaxyHost named-pipe ACL explicitly denies Administrators per the IPC security design (decision #76 / PipeAcl.cs). Re-run from a NORMAL (non-admin) PowerShell window — even when your user is already in the pipe's allow list, the elevated token's Admins group membership trumps the allow rule. The pre-existing `ParityFixture` (PR 18) already does the same thing for the same reason. `LiveStackFixture` (PR 37) didn't — this matches it. ## Why before the prereq probe `AvevaPrerequisites.CheckAllAsync` includes a 2s named-pipe probe that hits the same admin-deny and surfaces `UnauthorizedAccessException` with no context. Short-circuiting earlier saves the 10-second probe + produces a single actionable line. ## Tests Verified manually from an elevated bash session against the just-installed `OtOpcUaGalaxyHost` service — skip message reads as quoted above. Proxy.Tests Unit: **17 / 0** unchanged (fixture change is non-breaking; existing tests don't run as admin in normal CI). ## Bonus Gitignored `.local/` so per-install secrets (the Galaxy.Host shared-secret file written during the install workflow) don't leak into the repo.
dohertj2 added 2 commits 2026-04-18 19:31:29 -04:00
PR 39 closes the gap. New IsElevatedAdministratorOnWindows static helper (Windows-only via RuntimeInformation.IsOSPlatform; non-Windows hosts return false and let the prerequisite probe own the skip-with-reason path) checks WindowsPrincipal.IsInRole(WindowsBuiltInRole.Administrator) on the current process token. When true, InitializeAsync short-circuits to a SkipReason that names the cause directly: 'elevated token's Admins group membership trumps the allow rule — re-run from a NORMAL (non-admin) PowerShell window'. Catches and swallows any probe-side exception so a Win32 oddity can't crash the test fixture; failed probe falls through to the regular prerequisite path.
The check fires BEFORE AvevaPrerequisites.CheckAllAsync runs because the prereq probe's own pipe connect hits the same admin-deny and surfaces UnauthorizedAccessException with no context. Short-circuiting earlier saves the 10-second probe + produces a single actionable line.
Tests — verified manually from an elevated bash session against the just-installed OtOpcUaGalaxyHost service: skip message reads 'Test host is running with elevated (Administrators) privileges, but the OtOpcUaGalaxyHost named-pipe ACL explicitly denies Administrators per the IPC security design (decision #76 / PipeAcl.cs). Re-run from a NORMAL (non-admin) PowerShell window — even when your user is already in the pipe's allow list, the elevated token's Admins group membership trumps the allow rule.' Proxy.Tests Unit: 17 pass / 0 fail (unchanged — fixture change is non-breaking; existing tests don't run as admin in normal CI flow). Build clean.
Bonus: gitignored .local/ directory (a previous direct commit on local v2 that I'm now landing here) so per-install secrets like the Galaxy.Host shared-secret file don't leak into the repo.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
dohertj2 merged commit 976e73e051 into v2 2026-04-18 19:31:31 -04:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: dohertj2/lmxopcua#38