Sets up the project skeleton: - FastAPI app factory with lifespan, request-id middleware, and RFC 9457 problem+json error handlers - Async SQLAlchemy 2.0 over MySQL (asyncmy), with a constraint naming convention in place before the first migration and async Alembic - Keycloak as a pure resource server: OIDC discovery, cached JWKS with rotation-aware refresh, and require_roles dependencies - Devcontainer running MySQL 8.4 and Keycloak 26.7 as compose siblings, with the realm (clients, roles, test users) imported on first boot - Test suite covering the endpoints plus the token validator itself, exercised against a locally generated RSA keypair - uv packaging, ruff, mypy --strict, pre-commit, Gitea CI, prod Dockerfile Two Keycloak-in-containers traps are handled explicitly and documented in the README: the issuer/internal-URL split (the browser sees localhost:8080, the API sees keycloak:8080) and the audience mapper that stops Keycloak issuing tokens with aud=account. The devices resource is a placeholder proving the routing -> auth -> ORM -> migration path end to end; replace it with the real domain. Co-Authored-By: Claude Opus 5 <[email protected]>
55 lines
1.3 KiB
YAML
55 lines
1.3 KiB
YAML
name: CI
|
|
|
|
on:
|
|
push:
|
|
branches: [main]
|
|
pull_request:
|
|
|
|
jobs:
|
|
check:
|
|
runs-on: ubuntu-latest
|
|
|
|
services:
|
|
mysql:
|
|
image: mysql:8.4
|
|
env:
|
|
MYSQL_ROOT_PASSWORD: rootpassword
|
|
MYSQL_DATABASE: v2x_test
|
|
MYSQL_USER: v2x
|
|
MYSQL_PASSWORD: v2xpassword
|
|
ports:
|
|
- 3306:3306
|
|
options: >-
|
|
--health-cmd="mysqladmin ping -h 127.0.0.1 -uroot -prootpassword"
|
|
--health-interval=5s
|
|
--health-timeout=5s
|
|
--health-retries=20
|
|
|
|
env:
|
|
# CI reaches MySQL over the mapped port; Keycloak is never contacted
|
|
# because the auth tests mint their own tokens against a stub JWKS.
|
|
DATABASE_URL: mysql+asyncmy://v2x:[email protected]:3306/v2x_test?charset=utf8mb4
|
|
TEST_DATABASE_URL: mysql+asyncmy://v2x:[email protected]:3306/v2x_test?charset=utf8mb4
|
|
APP_ENV: test
|
|
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- uses: astral-sh/setup-uv@v5
|
|
with:
|
|
version: "0.9.7"
|
|
enable-cache: true
|
|
|
|
- run: uv sync --frozen
|
|
|
|
- name: Lint
|
|
run: |
|
|
uv run ruff check .
|
|
uv run ruff format --check .
|
|
|
|
- name: Type check
|
|
run: uv run mypy
|
|
|
|
- name: Test
|
|
run: uv run pytest --cov --cov-report=term-missing
|