fix(ci): guard win7 webview2 loader link against sccache

v0.6.0 shipped a win7/Server 2012 R2 installer whose dbx.exe statically
linked a WebView2 loader >= 1.0.1054.31 instead of the pinned 1.0.902.49,
failing on kernel 6.3 with ERROR_NOT_SUPPORTED. The loader patch rewrites
a file inside the cargo registry, which no compile cache can observe, so
the win7 release job stops using sccache until the loader is vendored,
and a binary audit now rejects any dbx.exe carrying post-1.0.902.49
loader strings.
This commit is contained in:
t8y2
2026-09-02 21:08:39 +08:00
parent 7d92433689
commit 11ff1c29a6
4 changed files with 94 additions and 38 deletions
@@ -0,0 +1,54 @@
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$BinaryPath
)
Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
# The Win7 / Server 2012 R2 bundle must statically link the WebView2 loader from
# SDK 1.0.902.49, the last one verified to work on kernel 6.1/6.3. Loader
# 1.0.1054.31 and everything newer fail on Server 2012 R2 with
# ERROR_NOT_SUPPORTED (0x80070032, MicrosoftEdge/WebView2Feedback#2025) and make
# the app show "Could not find the WebView2 Runtime". Those loaders carry error
# strings that 1.0.902.49 does not, so any of the markers below appearing in
# dbx.exe proves the pinned loader was not the one linked. The PE import audit
# cannot catch this: 1.0.1054.31 imports nothing newer than 1.0.902.49.
$loaderMarkers = @(
"Failed to find the Web",
"Failed to find the app",
"Failed to find an inst",
"WebView2: Failed to find an installed"
)
if (!(Test-Path -LiteralPath $BinaryPath -PathType Leaf)) {
throw "Win7 WebView2 loader audit target does not exist: $BinaryPath"
}
$resolvedPath = (Resolve-Path -LiteralPath $BinaryPath).Path
# Map every byte to one character so the ASCII needle search cannot miss on
# arbitrary binary content.
$latin1 = [System.Text.Encoding]::GetEncoding(28591)
$content = $latin1.GetString([System.IO.File]::ReadAllBytes($resolvedPath))
$violations = @()
foreach ($marker in $loaderMarkers) {
if ($content.Contains($marker)) {
$violations += $marker
}
}
if ($violations.Count -gt 0) {
$summary = $violations -join "`n"
throw @"
dbx.exe contains WebView2 loader strings newer than the pinned 1.0.902.49:
$summary
A loader >= 1.0.1054.31 was linked instead of the prepared one and will fail on
Server 2012 R2 with ERROR_NOT_SUPPORTED. Do not ship this binary: rebuild the
win7 target and investigate how the registry loader patch was bypassed.
"@
}
Write-Host "Win7 WebView2 loader audit passed: no post-1.0.902.49 loader markers in $resolvedPath"
+5
View File
@@ -258,6 +258,10 @@ jobs:
shell: pwsh
run: ./.github/scripts/assert-win7-pe-compat.ps1 -BinaryPath target/x86_64-win7-windows-msvc/release/dbx.exe
- name: Audit Win7 WebView2 loader markers
shell: pwsh
run: ./.github/scripts/assert-webview2-win7-loader.ps1 -BinaryPath target/x86_64-win7-windows-msvc/release/dbx.exe
- name: Bundle Windows 7 fixed-runtime installer
shell: pwsh
run: |
@@ -698,6 +702,7 @@ jobs:
- '.github/workflows/update-nix-pnpm-hash.yml'
windows_win7_bundle:
- '.github/scripts/assert-win7-pe-compat.ps1'
- '.github/scripts/assert-webview2-win7-loader.ps1'
- '.github/scripts/assert-win7-installer-content.ps1'
- '.github/scripts/assert-webview2-win7-runtime.ps1'
- '.github/scripts/prepare-webview2-win7-loader.ps1'
+10 -38
View File
@@ -551,10 +551,14 @@ jobs:
needs: release-ready
runs-on: windows-2022
environment: release-signing
# No sccache here: the loader patch rewrites a file inside the cargo
# registry, which is invisible to any compile cache. v0.6.0 shipped a
# binary linked against the wrong (>= 1.0.1054.31) WebView2 loader even
# though the patched 1.0.902.49 loader was verified on disk, so caching is
# disabled for this target until the patch is vendored into the source
# tree.
env:
CARGO_INCREMENTAL: "0"
RUSTC_WRAPPER: sccache
SCCACHE_GHA_ENABLED: ${{ secrets.SCCACHE_S3_BUCKET == '' && 'true' || 'false' }}
RUSTFLAGS: -C debuginfo=line-tables-only -C target-feature=+crt-static
VSIGN_CERT_HASH: ${{ vars.VSIGN_CERT_HASH }}
VSIGN_OPERATOR_SHA1: ${{ vars.VSIGN_OPERATOR_SHA1 }}
@@ -580,36 +584,6 @@ jobs:
toolchain: nightly-2026-07-22
components: rust-src
- name: Setup sccache
uses: mozilla-actions/sccache-action@9e7fa8a12102821edf02ca5dbea1acd0f89a2696 # v0.0.10
with:
version: "v0.10.0"
- name: Configure S3 sccache
if: env.SCCACHE_GHA_ENABLED != 'true'
shell: bash
env:
CACHE_BUCKET: ${{ secrets.SCCACHE_S3_BUCKET }}
CACHE_ENDPOINT: ${{ secrets.SCCACHE_S3_ENDPOINT }}
CACHE_REGION: ${{ secrets.SCCACHE_S3_REGION }}
CACHE_KEY_PREFIX: ${{ secrets.SCCACHE_S3_KEY_PREFIX }}
CACHE_ACCESS_KEY_ID: ${{ secrets.SCCACHE_S3_ACCESS_KEY_ID }}
CACHE_SECRET_ACCESS_KEY: ${{ secrets.SCCACHE_S3_SECRET_ACCESS_KEY }}
run: |
{
echo "SCCACHE_BUCKET=${CACHE_BUCKET}"
echo "SCCACHE_ENDPOINT=${CACHE_ENDPOINT}"
echo "SCCACHE_REGION=${CACHE_REGION}"
echo "SCCACHE_S3_KEY_PREFIX=${CACHE_KEY_PREFIX}"
echo "SCCACHE_S3_USE_SSL=true"
echo "AWS_ACCESS_KEY_ID=${CACHE_ACCESS_KEY_ID}"
echo "AWS_SECRET_ACCESS_KEY=${CACHE_SECRET_ACCESS_KEY}"
# Linking, bundling, and signing run for 30+ minutes after the last
# rustc call; the server's 10-minute default idle timeout would
# exit first and zero the counters shown by "Show sccache stats".
echo "SCCACHE_IDLE_TIMEOUT=0"
} >> "$GITHUB_ENV"
- name: Prepare Win7-compatible WebView2 loader
shell: pwsh
run: ./.github/scripts/prepare-webview2-win7-loader.ps1
@@ -644,6 +618,10 @@ jobs:
shell: pwsh
run: ./.github/scripts/assert-win7-pe-compat.ps1 -BinaryPath target/x86_64-win7-windows-msvc/release/dbx.exe
- name: Audit Win7 WebView2 loader markers
shell: pwsh
run: ./.github/scripts/assert-webview2-win7-loader.ps1 -BinaryPath target/x86_64-win7-windows-msvc/release/dbx.exe
- name: Setup TrustAsia VSign
shell: pwsh
env:
@@ -691,12 +669,6 @@ jobs:
gh release upload "${env:GITHUB_REF_NAME}" $offlineName $checksumName `
--repo "${env:GITHUB_REPOSITORY}" --clobber
- name: Show sccache stats
if: always()
continue-on-error: true
shell: bash
run: ${SCCACHE_PATH} --show-stats
- name: Remove temporary VSign files
if: always()
shell: pwsh
@@ -7,6 +7,7 @@ const template = readFileSync(resolve(process.cwd(), "src-tauri/windows/nsis/ins
const win7Config = JSON.parse(readFileSync(resolve(process.cwd(), "src-tauri/tauri.webview2-win7-fixed.conf.json"), "utf8"));
const win7RuntimeScript = readFileSync(resolve(process.cwd(), ".github/scripts/prepare-webview2-win7-runtime.ps1"), "utf8");
const win7PeAuditScript = readFileSync(resolve(process.cwd(), ".github/scripts/assert-win7-pe-compat.ps1"), "utf8");
const win7LoaderAuditScript = readFileSync(resolve(process.cwd(), ".github/scripts/assert-webview2-win7-loader.ps1"), "utf8");
const win7RuntimeProbeScript = readFileSync(resolve(process.cwd(), ".github/scripts/assert-webview2-win7-runtime.ps1"), "utf8");
const win7InstallerAuditScript = readFileSync(resolve(process.cwd(), ".github/scripts/assert-win7-installer-content.ps1"), "utf8");
const appCargoToml = readFileSync(resolve(process.cwd(), "src-tauri/Cargo.toml"), "utf8");
@@ -127,6 +128,30 @@ describe("Windows 7 fixed WebView2 runtime bundle", () => {
expect(win7PeAuditScript).toContain("dumpbin.exe");
});
it("audits the linked WebView2 loader in the final Win7 binary", () => {
expect(win7LoaderAuditScript).toContain('"Failed to find the Web"');
expect(win7LoaderAuditScript).toContain('"Failed to find the app"');
expect(win7LoaderAuditScript).toContain('"Failed to find an inst"');
expect(win7LoaderAuditScript).toContain('"WebView2: Failed to find an installed"');
expect(win7LoaderAuditScript).toContain("GetEncoding(28591)");
expect(ciWorkflow).toContain("./.github/scripts/assert-webview2-win7-loader.ps1");
expect(releaseWorkflow).toContain("./.github/scripts/assert-webview2-win7-loader.ps1");
});
it("keeps compile caching away from the Win7 WebView2 loader patch", () => {
const releaseWin7Job = releaseWorkflow.slice(releaseWorkflow.indexOf(" build-windows-7-offline:"), releaseWorkflow.indexOf(" static-browser:"));
const ciWin7Job = ciWorkflow.slice(ciWorkflow.indexOf(" windows-win7-bundle:"), ciWorkflow.indexOf(" duckdb-windows-driver:"));
// The loader patch rewrites a file inside the cargo registry, which no
// compile cache can see. v0.6.0 linked a >= 1.0.1054.31 loader despite the
// patched 1.0.902.49 one being verified on disk, so neither Win7 job may
// route rustc through sccache until the loader is vendored into the tree.
expect(releaseWin7Job).not.toContain("RUSTC_WRAPPER");
expect(releaseWin7Job).not.toContain("sccache-action");
expect(ciWin7Job).not.toContain("RUSTC_WRAPPER");
expect(ciWin7Job).not.toContain("sccache-action");
});
it("probes the fixed runtime through the Win7-compatible loader", () => {
expect(win7RuntimeProbeScript).toContain("GetAvailableCoreWebView2BrowserVersionString");
expect(win7RuntimeProbeScript).toContain('$ExpectedVersion = "109.0.1518.78"');