|
| 1 | +# AGENTS.md |
| 2 | + |
| 3 | +This file guides automated coding agents working in this repository. |
| 4 | +Follow existing patterns and run the same tooling as humans. |
| 5 | + |
| 6 | +## Project overview |
| 7 | + |
| 8 | +- Language: Python 3.9+ |
| 9 | +- Package: `fastapi_api_key` (src layout) |
| 10 | +- Async-first services and repositories |
| 11 | +- Optional extras for FastAPI, SQLAlchemy, Argon2, bcrypt, aiocache |
| 12 | + |
| 13 | +## Tooling and environment |
| 14 | + |
| 15 | +- Dependency manager: `uv` |
| 16 | +- Build backend: `hatchling` |
| 17 | +- Format/lint: Ruff |
| 18 | +- Type checks: Ty and Pyrefly |
| 19 | +- Security lint: Bandit |
| 20 | +- Tests: pytest + pytest-cov + pytest-asyncio |
| 21 | + |
| 22 | +## Build, lint, and test commands |
| 23 | + |
| 24 | +### Install (dev) |
| 25 | + |
| 26 | +- `uv sync --extra all --group dev` |
| 27 | +- `source .venv/bin/activate` (or Windows `.venv\Scripts\Activate.ps1`) |
| 28 | + |
| 29 | +### Lint and format |
| 30 | + |
| 31 | +- `make lint` |
| 32 | + - Runs: `ruff format`, `ruff check --fix`, `ty check`, `pyrefly check`, `bandit` |
| 33 | +- Direct commands: |
| 34 | + - `uv run ruff format .` |
| 35 | + - `uv run ruff check --fix .` |
| 36 | + - `uv run ty check .` |
| 37 | + - `uv run pyrefly check .` |
| 38 | + - `uv run bandit -c pyproject.toml -r src examples -q` |
| 39 | + |
| 40 | +### Tests |
| 41 | + |
| 42 | +- Full test suite: `uv run pytest` |
| 43 | +- Single test file: `uv run pytest tests/unit/test_service.py` |
| 44 | +- Single test by node id: |
| 45 | + - `uv run pytest tests/unit/test_service.py::test_create_api_key` |
| 46 | +- Single test by keyword: |
| 47 | + - `uv run pytest -k "create_api_key"` |
| 48 | +- Run a test class: `uv run pytest tests/unit/test_service.py::TestApiKeyService` |
| 49 | + |
| 50 | +### Coverage output |
| 51 | + |
| 52 | +Pytest defaults include coverage reports (XML/HTML/terminal) via `pyproject.toml`. |
| 53 | +Artifacts: `coverage.xml`, `htmlcov/`, `junit.xml`. |
| 54 | + |
| 55 | +## Code style and conventions |
| 56 | + |
| 57 | +### Formatting |
| 58 | + |
| 59 | +- Ruff handles formatting; follow it instead of manual styling. |
| 60 | +- Line length: 120 characters. |
| 61 | +- Indentation: 4 spaces. |
| 62 | +- Quotes: double quotes. |
| 63 | + |
| 64 | +### Imports |
| 65 | + |
| 66 | +- Standard library imports first, then third-party, then local. |
| 67 | +- Prefer explicit imports over wildcard. |
| 68 | +- Keep module-level imports; avoid local imports unless required to break cycles. |
| 69 | +- In optional dependency modules, guard imports with `try/except ModuleNotFoundError`. |
| 70 | + |
| 71 | +### Typing |
| 72 | + |
| 73 | +- Use Python 3.9+ type hints everywhere. |
| 74 | +- Prefer `Optional[T]` and `list[T]`/`dict[K, V]` style. |
| 75 | +- Return concrete types (`ApiKey`, `list[ApiKey]`, etc.) not `Any`. |
| 76 | +- Use `Annotated` for FastAPI params when needed. |
| 77 | + |
| 78 | +### Naming |
| 79 | + |
| 80 | +- Classes: `CamelCase` (e.g., `ApiKeyService`). |
| 81 | +- Functions/vars: `snake_case`. |
| 82 | +- Constants: `UPPER_SNAKE_CASE`. |
| 83 | +- Private helpers: prefix `_` (e.g., `_verify_entity`). |
| 84 | +- API key fields follow existing names (`key_id`, `key_secret`, `key_hash`). |
| 85 | + |
| 86 | +### Dataclasses and models |
| 87 | + |
| 88 | +- Use `@dataclass` for small data carriers (e.g., parsed key results). |
| 89 | +- Use Pydantic models for API request/response schemas. |
| 90 | + |
| 91 | +### Error handling |
| 92 | + |
| 93 | +- Domain exceptions live in `fastapi_api_key.domain.errors`. |
| 94 | +- Raise domain errors in services and repositories, translate to HTTP exceptions in API layer. |
| 95 | +- Preserve original errors with `raise ... from exc`. |
| 96 | +- Use specific exceptions (`KeyNotFound`, `InvalidKey`, `ConfigurationError`) rather than `ValueError` unless appropriate. |
| 97 | +- Validate inputs early; prefer guard clauses. |
| 98 | + |
| 99 | +### Async and I/O |
| 100 | + |
| 101 | +- Services and repositories are async; keep APIs async throughout. |
| 102 | +- Use `await` for repo calls and when composing service logic. |
| 103 | +- Avoid blocking I/O in async paths. |
| 104 | + |
| 105 | +### Security-sensitive behavior |
| 106 | + |
| 107 | +- Never log or return plaintext API keys after creation. |
| 108 | +- Enforce API key parsing/validation via `ParsedApiKey` and `_get_parts` patterns. |
| 109 | +- Use timing jitter on auth failures (`verify_key` behavior). |
| 110 | +- Treat secret pepper as external configuration; do not hardcode. |
| 111 | + |
| 112 | +### API layer |
| 113 | + |
| 114 | +- Use FastAPI dependency injection with `Depends`. |
| 115 | +- Map domain errors to `HTTPException` with correct status codes. |
| 116 | +- API responses use Pydantic models; keep output schemas stable. |
| 117 | + |
| 118 | +### Tests |
| 119 | + |
| 120 | +- Tests live in `tests/` with unit and integration subpackages. |
| 121 | +- Prefer clear arrange/act/assert structure. |
| 122 | +- Use fixtures from `tests/conftest.py` where available. |
| 123 | + |
| 124 | +## Repository layout |
| 125 | + |
| 126 | +- `src/fastapi_api_key/` core library |
| 127 | +- `tests/` unit/integration tests |
| 128 | +- `examples/` example applications (used in docs) |
| 129 | + |
| 130 | +## Repo-specific notes |
| 131 | + |
| 132 | +- `make lint` is the canonical lint entrypoint. |
| 133 | +- The project warns when the default pepper is used; tests expect that behavior. |
| 134 | +- Examples are used in docs; keep them runnable. |
| 135 | + |
| 136 | +## Cursor and Copilot rules |
| 137 | + |
| 138 | +- No `.cursor/rules/`, `.cursorrules`, or `.github/copilot-instructions.md` found in this repo. |
| 139 | + |
| 140 | +## When editing |
| 141 | + |
| 142 | +- Preserve public API behavior and exception types. |
| 143 | +- Keep docstrings consistent with existing style. |
| 144 | +- Match current error messages when possible (tests may assert them). |
| 145 | +- Avoid introducing extra dependencies without updating optional extras. |
0 commit comments