|
| 1 | +name: sync winredirect driver |
| 2 | + |
| 3 | +on: |
| 4 | + pull_request: |
| 5 | + branches: |
| 6 | + - main |
| 7 | + - dev |
| 8 | + paths: |
| 9 | + - '.github/scripts/compare_signed_pe.py' |
| 10 | + - '.github/workflows/winredirect-driver-sync.yml' |
| 11 | + - 'internal/winredirect/driver/**' |
| 12 | + |
| 13 | +permissions: |
| 14 | + contents: write |
| 15 | + |
| 16 | +concurrency: |
| 17 | + group: winredirect-driver-${{ github.event.pull_request.head.repo.full_name }}-${{ github.event.pull_request.head.ref }} |
| 18 | + cancel-in-progress: true |
| 19 | + |
| 20 | +jobs: |
| 21 | + sync: |
| 22 | + name: Refresh bundled drivers |
| 23 | + if: github.event.pull_request.head.repo.full_name == github.repository |
| 24 | + runs-on: windows-2025 |
| 25 | + env: |
| 26 | + REPO_DIR: C:\Users\sekai\Projects\sing-tun |
| 27 | + steps: |
| 28 | + - name: Checkout PR head |
| 29 | + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 |
| 30 | + with: |
| 31 | + fetch-depth: 0 |
| 32 | + ref: ${{ github.event.pull_request.head.ref }} |
| 33 | + |
| 34 | + - name: Install Windows SDK and WDK |
| 35 | + shell: pwsh |
| 36 | + run: | |
| 37 | + $sdkHeader = 'C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\um\Windows.h' |
| 38 | + $wdkHeader = 'C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\km\ntddk.h' |
| 39 | +
|
| 40 | + if (-not (Test-Path $sdkHeader)) { |
| 41 | + winget install --source winget --exact --id Microsoft.WindowsSDK.10.0.26100 --accept-source-agreements --accept-package-agreements --disable-interactivity --log "$env:RUNNER_TEMP\sdk-install.log" |
| 42 | + Write-Host "Windows SDK install exit code: $LASTEXITCODE" |
| 43 | + } |
| 44 | +
|
| 45 | + if (-not (Test-Path $wdkHeader)) { |
| 46 | + winget install --source winget --exact --id Microsoft.WindowsWDK.10.0.26100 --accept-source-agreements --accept-package-agreements --disable-interactivity --log "$env:RUNNER_TEMP\wdk-install.log" |
| 47 | + Write-Host "WDK install exit code: $LASTEXITCODE" |
| 48 | + } |
| 49 | +
|
| 50 | + if (-not (Test-Path $sdkHeader)) { |
| 51 | + throw "Windows SDK header not found after installation: $sdkHeader" |
| 52 | + } |
| 53 | + if (-not (Test-Path $wdkHeader)) { |
| 54 | + throw "WDK header not found after installation: $wdkHeader" |
| 55 | + } |
| 56 | +
|
| 57 | + - name: Mirror repository to stable Windows path |
| 58 | + shell: pwsh |
| 59 | + run: | |
| 60 | + if (Test-Path $env:REPO_DIR) { |
| 61 | + Remove-Item -LiteralPath $env:REPO_DIR -Recurse -Force |
| 62 | + } |
| 63 | + New-Item -ItemType Directory -Path (Split-Path -Parent $env:REPO_DIR) -Force | Out-Null |
| 64 | + robocopy $env:GITHUB_WORKSPACE $env:REPO_DIR /MIR /NFL /NDL /NJH /NJS /NP |
| 65 | + $robocopyExitCode = $LASTEXITCODE |
| 66 | + if ($robocopyExitCode -gt 7) { |
| 67 | + throw "robocopy failed with exit code $robocopyExitCode" |
| 68 | + } |
| 69 | + Write-Host "robocopy completed with exit code $robocopyExitCode" |
| 70 | + exit 0 |
| 71 | +
|
| 72 | + - name: Print toolchain versions |
| 73 | + shell: pwsh |
| 74 | + run: | |
| 75 | + $vswhere = Join-Path ${env:ProgramFiles(x86)} 'Microsoft Visual Studio\Installer\vswhere.exe' |
| 76 | + $vsInstall = & $vswhere -latest -products * -property installationPath | Select-Object -First 1 |
| 77 | + $msbuild = & $vswhere -latest -products * -requires Microsoft.Component.MSBuild -find 'MSBuild\**\Bin\MSBuild.exe' | Select-Object -First 1 |
| 78 | + if (-not $vsInstall) { |
| 79 | + throw 'Visual Studio installation path not found' |
| 80 | + } |
| 81 | + if (-not $msbuild) { |
| 82 | + throw 'MSBuild.exe not found' |
| 83 | + } |
| 84 | +
|
| 85 | + $vcToolsRoot = Join-Path $vsInstall 'VC\Tools\MSVC' |
| 86 | + $vcToolsVersion = (Get-ChildItem $vcToolsRoot | Sort-Object Name | Select-Object -Last 1).Name |
| 87 | + $kitsRoot = 'C:\Program Files (x86)\Windows Kits\10\Include' |
| 88 | + $sdkHeader = 'C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\um\Windows.h' |
| 89 | + $wdkHeader = 'C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\km\ntddk.h' |
| 90 | +
|
| 91 | + function Show-FileVersion([string] $label, [string] $path) { |
| 92 | + if (Test-Path $path) { |
| 93 | + $item = Get-Item $path |
| 94 | + Write-Host "$label path: $path" |
| 95 | + Write-Host "$label version: $($item.VersionInfo.FileVersion)" |
| 96 | + } else { |
| 97 | + Write-Host "$label path: missing ($path)" |
| 98 | + } |
| 99 | + } |
| 100 | +
|
| 101 | + Write-Host "Visual Studio install: $vsInstall" |
| 102 | + Write-Host "MSBuild path: $msbuild" |
| 103 | + & $msbuild -version |
| 104 | + Write-Host "VC tools root: $vcToolsRoot" |
| 105 | + Write-Host "VC tools version: $vcToolsVersion" |
| 106 | +
|
| 107 | + Show-FileVersion 'cl Hostx64 x64' (Join-Path $vcToolsRoot "$vcToolsVersion\bin\Hostx64\x64\cl.exe") |
| 108 | + Show-FileVersion 'cl Hostx64 ARM64' (Join-Path $vcToolsRoot "$vcToolsVersion\bin\Hostx64\arm64\cl.exe") |
| 109 | + Show-FileVersion 'link Hostx64 x64' (Join-Path $vcToolsRoot "$vcToolsVersion\bin\Hostx64\x64\link.exe") |
| 110 | + Show-FileVersion 'link Hostx64 ARM64' (Join-Path $vcToolsRoot "$vcToolsVersion\bin\Hostx64\arm64\link.exe") |
| 111 | +
|
| 112 | + Write-Host 'Windows Kits include directories:' |
| 113 | + Get-ChildItem $kitsRoot | Sort-Object Name | ForEach-Object { Write-Host " $($_.Name)" } |
| 114 | + Write-Host "Windows SDK header present: $(Test-Path $sdkHeader)" |
| 115 | + Write-Host "WDK header present: $(Test-Path $wdkHeader)" |
| 116 | +
|
| 117 | + - name: Build, verify reproducibility, and refresh tracked drivers |
| 118 | + id: sync |
| 119 | + shell: pwsh |
| 120 | + working-directory: ${{ env.REPO_DIR }} |
| 121 | + run: | |
| 122 | + git config --global --add safe.directory $env:REPO_DIR |
| 123 | +
|
| 124 | + $vswhere = Join-Path ${env:ProgramFiles(x86)} 'Microsoft Visual Studio\Installer\vswhere.exe' |
| 125 | + $msbuild = & $vswhere -latest -products * -requires Microsoft.Component.MSBuild -find 'MSBuild\**\Bin\MSBuild.exe' | Select-Object -First 1 |
| 126 | + if (-not $msbuild) { |
| 127 | + throw 'MSBuild.exe not found' |
| 128 | + } |
| 129 | +
|
| 130 | + $env:CL = '/Brepro' |
| 131 | + $env:LINK = '/Brepro' |
| 132 | + $artifactDir = Join-Path $env:RUNNER_TEMP 'winredirect-driver-sync' |
| 133 | + $failureDir = Join-Path $artifactDir 'failure' |
| 134 | + Remove-Item -LiteralPath $artifactDir -Recurse -Force -ErrorAction SilentlyContinue |
| 135 | + New-Item -ItemType Directory -Path $artifactDir -Force | Out-Null |
| 136 | +
|
| 137 | + function Invoke-DriverBuild([string] $platform) { |
| 138 | + Remove-Item -LiteralPath "internal/winredirect/driver/build/$platform" -Recurse -Force -ErrorAction SilentlyContinue |
| 139 | + Remove-Item -LiteralPath "internal/winredirect/driver/intermediate/$platform" -Recurse -Force -ErrorAction SilentlyContinue |
| 140 | + & $msbuild 'internal/winredirect/driver/winredirect.vcxproj' '/t:Rebuild' '/p:Configuration=Release' "/p:Platform=$platform" '/p:SpectreMitigation=false' '/v:minimal' |
| 141 | + if ($LASTEXITCODE -ne 0) { |
| 142 | + throw "MSBuild failed for $platform with exit code $LASTEXITCODE" |
| 143 | + } |
| 144 | + } |
| 145 | +
|
| 146 | + $targets = @( |
| 147 | + @{ platform = 'x64'; repo = 'internal/winredirect/amd64/winredirect.sys' }, |
| 148 | + @{ platform = 'ARM64'; repo = 'internal/winredirect/arm64/winredirect.sys' } |
| 149 | + ) |
| 150 | +
|
| 151 | + Write-Host 'ARM and x86 are intentionally skipped here: WDK 10.0.26100 on GitHub-hosted CI does not support them.' |
| 152 | +
|
| 153 | + $changed = $false |
| 154 | + foreach ($target in $targets) { |
| 155 | + $platform = $target.platform |
| 156 | + $tracked = $target.repo |
| 157 | + $buildOutput = "internal/winredirect/driver/build/$platform/Release/winredirect.sys" |
| 158 | + $run1 = Join-Path $artifactDir "$platform-run1.sys" |
| 159 | + $run2 = Join-Path $artifactDir "$platform-run2.sys" |
| 160 | +
|
| 161 | + Invoke-DriverBuild $platform |
| 162 | + Copy-Item -LiteralPath $buildOutput -Destination $run1 -Force |
| 163 | +
|
| 164 | + Invoke-DriverBuild $platform |
| 165 | + Copy-Item -LiteralPath $buildOutput -Destination $run2 -Force |
| 166 | +
|
| 167 | + & python '.github/scripts/compare_signed_pe.py' $run1 $run2 |
| 168 | + switch ($LASTEXITCODE) { |
| 169 | + 0 { |
| 170 | + Write-Host "$platform reproduced after stripping Authenticode data." |
| 171 | + } |
| 172 | + 1 { |
| 173 | + New-Item -ItemType Directory -Path $failureDir -Force | Out-Null |
| 174 | + Copy-Item -LiteralPath $run1 -Destination (Join-Path $failureDir "$platform-run1.sys") -Force |
| 175 | + Copy-Item -LiteralPath $run2 -Destination (Join-Path $failureDir "$platform-run2.sys") -Force |
| 176 | + throw "$platform build is not reproducible beyond signing metadata." |
| 177 | + } |
| 178 | + default { |
| 179 | + throw "reproducibility comparison failed for $platform with exit code $LASTEXITCODE" |
| 180 | + } |
| 181 | + } |
| 182 | +
|
| 183 | + & python '.github/scripts/compare_signed_pe.py' $run2 $tracked |
| 184 | + switch ($LASTEXITCODE) { |
| 185 | + 0 { |
| 186 | + Write-Host "$platform matches the tracked driver after stripping Authenticode data." |
| 187 | + } |
| 188 | + 1 { |
| 189 | + Write-Host "$platform differs beyond signing metadata; replacing tracked driver." |
| 190 | + Copy-Item -LiteralPath $run2 -Destination $tracked -Force |
| 191 | + git add -- $tracked |
| 192 | + $changed = $true |
| 193 | + } |
| 194 | + default { |
| 195 | + throw "comparison failed for $platform with exit code $LASTEXITCODE" |
| 196 | + } |
| 197 | + } |
| 198 | + } |
| 199 | +
|
| 200 | + if ($changed) { |
| 201 | + "changed=true" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append |
| 202 | + } else { |
| 203 | + "changed=false" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append |
| 204 | + } |
| 205 | +
|
| 206 | + - name: Upload failed reproducibility artifacts |
| 207 | + if: failure() |
| 208 | + uses: actions/upload-artifact@v4 |
| 209 | + with: |
| 210 | + name: winredirect-repro-failure-${{ github.run_id }}-${{ github.run_attempt }} |
| 211 | + path: ${{ runner.temp }}\winredirect-driver-sync\failure\*.sys |
| 212 | + if-no-files-found: warn |
| 213 | + |
| 214 | + - name: Commit and push refreshed drivers |
| 215 | + if: steps.sync.outputs.changed == 'true' |
| 216 | + shell: pwsh |
| 217 | + working-directory: ${{ env.REPO_DIR }} |
| 218 | + run: | |
| 219 | + git config user.name 'github-actions[bot]' |
| 220 | + git config user.email '41898282+github-actions[bot]@users.noreply.github.com' |
| 221 | +
|
| 222 | + git diff --cached --quiet |
| 223 | + if ($LASTEXITCODE -eq 0) { |
| 224 | + exit 0 |
| 225 | + } |
| 226 | +
|
| 227 | + git commit -m 'winredirect: update bundled drivers' |
| 228 | + git push origin "HEAD:${{ github.event.pull_request.head.ref }}" |
0 commit comments