From f120dbe9537b9e3211b57c707efc8197601b6dcf Mon Sep 17 00:00:00 2001 From: epstomai Date: Tue, 23 Jun 2026 15:37:14 +0800 Subject: [PATCH 1/2] inf: add PnpLockdown=1 to [Version] Modern InfVerif (WDK 26100+) rejects a driver package whose [Version] section omits PnpLockdown; it is required so installed driver files are protected from modification. Harmless on older toolchains. Co-Authored-By: Claude Opus 4.8 --- SynchronousAudioRouter/SynchronousAudioRouter.inf | 1 + 1 file changed, 1 insertion(+) diff --git a/SynchronousAudioRouter/SynchronousAudioRouter.inf b/SynchronousAudioRouter/SynchronousAudioRouter.inf index 036e664..1c32e08 100644 --- a/SynchronousAudioRouter/SynchronousAudioRouter.inf +++ b/SynchronousAudioRouter/SynchronousAudioRouter.inf @@ -9,6 +9,7 @@ ClassGuid={4d36e96c-e325-11ce-bfc1-08002be10318} Provider=%Provider% DriverVer=0.1 CatalogFile=SynchronousAudioRouter.cat +PnpLockdown=1 [ControlFlags] ExcludeFromSelect=* From 19c32dfa74b779bcba6d0748a9529b7e43a543b5 Mon Sep 17 00:00:00 2001 From: epstomai Date: Tue, 23 Jun 2026 15:37:15 +0800 Subject: [PATCH 2/2] ci: add verifiable WDK build + driver packaging pipeline Replace the non-building workflow stub with a pipeline that actually compiles the kernel driver and emits a signing-ready, verifiable package. - driver (x64): ensures the WindowsKernelModeDriver10.0 toolset is registered (works around the WDK-not-provisioned issue on windows-2022), auto-selects the SDK that carries the WDK kernel headers, builds unsigned (SignMode=Off), then stages .sys/.inf/.cat, builds a submission .cab, writes SHA256SUMS + BUILD-INFO, and attaches build provenance. - usermode (x64/x86): builds the SarAsio ASIO plugin. - tools/Install-WdkBuildEnv.ps1, tools/Package-SarDriver.ps1: reusable locally and in CI. - BUILDING.md: build, signing and follow-up notes (ARM64, Spectre, MSI). Signing is intentionally left to attestation / OSSign; the build only produces the verifiable, unsigned package they consume. Co-Authored-By: Claude Opus 4.8 --- .github/workflows/build.yml | 183 +++++++++++++++++++++++++++++++--- BUILDING.md | 89 +++++++++++++++++ tools/Install-WdkBuildEnv.ps1 | 94 +++++++++++++++++ tools/Package-SarDriver.ps1 | 116 +++++++++++++++++++++ 4 files changed, 466 insertions(+), 16 deletions(-) create mode 100644 BUILDING.md create mode 100644 tools/Install-WdkBuildEnv.ps1 create mode 100644 tools/Package-SarDriver.ps1 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a9992d9..7a2cdbf 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,36 +1,187 @@ -name: Build SynchronousAudioRouter +name: build-and-package + +# Verifiable WDK build pipeline. +# +# Produces, for every push/PR, an UNSIGNED but submission-ready driver package +# (.sys/.inf/.cat + a .cab) together with SHA-256 hashes and - on master/tags - +# a cryptographic build-provenance attestation linking each binary to its exact +# source commit. That provenance + reproducibility is what OSSign / Microsoft +# attestation signing require before they will sign the driver. See BUILDING.md. + on: workflow_dispatch: push: branches: [master] + tags: ["v*"] pull_request: branches: [master] + permissions: contents: read - pull-requests: read + concurrency: - group: "${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}" + group: "${{ github.workflow }}-${{ github.event.pull_request.head.label || github.head_ref || github.ref }}" cancel-in-progress: true -jobs: - build: - runs-on: windows-latest +env: + # Keep in lockstep with in the driver .vcxproj + # and with the defaults in tools/Install-WdkBuildEnv.ps1. + SDK_VERSION: "10.0.22621.0" + +jobs: + # --------------------------------------------------------------------------- + # Kernel driver: needs the WDK + its VS extension installed on the runner. + # ARM64 is intentionally omitted for now: the INF has no [Standard.NTARM64] + # model yet, so Inf2Cat cannot package it. Add that section first (see + # BUILDING.md) before enabling an ARM64 matrix entry. + # --------------------------------------------------------------------------- + driver: + name: driver (${{ matrix.platform }}) + runs-on: windows-2022 + permissions: + contents: read + id-token: write # required by attest-build-provenance + attestations: write + strategy: + fail-fast: false + matrix: + platform: [x64] steps: - uses: actions/checkout@v4 + with: + fetch-depth: 0 # tags needed for version stamping - - name: Setup MSBuild + - name: Add MSBuild to PATH uses: microsoft/setup-msbuild@v2 with: vs-version: "[17.0,18.0)" msbuild-architecture: x64 - - name: Build 32 - working-directory: ${{env.GITHUB_WORKSPACE}} - run: msbuild SynchronousAudioRouter.sln /t:Build /p:Configuration=Release /p:Platform=x86 /m /verbosity:minimal - - name: Build 64 - working-directory: ${{env.GITHUB_WORKSPACE}} - run: msbuild SynchronousAudioRouter.sln /t:Build /p:Configuration=Release /p:Platform=x64 /m /verbosity:minimal - - name: Artifact + + - name: Install WDK build environment + shell: pwsh + run: ./tools/Install-WdkBuildEnv.ps1 -SdkVersion "${{ env.SDK_VERSION }}" + + - name: Compute version + id: ver + shell: pwsh + run: | + $desc = (& git describe --tags --always --dirty 2>$null) + if (-not $desc) { $desc = "0.0.0-$(& git rev-parse --short HEAD)" } + $tag = (& git describe --tags --abbrev=0 2>$null) + if ($tag -match '(\d+)\.(\d+)\.(\d+)') { + $numeric = "$($Matches[1]).$($Matches[2]).$($Matches[3]).$env:GITHUB_RUN_NUMBER" + } else { + $numeric = "0.0.0.$env:GITHUB_RUN_NUMBER" + } + "describe=$desc" | Out-File $env:GITHUB_OUTPUT -Append + "numeric=$numeric" | Out-File $env:GITHUB_OUTPUT -Append + Write-Host "version: $desc (DriverVer numeric: $numeric)" + + - name: Build driver + shell: pwsh + run: | + # Pin to whatever 10.0.22621.x SDK the runner actually has installed, + # so the build doesn't fail if the image carries a different revision + # than the .0 hard-coded in the .vcxproj. + $inc = 'C:\Program Files (x86)\Windows Kits\10\Include' + # Pick the highest SDK version that ALSO ships the WDK kernel headers + # (km\ntifs.h). The image's plain SDK and its matching WDK can live under + # different version folders, so requiring km\ntifs.h guarantees both the + # headers and the matching kernel import libs are present for $sdk. + $sdk = (Get-ChildItem $inc -Directory | + Where-Object { Test-Path (Join-Path $_.FullName 'km\ntifs.h') } | + Sort-Object { [version]$_.Name } -Descending | + Select-Object -First 1).Name + if (-not $sdk) { throw "No SDK carrying WDK kernel headers (km\ntifs.h) under $inc" } + Write-Host "Using Windows SDK+WDK: $sdk" + + # SignMode=Off: leave the binary unsigned for attestation/OSSign to sign. + # SpectreMitigation=false: keep iteration-1 green without the Spectre libs; + # flip to Spectre + install the libs for production security (BUILDING.md). + & msbuild SynchronousAudioRouter.sln ` + /t:SynchronousAudioRouter ` + /p:Configuration=Release ` + /p:Platform=${{ matrix.platform }} ` + /p:WindowsTargetPlatformVersion=$sdk ` + /p:SignMode=Off ` + /p:SpectreMitigation=false ` + /m /verbosity:minimal /nologo + if ($LASTEXITCODE -ne 0) { throw "msbuild failed (exit $LASTEXITCODE)" } + + - name: Package + hash + shell: pwsh + run: | + ./tools/Package-SarDriver.ps1 ` + -Platform ${{ matrix.platform }} ` + -Configuration Release ` + -DriverVersion ${{ steps.ver.outputs.numeric }} ` + -Describe "${{ steps.ver.outputs.describe }}" + + - name: Attest build provenance + if: github.event_name == 'push' # OIDC token isn't writable on fork PRs + uses: actions/attest-build-provenance@v1 + with: + subject-path: artifacts/${{ matrix.platform }}/SynchronousAudioRouter.sys + + - name: Upload driver package + uses: actions/upload-artifact@v4 + with: + name: sar-driver-${{ matrix.platform }} + path: artifacts/${{ matrix.platform }}/ + if-no-files-found: error + + # --------------------------------------------------------------------------- + # User-mode ASIO plugin: plain MSVC, no WDK. 32-bit (Win32) is still built + # because 32-bit DAWs need a 32-bit ASIO DLL. + # --------------------------------------------------------------------------- + usermode: + name: usermode (${{ matrix.platform }}) + runs-on: windows-2022 + strategy: + fail-fast: false + matrix: + platform: [x64, x86] + steps: + - uses: actions/checkout@v4 + + - name: Add MSBuild to PATH + uses: microsoft/setup-msbuild@v2 + with: + vs-version: "[17.0,18.0)" + + - name: Build SarAsio + shell: pwsh + run: | + & msbuild SynchronousAudioRouter.sln ` + /t:SarAsio ` + /p:Configuration=Release ` + /p:Platform=${{ matrix.platform }} ` + /m /verbosity:minimal /nologo + if ($LASTEXITCODE -ne 0) { throw "msbuild failed (exit $LASTEXITCODE)" } + + - name: Collect + hash + shell: pwsh + run: | + $plat = "${{ matrix.platform }}" + $stage = "artifacts/$plat" + New-Item -ItemType Directory -Force -Path $stage | Out-Null + $dll = Get-ChildItem -Recurse -Filter 'SarAsio.dll' | + Where-Object { $_.FullName -match "\\Release\\" } | + Sort-Object LastWriteTime -Descending | Select-Object -First 1 + if (-not $dll) { throw "SarAsio.dll not found - did the build succeed?" } + Copy-Item $dll.FullName $stage -Force + # Materialize the hash lines into a variable BEFORE opening the output + # file, and skip the sums file itself - otherwise the same pipeline both + # reads and writes SHA256SUMS.txt and Get-FileHash hits a file lock. + $lines = Get-ChildItem $stage -File | + Where-Object { $_.Name -ne 'SHA256SUMS.txt' } | + Get-FileHash -Algorithm SHA256 | + ForEach-Object { '{0} {1}' -f $_.Hash, (Split-Path $_.Path -Leaf) } + $lines | Out-File "$stage/SHA256SUMS.txt" -Encoding ascii + + - name: Upload SarAsio uses: actions/upload-artifact@v4 with: - name: SynchronousAudioRouter - path: SarInstaller/bin/x64/Release/SynchronousAudioRouter.msi + name: sar-asio-${{ matrix.platform }} + path: artifacts/${{ matrix.platform }}/ + if-no-files-found: error diff --git a/BUILDING.md b/BUILDING.md new file mode 100644 index 0000000..faa5b22 --- /dev/null +++ b/BUILDING.md @@ -0,0 +1,89 @@ +# Building SynchronousAudioRouter + +This repo ships a verifiable WDK build pipeline (`.github/workflows/build.yml`) +plus two helper scripts under `tools/`. The goal is a **reproducible, unsigned, +submission-ready driver package** that can then be signed for free via +[OSSign](https://ossign.org/) or Microsoft attestation signing. The build itself +never signs anything — signing is a separate, later step. + +## What the pipeline produces + +For each run, the `driver` job emits an artifact `sar-driver-x64/` containing: + +| file | purpose | +|------|---------| +| `SynchronousAudioRouter.sys` | the unsigned kernel driver | +| `SynchronousAudioRouter.inf` | INF with a **valid** `DriverVer` stamped at build time | +| `SynchronousAudioRouter.cat` | security catalog generated by `Inf2Cat` | +| `SynchronousAudioRouter_x64.cab` | the package you submit for attestation signing | +| `SHA256SUMS.txt` | SHA-256 of every payload file | +| `BUILD-INFO.txt` | commit, version, platform, build time | + +On pushes to `master`/tags the job also produces a GitHub **build-provenance +attestation** for the `.sys`, cryptographically linking the binary to the exact +workflow run and source commit. Hashes + provenance are precisely the +"source ↔ binary is verifiable" property OSSign asks for. + +The `usermode` job builds the `SarAsio.dll` ASIO plugin for x64 and x86 (32-bit +DAWs need the 32-bit DLL). + +## Local build + +```powershell +# One-time: install the WDK + its VS extension (needs VS2022 already present) +./tools/Install-WdkBuildEnv.ps1 + +# Build the driver (unsigned) +msbuild SynchronousAudioRouter.sln /t:SynchronousAudioRouter ` + /p:Configuration=Release /p:Platform=x64 /p:SignMode=Off /p:SpectreMitigation=false + +# Stage, version-stamp, catalog, cab and hash it +./tools/Package-SarDriver.ps1 -Platform x64 -DriverVersion 0.13.2.0 -Describe local +``` + +## Signing (the part the build deliberately skips) + +A modified kernel driver does **not** inherit anyone else's signature; the +package above must be signed before stock Windows will load it without test mode. + +1. **For your own machine, right now (free):** enable test signing + (`bcdedit /set testsigning on`, reboot) and test-sign the `.sys`/`.cat`. Note + the desktop watermark and that this breaks most anti-cheat games and requires + Secure Boot off on Windows 11. +2. **For a clean, redistributable driver (free, the real goal):** submit + `SynchronousAudioRouter_x64.cab` to OSSign or, if you hold an EV certificate, + to Microsoft Partner Center for **attestation signing**. The returned + signature loads on stock Windows 11 with no test mode. + +## Known follow-ups (intentionally not done in iteration 1) + +These are tracked here so nothing is silently missing: + +- **ARM64.** The INF has only `[Standard.NTamd64]` / `[Standard.NTx86]` models, + so `Inf2Cat` cannot package ARM64. Add `[Standard.NTARM64]` (and the matching + install/service sections) before enabling an ARM64 matrix entry. This is the + step that matters for the Windows-on-Arm direction. +- **Spectre mitigation.** The build passes `/p:SpectreMitigation=false` to stay + green without the Spectre-mitigated runtime libs. For a production/attestation + driver, install those libs (VS component + `Microsoft.VisualStudio.Component.VC.Runtimes.x86.x64.Spectre`) and drop the + flag so it builds with `Spectre`. +- **`DriverVer` in source.** The committed INF still has the placeholder + `DriverVer=0.1`; the pipeline stamps a valid value at build time but the source + value should eventually be fixed too. +- **Installer (MSI).** The WiX `SarInstaller` project is not built by this + pipeline yet (needs the WiX 3.x toolset on the runner). The driver package is + sufficient for signing; the MSI is a packaging convenience to add back later. +- **EWDK alternative.** For maximum reproducibility you can swap the + `Install-WdkBuildEnv.ps1` step for a pinned **Enterprise WDK** ISO (a fully + self-contained, version-locked build environment). That removes the dependency + on the mutable runner image at the cost of a large ISO download per run. + +> Note on WDK/SDK version: the CI build does **not** hard-pin a version. The +> `Build driver` step auto-selects the highest SDK under `Windows Kits\10\Include` +> that actually carries the WDK kernel headers (`km\ntifs.h`) and passes it as +> `WindowsTargetPlatformVersion`. On today's `windows-2022` image that resolves to +> `10.0.26100` (the SDK pinned in the `.vcxproj`, `10.0.22621.0`, ships without the +> matching kernel headers, which is why pinning it broke the build). `SDK_VERSION` +> in the workflow and the param in `tools/Install-WdkBuildEnv.ps1` are only a +> fallback-download hint for machines that have no WDK at all. diff --git a/tools/Install-WdkBuildEnv.ps1 b/tools/Install-WdkBuildEnv.ps1 new file mode 100644 index 0000000..8ee35d4 --- /dev/null +++ b/tools/Install-WdkBuildEnv.ps1 @@ -0,0 +1,94 @@ +<# +.SYNOPSIS + Ensure the WDK kernel-mode platform toolset is available to MSBuild. + +.DESCRIPTION + GitHub's windows-2022 image ships the WDK (22H2) + VS2022, but a known + runner-images bug (actions/runner-images#5970) can leave the + "WindowsKernelModeDriver10.0" VS platform toolset *unregistered*, so the + driver project fails to load. This script is defensive and fast: + + 1. if the kernel toolset is already registered -> do nothing, + 2. else install the WDK.vsix that already ships on the image, + 3. only if no WDK is present at all -> download + install it (fallback). + + Keep $SdkVersion / $WdkFwlink in lockstep with the driver .vcxproj and the + workflow's SDK_VERSION when you bump the target WDK. + +.NOTES + Idempotent. Works under Windows PowerShell 5.1 and pwsh 7+. +#> +#Requires -Version 5.1 +[CmdletBinding()] +param( + [string]$SdkVersion = '10.0.22621.0', + # WDK for Windows 11, version 22H2 (fallback download only). + [string]$WdkFwlink = 'https://go.microsoft.com/fwlink/?linkid=2196230', + [string]$WorkDir = $(if ($env:RUNNER_TEMP) { $env:RUNNER_TEMP } else { $env:TEMP }) +) + +$ErrorActionPreference = 'Stop' +Set-StrictMode -Version Latest + +$VsixSearchRoots = @( + 'C:\Program Files (x86)\Windows Kits\10\Vsix', + 'C:\Program Files\Windows Kits\10\Vsix' +) + +function Find-VsInstall { + $vswhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" + if (-not (Test-Path $vswhere)) { throw "vswhere.exe not found: $vswhere" } + $p = (& $vswhere -latest -products * -property installationPath | Select-Object -First 1) + if (-not $p) { throw "No Visual Studio installation found by vswhere." } + return $p.Trim() +} + +function Test-KernelToolset([string]$vs) { + # The WDK VS extension registers the kernel-mode toolset here. + $tp = Join-Path $vs 'MSBuild\Microsoft\VC\v170\Platforms\x64\PlatformToolsets\WindowsKernelModeDriver10.0' + return (Test-Path $tp) +} + +function Find-WdkVsix { + Get-ChildItem -Path $VsixSearchRoots -Recurse -Filter 'WDK.vsix' -ErrorAction SilentlyContinue | + Sort-Object FullName -Descending | Select-Object -First 1 +} + +function Install-Vsix([string]$vs, [string]$vsixPath) { + $vsixInstaller = Join-Path $vs 'Common7\IDE\VSIXInstaller.exe' + if (-not (Test-Path $vsixInstaller)) { throw "VSIXInstaller.exe not found: $vsixInstaller" } + Write-Host "==> Installing extension: $vsixPath" + $proc = Start-Process -FilePath $vsixInstaller ` + -ArgumentList '/admin', '/quiet', "`"$vsixPath`"" -PassThru -Wait + # 0 = installed, 1001 = already installed. + if ($proc.ExitCode -notin 0, 1001) { throw "VSIXInstaller failed (exit $($proc.ExitCode))." } +} + +$vs = Find-VsInstall +Write-Host "==> Visual Studio: $vs" + +if (Test-KernelToolset $vs) { + Write-Host "==> WindowsKernelModeDriver10.0 toolset already registered - nothing to do." + return +} + +Write-Host "==> Kernel toolset missing; looking for the WDK extension on the image..." +$vsix = Find-WdkVsix + +if (-not $vsix) { + Write-Host "==> No WDK found on image; downloading (fallback) from $WdkFwlink ..." + $wdkSetup = Join-Path $WorkDir 'wdksetup.exe' + Invoke-WebRequest -Uri $WdkFwlink -OutFile $wdkSetup -UseBasicParsing + $proc = Start-Process -FilePath $wdkSetup ` + -ArgumentList '/q', '/norestart', '/ceip', 'off' -PassThru -Wait + if ($proc.ExitCode -notin 0, 3010) { throw "WDK install failed (exit $($proc.ExitCode))." } + $vsix = Find-WdkVsix + if (-not $vsix) { throw "WDK.vsix not found even after install." } +} + +Install-Vsix $vs $vsix.FullName + +if (-not (Test-KernelToolset $vs)) { + throw "WindowsKernelModeDriver10.0 still not registered after installing the WDK extension." +} +Write-Host "==> Kernel toolset registered. WDK build environment ready." diff --git a/tools/Package-SarDriver.ps1 b/tools/Package-SarDriver.ps1 new file mode 100644 index 0000000..8d6c8aa --- /dev/null +++ b/tools/Package-SarDriver.ps1 @@ -0,0 +1,116 @@ +<# +.SYNOPSIS + Stage, version-stamp, catalog and hash the built SynchronousAudioRouter driver + into a submission-ready, verifiable package. + +.DESCRIPTION + Run AFTER msbuild has produced SynchronousAudioRouter.sys. This script: + + 1. locates the freshly built .sys, + 2. stamps a valid DriverVer into a staged copy of the INF + (the committed INF still carries the placeholder "DriverVer=0.1", + which is illegal for a real package), + 3. generates the security catalog (.cat) with Inf2Cat, + 4. packs .sys/.inf/.cat into a .cab ready to submit for + Microsoft attestation signing (Partner Center) or to OSSign, + 5. writes SHA256SUMS.txt and BUILD-INFO.txt so the binary is + traceable back to its exact source commit. + + The build is intentionally UNSIGNED (SignMode=Off). Signing is a separate, + later step performed by the attestation service - see BUILDING.md. + +.NOTES + Designed for Windows PowerShell 5.1 and pwsh 7+. +#> +#Requires -Version 5.1 +[CmdletBinding()] +param( + [Parameter(Mandatory)] [ValidateSet('x64', 'ARM64')] [string]$Platform, + [string]$Configuration = 'Release', + + # Four-field DriverVer version (x.y.z.w), e.g. 0.13.2.137 + [Parameter(Mandatory)] [string]$DriverVersion, + + # Human-readable build label (e.g. `git describe` output), recorded in BUILD-INFO. + [string]$Describe = 'dev', + + [string]$OutDir = 'artifacts', + [string]$InfSource = 'SynchronousAudioRouter/SynchronousAudioRouter.inf' +) + +$ErrorActionPreference = 'Stop' +Set-StrictMode -Version Latest + +$repo = (Resolve-Path '.').Path +$stage = Join-Path $repo (Join-Path $OutDir $Platform) +New-Item -ItemType Directory -Force -Path $stage | Out-Null + +# 1. Locate the freshly built .sys (prefer the linker output under \). +$candidates = Get-ChildItem -Path $repo -Recurse -Filter 'SynchronousAudioRouter.sys' -ErrorAction SilentlyContinue +$sys = $candidates | Where-Object { $_.FullName -match "\\$Platform\\$Configuration\\" } | + Sort-Object LastWriteTime -Descending | Select-Object -First 1 +if (-not $sys) { $sys = $candidates | Sort-Object LastWriteTime -Descending | Select-Object -First 1 } +if (-not $sys) { throw "SynchronousAudioRouter.sys not found - did the driver build succeed?" } +Write-Host "==> Driver binary: $($sys.FullName)" +Copy-Item $sys.FullName (Join-Path $stage 'SynchronousAudioRouter.sys') -Force + +# 2. Stamp a valid DriverVer into a staged copy of the INF. +$today = (Get-Date).ToString('MM/dd/yyyy') +$inf = Get-Content -Raw -Path (Join-Path $repo $InfSource) +$inf = [regex]::Replace($inf, '(?m)^\s*DriverVer\s*=.*$', "DriverVer=$today,$DriverVersion") +$infOut = Join-Path $stage 'SynchronousAudioRouter.inf' +Set-Content -Path $infOut -Value $inf -Encoding ASCII +Write-Host "==> Stamped DriverVer=$today,$DriverVersion" + +# 3. Generate the security catalog (.cat) with Inf2Cat. +$inf2cat = Get-ChildItem "${env:ProgramFiles(x86)}\Windows Kits\10\bin" ` + -Recurse -Filter 'Inf2Cat.exe' -ErrorAction SilentlyContinue | + Sort-Object FullName -Descending | Select-Object -First 1 +if (-not $inf2cat) { throw "Inf2Cat.exe not found - is the WDK installed?" } +$osMap = @{ 'x64' = '10_X64'; 'ARM64' = '10_ARM64' } +$osList = $osMap[$Platform] +Write-Host "==> Inf2Cat (/os:$osList) ..." +& $inf2cat.FullName "/driver:$stage" "/os:$osList" /uselocaltime +if ($LASTEXITCODE -ne 0) { throw "Inf2Cat failed (exit $LASTEXITCODE)." } + +# 4. Build a .cab for attestation / OSSign submission. +$cabName = "SynchronousAudioRouter_$Platform.cab" +$ddf = Join-Path $stage '_package.ddf' +@" +.OPTION EXPLICIT +.Set CabinetNameTemplate=$cabName +.Set DiskDirectory1=$stage +.Set CompressionType=MSZIP +.Set Cabinet=on +.Set Compress=on +"$stage\SynchronousAudioRouter.sys" +"$stage\SynchronousAudioRouter.inf" +"$stage\SynchronousAudioRouter.cat" +"@ | Set-Content -Path $ddf -Encoding ASCII +Write-Host "==> makecab -> $cabName" +& makecab /f $ddf | Out-Null +if ($LASTEXITCODE -ne 0) { throw "makecab failed (exit $LASTEXITCODE)." } +Remove-Item $ddf, (Join-Path $stage 'setup.inf'), (Join-Path $stage 'setup.rpt') -ErrorAction SilentlyContinue + +# 5. Hashes + provenance, so the package is traceable to its source commit. +$payload = Get-ChildItem $stage -File | + Where-Object { $_.Extension -in '.sys', '.inf', '.cat', '.cab' } +$payload | Get-FileHash -Algorithm SHA256 | + ForEach-Object { '{0} {1}' -f $_.Hash, (Split-Path $_.Path -Leaf) } | + Out-File (Join-Path $stage 'SHA256SUMS.txt') -Encoding ascii + +$commit = (& git rev-parse HEAD 2>$null) +@" +SynchronousAudioRouter driver package +===================================== +describe : $Describe +commit : $commit +platform : $Platform +configuration : $Configuration +DriverVer : $today,$DriverVersion +built (UTC) : $((Get-Date).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ')) +sign mode : Off (UNSIGNED - submit the .cab to attestation/OSSign to sign) +"@ | Out-File (Join-Path $stage 'BUILD-INFO.txt') -Encoding ascii + +Write-Host "==> Package staged at: $stage" +Get-Content (Join-Path $stage 'SHA256SUMS.txt')