Compare commits
3 Commits
phase-3-pr
...
phase-3-pr
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8fb3dbe53b | ||
|
|
a61e637411 | ||
| e4885aadd0 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -29,3 +29,4 @@ packages/
|
|||||||
# Claude Code (per-developer settings, runtime lock files, agent transcripts)
|
# Claude Code (per-developer settings, runtime lock files, agent transcripts)
|
||||||
.claude/
|
.claude/
|
||||||
|
|
||||||
|
.local/
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Runtime.Versioning;
|
||||||
|
using System.Security.Principal;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
@@ -40,6 +43,25 @@ public sealed class LiveStackFixture : IAsyncLifetime
|
|||||||
|
|
||||||
public async ValueTask InitializeAsync()
|
public async ValueTask InitializeAsync()
|
||||||
{
|
{
|
||||||
|
// 0. Elevated-shell short-circuit. The OtOpcUaGalaxyHost pipe ACL allows the configured
|
||||||
|
// SID but explicitly DENIES Administrators (decision #76 — production hardening).
|
||||||
|
// A test process running with a high-integrity token (any elevated shell) carries the
|
||||||
|
// Admins group in its security context, so the deny rule trumps the user's allow and
|
||||||
|
// the pipe connect returns UnauthorizedAccessException — technically correct but
|
||||||
|
// the operationally confusing failure mode that ate most of the PR 37 install
|
||||||
|
// debugging session. Surfacing it explicitly here saves the next operator the same
|
||||||
|
// five-step diagnosis. ParityFixture has the same skip with the same rationale.
|
||||||
|
if (IsElevatedAdministratorOnWindows())
|
||||||
|
{
|
||||||
|
SkipReason =
|
||||||
|
"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.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// 1. AVEVA + OtOpcUa service state — actionable diagnostic if anything is missing.
|
// 1. AVEVA + OtOpcUa service state — actionable diagnostic if anything is missing.
|
||||||
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10));
|
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10));
|
||||||
PrerequisiteReport = await AvevaPrerequisites.CheckAllAsync(
|
PrerequisiteReport = await AvevaPrerequisites.CheckAllAsync(
|
||||||
@@ -111,6 +133,28 @@ public sealed class LiveStackFixture : IAsyncLifetime
|
|||||||
{
|
{
|
||||||
if (SkipReason is not null) Assert.Skip(SkipReason);
|
if (SkipReason is not null) Assert.Skip(SkipReason);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static bool IsElevatedAdministratorOnWindows()
|
||||||
|
{
|
||||||
|
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) return false;
|
||||||
|
return CheckWindowsAdminToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
[SupportedOSPlatform("windows")]
|
||||||
|
private static bool CheckWindowsAdminToken()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var identity = WindowsIdentity.GetCurrent();
|
||||||
|
return new WindowsPrincipal(identity).IsInRole(WindowsBuiltInRole.Administrator);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// Probe shouldn't crash the test; if we can't determine elevation, optimistically
|
||||||
|
// continue and let the actual pipe connect surface its own error.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[CollectionDefinition(Name)]
|
[CollectionDefinition(Name)]
|
||||||
|
|||||||
Reference in New Issue
Block a user