This commit is contained in:
2026-04-27 18:58:52 -05:00
parent a5d6c8aa99
commit ea006827f5
9 changed files with 539 additions and 4 deletions
+2
View File
@@ -1,3 +1,5 @@
# Added by cargo
/dist*
/target
/.vagrant/
/vm/self-test/payload/
+34 -1
View File
@@ -141,4 +141,37 @@ cargo fmt
cargo check
```
Interactive GUI/TUI flows have been exercised during development, but there is not yet a formal automated integration harness for packaged installer behavior.
Interactive GUI/TUI flows now have a Windows VM smoke harness for packaged installer behavior, while broader automated coverage is still limited.
## Windows VM Smoke Test
A Windows Hyper-V Vagrant VM now lives in [`Vagrantfile`](C:\Users\jasonross\workspace\covenant-setup\Vagrantfile), and the host harness in [`scripts/run-windows-vm-smoke.ps1`](C:\Users\jasonross\workspace\covenant-setup\scripts\run-windows-vm-smoke.ps1) packages `covenant-setup`, boots the VM, opens Hyper-V's console viewer, and runs the packaged installer inside the guest's interactive desktop session.
The self-install manifest used for this path lives at [`vm/self-test/install.toml`](C:\Users\jasonross\workspace\covenant-setup\vm\self-test\install.toml). The guest verifies that install produced:
- `%LOCALAPPDATA%\CovenantSetupSelfTest\bin\covenant-setup.exe`
- `%LOCALAPPDATA%\CovenantSetupSelfTest\journal.json`
- `%LOCALAPPDATA%\CovenantSetupSelfTest\covenant-setup-uninstall.exe`
- `HKCU\Software\CovenantSetupSelfTest\InstallRoot`
- `Desktop\Covenant Setup Self Test.lnk`
Run the smoke test from the repo root:
```powershell
$env:COVENANT_WINDOWS_BOX = "gusztavvargadr/windows-11"
$env:COVENANT_HYPERV_SWITCH = "Default Switch"
.\scripts\run-windows-vm-smoke.ps1
```
Notes:
- The Vagrant provider is `hyperv`, and the box you choose must support that provider.
- The harness opens `vmconnect.exe` after `vagrant up` so the guest desktop stays visible during the install.
- The default Vagrant synced folder is disabled to avoid SMB credential prompts; the harness uploads the installer and guest scripts over WinRM instead.
- The guest install is launched through an interactive scheduled task because WinRM sessions are not desktop-visible.
- The packaged installer now has a hidden automation mode that suppresses blocking GUI message boxes while leaving the progress window visible for the VM smoke test.
- The Windows box should auto-log the `vagrant` user into the desktop session for the visual install path to appear.
- Set `COVENANT_HYPERV_SWITCH` to the Hyper-V virtual switch name you want Vagrant to use.
- The harness writes its verification artifact to `dist\vagrant-self-test\guest-result.json`.
- Use `-SkipViewer` if you do not want the harness to open the Hyper-V console window.
- Use `-HaltAfter` or `-DestroyAfter` if you want the harness to stop the VM after the test run.
Vendored
+36
View File
@@ -0,0 +1,36 @@
WINDOWS_BOX = ENV.fetch("COVENANT_WINDOWS_BOX", "gusztavvargadr/windows-11")
WINDOWS_BOX_VERSION = ENV["COVENANT_WINDOWS_BOX_VERSION"]
VM_NAME = ENV.fetch("COVENANT_VM_NAME", "covenant-setup-windows")
VM_MEMORY = ENV.fetch("COVENANT_VM_MEMORY", "6144")
VM_CPUS = ENV.fetch("COVENANT_VM_CPUS", "4")
WINRM_USERNAME = ENV.fetch("COVENANT_WINRM_USERNAME", "vagrant")
WINRM_PASSWORD = ENV.fetch("COVENANT_WINRM_PASSWORD", "vagrant")
HYPERV_SWITCH = ENV.fetch("COVENANT_HYPERV_SWITCH", "Default Switch")
Vagrant.configure("2") do |config|
config.vm.box = WINDOWS_BOX
if WINDOWS_BOX_VERSION && !WINDOWS_BOX_VERSION.empty?
config.vm.box_version = WINDOWS_BOX_VERSION
end
config.vm.hostname = VM_NAME
config.vm.guest = :windows
config.vm.communicator = "winrm"
config.vm.boot_timeout = ENV.fetch("COVENANT_BOOT_TIMEOUT", "1800").to_i
config.vm.graceful_halt_timeout = 180
config.vm.box_check_update = false
config.vm.network "public_network", bridge: HYPERV_SWITCH
config.vm.synced_folder ".", "/vagrant", disabled: true
config.winrm.username = WINRM_USERNAME
config.winrm.password = WINRM_PASSWORD
config.winrm.retry_limit = 60
config.winrm.retry_delay = 10
config.winrm.timeout = 1800
config.vm.provider "hyperv" do |h|
h.vmname = VM_NAME
h.memory = VM_MEMORY.to_i
h.cpus = VM_CPUS.to_i
end
end
+202
View File
@@ -0,0 +1,202 @@
[CmdletBinding()]
param(
[string]$Provider = "hyperv",
[string]$ManifestPath = "vm\self-test\install.toml",
[string]$OutputRoot = "dist\vagrant-self-test",
[string]$VmName = $(if ($env:COVENANT_VM_NAME) { $env:COVENANT_VM_NAME } else { "covenant-setup-windows" }),
[string]$GuestUsername = $(if ($env:COVENANT_WINRM_USERNAME) { $env:COVENANT_WINRM_USERNAME } else { "vagrant" }),
[string]$GuestPassword = $(if ($env:COVENANT_WINRM_PASSWORD) { $env:COVENANT_WINRM_PASSWORD } else { "vagrant" }),
[switch]$SkipBuild,
[switch]$SkipVmBoot,
[switch]$SkipViewer,
[switch]$HaltAfter,
[switch]$DestroyAfter
)
Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
function Assert-Command {
param([Parameter(Mandatory)][string]$Name)
if (-not (Get-Command $Name -ErrorAction SilentlyContinue)) {
throw "Required command not found on PATH: $Name"
}
}
function Resolve-RepoPath {
param(
[Parameter(Mandatory)][string]$RepoRoot,
[Parameter(Mandatory)][string]$Path
)
if ([System.IO.Path]::IsPathRooted($Path)) {
return $Path
}
return Join-Path $RepoRoot $Path
}
function Convert-ToSingleQuotedPowerShellLiteral {
param([Parameter(Mandatory)][string]$Value)
return "'" + $Value.Replace("'", "''") + "'"
}
function Invoke-Tool {
param(
[Parameter(Mandatory)][string]$FilePath,
[string[]]$Arguments = @()
)
Write-Host "==> $FilePath $($Arguments -join ' ')"
Remove-Variable -Name LASTEXITCODE -Scope Global -ErrorAction SilentlyContinue
& $FilePath @Arguments
$exitCodeVar = Get-Variable -Name LASTEXITCODE -Scope Global -ErrorAction SilentlyContinue
$exitCode = if ($exitCodeVar) { [int]$exitCodeVar.Value } elseif ($?) { 0 } else { 1 }
if ($exitCode -ne 0) {
throw "Command failed with exit code ${exitCode}: $FilePath $($Arguments -join ' ')"
}
}
function Invoke-Vagrant {
param([string[]]$Arguments)
Invoke-Tool -FilePath "vagrant" -Arguments $Arguments
}
function Open-HyperVViewer {
param([Parameter(Mandatory)][string]$VmName)
$vmConnect = Join-Path $env:SystemRoot "System32\vmconnect.exe"
if (-not (Test-Path -LiteralPath $vmConnect)) {
Write-Warning "Hyper-V viewer not found at $vmConnect"
return
}
Write-Host "==> $vmConnect localhost $VmName"
Start-Process -FilePath $vmConnect -ArgumentList @("localhost", $VmName) | Out-Null
}
function Invoke-Process {
param(
[Parameter(Mandatory)][string]$FilePath,
[string[]]$Arguments = @()
)
Write-Host "==> $FilePath $($Arguments -join ' ')"
$process = Start-Process -FilePath $FilePath -ArgumentList $Arguments -Wait -PassThru
if ($process.ExitCode -ne 0) {
throw "Command failed with exit code $($process.ExitCode): $FilePath $($Arguments -join ' ')"
}
}
$repoRoot = Split-Path -Parent $PSScriptRoot
$releaseExe = Join-Path $repoRoot "target\release\covenant-setup.exe"
$payloadRoot = Join-Path $repoRoot "vm\self-test\payload"
$stagedPayload = Join-Path $payloadRoot "covenant-setup.exe"
$manifestPathAbs = Resolve-RepoPath -RepoRoot $repoRoot -Path $ManifestPath
$outputRootAbs = Resolve-RepoPath -RepoRoot $repoRoot -Path $OutputRoot
$installerPath = Join-Path $outputRootAbs "covenant-setup-installer.exe"
$resultPath = Join-Path $outputRootAbs "guest-result.json"
$guestRoot = "C:\Users\vagrant\AppData\Local\Temp\covenant-setup-smoke"
$guestInstallerPath = Join-Path $guestRoot "covenant-setup-installer.exe"
$guestResultPath = Join-Path $guestRoot "guest-result.json"
$guestScriptRoot = Join-Path $guestRoot "scripts"
$guestCommand = "& '$guestScriptRoot\Start-InteractiveSelfInstall.ps1' -InstallerPath '$guestInstallerPath' -ResultPath '$guestResultPath' -ScriptRoot '$guestScriptRoot'"
Assert-Command -Name "cargo"
Assert-Command -Name "vagrant"
New-Item -ItemType Directory -Force -Path $payloadRoot | Out-Null
New-Item -ItemType Directory -Force -Path $outputRootAbs | Out-Null
Remove-Item -LiteralPath $resultPath -Force -ErrorAction SilentlyContinue
try {
if (-not $SkipBuild) {
Invoke-Tool -FilePath "cargo" -Arguments @("build", "--release")
}
if (-not (Test-Path -LiteralPath $releaseExe)) {
throw "Release binary not found at $releaseExe"
}
if (-not (Test-Path -LiteralPath $manifestPathAbs)) {
throw "Self-test manifest not found at $manifestPathAbs"
}
Copy-Item -LiteralPath $releaseExe -Destination $stagedPayload -Force
Invoke-Process -FilePath $releaseExe -Arguments @("package", $manifestPathAbs, "--output", $outputRootAbs)
if (-not (Test-Path -LiteralPath $installerPath)) {
throw "Packaged installer not found at $installerPath"
}
if (-not $SkipVmBoot) {
Invoke-Vagrant -Arguments @("up", "--provider", $Provider)
$guestUsernameLiteral = Convert-ToSingleQuotedPowerShellLiteral -Value $GuestUsername
$guestPasswordLiteral = Convert-ToSingleQuotedPowerShellLiteral -Value $GuestPassword
$enableAutoLogonCommand = @(
'$winlogon = ''HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon'''
"New-ItemProperty -Path `$winlogon -Name 'AutoAdminLogon' -PropertyType String -Value '1' -Force | Out-Null"
"New-ItemProperty -Path `$winlogon -Name 'ForceAutoLogon' -PropertyType String -Value '1' -Force | Out-Null"
"New-ItemProperty -Path `$winlogon -Name 'DefaultUserName' -PropertyType String -Value $guestUsernameLiteral -Force | Out-Null"
"New-ItemProperty -Path `$winlogon -Name 'DefaultPassword' -PropertyType String -Value $guestPasswordLiteral -Force | Out-Null"
"New-ItemProperty -Path `$winlogon -Name 'DefaultDomainName' -PropertyType String -Value `$env:COMPUTERNAME -Force | Out-Null"
) -join "; "
Invoke-Vagrant -Arguments @("winrm", "-s", "powershell", "-c", $enableAutoLogonCommand)
Invoke-Vagrant -Arguments @("reload")
}
if ($Provider -ieq "hyperv" -and -not $SkipViewer) {
Open-HyperVViewer -VmName $VmName
}
$waitForShellCommand = "for (`$i = 0; `$i -lt 90; `$i++) { if (Get-Process -Name explorer -ErrorAction SilentlyContinue) { exit 0 }; Start-Sleep -Seconds 2 }; Write-Error 'Explorer shell did not start in time.'; exit 1"
Invoke-Vagrant -Arguments @("winrm", "-s", "powershell", "-c", $waitForShellCommand)
Invoke-Vagrant -Arguments @("winrm", "-s", "powershell", "-c", "New-Item -ItemType Directory -Force -Path '$guestRoot' | Out-Null; New-Item -ItemType Directory -Force -Path '$guestScriptRoot' | Out-Null")
Invoke-Vagrant -Arguments @("upload", $installerPath, $guestInstallerPath)
Invoke-Vagrant -Arguments @("upload", (Join-Path $repoRoot "scripts\windows-vm\Approve-InstallerDialogs.ps1"), (Join-Path $guestScriptRoot "Approve-InstallerDialogs.ps1"))
Invoke-Vagrant -Arguments @("upload", (Join-Path $repoRoot "scripts\windows-vm\Invoke-InteractiveInstaller.ps1"), (Join-Path $guestScriptRoot "Invoke-InteractiveInstaller.ps1"))
Invoke-Vagrant -Arguments @("upload", (Join-Path $repoRoot "scripts\windows-vm\Start-InteractiveSelfInstall.ps1"), (Join-Path $guestScriptRoot "Start-InteractiveSelfInstall.ps1"))
Invoke-Vagrant -Arguments @("winrm", "-s", "powershell", "-c", $guestCommand)
$resultJson = Invoke-Vagrant -Arguments @("winrm", "-s", "powershell", "-c", "Get-Content -LiteralPath '$guestResultPath' -Raw")
Set-Content -LiteralPath $resultPath -Value $resultJson -Encoding UTF8
if (-not (Test-Path -LiteralPath $resultPath)) {
throw "Guest smoke-test result file was not written: $resultPath"
}
$result = $resultJson | ConvertFrom-Json
if (-not $result.success) {
throw "Guest reported a failed smoke test: $($result.error)"
}
Write-Host ""
Write-Host "Smoke test passed."
Write-Host "Installer: $installerPath"
Write-Host "Result JSON: $resultPath"
Write-Host "InstallRoot: $($result.installRoot)"
}
finally {
if ($DestroyAfter) {
try {
Invoke-Vagrant -Arguments @("destroy", "-f")
}
catch {
Write-Warning "Failed to destroy VM after smoke test: $($_.Exception.Message)"
}
}
elseif ($HaltAfter) {
try {
Invoke-Vagrant -Arguments @("halt")
}
catch {
Write-Warning "Failed to halt VM after smoke test: $($_.Exception.Message)"
}
}
}
@@ -0,0 +1,26 @@
[CmdletBinding()]
param(
[Parameter(Mandatory)][int]$InstallerProcessId,
[string]$WindowTitle = "covenant-setup",
[int]$PollMilliseconds = 500
)
Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
Add-Type -AssemblyName Microsoft.VisualBasic
Add-Type -AssemblyName System.Windows.Forms
while ($true) {
$process = Get-Process -Id $InstallerProcessId -ErrorAction SilentlyContinue
if (-not $process) {
break
}
if ([Microsoft.VisualBasic.Interaction]::AppActivate($WindowTitle)) {
Start-Sleep -Milliseconds 200
[System.Windows.Forms.SendKeys]::SendWait("{ENTER}")
}
Start-Sleep -Milliseconds $PollMilliseconds
}
@@ -0,0 +1,54 @@
[CmdletBinding()]
param(
[Parameter(Mandatory)][string]$InstallerPath,
[Parameter(Mandatory)][string]$ResultPath,
[int]$TimeoutSeconds = 600
)
Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
$installer = $null
$startedAt = Get-Date
try {
if (-not (Test-Path -LiteralPath $InstallerPath)) {
throw "Installer not found: $InstallerPath"
}
$resultDir = Split-Path -Parent $ResultPath
if ($resultDir) {
New-Item -ItemType Directory -Force -Path $resultDir | Out-Null
}
Remove-Item -LiteralPath $ResultPath -Force -ErrorAction SilentlyContinue
$installer = Start-Process -FilePath $InstallerPath -ArgumentList @("--headed", "--automation") -PassThru
if (-not $installer.WaitForExit($TimeoutSeconds * 1000)) {
Stop-Process -Id $installer.Id -Force -ErrorAction SilentlyContinue
throw "Installer timed out after $TimeoutSeconds seconds."
}
$result = [ordered]@{
success = ($installer.ExitCode -eq 0)
exitCode = [int]$installer.ExitCode
installerPath = $InstallerPath
startedAt = $startedAt.ToString("o")
finishedAt = (Get-Date).ToString("o")
}
$result | ConvertTo-Json | Set-Content -LiteralPath $ResultPath -Encoding UTF8
if ($installer.ExitCode -ne 0) {
exit $installer.ExitCode
}
}
catch {
$failure = [ordered]@{
success = $false
error = $_.Exception.Message
startedAt = $startedAt.ToString("o")
finishedAt = (Get-Date).ToString("o")
}
$failure | ConvertTo-Json | Set-Content -LiteralPath $ResultPath -Encoding UTF8
exit 1
}
@@ -0,0 +1,147 @@
[CmdletBinding()]
param(
[Parameter(Mandatory)][string]$InstallerPath,
[Parameter(Mandatory)][string]$ResultPath,
[string]$ScriptRoot = $PSScriptRoot,
[int]$TimeoutSeconds = 600,
[string]$TaskNamePrefix = "CovenantSetupSelfInstall"
)
Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
function Quote-TaskArgument {
param([Parameter(Mandatory)][string]$Value)
return '"' + $Value.Replace('"', '""') + '"'
}
$installRoot = Join-Path $env:LOCALAPPDATA "CovenantSetupSelfTest"
$shortcutPath = Join-Path ([Environment]::GetFolderPath("Desktop")) "Covenant Setup Self Test.lnk"
$registryPath = "HKCU:\Software\CovenantSetupSelfTest"
$journalPath = Join-Path $installRoot "journal.json"
$installedExe = Join-Path $installRoot "bin\covenant-setup.exe"
$uninstallExe = Join-Path $installRoot "covenant-setup-uninstall.exe"
$taskName = "{0}-{1}" -f $TaskNamePrefix, ([DateTimeOffset]::UtcNow.ToUnixTimeSeconds())
$interactiveScript = Join-Path $ScriptRoot "Invoke-InteractiveInstaller.ps1"
try {
if (-not (Test-Path -LiteralPath $InstallerPath)) {
throw "Installer not found in guest: $InstallerPath"
}
if (-not (Test-Path -LiteralPath $interactiveScript)) {
throw "Interactive installer script not found in guest: $interactiveScript"
}
$resultDir = Split-Path -Parent $ResultPath
if ($resultDir) {
New-Item -ItemType Directory -Force -Path $resultDir | Out-Null
}
Remove-Item -LiteralPath $ResultPath -Force -ErrorAction SilentlyContinue
Remove-Item -LiteralPath $installRoot -Recurse -Force -ErrorAction SilentlyContinue
Remove-Item -LiteralPath $shortcutPath -Force -ErrorAction SilentlyContinue
Remove-Item -LiteralPath $registryPath -Recurse -Force -ErrorAction SilentlyContinue
$trigger = New-ScheduledTaskTrigger -Once -At (Get-Date).AddMinutes(1)
$actionArguments = @(
"-NoProfile",
"-ExecutionPolicy", "Bypass",
"-File", (Quote-TaskArgument -Value $interactiveScript),
"-InstallerPath", (Quote-TaskArgument -Value $InstallerPath),
"-ResultPath", (Quote-TaskArgument -Value $ResultPath),
"-TimeoutSeconds", $TimeoutSeconds
) -join " "
$action = New-ScheduledTaskAction -Execute "powershell.exe" -Argument $actionArguments
$principal = New-ScheduledTaskPrincipal -UserId $env:USERNAME -LogonType Interactive -RunLevel Highest
$settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -StartWhenAvailable
Register-ScheduledTask `
-TaskName $taskName `
-Action $action `
-Trigger $trigger `
-Settings $settings `
-Principal $principal `
-Force | Out-Null
Start-ScheduledTask -TaskName $taskName
$deadline = (Get-Date).AddSeconds($TimeoutSeconds + 120)
while ((Get-Date) -lt $deadline) {
if (Test-Path -LiteralPath $ResultPath) {
break
}
Start-Sleep -Seconds 2
}
if (-not (Test-Path -LiteralPath $ResultPath)) {
$taskInfo = Get-ScheduledTaskInfo -TaskName $taskName
throw "Timed out waiting for interactive installer task. LastTaskResult=$($taskInfo.LastTaskResult)"
}
$runResult = Get-Content -LiteralPath $ResultPath -Raw | ConvertFrom-Json
if (-not $runResult.success) {
throw "Interactive installer task failed: $($runResult.error)"
}
if (-not (Test-Path -LiteralPath $installedExe)) {
throw "Installed executable missing: $installedExe"
}
if (-not (Test-Path -LiteralPath $journalPath)) {
throw "Journal missing: $journalPath"
}
if (-not (Test-Path -LiteralPath $uninstallExe)) {
throw "Installed uninstaller missing: $uninstallExe"
}
if (-not (Test-Path -LiteralPath $shortcutPath)) {
throw "Desktop shortcut missing: $shortcutPath"
}
if (-not (Test-Path -LiteralPath $registryPath)) {
throw "Registry key missing: $registryPath"
}
$installRootValue = Get-ItemPropertyValue -Path $registryPath -Name "InstallRoot"
if ($installRootValue -ne $installRoot) {
throw "Unexpected registry InstallRoot value: $installRootValue"
}
$journal = Get-Content -LiteralPath $journalPath -Raw | ConvertFrom-Json
$journalActionTypes = @($journal.actions | ForEach-Object { $_.type })
if ($journal.app_name -ne "Covenant Setup Self Test") {
throw "Unexpected journal app name: $($journal.app_name)"
}
if ($journalActionTypes -notcontains "copy_file") {
throw "Journal did not record the packaged payload copy."
}
$verification = [ordered]@{
success = $true
exitCode = [int]$runResult.exitCode
installerPath = $InstallerPath
installRoot = $installRoot
installedExe = $installedExe
journalPath = $journalPath
uninstallExe = $uninstallExe
shortcutPath = $shortcutPath
registryPath = $registryPath
journalActionTypes = $journalActionTypes
taskName = $taskName
startedAt = $runResult.startedAt
finishedAt = $runResult.finishedAt
}
$verification | ConvertTo-Json | Set-Content -LiteralPath $ResultPath -Encoding UTF8
}
catch {
$failure = [ordered]@{
success = $false
error = $_.Exception.Message
taskName = $taskName
installRoot = $installRoot
resultPath = $ResultPath
}
$failure | ConvertTo-Json | Set-Content -LiteralPath $ResultPath -Encoding UTF8
exit 1
}
finally {
Unregister-ScheduledTask -TaskName $taskName -Confirm:$false -ErrorAction SilentlyContinue
}
+13 -3
View File
@@ -40,6 +40,8 @@ struct Cli {
headless: bool,
#[arg(long, global = true, action = ArgAction::SetTrue, conflicts_with = "headless")]
headed: bool,
#[arg(long, global = true, hide = true, action = ArgAction::SetTrue)]
automation: bool,
#[arg(long, global = true, action = ArgAction::SetTrue)]
elevate: bool,
#[command(subcommand)]
@@ -328,6 +330,7 @@ enum RuntimeMode {
struct UiPreferences {
headless: bool,
headed: bool,
automation: bool,
}
#[derive(Clone, Copy, PartialEq, Eq)]
@@ -698,18 +701,21 @@ fn run_bundled_installer(
match mode {
RuntimeMode::Bundled => {
let ui_mode = select_ui(UiPhase::Install, preferences, logger)?;
if ui_mode == UiMode::Gui && !win::gui_confirm_install(&metadata.app_name, logger)? {
if ui_mode == UiMode::Gui
&& !preferences.automation
&& !win::gui_confirm_install(&metadata.app_name, logger)?
{
return Ok(());
}
match install(&manifest_path, Some(journal_path), true, ui_mode, logger) {
Ok(()) => {
if ui_mode == UiMode::Gui {
if ui_mode == UiMode::Gui && !preferences.automation {
win::gui_report_success(&metadata.app_name, logger)?;
}
Ok(())
}
Err(err) => {
if ui_mode == UiMode::Gui {
if ui_mode == UiMode::Gui && !preferences.automation {
win::gui_report_error(&err.to_string(), logger)?;
}
Err(err)
@@ -1335,6 +1341,7 @@ fn parse_ui_preferences(args: &[OsString]) -> UiPreferences {
let mut preferences = UiPreferences {
headless: false,
headed: false,
automation: false,
};
for arg in args.iter().skip(1) {
let value = arg.to_string_lossy();
@@ -1342,6 +1349,8 @@ fn parse_ui_preferences(args: &[OsString]) -> UiPreferences {
preferences.headless = true;
} else if value == "--headed" {
preferences.headed = true;
} else if value == "--automation" {
preferences.automation = true;
}
}
preferences
@@ -1351,6 +1360,7 @@ fn ui_preferences_from_cli(cli: &Cli) -> UiPreferences {
UiPreferences {
headless: cli.headless,
headed: cli.headed,
automation: cli.automation,
}
}
+25
View File
@@ -0,0 +1,25 @@
app_name = "Covenant Setup Self Test"
[[directories]]
path = "{LocalAppData}\\CovenantSetupSelfTest"
[[directories]]
path = "{LocalAppData}\\CovenantSetupSelfTest\\bin"
[[files]]
source = "payload\\covenant-setup.exe"
destination = "{LocalAppData}\\CovenantSetupSelfTest\\bin\\covenant-setup.exe"
[[registry]]
key = "HKCU\\Software\\CovenantSetupSelfTest"
name = "InstallRoot"
value = "{LocalAppData}\\CovenantSetupSelfTest"
[[shortcuts]]
path = "{Desktop}\\Covenant Setup Self Test.lnk"
target = "{LocalAppData}\\CovenantSetupSelfTest\\bin\\covenant-setup.exe"
description = "Launch the Covenant Setup self-installed test payload"
[purge]
registry_branches = ["HKCU\\Software\\CovenantSetupSelfTest"]
paths = ["{LocalAppData}\\CovenantSetupSelfTest"]