fix(db): enable RLS on all 11 public app tables and revoke API-role grants #247
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| branches: [main] | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| permissions: | |
| contents: read | |
| jobs: | |
| unit: | |
| name: lint · type-check · unit tests | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v7 | |
| with: | |
| version: "0.10.4" | |
| enable-cache: true | |
| - name: Set up Python | |
| run: uv python install 3.13 | |
| - name: Sync dependencies | |
| run: uv sync --all-extras --frozen || uv sync --all-extras | |
| - name: Ruff lint | |
| run: uv run ruff check . | |
| - name: Ruff format check | |
| run: uv run ruff format --check . | |
| - name: Type-check (mypy) | |
| run: uv run mypy aeroza | |
| - name: Run unit tests | |
| # Coverage floor for the unit-only suite. Integration tests in the | |
| # next job push the combined number much higher; this gate exists | |
| # to prevent the unit suite from regressing below today's level. | |
| # Ratchet up as unit coverage improves. | |
| run: uv run pytest -m "not integration" --cov=aeroza --cov-report=xml --cov-report=term --cov-fail-under=60 | |
| - name: Upload coverage | |
| if: always() | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: coverage-unit-xml | |
| path: coverage.xml | |
| if-no-files-found: ignore | |
| integration: | |
| name: integration tests (Postgres+PostGIS, eccodes) | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| needs: unit | |
| services: | |
| postgres: | |
| image: postgis/postgis:16-3.5 | |
| env: | |
| POSTGRES_DB: postgres | |
| POSTGRES_USER: aeroza | |
| POSTGRES_PASSWORD: aeroza | |
| ports: | |
| - 5432:5432 | |
| options: >- | |
| --health-cmd "pg_isready -U aeroza -d postgres" | |
| --health-interval 5s | |
| --health-timeout 5s | |
| --health-retries 10 | |
| env: | |
| AEROZA_TEST_DATABASE_URL: postgresql+asyncpg://aeroza:aeroza@localhost:5432/aeroza_test | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v7 | |
| with: | |
| version: "0.10.4" | |
| enable-cache: true | |
| - name: Set up Python | |
| run: uv python install 3.13 | |
| - name: Install eccodes (for cfgrib / @pytest.mark.grib) | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y --no-install-recommends libeccodes-dev | |
| - name: Sync dependencies | |
| # ``--all-extras`` already includes ``[grib]`` (cfgrib installs as | |
| # pure-Python from PyPI; the eccodes system lib is installed above). | |
| # ``--all-extras`` and ``--extra <name>`` are mutually exclusive in uv. | |
| run: uv sync --all-extras --frozen || uv sync --all-extras | |
| - name: Create test database | |
| run: | | |
| PGPASSWORD=aeroza psql -h localhost -U aeroza -d postgres \ | |
| -c "CREATE DATABASE aeroza_test" | |
| - name: Run integration + grib tests | |
| run: | | |
| uv run pytest -m "integration or grib" \ | |
| --cov=aeroza --cov-report=xml --cov-report=term | |
| - name: Upload coverage | |
| if: always() | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: coverage-integration-xml | |
| path: coverage.xml | |
| if-no-files-found: ignore | |
| web-e2e: | |
| name: web · Playwright /map smoke | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| needs: unit | |
| services: | |
| postgres: | |
| image: postgis/postgis:16-3.5 | |
| env: | |
| POSTGRES_DB: aeroza | |
| POSTGRES_USER: aeroza | |
| POSTGRES_PASSWORD: aeroza | |
| ports: | |
| - 5432:5432 | |
| options: >- | |
| --health-cmd "pg_isready -U aeroza -d aeroza" | |
| --health-interval 5s | |
| --health-timeout 5s | |
| --health-retries 10 | |
| # NATS is best-effort at API startup, but `nats.connect` retries for | |
| # ~2 minutes on a refused connection — much longer than our health | |
| # poll. Run a NATS service so the API's lifespan finishes promptly. | |
| nats: | |
| image: nats:2.10 | |
| ports: | |
| - 4222:4222 | |
| env: | |
| DATABASE_URL: postgresql+asyncpg://aeroza:aeroza@localhost:5432/aeroza | |
| AEROZA_NATS_URL: nats://localhost:4222 | |
| NEXT_PUBLIC_AEROZA_API_URL: http://localhost:8000 | |
| AEROZA_WEB_E2E_PORT: "3100" | |
| AEROZA_WEB_E2E_REUSE_SERVER: "1" | |
| AEROZA_WEB_E2E_BASE_URL: http://localhost:3100 | |
| steps: | |
| - uses: actions/checkout@v6 | |
| # ---- Python / API setup ---- | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v7 | |
| with: | |
| version: "0.10.4" | |
| enable-cache: true | |
| - name: Set up Python | |
| run: uv python install 3.13 | |
| - name: Sync dependencies (skip [grib] — Playwright doesn't need eccodes) | |
| run: uv sync --extra db --extra cache --extra stream --extra ingest --extra verify --frozen || uv sync --extra db --extra cache --extra stream --extra ingest --extra verify | |
| - name: Run Alembic migrations on the dev DB | |
| run: uv run alembic upgrade head | |
| - name: Start the API in the background | |
| # `nohup` so the process keeps running after the step exits; | |
| # `& disown` would also work but nohup matches the rest of CI. | |
| run: | | |
| nohup uv run uvicorn aeroza.main:app --host 0.0.0.0 --port 8000 \ | |
| > /tmp/api.log 2>&1 & | |
| echo $! > /tmp/api.pid | |
| # Poll until /health returns 200, with a 60s ceiling. | |
| for _ in $(seq 1 30); do | |
| if curl -sf http://localhost:8000/health -o /dev/null; then | |
| echo "API up" | |
| exit 0 | |
| fi | |
| sleep 2 | |
| done | |
| echo "API did not start in time" | |
| tail -50 /tmp/api.log | |
| exit 1 | |
| # ---- Web setup ---- | |
| - name: Set up Node | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: "20" | |
| - name: Install npm workspaces | |
| run: npm install --no-audit --no-fund | |
| - name: Build the web app | |
| working-directory: web | |
| run: npm run build | |
| - name: Start the web app in the background | |
| working-directory: web | |
| run: | | |
| nohup npm run start -- --port 3100 > /tmp/web.log 2>&1 & | |
| echo $! > /tmp/web.pid | |
| for _ in $(seq 1 30); do | |
| if curl -sf http://localhost:3100/ -o /dev/null; then | |
| echo "Web up" | |
| exit 0 | |
| fi | |
| sleep 2 | |
| done | |
| echo "Web did not start in time" | |
| tail -50 /tmp/web.log | |
| exit 1 | |
| - name: Install Playwright Chromium | |
| working-directory: web | |
| run: npx playwright install --with-deps chromium | |
| - name: Run Playwright smoke tests | |
| working-directory: web | |
| run: npm run test:e2e | |
| - name: Upload Playwright report on failure | |
| if: failure() | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: playwright-report | |
| path: | | |
| web/playwright-report | |
| web/test-results | |
| if-no-files-found: ignore | |
| - name: Stop background services | |
| if: always() | |
| run: | | |
| [ -f /tmp/api.pid ] && kill "$(cat /tmp/api.pid)" || true | |
| [ -f /tmp/web.pid ] && kill "$(cat /tmp/web.pid)" || true |