name: CI on: push: branches: [master] pull_request: branches: [master] env: CARGO_TERM_COLOR: always RUST_BACKTRACE: 1 jobs: rust-quality: name: Rust Quality runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable with: components: rustfmt, clippy - name: Cache Rust dependencies uses: Swatinem/rust-cache@v2 with: cache-on-failure: true - name: Check formatting run: | if [ "${{ github.event_name }}" = "pull_request" ]; then cargo fmt --all -- --check else cargo fmt --all -- --check || echo "::warning::Rust formatting issues found (not failing on push)" fi - name: Clippy run: cargo clippy --no-default-features -- -D warnings frontend-quality: name: Frontend Quality runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Setup Bun uses: oven-sh/setup-bun@v2 with: bun-version: latest - name: Install dependencies working-directory: web run: bun install --frozen-lockfile - name: Check formatting working-directory: web run: | if [ "${{ github.event_name }}" = "pull_request" ]; then bun run format:check else bun run format:check || echo "::warning::Frontend formatting issues found (not failing on push)" fi - name: Type check working-directory: web run: bun run typecheck rust-tests: name: Rust Tests runs-on: ubuntu-latest services: postgres: image: postgres:17-alpine env: POSTGRES_USER: banner POSTGRES_PASSWORD: banner POSTGRES_DB: banner ports: - 5432:5432 options: >- --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 env: DATABASE_URL: postgresql://banner:banner@localhost:5432/banner steps: - uses: actions/checkout@v4 - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable - name: Cache Rust dependencies uses: Swatinem/rust-cache@v2 with: cache-on-failure: true - name: Run tests run: cargo test --no-default-features frontend-tests: name: Frontend Tests runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Setup Bun uses: oven-sh/setup-bun@v2 with: bun-version: latest - name: Install dependencies working-directory: web run: bun install --frozen-lockfile - name: Run tests working-directory: web run: bun run test docker-build: name: Docker Build runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Build image uses: docker/build-push-action@v6 with: context: . push: false cache-from: type=gha cache-to: type=gha,mode=max security: name: Security Scan runs-on: ubuntu-latest permissions: contents: read security-events: write steps: - uses: actions/checkout@v4 - name: Install cargo-audit uses: taiki-e/install-action@cargo-audit - name: Rust security audit run: cargo audit - name: Setup Bun uses: oven-sh/setup-bun@v2 with: bun-version: latest - name: Install frontend dependencies working-directory: web run: bun install --frozen-lockfile - name: Frontend security audit working-directory: web run: bun audit --audit-level=moderate continue-on-error: true - name: Trivy filesystem scan uses: aquasecurity/trivy-action@master with: scan-type: fs scan-ref: . format: sarif output: trivy-results.sarif severity: CRITICAL,HIGH exit-code: 0 - name: Upload Trivy results uses: github/codeql-action/upload-sarif@v4 if: always() && hashFiles('trivy-results.sarif') != '' with: sarif_file: trivy-results.sarif