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

66 lines
2.9 KiB
Markdown

# 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
```bash
# 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/`.