name: CI description: Runs Go tests, race detection, vulnerability scanning, and frontend quality checks. on: push: branches: - main - develop pull_request: env: POSTGRES_USER: myuser POSTGRES_PASSWORD: mypassword POSTGRES_DB: mydb jobs: vet: name: Build & Vet runs-on: ubuntu-latest defaults: run: shell: sh steps: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: go-version: "1.26.5" cache: false - name: Cache Go modules uses: actions/cache@v4 with: path: | ~/go/pkg/mod ~/.cache/go-build key: ${{ runner.os }}-go-${{ hashFiles('backend/go.sum') }}-vet restore-keys: | ${{ runner.os }}-go- - name: Fix node toolcache path for Post-step cleanup run: | mkdir -p /opt/hostedtoolcache/node/22.23.1/x64/bin ln -sf /usr/local/bin/node /opt/hostedtoolcache/node/22.23.1/x64/bin/node - run: go build ./... working-directory: backend - name: Vet (dev tags) run: go vet -tags "test,dev" ./... working-directory: backend - name: Vet (prod tags) run: go vet -tags "test,!dev" ./... working-directory: backend test: name: Tests (${{ matrix.label }}) needs: [vet, vulns] runs-on: ubuntu-latest defaults: run: shell: sh services: postgres: image: postgres:16-alpine env: POSTGRES_USER: myuser POSTGRES_PASSWORD: mypassword POSTGRES_DB: mydb options: >- --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 strategy: matrix: include: - label: dev gotags: test,dev verbose: -v - label: prod gotags: test,!dev verbose: "" steps: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: go-version: "1.26.5" cache: false - name: Cache Go modules uses: actions/cache@v4 with: path: | ~/go/pkg/mod ~/.cache/go-build key: ${{ runner.os }}-go-${{ hashFiles('backend/go.sum') }}-test-${{ matrix.label }} restore-keys: | ${{ runner.os }}-go- - name: Fix node toolcache path for Post-step cleanup run: | mkdir -p /opt/hostedtoolcache/node/22.23.1/x64/bin ln -sf /usr/local/bin/node /opt/hostedtoolcache/node/22.23.1/x64/bin/node - run: apk add --no-cache postgresql-client - run: | for i in $(seq 1 30); do pg_isready -h postgres -U myuser && break sleep 1 done - run: PGPASSWORD=mypassword psql -h postgres -U myuser -d mydb -c "CREATE DATABASE crussell_test_db;" 2>/dev/null || true - name: Test (${{ matrix.label }} tags) working-directory: backend run: go test -tags "${{ matrix.gotags }}" -count=1 ${{ matrix.verbose }} -timeout 180s ./... env: POSTGRES_HOST: postgres TEST_DB_HOST: postgres race: name: Race (${{ matrix.label }}) needs: [vet, vulns] runs-on: ubuntu-latest defaults: run: shell: sh services: postgres: image: postgres:16-alpine env: POSTGRES_USER: myuser POSTGRES_PASSWORD: mypassword POSTGRES_DB: mydb options: >- --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 strategy: matrix: include: - label: dev gotags: test,dev - label: prod gotags: test,!dev steps: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: go-version: "1.26.5" cache: false - name: Cache Go modules uses: actions/cache@v4 with: path: | ~/go/pkg/mod ~/.cache/go-build key: ${{ runner.os }}-go-${{ hashFiles('backend/go.sum') }}-race-${{ matrix.label }} restore-keys: | ${{ runner.os }}-go- - name: Fix node toolcache path for Post-step cleanup run: | mkdir -p /opt/hostedtoolcache/node/22.23.1/x64/bin ln -sf /usr/local/bin/node /opt/hostedtoolcache/node/22.23.1/x64/bin/node - run: apk add --no-cache postgresql-client build-base - run: | for i in $(seq 1 30); do pg_isready -h postgres -U myuser && break sleep 1 done - run: PGPASSWORD=mypassword psql -h postgres -U myuser -d mydb -c "CREATE DATABASE crussell_test_db;" 2>/dev/null || true - name: Race (${{ matrix.label }} tags) working-directory: backend run: go test -tags "${{ matrix.gotags }}" -race -count=1 -timeout 240s ./... env: POSTGRES_HOST: postgres TEST_DB_HOST: postgres CGO_ENABLED: "1" vulns: name: Go vulnerabilities runs-on: ubuntu-latest defaults: run: shell: sh steps: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: go-version: "1.26.5" cache: false - name: Cache Go modules uses: actions/cache@v4 with: path: | ~/go/pkg/mod ~/.cache/go-build key: ${{ runner.os }}-go-${{ hashFiles('backend/go.sum') }}-vulns restore-keys: | ${{ runner.os }}-go- - name: Fix node toolcache path for Post-step cleanup run: | mkdir -p /opt/hostedtoolcache/node/22.23.1/x64/bin ln -sf /usr/local/bin/node /opt/hostedtoolcache/node/22.23.1/x64/bin/node - name: Go vulnerability scan working-directory: backend run: | go install golang.org/x/vuln/cmd/govulncheck@latest govulncheck ./... frontend-build: name: Frontend build (gate) runs-on: ubuntu-latest defaults: run: shell: sh steps: - uses: actions/checkout@v4 - name: Fix node toolcache path for Post-step cleanup run: | mkdir -p /opt/hostedtoolcache/node/22.23.1/x64/bin ln -sf /usr/local/bin/node /opt/hostedtoolcache/node/22.23.1/x64/bin/node - name: Cache npm dependencies uses: actions/cache@v4 with: path: | ~/.npm frontend/node_modules key: ${{ runner.os }}-npm-${{ hashFiles('frontend/package-lock.json') }} restore-keys: | ${{ runner.os }}-npm- - name: Install dependencies run: cd frontend && npm ci - name: Build run: cd frontend && npm run build frontend-qc: name: Frontend ${{ matrix.script }} needs: [frontend-build] runs-on: ubuntu-latest defaults: run: shell: sh strategy: matrix: include: - script: typecheck cmd: npm run check - script: lint cmd: npm run lint - script: audit cmd: npm audit --audit-level=high steps: - uses: actions/checkout@v4 - name: Fix node toolcache path for Post-step cleanup run: | mkdir -p /opt/hostedtoolcache/node/22.23.1/x64/bin ln -sf /usr/local/bin/node /opt/hostedtoolcache/node/22.23.1/x64/bin/node - name: Restore npm dependencies uses: actions/cache@v4 with: path: | ~/.npm frontend/node_modules key: ${{ runner.os }}-npm-${{ hashFiles('frontend/package-lock.json') }} restore-keys: | ${{ runner.os }}-npm- - name: Ensure dependencies run: cd frontend && npm ci - name: ${{ matrix.script }} run: cd frontend && ${{ matrix.cmd }}