name: "Bundle Desktop (Windows)" on: workflow_dispatch: inputs: signing: description: 'Whether to sign the Windows executable' required: false type: boolean default: false workflow_call: inputs: version: description: 'Version to build' required: false type: string signing: description: 'Whether to sign the Windows executable' required: false type: boolean default: false ref: description: 'Git ref to checkout' required: false type: string default: '' # Permissions required for OIDC authentication with Azure Trusted Signing permissions: id-token: write # Required to fetch the OIDC token for Azure federated credentials contents: read # Required by actions/checkout actions: read # May be needed for some workflows jobs: build-desktop-windows: name: Build Desktop (Windows) runs-on: windows-latest steps: - name: Checkout repository uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: ref: ${{ inputs.ref != '' && inputs.ref || '' }} - name: Set up Node.js uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 with: node-version: 24.10.0 - name: Install pnpm run: npm install -g pnpm@10.30.3 - name: Cache node_modules uses: actions/cache@8b402f58fbc84540c8b491a91e594a4576fec3d7 # v5.0.2 with: path: | node_modules ui/desktop/node_modules .hermit/node/cache key: windows-pnpm-cache-v1-${{ runner.os }}-node24-${{ hashFiles('**/pnpm-lock.yaml') }} restore-keys: | windows-pnpm-cache-v1-${{ runner.os }}-node24- - name: Cache Rust dependencies uses: Swatinem/rust-cache@v2 with: key: windows-msvc-desktop - name: Setup Rust shell: bash run: | rustup show rustup target add x86_64-pc-windows-msvc - name: Build Windows executable shell: bash run: | echo "🚀 Building Windows executable..." cargo build --release --target x86_64-pc-windows-msvc # Verify build succeeded if [ ! -f "./target/x86_64-pc-windows-msvc/release/goosed.exe" ]; then echo "❌ Windows binary not found." ls -la ./target/x86_64-pc-windows-msvc/release/ || echo "Release directory doesn't exist" exit 1 fi echo "✅ Windows binary found!" ls -la ./target/x86_64-pc-windows-msvc/release/goosed.exe - name: Prepare Windows binary shell: bash run: | if [ ! -f "./target/x86_64-pc-windows-msvc/release/goosed.exe" ]; then echo "Windows binary not found." exit 1 fi echo "Cleaning destination directory..." rm -rf ./ui/desktop/src/bin mkdir -p ./ui/desktop/src/bin echo "Copying Windows binary..." cp -f ./target/x86_64-pc-windows-msvc/release/goosed.exe ./ui/desktop/src/bin/ if [ -d "./ui/desktop/src/platform/windows/bin" ]; then echo "Copying Windows platform files..." for file in ./ui/desktop/src/platform/windows/bin/*.{exe,dll,cmd}; do if [ -f "$file" ] && [ "$(basename "$file")" != "goosed.exe" ]; then cp -f "$file" ./ui/desktop/src/bin/ fi done if [ -d "./ui/desktop/src/platform/windows/bin/goose-npm" ]; then echo "Setting up npm environment..." cp -r ./ui/desktop/src/platform/windows/bin/goose-npm/ ./ui/desktop/src/bin/goose-npm/ fi echo "Windows-specific files copied successfully" fi - name: Force GitHub HTTPS for npm git dependencies shell: bash run: | git config --global url."https://github.com/".insteadOf "ssh://git@github.com/" git config --global url."https://github.com/".insteadOf "git@github.com:" git config --global url."https://github.com/".insteadOf "git+ssh://git@github.com/" - name: Build desktop UI with pnpm shell: bash env: ELECTRON_PLATFORM: win32 run: | cd ui/desktop pnpm install --frozen-lockfile node scripts/build-main.js node scripts/prepare-platform-binaries.js pnpm run make --platform=win32 --arch=x64 - name: Copy exe to final out folder and prepare flat distribution shell: bash run: | cd ui/desktop mkdir -p ./out/Goose-win32-x64/resources/bin cp -r src/bin/* out/Goose-win32-x64/resources/bin/ mkdir -p ./dist-windows cp -r ./out/Goose-win32-x64/* ./dist-windows/ echo "📋 Final flat distribution structure:" ls -la ./dist-windows/ echo "📋 Binary files in resources/bin:" ls -la ./dist-windows/resources/bin/ - name: Upload unsigned distribution uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 with: name: windows-unsigned path: ui/desktop/dist-windows/ sign-desktop-windows: name: Sign Desktop (Windows) needs: build-desktop-windows if: inputs.signing runs-on: windows-latest environment: ${{ inputs.signing && 'signing' || null }} steps: - name: Download unsigned distribution uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 with: name: windows-unsigned path: dist-windows - name: Azure login uses: azure/login@a457da9ea143d694b1b9c7c869ebb04ebe844ef5 # v2.3.0 with: client-id: ${{ secrets.AZURE_CLIENT_ID }} tenant-id: ${{ secrets.AZURE_TENANT_ID }} subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} - name: Sign Windows executables with Azure Trusted Signing uses: azure/trusted-signing-action@b443cf8ea4124818d2ea9f043cba29fc3ec47b16 # v1.2.0 with: endpoint: ${{ secrets.AZURE_SIGNING_ENDPOINT }} trusted-signing-account-name: ${{ secrets.AZURE_SIGNING_ACCOUNT_NAME }} certificate-profile-name: ${{ secrets.AZURE_CERTIFICATE_PROFILE_NAME }} files: | ${{ github.workspace }}/dist-windows/Goose.exe ${{ github.workspace }}/dist-windows/resources/bin/goosed.exe - name: Verify signed executables shell: pwsh run: | $files = @( "dist-windows/Goose.exe", "dist-windows/resources/bin/goosed.exe" ) foreach ($file in $files) { Write-Output "Verifying signature: $file" $sig = Get-AuthenticodeSignature $file if ($sig.Status -ne "Valid") { throw "Signature invalid for ${file}: $($sig.Status)" } Write-Output "Signature valid: $file" } - name: Create Windows zip package shell: bash run: | 7z a -tzip "Goose-win32-x64.zip" dist-windows/ - name: Upload signed Windows build uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 with: name: Goose-win32-x64 path: Goose-win32-x64.zip # When signing is disabled, package the unsigned build directly package-desktop-windows: name: Package Desktop (Windows) needs: build-desktop-windows if: ${{ !inputs.signing }} runs-on: windows-latest steps: - name: Download unsigned distribution uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 with: name: windows-unsigned path: dist-windows - name: Create Windows zip package shell: bash run: | 7z a -tzip "Goose-win32-x64.zip" dist-windows/ - name: Upload Windows build uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 with: name: Goose-win32-x64 path: Goose-win32-x64.zip