Skip to content
Open
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
114 changes: 114 additions & 0 deletions .github/workflows/codesign-windows-binaries.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# Codesign `air.exe` for Windows platforms
#
# Overwrites Windows specific GitHub Artifacts generated by `cargo-dist`
# containing the executable and a SHA with signed equivalents.
#
# Assumed to run as a subworkflow of .github/workflows/release.yml; specifically, as a local
# artifacts job within `cargo-dist` after binaries have been built.
name: "Codesign Windows binaries"

on:
workflow_call:
inputs:
# Required for how cargo-dist calls us from `release.yml`, but goes unused
plan:
required: true
type: string

jobs:
extract-windows-executables:
name: Extract Windows executables
runs-on: ubuntu-latest
strategy:
matrix:
target: [x86_64-pc-windows-msvc, aarch64-pc-windows-msvc]
steps:
# Pull down the artifacts cargo-dist has created for us
- name: Download Windows artifacts
uses: actions/download-artifact@v4
with:
pattern: artifacts-build-local-${{ matrix.target }}
path: artifacts
merge-multiple: true

# The artifacts contain `air-*-${{ matrix.target }}.zip` and
# `air-*-${{ matrix.target }}.zip.sha256`. `air-*-${{ matrix.target }}.zip`
# directly unzips into `air.exe`.
- name: Extract executable from archive
shell: bash
run: |
# Find the Windows zip archive for this target
ARCHIVE=$(find artifacts -name "air-*-${{ matrix.target }}.zip" -type f | head -1)
if [ -z "$ARCHIVE" ]; then
echo "Error: Could not find Windows archive for ${{ matrix.target }}"
exit 1
fi

echo "Found archive: $ARCHIVE"

# Extract the executable
unzip -j "$ARCHIVE" "*/air.exe" -d unsigned/

# Verify extraction
if [ ! -f "unsigned/air.exe" ]; then
echo "Error: Failed to extract air.exe"
exit 1
fi

- name: Upload unsigned executable
uses: actions/upload-artifact@v4
with:
name: air-unsigned-${{ matrix.target }}
path: unsigned/air.exe

sign-windows:
name: Sign Windows executables
uses: posit-dev/posit-gh-actions/.github/workflows/sign-windows.yml@main
needs: [extract-windows-executables]
secrets: inherit
strategy:
matrix:
target: [x86_64-pc-windows-msvc, aarch64-pc-windows-msvc]
with:
unsigned_artifact_name: air-unsigned-${{ matrix.target }}
signed_artifact_name: air-signed-${{ matrix.target }}

# Overwrites unsigned artifacts with signed artifacts,
# including updated SHAs
reupload-windows-artifacts:
name: Reupload Windows artifacts
needs: [sign-windows]
runs-on: ubuntu-latest
strategy:
matrix:
target: [x86_64-pc-windows-msvc, aarch64-pc-windows-msvc]
steps:
- name: Download Windows artifacts
uses: actions/download-artifact@v4
with:
pattern: air-signed-${{ matrix.target }}
path: artifacts
merge-multiple: true

- name: Rearchive signed binary and compute its SHA
shell: bash
run: |
# Find the Windows zip archive for this target
EXECUTABLE=$(find artifacts -name "air.exe" -type f | head -1)
if [ -z "$EXECUTABLE" ]; then
echo "Error: Could not find signed executable for ${{ matrix.target }}"
exit 1
fi

echo "Found signed executable: $EXECUTABLE"

7z a air-${{ matrix.target }}.zip $EXECUTABLE
sha256sum air-${{ matrix.target }}.zip > air-${{ matrix.target }}.zip.sha256

- name: Reupload signed artifacts
uses: actions/upload-artifact@v4
with:
name: artifacts-${{ matrix.target }}
path: |
air-${{ matrix.target }}.zip
air-${{ matrix.target }}.zip.sha256
17 changes: 16 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -166,11 +166,25 @@ jobs:
${{ steps.cargo-dist.outputs.paths }}
${{ env.BUILD_MANIFEST_NAME }}

custom-codesign-windows-binaries:
needs:
- plan
# ---
# TODO: Can cargo-dist let us require this?
- build-local-artifacts
# ---
if: ${{ needs.plan.outputs.publishing == 'true' || fromJson(needs.plan.outputs.val).ci.github.pr_run_mode == 'upload' || inputs.tag == 'dry-run' }}
uses: ./.github/workflows/codesign-windows-binaries.yml
with:
plan: ${{ needs.plan.outputs.val }}
secrets: inherit

# Build and package all the platform-agnostic(ish) things
build-global-artifacts:
needs:
- plan
- build-local-artifacts
- custom-codesign-windows-binaries
runs-on: "ubuntu-latest"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Expand Down Expand Up @@ -216,9 +230,10 @@ jobs:
needs:
- plan
- build-local-artifacts
- custom-codesign-windows-binaries
- build-global-artifacts
# Only run if we're "publishing", and only if local and global didn't fail (skipped is fine)
if: ${{ always() && needs.plan.outputs.publishing == 'true' && (needs.build-global-artifacts.result == 'skipped' || needs.build-global-artifacts.result == 'success') && (needs.build-local-artifacts.result == 'skipped' || needs.build-local-artifacts.result == 'success') }}
if: ${{ always() && needs.plan.outputs.publishing == 'true' && (needs.build-global-artifacts.result == 'skipped' || needs.build-global-artifacts.result == 'success') && (needs.build-local-artifacts.result == 'skipped' || needs.build-local-artifacts.result == 'success') && (needs.custom-codesign-windows-binaries.result == 'skipped' || needs.custom-codesign-windows-binaries.result == 'success') }}
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
runs-on: "ubuntu-latest"
Expand Down
2 changes: 2 additions & 0 deletions dist-workspace.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ targets = [
"x86_64-unknown-linux-gnu",
"aarch64-unknown-linux-gnu",
]
# Local artifacts jobs to run in CI
local-artifacts-jobs = ["./codesign-windows-binaries"]
# Tell dist to only build `crates/air` rather than every crate in the workspace,
# which it does by default to be conservative but would include some heavier test-only
# crates that aren't required (including xtask).
Expand Down
Loading