fauth 0.4.0__tar.gz → 0.4.2__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.
- {fauth-0.4.0 → fauth-0.4.2}/.github/workflows/cicd.yml +1 -1
- fauth-0.4.2/.github/workflows/semgrep.yml +29 -0
- fauth-0.4.2/.github/workflows/snyk.yml +35 -0
- {fauth-0.4.0 → fauth-0.4.2}/.pre-commit-config.yaml +12 -1
- {fauth-0.4.0 → fauth-0.4.2}/CHANGELOG.md +68 -0
- {fauth-0.4.0 → fauth-0.4.2}/PKG-INFO +1 -1
- {fauth-0.4.0 → fauth-0.4.2}/fauth/providers/provider.py +11 -5
- {fauth-0.4.0 → fauth-0.4.2}/pyproject.toml +1 -1
- fauth-0.4.2/pytest.ini +4 -0
- {fauth-0.4.0 → fauth-0.4.2}/tests/providers/conftest.py +63 -1
- {fauth-0.4.0 → fauth-0.4.2}/tests/providers/test_provider.py +52 -1
- {fauth-0.4.0 → fauth-0.4.2}/uv.lock +1 -1
- fauth-0.4.0/.github/workflows/pre-commit-autoupdate.yml +0 -45
- fauth-0.4.0/pytest.ini +0 -2
- {fauth-0.4.0 → fauth-0.4.2}/.github/actions/setup-python-env/action.yml +0 -0
- {fauth-0.4.0 → fauth-0.4.2}/.github/dependabot.yml +0 -0
- {fauth-0.4.0 → fauth-0.4.2}/.gitignore +0 -0
- {fauth-0.4.0 → fauth-0.4.2}/LICENSE +0 -0
- {fauth-0.4.0 → fauth-0.4.2}/README.md +0 -0
- {fauth-0.4.0 → fauth-0.4.2}/fauth/__init__.py +0 -0
- {fauth-0.4.0 → fauth-0.4.2}/fauth/api/__init__.py +0 -0
- {fauth-0.4.0 → fauth-0.4.2}/fauth/api/router.py +0 -0
- {fauth-0.4.0 → fauth-0.4.2}/fauth/core/__init__.py +0 -0
- {fauth-0.4.0 → fauth-0.4.2}/fauth/core/config.py +0 -0
- {fauth-0.4.0 → fauth-0.4.2}/fauth/core/exceptions.py +0 -0
- {fauth-0.4.0 → fauth-0.4.2}/fauth/core/schemas.py +0 -0
- {fauth-0.4.0 → fauth-0.4.2}/fauth/crypto/__init__.py +0 -0
- {fauth-0.4.0 → fauth-0.4.2}/fauth/crypto/jwt.py +0 -0
- {fauth-0.4.0 → fauth-0.4.2}/fauth/crypto/password.py +0 -0
- {fauth-0.4.0 → fauth-0.4.2}/fauth/middleware/__init__.py +0 -0
- {fauth-0.4.0 → fauth-0.4.2}/fauth/middleware/auth.py +0 -0
- {fauth-0.4.0 → fauth-0.4.2}/fauth/providers/__init__.py +0 -0
- {fauth-0.4.0 → fauth-0.4.2}/fauth/providers/protocols.py +0 -0
- {fauth-0.4.0 → fauth-0.4.2}/fauth/py.typed +0 -0
- {fauth-0.4.0 → fauth-0.4.2}/fauth/testing/__init__.py +0 -0
- {fauth-0.4.0 → fauth-0.4.2}/fauth/testing/config.py +0 -0
- {fauth-0.4.0 → fauth-0.4.2}/fauth/testing/fakes.py +0 -0
- {fauth-0.4.0 → fauth-0.4.2}/fauth/testing/provider.py +0 -0
- {fauth-0.4.0 → fauth-0.4.2}/fauth/transports/__init__.py +0 -0
- {fauth-0.4.0 → fauth-0.4.2}/fauth/transports/base.py +0 -0
- {fauth-0.4.0 → fauth-0.4.2}/fauth/transports/bearer.py +0 -0
- {fauth-0.4.0 → fauth-0.4.2}/fauth/utils/__init__.py +0 -0
- {fauth-0.4.0 → fauth-0.4.2}/fauth/utils/logging.py +0 -0
- {fauth-0.4.0 → fauth-0.4.2}/tests/__init__.py +0 -0
- {fauth-0.4.0 → fauth-0.4.2}/tests/api/__init__.py +0 -0
- {fauth-0.4.0 → fauth-0.4.2}/tests/api/conftest.py +0 -0
- {fauth-0.4.0 → fauth-0.4.2}/tests/api/test_openapi.py +0 -0
- {fauth-0.4.0 → fauth-0.4.2}/tests/api/test_router.py +0 -0
- {fauth-0.4.0 → fauth-0.4.2}/tests/conftest.py +0 -0
- {fauth-0.4.0 → fauth-0.4.2}/tests/core/__init__.py +0 -0
- {fauth-0.4.0 → fauth-0.4.2}/tests/core/conftest.py +0 -0
- {fauth-0.4.0 → fauth-0.4.2}/tests/core/test_config.py +0 -0
- {fauth-0.4.0 → fauth-0.4.2}/tests/core/test_exceptions.py +0 -0
- {fauth-0.4.0 → fauth-0.4.2}/tests/crypto/__init__.py +0 -0
- {fauth-0.4.0 → fauth-0.4.2}/tests/crypto/conftest.py +0 -0
- {fauth-0.4.0 → fauth-0.4.2}/tests/crypto/test_jwt.py +0 -0
- {fauth-0.4.0 → fauth-0.4.2}/tests/crypto/test_password.py +0 -0
- {fauth-0.4.0 → fauth-0.4.2}/tests/middleware/__init__.py +0 -0
- {fauth-0.4.0 → fauth-0.4.2}/tests/middleware/conftest.py +0 -0
- {fauth-0.4.0 → fauth-0.4.2}/tests/middleware/test_auth_middleware.py +0 -0
- {fauth-0.4.0 → fauth-0.4.2}/tests/providers/__init__.py +0 -0
- {fauth-0.4.0 → fauth-0.4.2}/tests/testing/__init__.py +0 -0
- {fauth-0.4.0 → fauth-0.4.2}/tests/testing/test_testing.py +0 -0
- {fauth-0.4.0 → fauth-0.4.2}/tests/utils/conftest.py +0 -0
- {fauth-0.4.0 → fauth-0.4.2}/tests/utils/test_logging.py +0 -0
|
@@ -80,7 +80,7 @@ jobs:
|
|
|
80
80
|
git config --local user.name "github-actions[bot]"
|
|
81
81
|
git add .pre-commit-config.yaml
|
|
82
82
|
git diff --staged --quiet || git commit -m "chore(config): update pre-commit hooks"
|
|
83
|
-
git push origin HEAD:${
|
|
83
|
+
git push origin "HEAD:${GITHUB_HEAD_REF:-$GITHUB_REF_NAME}"
|
|
84
84
|
|
|
85
85
|
versioning:
|
|
86
86
|
name: Versioning
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
name: Semgrep
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
push:
|
|
6
|
+
branches: ["main"]
|
|
7
|
+
pull_request:
|
|
8
|
+
branches: ["main"]
|
|
9
|
+
schedule:
|
|
10
|
+
- cron: "0 0 * * 0" # 00:00 every Sunday
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
semgrep_scan:
|
|
14
|
+
name: Semgrep Analysis
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
container:
|
|
17
|
+
image: returntocorp/semgrep
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@v6
|
|
20
|
+
with:
|
|
21
|
+
token: ${{ secrets.GH_TOKEN || secrets.GITHUB_TOKEN }}
|
|
22
|
+
fetch-depth: 0
|
|
23
|
+
|
|
24
|
+
- name: Run Semgrep
|
|
25
|
+
run: |
|
|
26
|
+
semgrep \
|
|
27
|
+
--config auto \
|
|
28
|
+
--error \
|
|
29
|
+
--metrics=auto
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
name: Snyk Security with uv
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: ["main"]
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
schedule:
|
|
8
|
+
- cron: "0 0 * * 0" # 00:00 every Sunday
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
snyk_scan:
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
strategy:
|
|
14
|
+
matrix:
|
|
15
|
+
python-version: ["3.12", "3.13", "3.14"]
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v6
|
|
18
|
+
with:
|
|
19
|
+
token: ${{ secrets.GH_TOKEN || secrets.GITHUB_TOKEN }}
|
|
20
|
+
fetch-depth: 0
|
|
21
|
+
|
|
22
|
+
- name: Setup environment
|
|
23
|
+
uses: ./.github/actions/setup-python-env
|
|
24
|
+
with:
|
|
25
|
+
python-version: ${{ matrix.python-version }}
|
|
26
|
+
|
|
27
|
+
- name: Export dependencies
|
|
28
|
+
run: uv export --format requirements-txt --output-file requirements.txt
|
|
29
|
+
|
|
30
|
+
- name: Run Snyk Open Source
|
|
31
|
+
uses: snyk/actions/python@master
|
|
32
|
+
env:
|
|
33
|
+
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
|
|
34
|
+
with:
|
|
35
|
+
command: test
|
|
@@ -10,6 +10,10 @@ repos:
|
|
|
10
10
|
- id: trailing-whitespace
|
|
11
11
|
- id: end-of-file-fixer
|
|
12
12
|
- id: detect-private-key
|
|
13
|
+
- id: check-yaml
|
|
14
|
+
- id: pretty-format-json
|
|
15
|
+
args: ['--autofix']
|
|
16
|
+
- id: check-merge-conflict
|
|
13
17
|
|
|
14
18
|
- repo: https://github.com/gitleaks/gitleaks
|
|
15
19
|
rev: v8.30.0
|
|
@@ -17,11 +21,12 @@ repos:
|
|
|
17
21
|
- id: gitleaks
|
|
18
22
|
|
|
19
23
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
20
|
-
rev: 'v0.15.
|
|
24
|
+
rev: 'v0.15.11'
|
|
21
25
|
hooks:
|
|
22
26
|
- id: ruff-check
|
|
23
27
|
name: ruff
|
|
24
28
|
args: ['--fix']
|
|
29
|
+
- id: ruff-format
|
|
25
30
|
|
|
26
31
|
- repo: https://github.com/PyCQA/bandit
|
|
27
32
|
rev: 1.9.4
|
|
@@ -56,3 +61,9 @@ repos:
|
|
|
56
61
|
- fastapi==0.135.1
|
|
57
62
|
- pyjwt==2.11.0
|
|
58
63
|
- pwdlib==0.3.0
|
|
64
|
+
|
|
65
|
+
- repo: https://github.com/hadolint/hadolint
|
|
66
|
+
rev: v2.14.0
|
|
67
|
+
hooks:
|
|
68
|
+
- id: hadolint
|
|
69
|
+
args: ['--ignore', 'DL3008,DL3015,DL3002']
|
|
@@ -1,6 +1,74 @@
|
|
|
1
1
|
# CHANGELOG
|
|
2
2
|
|
|
3
3
|
|
|
4
|
+
## v0.4.2 (2026-04-18)
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
- Update require_roles to support singular role fields and enum types with regression tests
|
|
9
|
+
([#39](https://github.com/justmatias/fauth/pull/39),
|
|
10
|
+
[`0d2c646`](https://github.com/justmatias/fauth/commit/0d2c646729fcfffe9e10b047e117636b97530620))
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
## v0.4.1 (2026-04-18)
|
|
14
|
+
|
|
15
|
+
### Bug Fixes
|
|
16
|
+
|
|
17
|
+
- **ci**: Prevent shell injection in GitHub Actions workflow
|
|
18
|
+
([#37](https://github.com/justmatias/fauth/pull/37),
|
|
19
|
+
[`11835f1`](https://github.com/justmatias/fauth/commit/11835f16cedd3f064c9ffe2df26f02a53f9b81f9))
|
|
20
|
+
|
|
21
|
+
Fix potential shell injection vulnerability in CI/CD workflow by avoiding GitHub expression
|
|
22
|
+
interpolation.
|
|
23
|
+
|
|
24
|
+
## Changes - Removed `env:` block that used `${{ github.head_ref || github.ref_name }}`
|
|
25
|
+
interpolation - Changed git push command to use GitHub's built-in environment variables
|
|
26
|
+
(`GITHUB_HEAD_REF` and `GITHUB_REF_NAME`) directly in the shell - Properly quoted the variable to
|
|
27
|
+
prevent word splitting
|
|
28
|
+
|
|
29
|
+
## Why Using `${{ }}` expression interpolation with `github.head_ref` in a workflow step can be
|
|
30
|
+
exploited by attackers who create pull requests with maliciously crafted branch names. By using
|
|
31
|
+
the shell environment variables `GITHUB_HEAD_REF` and `GITHUB_REF_NAME` (which GitHub Actions
|
|
32
|
+
automatically provides), we avoid the expression interpolation while maintaining the same
|
|
33
|
+
functionality. The shell handles these variables safely when properly quoted.
|
|
34
|
+
|
|
35
|
+
## Semgrep Finding Details Using variable interpolation `${{...}}` with `github` context data in a
|
|
36
|
+
`run:` step could allow an attacker to inject their own code into the runner. This would allow
|
|
37
|
+
them to steal secrets and code. `github` context data can have arbitrary user input and should be
|
|
38
|
+
treated as untrusted. Instead, use an intermediate environment variable with `env:` to store the
|
|
39
|
+
data and use the environment variable in the `run:` script. Be sure to use double-quotes the
|
|
40
|
+
environment variable, like this: "$ENVVAR".
|
|
41
|
+
|
|
42
|
+
Semgrep Assistant generated this pull request to fix [a
|
|
43
|
+
finding](https://semgrep.dev/orgs/justmatias/findings/756619268) from the detection rule
|
|
44
|
+
[yaml.github-actions.security.run-shell-injection.run-shell-injection](https://semgrep.dev/r/yaml.github-actions.security.run-shell-injection.run-shell-injection).
|
|
45
|
+
|
|
46
|
+
Co-authored-by: Semgrep Autofix <autofix@semgrep.com>
|
|
47
|
+
|
|
48
|
+
### Chores
|
|
49
|
+
|
|
50
|
+
- Add Snyk and Semgrep security scanning workflows
|
|
51
|
+
([#35](https://github.com/justmatias/fauth/pull/35),
|
|
52
|
+
[`768b38b`](https://github.com/justmatias/fauth/commit/768b38b2880b9a52cb8a7d8d3a5c6200dc456db9))
|
|
53
|
+
|
|
54
|
+
* ci: add Snyk and Semgrep security scanning workflows
|
|
55
|
+
|
|
56
|
+
* chore(config): update pre-commit hooks
|
|
57
|
+
|
|
58
|
+
* chore: update autotrigger
|
|
59
|
+
|
|
60
|
+
* chore: change semgrep metrics option from off to auto
|
|
61
|
+
|
|
62
|
+
* ci: fix shell injection vulnerability in cicd workflow
|
|
63
|
+
|
|
64
|
+
---------
|
|
65
|
+
|
|
66
|
+
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
|
|
67
|
+
|
|
68
|
+
- Remove pre-commit autoupdate workflow ([#36](https://github.com/justmatias/fauth/pull/36),
|
|
69
|
+
[`7022909`](https://github.com/justmatias/fauth/commit/7022909b390658add76bb9bf767b0fdf9fcf4657))
|
|
70
|
+
|
|
71
|
+
|
|
4
72
|
## v0.4.0 (2026-04-15)
|
|
5
73
|
|
|
6
74
|
### Chores
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fauth
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.2
|
|
4
4
|
Summary: Ergonomic, lightweight JWT authentication for FastAPI. Secure your routes instantly with plug-and-play dependency injection
|
|
5
5
|
Project-URL: Homepage, https://github.com/justmatias/fauth
|
|
6
6
|
Project-URL: Repository, https://github.com/justmatias/fauth
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import enum
|
|
1
2
|
from collections.abc import Callable
|
|
2
3
|
from typing import Annotated, Any, Generic, TypeVar
|
|
3
4
|
|
|
@@ -111,16 +112,21 @@ class AuthProvider(Generic[T]):
|
|
|
111
112
|
)
|
|
112
113
|
return user
|
|
113
114
|
|
|
114
|
-
def require_roles(self,
|
|
115
|
+
def require_roles(self, required_roles: list[str | enum.Enum]) -> Callable:
|
|
115
116
|
"""Dependency demanding the current user has all specified roles."""
|
|
116
117
|
|
|
117
118
|
async def role_checker(
|
|
118
119
|
user: Annotated[T, Depends(self.require_active_user)],
|
|
119
120
|
) -> T:
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
121
|
+
roles = list(getattr(user, "roles", []))
|
|
122
|
+
role = getattr(user, "role", None)
|
|
123
|
+
|
|
124
|
+
if role is not None:
|
|
125
|
+
roles.append(role)
|
|
126
|
+
|
|
127
|
+
required_roles_set = set(required_roles)
|
|
128
|
+
for role in required_roles_set:
|
|
129
|
+
if role not in roles:
|
|
124
130
|
await logger.error(
|
|
125
131
|
"Authorization failed",
|
|
126
132
|
reason="Missing role",
|
fauth-0.4.2/pytest.ini
ADDED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import enum
|
|
1
2
|
import time
|
|
2
3
|
from typing import Any
|
|
3
4
|
from uuid import UUID, uuid4
|
|
@@ -13,6 +14,11 @@ from fauth.providers import AuthProvider
|
|
|
13
14
|
from fauth.testing import FakeIdentityLoader, FakeUserLoader
|
|
14
15
|
|
|
15
16
|
|
|
17
|
+
class Role(enum.Enum):
|
|
18
|
+
ADMIN = "admin"
|
|
19
|
+
USER = "user"
|
|
20
|
+
|
|
21
|
+
|
|
16
22
|
class DummyUser(BaseModel):
|
|
17
23
|
id_: UUID = Field(default_factory=uuid4)
|
|
18
24
|
hashed_password: str = Field(default=hash_password("secret_password"))
|
|
@@ -21,6 +27,25 @@ class DummyUser(BaseModel):
|
|
|
21
27
|
permissions: list[str] = Field(default_factory=list)
|
|
22
28
|
|
|
23
29
|
|
|
30
|
+
class StringRoleUser(BaseModel):
|
|
31
|
+
id_: UUID = Field(default_factory=uuid4)
|
|
32
|
+
is_active: bool = Field(default=True)
|
|
33
|
+
role: str = "admin"
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class EnumRoleUser(BaseModel):
|
|
37
|
+
id_: UUID = Field(default_factory=uuid4)
|
|
38
|
+
is_active: bool = Field(default=True)
|
|
39
|
+
role: Role = Role.ADMIN
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class CombinedRolesUser(BaseModel):
|
|
43
|
+
id_: UUID = Field(default_factory=uuid4)
|
|
44
|
+
is_active: bool = Field(default=True)
|
|
45
|
+
roles: list[str] = Field(default_factory=lambda: ["user"])
|
|
46
|
+
role: str = "admin"
|
|
47
|
+
|
|
48
|
+
|
|
24
49
|
@pytest.fixture
|
|
25
50
|
def user() -> DummyUser:
|
|
26
51
|
return DummyUser(roles=["admin"], permissions=["read", "write"])
|
|
@@ -31,6 +56,21 @@ def inactive_user() -> DummyUser:
|
|
|
31
56
|
return DummyUser(is_active=False)
|
|
32
57
|
|
|
33
58
|
|
|
59
|
+
@pytest.fixture
|
|
60
|
+
def string_role_user() -> StringRoleUser:
|
|
61
|
+
return StringRoleUser()
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
@pytest.fixture
|
|
65
|
+
def enum_role_user() -> EnumRoleUser:
|
|
66
|
+
return EnumRoleUser()
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
@pytest.fixture
|
|
70
|
+
def combined_roles_user() -> CombinedRolesUser:
|
|
71
|
+
return CombinedRolesUser()
|
|
72
|
+
|
|
73
|
+
|
|
34
74
|
@pytest.fixture
|
|
35
75
|
def user_loader() -> FakeUserLoader[DummyUser]:
|
|
36
76
|
return FakeUserLoader()
|
|
@@ -132,9 +172,12 @@ def expired_refresh_token(auth_config: AuthConfig) -> str:
|
|
|
132
172
|
|
|
133
173
|
|
|
134
174
|
@pytest.fixture
|
|
135
|
-
def inactive_user_refresh_token(
|
|
175
|
+
def inactive_user_refresh_token(
|
|
176
|
+
auth_config: AuthConfig, inactive_user: DummyUser
|
|
177
|
+
) -> str:
|
|
136
178
|
return create_refresh_token(sub=str(inactive_user.id_), config=auth_config)
|
|
137
179
|
|
|
180
|
+
|
|
138
181
|
@pytest.fixture
|
|
139
182
|
def _populate_user(user_loader: FakeUserLoader[DummyUser], user: DummyUser) -> None:
|
|
140
183
|
user_loader.add_user(str(user.id_), user)
|
|
@@ -195,6 +238,25 @@ def _populate_identity_inactive_user(
|
|
|
195
238
|
identity_loader.add_user("alice", inactive_user)
|
|
196
239
|
|
|
197
240
|
|
|
241
|
+
@pytest.fixture
|
|
242
|
+
def user_with_singular_role() -> DummyUser:
|
|
243
|
+
return DummyUser(roles=["admin"])
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
@pytest.fixture
|
|
247
|
+
def _populate_user_with_singular_role(
|
|
248
|
+
user_loader: FakeUserLoader[DummyUser], user_with_singular_role: DummyUser
|
|
249
|
+
) -> None:
|
|
250
|
+
user_loader.add_user(str(user_with_singular_role.id_), user_with_singular_role)
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
@pytest.fixture
|
|
254
|
+
def user_with_singular_role_token(
|
|
255
|
+
auth_config: AuthConfig, user_with_singular_role: DummyUser
|
|
256
|
+
) -> str:
|
|
257
|
+
return create_access_token(sub=str(user_with_singular_role.id_), config=auth_config)
|
|
258
|
+
|
|
259
|
+
|
|
198
260
|
@pytest.fixture
|
|
199
261
|
def password() -> str:
|
|
200
262
|
return "secret_password"
|
|
@@ -8,7 +8,14 @@ from fauth.crypto import hash_password
|
|
|
8
8
|
from fauth.providers import AuthProvider
|
|
9
9
|
from fauth.testing import FakeIdentityLoader
|
|
10
10
|
|
|
11
|
-
from .conftest import
|
|
11
|
+
from .conftest import (
|
|
12
|
+
CombinedRolesUser,
|
|
13
|
+
DummyUser,
|
|
14
|
+
EnumRoleUser,
|
|
15
|
+
FakeUserLoader,
|
|
16
|
+
Role,
|
|
17
|
+
StringRoleUser,
|
|
18
|
+
)
|
|
12
19
|
|
|
13
20
|
|
|
14
21
|
def test_require_user_expired_token(client: TestClient, expired_token: str) -> None:
|
|
@@ -59,6 +66,50 @@ def test_require_roles_granted(client: TestClient, user_token: str) -> None:
|
|
|
59
66
|
assert response.status_code == 200
|
|
60
67
|
|
|
61
68
|
|
|
69
|
+
@pytest.mark.usefixtures("_populate_user_with_singular_role")
|
|
70
|
+
@pytest.mark.regression
|
|
71
|
+
def test_require_roles_with_singular_role_fallback(
|
|
72
|
+
client: TestClient, user_with_singular_role_token: str
|
|
73
|
+
) -> None:
|
|
74
|
+
response = client.get(
|
|
75
|
+
"/admin", headers={"Authorization": f"Bearer {user_with_singular_role_token}"}
|
|
76
|
+
)
|
|
77
|
+
assert response.status_code == 200
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
@pytest.mark.asyncio
|
|
81
|
+
@pytest.mark.regression
|
|
82
|
+
async def test_require_roles_with_string_role_fallback(
|
|
83
|
+
provider: AuthProvider[DummyUser],
|
|
84
|
+
string_role_user: StringRoleUser,
|
|
85
|
+
) -> None:
|
|
86
|
+
role_checker = provider.require_roles(["admin"])
|
|
87
|
+
result = await role_checker(string_role_user)
|
|
88
|
+
assert result.id_ == string_role_user.id_
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
@pytest.mark.asyncio
|
|
92
|
+
@pytest.mark.regression
|
|
93
|
+
async def test_require_roles_combined_roles_and_role(
|
|
94
|
+
provider: AuthProvider[DummyUser],
|
|
95
|
+
combined_roles_user: CombinedRolesUser,
|
|
96
|
+
) -> None:
|
|
97
|
+
role_checker = provider.require_roles(["admin"])
|
|
98
|
+
result = await role_checker(combined_roles_user)
|
|
99
|
+
assert result.id_ == combined_roles_user.id_
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
@pytest.mark.asyncio
|
|
103
|
+
@pytest.mark.regression
|
|
104
|
+
async def test_require_roles_with_enum_role_fallback(
|
|
105
|
+
provider: AuthProvider[DummyUser],
|
|
106
|
+
enum_role_user: EnumRoleUser,
|
|
107
|
+
) -> None:
|
|
108
|
+
role_checker = provider.require_roles([Role.ADMIN])
|
|
109
|
+
result = await role_checker(enum_role_user)
|
|
110
|
+
assert result.id_ == enum_role_user.id_
|
|
111
|
+
|
|
112
|
+
|
|
62
113
|
@pytest.mark.usefixtures("_populate_no_roles_user")
|
|
63
114
|
def test_require_roles_denied(client: TestClient, no_roles_user_token: str) -> None:
|
|
64
115
|
response = client.get(
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
# The workflow checks out the repository, installs pre-commit, and runs the autoupdate command.
|
|
2
|
-
# If there are any updates, it creates a pull request with the changes.
|
|
3
|
-
|
|
4
|
-
name: Pre-commit Update
|
|
5
|
-
|
|
6
|
-
on:
|
|
7
|
-
schedule:
|
|
8
|
-
- cron: '0 2 * * 1' # Mondays at 2 AM UTC
|
|
9
|
-
workflow_dispatch:
|
|
10
|
-
|
|
11
|
-
permissions:
|
|
12
|
-
contents: read
|
|
13
|
-
|
|
14
|
-
jobs:
|
|
15
|
-
auto-update:
|
|
16
|
-
permissions:
|
|
17
|
-
contents: write
|
|
18
|
-
pull-requests: write
|
|
19
|
-
|
|
20
|
-
runs-on: ubuntu-latest
|
|
21
|
-
steps:
|
|
22
|
-
- uses: actions/checkout@v6
|
|
23
|
-
with:
|
|
24
|
-
token: ${{ secrets.GH_TOKEN }}
|
|
25
|
-
fetch-depth: 0
|
|
26
|
-
|
|
27
|
-
- name: Setup environment
|
|
28
|
-
uses: ./.github/actions/setup-python-env
|
|
29
|
-
with:
|
|
30
|
-
python-version: '3.13'
|
|
31
|
-
|
|
32
|
-
- name: Autoupdate pre-commit hooks
|
|
33
|
-
run: uv run pre-commit autoupdate
|
|
34
|
-
|
|
35
|
-
- name: Create Pull Request
|
|
36
|
-
uses: peter-evans/create-pull-request@v8
|
|
37
|
-
with:
|
|
38
|
-
token: ${{ secrets.GH_TOKEN }}
|
|
39
|
-
branch: chore/pre-commit-autoupdate
|
|
40
|
-
title: Update pre-commit hooks
|
|
41
|
-
commit-message: 'chore(config): update pre-commit hooks'
|
|
42
|
-
body: |
|
|
43
|
-
This PR was created automatically by the pre-commit autoupdate workflow.
|
|
44
|
-
It updates the pre-commit hooks to their latest versions.
|
|
45
|
-
labels: update-hooks
|
fauth-0.4.0/pytest.ini
DELETED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|