Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
171 changes: 143 additions & 28 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -434,8 +434,7 @@ jobs:
- uses: actions/checkout@v4

- name: Build API container image
run: |
docker build -t predictiq-api:${{ github.sha }} -f services/api/Dockerfile .
run: docker build -t predictiq-api:${{ github.sha }} -f services/api/Dockerfile .
continue-on-error: true

- name: Scan API container with Trivy
Expand All @@ -444,15 +443,37 @@ jobs:
with:
image-ref: "predictiq-api:${{ github.sha }}"
format: "sarif"
output: "trivy-container.sarif"
output: "trivy-api.sarif"
severity: "CRITICAL,HIGH"
exit-code: "1"

- name: Upload container scan SARIF
- name: Upload API container scan SARIF
uses: github/codeql-action/upload-sarif@v4
if: always()
with:
sarif_file: trivy-container.sarif
sarif_file: trivy-api.sarif
category: trivy-api

- name: Build TTS container image
run: docker build -t predictiq-tts:${{ github.sha }} -f services/tts/Dockerfile services/tts/
continue-on-error: true

- name: Scan TTS container with Trivy
uses: aquasecurity/trivy-action@314ff8b43182423b84c50b1670b0e10f858f2d98 # master
if: success()
with:
image-ref: "predictiq-tts:${{ github.sha }}"
format: "sarif"
output: "trivy-tts.sarif"
severity: "CRITICAL,HIGH"
exit-code: "1"

- name: Upload TTS container scan SARIF
uses: github/codeql-action/upload-sarif@v4
if: always()
with:
sarif_file: trivy-tts.sarif
category: trivy-tts

codeql-analysis:
name: CodeQL Analysis
Expand Down Expand Up @@ -725,13 +746,24 @@ jobs:
node services/api/scripts/parse-bench-output.js \
bench-output.txt bench-results.json

- name: Fetch baseline from benchmarks branch
if: github.event_name == 'pull_request'
run: |
git fetch origin benchmarks:refs/remotes/origin/benchmarks 2>/dev/null || true
if git show origin/benchmarks:api-benchmark-baseline.json > baseline-from-branch.json 2>/dev/null; then
echo "BASELINE_FILE=baseline-from-branch.json" >> "$GITHUB_ENV"
else
echo "BASELINE_FILE=services/api/benches/.benchmarks/baseline.json" >> "$GITHUB_ENV"
echo "No dedicated branch baseline found, falling back to repo baseline."
fi

- name: Compare against baseline
if: github.event_name == 'pull_request'
run: |
node services/api/scripts/compare-api-benchmarks.js \
bench-results.json \
services/api/benches/.benchmarks/baseline.json \
--threshold 10
"$BASELINE_FILE" \
--threshold 20

- name: Upload benchmark results
if: always()
Expand All @@ -748,8 +780,12 @@ jobs:
runs-on: ubuntu-latest
needs: [api-criterion-benchmarks]
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
permissions:
contents: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Install Rust
uses: dtolnay/rust-toolchain@stable
Expand All @@ -772,31 +808,30 @@ jobs:
with:
node-version: "18"

- name: Parse and save new baseline
- name: Parse benchmark results
run: |
node services/api/scripts/parse-bench-output.js \
bench-output.txt \
services/api/benches/.benchmarks/baseline.json
api-benchmark-baseline.json

- name: Create Pull Request with baseline updates
uses: peter-evans/create-pull-request@v6
with:
commit-message: "chore: update API benchmark baseline for main branch"
title: "chore: update API benchmark baseline"
body: |
## Automated API Benchmark Baseline Update

This PR updates the API benchmark baseline after changes to main branch.

**Changes:**
- Updated `services/api/benches/.benchmarks/baseline.json` with latest benchmark results

**Note:** This is an automated PR. Please review the baseline changes before merging.
branch: chore/api-baseline-${{ github.run_id }}
delete-branch: true
labels: |
ci/cd
automated
- name: Push baseline to benchmarks branch
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"

# Switch to (or create) the dedicated benchmarks branch.
git fetch origin benchmarks 2>/dev/null || true
if git show-ref --verify --quiet refs/remotes/origin/benchmarks; then
git checkout -B benchmarks origin/benchmarks
else
git checkout --orphan benchmarks
git rm -rf . --quiet
fi

cp api-benchmark-baseline.json .
git add api-benchmark-baseline.json
git commit --allow-empty -m "chore: update API benchmark baseline (run ${{ github.run_id }})"
git push origin benchmarks

# ── #743: frontend unit-test coverage gate ───────────────────────────────────
frontend-unit-coverage:
Expand Down Expand Up @@ -831,6 +866,85 @@ jobs:
path: frontend/coverage/
retention-days: 14

# ── #742: schema drift detection ─────────────────────────────────────────────
schema-drift-check:
name: Schema Drift Detection
runs-on: ubuntu-latest
services:
postgres:
image: postgres:16
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: predictiq_schema_check
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
env:
PGUSER: postgres
PGPASSWORD: postgres
PGHOST: localhost
PGDATABASE: predictiq_schema_check
steps:
- uses: actions/checkout@v4

- name: Apply all migrations
run: |
for f in $(ls services/api/database/migrations/*.sql | sort); do
echo "▶ $f"
psql -f "$f" || { echo "❌ Migration failed: $f"; exit 1; }
done

- name: Dump live schema
run: |
pg_dump \
--schema-only \
--no-owner \
--no-privileges \
--no-comments \
--schema=public \
> /tmp/live-schema.sql

- name: Normalise both dumps for comparison
run: |
# Strip pg_dump header lines (SET …, SELECT …) that are not structural.
normalize() {
grep -vE '^(SET |SELECT |--|$)' "$1" \
| sed 's/ *$//; s/\t/ /g' \
| sort
}
normalize /tmp/live-schema.sql > /tmp/live-normalized.sql
normalize services/api/database/schema.sql > /tmp/snap-normalized.sql

- name: Compare against committed snapshot
run: |
if ! diff -u /tmp/snap-normalized.sql /tmp/live-normalized.sql; then
echo ""
echo "❌ Schema drift detected!"
echo " The live schema (after running all migrations) differs from"
echo " services/api/database/schema.sql."
echo ""
echo " To update the snapshot:"
echo " pg_dump --schema-only --no-owner --no-privileges --no-comments \\"
echo " --schema=public <db> > services/api/database/schema.sql"
echo " git add services/api/database/schema.sql"
echo " git commit -m 'chore: update schema snapshot'"
exit 1
fi
echo "✅ Schema matches snapshot — no drift detected."

- name: Upload live schema dump
if: always()
uses: actions/upload-artifact@v4
with:
name: live-schema-dump
path: /tmp/live-schema.sql
retention-days: 7

all-tests-passed:
name: All Tests Passed
needs:
Expand All @@ -855,6 +969,7 @@ jobs:
- validate-migration-rollbacks
- api-criterion-benchmarks
- frontend-unit-coverage
- schema-drift-check
runs-on: ubuntu-latest
steps:
- name: Success
Expand Down
Loading