From 8c4455cc1cf6a7cfde4f69bfffb0e19fe26b9cd8 Mon Sep 17 00:00:00 2001 From: Origami74 Date: Wed, 25 Mar 2026 13:23:24 +0100 Subject: [PATCH 1/5] Fix OpenWrt ipk build: exclude BLE feature that requires D-Bus The ble feature (bluer crate) pulls in libdbus-sys which cannot cross-compile with cargo-zigbuild. Disable default features and explicitly enable only tui for the OpenWrt package build. --- packaging/openwrt-ipk/build-ipk.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packaging/openwrt-ipk/build-ipk.sh b/packaging/openwrt-ipk/build-ipk.sh index 07efc24..583f990 100755 --- a/packaging/openwrt-ipk/build-ipk.sh +++ b/packaging/openwrt-ipk/build-ipk.sh @@ -109,6 +109,8 @@ cd "$PROJECT_ROOT" cargo zigbuild \ --release \ --target "$RUST_TARGET" \ + --no-default-features \ + --features tui \ --bin fips \ --bin fipsctl \ --bin fipstop From 97fc29eb82daa7650f95a25ac428a93a4df4a20a Mon Sep 17 00:00:00 2001 From: Johnathan Corgan Date: Thu, 26 Mar 2026 16:31:05 +0000 Subject: [PATCH 2/5] Add ip6 routing policy rule to protect fd00::/8 from interception Tailscale (and potentially other routing software) installs a default IPv6 route in an auxiliary routing table with a policy rule that runs before the main table. This silently diverts fd00::/8 FIPS traffic away from the fips0 TUN device. Add an ip6 rule (priority 5265) during TUN setup that directs fd00::/8 to the main routing table, ensuring the fips0 route is always used. --- src/upper/tun.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/upper/tun.rs b/src/upper/tun.rs index 50c9e6c..d7542a0 100644 --- a/src/upper/tun.rs +++ b/src/upper/tun.rs @@ -467,6 +467,15 @@ async fn configure_interface(name: &str, addr: Ipv6Addr, mtu: u16) -> Result<(), .await .map_err(|e| TunError::Configure(format!("failed to add fd00::/8 route: {}", e)))?; + // Add ip6 rule to ensure fd00::/8 uses the main table, preventing other + // routing software (e.g. Tailscale) from intercepting FIPS traffic via + // catch-all rules in auxiliary routing tables. + let mut rule_req = handle.rule().add().v6().destination_prefix(fd_prefix, 8).table_id(254).priority(5265); + rule_req.message_mut().header.action = 1.into(); // FR_ACT_TO_TBL + if let Err(e) = rule_req.execute().await { + debug!("ip6 rule for fd00::/8 not added (may already exist): {e}"); + } + Ok(()) } From 7d33f1f2c98d4d47d46a35582c5af7d2c7ba758b Mon Sep 17 00:00:00 2001 From: jo <_@jodobear.com> Date: Tue, 31 Mar 2026 18:53:11 +0000 Subject: [PATCH 3/5] ci: add Linux packaging workflow and target-aware build scripts - Add package-linux.yml: builds tarball and .deb for x86_64 and aarch64 on v* tag push, uploads artifacts to GitHub release with checksums - Make build-tarball.sh target-aware: --target, --version, --arch, --no-build - Make build-deb.sh target-aware: --target, --version, --no-build - Configurable strip binary via STRIP env var --- .github/workflows/package-linux.yml | 196 ++++++++++++++++++++++++++++ packaging/debian/build-deb.sh | 63 ++++++++- packaging/systemd/build-tarball.sh | 97 ++++++++++++-- 3 files changed, 343 insertions(+), 13 deletions(-) create mode 100644 .github/workflows/package-linux.yml diff --git a/.github/workflows/package-linux.yml b/.github/workflows/package-linux.yml new file mode 100644 index 0000000..62c22de --- /dev/null +++ b/.github/workflows/package-linux.yml @@ -0,0 +1,196 @@ +name: Linux Package +on: + push: + tags: + - "v*" + workflow_dispatch: + +env: + CARGO_TERM_COLOR: always + +jobs: + determine-versioning: + runs-on: ubuntu-latest + outputs: + linux_package_version: ${{ steps.linux_version.outputs.linux_package_version }} + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Derive Linux package version + id: linux_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 "linux_package_version=${VERSION}" >> "$GITHUB_OUTPUT" + + build: + name: Build Linux artifacts (${{ matrix.artifact_arch }}) + runs-on: ${{ matrix.os }} + needs: determine-versioning + + strategy: + fail-fast: false + matrix: + include: + - os: ubuntu-latest + artifact_arch: x86_64 + deb_arch: amd64 + - os: ubuntu-24.04-arm + artifact_arch: aarch64 + deb_arch: arm64 + + steps: + - uses: actions/checkout@v4 + 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 system dependencies + run: sudo apt-get update && sudo apt-get install -y --no-install-recommends libdbus-1-dev llvm + + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@stable + + - name: Cache Cargo registry + build + if: ${{ env.ACT != 'true' }} + uses: actions/cache@v4 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + target + key: linux-release-${{ runner.os }}-${{ matrix.artifact_arch }}-${{ hashFiles('**/Cargo.lock') }} + restore-keys: | + linux-release-${{ runner.os }}-${{ matrix.artifact_arch }}- + + - name: Install cargo-deb + run: cargo install cargo-deb --version 3.6.3 --locked + + - name: Build release binaries + run: cargo build --release + + - name: Build systemd tarball + env: + STRIP: llvm-strip + run: | + packaging/systemd/build-tarball.sh \ + --version "${{ needs.determine-versioning.outputs.linux_package_version }}" \ + --arch "${{ matrix.artifact_arch }}" \ + --no-build + + - name: Build Debian package + run: | + packaging/debian/build-deb.sh \ + --version "${{ needs.determine-versioning.outputs.linux_package_version }}" \ + --no-build + + - name: Resolve Linux asset paths + id: linux-assets + shell: bash + run: | + : ${GITHUB_OUTPUT:=/tmp/github_output} + + TARBALL="deploy/fips-${{ needs.determine-versioning.outputs.linux_package_version }}-linux-${{ matrix.artifact_arch }}.tar.gz" + if [[ ! -f "$TARBALL" ]]; then + echo "Missing tarball: $TARBALL" >&2 + exit 1 + fi + + DEB_FILE=$(find deploy -maxdepth 1 -type f -name "fips_*_${{ matrix.deb_arch }}.deb" | sort | head -n 1) + if [[ -z "$DEB_FILE" ]]; then + echo "Missing Debian package for ${{ matrix.deb_arch }}" >&2 + exit 1 + fi + + echo "tarball=$TARBALL" >> "$GITHUB_OUTPUT" + echo "deb=$DEB_FILE" >> "$GITHUB_OUTPUT" + + - name: SHA-256 hashes + run: | + echo "==> Linux release assets:" + sha256sum \ + "${{ steps.linux-assets.outputs.tarball }}" \ + "${{ steps.linux-assets.outputs.deb }}" + + - name: Upload artifact (GitHub only) + if: ${{ env.ACT != 'true' }} + uses: actions/upload-artifact@v4 + with: + name: fips_${{ needs.determine-versioning.outputs.linux_package_version }}_${{ matrix.artifact_arch }}_linux + path: | + ${{ steps.linux-assets.outputs.tarball }} + ${{ steps.linux-assets.outputs.deb }} + retention-days: 30 + + - name: Build Summary + run: | + echo "Build Summary for linux/${{ matrix.artifact_arch }}:" + echo " Tarball: ${{ steps.linux-assets.outputs.tarball }}" + echo " Debian: ${{ steps.linux-assets.outputs.deb }}" + + release: + name: Publish Linux assets to GitHub Release + runs-on: ubuntu-latest + needs: build + if: startsWith(github.ref, 'refs/tags/') + permissions: + contents: write + + steps: + - name: Download Linux artifacts + uses: actions/download-artifact@v4 + with: + path: dist + merge-multiple: true + + - name: Generate Linux release checksums + run: | + cd dist + find . -maxdepth 1 -type f \( -name '*.deb' -o -name '*.tar.gz' \) -printf '%P\n' \ + | LC_ALL=C sort \ + | xargs sha256sum \ + > checksums-linux.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 Linux assets + env: + GH_TOKEN: ${{ github.token }} + run: | + gh release upload "${GITHUB_REF_NAME}" \ + dist/*.deb \ + dist/*.tar.gz \ + dist/checksums-linux.txt \ + --clobber \ + --repo "${GITHUB_REPOSITORY}" diff --git a/packaging/debian/build-deb.sh b/packaging/debian/build-deb.sh index 7ba3f7e..d703044 100755 --- a/packaging/debian/build-deb.sh +++ b/packaging/debian/build-deb.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash # Build a .deb package for FIPS using cargo-deb. # -# Usage: ./build-deb.sh +# Usage: ./build-deb.sh [--target ] [--version ] [--no-build] # # Prerequisites: cargo-deb (install with: cargo install cargo-deb) # Output: deploy/fips__.deb @@ -11,6 +11,48 @@ set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" PROJECT_ROOT="${SCRIPT_DIR}/../.." +usage() { + cat <<'EOF' +Usage: packaging/debian/build-deb.sh [options] + +Options: + --target Rust target triple to build/package + --version Override Debian package version + --no-build Package existing binaries without running cargo build + -h, --help Show this help +EOF +} + +TARGET_TRIPLE="" +VERSION_OVERRIDE="" +NO_BUILD=0 + +while [[ $# -gt 0 ]]; do + case "$1" in + --target) + TARGET_TRIPLE="${2:?missing value for --target}" + shift 2 + ;; + --version) + VERSION_OVERRIDE="${2:?missing value for --version}" + shift 2 + ;; + --no-build) + NO_BUILD=1 + shift + ;; + -h|--help) + usage + exit 0 + ;; + *) + echo "Unknown option: $1" >&2 + usage >&2 + exit 1 + ;; + esac +done + cd "${PROJECT_ROOT}" # Ensure cargo-deb is available @@ -26,14 +68,27 @@ fi # Build the .deb package echo "Building .deb package..." -cargo deb +OUTPUT_DIR="$(mktemp -d)" +trap 'rm -rf "${OUTPUT_DIR}"' EXIT + +cargo_args=(deb --output "${OUTPUT_DIR}") +if [[ -n "${TARGET_TRIPLE}" ]]; then + cargo_args+=(--target "${TARGET_TRIPLE}") +fi +if [[ -n "${VERSION_OVERRIDE}" ]]; then + cargo_args+=(--deb-version "${VERSION_OVERRIDE}") +fi +if [[ "${NO_BUILD}" -eq 1 ]]; then + cargo_args+=(--no-build) +fi +cargo "${cargo_args[@]}" # Move output to deploy/ mkdir -p deploy -DEB_FILE=$(find target/debian -name '*.deb' -printf '%T@ %p\n' | sort -rn | head -1 | cut -d' ' -f2) +DEB_FILE=$(find "${OUTPUT_DIR}" -maxdepth 1 -name '*.deb' -printf '%T@ %p\n' | sort -rn | head -1 | cut -d' ' -f2) if [ -z "${DEB_FILE}" ]; then - echo "Error: No .deb file found in target/debian/" >&2 + echo "Error: No .deb file found in ${OUTPUT_DIR}" >&2 exit 1 fi diff --git a/packaging/systemd/build-tarball.sh b/packaging/systemd/build-tarball.sh index d6c0e61..7887735 100755 --- a/packaging/systemd/build-tarball.sh +++ b/packaging/systemd/build-tarball.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash # Build FIPS release binaries and create an install tarball. # -# Usage: ./packaging/build-tarball.sh +# Usage: ./packaging/build-tarball.sh [--target ] [--version ] [--arch ] [--no-build] # Output: deploy/fips--linux-.tar.gz set -euo pipefail @@ -10,29 +10,108 @@ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" PACKAGING_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)" PROJECT_ROOT="$(cd "${PACKAGING_DIR}/.." && pwd)" -# Extract version from Cargo.toml -VERSION=$(grep '^version' "${PROJECT_ROOT}/Cargo.toml" | head -1 | sed 's/.*"\(.*\)"/\1/') -ARCH=$(uname -m) +usage() { + cat <<'EOF' +Usage: packaging/systemd/build-tarball.sh [options] + +Options: + --target Rust target triple to build/package + --version Override artifact version + --arch Override artifact architecture name + --no-build Package existing binaries without running cargo build + -h, --help Show this help +EOF +} + +target_to_arch() { + local target="$1" + printf '%s\n' "${target%%-*}" +} + +VERSION_OVERRIDE="" +TARGET_TRIPLE="" +ARCH_OVERRIDE="" +NO_BUILD=0 + +while [[ $# -gt 0 ]]; do + case "$1" in + --target) + TARGET_TRIPLE="${2:?missing value for --target}" + shift 2 + ;; + --version) + VERSION_OVERRIDE="${2:?missing value for --version}" + shift 2 + ;; + --arch) + ARCH_OVERRIDE="${2:?missing value for --arch}" + shift 2 + ;; + --no-build) + NO_BUILD=1 + shift + ;; + -h|--help) + usage + exit 0 + ;; + *) + echo "Unknown option: $1" >&2 + usage >&2 + exit 1 + ;; + esac +done + +VERSION="${VERSION_OVERRIDE:-$(grep '^version' "${PROJECT_ROOT}/Cargo.toml" | head -1 | sed 's/.*"\(.*\)"/\1/')}" +if [[ -n "${ARCH_OVERRIDE}" ]]; then + ARCH="${ARCH_OVERRIDE}" +elif [[ -n "${TARGET_TRIPLE}" ]]; then + ARCH="$(target_to_arch "${TARGET_TRIPLE}")" +else + ARCH="$(uname -m)" +fi TARBALL_NAME="fips-${VERSION}-linux-${ARCH}" DEPLOY_DIR="${PROJECT_ROOT}/deploy" STAGING_DIR="${DEPLOY_DIR}/${TARBALL_NAME}" +STRIP_BIN="${STRIP:-strip}" + +if [[ -n "${TARGET_TRIPLE}" ]]; then + BINARY_DIR="${PROJECT_ROOT}/target/${TARGET_TRIPLE}/release" +else + BINARY_DIR="${PROJECT_ROOT}/target/release" +fi echo "Building FIPS v${VERSION} for ${ARCH}..." # Build release binaries (tui is a default feature, includes fipstop) -cargo build --release --manifest-path="${PROJECT_ROOT}/Cargo.toml" +if [[ "${NO_BUILD}" -eq 0 ]]; then + cargo_args=(build --release --manifest-path="${PROJECT_ROOT}/Cargo.toml") + if [[ -n "${TARGET_TRIPLE}" ]]; then + cargo_args+=(--target "${TARGET_TRIPLE}") + fi + cargo "${cargo_args[@]}" +fi # Create staging directory rm -rf "${STAGING_DIR}" mkdir -p "${STAGING_DIR}" # Copy binaries -cp "${PROJECT_ROOT}/target/release/fips" "${STAGING_DIR}/" -cp "${PROJECT_ROOT}/target/release/fipsctl" "${STAGING_DIR}/" -cp "${PROJECT_ROOT}/target/release/fipstop" "${STAGING_DIR}/" +for bin in fips fipsctl fipstop; do + if [[ ! -f "${BINARY_DIR}/${bin}" ]]; then + echo "Missing binary: ${BINARY_DIR}/${bin}" >&2 + exit 1 + fi + cp "${BINARY_DIR}/${bin}" "${STAGING_DIR}/" +done # Strip binaries to reduce size -strip "${STAGING_DIR}/fips" "${STAGING_DIR}/fipsctl" "${STAGING_DIR}/fipstop" +if ! command -v "${STRIP_BIN}" &>/dev/null; then + echo "Strip tool not found: ${STRIP_BIN}" >&2 + exit 1 +fi +"${STRIP_BIN}" "${STAGING_DIR}/fips" "${STAGING_DIR}/fipsctl" "${STAGING_DIR}/fipstop" # Copy packaging files cp "${SCRIPT_DIR}/install.sh" "${STAGING_DIR}/" From 0ff9139b64a6ff164d7b6b3e732cca057a762b68 Mon Sep 17 00:00:00 2001 From: sandwich Date: Tue, 31 Mar 2026 19:14:49 +0000 Subject: [PATCH 4/5] ci: add AUR publish workflow for tagged releases - Publish fips PKGBUILD to AUR on stable v* tag push - Skip pre-release tags (containing '-') - Uses KSXGitHub/github-actions-deploy-aur, continue-on-error - Requires AUR_SSH_PRIVATE_KEY and AUR_EMAIL secrets --- .github/workflows/aur-publish.yml | 36 +++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 .github/workflows/aur-publish.yml diff --git a/.github/workflows/aur-publish.yml b/.github/workflows/aur-publish.yml new file mode 100644 index 0000000..38a9057 --- /dev/null +++ b/.github/workflows/aur-publish.yml @@ -0,0 +1,36 @@ +name: AUR Publish + +on: + push: + tags: + - 'v*' + +jobs: + aur-publish-fips: + name: Publish fips to AUR + runs-on: ubuntu-latest + continue-on-error: true + if: "!contains(github.ref_name, '-')" + + steps: + - uses: actions/checkout@v4 + + - name: Update pkgver in PKGBUILD + run: | + VERSION="${GITHUB_REF_NAME#v}" + sed -i "s/^pkgver=.*/pkgver=${VERSION}/" packaging/aur/PKGBUILD + + - name: Publish to AUR + uses: KSXGitHub/github-actions-deploy-aur@v4.1.1 + with: + pkgname: fips + pkgbuild: packaging/aur/PKGBUILD + updpkgsums: true + assets: | + packaging/aur/fips.sysusers + packaging/aur/fips.tmpfiles + packaging/aur/fips.install + commit_username: ${{ github.repository_owner }} + commit_email: ${{ secrets.AUR_EMAIL }} + ssh_private_key: ${{ secrets.AUR_SSH_PRIVATE_KEY }} + commit_message: "Update to ${{ github.ref_name }}" From f6f2bea7925eba8a88453e6fa0aa585b067e85d3 Mon Sep 17 00:00:00 2001 From: Johnathan Corgan Date: Tue, 31 Mar 2026 19:52:56 +0000 Subject: [PATCH 5/5] Update changelog with backported fixes and packaging workflows --- CHANGELOG.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a038073..f603332 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +- Linux release artifact workflow: builds x86_64 and aarch64 tarballs + and `.deb` packages on `v*` tag push, with SHA-256 checksums +- AUR publish workflow for tagged stable releases + ### Fixed - Control socket path detection in fipsctl and fipstop now checks for @@ -15,6 +21,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 error instead of a misleading "No such file" fallback to `$XDG_RUNTIME_DIR` ([#30](https://github.com/jmcorgan/fips/issues/30), reported by [@Sebastix](https://github.com/Sebastix)) +- OpenWrt ipk build excluded BLE feature that requires D-Bus, which is + unavailable on OpenWrt targets +- IPv6 routing policy rule added at TUN setup to protect `fd00::/8` + from interception by Tailscale's table 52 default route ## [0.2.0] - 2026-03-22