name: CI/CD Pipeline "on": push: branches: [ master, develop ] tags: [ 'v*.*.*' ] pull_request: branches: [ master ] env: CARGO_TERM_COLOR: always RUST_BACKTRACE: 1 jobs: fmt: name: Code Format runs-on: ubuntu-24.04 steps: - name: Checkout repository run: | curl -sfL -H "Authorization: token ${{ secrets.GITEATOKEN }}" "https://gitea-lxc.moon-dragon.us/git-echo/linux_patch_api/archive/${GITHUB_SHA}.tar.gz" -o repo.tar.gz tar -xzf repo.tar.gz --strip-components=1 rm -f repo.tar.gz - name: Install Rust run: | curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable --profile minimal . "$HOME/.cargo/env" rustup component add rustfmt echo "$HOME/.cargo/bin" >> "$GITHUB_PATH" - name: Check formatting run: cargo fmt --all -- --check clippy: name: Clippy Lints runs-on: ubuntu-24.04 steps: - name: Checkout repository run: | curl -sfL -H "Authorization: token ${{ secrets.GITEATOKEN }}" "https://gitea-lxc.moon-dragon.us/git-echo/linux_patch_api/archive/${GITHUB_SHA}.tar.gz" -o repo.tar.gz tar -xzf repo.tar.gz --strip-components=1 rm -f repo.tar.gz - name: Install Rust run: | curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable --profile minimal . "$HOME/.cargo/env" rustup component add clippy echo "$HOME/.cargo/bin" >> "$GITHUB_PATH" - name: Install system dependencies run: | sudo apt-get update sudo apt-get -f install -y sudo apt-get install -y build-essential libsystemd-dev pkg-config libssl-dev - name: Run clippy run: cargo clippy --all-targets --all-features -- -D warnings test: name: All Unit Tests runs-on: ubuntu-24.04 steps: - name: Checkout repository run: | curl -sfL -H "Authorization: token ${{ secrets.GITEATOKEN }}" "https://gitea-lxc.moon-dragon.us/git-echo/linux_patch_api/archive/${GITHUB_SHA}.tar.gz" -o repo.tar.gz tar -xzf repo.tar.gz --strip-components=1 rm -f repo.tar.gz - name: Install Rust run: | curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable --profile minimal . "$HOME/.cargo/env" echo "$HOME/.cargo/bin" >> "$GITHUB_PATH" - name: Install system dependencies run: | sudo apt-get update sudo apt-get -f install -y sudo apt-get install -y build-essential libsystemd-dev pkg-config libssl-dev - name: Run tests run: cargo test --all-features audit: name: Security Audit runs-on: ubuntu-24.04 steps: - name: Checkout repository run: | curl -sfL -H "Authorization: token ${{ secrets.GITEATOKEN }}" "https://gitea-lxc.moon-dragon.us/git-echo/linux_patch_api/archive/${GITHUB_SHA}.tar.gz" -o repo.tar.gz tar -xzf repo.tar.gz --strip-components=1 rm -f repo.tar.gz - name: Install Rust run: | curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable --profile minimal . "$HOME/.cargo/env" echo "$HOME/.cargo/bin" >> "$GITHUB_PATH" - name: Install system dependencies run: | sudo apt-get update sudo apt-get -f install -y sudo apt-get install -y build-essential libsystemd-dev pkg-config libssl-dev - name: Run cargo-audit run: | cargo install cargo-audit cargo audit --ignore RUSTSEC-2025-0134 enrollment-tests: name: Enrollment Tests needs: [fmt, clippy] runs-on: ubuntu-24.04 steps: - name: Checkout repository run: | curl -sfL -H "Authorization: token ${{ secrets.GITEATOKEN }}" "https://gitea-lxc.moon-dragon.us/git-echo/linux_patch_api/archive/${GITHUB_SHA}.tar.gz" -o repo.tar.gz tar -xzf repo.tar.gz --strip-components=1 rm -f repo.tar.gz - name: Install Rust run: | curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable --profile minimal . "$HOME/.cargo/env" echo "$HOME/.cargo/bin" >> "$GITHUB_PATH" - name: Install system dependencies run: | sudo apt-get update sudo apt-get -f install -y sudo apt-get install -y build-essential libsystemd-dev pkg-config libssl-dev - name: Run enrollment unit tests run: cargo test --test enroll_identity - name: Run enrollment integration tests run: cargo test --test enrollment_test - name: Run enrollment E2E tests run: cargo test --test enrollment_e2e verify-enrollment-cli: name: Verify Enrollment CLI Flag needs: [clippy] runs-on: ubuntu-24.04 steps: - name: Checkout repository run: | curl -sfL -H "Authorization: token ${{ secrets.GITEATOKEN }}" "https://gitea-lxc.moon-dragon.us/git-echo/linux_patch_api/archive/${GITHUB_SHA}.tar.gz" -o repo.tar.gz tar -xzf repo.tar.gz --strip-components=1 rm -f repo.tar.gz - name: Install Rust run: | curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable --profile minimal . "$HOME/.cargo/env" echo "$HOME/.cargo/bin" >> "$GITHUB_PATH" - name: Install system dependencies run: | sudo apt-get update sudo apt-get -f install -y sudo apt-get install -y build-essential libsystemd-dev pkg-config libssl-dev - name: Build binary run: cargo build - name: Verify --enroll flag exists run: cargo run -- --help | grep -q '\-\-enroll' build-deb: name: Build Debian Package needs: [fmt, clippy, test, enrollment-tests] runs-on: ubuntu-24.04 steps: - name: Checkout repository run: | curl -sfL -H "Authorization: token ${{ secrets.GITEATOKEN }}" "https://gitea-lxc.moon-dragon.us/git-echo/linux_patch_api/archive/${GITHUB_SHA}.tar.gz" -o repo.tar.gz tar -xzf repo.tar.gz --strip-components=1 rm -f repo.tar.gz - name: Install Rust run: | curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable --profile minimal . "$HOME/.cargo/env" echo "$HOME/.cargo/bin" >> "$GITHUB_PATH" - name: Install build dependencies run: | sudo apt-get update sudo apt-get -f install -y sudo apt-get install -y build-essential debhelper pkg-config libsystemd-dev libssl-dev - name: Clean previous build artifacts run: | cargo clean rm -f ../linux-patch-api_*.deb - name: Build Debian package run: | sudo dpkg-buildpackage -us -uc -b -d - name: Upload to Gitea Release if: github.ref_type == 'tag' env: GITEA_TOKEN: ${{ secrets.GITEATOKEN }} run: | TAG_NAME=${GITHUB_REF#refs/tags/} FILE=$(ls ../linux-patch-api_*.deb 2>/dev/null | head -1) # Rename deb to include u2404 in filename to distinguish from u2204 build if [ -n "$FILE" ]; then U2404_FILE="$(echo "$FILE" | sed 's/_amd64/_u2404_amd64/')" mv "$FILE" "$U2404_FILE" FILE="$U2404_FILE" fi chmod +x scripts/upload-release.sh ./scripts/upload-release.sh "$TAG_NAME" "$FILE" build-deb-u2204: name: Build Debian Package (Ubuntu 22.04) needs: [fmt, clippy, test, enrollment-tests] runs-on: ubuntu-22.04 steps: - name: Checkout repository run: | curl -sfL -H "Authorization: token ${{ secrets.GITEATOKEN }}" "https://gitea-lxc.moon-dragon.us/git-echo/linux_patch_api/archive/${GITHUB_SHA}.tar.gz" -o repo.tar.gz tar -xzf repo.tar.gz --strip-components=1 rm -f repo.tar.gz - name: Install Rust run: | curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable --profile minimal . "$HOME/.cargo/env" echo "$HOME/.cargo/bin" >> "$GITHUB_PATH" - name: Install build dependencies run: | sudo apt-get update sudo apt-get -f install -y sudo apt-get install -y build-essential debhelper pkg-config libsystemd-dev libssl-dev - name: Clean previous build artifacts run: | cargo clean rm -f ../linux-patch-api_*.deb - name: Build Debian package run: | sudo dpkg-buildpackage -us -uc -b -d - name: Upload to Gitea Release if: github.ref_type == 'tag' env: GITEA_TOKEN: ${{ secrets.GITEATOKEN }} run: | TAG_NAME=${GITHUB_REF#refs/tags/} FILE=$(ls ../linux-patch-api_*.deb 2>/dev/null | head -1) # Rename deb to include u2204 in filename to avoid collision with main build if [ -n "$FILE" ]; then U2204_FILE="$(echo "$FILE" | sed 's/_amd64/_u2204_amd64/')" mv "$FILE" "$U2204_FILE" FILE="$U2204_FILE" fi chmod +x scripts/upload-release.sh ./scripts/upload-release.sh "$TAG_NAME" "$FILE" build-rpm: name: Build RPM Package needs: [fmt, clippy, test, enrollment-tests] runs-on: fedora steps: - name: Checkout repository run: | curl -sfL -H "Authorization: token ${{ secrets.GITEATOKEN }}" "https://gitea-lxc.moon-dragon.us/git-echo/linux_patch_api/archive/${GITHUB_SHA}.tar.gz" -o repo.tar.gz tar -xzf repo.tar.gz --strip-components=1 rm -f repo.tar.gz - name: Install Rust run: | curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable --profile minimal . "$HOME/.cargo/env" echo "$HOME/.cargo/bin" >> "$GITHUB_PATH" - name: Install build dependencies run: | sudo dnf install -y gcc rpm-build systemd-devel pkg-config openssl-devel - name: Clean stale RPM artifacts run: | rm -f ~/rpmbuild/RPMS/x86_64/linux-patch-api-*.rpm rm -f releases/linux-patch-api-*.rpm - name: Build release binary run: cargo build --release - name: Build RPM package run: | chmod +x build-rpm.sh SKIP_CARGO_BUILD=1 ./build-rpm.sh - name: Verify RPM package run: | VERSION=$(grep '^version' Cargo.toml | head -1 | sed 's/.*=.*"\([^"]*\)".*/\1/') RPM_FILE=$(ls ~/rpmbuild/RPMS/x86_64/linux-patch-api-${VERSION}-*.rpm 2>/dev/null | head -1) if [ -z "$RPM_FILE" ]; then echo "ERROR: RPM package not found for version $VERSION!" ls -la ~/rpmbuild/RPMS/x86_64/ 2>/dev/null || echo "RPM directory empty or missing" exit 1 fi RPM_VERSION=$(rpm -qp --queryformat '%{VERSION}' "$RPM_FILE" 2>/dev/null || true) echo "RPM file: $RPM_FILE" echo "RPM version: $RPM_VERSION" echo "Expected version: $VERSION" if [ "$RPM_VERSION" != "$VERSION" ]; then echo "ERROR: RPM version ($RPM_VERSION) does not match expected version ($VERSION)!" exit 1 fi echo "RPM verification passed" - name: Upload to Gitea Release if: github.ref_type == 'tag' env: GITEA_TOKEN: ${{ secrets.GITEATOKEN }} run: | TAG_NAME=${GITHUB_REF#refs/tags/} VERSION=$(grep '^version' Cargo.toml | head -1 | sed 's/.*=.*"\([^"]*\)".*/\1/') FILE=$(ls ~/rpmbuild/RPMS/x86_64/linux-patch-api-${VERSION}-*.rpm 2>/dev/null | head -1) if [ -z "$FILE" ]; then echo "ERROR: No RPM found with version $VERSION for upload!" exit 1 fi chmod +x scripts/upload-release.sh ./scripts/upload-release.sh "$TAG_NAME" "$FILE" build-apk: name: Build Alpine Package needs: [fmt, clippy, test, enrollment-tests] runs-on: alpine steps: - name: Checkout repository run: | apk add --no-cache curl curl -sfL -H "Authorization: token ${{ secrets.GITEATOKEN }}" "https://gitea-lxc.moon-dragon.us/git-echo/linux_patch_api/archive/${GITHUB_SHA}.tar.gz" -o repo.tar.gz tar -xzf repo.tar.gz --strip-components=1 rm -f repo.tar.gz - name: Install Rust run: | apk add --no-cache curl bash curl --ipv4 --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable --profile minimal . "$HOME/.cargo/env" rustup target add x86_64-unknown-linux-musl echo "$HOME/.cargo/bin" >> "$GITHUB_PATH" - name: Install build dependencies run: | apk add --no-cache alpine-sdk rust cargo openssl openssl-dev elogind-dev musl-dev abuild gcc - name: Build release binary run: cargo build --release --target x86_64-unknown-linux-musl - name: Clean stale Alpine packages run: | rm -f releases/linux-patch-api-*.apk 2>/dev/null || true rm -f /home/builduser/packages/home/x86_64/linux-patch-api-*.apk 2>/dev/null || true - name: Build Alpine package run: | chmod +x build-alpine.sh SKIP_CARGO_BUILD=1 ./build-alpine.sh - name: Verify Alpine package run: | EXPECTED_VERSION=$(grep '^version' Cargo.toml | head -1 | sed 's/.*=.*"\([^"]*\)".*/\1/') FILE=$(ls releases/linux-patch-api-*.apk 2>/dev/null | head -1) if [ -z "$FILE" ]; then echo "ERROR: No Alpine package found!" exit 1 fi echo "Expected version: $EXPECTED_VERSION" echo "Package file: $FILE" # Verify filename contains expected version if ! echo "$FILE" | grep -q "$EXPECTED_VERSION build-arch: name: Build Arch Package needs: [fmt, clippy, test, enrollment-tests] runs-on: arch steps: - name: Checkout repository run: | curl -sfL -H "Authorization: token ${{ secrets.GITEATOKEN }}" "https://gitea-lxc.moon-dragon.us/git-echo/linux_patch_api/archive/${GITHUB_SHA}.tar.gz" -o repo.tar.gz tar -xzf repo.tar.gz --strip-components=1 rm -f repo.tar.gz - name: Install Rust run: | curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable --profile minimal . "$HOME/.cargo/env" echo "$HOME/.cargo/bin" >> "$GITHUB_PATH" - name: Install build dependencies run: | sudo pacman -Syu --noconfirm rust cargo systemd git base-devel gcc - name: Clean previous build artifacts run: | cargo clean rm -f releases/linux-patch-api-*.pkg.tar.zst - name: Build release binary run: cargo build --release - name: Build Arch package run: | chmod +x build-arch.sh SKIP_CARGO_BUILD=1 ./build-arch.sh - name: Verify Arch package run: | FILE=$(ls releases/*.pkg.tar.zst 2>/dev/null | head -1) if [ -z "$FILE" ]; then echo "ERROR: No Arch package found!" exit 1 fi EXPECTED_VERSION=$(grep '^version' Cargo.toml | head -1 | sed 's/.*=.*"\([^"]*\)".*/\1/') echo "Expected version: $EXPECTED_VERSION" echo "Package file: $FILE" # Verify the package contains the correct binary version pacman -Qip "$FILE" 2>/dev/null | grep -i version || true - name: Upload to Gitea Release if: startsWith(github.ref, 'refs/tags/') env: GITEA_TOKEN: ${{ secrets.GITEATOKEN }} run: | TAG_NAME=${GITHUB_REF#refs/tags/} FILE=$(ls releases/*.pkg.tar.zst 2>/dev/null | head -1) chmod +x scripts/upload-release.sh ./scripts/upload-release.sh "$TAG_NAME" "$FILE"