Skip to content

Commit 6e66c92

Browse files
feat(desktop): sign every Windows release artifact (#1548)
1 parent 873c203 commit 6e66c92

89 files changed

Lines changed: 2501 additions & 2833 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/build-desktop.yaml

Lines changed: 81 additions & 170 deletions
Original file line numberDiff line numberDiff line change
@@ -83,12 +83,6 @@ jobs:
8383
timeout-minutes: 25
8484
outputs:
8585
matrix: ${{ steps.set-matrix.outputs.matrix }}
86-
windows_x64: ${{ steps.set-matrix.outputs.windows_x64 }}
87-
windows_arm64: ${{ steps.set-matrix.outputs.windows_arm64 }}
88-
windows_x64_default: ${{ steps.set-matrix.outputs.windows_x64_default }}
89-
windows_arm64_default: ${{ steps.set-matrix.outputs.windows_arm64_default }}
90-
windows_game_capture_x64: ${{ steps.set-matrix.outputs.windows_game_capture_x64 }}
91-
windows_game_capture_arm64: ${{ steps.set-matrix.outputs.windows_game_capture_arm64 }}
9286
steps:
9387
- name: Checkout source
9488
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
@@ -135,11 +129,9 @@ jobs:
135129
DESKTOP_PLATFORM: ${{ matrix.platform }}
136130
DESKTOP_ARCH: ${{ matrix.arch }}
137131
DESKTOP_VARIANT: ${{ matrix.desktop_variant }}
138-
FLUXER_DESKTOP_BUILD_VARIANT: ${{ matrix.desktop_variant }}
139132
PLATFORM: ${{ matrix.platform }}
140133
ARCH: ${{ matrix.arch }}
141134
ELECTRON_ARCH: ${{ matrix.electron_arch }}
142-
FLUXER_WINDOWS_GAME_CAPTURE_MODULE_ENABLED: ${{ matrix.desktop_variant == 'windows-game-capture' && 'true' || 'false' }}
143135
steps:
144136
- name: Checkout CI helpers
145137
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
@@ -339,6 +331,83 @@ jobs:
339331
cargo run --locked --quiet --manifest-path ${{ github.workspace }}/_ci/tools/ci/Cargo.toml -- build-desktop
340332
--step build_app_windows
341333
334+
- name: Validate Windows signing inputs
335+
if: matrix.platform == 'windows'
336+
env:
337+
AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
338+
AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
339+
AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
340+
AZURE_ARTIFACT_SIGNING_ENDPOINT: ${{ secrets.AZURE_ARTIFACT_SIGNING_ENDPOINT }}
341+
AZURE_ARTIFACT_SIGNING_ACCOUNT_NAME: ${{ secrets.AZURE_ARTIFACT_SIGNING_ACCOUNT_NAME }}
342+
AZURE_ARTIFACT_SIGNING_CERTIFICATE_PROFILE_NAME: ${{ secrets.AZURE_ARTIFACT_SIGNING_CERTIFICATE_PROFILE_NAME }}
343+
run: >-
344+
cargo run --locked --quiet --manifest-path ${{ github.workspace }}/_ci/tools/ci/Cargo.toml -- build-desktop
345+
--step validate_windows_signing_inputs
346+
347+
- name: Azure login for Artifact Signing
348+
if: matrix.platform == 'windows'
349+
uses: azure/login@532459ea530d8321f2fb9bb10d1e0bcf23869a43
350+
with:
351+
client-id: ${{ secrets.AZURE_CLIENT_ID }}
352+
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
353+
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
354+
355+
- name: Write Velopack Trusted Signing metadata
356+
if: matrix.platform == 'windows'
357+
env:
358+
AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
359+
AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
360+
AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
361+
AZURE_ARTIFACT_SIGNING_ENDPOINT: ${{ secrets.AZURE_ARTIFACT_SIGNING_ENDPOINT }}
362+
AZURE_ARTIFACT_SIGNING_ACCOUNT_NAME: ${{ secrets.AZURE_ARTIFACT_SIGNING_ACCOUNT_NAME }}
363+
AZURE_ARTIFACT_SIGNING_CERTIFICATE_PROFILE_NAME: ${{ secrets.AZURE_ARTIFACT_SIGNING_CERTIFICATE_PROFILE_NAME }}
364+
run: >-
365+
cargo run --locked --quiet --manifest-path ${{ github.workspace }}/_ci/tools/ci/Cargo.toml -- build-desktop
366+
--step write_windows_signing_metadata
367+
368+
- name: Resolve unpacked Windows app directory
369+
id: resolve_unpacked
370+
if: matrix.platform == 'windows'
371+
working-directory: ${{ env.WORKDIR }}/fluxer_desktop
372+
env:
373+
BUILD_CHANNEL: ${{ env.BUILD_CHANNEL }}
374+
run: >-
375+
cargo run --locked --quiet --manifest-path ${{ github.workspace }}/_ci/tools/ci/Cargo.toml -- build-desktop
376+
--step resolve_windows_unpacked_dir
377+
378+
- name: Sign unpacked Windows binaries with Artifact Signing
379+
if: matrix.platform == 'windows'
380+
uses: azure/artifact-signing-action@c7ab2a863ab5f9a846ddb8265964877ef296ee82
381+
with:
382+
endpoint: ${{ secrets.AZURE_ARTIFACT_SIGNING_ENDPOINT }}
383+
signing-account-name: ${{ secrets.AZURE_ARTIFACT_SIGNING_ACCOUNT_NAME }}
384+
certificate-profile-name: ${{ secrets.AZURE_ARTIFACT_SIGNING_CERTIFICATE_PROFILE_NAME }}
385+
files-folder: ${{ steps.resolve_unpacked.outputs.unpacked_dir }}
386+
files-folder-filter: exe,dll,node
387+
files-folder-recurse: true
388+
file-digest: SHA256
389+
timestamp-rfc3161: http://timestamp.acs.microsoft.com
390+
timestamp-digest: SHA256
391+
exclude-environment-credential: true
392+
393+
- name: Verify unpacked Windows signatures
394+
if: matrix.platform == 'windows'
395+
working-directory: ${{ env.WORKDIR }}/fluxer_desktop
396+
env:
397+
BUILD_CHANNEL: ${{ env.BUILD_CHANNEL }}
398+
run: >-
399+
cargo run --locked --quiet --manifest-path ${{ github.workspace }}/_ci/tools/ci/Cargo.toml -- build-desktop
400+
--step verify_windows_unpacked_signatures
401+
402+
- name: Create portable ZIP (Windows)
403+
if: matrix.platform == 'windows'
404+
working-directory: ${{ env.WORKDIR }}/fluxer_desktop
405+
env:
406+
BUILD_CHANNEL: ${{ env.BUILD_CHANNEL }}
407+
run: >-
408+
cargo run --locked --quiet --manifest-path ${{ github.workspace }}/_ci/tools/ci/Cargo.toml -- build-desktop
409+
--step create_portable_zip_windows
410+
342411
- name: Package Windows app with Velopack
343412
if: matrix.platform == 'windows'
344413
working-directory: ${{ env.WORKDIR }}/fluxer_desktop
@@ -370,14 +439,14 @@ jobs:
370439
cargo run --locked --quiet --manifest-path ${{ github.workspace }}/_ci/tools/ci/Cargo.toml -- build-desktop
371440
--step build_app_linux
372441
373-
- name: Create portable ZIP (Windows)
442+
- name: Verify signed Windows artifacts
374443
if: matrix.platform == 'windows'
375444
working-directory: ${{ env.WORKDIR }}/fluxer_desktop
376445
env:
377446
BUILD_CHANNEL: ${{ env.BUILD_CHANNEL }}
378447
run: >-
379448
cargo run --locked --quiet --manifest-path ${{ github.workspace }}/_ci/tools/ci/Cargo.toml -- build-desktop
380-
--step create_portable_zip_windows
449+
--step verify_windows_signed_artifacts
381450
382451
- name: Prepare artifacts (Windows)
383452
if: runner.os == 'Windows'
@@ -409,162 +478,17 @@ jobs:
409478
cargo run --locked --quiet --manifest-path ${{ github.workspace }}/_ci/tools/ci/Cargo.toml -- build-desktop
410479
--step generate_checksums_windows
411480
412-
- name: Build desktop source tarball
413-
if: matrix.platform == 'linux' && matrix.arch == 'x64' && needs.meta.outputs.build_channel == 'canary'
414-
run: >-
415-
cargo run --locked --quiet --manifest-path ${{ github.workspace }}/_ci/tools/ci/Cargo.toml -- build-desktop
416-
--step build_source_tarball
417-
418481
- name: Upload artifacts to S3 handoff
419482
run: >-
420483
cargo run --locked --quiet --manifest-path ${{ github.workspace }}/_ci/tools/ci/Cargo.toml -- build-desktop
421484
--step upload_handoff
422485
423-
check_signing:
424-
name: Check signing secrets
425-
runs-on: ubuntu-24.04-arm
426-
environment: desktop-releases
427-
timeout-minutes: 5
428-
outputs:
429-
enabled: ${{ steps.check.outputs.enabled }}
430-
steps:
431-
- name: Checkout source
432-
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
433-
434-
- name: Set up Rust toolchain (CI helpers)
435-
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9
436-
with:
437-
toolchain: "1.93.0"
438-
439-
- name: Check for Azure signing secrets
440-
id: check
441-
env:
442-
AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
443-
run: >-
444-
cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- build-desktop
445-
--step check_signing_secrets
446-
447-
sign_windows:
448-
name: Sign Windows artifacts (${{ matrix.arch }}, ${{ matrix.desktop_variant }})
449-
if: ${{ needs.check_signing.outputs.enabled == 'true' }}
450-
needs:
451-
- meta
452-
- matrix
453-
- build
454-
- check_signing
455-
runs-on: blacksmith-32vcpu-windows-2025
456-
environment: desktop-releases
457-
timeout-minutes: 25
458-
env:
459-
BUILD_CHANNEL: ${{ needs.meta.outputs.build_channel }}
460-
DESKTOP_HANDOFF_PREFIX: _handoff/desktop/${{ needs.meta.outputs.build_channel }}/${{ needs.meta.outputs.version }}/${{ needs.meta.outputs.source_sha }}
461-
S3_ENDPOINT: https://ewr1.vultrobjects.com
462-
S3_BUCKET: fluxer-downloads
463-
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
464-
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
465-
EXPECT_WINDOWS_X64: ${{ needs.matrix.outputs.windows_x64 }}
466-
EXPECT_WINDOWS_ARM64: ${{ needs.matrix.outputs.windows_arm64 }}
467-
EXPECT_WINDOWS_X64_DEFAULT: ${{ needs.matrix.outputs.windows_x64_default }}
468-
EXPECT_WINDOWS_ARM64_DEFAULT: ${{ needs.matrix.outputs.windows_arm64_default }}
469-
EXPECT_WINDOWS_GAME_CAPTURE_X64: ${{ needs.matrix.outputs.windows_game_capture_x64 }}
470-
EXPECT_WINDOWS_GAME_CAPTURE_ARM64: ${{ needs.matrix.outputs.windows_game_capture_arm64 }}
471-
EXPECT_WINDOWS_ARTIFACTS: ${{ (matrix.desktop_variant == 'default' && matrix.arch == 'x64' && needs.matrix.outputs.windows_x64_default == 'true') || (matrix.desktop_variant == 'default' && matrix.arch == 'arm64' && needs.matrix.outputs.windows_arm64_default == 'true') || (matrix.desktop_variant == 'windows-game-capture' && matrix.arch == 'x64' && needs.matrix.outputs.windows_game_capture_x64 == 'true') || (matrix.desktop_variant == 'windows-game-capture' && matrix.arch == 'arm64' && needs.matrix.outputs.windows_game_capture_arm64 == 'true') }}
472-
DESKTOP_VARIANT: ${{ matrix.desktop_variant }}
473-
strategy:
474-
fail-fast: false
475-
matrix:
476-
include:
477-
- arch: x64
478-
desktop_variant: default
479-
- arch: arm64
480-
desktop_variant: default
481-
- arch: x64
482-
desktop_variant: windows-game-capture
483-
- arch: arm64
484-
desktop_variant: windows-game-capture
485-
steps:
486-
- name: Checkout CI helpers
487-
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
488-
with:
489-
ref: ${{ needs.meta.outputs.source_sha }}
490-
491-
- name: Set up Rust toolchain (CI helpers)
492-
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9
493-
with:
494-
toolchain: "1.93.0"
495-
496-
- name: Download Windows artifacts from S3 handoff
497-
id: download_artifact
498-
if: env.EXPECT_WINDOWS_ARTIFACTS == 'true'
499-
env:
500-
ARCH: ${{ matrix.arch }}
501-
run: >-
502-
cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- build-desktop
503-
--step download_windows_handoff
504-
505-
- name: Check whether artifacts exist for this arch
506-
id: check_artifacts
507-
env:
508-
ARCH: ${{ matrix.arch }}
509-
run: >-
510-
cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- build-desktop
511-
--step check_windows_artifacts
512-
513-
- name: Azure login for Artifact Signing
514-
if: steps.check_artifacts.outputs.found == 'true'
515-
uses: azure/login@532459ea530d8321f2fb9bb10d1e0bcf23869a43
516-
with:
517-
client-id: ${{ secrets.AZURE_CLIENT_ID }}
518-
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
519-
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
520-
521-
- name: Sign Windows executables with Artifact Signing
522-
if: steps.check_artifacts.outputs.found == 'true'
523-
uses: azure/artifact-signing-action@c7ab2a863ab5f9a846ddb8265964877ef296ee82
524-
with:
525-
endpoint: ${{ secrets.AZURE_ARTIFACT_SIGNING_ENDPOINT }}
526-
signing-account-name: ${{ secrets.AZURE_ARTIFACT_SIGNING_ACCOUNT_NAME }}
527-
certificate-profile-name: ${{ secrets.AZURE_ARTIFACT_SIGNING_CERTIFICATE_PROFILE_NAME }}
528-
files-folder: ${{ github.workspace }}\artifacts\windows-${{ matrix.arch }}${{ matrix.desktop_variant == 'windows-game-capture' && '-windows-game-capture' || '' }}
529-
files-folder-filter: exe
530-
files-folder-recurse: true
531-
file-digest: SHA256
532-
timestamp-rfc3161: http://timestamp.acs.microsoft.com
533-
timestamp-digest: SHA256
534-
535-
- name: Verify Authenticode signatures
536-
if: steps.check_artifacts.outputs.found == 'true'
537-
env:
538-
ARCH: ${{ matrix.arch }}
539-
run: >-
540-
cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- build-desktop
541-
--step verify_authenticode
542-
543-
- name: Regenerate SHA256 checksums for signed executables
544-
if: steps.check_artifacts.outputs.found == 'true'
545-
env:
546-
ARCH: ${{ matrix.arch }}
547-
run: >-
548-
cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- build-desktop
549-
--step regenerate_signed_checksums
550-
551-
- name: Re-upload signed Windows artifacts to S3 handoff
552-
if: steps.check_artifacts.outputs.found == 'true'
553-
env:
554-
DESKTOP_PLATFORM: windows
555-
DESKTOP_ARCH: ${{ matrix.arch }}
556-
DESKTOP_VARIANT: ${{ matrix.desktop_variant }}
557-
run: >-
558-
cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- build-desktop
559-
--step stage_signed_windows_artifacts
560-
561486
upload:
562487
name: Upload to S3
563-
if: ${{ !failure() && !cancelled() }}
488+
if: ${{ !cancelled() && needs.build.result == 'success' }}
564489
needs:
565490
- meta
566491
- build
567-
- sign_windows
568492
runs-on: ubuntu-24.04-arm
569493
environment: desktop-releases
570494
timeout-minutes: 60
@@ -615,11 +539,6 @@ jobs:
615539
cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- build-desktop
616540
--step upload_payload
617541
618-
- name: Verify uploaded source tarball
619-
run: >-
620-
cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- build-desktop
621-
--step verify_source_tarball
622-
623542
- name: Build summary
624543
run: >-
625544
cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- build-desktop
@@ -645,14 +564,6 @@ jobs:
645564
if-no-files-found: error
646565
retention-days: 14
647566

648-
- name: Notify canary desktop webhook
649-
if: ${{ success() && needs.meta.outputs.channel == 'canary' }}
650-
env:
651-
FLUXER_WEBHOOK_URL: ${{ secrets.FLUXER_WEBHOOK_URL }}
652-
run: >-
653-
cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- build-desktop
654-
--step notify_webhook
655-
656567
- name: Cleanup S3 handoff
657568
if: ${{ success() }}
658569
run: >-
@@ -661,7 +572,7 @@ jobs:
661572
662573
finalise_release:
663574
name: Finalise GitHub desktop release
664-
if: ${{ !failure() && !cancelled() && needs.meta.outputs.test_build != 'true' }}
575+
if: ${{ !cancelled() && needs.upload.result == 'success' && needs.meta.outputs.test_build != 'true' }}
665576
needs:
666577
- meta
667578
- upload

.github/workflows/deploy-service.yaml

Lines changed: 0 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,6 @@ on:
7575
required: false
7676
GHCR_TOKEN:
7777
required: false
78-
FLUXER_WEBHOOK_URL:
79-
required: false
8078

8179
env:
8280
GHCR_OWNER: ${{ github.repository_owner }}
@@ -458,37 +456,6 @@ jobs:
458456
--dry-run=client -o yaml \
459457
| kubectl apply -f -
460458
461-
- name: notify web app canary deploy
462-
if: ${{ success() && inputs.service == 'app-proxy' && inputs.channel == 'canary' }}
463-
shell: bash
464-
env:
465-
FLUXER_WEBHOOK_URL: ${{ secrets.FLUXER_WEBHOOK_URL }}
466-
IMAGE_TAG: ${{ inputs['image-tag'] }}
467-
BUILD_VERSION: ${{ inputs['build-version'] }}
468-
run: |
469-
set -euo pipefail
470-
471-
if [[ -z "${FLUXER_WEBHOOK_URL:-}" ]]; then
472-
echo "FLUXER_WEBHOOK_URL is not set; skipping web app canary deploy notification."
473-
exit 0
474-
fi
475-
476-
web_app_version="${BUILD_VERSION:-$IMAGE_TAG}"
477-
478-
markdown_tick=$(printf '\140')
479-
content=$(printf '## Canary Web App Deployed\n\nWeb app version: %s%s%s' \
480-
"$markdown_tick" "$web_app_version" "$markdown_tick")
481-
if [[ "$IMAGE_TAG" != "$web_app_version" ]]; then
482-
content=$(printf '%s\nContainer image tag: %s%s%s' "$content" "$markdown_tick" "$IMAGE_TAG" "$markdown_tick")
483-
fi
484-
485-
jq -n --arg content "$content" \
486-
'{content: $content, allowed_mentions: {parse: []}}' \
487-
| curl -fsS --retry 3 \
488-
-H 'Content-Type: application/json' \
489-
--data-binary @- \
490-
"$FLUXER_WEBHOOK_URL"
491-
492459
- name: recover stuck release on failure
493460
if: failure() || cancelled()
494461
shell: bash

0 commit comments

Comments
 (0)