mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-07-09 16:00:59 +00:00
Fix Windows agent installer readiness path
This commit is contained in:
parent
6f4a9ca88b
commit
84c43ad3e1
10 changed files with 190 additions and 44 deletions
|
|
@ -1935,6 +1935,27 @@ func TestRunAsWindowsServiceStub(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestWindowsServiceRuntimeStartsHealthServer(t *testing.T) {
|
||||
source, err := os.ReadFile("service_windows.go")
|
||||
if err != nil {
|
||||
t.Fatalf("read pulse-agent service_windows.go: %v", err)
|
||||
}
|
||||
text := string(source)
|
||||
|
||||
required := []string{
|
||||
`var ready atomic.Bool`,
|
||||
`startHealthServer(ctx, ws.cfg.HealthAddr, &ready, &ws.logger)`,
|
||||
`ready.Store(true)`,
|
||||
`agentUp.Set(1)`,
|
||||
`defer agentUp.Set(0)`,
|
||||
}
|
||||
for _, want := range required {
|
||||
if !strings.Contains(text, want) {
|
||||
t.Fatalf("expected Windows service runtime to include %q", want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRun_KubeRetry(t *testing.T) {
|
||||
origKube := newKubeAgent
|
||||
defer func() { newKubeAgent = origKube }()
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/rcourtman/pulse-go-rewrite/internal/agentupdate"
|
||||
|
|
@ -39,6 +40,20 @@ func (ws *windowsService) Execute(args []string, r <-chan svc.ChangeRequest, cha
|
|||
|
||||
g, ctx := errgroup.WithContext(ctx)
|
||||
|
||||
agentInfo.WithLabelValues(
|
||||
Version,
|
||||
fmt.Sprintf("%t", ws.cfg.EnableHost),
|
||||
fmt.Sprintf("%t", ws.cfg.EnableDocker),
|
||||
fmt.Sprintf("%t", ws.cfg.EnableKubernetes),
|
||||
).Set(1)
|
||||
agentUp.Set(1)
|
||||
defer agentUp.Set(0)
|
||||
|
||||
var ready atomic.Bool
|
||||
if ws.cfg.HealthAddr != "" {
|
||||
startHealthServer(ctx, ws.cfg.HealthAddr, &ready, &ws.logger)
|
||||
}
|
||||
|
||||
// Start Auto-Updater
|
||||
updater := newUpdater(agentupdate.Config{
|
||||
PulseURL: ws.cfg.PulseURL,
|
||||
|
|
@ -131,6 +146,8 @@ func (ws *windowsService) Execute(args []string, r <-chan svc.ChangeRequest, cha
|
|||
})
|
||||
}
|
||||
|
||||
ready.Store(true)
|
||||
|
||||
changes <- svc.Status{State: svc.Running, Accepts: cmdsAccepted}
|
||||
ws.logger.Info().
|
||||
Str("version", Version).
|
||||
|
|
|
|||
|
|
@ -141,7 +141,11 @@ reverse.
|
|||
The Windows installer must support a non-mutating download preflight that
|
||||
can run before Administrator-only install work, must accept token-file
|
||||
enrollment input, and must persist plain-HTTP/insecure runtime continuity
|
||||
consistently with the Unix installer.
|
||||
consistently with the Unix installer. The installed Windows service must
|
||||
also expose the same local health/readiness server as foreground
|
||||
`pulse-agent` runs so installer "healthy" verification and post-install
|
||||
smoke checks prove a live agent runtime, not merely a running service
|
||||
wrapper.
|
||||
23. `scripts/install.sh` shared with `deployment-installability`: the shell installer is both a deployment installability entry point and a canonical agent lifecycle runtime continuity boundary.
|
||||
|
||||
Agent lifecycle and fleet-operation surfaces may consume
|
||||
|
|
|
|||
|
|
@ -266,7 +266,11 @@ platform page needs source-native backup columns.
|
|||
behavior, and `/download/pulse-agent?arch=...` availability proof into the
|
||||
installer invocation. Windows, macOS, and Linux commands must therefore
|
||||
preflight the exact platform artifact and avoid raw token process
|
||||
arguments.
|
||||
arguments. Windows generated commands must pass boolean installer intent
|
||||
through environment variables and invoke `install.ps1` through child
|
||||
PowerShell `-File` calls so Windows PowerShell argument binding cannot
|
||||
reinterpret copied `$true` values as strings or let preflight-only returns
|
||||
abort the parent wrapper before install.
|
||||
29. `frontend-modern/src/utils/apiTokenPresentation.ts` shared with `security-privacy`: the API token presentation helper is both a security/privacy control surface and a canonical API token management boundary.
|
||||
It owns the operator-facing Docker / Podman token vocabulary used by API
|
||||
Access, token presets, usage summaries, and revoke warnings.
|
||||
|
|
|
|||
|
|
@ -1353,6 +1353,10 @@ when `PULSE_INSECURE_SKIP_VERIFY` is enabled, `scripts/install.ps1` must use
|
|||
that relaxed certificate policy for its own agent download and uninstall
|
||||
deregistration requests so self-signed deployments do not fail before the
|
||||
persisted Windows service ever starts.
|
||||
Windows installability proof must also verify the installed service's local
|
||||
readiness endpoint, not just SCM `Running` state: the Windows service runtime
|
||||
must start the shared Pulse Agent health/readiness server so `/readyz` can prove
|
||||
the agent modules initialized after install.
|
||||
Copied PowerShell uninstall commands must preserve that same
|
||||
`PULSE_INSECURE_SKIP_VERIFY` setting so the governed deregistration request can
|
||||
still reach self-signed Pulse deployments during removal.
|
||||
|
|
|
|||
|
|
@ -134,12 +134,22 @@ describe('agentInstallCommand', () => {
|
|||
'[System.IO.File]::WriteAllText($pulseTokenFile, "token-123", [System.Text.Encoding]::ASCII)',
|
||||
);
|
||||
expect(command).toContain('-TokenFile $pulseTokenFile');
|
||||
expect(command).toContain('-PreflightOnly $true');
|
||||
expect(command).toContain('-Output "json"');
|
||||
expect(command).toContain('-NonInteractive $true');
|
||||
expect(command).toContain('-Insecure $true');
|
||||
expect(command).toContain('-CACertPath "C:\\Pulse\\custom-ca.cer"');
|
||||
expect(command).toContain('$env:PULSE_PREFLIGHT_ONLY="true"');
|
||||
expect(command).toContain('$env:PULSE_OUTPUT="json"');
|
||||
expect(command).toContain('$env:PULSE_NON_INTERACTIVE="true"');
|
||||
expect(command).toContain('$env:PULSE_INSECURE_SKIP_VERIFY="true"');
|
||||
expect(command).toContain('$env:PULSE_CACERT="C:\\Pulse\\custom-ca.cer"');
|
||||
expect(command).toContain('Invoke-WebRequest -Uri $pulseScriptUrl -UseBasicParsing -OutFile $pulseInstallScript');
|
||||
expect(command).toContain(
|
||||
'& $pulsePowerShell -NoProfile -ExecutionPolicy Bypass -File $pulseInstallScript -Url',
|
||||
);
|
||||
expect(command).toContain('if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }');
|
||||
expect(command).toContain(
|
||||
'Remove-Item Env:PULSE_PREFLIGHT_ONLY -ErrorAction SilentlyContinue',
|
||||
);
|
||||
expect(command).not.toContain('-PreflightOnly $true');
|
||||
expect(command).not.toContain('-NonInteractive $true');
|
||||
expect(command).not.toContain('-Insecure $true');
|
||||
expect(command).not.toContain('$env:PULSE_TOKEN=');
|
||||
});
|
||||
|
||||
|
|
@ -152,8 +162,10 @@ describe('agentInstallCommand', () => {
|
|||
expect(command).toContain('$pulseScriptUrl="https://pulse.example/install.ps1"');
|
||||
expect(command).not.toContain('$env:PULSE_TOKEN=');
|
||||
expect(command).not.toContain('-TokenFile $pulseTokenFile');
|
||||
expect(command).toContain('-PreflightOnly $true');
|
||||
expect(command).toContain('-NonInteractive $true');
|
||||
expect(command).toContain('$env:PULSE_PREFLIGHT_ONLY="true"');
|
||||
expect(command).toContain('$env:PULSE_NON_INTERACTIVE="true"');
|
||||
expect(command).not.toContain('-PreflightOnly $true');
|
||||
expect(command).not.toContain('-NonInteractive $true');
|
||||
});
|
||||
|
||||
it('fails closed when the install endpoint URL is blank', () => {
|
||||
|
|
@ -199,6 +211,9 @@ describe('agentInstallCommand', () => {
|
|||
expect(command).toContain('$env:PULSE_ENABLE_PROXMOX="true"');
|
||||
expect(command).toContain('$env:PULSE_PROXMOX_TYPE="pbs"');
|
||||
expect(command).toContain('$env:PULSE_ENABLE_COMMANDS="true"');
|
||||
expect(command).toContain(
|
||||
'& $pulsePowerShell -NoProfile -ExecutionPolicy Bypass -File $pulseInstallScript -Url',
|
||||
);
|
||||
});
|
||||
|
||||
it('passes insecure runtime continuity for plain-http Windows installs', () => {
|
||||
|
|
@ -208,8 +223,10 @@ describe('agentInstallCommand', () => {
|
|||
});
|
||||
|
||||
expect(command).toContain('-Url "http://pulse.example:7655"');
|
||||
expect(command).toContain('-Insecure $true');
|
||||
expect(command).toContain('-PreflightOnly $true');
|
||||
expect(command).toContain('$env:PULSE_INSECURE_SKIP_VERIFY="true"');
|
||||
expect(command).toContain('$env:PULSE_PREFLIGHT_ONLY="true"');
|
||||
expect(command).not.toContain('-Insecure $true');
|
||||
expect(command).not.toContain('-PreflightOnly $true');
|
||||
expect(command).not.toContain('$env:PULSE_TOKEN=');
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -148,11 +148,7 @@ export const buildWindowsAgentInstallCommand = ({
|
|||
const installArgs = [
|
||||
`-Url "${powerShellQuote(normalizedBaseUrl)}"`,
|
||||
...(normalizedToken ? ['-TokenFile $pulseTokenFile'] : []),
|
||||
...(installRequiresInsecure ? ['-Insecure $true'] : []),
|
||||
...(normalizedCaCertPath ? [`-CACertPath "${powerShellQuote(normalizedCaCertPath)}"`] : []),
|
||||
'-NonInteractive $true',
|
||||
];
|
||||
const preflightArgs = [...installArgs, '-PreflightOnly $true', '-Output "json"'];
|
||||
const customTrustFetch = installerFetchRequiresCustomTrust
|
||||
? `$pulseCustomCa=$null; if (-not [string]::IsNullOrWhiteSpace($pulseCaCertPath)) { $pulseCustomCaBytes=[System.IO.File]::ReadAllBytes($pulseCaCertPath); $pulseCustomCaText=[System.Text.Encoding]::ASCII.GetString($pulseCustomCaBytes); if ($pulseCustomCaText.Contains("-----BEGIN CERTIFICATE-----")) { $pulseCustomCa=[System.Security.Cryptography.X509Certificates.X509Certificate2]::CreateFromPem($pulseCustomCaText) } else { $pulseCustomCa=[System.Security.Cryptography.X509Certificates.X509Certificate2]::new($pulseCustomCaBytes) } }; $pulsePrev=[System.Net.ServicePointManager]::ServerCertificateValidationCallback; try { [System.Net.ServicePointManager]::ServerCertificateValidationCallback={ param($sender,$certificate,$chain,$sslPolicyErrors) if ($pulseAllowInsecure) { return $true }; if ($null -eq $pulseCustomCa) { return $sslPolicyErrors -eq [System.Net.Security.SslPolicyErrors]::None }; if ($null -eq $certificate) { return $false }; $pulseChain=[System.Security.Cryptography.X509Certificates.X509Chain]::new(); $pulseChain.ChainPolicy.RevocationMode=[System.Security.Cryptography.X509Certificates.X509RevocationMode]::NoCheck; $null=$pulseChain.ChainPolicy.ExtraStore.Add($pulseCustomCa); $null=$pulseChain.Build($certificate); foreach ($pulseElement in $pulseChain.ChainElements) { if ($pulseElement.Certificate.Thumbprint -eq $pulseCustomCa.Thumbprint) { return $true } }; return $false }; Invoke-WebRequest -Uri $pulseScriptUrl -UseBasicParsing -OutFile $pulseInstallScript } finally { [System.Net.ServicePointManager]::ServerCertificateValidationCallback=$pulsePrev }`
|
||||
: `Invoke-WebRequest -Uri $pulseScriptUrl -UseBasicParsing -OutFile $pulseInstallScript`;
|
||||
|
|
@ -163,6 +159,11 @@ export const buildWindowsAgentInstallCommand = ({
|
|||
const extraEnvBootstrap = normalizedExtraEnvAssignments.length
|
||||
? `${normalizedExtraEnvAssignments.join('; ')}; `
|
||||
: '';
|
||||
const runtimeEnvBootstrap =
|
||||
`${installRequiresInsecure ? '$env:PULSE_INSECURE_SKIP_VERIFY="true"; ' : ''}` +
|
||||
`${normalizedCaCertPath ? `$env:PULSE_CACERT="${powerShellQuote(normalizedCaCertPath)}"; ` : ''}` +
|
||||
'$env:PULSE_NON_INTERACTIVE="true"; ';
|
||||
const installCommand = `& $pulsePowerShell -NoProfile -ExecutionPolicy Bypass -File $pulseInstallScript ${installArgs.join(' ')}`;
|
||||
|
||||
return (
|
||||
`& { $ErrorActionPreference="Stop"; ` +
|
||||
|
|
@ -176,10 +177,13 @@ export const buildWindowsAgentInstallCommand = ({
|
|||
`${customTrustFetch}; ` +
|
||||
`${tokenBootstrap}` +
|
||||
`${extraEnvBootstrap}` +
|
||||
`${runtimeEnvBootstrap}` +
|
||||
`$pulsePowerShell=(Get-Process -Id $PID).Path; ` +
|
||||
`& $pulsePowerShell -NoProfile -ExecutionPolicy Bypass -File $pulseInstallScript ${preflightArgs.join(' ')}; ` +
|
||||
`$env:PULSE_PREFLIGHT_ONLY="true"; $env:PULSE_OUTPUT="json"; ` +
|
||||
`${installCommand}; ` +
|
||||
`if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }; ` +
|
||||
`& $pulsePowerShell -NoProfile -ExecutionPolicy Bypass -File $pulseInstallScript ${installArgs.join(' ')}; ` +
|
||||
`Remove-Item Env:PULSE_PREFLIGHT_ONLY -ErrorAction SilentlyContinue; Remove-Item Env:PULSE_OUTPUT -ErrorAction SilentlyContinue; ` +
|
||||
`${installCommand}; ` +
|
||||
`if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } ` +
|
||||
`} finally { Remove-Item -LiteralPath $pulseTmp -Recurse -Force -ErrorAction SilentlyContinue } }`
|
||||
);
|
||||
|
|
|
|||
|
|
@ -152,6 +152,45 @@ function Write-InstallerEvent {
|
|||
Write-Host $Message
|
||||
}
|
||||
|
||||
function Get-ResponseHeaderValue {
|
||||
param(
|
||||
$Headers,
|
||||
[string]$Name
|
||||
)
|
||||
|
||||
if ($null -eq $Headers -or [string]::IsNullOrWhiteSpace($Name)) {
|
||||
return ""
|
||||
}
|
||||
|
||||
try {
|
||||
$value = $Headers[$Name]
|
||||
if ($null -ne $value) {
|
||||
if ($value -is [array]) {
|
||||
return [string]$value[0]
|
||||
}
|
||||
return [string]$value
|
||||
}
|
||||
} catch {
|
||||
# Fall back to case-insensitive enumeration below.
|
||||
}
|
||||
|
||||
try {
|
||||
foreach ($key in $Headers.Keys) {
|
||||
if ([string]::Equals([string]$key, $Name, [System.StringComparison]::OrdinalIgnoreCase)) {
|
||||
$value = $Headers[$key]
|
||||
if ($value -is [array]) {
|
||||
return [string]$value[0]
|
||||
}
|
||||
return [string]$value
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
return ""
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
function Test-ValidUrl {
|
||||
param([string]$TestUrl)
|
||||
if ([string]::IsNullOrWhiteSpace($TestUrl)) { return $false }
|
||||
|
|
@ -482,9 +521,8 @@ if ($Uninstall) {
|
|||
$lookupArgs.Headers = @{ "X-API-Token" = $Token }
|
||||
}
|
||||
|
||||
$lookupResult = $null
|
||||
Invoke-WithOptionalInsecureTls -AllowInsecure $Insecure -CustomCaCertificate $customCaCertificate -Action {
|
||||
$lookupResult = Invoke-RestMethod @lookupArgs
|
||||
$lookupResult = Invoke-WithOptionalInsecureTls -AllowInsecure $Insecure -CustomCaCertificate $customCaCertificate -Action {
|
||||
Invoke-RestMethod @lookupArgs
|
||||
}
|
||||
if ($lookupResult -and $lookupResult.agent -and -not [string]::IsNullOrWhiteSpace($lookupResult.agent.id)) {
|
||||
$detectedAgentId = $lookupResult.agent.id.Trim()
|
||||
|
|
@ -622,12 +660,11 @@ function Invoke-AgentDownloadPreflight {
|
|||
param([string]$Uri)
|
||||
|
||||
try {
|
||||
$preflightResponse = $null
|
||||
Invoke-WithOptionalInsecureTls -AllowInsecure $Insecure -CustomCaCertificate $CustomCaCertificate -Action {
|
||||
$preflightResponse = Invoke-WebRequest -Uri $Uri -Method Head -UseBasicParsing -TimeoutSec 10 -ErrorAction Stop
|
||||
$preflightResponse = Invoke-WithOptionalInsecureTls -AllowInsecure $Insecure -CustomCaCertificate $CustomCaCertificate -Action {
|
||||
Invoke-WebRequest -Uri $Uri -Method Head -UseBasicParsing -TimeoutSec 10 -ErrorAction Stop
|
||||
}
|
||||
|
||||
$checksum = $preflightResponse.Headers["X-Checksum-Sha256"]
|
||||
$checksum = Get-ResponseHeaderValue -Headers $preflightResponse.Headers -Name "X-Checksum-Sha256"
|
||||
if ([string]::IsNullOrWhiteSpace($checksum)) {
|
||||
Write-InstallerEvent -Phase "preflight" -Code "agent_download_checksum_missing" -Message "Agent download exists but did not include a checksum header: $Uri" -ExitCode 12
|
||||
Exit 12
|
||||
|
|
@ -662,24 +699,57 @@ try {
|
|||
# Configure TLS 1.2 minimum
|
||||
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 -bor [Net.SecurityProtocolType]::Tls13
|
||||
|
||||
Invoke-WithOptionalInsecureTls -AllowInsecure $Insecure -CustomCaCertificate $CustomCaCertificate -Action {
|
||||
$downloadPreflightResponse = Invoke-WithOptionalInsecureTls -AllowInsecure $Insecure -CustomCaCertificate $CustomCaCertificate -Action {
|
||||
Invoke-WebRequest -Uri $DownloadUrl -Method Head -UseBasicParsing -TimeoutSec 10 -ErrorAction Stop
|
||||
}
|
||||
$serverChecksum = Get-ResponseHeaderValue -Headers $downloadPreflightResponse.Headers -Name "X-Checksum-Sha256"
|
||||
$serverSshSignature = Get-ResponseHeaderValue -Headers $downloadPreflightResponse.Headers -Name $InstallerSignatureHeaderName
|
||||
if ([string]::IsNullOrWhiteSpace($serverChecksum)) {
|
||||
Cleanup
|
||||
Show-Error "Server did not provide checksum header; refusing install."
|
||||
Exit 1
|
||||
}
|
||||
|
||||
$downloadMetadata = Invoke-WithOptionalInsecureTls -AllowInsecure $Insecure -CustomCaCertificate $CustomCaCertificate -Action {
|
||||
# Download with timeout
|
||||
$webClient = New-Object System.Net.WebClient
|
||||
$webClient.Headers.Add("User-Agent", "PulseInstaller/1.0")
|
||||
try {
|
||||
$webClient.Headers.Add("User-Agent", "PulseInstaller/1.0")
|
||||
|
||||
# Set up async download with timeout
|
||||
$downloadTask = $webClient.DownloadFileTaskAsync($DownloadUrl, $TempPath)
|
||||
if (-not $downloadTask.Wait($DownloadTimeoutSec * 1000)) {
|
||||
$webClient.CancelAsync()
|
||||
throw "Download timed out after $DownloadTimeoutSec seconds"
|
||||
}
|
||||
if ($downloadTask.IsFaulted) {
|
||||
throw $downloadTask.Exception.InnerException
|
||||
}
|
||||
# Set up async download with timeout
|
||||
$downloadTask = $webClient.DownloadFileTaskAsync($DownloadUrl, $TempPath)
|
||||
if (-not $downloadTask.Wait($DownloadTimeoutSec * 1000)) {
|
||||
$webClient.CancelAsync()
|
||||
throw "Download timed out after $DownloadTimeoutSec seconds"
|
||||
}
|
||||
if ($downloadTask.IsFaulted) {
|
||||
throw $downloadTask.Exception.InnerException
|
||||
}
|
||||
|
||||
# Get checksum from server response headers if available
|
||||
$serverChecksum = $webClient.ResponseHeaders["X-Checksum-Sha256"]
|
||||
$serverSshSignature = $webClient.ResponseHeaders[$InstallerSignatureHeaderName]
|
||||
# Prefer the same-download headers if Windows exposes them; otherwise
|
||||
# retain the HEAD metadata captured immediately before download.
|
||||
$downloadChecksum = Get-ResponseHeaderValue -Headers $webClient.ResponseHeaders -Name "X-Checksum-Sha256"
|
||||
$downloadSshSignature = Get-ResponseHeaderValue -Headers $webClient.ResponseHeaders -Name $InstallerSignatureHeaderName
|
||||
if (-not [string]::IsNullOrWhiteSpace($downloadChecksum)) {
|
||||
$serverChecksum = $downloadChecksum
|
||||
}
|
||||
if (-not [string]::IsNullOrWhiteSpace($downloadSshSignature)) {
|
||||
$serverSshSignature = $downloadSshSignature
|
||||
}
|
||||
|
||||
@{
|
||||
Checksum = $serverChecksum
|
||||
SshSignature = $serverSshSignature
|
||||
}
|
||||
} finally {
|
||||
$webClient.Dispose()
|
||||
}
|
||||
}
|
||||
if ($downloadMetadata -and -not [string]::IsNullOrWhiteSpace($downloadMetadata.Checksum)) {
|
||||
$serverChecksum = $downloadMetadata.Checksum
|
||||
}
|
||||
if ($downloadMetadata -and -not [string]::IsNullOrWhiteSpace($downloadMetadata.SshSignature)) {
|
||||
$serverSshSignature = $downloadMetadata.SshSignature
|
||||
}
|
||||
|
||||
} catch {
|
||||
|
|
@ -691,8 +761,6 @@ try {
|
|||
Read-Host
|
||||
}
|
||||
Exit 1
|
||||
} finally {
|
||||
if ($webClient) { $webClient.Dispose() }
|
||||
}
|
||||
|
||||
# --- Binary Verification ---
|
||||
|
|
|
|||
|
|
@ -171,9 +171,15 @@ func TestInstallPS1SupportsDownloadPreflightBeforeAdministratorInstall(t *testin
|
|||
`[bool]$NonInteractive = $false`,
|
||||
`if (-not $isAdmin -and -not $PreflightOnly) {`,
|
||||
`function Write-InstallerEvent {`,
|
||||
`function Get-ResponseHeaderValue {`,
|
||||
`function Invoke-AgentDownloadPreflight {`,
|
||||
`Invoke-WebRequest -Uri $Uri -Method Head -UseBasicParsing -TimeoutSec 10 -ErrorAction Stop`,
|
||||
`$checksum = $preflightResponse.Headers["X-Checksum-Sha256"]`,
|
||||
`$checksum = Get-ResponseHeaderValue -Headers $preflightResponse.Headers -Name "X-Checksum-Sha256"`,
|
||||
`$downloadPreflightResponse = Invoke-WithOptionalInsecureTls -AllowInsecure $Insecure -CustomCaCertificate $CustomCaCertificate -Action {`,
|
||||
`Invoke-WebRequest -Uri $DownloadUrl -Method Head -UseBasicParsing -TimeoutSec 10 -ErrorAction Stop`,
|
||||
`$serverChecksum = Get-ResponseHeaderValue -Headers $downloadPreflightResponse.Headers -Name "X-Checksum-Sha256"`,
|
||||
`$downloadMetadata = Invoke-WithOptionalInsecureTls -AllowInsecure $Insecure -CustomCaCertificate $CustomCaCertificate -Action {`,
|
||||
`$downloadChecksum = Get-ResponseHeaderValue -Headers $webClient.ResponseHeaders -Name "X-Checksum-Sha256"`,
|
||||
`agent_download_checksum_missing`,
|
||||
`agent_download_available`,
|
||||
`agent_download_unavailable`,
|
||||
|
|
@ -217,7 +223,8 @@ func TestInstallPS1UsesHostnameLookupForUninstallFallback(t *testing.T) {
|
|||
`$lookupHostname = $Hostname`,
|
||||
`$lookupHostname = $env:COMPUTERNAME`,
|
||||
`Uri = "$Url/api/agents/agent/lookup?hostname=$([System.Uri]::EscapeDataString($lookupHostname))"`,
|
||||
`$lookupResult = Invoke-RestMethod @lookupArgs`,
|
||||
`$lookupResult = Invoke-WithOptionalInsecureTls -AllowInsecure $Insecure -CustomCaCertificate $customCaCertificate -Action {`,
|
||||
`Invoke-RestMethod @lookupArgs`,
|
||||
}
|
||||
for _, needle := range required {
|
||||
if !strings.Contains(script, needle) {
|
||||
|
|
@ -313,7 +320,7 @@ func TestInstallPS1RequiresPinnedSignatureVerificationForReleaseDownloads(t *tes
|
|||
`function Test-HasPinnedInstallerSignatureKey {`,
|
||||
`function Invoke-InstallerSignatureVerification {`,
|
||||
`Get-Command ssh-keygen.exe -ErrorAction SilentlyContinue`,
|
||||
`$serverSshSignature = $webClient.ResponseHeaders[$InstallerSignatureHeaderName]`,
|
||||
`$serverSshSignature = Get-ResponseHeaderValue -Headers $downloadPreflightResponse.Headers -Name $InstallerSignatureHeaderName`,
|
||||
`Show-Error "Server did not provide checksum header; refusing signed install."`,
|
||||
`Show-Error "Server did not provide SSH signature header; refusing signed install."`,
|
||||
`Invoke-InstallerSignatureVerification -FilePath $TempPath -SignatureHeader $serverSshSignature`,
|
||||
|
|
|
|||
|
|
@ -3529,7 +3529,7 @@ class SubsystemLookupTest(unittest.TestCase):
|
|||
{
|
||||
"heading": "## Shared Boundaries",
|
||||
"path": "internal/api/access_control_handlers.go",
|
||||
"line": 274,
|
||||
"line": 278,
|
||||
"heading_line": 112,
|
||||
}
|
||||
],
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue