From 2d613b13176554b5b54f7c98249dc9b7623403a0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 13 Jul 2025 23:49:31 +0000 Subject: [PATCH 1/4] Initial plan From c00f3e12e4cba5415a1993362cebe91f8414e02e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 13 Jul 2025 23:53:14 +0000 Subject: [PATCH 2/4] Add copilot-instructions.md with comprehensive project context Co-authored-by: lucasrcezimbra <7042915+lucasrcezimbra@users.noreply.github.com> --- copilot-instructions.md | 116 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 copilot-instructions.md diff --git a/copilot-instructions.md b/copilot-instructions.md new file mode 100644 index 0000000..6c8bbb1 --- /dev/null +++ b/copilot-instructions.md @@ -0,0 +1,116 @@ +# GitHub Copilot Instructions for ninja-api-key + +## Project Overview + +This is a Django package that provides API Key authentication for [Django Ninja](https://django-ninja.dev/). It's a fork of django-ninja-apikey with enhanced security features and better Django integration. + +## Key Components + +### Core Models +- `APIKey` model: Stores API keys with prefix, hashed key, user association, labels, expiration, and revocation status +- Uses Django's password hashing system for secure key storage +- Keys have format: `{prefix}.{key}` (8-char prefix + 56-char key) + +### Authentication +- `APIKeyAuth` class extends Django Ninja's `APIKeyHeader` +- Uses `X-API-Key` header for authentication +- Integrates with Django's user system and permissions + +### Security Features +- API keys are hashed using Django's `PASSWORD_HASHERS` setting +- Keys can be expired, revoked, or associated with inactive users +- Includes custom SHA256 hasher for performance when needed + +## Code Patterns + +### Django Integration +- Follow Django's model patterns and conventions +- Use `get_user_model()` for user model references +- Leverage Django's admin interface for key management +- Use Django's timezone utilities for datetime handling + +### Testing +- Use pytest with pytest-django for testing +- Test files are in `ninja_apikey/tests/` +- Use parametrized tests for multiple scenarios +- Mock Django settings with `@override_settings` decorator +- Test security, models, admin, and hashers separately + +### Code Style +- Use Black for code formatting (line length: 88) +- Use Ruff for linting (select: E, F, I; ignore: E501) +- Use isort with black profile for import sorting +- Follow pre-commit hooks configuration for consistency + +## Development Patterns + +### Dependencies +- Core: Django, django-ninja +- Testing: pytest, pytest-django, pytest-cov +- Optional: django[argon2,bcrypt] for enhanced password hashing + +### Key Generation +- Use `get_random_string()` for secure random generation +- Always hash keys before storage using `make_password()` +- Return structured `KeyData` namedtuple for generated keys + +### Authentication Flow +1. Extract API key from `X-API-Key` header +2. Split into prefix and key components +3. Look up APIKey record by prefix +4. Verify key against hashed value using `check_password()` +5. Validate key is not revoked and not expired +6. Ensure associated user is active +7. Set `request.user` and return user object + +## Common Use Cases + +### Basic API Protection +```python +from ninja import NinjaAPI +from ninja_apikey.security import APIKeyAuth + +api = NinjaAPI(auth=APIKeyAuth()) + +@api.get("/protected") +def protected_endpoint(request): + return f"Hello, {request.user}!" +``` + +### Endpoint-Specific Protection +```python +from ninja_apikey.security import APIKeyAuth + +auth = APIKeyAuth() + +@api.get("/specific", auth=auth) +def specific_endpoint(request): + return {"user": request.user.username} +``` + +### Performance Optimization +```python +# In settings.py for faster hashing +PASSWORD_HASHERS = [ + "ninja_apikey.hashers.SHA256PasswordHasher", + # ... other hashers +] +``` + +## Testing Guidelines + +- Test security edge cases (invalid keys, expired keys, revoked keys) +- Test Django admin integration and form handling +- Test password hasher compatibility and migration +- Use fixtures for creating test users and API keys +- Mock external dependencies and Django settings when needed + +## File Structure +- `models.py`: APIKey model definition +- `security.py`: Authentication classes and key utilities +- `admin.py`: Django admin integration +- `hashers.py`: Custom password hashers +- `tests/`: Comprehensive test suite +- `migrations/`: Database migrations + +When working with this codebase, prioritize security, follow Django conventions, and ensure compatibility with the Django Ninja framework. \ No newline at end of file From 52396b19066c01606836ac7694540869e92f1cf3 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 14 Jul 2025 00:50:20 +0000 Subject: [PATCH 3/4] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- copilot-instructions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/copilot-instructions.md b/copilot-instructions.md index 6c8bbb1..97ff39a 100644 --- a/copilot-instructions.md +++ b/copilot-instructions.md @@ -113,4 +113,4 @@ PASSWORD_HASHERS = [ - `tests/`: Comprehensive test suite - `migrations/`: Database migrations -When working with this codebase, prioritize security, follow Django conventions, and ensure compatibility with the Django Ninja framework. \ No newline at end of file +When working with this codebase, prioritize security, follow Django conventions, and ensure compatibility with the Django Ninja framework. From e1db3d886bb08fe7a1df6992565b9edc5ecfb9c5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 14 Jul 2025 03:15:02 +0000 Subject: [PATCH 4/4] Move copilot-instructions.md to .github/ directory Co-authored-by: lucasrcezimbra <7042915+lucasrcezimbra@users.noreply.github.com> --- copilot-instructions.md => .github/copilot-instructions.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename copilot-instructions.md => .github/copilot-instructions.md (100%) diff --git a/copilot-instructions.md b/.github/copilot-instructions.md similarity index 100% rename from copilot-instructions.md rename to .github/copilot-instructions.md