Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 19 additions & 9 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,13 @@ permissions:
env:
CARGO_TERM_COLOR: always
# The bundled Virtual Display Driver (VirtualDrivers/Virtual-Display-Driver,
# MIT). Pinned: the installer's scheduled tasks and lifecycle handling are
# verified against this exact version.
# MIT). Pinned by tag AND by the asset's SHA-256: upstream ships this setup
# wrapper unsigned (the driver files inside are the signed part), so exact-
# bytes pinning is the supply-chain gate — a re-tagged or replaced asset
# fails the build loudly.
VDD_RELEASE_TAG: "25.5.2"
VDD_ASSET: "Virtual.Display.Driver-v25.05.03-setup-x64.exe"
VDD_SHA256: "ca10b85babecfb636c85b3f04d2306968d4f940dd3dd35767f866207bfba846e"

jobs:
windows-installer:
Expand Down Expand Up @@ -64,22 +67,29 @@ jobs:
Invoke-WebRequest -Uri "https://raw.githubusercontent.com/VirtualDrivers/Virtual-Display-Driver/$env:VDD_RELEASE_TAG/LICENSE" `
-OutFile (Join-Path $dest "LICENSE-VirtualDisplayDriver.txt")

- name: Verify the driver's Authenticode signature
- name: Verify the driver against the pinned SHA-256
shell: pwsh
run: |
$sig = Get-AuthenticodeSignature "installer\vendor\vdd\$env:VDD_ASSET"
Write-Host "Signature status: $($sig.Status) Signer: $($sig.SignerCertificate.Subject)"
if ($sig.Status -ne "Valid") {
throw "Driver signature is '$($sig.Status)' — refusing to release an unverified driver."
$path = "installer\vendor\vdd\$env:VDD_ASSET"
$hash = (Get-FileHash $path -Algorithm SHA256).Hash.ToLower()
Write-Host "Downloaded: $hash"
Write-Host "Pinned: $env:VDD_SHA256"
if ($hash -ne $env:VDD_SHA256) {
throw "Driver asset hash mismatch — upstream bytes changed; re-vet the driver before updating the pin."
}
# Informational: upstream's setup wrapper is unsigned today (the
# driver files inside are the signed part). If this ever reports
# Valid, tighten this step into a hard signature check too.
$sig = Get-AuthenticodeSignature $path
Write-Host "Authenticode status (informational): $($sig.Status)"

- name: Install Inno Setup
shell: pwsh
run: choco install innosetup -y --no-progress

- name: Build the installer (strict driver signature)
- name: Build the installer
shell: pwsh
run: .\scripts\build-installer.ps1 -StrictSignature
run: .\scripts\build-installer.ps1

- name: Compute SHA-256
id: hash
Expand Down
11 changes: 7 additions & 4 deletions DECISIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,10 +143,13 @@ multi-monitor and virtual-display layouts land clicks on the right screen.

- One version, single-sourced from `host/Cargo.toml` (`env!` into the
banner and the mDNS TXT), matched by the iOS `MARKETING_VERSION`.
- CI builds releases from a `v*` tag: pinned FFmpeg, pinned driver version,
hard-fail Authenticode verification on the bundled driver, and the
installer's SHA-256 published in the release body, where the website
reads it.
- CI builds releases from a `v*` tag: pinned FFmpeg, and the bundled driver
pinned by tag AND by the asset's SHA-256 with a hard fail on mismatch.
(Upstream ships the setup wrapper unsigned — the driver files inside are
the signed part — so exact-bytes pinning is the supply-chain gate, and
the workflow reports the Authenticode status informationally in case
upstream starts signing.) The installer's SHA-256 is published in the
release body, where the website reads it.

## Deferred

Expand Down
10 changes: 7 additions & 3 deletions installer/vendor/vdd/README.txt
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,13 @@ license on its repository before public distribution.

VERIFY BEFORE BUNDLING
----------------------
After downloading, confirm the file is signed:
Get-AuthenticodeSignature .\Virtual.Display.Driver-v25.05.03-setup-x64.exe
The Status should be "Valid".
Upstream ships this setup wrapper UNSIGNED (Get-AuthenticodeSignature
reports NotSigned) — the signed part is the driver package inside it, which
Windows itself validates at install time. Verify the download by hash
instead; the vetted 25.5.2 asset is:
SHA-256: ca10b85babecfb636c85b3f04d2306968d4f940dd3dd35767f866207bfba846e
(Get-FileHash .\Virtual.Display.Driver-v25.05.03-setup-x64.exe)
The release workflow pins this same hash and fails the build on mismatch.

NOTE: files in this folder (other than this README) are git-ignored so the binary
is not committed to the repository.
7 changes: 4 additions & 3 deletions scripts/build-installer.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@
# Without it, the build still succeeds and produces an app-only installer.

param(
# Release builds (CI) pass this: an unsigned or invalidly-signed bundled
# driver then FAILS the build instead of warning. Local developer builds
# keep the warning so an unsigned test driver doesn't block iteration.
# Fail the build on a driver whose Authenticode signature isn't Valid.
# Today's upstream setup wrapper is unsigned (CI pins its SHA-256 in
# release.yml instead), so leave this off unless you are bundling a
# signed driver build and want the signature enforced.
[switch]$StrictSignature
)

Expand Down
Loading