From 1eb014f7c17e342d413a8f6a1928c3dd1d554b7c Mon Sep 17 00:00:00 2001 From: Satish Tagirisapu Date: Mon, 31 Aug 2026 02:28:59 -0400 Subject: [PATCH] Functest: add sigverif helpers and raise driver sign timeouts. Add Invoke-InteractiveSession/Invoke-AutoIt common helpers, driver_sigverif case (sigverif GUI + AutoIt), and platform-aware AutoIt path selection for native x86. Launch uploaded helpers with -ExecutionPolicy Bypass from Session 0. Raise driver_sign_check timeouts for slow guests. Pass the 900s scan timeout into AutoIt, match the complete driver filename and reject Not Signed, wait for AutoIt exit and fail killed or nonzero runs, declare case extra_software autoit, and fix README headings. Signed-off-by: Satish Tagirisapu Co-authored-by: Cursor --- .../tests/cases/driver_sign_check.json | 6 +- .../functest/tests/cases/driver_sigverif.json | 41 ++++++ .../tests/scripts/common/Invoke-AutoIt.ps1 | 138 ++++++++++++++++++ .../common/Invoke-InteractiveSession.ps1 | 121 +++++++++++++++ .../functest/tests/scripts/common/README.md | 18 +++ .../tests/scripts/run_sigverif_gui.ps1 | 45 ++++++ .../functest/tests/scripts/sigverif.au3 | 26 ++++ .../tests/scripts/sigverif_worker.ps1 | 92 ++++++++++++ 8 files changed, 484 insertions(+), 3 deletions(-) create mode 100644 lib/engines/functest/tests/cases/driver_sigverif.json create mode 100644 lib/engines/functest/tests/scripts/common/Invoke-AutoIt.ps1 create mode 100644 lib/engines/functest/tests/scripts/common/Invoke-InteractiveSession.ps1 create mode 100644 lib/engines/functest/tests/scripts/common/README.md create mode 100644 lib/engines/functest/tests/scripts/run_sigverif_gui.ps1 create mode 100644 lib/engines/functest/tests/scripts/sigverif.au3 create mode 100644 lib/engines/functest/tests/scripts/sigverif_worker.ps1 diff --git a/lib/engines/functest/tests/cases/driver_sign_check.json b/lib/engines/functest/tests/cases/driver_sign_check.json index e8aa46c3..14f1c880 100644 --- a/lib/engines/functest/tests/cases/driver_sign_check.json +++ b/lib/engines/functest/tests/cases/driver_sign_check.json @@ -3,7 +3,7 @@ "display_name": "Installed driver is digitally signed", "description": "Verify the installed driver .sys is digitally signed (@driver_module@)", "test_system_ref": "VIRT-200", - "timeout": 120, + "timeout": 720, "test_steps": [ { "desc": "Reboot so the freshly installed driver is fully loaded", @@ -13,13 +13,13 @@ "desc": "Locate @driver_module@.sys in the DriverStore", "guest_run_file": "lib/engines/functest/tests/scripts/find_driver_in_store.ps1", "expected_output_contains": "PASS:", - "timeout": 60 + "timeout": 300 }, { "desc": "Verify @driver_module@.sys is digitally signed", "guest_run_file": "lib/engines/functest/tests/scripts/verify_driver_signed.ps1", "expected_output_contains": "PASS:", - "timeout": 60 + "timeout": 180 } ] } diff --git a/lib/engines/functest/tests/cases/driver_sigverif.json b/lib/engines/functest/tests/cases/driver_sigverif.json new file mode 100644 index 00000000..3590bbf3 --- /dev/null +++ b/lib/engines/functest/tests/cases/driver_sigverif.json @@ -0,0 +1,41 @@ +{ + "name": "driver_sigverif", + "description": "Verify @driver_module@.sys is Signed via Windows File Signature Verification GUI (sigverif + AutoIt), mirrors KAR win_sigverif", + "test_system_ref": "VIRT-SIGVERIF", + "timeout": 1320, + "extra_software": ["autoit"], + "test_steps": [ + { + "desc": "Upload common interactive/AutoIt helpers, sigverif.au3, and worker", + "files_action": [ + { + "local_path": "lib/engines/functest/tests/scripts/common/Invoke-InteractiveSession.ps1", + "remote_path": "C:\\AutoHCK\\common\\Invoke-InteractiveSession.ps1", + "direction": "local-to-remote" + }, + { + "local_path": "lib/engines/functest/tests/scripts/common/Invoke-AutoIt.ps1", + "remote_path": "C:\\AutoHCK\\common\\Invoke-AutoIt.ps1", + "direction": "local-to-remote" + }, + { + "local_path": "lib/engines/functest/tests/scripts/sigverif.au3", + "remote_path": "C:\\AutoHCK\\sigverif.au3", + "direction": "local-to-remote" + }, + { + "local_path": "lib/engines/functest/tests/scripts/sigverif_worker.ps1", + "remote_path": "C:\\AutoHCK\\sigverif_worker.ps1", + "direction": "local-to-remote" + } + ], + "timeout": 120 + }, + { + "desc": "Run sigverif GUI via AutoIt and confirm @driver_module@.sys is Signed", + "guest_run_file": "lib/engines/functest/tests/scripts/run_sigverif_gui.ps1", + "expected_output_contains": "PASS:", + "timeout": 1200 + } + ] +} diff --git a/lib/engines/functest/tests/scripts/common/Invoke-AutoIt.ps1 b/lib/engines/functest/tests/scripts/common/Invoke-AutoIt.ps1 new file mode 100644 index 00000000..67e11b10 --- /dev/null +++ b/lib/engines/functest/tests/scripts/common/Invoke-AutoIt.ps1 @@ -0,0 +1,138 @@ +<# +.SYNOPSIS + Locate AutoIt and run a .au3 script on the current desktop session. + +.DESCRIPTION + Intended to run inside an interactive session (e.g. after + Invoke-InteractiveSession.ps1). Requires suite or case extra_software: ["autoit"]. + + Usage: upload this script (and Invoke-InteractiveSession.ps1 if needed) from + lib/engines/functest/tests/scripts/common/ via the case files_action step to + e.g. C:\AutoHCK\common\, then invoke it from the interactive worker. + +.PARAMETER Au3Path + Absolute guest path to the .au3 script. + +.PARAMETER TimeoutSec + Max seconds to wait for AutoIt to exit (and optional -WaitForFile). + +.PARAMETER WaitForFile + If set, success requires this file to exist. The helper waits until + AutoIt has exited and the file is present, or TimeoutSec elapses. + +.PARAMETER ScriptArgs + Extra arguments forwarded to the AutoIt script ($CmdLine[1] ...). + +.PARAMETER MinimizeWindows + Call Shell.Application MinimizeAll before starting AutoIt. + +.PARAMETER LogPath + Optional log file to append status lines to. +#> + +param( + [Parameter(Mandatory = $true)] + [string]$Au3Path, + + [int]$TimeoutSec = 180, + + [string]$WaitForFile = '', + + [string[]]$ScriptArgs = @(), + + [switch]$MinimizeWindows, + + [string]$LogPath = '' +) + +$ErrorActionPreference = 'Stop' + +function Write-AutoItLog([string]$Text) { + if ($LogPath) { + Add-Content -Path $LogPath -Value $Text -Encoding ASCII + } +} + +function Get-AutoItPath { + # Native x86 OS: AutoIt3_x64.exe does not exist and ProgramFiles(x86) + # is empty, so skip both to avoid a hang/timeout. + $isNativeX86 = ($env:PROCESSOR_ARCHITECTURE -eq 'x86') -and + [string]::IsNullOrEmpty($env:PROCESSOR_ARCHITEW6432) + + if ($isNativeX86) { + $candidates = @( + "${env:ProgramFiles}\AutoIt3\AutoIt3.exe" + ) + } else { + $candidates = @( + "${env:ProgramFiles}\AutoIt3\AutoIt3_x64.exe", + "${env:ProgramFiles}\AutoIt3\AutoIt3.exe", + "${env:ProgramFiles(x86)}\AutoIt3\AutoIt3_x64.exe", + "${env:ProgramFiles(x86)}\AutoIt3\AutoIt3.exe" + ) + } + foreach ($p in $candidates) { + if ($p -and (Test-Path $p)) { return $p } + } + return $null +} + +$autoIt = Get-AutoItPath +if (-not $autoIt) { + Write-Output 'FAIL: AutoIt not found (suite or case extra_software autoit required)' + exit 1 +} +if (-not (Test-Path $Au3Path)) { + Write-Output "FAIL: AutoIt script not found at $Au3Path" + exit 1 +} + +if ($MinimizeWindows) { + try { + $shell = New-Object -ComObject Shell.Application + $shell.MinimizeAll() + Start-Sleep -Seconds 2 + } catch { + Write-AutoItLog ("WARN: MinimizeAll failed: $($_.Exception.Message)") + } +} + +$argList = @('"' + $Au3Path + '"') +if ($ScriptArgs) { $argList += $ScriptArgs } +Write-AutoItLog ("Running: $autoIt $($argList -join ' ')") +$p = Start-Process -FilePath $autoIt -ArgumentList $argList -PassThru + +$killedOnTimeout = $false +$deadline = (Get-Date).AddSeconds($TimeoutSec) +while ((Get-Date) -lt $deadline) { + $null = $p.Refresh() + if ($p.HasExited) { + if (-not $WaitForFile -or (Test-Path $WaitForFile)) { break } + # AutoIt already exited; keep polling for the output file until deadline. + } + Start-Sleep -Seconds 2 +} + +if (-not $p.HasExited) { + Stop-Process -Id $p.Id -Force -ErrorAction SilentlyContinue + Write-AutoItLog 'WARN: AutoIt still running after timeout; killed' + $killedOnTimeout = $true +} else { + Write-AutoItLog ("AutoIt exit code=$($p.ExitCode)") +} + +if ($WaitForFile -and -not (Test-Path $WaitForFile)) { + Write-Output "FAIL: expected output file not created: $WaitForFile" + exit 1 +} +if ($killedOnTimeout) { + Write-Output "FAIL: AutoIt killed after timeout (${TimeoutSec}s)" + exit 1 +} +if ($p.ExitCode -ne 0) { + Write-Output "FAIL: AutoIt exited $($p.ExitCode) ($Au3Path)" + exit 1 +} + +Write-Output "PASS: AutoIt finished ($Au3Path)" +exit 0 diff --git a/lib/engines/functest/tests/scripts/common/Invoke-InteractiveSession.ps1 b/lib/engines/functest/tests/scripts/common/Invoke-InteractiveSession.ps1 new file mode 100644 index 00000000..c3c7c294 --- /dev/null +++ b/lib/engines/functest/tests/scripts/common/Invoke-InteractiveSession.ps1 @@ -0,0 +1,121 @@ +<# +.SYNOPSIS + Hop from Session 0 to the interactive desktop and run a worker script. + +.DESCRIPTION + Functest guest_run / guest_run_file often execute in Session 0, where GUI + automation (AutoIt, etc.) cannot attach to the user desktop. This helper + registers a Scheduled Task with LogonType Interactive, starts it as the + AutoHCK autologin user, and waits for a result file. + + Any GUI / AutoIt functest can reuse this; keep test-specific logic in the + worker script pointed at by -ScriptPath. + + Usage: upload helpers from lib/engines/functest/tests/scripts/common/ via + the case files_action step to e.g. C:\AutoHCK\common\, then call this + script from the Session-0 launcher (see driver_sigverif). + +.PARAMETER ScriptPath + Absolute guest path to the worker .ps1 (uploaded via files_action). + +.PARAMETER ArgumentList + Extra arguments appended after powershell -File . + +.PARAMETER TaskName + Scheduled Task name. Must be unique per concurrent test/client (use an + AutoHCK_ prefix plus a test-specific suffix, e.g. AutoHCK_Sigverif) so + overlapping runs do not unregister each other's tasks. + +.PARAMETER ResultFile + Absolute path the worker writes; first line should be PASS:... or FAIL:... + +.PARAMETER TimeoutSec + Seconds to wait for ResultFile before failing. + +.PARAMETER WorkDir + Working directory created before the task starts. + +.PARAMETER WorkerLog + Optional log path to dump on success/timeout (if present). +#> + +param( + [Parameter(Mandatory = $true)] + [string]$ScriptPath, + + [string]$ArgumentList = '', + + [string]$TaskName = 'AutoHCK_Interactive', + + [Parameter(Mandatory = $true)] + [string]$ResultFile, + + [int]$TimeoutSec = 240, + + [string]$WorkDir = 'C:\AutoHCK\interactive_work', + + [string]$WorkerLog = '' +) + +$ErrorActionPreference = 'Stop' + +function Get-InteractiveUser { + # AutoHCK autologin: Winlogon DefaultUserName names the interactive user. + $winlogon = 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon' + $autoUser = (Get-ItemProperty -Path $winlogon -Name 'DefaultUserName' -ErrorAction SilentlyContinue).DefaultUserName + if ($autoUser) { return $autoUser } + return 'Administrator' +} + +if (-not (Test-Path $ScriptPath)) { + Write-Output "FAIL: worker script not found at $ScriptPath (files_action upload required)" + exit 1 +} + +New-Item -ItemType Directory -Force -Path $WorkDir | Out-Null +Remove-Item -Force $ResultFile -ErrorAction SilentlyContinue +if ($WorkerLog) { + Remove-Item -Force $WorkerLog -ErrorAction SilentlyContinue +} + +$user = Get-InteractiveUser +Write-Output "Outer session=$((Get-Process -Id $PID).SessionId); launching interactive user='$user'" +Write-Output "Worker: $ScriptPath" + +Unregister-ScheduledTask -TaskName $TaskName -Confirm:$false -ErrorAction SilentlyContinue + +$arg = "-NoProfile -ExecutionPolicy Bypass -File `"$ScriptPath`"" +if ($ArgumentList) { + $arg = "$arg $ArgumentList" +} + +$action = New-ScheduledTaskAction -Execute 'powershell.exe' -Argument $arg +$principal = New-ScheduledTaskPrincipal -UserId $user -LogonType Interactive -RunLevel Highest +$settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -MultipleInstances IgnoreNew +Register-ScheduledTask -TaskName $TaskName -Action $action -Principal $principal -Settings $settings -Force | Out-Null +Start-ScheduledTask -TaskName $TaskName +Write-Output "Started scheduled task '$TaskName'; waiting for result..." + +$deadline = (Get-Date).AddSeconds($TimeoutSec) +while ((Get-Date) -lt $deadline) { + if (Test-Path $ResultFile) { + $text = (Get-Content -Path $ResultFile -Raw).Trim() + Write-Output $text + if ($WorkerLog -and (Test-Path $WorkerLog)) { + Write-Output '--- worker.log ---' + Get-Content -Path $WorkerLog | ForEach-Object { Write-Output $_ } + } + Unregister-ScheduledTask -TaskName $TaskName -Confirm:$false -ErrorAction SilentlyContinue + if ($text -like 'PASS:*') { exit 0 } + exit 1 + } + Start-Sleep -Seconds 2 +} + +Write-Output "FAIL: timed out waiting for interactive worker result ($TaskName)" +if ($WorkerLog -and (Test-Path $WorkerLog)) { + Write-Output '--- worker.log ---' + Get-Content -Path $WorkerLog | ForEach-Object { Write-Output $_ } +} +Unregister-ScheduledTask -TaskName $TaskName -Confirm:$false -ErrorAction SilentlyContinue +exit 1 diff --git a/lib/engines/functest/tests/scripts/common/README.md b/lib/engines/functest/tests/scripts/common/README.md new file mode 100644 index 00000000..845f09d5 --- /dev/null +++ b/lib/engines/functest/tests/scripts/common/README.md @@ -0,0 +1,18 @@ +# Common functest helpers (guest scripts) + +Upload the scripts you need via the test case `files_action` step, for example: + +``` +local_path: lib/engines/functest/tests/scripts/common/Invoke-InteractiveSession.ps1 +remote_path: C:\AutoHCK\common\Invoke-InteractiveSession.ps1 +``` + +Typical GUI flow: + +``` +Session 0 launcher -> Invoke-InteractiveSession.ps1 (-TaskName unique per test) + -> worker.ps1 on interactive desktop + -> Invoke-AutoIt.ps1 (-Au3Path ..., optional -WaitForFile) +``` + +Requires suite or case `extra_software: ["autoit"]` when using Invoke-AutoIt.ps1. diff --git a/lib/engines/functest/tests/scripts/run_sigverif_gui.ps1 b/lib/engines/functest/tests/scripts/run_sigverif_gui.ps1 new file mode 100644 index 00000000..69d3b501 --- /dev/null +++ b/lib/engines/functest/tests/scripts/run_sigverif_gui.ps1 @@ -0,0 +1,45 @@ +<# +.SYNOPSIS + Run Windows File Signature Verification (sigverif) via AutoIt and confirm + @driver_module@.sys is Signed — mirrors KAR/avocado win_sigverif. + +.DESCRIPTION + Requires suite or case extra_software: ["autoit"]. The test case uploads common + helpers, sigverif.au3, and sigverif_worker.ps1 via files_action. + + This launcher only hops to the interactive desktop via + Invoke-InteractiveSession.ps1; GUI work lives in the worker. +#> + +$ErrorActionPreference = 'Stop' + +$moduleName = '@driver_module@' +if (-not $moduleName -or $moduleName -like '@*@') { + Write-Output 'FAIL: driver_module was not substituted by functest' + exit 1 +} + +$workDir = 'C:\AutoHCK\sigverif_work' +$resultFile = Join-Path $workDir 'result.txt' +$workerLog = Join-Path $workDir 'worker.log' +$workerScript = 'C:\AutoHCK\sigverif_worker.ps1' +$interactiveHelper = 'C:\AutoHCK\common\Invoke-InteractiveSession.ps1' +$scanTimeoutSec = 900 + +Write-Output "driver_module=$moduleName" + +if (-not (Test-Path $interactiveHelper)) { + Write-Output "FAIL: interactive helper not found at $interactiveHelper (files_action upload required)" + exit 1 +} + +# Uploaded helpers need an explicit Bypass launch from Session 0 guest_run_file. +& powershell.exe -NoProfile -ExecutionPolicy Bypass -File $interactiveHelper ` + -ScriptPath $workerScript ` + -ArgumentList "-ModuleName `"$moduleName`"" ` + -TaskName 'AutoHCK_Sigverif' ` + -ResultFile $resultFile ` + -TimeoutSec ($scanTimeoutSec + 60) ` + -WorkDir $workDir ` + -WorkerLog $workerLog +exit $LASTEXITCODE diff --git a/lib/engines/functest/tests/scripts/sigverif.au3 b/lib/engines/functest/tests/scripts/sigverif.au3 new file mode 100644 index 00000000..43a744ef --- /dev/null +++ b/lib/engines/functest/tests/scripts/sigverif.au3 @@ -0,0 +1,26 @@ +#cs ---------------------------------------------------------------------------- + + AutoIt Version: 3.3.14.5 + Author: Li Jin + Script Function: + Driver File Signature Verification (sigverif.exe): Start scan, dismiss + result dialog, close. Used by functest driver_sigverif (KAR win_sigverif). + Optional $CmdLine[1] is the scan timeout in seconds (default 900). +#ce ---------------------------------------------------------------------------- + +Local $scanTimeout = 900 +If $CmdLine[0] >= 1 Then + $scanTimeout = Number($CmdLine[1]) + If $scanTimeout < 1 Then $scanTimeout = 900 +EndIf + +Run("sigverif.exe") +WinWaitActive("File Signature Verification", "&Start") +Send("!s") +if WinWaitActive("SigVerif", "Your files have been scanned and verified as digitally signed.", $scanTimeout) then + Send("{ENTER}") +else + Send("!c") +endif +WinWaitActive("File Signature Verification", "&Start") +Send("!c") diff --git a/lib/engines/functest/tests/scripts/sigverif_worker.ps1 b/lib/engines/functest/tests/scripts/sigverif_worker.ps1 new file mode 100644 index 00000000..a727e47d --- /dev/null +++ b/lib/engines/functest/tests/scripts/sigverif_worker.ps1 @@ -0,0 +1,92 @@ +<# +.SYNOPSIS + Interactive-session worker: run sigverif via AutoIt and check @driver_module@.sys. + +.DESCRIPTION + Runs on the interactive desktop (via Invoke-InteractiveSession). Uploaded + from the host via files_action; launched by run_sigverif_gui.ps1. +#> + +param( + [Parameter(Mandatory = $true)] + [string]$ModuleName +) + +$ErrorActionPreference = 'Stop' + +$driverSys = "$ModuleName.sys" +$sigverifLog = 'C:\Users\Public\Documents\SIGVERIF.TXT' +$au3 = 'C:\AutoHCK\sigverif.au3' +$autoItHelper = 'C:\AutoHCK\common\Invoke-AutoIt.ps1' +$workDir = 'C:\AutoHCK\sigverif_work' +$resultFile = Join-Path $workDir 'result.txt' +$workerLog = Join-Path $workDir 'worker.log' +$scanTimeoutSec = 900 + +function Write-Result([string]$Text, [int]$Code = 0) { + Set-Content -Path $resultFile -Value $Text -Encoding ASCII + Add-Content -Path $workerLog -Value $Text -Encoding ASCII + exit $Code +} + +New-Item -ItemType Directory -Force -Path $workDir | Out-Null +Set-Content -Path $workerLog -Value ("worker start module=$ModuleName session=$((Get-Process -Id $PID).SessionId)") -Encoding ASCII + +if (-not (Test-Path $autoItHelper)) { + Write-Result "FAIL: AutoIt helper not found at $autoItHelper" 1 +} + +if (Test-Path $sigverifLog) { + Remove-Item -Force $sigverifLog + Add-Content -Path $workerLog -Value ("Removed previous log: $sigverifLog") +} + +& powershell.exe -NoProfile -ExecutionPolicy Bypass -File $autoItHelper ` + -Au3Path $au3 ` + -TimeoutSec $scanTimeoutSec ` + -ScriptArgs $scanTimeoutSec ` + -WaitForFile $sigverifLog ` + -MinimizeWindows ` + -LogPath $workerLog +if ($LASTEXITCODE -ne 0) { + Write-Result "FAIL: AutoIt/sigverif run failed (exit=$LASTEXITCODE)" 1 +} + +if (-not (Test-Path $sigverifLog)) { + Write-Result ("FAIL: sigverif log not created: $sigverifLog") 1 +} + +$logText = Get-Content -Path $sigverifLog -Raw -ErrorAction Stop +Add-Content -Path $workerLog -Value ("--- SIGVERIF.TXT ($ModuleName lines) ---") +foreach ($line in ($logText -split [Environment]::NewLine)) { + if ($line -match [regex]::Escape($ModuleName)) { + Add-Content -Path $workerLog -Value $line + } +} + +function Test-SigverifSignedLine([string]$Line, [string]$DriverSys) { + $esc = [regex]::Escape($DriverSys) + # Complete filename token, not a substring of another filename. + if ($Line -notmatch "(?i)(?