mirror of
https://github.com/jmcorgan/fips.git
synced 2026-07-30 19:46:15 +00:00
macos package: derive package arch from the build target
The published v0.3.0 macOS installer is a structurally corrupt xar archive: pkgutil and xar reject it even though its SHA-256 matches the published checksum. build-pkg.sh derived the architecture suffix in the .pkg filename from `uname -m`. On the Apple-silicon macOS runner that always reports arm64, so the cross-compiled x86_64 build also named its output fips-<version>-macos-arm64.pkg. The release job downloads both build artifacts with merge-multiple into one directory, where the two identically named files collide and tear into a malformed result. The x86_64 package never reaches the release at all. Derive the package architecture from the Rust target triple, which is authoritative for cross-compiles, instead of from the build host. Each matrix leg now produces a distinctly named, arch-correct package, so the two artifacts no longer collide. Add a SHA-256 integrity chain so a corrupt or mismatched asset cannot be published again: - Capture the .pkg SHA-256 on the macOS runner, after the on-runner structural verification, into a sidecar file carried in the artifact. - Add a verify-handoff job that runs on every trigger and asserts each downloaded .pkg still matches its macOS-runner SHA-256. - Gate the release job on verify-handoff and repeat the check on the exact bytes about to be published. The build step now asserts it produced the expected arch-named package so a regression in the naming fails loudly rather than as a silent collision. Relates to #102. The published v0.3.0 macOS assets still need to be rebuilt and reuploaded separately.
This commit is contained in:
@@ -100,14 +100,22 @@ jobs:
|
||||
shell: bash
|
||||
run: |
|
||||
: ${GITHUB_OUTPUT:=/tmp/github_output}
|
||||
set -euo pipefail
|
||||
|
||||
PKG_FILE=$(find deploy -maxdepth 1 -type f -name "fips-*-macos-*.pkg" | sort | head -n 1)
|
||||
if [[ -z "$PKG_FILE" ]]; then
|
||||
echo "Missing macOS package" >&2
|
||||
# build-pkg.sh names the package from the build target, so each
|
||||
# matrix leg produces a distinctly named, arch-correct asset.
|
||||
# Assert that here: a regression in that naming then fails loudly
|
||||
# at the build stage instead of as a silent collision when the
|
||||
# release job merges both artifacts into one directory.
|
||||
EXPECTED="deploy/fips-${{ needs.determine-versioning.outputs.macos_package_version }}-macos-${{ matrix.arch }}.pkg"
|
||||
if [[ ! -f "$EXPECTED" ]]; then
|
||||
echo "Expected package $EXPECTED was not produced" >&2
|
||||
echo "deploy/ contains:" >&2
|
||||
ls -la deploy >&2 || true
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "pkg=$PKG_FILE" >> "$GITHUB_OUTPUT"
|
||||
echo "pkg=$EXPECTED" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Verify .pkg structural correctness
|
||||
shell: bash
|
||||
@@ -185,16 +193,27 @@ jobs:
|
||||
fi
|
||||
echo "==> .pkg verification PASSED"
|
||||
|
||||
- name: SHA-256 hash
|
||||
- name: SHA-256 hash and sidecar
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
PKG="${{ steps.macos-assets.outputs.pkg }}"
|
||||
echo "==> macOS release asset:"
|
||||
shasum -a 256 "${{ steps.macos-assets.outputs.pkg }}"
|
||||
# Capture the SHA-256 of the verified .pkg on the macOS runner and
|
||||
# write it to a sidecar file next to the .pkg, in the standard
|
||||
# `<hash> <basename>` shasum format. The verify-handoff and release
|
||||
# jobs re-check the downloaded bytes against this value, so any
|
||||
# corruption introduced after this point is detected before
|
||||
# publication.
|
||||
( cd "$(dirname "$PKG")" && shasum -a 256 "$(basename "$PKG")" | tee "$(basename "$PKG").sha256" )
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: fips_${{ needs.determine-versioning.outputs.macos_package_version }}_${{ matrix.arch }}_macos
|
||||
path: ${{ steps.macos-assets.outputs.pkg }}
|
||||
path: |
|
||||
${{ steps.macos-assets.outputs.pkg }}
|
||||
${{ steps.macos-assets.outputs.pkg }}.sha256
|
||||
retention-days: 30
|
||||
|
||||
- name: Build summary
|
||||
@@ -202,10 +221,61 @@ jobs:
|
||||
echo "Build Summary for macOS/${{ matrix.arch }}:"
|
||||
echo " Package: ${{ steps.macos-assets.outputs.pkg }}"
|
||||
|
||||
verify-handoff:
|
||||
name: Verify macOS package handoff integrity
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
|
||||
steps:
|
||||
- name: Download macOS artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: dist
|
||||
merge-multiple: true
|
||||
|
||||
- name: Verify .pkg integrity across the handoff
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
cd dist
|
||||
|
||||
pkgs=$(find . -maxdepth 1 -type f -name '*.pkg' | LC_ALL=C sort)
|
||||
if [[ -z "$pkgs" ]]; then
|
||||
echo "FAIL: no .pkg artifacts were downloaded" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
fail=0
|
||||
while IFS= read -r pkg; do
|
||||
base=$(basename "$pkg")
|
||||
sidecar="${pkg}.sha256"
|
||||
if [[ ! -f "$sidecar" ]]; then
|
||||
echo "FAIL: missing SHA-256 sidecar for $base" >&2
|
||||
fail=1
|
||||
continue
|
||||
fi
|
||||
expected=$(awk '{print $1}' "$sidecar")
|
||||
actual=$(sha256sum "$pkg" | awk '{print $1}')
|
||||
if [[ "$expected" != "$actual" ]]; then
|
||||
echo "FAIL: $base SHA-256 mismatch across the artifact handoff" >&2
|
||||
echo " expected (macOS runner): $expected" >&2
|
||||
echo " actual (downloaded): $actual" >&2
|
||||
fail=1
|
||||
continue
|
||||
fi
|
||||
echo "PASS: $base matches the macOS-runner SHA-256 ($actual)"
|
||||
done <<<"$pkgs"
|
||||
|
||||
if [[ "$fail" -ne 0 ]]; then
|
||||
echo "==> macOS package handoff verification FAILED" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "==> macOS package handoff verification PASSED"
|
||||
|
||||
release:
|
||||
name: Publish macOS assets to GitHub Release
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
needs: [build, verify-handoff]
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
permissions:
|
||||
contents: write
|
||||
@@ -217,6 +287,45 @@ jobs:
|
||||
path: dist
|
||||
merge-multiple: true
|
||||
|
||||
- name: Validate .pkg bytes before publishing
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
cd dist
|
||||
|
||||
pkgs=$(find . -maxdepth 1 -type f -name '*.pkg' | LC_ALL=C sort)
|
||||
if [[ -z "$pkgs" ]]; then
|
||||
echo "FAIL: no .pkg artifacts were downloaded" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
fail=0
|
||||
while IFS= read -r pkg; do
|
||||
base=$(basename "$pkg")
|
||||
sidecar="${pkg}.sha256"
|
||||
if [[ ! -f "$sidecar" ]]; then
|
||||
echo "FAIL: missing SHA-256 sidecar for $base" >&2
|
||||
fail=1
|
||||
continue
|
||||
fi
|
||||
expected=$(awk '{print $1}' "$sidecar")
|
||||
actual=$(sha256sum "$pkg" | awk '{print $1}')
|
||||
if [[ "$expected" != "$actual" ]]; then
|
||||
echo "FAIL: $base SHA-256 mismatch on the bytes about to be published" >&2
|
||||
echo " expected (macOS runner): $expected" >&2
|
||||
echo " actual (downloaded): $actual" >&2
|
||||
fail=1
|
||||
continue
|
||||
fi
|
||||
echo "PASS: $base matches the macOS-runner SHA-256 ($actual)"
|
||||
done <<<"$pkgs"
|
||||
|
||||
if [[ "$fail" -ne 0 ]]; then
|
||||
echo "==> pre-publish .pkg verification FAILED; not publishing" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "==> pre-publish .pkg verification PASSED"
|
||||
|
||||
- name: Generate macOS release checksums
|
||||
run: |
|
||||
cd dist
|
||||
|
||||
@@ -55,7 +55,23 @@ while [[ $# -gt 0 ]]; do
|
||||
done
|
||||
|
||||
VERSION="${VERSION_OVERRIDE:-$(grep '^version' "${PROJECT_ROOT}/Cargo.toml" | head -1 | sed 's/.*"\(.*\)"/\1/')}"
|
||||
ARCH="$(uname -m)"
|
||||
|
||||
# Derive the package architecture from the build target, not the build
|
||||
# host. When cross-compiling (for example building the x86_64 package on
|
||||
# an Apple-silicon machine) `uname -m` reports the host architecture and
|
||||
# would mislabel the package; the Rust target triple is authoritative.
|
||||
if [[ -n "${TARGET_TRIPLE}" ]]; then
|
||||
case "${TARGET_TRIPLE}" in
|
||||
aarch64-*) ARCH="arm64" ;;
|
||||
x86_64-*) ARCH="x86_64" ;;
|
||||
*)
|
||||
echo "Unsupported target triple: ${TARGET_TRIPLE}" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
else
|
||||
ARCH="$(uname -m)"
|
||||
fi
|
||||
PKG_NAME="fips-${VERSION}-macos-${ARCH}"
|
||||
DEPLOY_DIR="${PROJECT_ROOT}/deploy"
|
||||
STAGING_DIR="$(mktemp -d)"
|
||||
|
||||
Reference in New Issue
Block a user