Files
ms-private/tests/Run-FeatureTests.ps1
T
0x000 0274e7b398
Windows tests / test-and-build (push) Canceled after 0s
Fix deferred writers and release checksums
2026-09-24 13:55:18 -04:00

162 lines
17 KiB
PowerShell

#Requires -Version 5.1
$ErrorActionPreference='Stop';Set-StrictMode -Version Latest
$root=[IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..'))
Import-Module (Join-Path $root 'src/Wind.Network.psm1') -Force
Import-Module (Join-Path $root 'src/Wind.Cleanup.psm1') -Force
Import-Module (Join-Path $root 'src/Wind.Lock.psm1') -Force
Import-Module (Join-Path $root 'src/Wind.Security.psm1') -Force
Import-Module (Join-Path $root 'src/MsPrivate.Services.psm1') -Force
Import-Module (Join-Path $root 'src/MsPrivate.Accounts.psm1') -Force
Import-Module (Join-Path $root 'src/Wind.Core.psm1') -Force
Import-Module (Join-Path $root 'src/MsPrivate.IO.psm1') -Force
Import-Module (Join-Path $root 'src/MsPrivate.Presets.psm1') -Force
Import-Module (Join-Path $root 'src/MsPrivate.Execution.psm1') -Force
$script:passed=0
function Assert-True([bool]$Condition,[string]$Message){if(-not$Condition){throw $Message};$script:passed++}
$ioRoot=Join-Path ([IO.Path]::GetTempPath()) ('ms-private-feature-'+[guid]::NewGuid().ToString('N'))
try{
$jsonPath=Join-Path $ioRoot 'state.json'
Write-MsPrivateJsonAtomic -InputObject ([pscustomobject]@{Value=1}) -Path $jsonPath
Write-MsPrivateJsonAtomic -InputObject ([pscustomobject]@{Value=2}) -Path $jsonPath
$saved=Get-Content -LiteralPath $jsonPath -Raw|ConvertFrom-Json
Assert-True ($saved.Value-eq2-and-not@(Get-ChildItem -LiteralPath $ioRoot -Filter '*.tmp' -Force).Count-and-not@(Get-ChildItem -LiteralPath $ioRoot -Filter '*.previous' -Force).Count) 'Atomic JSON replacement left stale state or temporary files.'
$probePath=Join-Path $ioRoot 'Probe.ps1';[IO.File]::WriteAllText($probePath,"param([string]`$Value) [IO.File]::WriteAllText((Join-Path `$PSScriptRoot 'probe.txt'),`$Value)",[Text.UTF8Encoding]::new($false))
$invoker=New-MsPrivateScriptInvoker -Root $ioRoot
$action=({& $invoker 'Probe.ps1' @{Value='nested-module'}}.GetNewClosure())
$invokerRun=Invoke-MsPrivateGroupPlan -Groups @([pscustomobject]@{Id='Invoker';Label='Captured script invoker';DependsOn=@();Action=$action})
Assert-True ($invokerRun.Status-eq'Completed'-and[IO.File]::ReadAllText((Join-Path $ioRoot 'probe.txt'))-eq'nested-module') 'Captured child-script invoker failed across execution-module scope.'
$threw=$false;try{& $invoker '..\outside.ps1' @{}|Out-Null}catch{$threw=$true};Assert-True $threw 'Child-script invoker accepted path traversal.'
$writerPath=Join-Path $ioRoot 'captured-writer.json';$writer=New-MsPrivateJsonWriter -Path $writerPath -Depth 4
$writerAction=({& $writer ([pscustomobject]@{Value='captured-writer'})}.GetNewClosure())
$writerRun=Invoke-MsPrivateGroupPlan -Groups @([pscustomobject]@{Id='Writer';Label='Captured JSON writer';DependsOn=@();Action=$writerAction})
$writerSaved=Get-Content -LiteralPath $writerPath -Raw|ConvertFrom-Json
Assert-True ($writerRun.Status-eq'Completed'-and$writerSaved.Value-eq'captured-writer') 'Captured atomic JSON writer failed across execution-module scope.'
$cleanupReport=Join-Path $ioRoot 'cleanup.json';$cleanupPlan=[pscustomobject]@{Schema=2;AgeDays=7;CutoffUtc=[DateTime]::UtcNow.AddDays(-7).ToString('o');Categories=@('Temp');Files=@()}
$cleanupResult=Invoke-WindCleanup -Plan $cleanupPlan -ReportPath $cleanupReport -Confirm:$false
Assert-True ($cleanupResult.Status-eq'Completed'-and(Test-Path -LiteralPath $cleanupReport)) 'Cleanup could not create and finalize its atomic report.'
$network=Get-Content -LiteralPath (Join-Path $root 'config/network.json') -Raw|ConvertFrom-Json;$network.OptionalTelemetry[1].Fqdn=$network.OptionalTelemetry[0].Fqdn;$path=Join-Path $ioRoot 'network.json';$network|ConvertTo-Json -Depth 8|Set-Content -LiteralPath $path
$threw=$false;try{Get-WindNetworkCatalog -Path $path|Out-Null}catch{$threw=$true};Assert-True $threw 'Network catalog accepted a duplicate FQDN.'
$network=Get-Content -LiteralPath (Join-Path $root 'config/network.json') -Raw|ConvertFrom-Json;$network.OptionalTelemetry[0].Fqdn='ctldl.windowsupdate.com';$path=Join-Path $ioRoot 'network-protected.json';$network|ConvertTo-Json -Depth 8|Set-Content -LiteralPath $path
$threw=$false;try{Get-WindNetworkCatalog -Path $path|Out-Null}catch{$threw=$true};Assert-True $threw 'Network catalog accepted a protected Windows Update endpoint.'
$services=Get-Content -LiteralPath (Join-Path $root 'config/services.json') -Raw|ConvertFrom-Json;$services.Services[1].Id=$services.Services[0].Id;$path=Join-Path $ioRoot 'services.json';$services|ConvertTo-Json -Depth 8|Set-Content -LiteralPath $path
$threw=$false;try{Get-MsPrivateServiceCatalog -Path $path|Out-Null}catch{$threw=$true};Assert-True $threw 'Service catalog accepted a duplicate ID.'
$accounts=Get-Content -LiteralPath (Join-Path $root 'config/accounts.json') -Raw|ConvertFrom-Json;$accounts.CredentialTargetPatterns=@($accounts.CredentialTargetPatterns)+@('[');$path=Join-Path $ioRoot 'accounts.json';$accounts|ConvertTo-Json -Depth 8|Set-Content -LiteralPath $path
$threw=$false;try{Get-MsPrivateAccountCatalog -Path $path|Out-Null}catch{$threw=$true};Assert-True $threw 'Account catalog accepted an invalid credential pattern.'
$policies=@(Get-WindCatalog);$policies[1].Id=$policies[0].Id;$path=Join-Path $ioRoot 'policies.json';$policies|ConvertTo-Json -Depth 8|Set-Content -LiteralPath $path
$threw=$false;try{Get-WindCatalog -Path $path|Out-Null}catch{$threw=$true};Assert-True $threw 'Policy catalog accepted a duplicate ID.'
$policies=@(Get-WindCatalog);$policies[0]|Add-Member -NotePropertyName Hive -NotePropertyValue 'Users' -Force;$path=Join-Path $ioRoot 'policies-hive.json';$policies|ConvertTo-Json -Depth 8|Set-Content -LiteralPath $path
$threw=$false;try{Get-WindCatalog -Path $path|Out-Null}catch{$threw=$true};Assert-True $threw 'Policy catalog accepted an untrusted registry hive.'
$presets=Get-Content -LiteralPath (Join-Path $root 'config/presets.json') -Raw|ConvertFrom-Json;$presets.Presets[1].RemoveStore=$false;$path=Join-Path $ioRoot 'presets.json';$presets|ConvertTo-Json -Depth 8|Set-Content -LiteralPath $path
$threw=$false;try{Get-MsPrivatePresetCatalog -Path $path|Out-Null}catch{$threw=$true};Assert-True $threw 'Preset catalog accepted an incomplete aggressive preset.'
$now=[datetime]'2026-09-22T12:00:00Z'
$fresh=Get-MsPrivateInstallContext -NowUtc $now -Probe {[pscustomobject]@{InstallDate=$now.AddDays(-2);ProfileCreationUtc=$now.AddDays(-1)}}
Assert-True ($fresh.Classification-eq'FreshInstall'-and$fresh.RecommendedPreset-eq'FreshInstall') 'A fresh OS and profile did not select FreshInstall.'
$upgraded=Get-MsPrivateInstallContext -NowUtc $now -Probe {[pscustomobject]@{InstallDate=$now.AddDays(-2);ProfileCreationUtc=$now.AddDays(-100)}}
Assert-True ($upgraded.Classification-eq'Established'-and$upgraded.RecommendedPreset-eq'EstablishedSafe') 'An older profile after a recent OS date was misclassified as fresh.'
$unknown=Get-MsPrivateInstallContext -NowUtc $now -Probe {throw 'unavailable'}
Assert-True ($unknown.Classification-eq'Unknown'-and$unknown.RecommendedPreset-eq'EstablishedSafe') 'Unknown installation age did not fail safe.'
}finally{if(Test-Path -LiteralPath $ioRoot){Remove-Item -LiteralPath $ioRoot -Recurse -Force}}
$observe=Get-WindNetworkPlan -Profile Observe
Assert-True ($observe.Items.Count-eq 1-and$observe.Items[0].Status-eq'Ready') 'Observe plan must be non-mutating.'
$threw=$false;try{Get-WindNetworkPlan -Profile Observe -RollbackMinutes 1|Out-Null}catch{$threw=$true};Assert-True $threw 'Network rollback lower bound was not enforced.'
$supportedRecall=Resolve-MsPrivateRecallDisposition -Requested $true -Plan ([pscustomobject]@{Items=@([pscustomobject]@{Id='recall-policy';Status='WouldChange'},[pscustomobject]@{Id='recall-feature';Status='Configured'})})
Assert-True ($supportedRecall.Applicable-and-not$supportedRecall.Conflict-and-not$supportedRecall.Skipped.Count) 'Supported Recall plan was not marked applicable.'
$unsupportedRecall=Resolve-MsPrivateRecallDisposition -Requested $true -Plan ([pscustomobject]@{Items=@([pscustomobject]@{Id='recall-policy';Status='Unsupported'})})
Assert-True (-not$unsupportedRecall.Applicable-and-not$unsupportedRecall.Conflict-and$unsupportedRecall.Skipped.Count-eq1) 'Unsupported Recall action was not reported as skipped.'
$conflictingRecall=Resolve-MsPrivateRecallDisposition -Requested $true -Plan ([pscustomobject]@{Items=@([pscustomobject]@{Id='recall-policy';Status='Conflict'})})
Assert-True (-not$conflictingRecall.Applicable-and$conflictingRecall.Conflict) 'Conflicting Recall plan did not remain a hard stop.'
$events=[Collections.Generic.List[string]]::new()
$groups=@(
[pscustomobject]@{Id='First';Label='First';DependsOn=@();Action=({$events.Add('first')|Out-Null;throw 'expected failure'}.GetNewClosure())},
[pscustomobject]@{Id='Dependent';Label='Dependent';DependsOn=@('First');Action=({$events.Add('dependent')|Out-Null}.GetNewClosure())},
[pscustomobject]@{Id='Independent';Label='Independent';DependsOn=@();Action=({$events.Add('independent')|Out-Null}.GetNewClosure())}
)
$run=Invoke-MsPrivateGroupPlan -Groups $groups
Assert-True ($run.Status-eq'PartialFailure'-and($run.Entries | Where-Object { $_.Id -eq 'First' }).Status-eq'Failed') 'Operation runner did not record a failed group.'
Assert-True (($run.Entries | Where-Object { $_.Id -eq 'Dependent' }).Status-eq'SkippedDependency'-and$events-notcontains'dependent') 'Operation runner executed a blocked dependency.'
Assert-True (($run.Entries | Where-Object { $_.Id -eq 'Independent' }).Status-eq'Succeeded'-and$events-contains'independent') 'Operation runner did not continue with an independent group.'
$runReportRoot=Join-Path ([IO.Path]::GetTempPath()) ('ms-private-run-report-'+[guid]::NewGuid().ToString('N'))
try{
$runReportPath=Join-Path $runReportRoot 'run.json'
$savedRun=Invoke-MsPrivateGroupPlan -Groups @([pscustomobject]@{Id='WriteReport';Label='Write report';DependsOn=@();Action={}}) -ReportPath $runReportPath
$savedRunDisk=Get-Content -LiteralPath $runReportPath -Raw|ConvertFrom-Json
Assert-True ($savedRun.Status-eq'Completed'-and$savedRunDisk.Status-eq'Completed'-and$savedRunDisk.Entries[0].Status-eq'Succeeded') 'Operation runner could not write and finalize a run report.'
$emptyRunPath=Join-Path $runReportRoot 'empty.json';$emptyRun=Invoke-MsPrivateGroupPlan -Groups @() -ReportPath $emptyRunPath
Assert-True ($emptyRun.Status-eq'Completed'-and@($emptyRun.Entries).Count-eq0-and(Test-Path -LiteralPath $emptyRunPath)) 'Empty operation plan did not complete as a clean no-op.'
}finally{if(Test-Path -LiteralPath $runReportRoot){Remove-Item -LiteralPath $runReportRoot -Recurse -Force}}
$calls=[Collections.Generic.List[string]]::new()
$backend=@{
ReadProfiles={@([pscustomobject]@{Name='Domain';DefaultOutboundAction='Allow'},[pscustomobject]@{Name='Private';DefaultOutboundAction='Allow'},[pscustomobject]@{Name='Public';DefaultOutboundAction='Allow'})}
SetOutbound={param($name,$action)$calls.Add("set:${name}:$action")}
RemoveRules={param($g)$calls.Add("rules:$g")}
RemoveKeyword={param($id)$calls.Add("keyword:$id")}
RemoveRollback={param($n)$calls.Add("task:$n")}
}
$j=[pscustomobject]@{Schema=1;Kind='MsPrivateNetwork';Status='Applied';Profile='Isolate';RuleGroup='ms-private';KeywordIds=@();RollbackTask='ms-private Network Recovery 0123456789abcdef0123456789abcdef';Profiles=@([pscustomobject]@{Name='Domain';DefaultOutboundAction='Allow'},[pscustomobject]@{Name='Private';DefaultOutboundAction='Allow'},[pscustomobject]@{Name='Public';DefaultOutboundAction='Allow'})}
Restore-WindNetwork -Journal $j -Backend $backend -Save {param($x)}|Out-Null
Assert-True ($calls.Count-eq 4) 'Isolation restore did not restore three profiles and remove the task.'
Assert-True (Test-WindVeraCryptVolume 'X:') 'Valid VeraCrypt drive rejected.'
Assert-True (-not(Test-WindVeraCryptVolume 'C:\Windows')) 'Unsafe VeraCrypt target accepted.'
$threw=$false;try{Get-WindCleanupPlan -Root @((Join-Path $env:USERPROFILE 'Documents'))|Out-Null}catch{$threw=$true};Assert-True $threw 'Cleanup accepted a non-temp root.'
$cleanupCatalog=@(Get-WindPrivacyCleanupCatalog)
Assert-True (-not@($cleanupCatalog|Where-Object{$_.Root-match'(?i)winevt|System32\\LogFiles|Defender'}).Count) 'Cleanup catalog included protected event/security logs.'
Assert-True (-not@($cleanupCatalog|Where-Object{$_.Category-eq'WindReports'-and$_.Patterns-contains'*.journal.json'}).Count) 'Cleanup catalog included recovery journals.'
$browserPlan=Get-WindCleanupPlan -AgeDays 0 -Category BrowserCache
Assert-True ($browserPlan.Categories-contains'BrowserCache') 'Browser-cache cleanup category was not accepted.'
$browserRoots=@(Get-WindBrowserCacheCatalog);Assert-True (-not@($browserRoots|Where-Object{$_.Root-notmatch'(?i)\\(cache2|startupCache|Cache|Code Cache|GPUCache|DawnCache|GrShaderCache|ShaderCache|CacheStorage)$'}).Count) 'Browser cleanup included a non-cache profile path.'
$security=Get-WindSecurityStatus;Assert-True ($security.RecoveryKeysCaptured-eq$false) 'Security audit must never capture recovery keys.'
Assert-True ($security.SensitiveValuesCaptured-eq$false-and$security.Schema-eq2) 'Expanded security audit must remain secret-free and versioned.'
$serviceCatalog=Get-MsPrivateServiceCatalog
Assert-True (-not@($serviceCatalog.Services|Where-Object{$_.Name-in@($serviceCatalog.ProtectedServices)}).Count) 'Protected security/update service entered the privacy disable catalog.'
$serviceStates=@{DiagTrack=[pscustomobject]@{Exists=$true;StartExists=$true;Start=2;FlagsExists=$false;Flags=$null}}
$serviceCalls=[Collections.Generic.List[string]]::new();$serviceBackend=@{
ReadTemplate={param($name)if($serviceStates.ContainsKey($name)){$serviceStates[$name]}else{[pscustomobject]@{Exists=$false;StartExists=$false;Start=$null;FlagsExists=$false;Flags=$null}}}
WriteTemplate={param($name,$state)$serviceStates[$name]=[pscustomobject]@{Exists=$state.Exists;StartExists=$state.StartExists;Start=$state.Start;FlagsExists=$state.FlagsExists;Flags=$state.Flags};$serviceCalls.Add("write:${name}:$($state.Start)")}
ReadInstances={param($name,$instances)if($name-eq'DiagTrack'){@([pscustomobject]@{Name='DiagTrack';Status='Running'})}else{@()}}
StopInstance={param($name)$serviceCalls.Add("stop:$name")};StartInstance={param($name)$serviceCalls.Add("start:$name")}
}
$servicePlan=@(Get-MsPrivateServicePlan -Profile Strict -Backend $serviceBackend);$serviceJournal=Invoke-MsPrivateServiceApply -Plan $servicePlan -Backend $serviceBackend -Save {param($x)}
Assert-True ($serviceStates.DiagTrack.Start-eq4-and$serviceCalls-contains'stop:DiagTrack') 'Strict service plan did not disable and stop the telemetry service.'
$restored=Restore-MsPrivateServices -Journal $serviceJournal -Backend $serviceBackend -Save {param($x)}
Assert-True ($serviceStates.DiagTrack.Start-eq2-and$restored.Status-eq'Restored') 'Service journal did not restore original startup state.'
$forged=@(Get-MsPrivateServicePlan -Profile Strict -Backend $serviceBackend);$forged[0].Name='wuauserv';$threw=$false
try{Invoke-MsPrivateServiceApply -Plan $forged -Backend $serviceBackend -Save {param($x)}|Out-Null}catch{$threw=$true}
Assert-True $threw 'Service engine accepted a forged protected-service name.'
$accountCalls=[Collections.Generic.List[string]]::new();$accountBackend=@{
ListPackages={@([pscustomobject]@{Name='Microsoft.WindowsStore';PackageFullName='store_full'},[pscustomobject]@{Name='Microsoft.AAD.BrokerPlugin';PackageFullName='broker_full'})}
ResetPackage={param($name)$accountCalls.Add("reset:$name")}
ListCredentials={@([pscustomobject]@{TargetName='MicrosoftAccount:[email protected]';Type=[uint32]1},[pscustomobject]@{TargetName='unrelated-server';Type=[uint32]1})}
DeleteCredential={param($target,$type)$accountCalls.Add("delete:${target}:$type")}
}
$consumerPlan=@(Get-MsPrivateAccountPlan -Scope Consumer -Backend $accountBackend)
Assert-True (-not @($consumerPlan|Where-Object {$_.Id -eq 'web-account-broker'}).Count) 'Consumer account scope included the shared identity broker.'
$accountReport=Invoke-MsPrivateAccountPurge -Scope AllAppAccounts -Backend $accountBackend -Save {param($x)}
Assert-True ($accountReport.Status-eq'Completed'-and$accountCalls-contains'reset:store_full'-and$accountCalls-contains'reset:broker_full') 'Account purge did not reset exact installed package identities.'
Assert-True (@($accountCalls|Where-Object{$_-like'delete:MicrosoftAccount:*'}).Count-eq1-and-not@($accountCalls|Where-Object{$_-like'*unrelated-server*'}).Count) 'Account purge deleted outside its credential allowlist.'
Assert-True (-not@($accountReport.Entries|Where-Object{$_.PSObject.Properties['Key']}).Count) 'Account report retained a credential target.'
$accountReportPath=Join-Path ([IO.Path]::GetTempPath()) ('ms-private-account-test-'+[guid]::NewGuid().ToString('N')+'.json')
try{Save-MsPrivateAccountReport -Report $accountReport -Path $accountReportPath;Save-MsPrivateAccountReport -Report $accountReport -Path $accountReportPath;$roundTrip=Get-Content -LiteralPath $accountReportPath -Raw|ConvertFrom-Json;Assert-True ($roundTrip.Status-eq'Completed') 'Account report atomic replacement failed.'}finally{[IO.File]::Delete($accountReportPath)}
[xml]$ame=Get-Content -LiteralPath (Join-Path $root 'ame/src/playbook.conf') -Raw
Assert-True ($ame.Playbook.Overhaul-eq'false') 'AME wrapper must not claim an OS overhaul.'
Assert-True (-not($ame.Playbook.Requirements.Requirement -contains 'DefenderDisabled')) 'AME wrapper must preserve Defender.'
$yaml=Get-Content -LiteralPath (Join-Path $root 'ame/src/Configuration/main.yml') -Raw
Assert-True ($yaml -match 'ms-private\\\\Launch\.cmd') 'AME launcher action missing.'
Write-Output "$script:passed feature tests passed. No OS setting was changed."