Files
demo-oidc/AGENTS.md
T
2026-07-08 14:11:18 +02:00

2.9 KiB

AGENTS.md

Compact operational guide for OpenCode sessions. See CLAUDE.md for the prose overview; this file captures what an agent would otherwise get wrong.

Commands

# First-time test env (creates venv/, installs requirements.txt + requirements-test.txt)
./setup_test_env.sh

# Full suite with coverage (activates venv, erases old coverage, builds htmlcov/)
./run_tests.sh

# Manual, from an active venv
python -m pytest tests/ --cov=. --cov-config=.coveragerc -v

# Single test
python -m pytest tests/test_main.py::test_health_check -v

# Dev server (must run from repo root — see Gotchas)
uvicorn main:app --host 0.0.0.0 --port 8000 --reload

There is no lint, typecheck, formatter, or CI config in this repo. Do not claim to run ruff, mypy, flake8, or black — none are installed or configured. The only verification step is the pytest suite above.

Gotchas

  • Run from repo root. read_root() and favicon() open templates/index.html / templates/favicon.ico via relative paths (main.py:329, main.py:371). Invoking uvicorn from another cwd 404s the frontend.
  • @lru_cache on OIDC helpers. get_well_known_config, get_jwks, get_userinfo_endpoint, get_token_endpoint are all lru_cache(maxsize=1) (main.py:68-129). When a test patches requests with a different response, call func.cache_clear() first or you get the previous mock's cached value. Existing tests do this; new tests must too.
  • Python 3.14, not 3.7. .python-version and the Dockerfile (python:3.14-alpine) target 3.14. The README's "3.7+" claim is stale.
  • .envrc is gitignored and ships real credentials. It exports a live CLIENT_ID / CLIENT_SECRET for direnv. Never commit it, never paste its values into code or commits.
  • CLIENT_ID has no default. main.py:28 reads it from env with no fallback; the app and several tests need it set. OIDC_ISSUER defaults to https://login.infomaniak.com; CLIENT_SECRET defaults to "" (breaks /refresh-token with "Client secret not configured").

Architecture essentials

  • Single-file backend main.py (FastAPI) + single-file frontend templates/index.html. No package layout, no pyproject.toml, no setup.cfg.
  • AUTHORIZED_USERS (main.py:33) is a hardcoded {email: secret_phrase} dict — the "protected resource". Not a database.
  • Token validation: verify_token(id_token, expected_nonce=None) does JWKS signature verification + audience/issuer checks. The expected_nonce param binds the id_token to the login flow (anti-replay); /validate-token forwards the nonce from the request body (main.py:278). Tests in test_token_validation.py and test_main.py cover the nonce paths — keep them green when touching auth.
  • Tests use fastapi.testclient.TestClient (sync, backed by httpx) and unittest.mock.patch against main.*. Fixtures live in tests/conftest.py.
  • Coverage config (.coveragerc) omits venv/, tests/, .venv/.