Skip to content

Commit

Permalink
Add GitHub workflows to verify binary architecture matches target arc…
Browse files Browse the repository at this point in the history
…hitecture
  • Loading branch information
diemogebhardt committed Nov 26, 2024
1 parent b50695c commit e122a8a
Show file tree
Hide file tree
Showing 3 changed files with 529 additions and 0 deletions.
189 changes: 189 additions & 0 deletions .github/workflows/ci-verify-binary-architecture.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
name: ci-verify-binary-architecture

on:
workflow_dispatch:
push:

env:
CARGO_TERM_COLOR: always
RUSTFLAGS: "-D warnings"
CARGO_INCREMENTAL: 0
CARGO_PROFILE_DEV_DEBUG: 0
CARGO_PROFILE_TEST_DEBUG: 0
CROSS_CONTAINER_UID: 0

permissions:
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true

jobs:
test:
name: test
runs-on: ${{ matrix.os }}
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
toolchain: [stable]
target:
- x86_64-unknown-linux-gnu
- x86_64-unknown-linux-musl
- aarch64-unknown-linux-gnu
- aarch64-unknown-linux-musl
- x86_64-apple-darwin
- x86_64-pc-windows-msvc
include:
- os: ubuntu-latest
target: x86_64-unknown-linux-gnu
use-cross: false
run-integration-tests: true
- os: ubuntu-latest
target: x86_64-unknown-linux-musl
use-cross: true
run-integration-tests: true
- os: ubuntu-latest
target: aarch64-unknown-linux-gnu
use-cross: true
run-integration-tests: false # Cannot run aarch64 binaries on x86_64
- os: ubuntu-latest
target: aarch64-unknown-linux-musl
use-cross: true
run-integration-tests: false # Cannot run aarch64 binaries on x86_64
# macos>=14 runs exclusively on aarch64 and will thus fail to execute properly for x64
- os: macos-13 # intel
target: x86_64-apple-darwin
use-cross: false
run-integration-tests: true
- os: macos-latest # aarch64
toolchain: stable
target: aarch64-apple-darwin
use-cross: false
run-integration-tests: true
- os: windows-latest
target: x86_64-pc-windows-msvc
use-cross: false
run-integration-tests: true
steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Install musl-tools incl. musl-gcc
uses: awalsh128/cache-apt-pkgs-action@v1
with:
# musl-tools provide `musl-gcc` which is required for `ring` which is required for `rustls` et al.
packages: musl-tools
version: 1.1
if: ${{ matrix.target == 'x86_64-unknown-linux-musl'}}

- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
toolchain: ${{ matrix.toolchain }}
target: ${{ matrix.target }}

- name: Install Erlang (non-macos)
uses: erlef/setup-beam@v1
with:
otp-version: "26.1"
elixir-version: "1.16.1"
rebar3-version: "3"
if: ${{ runner.os != 'macOS' }} # setup-beam does not support macOS

- name: Install Erlang (macos)
run: |
brew install erlang rebar3 elixir
mix local.hex --force
if: ${{ runner.os == 'macOS' }} # setup-beam does not support macOS

- name: Handle Rust dependencies caching
uses: Swatinem/rust-cache@v2
with:
key: v1-${{ matrix.target }}

- name: Install Gleam
uses: clechasseur/rs-cargo@v2
with:
command: install
args: "--path compiler-cli --target ${{ matrix.target }} --debug --locked"
use-cross: ${{ matrix.use-cross }}
if: ${{ matrix.run-integration-tests }}

- name: Verify binary architecture
shell: bash
run: |
set -xeuo pipefail
BINARY_PATH="${CARGO_HOME}/bin/gleam"
if [[ "${{ matrix.target }}" == *"windows"* ]]; then
BINARY_PATH="${BINARY_PATH}.exe"
fi
# Parse target architecture
case "${{ matrix.target }}" in
"x86_64"*) TARGET_ARCHITECTURE="x86_64" ;;
"aarch64"*) TARGET_ARCHITECTURE="aarch64" ;;
*) echo "Unknown target architecture '${{ matrix.target }}'"; exit 1 ;;
esac
# Parse binary architecture and map expected binary architecture for target OS
case "${{ matrix.target }}" in
*"darwin"*)
# Parse binary architecture
file_output=$(file -b "${BINARY_PATH}")
BINARY_ARCHITECTURE=$(echo "${file_output}" | grep -o "x86_64\|arm64" || echo "")
# Map expected binary architecture
case "${TARGET_ARCHITECTURE}" in
"x86_64") EXPECTED_BINARY_ARCHITECTURE="x86_64" ;;
"aarch64") EXPECTED_BINARY_ARCHITECTURE="arm64" ;;
*) echo "Unknown Darwin architecture: '${TARGET_ARCHITECTURE}'"; exit 1 ;;
esac
;;
*"linux"*)
# Parse binary architecture
file_output=$(file -b "${BINARY_PATH}")
BINARY_ARCHITECTURE=$(echo "${file_output}" | grep -o "x86-64\|aarch64" | head -n1 || echo "")
# Map expected binary architecture
case "${TARGET_ARCHITECTURE}" in
"x86_64") EXPECTED_BINARY_ARCHITECTURE="x86-64" ;;
"aarch64") EXPECTED_BINARY_ARCHITECTURE="aarch64" ;;
*) echo "Unknown Linux architecture: '${TARGET_ARCHITECTURE}'"; exit 1 ;;
esac
;;
*"windows"*)
# Parse binary architecture
pe_header_output=$(powershell -Command "
\$bytes = [System.IO.File]::ReadAllBytes('${BINARY_PATH}');
\$header_offset = [System.BitConverter]::ToInt32(\$bytes, 0x3c);
\$machine_type = [System.BitConverter]::ToUInt16(\$bytes, \$header_offset + 4);
\$machine_type
" 2>&1) || echo "PE header extraction failed"
# Map binary architecture
case "${pe_header_output}" in
*"34404"*) BINARY_ARCHITECTURE="X64" ;; # 0x8664
*"43620"*) BINARY_ARCHITECTURE="Arm64" ;; # 0xAA64
*) echo "Unknown PE machine type: '${pe_header_output}'"; exit 1 ;;
esac
# Map expected binary architecture
case "${TARGET_ARCHITECTURE}" in
"x86_64") EXPECTED_BINARY_ARCHITECTURE="X64" ;;
"aarch64") EXPECTED_BINARY_ARCHITECTURE="Arm64" ;;
*) echo "Unknown Windows architecture: '${TARGET_ARCHITECTURE}'"; exit 1 ;;
esac
;;
*)
echo "Unknown target OS: '${{ matrix.target }}'"
exit 1
;;
esac
# Verify binary architecture
if [[ "${BINARY_ARCHITECTURE}" != "${EXPECTED_BINARY_ARCHITECTURE}" ]]; then
echo "Architecture mismatch for '${{ matrix.target }}'"
echo "Expected: '${EXPECTED_BINARY_ARCHITECTURE}'"
echo "Got: '${BINARY_ARCHITECTURE}'"
exit 1
fi
if: ${{ matrix.run-integration-tests }}
191 changes: 191 additions & 0 deletions .github/workflows/release-nightly-verify-binary-architecture.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
name: release-nightly-verify-binary-architecture

on:
workflow_dispatch:
push:

env:
CARGO_TERM_COLOR: always
RUSTFLAGS: "-D warnings"

jobs:
nightly-last-run:
runs-on: ubuntu-latest
name: Check latest commit
outputs:
should_run: ${{ steps.should_run.outputs.should_run }}
# if: ${{ github.repository_owner == 'gleam-lang' }}
steps:
- uses: actions/checkout@v4
- name: print latest_commit
run: echo ${{ github.sha }}

- id: should_run
continue-on-error: true
name: check latest commit is less than a day
if: ${{ github.event_name == 'schedule' }}
run: test -z $(git rev-list --after="24 hours" ${{ github.sha }}) && echo "should_run=false" >> $GITHUB_OUTPUT

build-nightly-clean:
runs-on: ubuntu-latest
needs: [ nightly-last-run ]
# if: ${{ github.repository_owner == 'gleam-lang' && needs.nightly-last-run.outputs.should_run != 'false' }}
steps:
- name: Delete old release assets
uses: mknejp/delete-release-assets@v1
with:
token: ${{ github.token }}
tag: nightly
fail-if-no-assets: false
fail-if-no-release: false
assets: |
*.zip
*.tar.gz
*.sha256
*.sha512
build-nightly:
name: build-release
runs-on: ${{ matrix.os }}
needs: [ build-nightly-clean ]
# if: ${{ github.repository_owner == 'gleam-lang' }}
strategy:
matrix:
target:
- x86_64-unknown-linux-gnu
- aarch64-unknown-linux-gnu
- x86_64-unknown-linux-musl
- aarch64-unknown-linux-musl
- x86_64-apple-darwin
- aarch64-apple-darwin
- x86_64-pc-windows-msvc
- aarch64-pc-windows-msvc
toolchain: [stable]
include:
- os: ubuntu-latest
target: x86_64-unknown-linux-gnu
use-cross: false
- os: ubuntu-latest
target: aarch64-unknown-linux-gnu
use-cross: true
- os: ubuntu-latest
target: x86_64-unknown-linux-musl
use-cross: true
- os: ubuntu-latest
target: aarch64-unknown-linux-musl
use-cross: true
# macos>=14 runs exclusively on aarch64 and will thus fail to execute properly for x64
- os: macos-13
target: x86_64-apple-darwin
use-cross: false
- os: macos-latest
target: aarch64-apple-darwin
use-cross: false
- os: windows-latest
target: x86_64-pc-windows-msvc
use-cross: false
- os: windows-latest
target: aarch64-pc-windows-msvc
use-cross: false
steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Update versions
shell: bash
run: |
./bin/add-nightly-suffix-to-versions.sh
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
toolchain: ${{ matrix.toolchain }}
target: ${{ matrix.target }}

- name: Handle Rust dependencies caching
uses: Swatinem/rust-cache@v2
with:
key: v1-${{ matrix.target }}

- name: Build release binary
uses: clechasseur/rs-cargo@v2
with:
command: build
args: --release --target ${{ matrix.target }}
use-cross: ${{ matrix.use-cross }}

- name: Verify binary architecture
shell: bash
run: |
set -xeuo pipefail
BINARY_PATH="target/${{ matrix.target }}/release/gleam"
if [[ "${{ matrix.target }}" == *"windows"* ]]; then
BINARY_PATH="${BINARY_PATH}.exe"
fi
# Parse target architecture
case "${{ matrix.target }}" in
"x86_64"*) TARGET_ARCHITECTURE="x86_64" ;;
"aarch64"*) TARGET_ARCHITECTURE="aarch64" ;;
*) echo "Unknown target architecture '${{ matrix.target }}'"; exit 1 ;;
esac
# Parse binary architecture and map expected binary architecture for target OS
case "${{ matrix.target }}" in
*"darwin"*)
# Parse binary architecture
file_output=$(file -b "${BINARY_PATH}")
BINARY_ARCHITECTURE=$(echo "${file_output}" | grep -o "x86_64\|arm64" || echo "")
# Map expected binary architecture
case "${TARGET_ARCHITECTURE}" in
"x86_64") EXPECTED_BINARY_ARCHITECTURE="x86_64" ;;
"aarch64") EXPECTED_BINARY_ARCHITECTURE="arm64" ;;
*) echo "Unknown Darwin architecture: '${TARGET_ARCHITECTURE}'"; exit 1 ;;
esac
;;
*"linux"*)
# Parse binary architecture
file_output=$(file -b "${BINARY_PATH}")
BINARY_ARCHITECTURE=$(echo "${file_output}" | grep -o "x86-64\|aarch64" | head -n1 || echo "")
# Map expected binary architecture
case "${TARGET_ARCHITECTURE}" in
"x86_64") EXPECTED_BINARY_ARCHITECTURE="x86-64" ;;
"aarch64") EXPECTED_BINARY_ARCHITECTURE="aarch64" ;;
*) echo "Unknown Linux architecture: '${TARGET_ARCHITECTURE}'"; exit 1 ;;
esac
;;
*"windows"*)
# Parse binary architecture
pe_header_output=$(powershell -Command "
\$bytes = [System.IO.File]::ReadAllBytes('${BINARY_PATH}');
\$header_offset = [System.BitConverter]::ToInt32(\$bytes, 0x3c);
\$machine_type = [System.BitConverter]::ToUInt16(\$bytes, \$header_offset + 4);
\$machine_type
" 2>&1) || echo "PE header extraction failed"
# Map binary architecture
case "${pe_header_output}" in
*"34404"*) BINARY_ARCHITECTURE="X64" ;; # 0x8664
*"43620"*) BINARY_ARCHITECTURE="Arm64" ;; # 0xAA64
*) echo "Unknown PE machine type: '${pe_header_output}'"; exit 1 ;;
esac
# Map expected binary architecture
case "${TARGET_ARCHITECTURE}" in
"x86_64") EXPECTED_BINARY_ARCHITECTURE="X64" ;;
"aarch64") EXPECTED_BINARY_ARCHITECTURE="Arm64" ;;
*) echo "Unknown Windows architecture: '${TARGET_ARCHITECTURE}'"; exit 1 ;;
esac
;;
*)
echo "Unknown target OS: '${{ matrix.target }}'"
exit 1
;;
esac
# Verify binary architecture
if [[ "${BINARY_ARCHITECTURE}" != "${EXPECTED_BINARY_ARCHITECTURE}" ]]; then
echo "Architecture mismatch for '${{ matrix.target }}'"
echo "Expected: '${EXPECTED_BINARY_ARCHITECTURE}'"
echo "Got: '${BINARY_ARCHITECTURE}'"
exit 1
fi
Loading

0 comments on commit e122a8a

Please sign in to comment.