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.
Files changed (65) hide show
  1. {fauth-0.4.0 → fauth-0.4.2}/.github/workflows/cicd.yml +1 -1
  2. fauth-0.4.2/.github/workflows/semgrep.yml +29 -0
  3. fauth-0.4.2/.github/workflows/snyk.yml +35 -0
  4. {fauth-0.4.0 → fauth-0.4.2}/.pre-commit-config.yaml +12 -1
  5. {fauth-0.4.0 → fauth-0.4.2}/CHANGELOG.md +68 -0
  6. {fauth-0.4.0 → fauth-0.4.2}/PKG-INFO +1 -1
  7. {fauth-0.4.0 → fauth-0.4.2}/fauth/providers/provider.py +11 -5
  8. {fauth-0.4.0 → fauth-0.4.2}/pyproject.toml +1 -1
  9. fauth-0.4.2/pytest.ini +4 -0
  10. {fauth-0.4.0 → fauth-0.4.2}/tests/providers/conftest.py +63 -1
  11. {fauth-0.4.0 → fauth-0.4.2}/tests/providers/test_provider.py +52 -1
  12. {fauth-0.4.0 → fauth-0.4.2}/uv.lock +1 -1
  13. fauth-0.4.0/.github/workflows/pre-commit-autoupdate.yml +0 -45
  14. fauth-0.4.0/pytest.ini +0 -2
  15. {fauth-0.4.0 → fauth-0.4.2}/.github/actions/setup-python-env/action.yml +0 -0
  16. {fauth-0.4.0 → fauth-0.4.2}/.github/dependabot.yml +0 -0
  17. {fauth-0.4.0 → fauth-0.4.2}/.gitignore +0 -0
  18. {fauth-0.4.0 → fauth-0.4.2}/LICENSE +0 -0
  19. {fauth-0.4.0 → fauth-0.4.2}/README.md +0 -0
  20. {fauth-0.4.0 → fauth-0.4.2}/fauth/__init__.py +0 -0
  21. {fauth-0.4.0 → fauth-0.4.2}/fauth/api/__init__.py +0 -0
  22. {fauth-0.4.0 → fauth-0.4.2}/fauth/api/router.py +0 -0
  23. {fauth-0.4.0 → fauth-0.4.2}/fauth/core/__init__.py +0 -0
  24. {fauth-0.4.0 → fauth-0.4.2}/fauth/core/config.py +0 -0
  25. {fauth-0.4.0 → fauth-0.4.2}/fauth/core/exceptions.py +0 -0
  26. {fauth-0.4.0 → fauth-0.4.2}/fauth/core/schemas.py +0 -0
  27. {fauth-0.4.0 → fauth-0.4.2}/fauth/crypto/__init__.py +0 -0
  28. {fauth-0.4.0 → fauth-0.4.2}/fauth/crypto/jwt.py +0 -0
  29. {fauth-0.4.0 → fauth-0.4.2}/fauth/crypto/password.py +0 -0
  30. {fauth-0.4.0 → fauth-0.4.2}/fauth/middleware/__init__.py +0 -0
  31. {fauth-0.4.0 → fauth-0.4.2}/fauth/middleware/auth.py +0 -0
  32. {fauth-0.4.0 → fauth-0.4.2}/fauth/providers/__init__.py +0 -0
  33. {fauth-0.4.0 → fauth-0.4.2}/fauth/providers/protocols.py +0 -0
  34. {fauth-0.4.0 → fauth-0.4.2}/fauth/py.typed +0 -0
  35. {fauth-0.4.0 → fauth-0.4.2}/fauth/testing/__init__.py +0 -0
  36. {fauth-0.4.0 → fauth-0.4.2}/fauth/testing/config.py +0 -0
  37. {fauth-0.4.0 → fauth-0.4.2}/fauth/testing/fakes.py +0 -0
  38. {fauth-0.4.0 → fauth-0.4.2}/fauth/testing/provider.py +0 -0
  39. {fauth-0.4.0 → fauth-0.4.2}/fauth/transports/__init__.py +0 -0
  40. {fauth-0.4.0 → fauth-0.4.2}/fauth/transports/base.py +0 -0
  41. {fauth-0.4.0 → fauth-0.4.2}/fauth/transports/bearer.py +0 -0
  42. {fauth-0.4.0 → fauth-0.4.2}/fauth/utils/__init__.py +0 -0
  43. {fauth-0.4.0 → fauth-0.4.2}/fauth/utils/logging.py +0 -0
  44. {fauth-0.4.0 → fauth-0.4.2}/tests/__init__.py +0 -0
  45. {fauth-0.4.0 → fauth-0.4.2}/tests/api/__init__.py +0 -0
  46. {fauth-0.4.0 → fauth-0.4.2}/tests/api/conftest.py +0 -0
  47. {fauth-0.4.0 → fauth-0.4.2}/tests/api/test_openapi.py +0 -0
  48. {fauth-0.4.0 → fauth-0.4.2}/tests/api/test_router.py +0 -0
  49. {fauth-0.4.0 → fauth-0.4.2}/tests/conftest.py +0 -0
  50. {fauth-0.4.0 → fauth-0.4.2}/tests/core/__init__.py +0 -0
  51. {fauth-0.4.0 → fauth-0.4.2}/tests/core/conftest.py +0 -0
  52. {fauth-0.4.0 → fauth-0.4.2}/tests/core/test_config.py +0 -0
  53. {fauth-0.4.0 → fauth-0.4.2}/tests/core/test_exceptions.py +0 -0
  54. {fauth-0.4.0 → fauth-0.4.2}/tests/crypto/__init__.py +0 -0
  55. {fauth-0.4.0 → fauth-0.4.2}/tests/crypto/conftest.py +0 -0
  56. {fauth-0.4.0 → fauth-0.4.2}/tests/crypto/test_jwt.py +0 -0
  57. {fauth-0.4.0 → fauth-0.4.2}/tests/crypto/test_password.py +0 -0
  58. {fauth-0.4.0 → fauth-0.4.2}/tests/middleware/__init__.py +0 -0
  59. {fauth-0.4.0 → fauth-0.4.2}/tests/middleware/conftest.py +0 -0
  60. {fauth-0.4.0 → fauth-0.4.2}/tests/middleware/test_auth_middleware.py +0 -0
  61. {fauth-0.4.0 → fauth-0.4.2}/tests/providers/__init__.py +0 -0
  62. {fauth-0.4.0 → fauth-0.4.2}/tests/testing/__init__.py +0 -0
  63. {fauth-0.4.0 → fauth-0.4.2}/tests/testing/test_testing.py +0 -0
  64. {fauth-0.4.0 → fauth-0.4.2}/tests/utils/conftest.py +0 -0
  65. {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:${{ github.head_ref }}
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.10'
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.0
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, roles: list[str]) -> Callable:
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
- user_roles = getattr(user, "roles", [])
121
- required_roles = set(roles)
122
- for role in required_roles:
123
- if role not in user_roles:
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",
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "fauth"
3
- version = "0.4.0"
3
+ version = "0.4.2"
4
4
  description = "Ergonomic, lightweight JWT authentication for FastAPI. Secure your routes instantly with plug-and-play dependency injection"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.12"
fauth-0.4.2/pytest.ini ADDED
@@ -0,0 +1,4 @@
1
+ [pytest]
2
+ pythonpath = fauth
3
+ markers =
4
+ regression: marks tests as regression tests
@@ -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(auth_config: AuthConfig, inactive_user: DummyUser) -> str:
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 DummyUser, FakeUserLoader
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(
@@ -340,7 +340,7 @@ wheels = [
340
340
 
341
341
  [[package]]
342
342
  name = "fauth"
343
- version = "0.3.1"
343
+ version = "0.4.1"
344
344
  source = { editable = "." }
345
345
  dependencies = [
346
346
  { name = "fastapi" },
@@ -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
@@ -1,2 +0,0 @@
1
- [pytest]
2
- pythonpath = fauth
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