Files
fips/.github/workflows/package-macos.yml
Johnathan Corgan c51ee30d4c Refresh four GitHub Action pins to their tags' current commits
actions/upload-artifact v7 (now v7.0.2), actions/download-artifact v8
(now v8.0.2) and vmactions/freebsd-vm v1 (v1.5.5 to v1.5.9) had moved
since they were pinned; each new SHA is what its tag resolves to today.

dorny/test-reporter v2 had not moved, but its pin was the annotated
tag's object SHA rather than the commit it points at. It now pins the
peeled commit, the form the other pins use.

taiki-e/install-action and dtolnay/rust-toolchain are left as they are:
moving the first changes the pinned cargo-nextest version, and the
second follows a branch, so re-pinning it pins no toolchain.
2026-10-16 02:56:18 +00:00

362 lines
12 KiB
YAML

name: macOS Package
on:
push:
branches:
- master
- maint
- next
tags:
- "v*"
pull_request:
workflow_dispatch:
env:
CARGO_TERM_COLOR: always
jobs:
determine-versioning:
runs-on: macos-latest
outputs:
macos_package_version: ${{ steps.macos_version.outputs.macos_package_version }}
steps:
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
with:
fetch-depth: 0
- name: Derive macOS package version
id: macos_version
shell: bash
run: |
: ${GITHUB_OUTPUT:=/tmp/github_output}
BASE_VERSION=$(grep '^version' Cargo.toml | head -1 | sed 's/.*"\(.*\)"/\1/')
if [[ "$GITHUB_REF" == refs/tags/* ]]; then
VERSION="${GITHUB_REF_NAME#v}"
else
BRANCH=$(echo "$GITHUB_REF_NAME" | sed 's|[^A-Za-z0-9]|.|g; s/\.\.+/./g; s/^\.//; s/\.$//')
HEIGHT=$(git rev-list --count HEAD)
HASH=$(git rev-parse --short HEAD)
if [[ -z "$BRANCH" ]]; then
BRANCH="ref"
fi
VERSION="${BASE_VERSION}+${BRANCH}.${HEIGHT}.${HASH}"
fi
echo "macos_package_version=${VERSION}" >> "$GITHUB_OUTPUT"
build:
name: Build macOS package (${{ matrix.arch }})
runs-on: ${{ matrix.os }}
needs: determine-versioning
strategy:
fail-fast: false
matrix:
include:
- os: macos-latest
arch: arm64
target: aarch64-apple-darwin
- os: macos-latest
arch: x86_64
target: x86_64-apple-darwin
steps:
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
with:
fetch-depth: 0
- name: Set SOURCE_DATE_EPOCH from git
run: echo "SOURCE_DATE_EPOCH=$(git log -1 --format=%ct)" >> "$GITHUB_ENV"
- name: Install Rust toolchain
uses: actions-rust-lang/setup-rust-toolchain@166cdcfd11aee3cb47222f9ddb555ce30ddb9659 # v1
with:
target: ${{ matrix.target }}
cache: false
rustflags: ''
- name: Cache Cargo registry + build
uses: actions/cache@caa296126883cff596d87d8935842f9db880ef25 # v5
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: macos-release-${{ matrix.arch }}-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
macos-release-${{ matrix.arch }}-
- name: Build release binaries
run: cargo build --release --target ${{ matrix.target }}
- name: Build macOS package
run: |
packaging/macos/build-pkg.sh \
--version "${{ needs.determine-versioning.outputs.macos_package_version }}" \
--target ${{ matrix.target }} \
--no-build
- name: Resolve macOS asset path
id: macos-assets
shell: bash
run: |
: ${GITHUB_OUTPUT:=/tmp/github_output}
set -euo pipefail
# 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=$EXPECTED" >> "$GITHUB_OUTPUT"
- name: Verify .pkg structural correctness
shell: bash
run: |
set -euo pipefail
PKG="${{ steps.macos-assets.outputs.pkg }}"
EXPAND_DIR="$(mktemp -d)/expanded"
PAYLOAD_DIR="$(mktemp -d)/payload"
fail=0
echo "==> Verifying $PKG"
# 1) Flat-package expansion
if pkgutil --expand "$PKG" "$EXPAND_DIR"; then
echo "PASS: pkgutil --expand"
else
echo "FAIL: pkgutil --expand"
fail=1
fi
# Extract the cpio.gz Payload so we can inspect installed file layout
PAYLOAD_FILE="$(find "$EXPAND_DIR" -name Payload -type f | head -n 1)"
if [[ -z "$PAYLOAD_FILE" ]]; then
echo "FAIL: no Payload file inside expanded pkg"
fail=1
else
mkdir -p "$PAYLOAD_DIR"
(cd "$PAYLOAD_DIR" && gzip -dc "$PAYLOAD_FILE" | cpio -i --quiet)
echo "PASS: extracted Payload to $PAYLOAD_DIR"
fi
# 2) Binary at canonical install path (./usr/local/bin/fips inside payload)
BIN_PATH="$PAYLOAD_DIR/usr/local/bin/fips"
if [[ -f "$BIN_PATH" ]]; then
echo "PASS: binary present at usr/local/bin/fips"
else
echo "FAIL: binary missing at usr/local/bin/fips"
echo " fallback search:"
find "$PAYLOAD_DIR" -name fips -type f -print || true
fail=1
fi
for extra in fipsctl fipstop; do
if [[ -f "$PAYLOAD_DIR/usr/local/bin/$extra" ]]; then
echo "PASS: binary present at usr/local/bin/$extra"
else
echo "FAIL: binary missing at usr/local/bin/$extra"
fail=1
fi
done
# 3) LaunchDaemon plist at canonical location
PLIST_PATH="$PAYLOAD_DIR/Library/LaunchDaemons/com.fips.daemon.plist"
if [[ -f "$PLIST_PATH" ]]; then
echo "PASS: plist present at Library/LaunchDaemons/com.fips.daemon.plist"
else
echo "FAIL: plist missing at Library/LaunchDaemons/com.fips.daemon.plist"
echo " fallback search:"
find "$PAYLOAD_DIR" -name '*.plist' -print || true
fail=1
fi
# 4) plutil -lint on the plist
if [[ -f "$PLIST_PATH" ]]; then
if plutil -lint "$PLIST_PATH"; then
echo "PASS: plutil -lint"
else
echo "FAIL: plutil -lint"
fail=1
fi
fi
if [[ "$fail" -ne 0 ]]; then
echo "==> .pkg verification FAILED"
exit 1
fi
echo "==> .pkg verification PASSED"
- name: SHA-256 hash and sidecar
shell: bash
run: |
set -euo pipefail
PKG="${{ steps.macos-assets.outputs.pkg }}"
echo "==> macOS release asset:"
# 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@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
with:
name: fips_${{ needs.determine-versioning.outputs.macos_package_version }}_${{ matrix.arch }}_macos
path: |
${{ steps.macos-assets.outputs.pkg }}
${{ steps.macos-assets.outputs.pkg }}.sha256
retention-days: 30
- name: Build summary
run: |
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@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8
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, verify-handoff]
if: startsWith(github.ref, 'refs/tags/')
permissions:
contents: write
steps:
- name: Download macOS artifacts
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8
with:
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
find . -maxdepth 1 -type f -name '*.pkg' -printf '%P\n' \
| LC_ALL=C sort \
| xargs sha256sum \
> checksums-macos.txt
- name: Wait for tag release
env:
GH_TOKEN: ${{ github.token }}
run: |
for attempt in $(seq 1 20); do
if gh release view "${GITHUB_REF_NAME}" --repo "${GITHUB_REPOSITORY}" >/dev/null 2>&1; then
exit 0
fi
echo "Release ${GITHUB_REF_NAME} not available yet; waiting..."
sleep 15
done
echo "Timed out waiting for release ${GITHUB_REF_NAME}" >&2
exit 1
- name: Upload macOS assets
env:
GH_TOKEN: ${{ github.token }}
run: |
gh release upload "${GITHUB_REF_NAME}" \
dist/*.pkg \
dist/checksums-macos.txt \
--clobber \
--repo "${GITHUB_REPOSITORY}"