name: CI/CD Pipeline on: push: branches: [main, develop] tags: - 'v*' pull_request: branches: [main, develop] schedule: - cron: '0 0 * * 0' env: CARGO_TERM_COLOR: always RUST_BACKTRACE: 1 RUSTFLAGS: -D warnings concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: check: name: Code Quality Checks runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v4 - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable with: components: rustfmt, clippy - name: Setup Rust cache uses: Swatinem/rust-cache@v2 with: shared-key: "check" - name: Check formatting run: cargo fmt --all -- --check - name: Run clippy (without YARA) run: cargo clippy --workspace --all-targets --no-default-features -- -D warnings - name: Check documentation run: cargo doc --workspace --no-deps --no-default-features env: RUSTDOCFLAGS: -D warnings test-linux: name: Test - Linux runs-on: ubuntu-latest needs: check strategy: matrix: rust: [stable, beta, nightly] features: ['', '--features yara-scanning', '--no-default-features'] continue-on-error: ${{ matrix.rust == 'nightly' }} steps: - name: Checkout repository uses: actions/checkout@v4 - name: Install YARA if: contains(matrix.features, 'yara-scanning') run: | sudo apt-get update sudo apt-get install -y libyara-dev pkg-config - name: Install Rust toolchain uses: dtolnay/rust-toolchain@master with: toolchain: ${{ matrix.rust }} - name: Setup Rust cache uses: Swatinem/rust-cache@v2 with: shared-key: "test-linux-${{ matrix.rust }}-${{ matrix.features }}" - name: Build run: cargo build --workspace --verbose ${{ matrix.features }} - name: Run tests run: cargo test --workspace --verbose ${{ matrix.features }} - name: Run doc tests run: cargo test --workspace --doc ${{ matrix.features }} test-windows: name: Test - Windows runs-on: windows-latest needs: check strategy: matrix: rust: [stable] features: ['', '--no-default-features'] steps: - name: Checkout repository uses: actions/checkout@v4 - name: Install Rust toolchain uses: dtolnay/rust-toolchain@master with: toolchain: ${{ matrix.rust }} - name: Setup Rust cache uses: Swatinem/rust-cache@v2 with: shared-key: "test-windows-${{ matrix.rust }}" - name: Build run: cargo build --workspace --verbose ${{ matrix.features }} - name: Run tests run: cargo test --workspace --verbose ${{ matrix.features }} test-macos: name: Test - macOS runs-on: macos-latest needs: check strategy: matrix: rust: [stable] features: ['', '--no-default-features'] steps: - name: Checkout repository uses: actions/checkout@v4 - name: Install Rust toolchain uses: dtolnay/rust-toolchain@master with: toolchain: ${{ matrix.rust }} - name: Setup Rust cache uses: Swatinem/rust-cache@v2 with: shared-key: "test-macos-${{ matrix.rust }}" - name: Build run: cargo build --workspace --verbose ${{ matrix.features }} - name: Run tests run: cargo test --workspace --verbose ${{ matrix.features }} coverage: name: Code Coverage runs-on: ubuntu-latest needs: check steps: - name: Checkout repository uses: actions/checkout@v4 - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable - name: Install cargo-llvm-cov uses: taiki-e/install-action@cargo-llvm-cov - name: Setup Rust cache uses: Swatinem/rust-cache@v2 - name: Generate coverage run: cargo llvm-cov --workspace --no-default-features --lcov --output-path lcov.info - name: Upload to codecov.io uses: codecov/codecov-action@v4 with: files: lcov.info fail_ci_if_error: false token: ${{ secrets.CODECOV_TOKEN }} security-audit: name: Security Audit runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v4 - name: Run cargo-audit uses: rustsec/audit-check@v1 with: token: ${{ secrets.GITHUB_TOKEN }} ignore: RUSTSEC-2024-0436 dependency-review: name: Dependency Review runs-on: ubuntu-latest if: github.event_name == 'pull_request' steps: - name: Checkout repository uses: actions/checkout@v4 - name: Dependency Review uses: actions/dependency-review-action@v4 build-release: name: Build Release - ${{ matrix.target }} runs-on: ${{ matrix.os }} needs: [test-linux, test-windows, test-macos] if: startsWith(github.ref, 'refs/tags/v') strategy: matrix: include: - target: x86_64-unknown-linux-gnu os: ubuntu-latest - target: x86_64-unknown-linux-musl os: ubuntu-latest - target: x86_64-pc-windows-msvc os: windows-latest - target: x86_64-apple-darwin os: macos-latest - target: aarch64-apple-darwin os: macos-latest steps: - name: Checkout repository uses: actions/checkout@v4 - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable with: targets: ${{ matrix.target }} - name: Setup Rust cache uses: Swatinem/rust-cache@v2 with: shared-key: "release-${{ matrix.target }}" - name: Install musl tools if: matrix.target == 'x86_64-unknown-linux-musl' run: sudo apt-get install -y musl-tools - name: Build release (musl) if: matrix.target == 'x86_64-unknown-linux-musl' run: cargo build --release --target ${{ matrix.target }} --no-default-features --features vendored-openssl - name: Build release (non-musl) if: matrix.target != 'x86_64-unknown-linux-musl' run: cargo build --release --target ${{ matrix.target }} --no-default-features - name: Create archive shell: bash run: | VERSION="${GITHUB_REF#refs/tags/v}" if [[ "${{ matrix.os }}" == "windows-latest" ]]; then ARCHIVE="ghost-${VERSION}-${{ matrix.target }}.zip" 7z a "${ARCHIVE}" ./target/${{ matrix.target }}/release/ghost-cli.exe ./target/${{ matrix.target }}/release/ghost-tui.exe else ARCHIVE="ghost-${VERSION}-${{ matrix.target }}.tar.gz" tar czf "${ARCHIVE}" -C ./target/${{ matrix.target }}/release ghost-cli ghost-tui fi echo "ARCHIVE=${ARCHIVE}" >> $GITHUB_ENV - name: Upload artifact uses: actions/upload-artifact@v4 with: name: ghost-${{ matrix.target }} path: ${{ env.ARCHIVE }} release: name: Create Release runs-on: ubuntu-latest needs: build-release if: startsWith(github.ref, 'refs/tags/v') permissions: contents: write steps: - name: Checkout repository uses: actions/checkout@v4 - name: Download artifacts uses: actions/download-artifact@v4 with: path: artifacts - name: Create GitHub Release uses: softprops/action-gh-release@v1 with: draft: false prerelease: ${{ contains(github.ref, 'alpha') || contains(github.ref, 'beta') || contains(github.ref, 'rc') }} generate_release_notes: true files: artifacts/**/* env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} benchmark: name: Performance Benchmarks runs-on: ubuntu-latest if: github.event_name == 'push' && github.ref == 'refs/heads/main' steps: - name: Checkout repository uses: actions/checkout@v4 - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable - name: Setup Rust cache uses: Swatinem/rust-cache@v2 - name: Run benchmarks run: cargo bench --no-default-features --no-fail-fast continue-on-error: true - name: Store benchmark result continue-on-error: true if: hashFiles('target/criterion/**/estimates.json') != '' uses: benchmark-action/github-action-benchmark@v1 with: tool: 'cargo' output-file-path: target/criterion/detection_performance/base/estimates.json github-token: ${{ secrets.GITHUB_TOKEN }} auto-push: true alert-threshold: '200%' comment-on-alert: true fail-on-alert: false all-checks-pass: name: All Checks Pass runs-on: ubuntu-latest needs: [check, test-linux, test-windows, test-macos, coverage, security-audit] if: always() steps: - name: Check job results run: | if [[ "${{ needs.check.result }}" != "success" ]] || \ [[ "${{ needs.test-linux.result }}" != "success" ]] || \ [[ "${{ needs.test-windows.result }}" != "success" ]] || \ [[ "${{ needs.test-macos.result }}" != "success" ]] || \ [[ "${{ needs.coverage.result }}" != "success" ]] || \ [[ "${{ needs.security-audit.result }}" != "success" ]]; then echo "One or more required checks failed" exit 1 fi echo "All required checks passed"