Add safe Windows desktop feed publication

This commit is contained in:
Курнат Андрей
2026-06-10 06:43:26 +03:00
parent 0ee974fa38
commit 0961491d52
4 changed files with 254 additions and 25 deletions
+21 -3
View File
@@ -36,11 +36,29 @@ feed with a concrete version:
</QSfera>
```
Validate the live feed before a Windows production release:
From the repository root, prepare the feed XML from a signed MSI and optionally
upload the MSI/feed to the web host:
```powershell
./scripts/validate-desktop-update-feed.ps1 -Url "https://qsfera.kusoft.xyz/desktop/updates/stable.xml"
./scripts/validate-production-release.ps1 -VerifyUpdateFeed
.\scripts\package-windows-desktop.ps1
.\scripts\publish-windows-desktop.ps1 -MsiPath ".\artifacts\windows-desktop\QSfera-Desktop-4.0.0-win-x64.msi"
.\scripts\publish-windows-desktop.ps1 `
-MsiPath ".\artifacts\windows-desktop\QSfera-Desktop-4.0.0-win-x64.msi" `
-RemoteHost "192.168.0.185" `
-RemoteDownloadDirectory "/var/www/qsfera/desktop/downloads" `
-RemoteFeedPath "/var/www/qsfera/desktop/updates/stable.xml"
```
`publish-windows-desktop.ps1` refuses remote publication when the MSI is not
Authenticode-signed. `-SkipSignatureCheck` is only for local feed validation and
is rejected when `-RemoteHost` is set.
From the repository root, validate the feed before a Windows production release:
```powershell
.\Desktop\scripts\validate-desktop-update-feed.ps1 -Url "https://qsfera.kusoft.xyz/desktop/updates/stable.xml"
.\Desktop\scripts\validate-desktop-update-feed.ps1 -Path ".\artifacts\windows-desktop\publish\stable.xml"
.\Desktop\scripts\validate-production-release.ps1 -VerifyUpdateFeed
```
For a stable signed tag release, `validate-production-release.ps1 -RequireSigning`
@@ -1,6 +1,10 @@
[CmdletBinding(DefaultParameterSetName = "Url")]
param(
[Parameter(Mandatory = $true)]
[string]$Url
[Parameter(Mandatory = $true, ParameterSetName = "Url")]
[string]$Url,
[Parameter(Mandatory = $true, ParameterSetName = "Path")]
[string]$Path
)
$ErrorActionPreference = "Stop"
@@ -10,27 +14,42 @@ function Fail($Message) {
exit 1
}
$parsedUrl = $null
if (-not [System.Uri]::TryCreate($Url, [System.UriKind]::Absolute, [ref]$parsedUrl)) {
Fail "Desktop update feed URL is not absolute: $Url"
}
$feedSource = $null
$feedContent = $null
if ($parsedUrl.Scheme -ne "https") {
Fail "Desktop update feed URL must use HTTPS: $Url"
if ($PSCmdlet.ParameterSetName -eq "Url") {
$parsedUrl = $null
if (-not [System.Uri]::TryCreate($Url, [System.UriKind]::Absolute, [ref]$parsedUrl)) {
Fail "Desktop update feed URL is not absolute: $Url"
}
if ($parsedUrl.Scheme -ne "https") {
Fail "Desktop update feed URL must use HTTPS: $Url"
}
try {
$response = Invoke-WebRequest -Uri $Url -UseBasicParsing -TimeoutSec 30
} catch {
Fail "Desktop update feed request failed for ${Url}: $($_.Exception.Message)"
}
if ($response.StatusCode -ne 200) {
Fail "Desktop update feed must return HTTP 200. Actual status: $($response.StatusCode)"
}
$feedSource = $Url
$feedContent = $response.Content
} else {
if (-not (Test-Path -LiteralPath $Path)) {
Fail "Desktop update feed file was not found: $Path"
}
$feedSource = (Resolve-Path -LiteralPath $Path).Path
$feedContent = Get-Content -LiteralPath $feedSource -Raw
}
try {
$response = Invoke-WebRequest -Uri $Url -UseBasicParsing -TimeoutSec 30
} catch {
Fail "Desktop update feed request failed for ${Url}: $($_.Exception.Message)"
}
if ($response.StatusCode -ne 200) {
Fail "Desktop update feed must return HTTP 200. Actual status: $($response.StatusCode)"
}
try {
[xml]$xml = $response.Content
[xml]$xml = $feedContent
} catch {
Fail "Desktop update feed is not valid XML: $($_.Exception.Message)"
}
@@ -82,4 +101,4 @@ if ([string]::IsNullOrWhiteSpace($version)) {
}
}
Write-Host "QSfera Desktop update feed validation passed: $Url"
Write-Host "QSfera Desktop update feed validation passed: $feedSource"