Skip to content
Merged
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
55 changes: 55 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,58 @@ jobs:
run: cargo test --locked
- name: Release build
run: cargo build --release --locked

linux-aarch64:
name: Test and build (linux-aarch64)
runs-on: ubuntu-22.04-arm
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
- uses: dtolnay/rust-toolchain@b725eda525362e7cf34af9a7243cac1e3f01a7ec # stable
with:
components: rustfmt, clippy
- uses: Swatinem/rust-cache@d1527c8f67ef9af357290475d4af4b0fab8f12e0 # v2
- name: Validate Linux AArch64 natively
shell: bash
run: |
set -euo pipefail
[[ "$(uname -m)" == aarch64 ]]
[[ "$(rustc -vV | sed -n 's/^host: //p')" == aarch64-unknown-linux-gnu ]]
cargo fmt --check
cargo clippy --locked --all-targets -- -D warnings
cargo test --locked
cargo build --release --locked
readelf -h target/release/mch | grep -Eq 'Machine:[[:space:]]+AArch64'
target/release/mch -v

termux-aarch64:
name: Cross-build (android-aarch64-termux)
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
- uses: dtolnay/rust-toolchain@b725eda525362e7cf34af9a7243cac1e3f01a7ec # stable
with:
targets: aarch64-linux-android
- uses: Swatinem/rust-cache@d1527c8f67ef9af357290475d4af4b0fab8f12e0 # v2
with:
key: android-aarch64-ndk
- name: Cross-build and validate Android Bionic ABI
shell: bash
run: |
set -euo pipefail
test -n "$ANDROID_NDK_HOME"
ndk_bin="$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin"
test -x "$ndk_bin/aarch64-linux-android24-clang"
test -x "$ndk_bin/llvm-ar"
export CARGO_TARGET_AARCH64_LINUX_ANDROID_LINKER="$ndk_bin/aarch64-linux-android24-clang"
export CC_aarch64_linux_android="$ndk_bin/aarch64-linux-android24-clang"
export AR_aarch64_linux_android="$ndk_bin/llvm-ar"
cargo build --release --locked --target aarch64-linux-android
binary=target/aarch64-linux-android/release/mch
test -s "$binary"
readelf -h "$binary" | grep -Eq 'Machine:[[:space:]]+AArch64'
readelf -l "$binary" | grep -F '/system/bin/linker64'
if readelf -d "$binary" | grep -E 'libc\.so\.6|ld-linux'; then
echo 'Refusing glibc-linked binary' >&2
exit 1
fi
sha256sum "$binary"
58 changes: 49 additions & 9 deletions .github/workflows/release-packages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ jobs:
git merge-base --is-ancestor "$sha" origin/main || { echo "Tag is not on public main"; exit 1; }
version="$(git show "$sha:Cargo.toml" | sed -n 's/^version = "\(.*\)"/\1/p' | head -n1)"
[[ "$TAG" == "v$version" ]] || { echo "Tag and Cargo version mismatch"; exit 1; }
[[ "$TAG" != v0.2.1 ]] || { echo 'Historical v0.2.1 assets must remain immutable; ARM64 archives begin with a future release'; exit 1; }
[[ "$(gh release view "$TAG" --json isDraft,isPrerelease --jq '.isDraft or .isPrerelease')" == false ]] || { echo "Release must be published and stable"; exit 1; }
[[ "$(gh release view "$TAG" --json tagName --jq .tagName)" == "$TAG" ]] || { echo "Release tag identity mismatch"; exit 1; }
printf 'tag=%s\nsha=%s\n' "$TAG" "$sha" >> "$GITHUB_OUTPUT"
Expand All @@ -66,6 +67,14 @@ jobs:
platform: linux-x86_64
target: x86_64-unknown-linux-gnu
binary: mch
- runner: ubuntu-22.04-arm
platform: linux-aarch64
target: aarch64-unknown-linux-gnu
binary: mch
- runner: ubuntu-24.04
platform: android-aarch64-termux
target: aarch64-linux-android
binary: mch
runs-on: ${{ matrix.runner }}
env:
TAG: ${{ needs.verify.outputs.tag }}
Expand All @@ -83,17 +92,46 @@ jobs:
run: |
set -euo pipefail
host="$(rustc -vV | sed -n 's/^host: //p')"
[[ "$host" == "$TARGET" ]] || { echo "Wrong native architecture: $host"; exit 1; }
if [[ "$PLATFORM" == macos-aarch64 ]]; then
[[ "$(uname -m)" == arm64 ]] || { echo "Not an Apple Silicon machine"; exit 1; }
fi
rustup target add "$TARGET"
if [[ "$PLATFORM" == android-aarch64-termux ]]; then
[[ "$host" == x86_64-unknown-linux-gnu ]] || { echo "Expected x86_64 Linux cross-build host"; exit 1; }
test -n "$ANDROID_NDK_HOME"
linker="$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android24-clang"
test -x "$linker"
export CARGO_TARGET_AARCH64_LINUX_ANDROID_LINKER="$linker"
export CC_aarch64_linux_android="$linker"
ar="$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-ar"
test -x "$ar"
export AR_aarch64_linux_android="$ar"
else
[[ "$host" == "$TARGET" ]] || { echo "Wrong native architecture: $host"; exit 1; }
if [[ "$PLATFORM" == macos-aarch64 ]]; then
[[ "$(uname -m)" == arm64 ]] || { echo "Not an Apple Silicon machine"; exit 1; }
fi
if [[ "$PLATFORM" == linux-aarch64 ]]; then
[[ "$(uname -m)" == aarch64 ]] || { echo "Not a Linux ARM64 machine"; exit 1; }
fi
fi
cargo test --locked
cargo build --release --locked --target "$TARGET"
test -s "target/$TARGET/release/$BINARY"
binary="target/$TARGET/release/$BINARY"
test -s "$binary"
version="$(printf '%s' "$TAG" | cut -c2-)"
actual="$( "target/$TARGET/release/$BINARY" -v | tail -n1 | tr -d '\r' )"
[[ "$actual" == "$version" ]] || { echo "Wrong executable version: $actual"; exit 1; }
if [[ "$PLATFORM" == android-aarch64-termux ]]; then
readelf -h "$binary" | grep -Eq 'Machine:[[:space:]]+AArch64'
readelf -l "$binary" | grep -F '/system/bin/linker64'
if readelf -d "$binary" | grep -E 'libc\.so\.6|ld-linux'; then
echo 'Refusing glibc-linked binary in Termux archive' >&2
exit 1
fi
echo 'Cross-build: native Termux execution tests are a separate release gate'

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Make the Termux runtime gate block publication

For every future published tag, the Android branch succeeds after static ELF checks and this informational echo; publish then depends only on binary/source and immediately uploads the archive. A repo-wide search found no native-Termux job or approval that gates that upload, so the exact binary built here cannot undergo the stated native smoke test before becoming public, allowing a linker-valid but nonfunctional Termux binary to ship. Add a blocking test or approval that validates this artifact before the publish job proceeds.

Useful? React with 👍 / 👎.

else
if [[ "$PLATFORM" == linux-aarch64 ]]; then
readelf -h "$binary" | grep -Eq 'Machine:[[:space:]]+AArch64'
fi
actual="$( "$binary" -v | tail -n1 | tr -d '\r' )"
[[ "$actual" == "$version" ]] || { echo "Wrong executable version: $actual"; exit 1; }
fi
- name: Package executable with license and README
shell: bash
run: |
Expand Down Expand Up @@ -179,9 +217,11 @@ jobs:
f"mch-{tag}-windows-x86_64.zip",
f"mch-{tag}-macos-aarch64.tar.gz",
f"mch-{tag}-linux-x86_64.tar.gz",
f"mch-{tag}-linux-aarch64.tar.gz",
f"mch-{tag}-android-aarch64-termux.tar.gz",
}
found = {p.name for p in folder.iterdir() if p.is_file()}
assert found == expected, f"Expected five archives, got: {found}"
assert found == expected, f"Expected seven archives, got: {found}"
for filename in sorted(expected):
file = folder / filename
assert file.stat().st_size > 1000, f"Archive is empty: {filename}"
Expand Down Expand Up @@ -211,5 +251,5 @@ jobs:
set -euo pipefail
gh release upload "$TAG" dist/* --repo "$GITHUB_REPOSITORY" --clobber
count="$(gh release view "$TAG" --repo "$GITHUB_REPOSITORY" --json assets --jq '.assets | length')"
[[ "$count" -eq 6 ]] || { echo "Expected six release assets, found $count"; exit 1; }
[[ "$count" -eq 8 ]] || { echo "Expected eight release assets, found $count"; exit 1; }
gh release view "$TAG" --repo "$GITHUB_REPOSITORY" --json assets --jq '[.assets[].name]'
Loading