Skip to content

Commit 8e855ae

Browse files
committed
ci: verify downloaded releases on native Windows
1 parent ddb945e commit 8e855ae

3 files changed

Lines changed: 134 additions & 0 deletions

File tree

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
name: Verify Downloaded Release
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
tag:
7+
description: GitHub Release tag to download and verify
8+
required: true
9+
type: string
10+
11+
permissions:
12+
contents: read
13+
14+
jobs:
15+
windows-download-verification:
16+
runs-on: windows-latest
17+
steps:
18+
- uses: actions/checkout@v4
19+
- uses: actions/setup-python@v5
20+
with: {python-version: "3.11", cache: pip}
21+
- run: python -m pip install -e ".[dev]"
22+
- name: Download and verify published assets
23+
shell: powershell
24+
env:
25+
GH_TOKEN: ${{ github.token }}
26+
run: >-
27+
powershell.exe -NoProfile -ExecutionPolicy Bypass
28+
-File scripts/verify_downloaded_release.ps1
29+
-Tag "${{ inputs.tag }}"
30+
-Repository "${{ github.repository }}"
31+
-WorkRoot "${{ runner.temp }}\release-verification-${{ github.run_id }}"
32+
- uses: actions/upload-artifact@v4
33+
with:
34+
name: release-verification-${{ inputs.tag }}
35+
path: ${{ runner.temp }}/release-verification-${{ github.run_id }}/release-verification.json
36+
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
param(
2+
[Parameter(Mandatory=$true)][string]$Tag,
3+
[Parameter(Mandatory=$true)][string]$Repository,
4+
[Parameter(Mandatory=$true)][string]$WorkRoot
5+
)
6+
7+
$ErrorActionPreference = "Stop"
8+
if (Test-Path -LiteralPath $WorkRoot) { throw "Verification root already exists: $WorkRoot" }
9+
$download = Join-Path $WorkRoot "download"
10+
$bundle = Join-Path $WorkRoot "bundle"
11+
$install = Join-Path $WorkRoot "installed"
12+
New-Item -ItemType Directory -Path $download | Out-Null
13+
14+
& gh release download $Tag --repo $Repository --dir $download
15+
if ($LASTEXITCODE -ne 0) { throw "gh release download failed" }
16+
& python scripts\verify_checksums.py (Join-Path $download "SHA256SUMS.txt") $download
17+
if ($LASTEXITCODE -ne 0) { throw "Downloaded aggregate SHA256 verification failed" }
18+
19+
$archives = @(Get-ChildItem -LiteralPath $download -Filter "multi-api-test-executor-*-windows-x64.zip")
20+
if ($archives.Count -ne 1) { throw "Expected exactly one Windows x64 release archive" }
21+
New-Item -ItemType Directory -Path $bundle | Out-Null
22+
Expand-Archive -LiteralPath $archives[0].FullName -DestinationPath $bundle
23+
24+
$env:PIP_NO_INDEX = "1"
25+
$env:PIP_DISABLE_PIP_VERSION_CHECK = "1"
26+
try {
27+
& powershell.exe -NoProfile -ExecutionPolicy Bypass -File (Join-Path $bundle "installers\install.ps1") -InstallRoot $install -SourceDirectory $bundle -PythonCommand python
28+
if ($LASTEXITCODE -ne 0) { throw "Downloaded Bundle installation failed" }
29+
} finally {
30+
Remove-Item Env:PIP_NO_INDEX -ErrorAction SilentlyContinue
31+
Remove-Item Env:PIP_DISABLE_PIP_VERSION_CHECK -ErrorAction SilentlyContinue
32+
}
33+
34+
$runner = Join-Path $install "multi-api.cmd"
35+
$installedPython = Join-Path $install "Scripts\python.exe"
36+
& $runner doctor
37+
if ($LASTEXITCODE -ne 0) { throw "Downloaded Runner doctor failed" }
38+
& $runner doctor --quick
39+
if ($LASTEXITCODE -ne 0) { throw "Downloaded Runner doctor --quick failed" }
40+
$version = (& $runner version | Out-String).Trim()
41+
$tagVersion = $Tag.TrimStart("v").Split("-", 2)[0]
42+
if ($version -ne $tagVersion) { throw "Runner version $version does not match tag $Tag" }
43+
$installInfo = (& $runner install-info | Out-String | ConvertFrom-Json)
44+
if (-not $installInfo.managed -or $installInfo.runner_version -ne $tagVersion) {
45+
throw "Installed state does not match the release version"
46+
}
47+
48+
$statePath = Join-Path $install "install-state.json"
49+
$stateHash = (Get-FileHash $statePath -Algorithm SHA256).Hash
50+
$env:INSTALLED_RUNNER = $runner
51+
$env:INSTALLED_PYTHON = $installedPython
52+
& python -m pytest tests\e2e\test_offline_cli.py -q
53+
if ($LASTEXITCODE -ne 0) { throw "First downloaded Release E2E failed" }
54+
& python -m pytest tests\e2e\test_offline_cli.py -q
55+
if ($LASTEXITCODE -ne 0) { throw "Second downloaded Release E2E failed" }
56+
$finalStateHash = (Get-FileHash $statePath -Algorithm SHA256).Hash
57+
if ($finalStateHash -ne $stateHash) { throw "Normal execution modified install-state.json" }
58+
59+
$audit = [ordered]@{
60+
tag = $Tag
61+
repository = $Repository
62+
runner_version = $version
63+
doctor = "healthy"
64+
doctor_quick = "healthy"
65+
aggregate_checksums = "verified"
66+
offline_install = "passed"
67+
e2e_runs = 2
68+
install_state_unchanged = $true
69+
install_state_sha256 = $stateHash.ToLowerInvariant()
70+
verified_at_utc = [DateTime]::UtcNow.ToString("o")
71+
}
72+
$audit | ConvertTo-Json -Depth 4 | Set-Content -LiteralPath (Join-Path $WorkRoot "release-verification.json") -Encoding utf8
73+
Write-Output ($audit | ConvertTo-Json -Compress)

tests/unit/test_release_packaging.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,28 @@ def test_release_asset_validator_requires_complete_exact_inventory(tmp_path: Pat
7070
assert "missing" in str(exc)
7171
else:
7272
raise AssertionError("incomplete release inventory was accepted")
73+
74+
75+
def test_downloaded_release_verification_contract_is_native_and_offline() -> None:
76+
workflow = (ROOT / ".github/workflows/release-verification.yml").read_text(encoding="utf-8")
77+
script = (ROOT / "scripts/verify_downloaded_release.ps1").read_text(encoding="utf-8")
78+
for phrase in [
79+
"windows-latest",
80+
'python-version: "3.11"',
81+
"workflow_dispatch:",
82+
"scripts/verify_downloaded_release.ps1",
83+
"actions/upload-artifact@v4",
84+
]:
85+
assert phrase in workflow
86+
for phrase in [
87+
"gh release download",
88+
"SHA256SUMS.txt",
89+
"PIP_NO_INDEX",
90+
"installers\\install.ps1",
91+
"multi-api.cmd",
92+
"doctor --quick",
93+
"tests\\e2e\\test_offline_cli.py",
94+
"install-state.json",
95+
"release-verification.json",
96+
]:
97+
assert phrase in script

0 commit comments

Comments
 (0)