halsabbah's picture
deploy: sync code from GitHub main
9baab59 verified
name: Backend CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
lint:
name: Lint & Format Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/setup-python@v6
with:
python-version: "3.12"
- name: Install ruff
run: pip install ruff
- name: Ruff lint
run: ruff check .
- name: Ruff format check
run: ruff format --check .
type-check:
name: Import & Syntax Validation
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/setup-python@v6
with:
python-version: "3.12"
cache: pip
- name: Install dependencies
run: pip install -r requirements.txt
- name: Validate Python syntax (compile all)
run: python -m compileall app/ main.py -q
- name: Verify imports resolve
run: python -c "from app.core.config import get_settings; from app.models.db import Base; print('All imports OK')"
tests:
name: Pytest
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/setup-python@v6
with:
python-version: "3.12"
cache: pip
- name: Install dependencies
run: |
pip install -r requirements.txt
pip install -r requirements-dev.txt
- name: Run pytest with coverage
env:
DATABASE_URL: "sqlite:///:memory:"
JWT_SECRET: "${{ github.run_id }}-${{ github.run_attempt }}-ci-ephemeral"
ENVIRONMENT: test
LLM_API_KEY: test-key
CORS_ORIGINS: '["http://testserver"]'
run: pytest tests/ --cov=app --cov-report=xml --cov-report=term
- name: Upload coverage artifact
uses: actions/upload-artifact@v4
if: always()
with:
name: backend-coverage
path: coverage.xml
retention-days: 14
migration-check:
name: Database Migration Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/setup-python@v6
with:
python-version: "3.12"
cache: pip
- name: Install dependencies
run: pip install -r requirements.txt
- name: Verify Alembic config
run: python -c "from alembic.config import Config; c = Config('alembic.ini'); print('Alembic config OK')"
dependency-audit:
name: Dependency Vulnerability Scan
runs-on: ubuntu-latest
# Don't block PR merging on upstream CVE noise; surface findings
# without failing. `fail_on_vuln` can be flipped to true once we've
# triaged the existing vulnerability backlog.
continue-on-error: true
steps:
- uses: actions/checkout@v5
- uses: actions/setup-python@v6
with:
python-version: "3.12"
cache: pip
- name: Install pip-audit
run: pip install pip-audit
- name: Audit backend requirements
# --desc: show a one-line description of each CVE
# --no-strict: twikit is installed from a Codeberg VCS URL (phin fork
# that fixes the KEY_BYTE indices bug in upstream 2.3.3). VCS
# dependencies are not registered on PyPI and cannot be audited by
# pip-audit. --no-strict (the default without --strict) treats
# unauditable packages as warnings rather than hard failures, so
# the scan still covers all 40+ PyPI-sourced dependencies.
# --ignore-vuln: deliberately ignored CVEs with justification:
# CVE-2026-1839 (transformers) — affects Trainer._load_rng_state,
# only reachable when loading malicious rng_state.pth checkpoints
# during training. We do inference-only, never Trainer, never
# deserialize external .pth files. Fix is in 5.0.0rc3 (pre-release);
# re-evaluate when 5.0.0 ships stable.
# CVE-2025-2953 (torch) — local DoS in torch.mkldnn_max_pool2d.
# Attack requires local access; no remote exploit path. Fix is in
# 2.7.1rc1 (pre-release); re-evaluate when stable 2.7.x ships.
# CVE-2025-3730 (torch) — local DoS in torch.nn.functional.ctc_loss.
# Attack requires local access; no remote exploit path. Fix is in
# 2.8.0; re-evaluate when 2.8.0 ships stable.
run: |
pip-audit --requirement requirements.txt --desc \
--ignore-vuln CVE-2026-1839 \
--ignore-vuln CVE-2025-2953 \
--ignore-vuln CVE-2025-3730
docker-build:
name: Docker Build
runs-on: ubuntu-latest
needs: [lint, type-check, tests]
services:
postgres:
image: pgvector/pgvector:pg16
env:
POSTGRES_PASSWORD: postgres
POSTGRES_DB: depscreen
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v5
- name: Build Docker image
run: docker build -t depscreen-backend .
- name: Verify container starts
run: |
docker run -d --name test-container \
--network host \
-e DATABASE_URL=postgresql://postgres:postgres@localhost:5432/depscreen \
-e LLM_API_KEY=test \
-e LLM_BASE_URL=https://test.example.com \
-e LLM_MODEL=test \
-e JWT_SECRET=test-secret \
-e ENVIRONMENT=testing \
-p 8000:8000 \
depscreen-backend
echo "Waiting for container to start..."
for i in $(seq 1 60); do
if curl -sf http://localhost:8000/health/live > /dev/null 2>&1; then
echo "Health check passed after ${i}s"
break
fi
sleep 2
done
curl -f http://localhost:8000/health/live || (docker logs test-container && exit 1)
docker stop test-container