mirror of
https://github.com/stablyai/orca.git
synced 2026-10-18 08:03:22 +00:00
fix(ssh): settle Windows system SSH fixture lifecycle
Co-authored-by: Orca <help@stably.ai>
This commit is contained in:
@@ -1457,19 +1457,40 @@ jobs:
|
||||
$account = New-LocalUser -Name $fixtureUser -Password $password -PasswordNeverExpires `
|
||||
-UserMayNotChangePassword -AccountNeverExpires
|
||||
$userSid = $account.SID.Value
|
||||
$creatorSid = [Security.Principal.WindowsIdentity]::GetCurrent().User.Value
|
||||
$systemSid = 'S-1-5-18'
|
||||
$administratorsSid = 'S-1-5-32-544'
|
||||
|
||||
function Set-FixtureAcl([string]$Path, [string[]]$Grants, [string[]]$ExpectedSids) {
|
||||
& icacls.exe $Path /inheritance:r | Out-Host
|
||||
if ($LASTEXITCODE -ne 0) { throw "Failed to remove inherited ACLs from $Path" }
|
||||
# Why: key generation adds a creator ACE that /grant:r does not replace for other trustees.
|
||||
& icacls.exe $Path /remove "*$creatorSid" | Out-Host
|
||||
if ($LASTEXITCODE -ne 0) { throw "Failed to remove creator ACL from $Path" }
|
||||
$arguments = @($Path, '/grant:r') + $Grants
|
||||
& icacls.exe @arguments | Out-Host
|
||||
if ($LASTEXITCODE -ne 0) { throw "Failed to grant fixture ACLs on $Path" }
|
||||
function New-FixtureAclRule(
|
||||
[string]$Sid,
|
||||
[Security.AccessControl.FileSystemRights]$Rights,
|
||||
[Security.AccessControl.InheritanceFlags]$InheritanceFlags
|
||||
) {
|
||||
$identity = [Security.Principal.SecurityIdentifier]::new($Sid)
|
||||
return [Security.AccessControl.FileSystemAccessRule]::new(
|
||||
$identity,
|
||||
$Rights,
|
||||
$InheritanceFlags,
|
||||
[Security.AccessControl.PropagationFlags]::None,
|
||||
[Security.AccessControl.AccessControlType]::Allow
|
||||
)
|
||||
}
|
||||
function Set-FixtureAcl(
|
||||
[string]$Path,
|
||||
[Security.AccessControl.FileSystemAccessRule[]]$AccessRules,
|
||||
[string[]]$ExpectedSids
|
||||
) {
|
||||
$item = Get-Item -LiteralPath $Path -Force
|
||||
$security = if ($item.PSIsContainer) {
|
||||
[Security.AccessControl.DirectorySecurity]::new()
|
||||
} else {
|
||||
[Security.AccessControl.FileSecurity]::new()
|
||||
}
|
||||
# Why: replacing the DACL atomically prevents drive-specific defaults from surviving.
|
||||
$security.SetAccessRuleProtection($true, $false)
|
||||
foreach ($accessRule in $AccessRules) {
|
||||
[void]$security.AddAccessRule($accessRule)
|
||||
}
|
||||
Set-Acl -LiteralPath $Path -AclObject $security
|
||||
$acl = Get-Acl -LiteralPath $Path
|
||||
$rules = @($acl.Access)
|
||||
if (-not $acl.AreAccessRulesProtected -or @($rules | Where-Object { $_.IsInherited }).Count -ne 0) {
|
||||
@@ -1490,14 +1511,19 @@ jobs:
|
||||
& icacls.exe $Path /setowner "*$OwnerSid" | Out-Host
|
||||
if ($LASTEXITCODE -ne 0) { throw "Failed to set fixture owner on $Path" }
|
||||
}
|
||||
$systemFull = '*S-1-5-18:(OI)(CI)F'
|
||||
$administratorsFull = '*S-1-5-32-544:(OI)(CI)F'
|
||||
$noInheritance = [Security.AccessControl.InheritanceFlags]::None
|
||||
$childInheritance = [Security.AccessControl.InheritanceFlags]::ContainerInherit -bor `
|
||||
[Security.AccessControl.InheritanceFlags]::ObjectInherit
|
||||
$fixtureTrustees = @($systemSid, $administratorsSid, $userSid)
|
||||
Set-FixtureAcl $fixture @($systemFull, $administratorsFull, "*$userSid`:RX") $fixtureTrustees
|
||||
Set-FixtureAcl $fixture @(
|
||||
(New-FixtureAclRule $systemSid FullControl $childInheritance),
|
||||
(New-FixtureAclRule $administratorsSid FullControl $childInheritance),
|
||||
(New-FixtureAclRule $userSid ReadAndExecute $noInheritance)
|
||||
) $fixtureTrustees
|
||||
Set-FixtureAcl $remoteRoot @(
|
||||
$systemFull,
|
||||
$administratorsFull,
|
||||
"*$userSid`:(OI)(CI)M"
|
||||
(New-FixtureAclRule $systemSid FullControl $childInheritance),
|
||||
(New-FixtureAclRule $administratorsSid FullControl $childInheritance),
|
||||
(New-FixtureAclRule $userSid Modify $childInheritance)
|
||||
) $fixtureTrustees
|
||||
|
||||
$clientKey = Join-Path $fixture 'client-key'
|
||||
@@ -1509,14 +1535,14 @@ jobs:
|
||||
$authorizedKeys = Join-Path $fixture 'authorized_keys'
|
||||
Copy-Item -LiteralPath "$clientKey.pub" -Destination $authorizedKeys
|
||||
Set-FixtureAcl $authorizedKeys @(
|
||||
'*S-1-5-18:F',
|
||||
'*S-1-5-32-544:F',
|
||||
"*$userSid`:R"
|
||||
(New-FixtureAclRule $systemSid FullControl $noInheritance),
|
||||
(New-FixtureAclRule $administratorsSid FullControl $noInheritance),
|
||||
(New-FixtureAclRule $userSid Read $noInheritance)
|
||||
) $fixtureTrustees
|
||||
Set-FixtureOwner $authorizedKeys $userSid
|
||||
Set-FixtureAcl $hostKey @(
|
||||
'*S-1-5-18:F',
|
||||
'*S-1-5-32-544:F'
|
||||
(New-FixtureAclRule $systemSid FullControl $noInheritance),
|
||||
(New-FixtureAclRule $administratorsSid FullControl $noInheritance)
|
||||
) @($systemSid, $administratorsSid)
|
||||
Set-FixtureOwner $hostKey 'S-1-5-18'
|
||||
|
||||
@@ -1638,6 +1664,11 @@ jobs:
|
||||
$ownsFixture = Test-Path -LiteralPath (Join-Path $fixture 'fixture-owned')
|
||||
$ownsService = Test-Path -LiteralPath (Join-Path $fixture 'service-owned')
|
||||
$ownsAccount = Test-Path -LiteralPath (Join-Path $fixture 'account-owned')
|
||||
$account = if ($ownsAccount) {
|
||||
Get-LocalUser -Name $fixtureUser -ErrorAction SilentlyContinue
|
||||
} else { $null }
|
||||
$userSid = if ($account) { $account.SID.Value } else { $null }
|
||||
$profilePath = Join-Path $env:SystemDrive "Users/$fixtureUser"
|
||||
try {
|
||||
$service = Get-CimInstance Win32_Service -Filter "Name='$serviceName'" -ErrorAction SilentlyContinue
|
||||
$servicePid = if ($service) { [int]$service.ProcessId } else { 0 }
|
||||
@@ -1665,14 +1696,35 @@ jobs:
|
||||
$log = Join-Path $fixture 'sshd.log'
|
||||
if (Test-Path -LiteralPath $log) { Get-Content -LiteralPath $log -Tail 200 }
|
||||
try {
|
||||
if ($ownsAccount -and (Get-LocalUser -Name $fixtureUser -ErrorAction SilentlyContinue)) {
|
||||
if ($ownsAccount -and $userSid) {
|
||||
$escapedSid = $userSid.Replace("'", "''")
|
||||
$profileFailure = $null
|
||||
for ($attempt = 1; $attempt -le 20; $attempt += 1) {
|
||||
$profile = Get-CimInstance Win32_UserProfile -Filter "SID='$escapedSid'" `
|
||||
-ErrorAction SilentlyContinue
|
||||
if (-not $profile) { break }
|
||||
try {
|
||||
Remove-CimInstance -InputObject $profile -ErrorAction Stop
|
||||
$profileFailure = $null
|
||||
} catch {
|
||||
$profileFailure = $_.Exception.Message
|
||||
}
|
||||
Start-Sleep -Milliseconds 500
|
||||
}
|
||||
if (Get-CimInstance Win32_UserProfile -Filter "SID='$escapedSid'" `
|
||||
-ErrorAction SilentlyContinue) {
|
||||
throw "Fixture profile did not settle within 10 seconds: $profileFailure"
|
||||
}
|
||||
}
|
||||
} catch { $failures.Add("profile teardown: $($_.Exception.Message)") }
|
||||
try {
|
||||
if ($account) {
|
||||
Remove-LocalUser -Name $fixtureUser -ErrorAction Stop
|
||||
}
|
||||
} catch { $failures.Add("account teardown: $($_.Exception.Message)") }
|
||||
try {
|
||||
$profile = Join-Path $env:SystemDrive "Users/$fixtureUser"
|
||||
if ($ownsAccount -and (Test-Path -LiteralPath $profile)) {
|
||||
Remove-Item -LiteralPath $profile -Recurse -Force -ErrorAction Stop
|
||||
if ($ownsAccount -and (Test-Path -LiteralPath $profilePath)) {
|
||||
Remove-Item -LiteralPath $profilePath -Recurse -Force -ErrorAction Stop
|
||||
}
|
||||
if ($ownsFixture -and (Test-Path -LiteralPath $fixture)) {
|
||||
Remove-Item -LiteralPath $fixture -Recurse -Force -ErrorAction Stop
|
||||
@@ -1681,6 +1733,9 @@ jobs:
|
||||
if ($ownsAccount -and (Get-LocalUser -Name $fixtureUser -ErrorAction SilentlyContinue)) {
|
||||
$failures.Add('fixture account remains registered')
|
||||
}
|
||||
if ($ownsAccount -and (Test-Path -LiteralPath $profilePath)) {
|
||||
$failures.Add('fixture profile directory remains')
|
||||
}
|
||||
if ($failures.Count -gt 0) { throw ($failures -join '; ') }
|
||||
|
||||
- name: Upload unpublished artifact evidence
|
||||
|
||||
Reference in New Issue
Block a user