keyshield 2.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- keyshield-2.0.0/.github/ISSUE_TEMPLATE/bug_report.md +38 -0
- keyshield-2.0.0/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
- keyshield-2.0.0/.github/workflows/develop.yml +107 -0
- keyshield-2.0.0/.github/workflows/release.yml +78 -0
- keyshield-2.0.0/.gitignore +253 -0
- keyshield-2.0.0/.pre-commit-config.yaml +30 -0
- keyshield-2.0.0/.python-version +1 -0
- keyshield-2.0.0/AGENTS.md +145 -0
- keyshield-2.0.0/CHANGELOG.md +320 -0
- keyshield-2.0.0/CODE_OF_CONDUCT.md +32 -0
- keyshield-2.0.0/CONTRIBUTING.md +105 -0
- keyshield-2.0.0/LICENSE +21 -0
- keyshield-2.0.0/Makefile +8 -0
- keyshield-2.0.0/PKG-INFO +460 -0
- keyshield-2.0.0/README.md +395 -0
- keyshield-2.0.0/SECURITY.md +16 -0
- keyshield-2.0.0/docs/index.md +196 -0
- keyshield-2.0.0/docs/mermaid-cache-api-key-system.png +0 -0
- keyshield-2.0.0/docs/quickstart.md +35 -0
- keyshield-2.0.0/docs/schema.mermaid +103 -0
- keyshield-2.0.0/docs/schema.svg +3 -0
- keyshield-2.0.0/docs/usage/cache.md +65 -0
- keyshield-2.0.0/docs/usage/database.md +22 -0
- keyshield-2.0.0/docs/usage/django.md +140 -0
- keyshield-2.0.0/docs/usage/dotenv.md +21 -0
- keyshield-2.0.0/docs/usage/fastapi.md +38 -0
- keyshield-2.0.0/docs/usage/litestar.md +134 -0
- keyshield-2.0.0/docs/usage/quart.md +126 -0
- keyshield-2.0.0/docs/usage/scopes.md +27 -0
- keyshield-2.0.0/docs/usage/typer.md +36 -0
- keyshield-2.0.0/examples/example_cached.py +58 -0
- keyshield-2.0.0/examples/example_cli.py +61 -0
- keyshield-2.0.0/examples/example_fastapi.py +81 -0
- keyshield-2.0.0/examples/example_fastapi_scopes.py +107 -0
- keyshield-2.0.0/examples/example_fastapi_v2.py +87 -0
- keyshield-2.0.0/examples/example_inmemory.py +30 -0
- keyshield-2.0.0/examples/example_inmemory_env.py +39 -0
- keyshield-2.0.0/examples/example_scopes.py +56 -0
- keyshield-2.0.0/examples/example_sql.py +46 -0
- keyshield-2.0.0/mkdocs.yml +80 -0
- keyshield-2.0.0/pyproject.toml +207 -0
- keyshield-2.0.0/ruff.toml +77 -0
- keyshield-2.0.0/src/keyshield/__init__.py +11 -0
- keyshield-2.0.0/src/keyshield/__main__.py +69 -0
- keyshield-2.0.0/src/keyshield/_schemas.py +201 -0
- keyshield-2.0.0/src/keyshield/_types.py +21 -0
- keyshield-2.0.0/src/keyshield/api.py +491 -0
- keyshield-2.0.0/src/keyshield/cli.py +420 -0
- keyshield-2.0.0/src/keyshield/django/__init__.py +13 -0
- keyshield-2.0.0/src/keyshield/django/apps.py +21 -0
- keyshield-2.0.0/src/keyshield/django/decorators.py +85 -0
- keyshield-2.0.0/src/keyshield/django/models.py +66 -0
- keyshield-2.0.0/src/keyshield/django/repository.py +231 -0
- keyshield-2.0.0/src/keyshield/django/urls.py +60 -0
- keyshield-2.0.0/src/keyshield/django/views.py +312 -0
- keyshield-2.0.0/src/keyshield/domain/__init__.py +0 -0
- keyshield-2.0.0/src/keyshield/domain/base.py +120 -0
- keyshield-2.0.0/src/keyshield/domain/entities.py +190 -0
- keyshield-2.0.0/src/keyshield/domain/errors.py +58 -0
- keyshield-2.0.0/src/keyshield/hasher/__init__.py +3 -0
- keyshield-2.0.0/src/keyshield/hasher/argon2.py +47 -0
- keyshield-2.0.0/src/keyshield/hasher/base.py +134 -0
- keyshield-2.0.0/src/keyshield/hasher/bcrypt.py +41 -0
- keyshield-2.0.0/src/keyshield/litestar_api.py +370 -0
- keyshield-2.0.0/src/keyshield/py.typed +0 -0
- keyshield-2.0.0/src/keyshield/quart_api.py +378 -0
- keyshield-2.0.0/src/keyshield/repositories/__init__.py +0 -0
- keyshield-2.0.0/src/keyshield/repositories/base.py +150 -0
- keyshield-2.0.0/src/keyshield/repositories/in_memory.py +142 -0
- keyshield-2.0.0/src/keyshield/repositories/sql.py +330 -0
- keyshield-2.0.0/src/keyshield/services/__init__.py +0 -0
- keyshield-2.0.0/src/keyshield/services/base.py +526 -0
- keyshield-2.0.0/src/keyshield/services/cached.py +133 -0
- keyshield-2.0.0/src/keyshield/utils.py +25 -0
- keyshield-2.0.0/tests/__init__.py +0 -0
- keyshield-2.0.0/tests/conftest.py +100 -0
- keyshield-2.0.0/tests/integration/__init__.py +0 -0
- keyshield-2.0.0/tests/settings_test_django.py +19 -0
- keyshield-2.0.0/tests/test_regression.py +156 -0
- keyshield-2.0.0/tests/unit/__init__.py +0 -0
- keyshield-2.0.0/tests/unit/test_api.py +861 -0
- keyshield-2.0.0/tests/unit/test_cached_service.py +314 -0
- keyshield-2.0.0/tests/unit/test_cli.py +522 -0
- keyshield-2.0.0/tests/unit/test_django_repo.py +355 -0
- keyshield-2.0.0/tests/unit/test_django_views.py +550 -0
- keyshield-2.0.0/tests/unit/test_entity.py +298 -0
- keyshield-2.0.0/tests/unit/test_hasher.py +238 -0
- keyshield-2.0.0/tests/unit/test_litestar_api.py +516 -0
- keyshield-2.0.0/tests/unit/test_quart_api.py +484 -0
- keyshield-2.0.0/tests/unit/test_repo.py +446 -0
- keyshield-2.0.0/tests/unit/test_service.py +570 -0
- keyshield-2.0.0/tests/unit/test_sql_repo.py +504 -0
- keyshield-2.0.0/uv.lock +3285 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Bug report
|
|
3
|
+
about: Create a report to help us improve
|
|
4
|
+
title: ''
|
|
5
|
+
labels: ''
|
|
6
|
+
assignees: ''
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
**Describe the bug**
|
|
11
|
+
A clear and concise description of what the bug is.
|
|
12
|
+
|
|
13
|
+
**To Reproduce**
|
|
14
|
+
Steps to reproduce the behavior:
|
|
15
|
+
1. Go to '...'
|
|
16
|
+
2. Click on '....'
|
|
17
|
+
3. Scroll down to '....'
|
|
18
|
+
4. See error
|
|
19
|
+
|
|
20
|
+
**Expected behavior**
|
|
21
|
+
A clear and concise description of what you expected to happen.
|
|
22
|
+
|
|
23
|
+
**Screenshots**
|
|
24
|
+
If applicable, add screenshots to help explain your problem.
|
|
25
|
+
|
|
26
|
+
**Desktop (please complete the following information):**
|
|
27
|
+
- OS: [e.g. iOS]
|
|
28
|
+
- Browser [e.g. chrome, safari]
|
|
29
|
+
- Version [e.g. 22]
|
|
30
|
+
|
|
31
|
+
**Smartphone (please complete the following information):**
|
|
32
|
+
- Device: [e.g. iPhone6]
|
|
33
|
+
- OS: [e.g. iOS8.1]
|
|
34
|
+
- Browser [e.g. stock browser, safari]
|
|
35
|
+
- Version [e.g. 22]
|
|
36
|
+
|
|
37
|
+
**Additional context**
|
|
38
|
+
Add any other context about the problem here.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Feature request
|
|
3
|
+
about: Suggest an idea for this project
|
|
4
|
+
title: ''
|
|
5
|
+
labels: ''
|
|
6
|
+
assignees: ''
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
**Is your feature request related to a problem? Please describe.**
|
|
11
|
+
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
|
12
|
+
|
|
13
|
+
**Describe the solution you'd like**
|
|
14
|
+
A clear and concise description of what you want to happen.
|
|
15
|
+
|
|
16
|
+
**Describe alternatives you've considered**
|
|
17
|
+
A clear and concise description of any alternative solutions or features you've considered.
|
|
18
|
+
|
|
19
|
+
**Additional context**
|
|
20
|
+
Add any other context or screenshots about the feature request here.
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
name: Development Workflow
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
branches: [ development ]
|
|
6
|
+
push:
|
|
7
|
+
branches: [ development ]
|
|
8
|
+
# Allow this workflow to be called by other workflows
|
|
9
|
+
workflow_call:
|
|
10
|
+
|
|
11
|
+
permissions:
|
|
12
|
+
contents: read
|
|
13
|
+
checks: none
|
|
14
|
+
pull-requests: none
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
lint:
|
|
18
|
+
name: Lint / Format / Type-check
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
|
|
21
|
+
steps:
|
|
22
|
+
- name: Checkout
|
|
23
|
+
uses: actions/checkout@v4
|
|
24
|
+
|
|
25
|
+
- name: Set up UV
|
|
26
|
+
uses: astral-sh/setup-uv@v6
|
|
27
|
+
with:
|
|
28
|
+
python-version: '3.14'
|
|
29
|
+
|
|
30
|
+
- name: Cache UV
|
|
31
|
+
uses: actions/cache@v4
|
|
32
|
+
with:
|
|
33
|
+
path: ~/.cache/uv
|
|
34
|
+
key: ${{ runner.os }}-uv-3.14-${{ hashFiles('uv.lock') }}
|
|
35
|
+
restore-keys: |
|
|
36
|
+
${{ runner.os }}-uv-3.14-
|
|
37
|
+
|
|
38
|
+
- name: Sync dev dependencies
|
|
39
|
+
run: uv sync --locked --all-extras --dev --no-progress -q
|
|
40
|
+
|
|
41
|
+
- name: Lint / Format / Type-check
|
|
42
|
+
run: make lint
|
|
43
|
+
|
|
44
|
+
tests:
|
|
45
|
+
name: Run tests (matrix)
|
|
46
|
+
runs-on: ubuntu-latest
|
|
47
|
+
needs: lint
|
|
48
|
+
strategy:
|
|
49
|
+
matrix:
|
|
50
|
+
python-version: [ '3.9', '3.10', '3.11', '3.12', '3.13', '3.14' ]
|
|
51
|
+
fail-fast: false
|
|
52
|
+
|
|
53
|
+
steps:
|
|
54
|
+
- name: Checkout
|
|
55
|
+
uses: actions/checkout@v4
|
|
56
|
+
|
|
57
|
+
- name: Set up UV
|
|
58
|
+
uses: astral-sh/setup-uv@v6
|
|
59
|
+
with:
|
|
60
|
+
python-version: ${{ matrix.python-version }}
|
|
61
|
+
|
|
62
|
+
- name: Cache UV
|
|
63
|
+
uses: actions/cache@v4
|
|
64
|
+
with:
|
|
65
|
+
path: ~/.cache/uv
|
|
66
|
+
key: ${{ runner.os }}-uv-${{ matrix.python-version }}-${{ hashFiles('uv.lock') }}
|
|
67
|
+
restore-keys: |
|
|
68
|
+
${{ runner.os }}-uv-${{ matrix.python-version }}-
|
|
69
|
+
|
|
70
|
+
- name: Sync dev dependencies
|
|
71
|
+
run: uv sync --locked --all-extras --dev --no-progress -q
|
|
72
|
+
|
|
73
|
+
- name: Run tests
|
|
74
|
+
run: uv run pytest
|
|
75
|
+
|
|
76
|
+
codecov:
|
|
77
|
+
name: Upload saved coverage to Codecov
|
|
78
|
+
runs-on: ubuntu-latest
|
|
79
|
+
needs: tests
|
|
80
|
+
steps:
|
|
81
|
+
# Codecov needs the full history to map commits correctly
|
|
82
|
+
- name: Checkout
|
|
83
|
+
uses: actions/checkout@v4
|
|
84
|
+
|
|
85
|
+
- name: Set up UV
|
|
86
|
+
uses: astral-sh/setup-uv@v6
|
|
87
|
+
with:
|
|
88
|
+
python-version: ${{ matrix.python-version }}
|
|
89
|
+
|
|
90
|
+
- name: Cache UV
|
|
91
|
+
uses: actions/cache@v4
|
|
92
|
+
with:
|
|
93
|
+
path: ~/.cache/uv
|
|
94
|
+
key: ${{ runner.os }}-uv-3.14-${{ hashFiles('uv.lock') }}
|
|
95
|
+
restore-keys: |
|
|
96
|
+
${{ runner.os }}-uv-3.14-
|
|
97
|
+
|
|
98
|
+
- name: Sync dev dependencies
|
|
99
|
+
run: uv sync --locked --all-extras --dev --no-progress -q
|
|
100
|
+
|
|
101
|
+
- name: Run tests
|
|
102
|
+
run: uv run pytest
|
|
103
|
+
|
|
104
|
+
- name: Upload coverage to Codecov
|
|
105
|
+
uses: codecov/codecov-action@v4
|
|
106
|
+
env:
|
|
107
|
+
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
name: CI & Publish (PyPI + Release)
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
branches: [ main ]
|
|
6
|
+
push:
|
|
7
|
+
branches: [ main ]
|
|
8
|
+
tags:
|
|
9
|
+
- '*'
|
|
10
|
+
permissions:
|
|
11
|
+
contents: write # For creating the release
|
|
12
|
+
id-token: write # Required for PyPI Trusted Publisher
|
|
13
|
+
actions: read
|
|
14
|
+
|
|
15
|
+
jobs:
|
|
16
|
+
dev:
|
|
17
|
+
name: Development Checks
|
|
18
|
+
uses: ./.github/workflows/develop.yml
|
|
19
|
+
secrets: inherit
|
|
20
|
+
|
|
21
|
+
publish:
|
|
22
|
+
needs: dev
|
|
23
|
+
name: Publish to PyPI & Create GitHub Release
|
|
24
|
+
runs-on: ubuntu-latest
|
|
25
|
+
|
|
26
|
+
# Runs only if on a version tag (e.g., refs/tags/1.2.3)
|
|
27
|
+
# Runs only when code is pushed to main (not on PRs)
|
|
28
|
+
if: startsWith(github.ref, 'refs/tags/')
|
|
29
|
+
steps:
|
|
30
|
+
- name: Checkout (full history for changelog/tools)
|
|
31
|
+
uses: actions/checkout@v4
|
|
32
|
+
with:
|
|
33
|
+
fetch-depth: 0
|
|
34
|
+
|
|
35
|
+
- name: Set up UV (publish runtime)
|
|
36
|
+
uses: astral-sh/setup-uv@v6
|
|
37
|
+
with:
|
|
38
|
+
python-version: "3.14"
|
|
39
|
+
|
|
40
|
+
- name: Sync dev dependencies
|
|
41
|
+
run: uv sync --locked --all-extras --dev --no-progress -q
|
|
42
|
+
|
|
43
|
+
- name: Build sdist & wheel with uv
|
|
44
|
+
run: uv build
|
|
45
|
+
|
|
46
|
+
# Publication via OIDC (Trusted Publisher) – no secret required on GitHub side
|
|
47
|
+
- name: Publish to PyPI
|
|
48
|
+
run: uv publish --verbose
|
|
49
|
+
|
|
50
|
+
# GitHub Release with auto notes + attached artifacts (sdist/wheel)
|
|
51
|
+
- name: Create GitHub Release
|
|
52
|
+
uses: softprops/action-gh-release@v2
|
|
53
|
+
with:
|
|
54
|
+
tag_name: ${{ github.ref_name }}
|
|
55
|
+
name: ${{ github.ref_name }}
|
|
56
|
+
generate_release_notes: true
|
|
57
|
+
files: |
|
|
58
|
+
dist/*.whl
|
|
59
|
+
dist/*.tar.gz
|
|
60
|
+
|
|
61
|
+
docs:
|
|
62
|
+
name: Deploy MkDocs
|
|
63
|
+
runs-on: ubuntu-latest
|
|
64
|
+
needs: publish
|
|
65
|
+
steps:
|
|
66
|
+
- name: Checkout
|
|
67
|
+
uses: actions/checkout@v4
|
|
68
|
+
|
|
69
|
+
- name: Set up UV
|
|
70
|
+
uses: astral-sh/setup-uv@v6
|
|
71
|
+
with:
|
|
72
|
+
python-version: '3.14'
|
|
73
|
+
|
|
74
|
+
- name: Install dependencies
|
|
75
|
+
run: uv sync --locked --all-extras --dev --no-progress -q
|
|
76
|
+
|
|
77
|
+
- name: Deploy MkDocs
|
|
78
|
+
run: uv run mkdocs gh-deploy --force
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
### PyCharm+all template
|
|
2
|
+
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
|
|
3
|
+
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
|
4
|
+
|
|
5
|
+
# User-specific stuff
|
|
6
|
+
.idea/**/workspace.xml
|
|
7
|
+
.idea/**/tasks.xml
|
|
8
|
+
.idea/**/usage.statistics.xml
|
|
9
|
+
.idea/**/dictionaries
|
|
10
|
+
.idea/**/shelf
|
|
11
|
+
|
|
12
|
+
# AWS User-specific
|
|
13
|
+
.idea/**/aws.xml
|
|
14
|
+
|
|
15
|
+
# Generated files
|
|
16
|
+
.idea/**/contentModel.xml
|
|
17
|
+
|
|
18
|
+
# Sensitive or high-churn files
|
|
19
|
+
.idea/**/dataSources/
|
|
20
|
+
.idea/**/dataSources.ids
|
|
21
|
+
.idea/**/dataSources.local.xml
|
|
22
|
+
.idea/**/sqlDataSources.xml
|
|
23
|
+
.idea/**/dynamic.xml
|
|
24
|
+
.idea/**/uiDesigner.xml
|
|
25
|
+
.idea/**/dbnavigator.xml
|
|
26
|
+
|
|
27
|
+
# Gradle
|
|
28
|
+
.idea/**/gradle.xml
|
|
29
|
+
.idea/**/libraries
|
|
30
|
+
|
|
31
|
+
# Gradle and Maven with auto-import
|
|
32
|
+
# When using Gradle or Maven with auto-import, you should exclude module files,
|
|
33
|
+
# since they will be recreated, and may cause churn. Uncomment if using
|
|
34
|
+
# auto-import.
|
|
35
|
+
# .idea/artifacts
|
|
36
|
+
# .idea/compiler.xml
|
|
37
|
+
# .idea/jarRepositories.xml
|
|
38
|
+
# .idea/modules.xml
|
|
39
|
+
# .idea/*.iml
|
|
40
|
+
# .idea/modules
|
|
41
|
+
# *.iml
|
|
42
|
+
# *.ipr
|
|
43
|
+
|
|
44
|
+
# CMake
|
|
45
|
+
cmake-build-*/
|
|
46
|
+
|
|
47
|
+
# Mongo Explorer plugin
|
|
48
|
+
.idea/**/mongoSettings.xml
|
|
49
|
+
|
|
50
|
+
# File-based project format
|
|
51
|
+
*.iws
|
|
52
|
+
|
|
53
|
+
# IntelliJ
|
|
54
|
+
out/
|
|
55
|
+
|
|
56
|
+
# mpeltonen/sbt-idea plugin
|
|
57
|
+
.idea_modules/
|
|
58
|
+
|
|
59
|
+
# JIRA plugin
|
|
60
|
+
atlassian-ide-plugin.xml
|
|
61
|
+
|
|
62
|
+
# Cursive Clojure plugin
|
|
63
|
+
.idea/replstate.xml
|
|
64
|
+
|
|
65
|
+
# SonarLint plugin
|
|
66
|
+
.idea/sonarlint/
|
|
67
|
+
|
|
68
|
+
# Crashlytics plugin (for Android Studio and IntelliJ)
|
|
69
|
+
com_crashlytics_export_strings.xml
|
|
70
|
+
crashlytics.properties
|
|
71
|
+
crashlytics-build.properties
|
|
72
|
+
fabric.properties
|
|
73
|
+
|
|
74
|
+
# Editor-based Rest Client
|
|
75
|
+
.idea/httpRequests
|
|
76
|
+
|
|
77
|
+
# Android studio 3.1+ serialized cache file
|
|
78
|
+
.idea/caches/build_file_checksums.ser
|
|
79
|
+
|
|
80
|
+
### Python template
|
|
81
|
+
# Byte-compiled / optimized / DLL files
|
|
82
|
+
__pycache__/
|
|
83
|
+
*.py[cod]
|
|
84
|
+
*$py.class
|
|
85
|
+
|
|
86
|
+
# C extensions
|
|
87
|
+
*.so
|
|
88
|
+
|
|
89
|
+
# Distribution / packaging
|
|
90
|
+
.Python
|
|
91
|
+
build/
|
|
92
|
+
develop-eggs/
|
|
93
|
+
dist/
|
|
94
|
+
downloads/
|
|
95
|
+
eggs/
|
|
96
|
+
.eggs/
|
|
97
|
+
lib/
|
|
98
|
+
lib64/
|
|
99
|
+
parts/
|
|
100
|
+
sdist/
|
|
101
|
+
var/
|
|
102
|
+
wheels/
|
|
103
|
+
share/python-wheels/
|
|
104
|
+
*.egg-info/
|
|
105
|
+
.installed.cfg
|
|
106
|
+
*.egg
|
|
107
|
+
MANIFEST
|
|
108
|
+
|
|
109
|
+
# PyInstaller
|
|
110
|
+
# Usually these files are written by a python script from a template
|
|
111
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
112
|
+
*.manifest
|
|
113
|
+
*.spec
|
|
114
|
+
|
|
115
|
+
# Installer logs
|
|
116
|
+
pip-log.txt
|
|
117
|
+
pip-delete-this-directory.txt
|
|
118
|
+
|
|
119
|
+
# Unit test / coverage reports
|
|
120
|
+
htmlcov/
|
|
121
|
+
.tox/
|
|
122
|
+
.nox/
|
|
123
|
+
.coverage
|
|
124
|
+
.coverage.*
|
|
125
|
+
.cache
|
|
126
|
+
nosetests.xml
|
|
127
|
+
coverage.xml
|
|
128
|
+
junit.xml
|
|
129
|
+
*.cover
|
|
130
|
+
*.py,cover
|
|
131
|
+
.hypothesis/
|
|
132
|
+
.pytest_cache/
|
|
133
|
+
cover/
|
|
134
|
+
|
|
135
|
+
# Translations
|
|
136
|
+
*.mo
|
|
137
|
+
*.pot
|
|
138
|
+
|
|
139
|
+
# Django stuff:
|
|
140
|
+
*.log
|
|
141
|
+
local_settings.py
|
|
142
|
+
db.sqlite3
|
|
143
|
+
db.sqlite3-journal
|
|
144
|
+
|
|
145
|
+
# Flask stuff:
|
|
146
|
+
instance/
|
|
147
|
+
.webassets-cache
|
|
148
|
+
|
|
149
|
+
# Scrapy stuff:
|
|
150
|
+
.scrapy
|
|
151
|
+
|
|
152
|
+
# Sphinx documentation
|
|
153
|
+
docs/_build/
|
|
154
|
+
|
|
155
|
+
# PyBuilder
|
|
156
|
+
.pybuilder/
|
|
157
|
+
target/
|
|
158
|
+
|
|
159
|
+
# Jupyter Notebook
|
|
160
|
+
.ipynb_checkpoints
|
|
161
|
+
|
|
162
|
+
# IPython
|
|
163
|
+
profile_default/
|
|
164
|
+
ipython_config.py
|
|
165
|
+
|
|
166
|
+
# pyenv
|
|
167
|
+
# For a library or package, you might want to ignore these files since the code is
|
|
168
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
169
|
+
# .python-version
|
|
170
|
+
|
|
171
|
+
# pipenv
|
|
172
|
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
173
|
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
174
|
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
175
|
+
# install all needed dependencies.
|
|
176
|
+
#Pipfile.lock
|
|
177
|
+
|
|
178
|
+
# poetry
|
|
179
|
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
|
180
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
181
|
+
# commonly ignored for libraries.
|
|
182
|
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
|
183
|
+
#poetry.lock
|
|
184
|
+
|
|
185
|
+
# pdm
|
|
186
|
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
|
187
|
+
#pdm.lock
|
|
188
|
+
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
|
189
|
+
# in version control.
|
|
190
|
+
# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
|
|
191
|
+
.pdm.toml
|
|
192
|
+
.pdm-python
|
|
193
|
+
.pdm-build/
|
|
194
|
+
|
|
195
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
196
|
+
__pypackages__/
|
|
197
|
+
|
|
198
|
+
# Celery stuff
|
|
199
|
+
celerybeat-schedule
|
|
200
|
+
celerybeat.pid
|
|
201
|
+
|
|
202
|
+
# SageMath parsed files
|
|
203
|
+
*.sage.py
|
|
204
|
+
|
|
205
|
+
# Environments
|
|
206
|
+
.env
|
|
207
|
+
.venv
|
|
208
|
+
env/
|
|
209
|
+
venv/
|
|
210
|
+
ENV/
|
|
211
|
+
env.bak/
|
|
212
|
+
venv.bak/
|
|
213
|
+
|
|
214
|
+
# Spyder project settings
|
|
215
|
+
.spyderproject
|
|
216
|
+
.spyproject
|
|
217
|
+
|
|
218
|
+
# Rope project settings
|
|
219
|
+
.ropeproject
|
|
220
|
+
|
|
221
|
+
# mkdocs documentation
|
|
222
|
+
/site
|
|
223
|
+
|
|
224
|
+
# mypy
|
|
225
|
+
.mypy_cache/
|
|
226
|
+
.dmypy.json
|
|
227
|
+
dmypy.json
|
|
228
|
+
|
|
229
|
+
# Pyre type checker
|
|
230
|
+
.pyre/
|
|
231
|
+
|
|
232
|
+
# pytype static type analyzer
|
|
233
|
+
.pytype/
|
|
234
|
+
|
|
235
|
+
# Cython debug symbols
|
|
236
|
+
cython_debug/
|
|
237
|
+
|
|
238
|
+
# PyCharm
|
|
239
|
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
240
|
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
241
|
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
242
|
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
243
|
+
.idea/
|
|
244
|
+
|
|
245
|
+
# Examples generated database files
|
|
246
|
+
examples/*.sqlite3
|
|
247
|
+
|
|
248
|
+
# Keep personal TODO list file
|
|
249
|
+
TODO.md
|
|
250
|
+
todo.md
|
|
251
|
+
|
|
252
|
+
# Keep AI assistant conversation history
|
|
253
|
+
CLAUDE.md
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
repos:
|
|
2
|
+
- repo: https://github.com/commitizen-tools/commitizen
|
|
3
|
+
rev: v4.8.3
|
|
4
|
+
hooks:
|
|
5
|
+
# Check the commit message when committing
|
|
6
|
+
- id: commitizen
|
|
7
|
+
stages: [commit-msg]
|
|
8
|
+
|
|
9
|
+
# Check all commits before pushing (optional but recommended)
|
|
10
|
+
- id: commitizen-branch
|
|
11
|
+
stages: [pre-push]
|
|
12
|
+
|
|
13
|
+
# Local hooks for linting and testing
|
|
14
|
+
- repo: local
|
|
15
|
+
hooks:
|
|
16
|
+
# Lint
|
|
17
|
+
- id: uv-lint
|
|
18
|
+
name: "Run linters and formatters"
|
|
19
|
+
entry: uv run lint
|
|
20
|
+
language: system # we leave the binary as is
|
|
21
|
+
pass_filenames: false # « uv run lint » don't need filenames
|
|
22
|
+
stages: [pre-commit]
|
|
23
|
+
|
|
24
|
+
# Tests
|
|
25
|
+
- id: uv-test
|
|
26
|
+
name: "Run tests"
|
|
27
|
+
entry: uv run test
|
|
28
|
+
language: system
|
|
29
|
+
pass_filenames: false
|
|
30
|
+
stages: [pre-commit]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.14
|
|
@@ -0,0 +1,145 @@
|
|
|
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: `keyshield` (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 `keyshield.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/keyshield/` 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.
|