From 04a0127c6bae4c96ec8fd28b67d4116a8fabb3f3 Mon Sep 17 00:00:00 2001 From: Esdras Renan Date: Mon, 20 Oct 2025 21:36:57 -0300 Subject: [PATCH] Add Windows diagnostics test --- apps/desktop/src-tauri/src/agent.rs | 63 ++++++++++ scripts/test-windows-machine-info.ps1 | 170 ++++++++++++++++++++++++++ 2 files changed, 233 insertions(+) create mode 100644 scripts/test-windows-machine-info.ps1 diff --git a/apps/desktop/src-tauri/src/agent.rs b/apps/desktop/src-tauri/src/agent.rs index 696b629..0ae55bb 100644 --- a/apps/desktop/src-tauri/src/agent.rs +++ b/apps/desktop/src-tauri/src/agent.rs @@ -1041,3 +1041,66 @@ impl AgentRuntime { } } } + +#[cfg(all(test, target_os = "windows"))] +mod windows_tests { + use super::collect_windows_extended; + use serde_json::Value; + + fn expect_object<'a>(value: &'a Value, context: &str) -> &'a serde_json::Map { + value + .as_object() + .unwrap_or_else(|| panic!("{context} não é um objeto JSON: {value:?}")) + } + + #[test] + fn collects_activation_and_defender_status() { + let extended = collect_windows_extended(); + let windows = extended.get("windows").unwrap_or_else(|| { + panic!("payload windows ausente: {extended:?}"); + }); + let windows_obj = expect_object(windows, "windows"); + + let os_info = windows_obj + .get("osInfo") + .unwrap_or_else(|| panic!("windows.osInfo ausente: {windows_obj:?}")); + let os_info_obj = expect_object(os_info, "windows.osInfo"); + + let is_activated = os_info_obj.get("IsActivated").unwrap_or_else(|| { + panic!( + "campo IsActivated ausente em windows.osInfo: {os_info_obj:?}" + ) + }); + assert!( + is_activated.as_bool().is_some(), + "esperava booleano em windows.osInfo.IsActivated, valor recebido: {is_activated:?}" + ); + + let license_status = os_info_obj.get("LicenseStatus").unwrap_or_else(|| { + panic!( + "campo LicenseStatus ausente em windows.osInfo: {os_info_obj:?}" + ) + }); + assert!( + license_status.as_i64().is_some(), + "esperava número em windows.osInfo.LicenseStatus, valor recebido: {license_status:?}" + ); + + let defender = windows_obj.get("defender").unwrap_or_else(|| { + panic!("windows.defender ausente: {windows_obj:?}"); + }); + let defender_obj = expect_object(defender, "windows.defender"); + + let realtime = defender_obj + .get("RealTimeProtectionEnabled") + .unwrap_or_else(|| { + panic!( + "campo RealTimeProtectionEnabled ausente em windows.defender: {defender_obj:?}" + ) + }); + assert!( + realtime.as_bool().is_some(), + "esperava booleano em windows.defender.RealTimeProtectionEnabled, valor recebido: {realtime:?}" + ); + } +} diff --git a/scripts/test-windows-machine-info.ps1 b/scripts/test-windows-machine-info.ps1 new file mode 100644 index 0000000..4e41f7a --- /dev/null +++ b/scripts/test-windows-machine-info.ps1 @@ -0,0 +1,170 @@ +[CmdletBinding()] +param( + [switch]$Json +) + +Set-StrictMode -Version Latest +$ErrorActionPreference = 'Stop' + +function Get-ActivationStatus { + $result = [ordered]@{ + LicenseStatus = $null + LicenseStatusText = $null + ProductName = $null + PartialProductKey = $null + IsActivated = $false + RawItemCount = 0 + Notes = @() + } + + try { + $cv = Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' + $os = Get-CimInstance Win32_OperatingSystem -ErrorAction Stop + $lsItems = Get-CimInstance -Query "SELECT Name, Description, LicenseStatus, PartialProductKey FROM SoftwareLicensingProduct WHERE PartialProductKey IS NOT NULL" -ErrorAction Stop | + Where-Object { $_.Name -like 'Windows*' -or $_.Description -like 'Windows*' } | + Sort-Object -Property LicenseStatus -Descending + + $result.RawItemCount = ($lsItems | Measure-Object).Count + $activated = $lsItems | Where-Object { $_.LicenseStatus -eq 1 } | Select-Object -First 1 + $primary = if ($activated) { $activated } else { $lsItems | Select-Object -First 1 } + + if ($primary) { + $result.LicenseStatus = $primary.LicenseStatus + $result.LicenseStatusText = switch ($primary.LicenseStatus) { + 0 { 'Unlicensed' } + 1 { 'Licensed' } + 2 { 'Out-Of-Box Grace Period' } + 3 { 'Out-Of-Tolerance Grace Period' } + 4 { 'Non-Genuine Grace Period' } + 5 { 'Notification' } + 6 { 'Extended Grace' } + Default { "Unknown ($($_))" } + } + $result.ProductName = $primary.Name + $result.PartialProductKey = $primary.PartialProductKey + $result.IsActivated = [bool]($primary.LicenseStatus -eq 1) + } else { + $result.Notes += 'Nenhum produto Windows com PartialProductKey encontrado.' + } + + if ($cv.InstallationType) { + $result.Notes += "InstallationType: $($cv.InstallationType)" + } + if ($os.Caption) { + $result.Notes += "Caption: $($os.Caption)" + } + } catch { + $result.Notes += "Erro ao consultar ativação: $($_.Exception.Message)" + } + + return $result +} + +function Get-DefenderStatus { + $result = [ordered]@{ + CommandAvailable = $false + AMRunningMode = $null + AntivirusEnabled = $null + RealTimeProtectionEnabled = $null + AntispywareEnabled = $null + Notes = @() + } + + $command = Get-Command -Name Get-MpComputerStatus -ErrorAction SilentlyContinue + if (-not $command) { + $result.Notes += 'Cmdlet Get-MpComputerStatus não está disponível (talvez a funcionalidade do Defender não esteja instalada).' + return $result + } + + $result.CommandAvailable = $true + + try { + $status = Get-MpComputerStatus | Select-Object AMRunningMode,AntivirusEnabled,RealTimeProtectionEnabled,AntispywareEnabled + if ($null -eq $status) { + $result.Notes += 'Get-MpComputerStatus retornou $null.' + return $result + } + + $result.AMRunningMode = $status.AMRunningMode + $result.AntivirusEnabled = $status.AntivirusEnabled + $result.RealTimeProtectionEnabled = $status.RealTimeProtectionEnabled + $result.AntispywareEnabled = $status.AntispywareEnabled + } catch { + $result.Notes += "Erro ao consultar Defender: $($_.Exception.Message)" + } + + return $result +} + +$payload = [ordered]@{ + Timestamp = (Get-Date).ToString('s') + ComputerName = $env:COMPUTERNAME + Activation = Get-ActivationStatus + Defender = Get-DefenderStatus +} + +$failures = @() + +if ($payload.Activation.IsActivated -isnot [bool]) { + $failures += 'Activation.IsActivated não é um booleano.' +} + +if ($payload.Activation.LicenseStatus -isnot [int] -and $payload.Activation.LicenseStatus -isnot [long]) { + $failures += 'Activation.LicenseStatus não é numérico.' +} + +if ($payload.Defender.CommandAvailable) { + if ($payload.Defender.RealTimeProtectionEnabled -isnot [bool]) { + $failures += 'Defender.RealTimeProtectionEnabled não é um booleano.' + } +} else { + $payload.Defender.Notes += 'Teste de Defender ignorado porque o cmdlet não está disponível.' +} + +if ($Json) { + $payload | ConvertTo-Json -Depth 6 +} else { + Write-Host "=== Diagnóstico de Ativação do Windows ===" + $activation = $payload.Activation + Write-Host ("IsActivated : {0}" -f $activation.IsActivated) + Write-Host ("LicenseStatus : {0}" -f $activation.LicenseStatus) + if ($activation.LicenseStatusText) { + Write-Host ("LicenseStatusText : {0}" -f $activation.LicenseStatusText) + } + if ($activation.ProductName) { + Write-Host ("ProductName : {0}" -f $activation.ProductName) + } + if ($activation.PartialProductKey) { + Write-Host ("PartialProductKey : {0}" -f $activation.PartialProductKey) + } + if ($activation.Notes.Count -gt 0) { + Write-Host "Notas:" + $activation.Notes | ForEach-Object { Write-Host " - $_" } + } + + Write-Host "" + Write-Host "=== Diagnóstico do Windows Defender ===" + $defender = $payload.Defender + Write-Host ("Cmdlet disponível : {0}" -f $defender.CommandAvailable) + Write-Host ("RealTimeProtection : {0}" -f $defender.RealTimeProtectionEnabled) + Write-Host ("AntivirusEnabled : {0}" -f $defender.AntivirusEnabled) + Write-Host ("AntispywareEnabled : {0}" -f $defender.AntispywareEnabled) + Write-Host ("AMRunningMode : {0}" -f $defender.AMRunningMode) + if ($defender.Notes.Count -gt 0) { + Write-Host "Notas:" + $defender.Notes | ForEach-Object { Write-Host " - $_" } + } + + if ($failures.Count -gt 0) { + Write-Host "" + Write-Host "Falhas encontradas:" + $failures | ForEach-Object { Write-Host " - $_" } + } else { + Write-Host "" + Write-Host "Status geral: OK" + } +} + +if ($failures.Count -gt 0) { + exit 1 +}