mirror of
https://github.com/jmcorgan/fips.git
synced 2026-10-05 19:18:25 +00:00
522 lines
22 KiB
YAML
522 lines
22 KiB
YAML
name: FreeBSD Package
|
|
on:
|
|
push:
|
|
branches:
|
|
- master
|
|
- maint
|
|
- next
|
|
tags:
|
|
- "v*"
|
|
pull_request:
|
|
workflow_dispatch:
|
|
|
|
env:
|
|
CARGO_TERM_COLOR: always
|
|
|
|
jobs:
|
|
determine-versioning:
|
|
runs-on: ubuntu-latest
|
|
outputs:
|
|
freebsd_package_version: ${{ steps.freebsd_version.outputs.freebsd_package_version }}
|
|
freebsd_pkg_file_version: ${{ steps.freebsd_version.outputs.freebsd_pkg_file_version }}
|
|
steps:
|
|
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
|
|
with:
|
|
fetch-depth: 0
|
|
|
|
- name: Derive FreeBSD package version
|
|
id: freebsd_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/\.\{2,\}/./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
|
|
|
|
# build-pkg.sh maps '-' and '+' to '.' (neither is allowed in a
|
|
# pkg version); derive the same mapping here so later steps can
|
|
# assert the exact artifact filename.
|
|
PKG_FILE_VERSION=$(printf '%s' "$VERSION" | tr -- '+-' '..')
|
|
|
|
echo "freebsd_package_version=${VERSION}" >> "$GITHUB_OUTPUT"
|
|
echo "freebsd_pkg_file_version=${PKG_FILE_VERSION}" >> "$GITHUB_OUTPUT"
|
|
|
|
build:
|
|
name: Build FreeBSD package (x86_64)
|
|
# No GitHub-hosted FreeBSD runners exist; build inside a KVM-accelerated
|
|
# FreeBSD VM on the Linux runner. The release must track the .pkg ABI
|
|
# major (FreeBSD:15:amd64) — pkg on other majors refuses the package.
|
|
runs-on: ubuntu-latest
|
|
needs: determine-versioning
|
|
# Successful runs of this job take 8 to 11 minutes. Five consecutive runs
|
|
# in August 2026 instead sat in the VM step for 70, 190, 360, 360 and 360
|
|
# minutes and ended cancelled, the last three at GitHub's own six-hour job
|
|
# ceiling. Nothing here bounded them. This bound is deliberately loose
|
|
# enough that a slow-but-working run still passes, and tight enough that a
|
|
# stall fails in half an hour instead of burning a runner for six.
|
|
timeout-minutes: 30
|
|
|
|
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: Build and smoke-install in FreeBSD VM
|
|
uses: vmactions/freebsd-vm@f0552d3b69211736abd97f02ff3d4674c56b73b1 # v1
|
|
env:
|
|
FREEBSD_PACKAGE_VERSION: ${{ needs.determine-versioning.outputs.freebsd_package_version }}
|
|
with:
|
|
release: "15.1"
|
|
usesh: true
|
|
sync: rsync
|
|
copyback: true
|
|
mem: 6144
|
|
envs: "SOURCE_DATE_EPOCH CARGO_TERM_COLOR FREEBSD_PACKAGE_VERSION"
|
|
prepare: |
|
|
pkg install -y curl
|
|
run: |
|
|
set -e
|
|
|
|
# rustup rather than the ports rust: rust-toolchain.toml pins
|
|
# the toolchain, and rustup honors the pin on first cargo use.
|
|
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \
|
|
| sh -s -- -y --default-toolchain none --profile minimal
|
|
. "$HOME/.cargo/env"
|
|
|
|
cargo build --release
|
|
|
|
# The only place the FreeBSD cfg arms' unit tests ever run in
|
|
# CI — the main CI matrix is Linux-only, and a release build
|
|
# compiles no #[cfg(test)] code (AF-prefix strip round-trips,
|
|
# platform module, config path gates).
|
|
#
|
|
# Bounded, because libtest has no per-test deadline and this job
|
|
# runs plain `cargo test` rather than nextest, so one test that
|
|
# blocks on a syscall holds the whole binary open with nothing to
|
|
# end it. Six runs in August 2026 did exactly that. The bound is on
|
|
# the suite rather than on the job so the failure is a named step
|
|
# failure at fifteen minutes instead of the job ceiling at thirty,
|
|
# and `timeout` leaves the test binary's stdout untouched up to the
|
|
# kill: that stdout is what carries libtest's "has been running for
|
|
# over N seconds" lines, which are what name the blocked test.
|
|
#
|
|
# This bounds the damage; it does not fix anything. A test that can
|
|
# block for ever is a defect at the test, and the ones this suite
|
|
# has are bounded where they are written.
|
|
if ! timeout -s KILL 900 cargo test; then
|
|
echo "FAIL: cargo test failed, or did not finish within its 900s bound." >&2
|
|
echo " If the output above stops mid-run, look for libtest's" >&2
|
|
echo " 'has been running for over' lines: they name the test" >&2
|
|
echo " that blocked, and the tests that never reported at all" >&2
|
|
echo " are the rest of the answer." >&2
|
|
exit 1
|
|
fi
|
|
|
|
packaging/freebsd/build-pkg.sh \
|
|
--version "$FREEBSD_PACKAGE_VERSION" \
|
|
--no-build
|
|
|
|
# Smoke-install the package in the VM: files land where the
|
|
# rc.d scripts and DNS integration expect them, and the
|
|
# binaries link against this release's base libraries.
|
|
PKG=$(ls deploy/fips-*-freebsd-*.pkg)
|
|
pkg add "$PKG"
|
|
for bin in fips fipsctl fipstop; do
|
|
test -x "/usr/local/bin/$bin" || { echo "FAIL: missing /usr/local/bin/$bin"; exit 1; }
|
|
if ldd "/usr/local/bin/$bin" | grep "not found"; then
|
|
echo "FAIL: unresolved shared libraries in $bin"; exit 1
|
|
fi
|
|
done
|
|
test -x /usr/local/etc/rc.d/fips
|
|
test -x /usr/local/etc/rc.d/fips_dns
|
|
test -f /usr/local/etc/fips/fips.yaml.sample
|
|
test -f /usr/local/etc/fips/hosts.sample
|
|
# The manifest post-install script must have copied the
|
|
# samples into place (install-if-absent semantics).
|
|
test -f /usr/local/etc/fips/fips.yaml
|
|
test -f /usr/local/etc/fips/hosts
|
|
# fips.yaml may hold a node private key (nsec:); it must not
|
|
# be world-readable — Debian and macOS both install it 0600.
|
|
for f in /usr/local/etc/fips/fips.yaml /usr/local/etc/fips/fips.yaml.sample; do
|
|
mode=$(stat -f %Lp "$f")
|
|
if [ "$mode" != "600" ]; then
|
|
echo "FAIL: $f mode is $mode, expected 600"; exit 1
|
|
fi
|
|
done
|
|
# post-install must create the control-socket access group.
|
|
pw groupshow fips >/dev/null || { echo "FAIL: fips group missing"; exit 1; }
|
|
test -x /usr/local/libexec/fips/fips-dns-setup
|
|
|
|
# The package's newsyslog entry must rotate the daemon log and
|
|
# make daemon(8) reopen it. The rc script starts daemon(8) with
|
|
# -H and records the supervisor's pid in daemon.pid, which the
|
|
# entry signals; without -H the supervisor keeps writing into
|
|
# the rotated file.
|
|
LOG=/var/log/fips.log
|
|
ENTRY=/usr/local/etc/newsyslog.conf.d/fips.conf
|
|
test -f "$ENTRY" || { echo "FAIL: missing $ENTRY"; exit 1; }
|
|
# Dry run of the stock configuration: the entry is reached only
|
|
# through newsyslog.conf's include of newsyslog.conf.d.
|
|
if ! newsyslog -nv 2>&1 | grep -q "$LOG"; then
|
|
echo "FAIL: the stock newsyslog configuration does not cover $LOG"
|
|
newsyslog -nv 2>&1 || true
|
|
exit 1
|
|
fi
|
|
service fips onestart
|
|
i=0
|
|
until [ -s /var/run/fips/daemon.pid ] && [ -s "$LOG" ]; do
|
|
i=$((i + 1))
|
|
if [ "$i" -gt 30 ]; then
|
|
echo "FAIL: no daemon.pid or empty $LOG 30s after start"
|
|
ls -l /var/run/fips "$LOG" 2>&1 || true
|
|
cat "$LOG" 2>&1 || true
|
|
exit 1
|
|
fi
|
|
sleep 1
|
|
done
|
|
sup_pid=$(cat /var/run/fips/daemon.pid)
|
|
# Inode numbers a process holds open, from fstat's INUM column.
|
|
open_inodes() { fstat -p "$1" 2>/dev/null | awk 'NR > 1 && $6 ~ /^[0-9]+$/ { print $6 }'; }
|
|
before=$(stat -f %i "$LOG")
|
|
# -F rotates regardless of size; -f reads the shipped entry alone.
|
|
newsyslog -F -f "$ENTRY"
|
|
after=$(stat -f %i "$LOG")
|
|
if [ "$after" = "$before" ]; then
|
|
echo "FAIL: newsyslog -F did not rotate $LOG"; ls -li "$LOG"*; exit 1
|
|
fi
|
|
if ! ls "$LOG".0* >/dev/null 2>&1; then
|
|
echo "FAIL: no rotated generation of $LOG"; ls -l "$LOG"*; exit 1
|
|
fi
|
|
i=0
|
|
until open_inodes "$sup_pid" | grep -qx "$after"; do
|
|
i=$((i + 1))
|
|
if [ "$i" -gt 10 ]; then
|
|
echo "FAIL: daemon(8) pid $sup_pid did not reopen $LOG after rotation"
|
|
fstat -p "$sup_pid" || true
|
|
exit 1
|
|
fi
|
|
sleep 1
|
|
done
|
|
if open_inodes "$sup_pid" | grep -qx "$before"; then
|
|
echo "FAIL: daemon(8) pid $sup_pid still holds the rotated $LOG open"; exit 1
|
|
fi
|
|
service fips onestop
|
|
echo "==> log rotation PASSED"
|
|
|
|
pkg info fips
|
|
echo "==> pkg smoke-install PASSED"
|
|
|
|
# SHA-256 sidecar computed inside the VM; the host verifies the
|
|
# bytes again after the rsync copyback, so corruption across
|
|
# the VM handoff is detected before upload.
|
|
( cd deploy && sha256 -q "$(basename "$PKG")" \
|
|
| { read -r h; printf '%s %s\n' "$h" "$(basename "$PKG")"; } \
|
|
> "$(basename "$PKG").sha256" )
|
|
|
|
# The whole workspace is rsynced back to the host; drop the
|
|
# build tree so the copyback moves megabytes, not gigabytes.
|
|
rm -rf target
|
|
|
|
- name: Resolve FreeBSD asset path
|
|
id: freebsd-assets
|
|
shell: bash
|
|
run: |
|
|
: ${GITHUB_OUTPUT:=/tmp/github_output}
|
|
set -euo pipefail
|
|
|
|
# build-pkg.sh names the package from the derived version and the
|
|
# pkg ABI arch; assert the exact name so a naming regression fails
|
|
# here instead of colliding on the release page.
|
|
EXPECTED="deploy/fips-${{ needs.determine-versioning.outputs.freebsd_pkg_file_version }}-freebsd-amd64.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 integrity across the VM handoff
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
PKG="${{ steps.freebsd-assets.outputs.pkg }}"
|
|
sidecar="${PKG}.sha256"
|
|
if [[ ! -f "$sidecar" ]]; then
|
|
echo "FAIL: missing SHA-256 sidecar for $(basename "$PKG")" >&2
|
|
exit 1
|
|
fi
|
|
expected=$(awk '{print $1}' "$sidecar")
|
|
actual=$(sha256sum "$PKG" | awk '{print $1}')
|
|
if [[ "$expected" != "$actual" ]]; then
|
|
echo "FAIL: $(basename "$PKG") SHA-256 mismatch across the VM copyback" >&2
|
|
echo " expected (FreeBSD VM): $expected" >&2
|
|
echo " actual (host): $actual" >&2
|
|
exit 1
|
|
fi
|
|
echo "PASS: $(basename "$PKG") matches the in-VM SHA-256 ($actual)"
|
|
|
|
- name: Upload artifact
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
|
with:
|
|
name: fips_${{ needs.determine-versioning.outputs.freebsd_package_version }}_x86_64_freebsd
|
|
path: |
|
|
${{ steps.freebsd-assets.outputs.pkg }}
|
|
${{ steps.freebsd-assets.outputs.pkg }}.sha256
|
|
retention-days: 30
|
|
|
|
- name: Build summary
|
|
run: |
|
|
echo "Build Summary for freebsd/x86_64:"
|
|
echo " Package: ${{ steps.freebsd-assets.outputs.pkg }}"
|
|
|
|
pfsense:
|
|
name: Build and check the pfSense package (x86_64)
|
|
# A job of its own, so a pfSense-only failure — a new key in the common
|
|
# dns: block, a dependency that stops linking statically, a checker
|
|
# regression — reds this check by name and can never hide behind the
|
|
# FreeBSD job's result. `release` needs both jobs: the packages this
|
|
# job builds are release assets next to the FreeBSD one, after being run
|
|
# on pfSense Plus 26.03.1 and 26.07 (see packaging/pfsense/README.md),
|
|
# so a pfSense failure holds the release the way a FreeBSD failure
|
|
# does. On every other ref the artifact is kept 30 days for anyone to
|
|
# test.
|
|
#
|
|
# This VM is FreeBSD 15.1. One build yields static FreeBSD 15 binaries,
|
|
# packaged twice: as FreeBSD:15:amd64 for pfSense CE 2.8.1, and relabelled
|
|
# as FreeBSD:16:amd64 for CE 2.9 and Plus 26.x on Intel. Older binaries on
|
|
# a newer kernel is the direction FreeBSD's binary compatibility supports;
|
|
# the relabelled package has been run on Plus 26.03.1 and 26.07 (see
|
|
# packaging/pfsense/README.md). No aarch64 package is built
|
|
# here or published anywhere: rustup ships no toolchain for
|
|
# aarch64-unknown-freebsd, so such a build cannot honour the
|
|
# rust-toolchain.toml pin every published artifact is built with. ARM is
|
|
# build-it-yourself, per the README.
|
|
runs-on: ubuntu-latest
|
|
needs: determine-versioning
|
|
# Its own full release build in an emulated FreeBSD VM, like the build
|
|
# job; the same generous bound applies.
|
|
timeout-minutes: 45
|
|
|
|
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: Lint the install smoke test
|
|
# Same arrangement as package-openwrt.yml's install-nak.sh lint: the
|
|
# script does not ship in the package, so the guards for shipped sh
|
|
# scripts do not apply. It is plain sh because pfSense has no bash.
|
|
run: |
|
|
if ! command -v shellcheck >/dev/null 2>&1; then
|
|
sudo apt-get install -y --no-install-recommends shellcheck
|
|
fi
|
|
shellcheck --shell=sh testing/pfsense-install-smoke.sh
|
|
|
|
- name: Build and check the pfSense package in a FreeBSD VM
|
|
uses: vmactions/freebsd-vm@f0552d3b69211736abd97f02ff3d4674c56b73b1 # v1
|
|
env:
|
|
FREEBSD_PACKAGE_VERSION: ${{ needs.determine-versioning.outputs.freebsd_package_version }}
|
|
with:
|
|
release: "15.1"
|
|
usesh: true
|
|
sync: rsync
|
|
copyback: true
|
|
mem: 6144
|
|
envs: "SOURCE_DATE_EPOCH CARGO_TERM_COLOR FREEBSD_PACKAGE_VERSION"
|
|
prepare: |
|
|
# curl for rustup; bash and php for testing/check-pfsense-pkg.sh
|
|
# (the checker is bash, and it runs php -l plus a fips_strip_block
|
|
# unit test on the config.xml helper).
|
|
pkg install -y curl bash php85
|
|
run: |
|
|
set -e
|
|
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain none --profile minimal
|
|
. "$HOME/.cargo/env"
|
|
|
|
# Builds the release binaries (static by default) and packages
|
|
# them; on a FreeBSD 15.1 VM this yields the FreeBSD:15:amd64
|
|
# package for pfSense CE 2.8.1.
|
|
packaging/pfsense/build-pkg.sh --version "$FREEBSD_PACKAGE_VERSION"
|
|
PKG15=$(ls deploy/fips-*-pfsense-ce2.8-amd64.pkg)
|
|
|
|
# The same binaries again, labelled for FreeBSD 16 (pfSense CE 2.9
|
|
# and Plus 26.x on Intel). No FreeBSD 16 host is needed for that:
|
|
# static binaries from 15.1 run on a 16 kernel, the direction
|
|
# FreeBSD supports, and pkg only checks the label.
|
|
packaging/pfsense/build-pkg.sh --no-build --abi FreeBSD:16:amd64 \
|
|
--version "$FREEBSD_PACKAGE_VERSION"
|
|
PKG16=$(ls deploy/fips-*-pfsense-ce2.9-plus26-amd64.pkg)
|
|
|
|
for PKG in "$PKG15" "$PKG16"; do
|
|
testing/check-pfsense-pkg.sh "$PKG"
|
|
( cd deploy && sha256 -q "$(basename "$PKG")" \
|
|
| { read -r h; printf '%s %s\n' "$h" "$(basename "$PKG")"; } \
|
|
> "$(basename "$PKG").sha256" )
|
|
done
|
|
php -l packaging/pfsense/fips-unbound-custom.php
|
|
# Install the FreeBSD 15 package and run the daemon through the
|
|
# boot script's life on this FreeBSD 15 kernel; see the script
|
|
# header for what that does and does not prove about pfSense
|
|
# itself. pkg refuses the FreeBSD 16 package on this host (ABI
|
|
# major mismatch); its binaries are the same bytes.
|
|
testing/pfsense-install-smoke.sh "$PKG15"
|
|
|
|
rm -rf target
|
|
|
|
- name: Resolve pfSense asset path
|
|
id: pfsense-asset
|
|
shell: bash
|
|
run: |
|
|
: ${GITHUB_OUTPUT:=/tmp/github_output}
|
|
set -euo pipefail
|
|
VER="${{ needs.determine-versioning.outputs.freebsd_pkg_file_version }}"
|
|
PKG15="deploy/fips-${VER}-pfsense-ce2.8-amd64.pkg"
|
|
PKG16="deploy/fips-${VER}-pfsense-ce2.9-plus26-amd64.pkg"
|
|
for p in "$PKG15" "$PKG16"; do
|
|
if [[ ! -f "$p" || ! -f "$p.sha256" ]]; then
|
|
echo "pfSense package or its checksum is missing: $p" >&2
|
|
ls -la deploy >&2 || true
|
|
exit 1
|
|
fi
|
|
done
|
|
echo "pkg15=$PKG15" >> "$GITHUB_OUTPUT"
|
|
echo "pkg16=$PKG16" >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Upload pfSense artifact
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
|
with:
|
|
name: fips_${{ needs.determine-versioning.outputs.freebsd_package_version }}_x86_64_pfsense
|
|
path: |
|
|
${{ steps.pfsense-asset.outputs.pkg15 }}
|
|
${{ steps.pfsense-asset.outputs.pkg15 }}.sha256
|
|
${{ steps.pfsense-asset.outputs.pkg16 }}
|
|
${{ steps.pfsense-asset.outputs.pkg16 }}.sha256
|
|
retention-days: 30
|
|
|
|
release:
|
|
name: Publish FreeBSD assets to GitHub Release
|
|
runs-on: ubuntu-latest
|
|
needs: [build, pfsense]
|
|
if: startsWith(github.ref, 'refs/tags/')
|
|
permissions:
|
|
contents: write
|
|
|
|
steps:
|
|
- name: Download FreeBSD artifacts
|
|
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
|
with:
|
|
# One named pattern per job: without a pattern this action downloads
|
|
# every artifact in the run, and `needs` only orders jobs; it does
|
|
# not scope this.
|
|
pattern: fips_*_x86_64_freebsd
|
|
path: dist
|
|
merge-multiple: true
|
|
|
|
- name: Download pfSense artifacts
|
|
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
|
with:
|
|
pattern: fips_*_x86_64_pfsense
|
|
path: dist
|
|
merge-multiple: true
|
|
|
|
- name: Validate .pkg bytes before publishing
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
cd dist
|
|
|
|
# Three packages are expected: the FreeBSD one and the two pfSense
|
|
# ones (each job wrote the sidecars inside its own VM). Missing one
|
|
# is a failure, not a smaller release.
|
|
for want in '*-freebsd-*.pkg' '*-pfsense-ce2.8-amd64.pkg' '*-pfsense-ce2.9-plus26-amd64.pkg'; do
|
|
if ! compgen -G "$want" >/dev/null; then
|
|
echo "FAIL: no package matching $want was downloaded" >&2
|
|
ls -la . >&2 || true
|
|
exit 1
|
|
fi
|
|
done
|
|
|
|
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 (FreeBSD VM): $expected" >&2
|
|
echo " actual (downloaded): $actual" >&2
|
|
fail=1
|
|
continue
|
|
fi
|
|
echo "PASS: $base matches the in-VM 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 FreeBSD release checksums
|
|
run: |
|
|
cd dist
|
|
find . -maxdepth 1 -type f -name '*.pkg' -printf '%P\n' \
|
|
| LC_ALL=C sort \
|
|
| xargs sha256sum \
|
|
> checksums-freebsd.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 FreeBSD assets
|
|
env:
|
|
GH_TOKEN: ${{ github.token }}
|
|
run: |
|
|
gh release upload "${GITHUB_REF_NAME}" \
|
|
dist/*.pkg \
|
|
dist/checksums-freebsd.txt \
|
|
--clobber \
|
|
--repo "${GITHUB_REPOSITORY}"
|