#!/usr/bin/env bash set -Eeuo pipefail source /opt/rust-package-builder/scripts/lib.sh : "${SHA:?SHA required}" : "${SRC:?SRC required}" : "${PKG:?PKG required}" : "${OUT:?OUT required}" : "${VERSION:?VERSION required}" : "${BINARY_NAME:?BINARY_NAME required}" : "${PACKAGE_NAME:?PACKAGE_NAME required}" REPOSITORY="$DATA_DIR/repository" APTLY_CONF="$DATA_DIR/state/aptly.conf" BRANCH_RELEASE_ID="$(date -u '+%Y%m%dT%H%M%SZ')-${SHORT_SHA}-linux" RELEASE_DIR="$REPOSITORY/releases/$BRANCH_RELEASE_ID" PUBLISHED=0 cleanup_linux_release() { if [[ "$PUBLISHED" != "1" && -d "$RELEASE_DIR" ]]; then rm -rf "$RELEASE_DIR" fi } trap cleanup_linux_release EXIT REQUESTED_PACKAGE_RELEASE=$PACKAGE_RELEASE if [[ "$REQUESTED_PACKAGE_RELEASE" == "auto" ]]; then LAST_LINUX_COMMIT="" LAST_VERSION="" LAST_PACKAGE_RELEASE=0 [[ -r "$DATA_DIR/state/last_linux_commit" ]] && LAST_LINUX_COMMIT=$(cat "$DATA_DIR/state/last_linux_commit") [[ -r "$DATA_DIR/state/last_version" ]] && LAST_VERSION=$(cat "$DATA_DIR/state/last_version") [[ -r "$DATA_DIR/state/last_package_release" ]] && LAST_PACKAGE_RELEASE=$(cat "$DATA_DIR/state/last_package_release") if [[ "$LAST_LINUX_COMMIT" == "$SHA" \ && "$LAST_VERSION" == "$VERSION" \ && "$LAST_PACKAGE_RELEASE" =~ ^[1-9][0-9]*$ ]]; then PACKAGE_RELEASE=$LAST_PACKAGE_RELEASE log "Linux repair build: reusing package release $PACKAGE_RELEASE" elif [[ "$LAST_VERSION" == "$VERSION" && "$LAST_PACKAGE_RELEASE" =~ ^[0-9]+$ ]]; then PACKAGE_RELEASE=$((LAST_PACKAGE_RELEASE + 1)) else PACKAGE_RELEASE=1 fi else PACKAGE_RELEASE=$REQUESTED_PACKAGE_RELEASE fi export PACKAGE_RELEASE cd "$SRC" log "Linux branch: version $VERSION release $PACKAGE_RELEASE" TEST_MODE="${RUN_LINUX_TESTS:-compile}" case "$TEST_MODE" in 0|off|false|no) log "Linux cargo tests skipped" ;; 1|compile|check|no-run) log "Linux cargo tests compile check started (--no-run)" if [[ -f Cargo.lock ]]; then cargo test --release --locked --no-run else cargo test --release --no-run fi log "Linux cargo tests compile check completed" ;; full|run) log "Linux full cargo tests started" if [[ -f Cargo.lock ]]; then cargo test --release --locked else cargo test --release fi log "Linux full cargo tests completed" ;; *) fatal "invalid RUN_LINUX_TESTS=$TEST_MODE (use: 0, 1/compile, or full)" ;; esac log "Linux cargo build started" if [[ -f Cargo.lock ]]; then cargo build --release --locked else cargo build --release fi log "Linux cargo build completed" BINARY_PATH="$CARGO_TARGET_DIR/release/$BINARY_NAME" [[ -x "$BINARY_PATH" ]] || fatal "built binary not found: $BINARY_PATH" MAX_GLIBC_FOUND=$(objdump -T "$BINARY_PATH" 2>/dev/null | grep -oE 'GLIBC_[0-9]+\.[0-9]+' | sed 's/^GLIBC_//' | sort -V | tail -n1 || true) if [[ -n "$MAX_GLIBC_FOUND" ]]; then if [[ "$(printf '%s\n%s\n' "$MAX_GLIBC_VERSION" "$MAX_GLIBC_FOUND" | sort -V | tail -n1)" != "$MAX_GLIBC_VERSION" ]]; then fatal "binary requires GLIBC_$MAX_GLIBC_FOUND, target maximum is GLIBC_$MAX_GLIBC_VERSION" fi log "glibc compatibility check: <= $MAX_GLIBC_FOUND" fi /opt/rust-package-builder/scripts/prepare-package.sh "$SRC" "$PKG" "$BINARY_PATH" DEB_FILE="$OUT/${PACKAGE_NAME}_${VERSION}-${PACKAGE_RELEASE}_amd64.deb" RPM_FILE="$OUT/${PACKAGE_NAME}-${VERSION}-${PACKAGE_RELEASE}.x86_64.rpm" log "creating deb package" nfpm package --config "$PKG/nfpm-deb.yaml" --packager deb --target "$DEB_FILE" log "creating rpm package" nfpm package --config "$PKG/nfpm-rpm.yaml" --packager rpm --target "$RPM_FILE" ar t "$DEB_FILE" | grep '^_gpgorigin$' >/dev/null || fatal "DEB package does not contain nFPM GPG origin signature" rpm -qpi "$RPM_FILE" | awk -F: '/^Signature/ && $0 !~ /\(none\)/ {ok=1} END{exit !ok}' || fatal "RPM package is not signed" log "Linux package signatures verified" cp -f "$DEB_FILE" "$DATA_DIR/packages/deb/" cp -f "$RPM_FILE" "$DATA_DIR/packages/rpm/x86_64/" log "updating aptly internal repository" aptly -config="$APTLY_CONF" repo add -force-replace package-builder "$DEB_FILE" >/dev/null SNAPSHOT="linux-${VERSION}-${SHORT_SHA}-$(date +%s)" aptly -config="$APTLY_CONF" snapshot create "$SNAPSHOT" from repo package-builder >/dev/null APTLY_SIGN_ARGS=(-batch -gpg-key="$GPG_KEY_ID") if [[ -r "$GPG_PASSPHRASE_FILE" ]]; then APTLY_SIGN_ARGS+=(-passphrase-file="$GPG_PASSPHRASE_FILE") fi if aptly -config="$APTLY_CONF" publish list -raw | awk -v d="$REPO_DISTRIBUTION" '$2 == d {found=1} END{exit !found}'; then aptly -config="$APTLY_CONF" publish switch -force-overwrite "${APTLY_SIGN_ARGS[@]}" "$REPO_DISTRIBUTION" . "$SNAPSHOT" >/dev/null else aptly -config="$APTLY_CONF" publish snapshot -force-overwrite "${APTLY_SIGN_ARGS[@]}" \ -distribution="$REPO_DISTRIBUTION" -component="$REPO_COMPONENT" -architectures=amd64 "$SNAPSHOT" >/dev/null fi APT_PUBLIC="$DATA_DIR/aptly/public" [[ -f "$APT_PUBLIC/dists/$REPO_DISTRIBUTION/InRelease" ]] || fatal "aptly did not create InRelease" [[ -f "$APT_PUBLIC/dists/$REPO_DISTRIBUTION/Release.gpg" ]] || fatal "aptly did not create Release.gpg" gpg --batch --verify "$APT_PUBLIC/dists/$REPO_DISTRIBUTION/Release.gpg" "$APT_PUBLIC/dists/$REPO_DISTRIBUTION/Release" >/dev/null 2>&1 \ || fatal "APT Release signature verification failed" mkdir -p "$RELEASE_DIR/apt" "$RELEASE_DIR/rpm/x86_64" "$RELEASE_DIR/opnsense" CURRENT_TARGET="" if [[ -L "$REPOSITORY/current" ]]; then CURRENT_LINK=$(readlink "$REPOSITORY/current") CURRENT_TARGET="$REPOSITORY/$CURRENT_LINK" fi log "staging Linux repository snapshot" if [[ -n "$CURRENT_TARGET" && -d "$CURRENT_TARGET/opnsense" ]]; then rsync -a --delete --link-dest="$CURRENT_TARGET/opnsense"/ "$CURRENT_TARGET/opnsense"/ "$RELEASE_DIR/opnsense"/ fi rsync -a --delete "$APT_PUBLIC"/ "$RELEASE_DIR/apt"/ rsync -a --delete "$DATA_DIR/packages/rpm"/ "$RELEASE_DIR/rpm"/ rm -rf "$RELEASE_DIR/rpm/x86_64/repodata" createrepo_c --update "$RELEASE_DIR/rpm/x86_64" >/dev/null GPG_SIGN_ARGS=(--batch --yes --pinentry-mode loopback) if [[ -r "$GPG_PASSPHRASE_FILE" ]]; then GPG_SIGN_ARGS+=(--passphrase-file "$GPG_PASSPHRASE_FILE") fi gpg "${GPG_SIGN_ARGS[@]}" --armor --detach-sign --local-user "$GPG_KEY_ID" \ --output "$RELEASE_DIR/rpm/x86_64/repodata/repomd.xml.asc" "$RELEASE_DIR/rpm/x86_64/repodata/repomd.xml" gpg --batch --verify "$RELEASE_DIR/rpm/x86_64/repodata/repomd.xml.asc" "$RELEASE_DIR/rpm/x86_64/repodata/repomd.xml" >/dev/null 2>&1 \ || fatal "RPM metadata signature verification failed" gpg --batch --armor --export "$GPG_KEY_ID" > "$RELEASE_DIR/repo-key.gpg" [[ -s "$RELEASE_DIR/repo-key.gpg" ]] || fatal "public GPG key export failed" /opt/rust-package-builder/scripts/generate-index.sh "$RELEASE_DIR/index.html" "$PACKAGE_NAME" cat > "$RELEASE_DIR/LINUX-BUILD-INFO.txt" <