Compare commits

..

39 Commits

Author SHA1 Message Date
ad7ad1fa78 release: 2024.8.2 2024-09-16 14:13:04 +02:00
c70e609e50 website/docs: prepare release notes for 2024.8.2 (#11394)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>

# Conflicts:
#	website/docs/releases/2024/v2024.8.md
2024-09-16 14:12:28 +02:00
5f08485fff web: revert lockfile lint, re-add integrity (#11380)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
# Conflicts:
#	web/package-lock.json
2024-09-14 23:16:56 +02:00
3a2ed11821 providers/proxy: fix URL path getting lost when partial URL is given to rd= (cherry-pick #11354) (#11355)
providers/proxy: fix URL path getting lost when partial URL is given to rd= (#11354)

* providers/proxy: fix URL path getting lost when partial URL is given to rd=



* better fallback + tests



---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Jens L. <jens@goauthentik.io>
2024-09-12 18:58:47 +02:00
ee04f39e28 enterprise: fix API mixin license validity check (cherry-pick #11331) (#11342)
Co-authored-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
Co-authored-by: Simonyi Gergő <28359278+gergosimonyi@users.noreply.github.com>
Co-authored-by: Jens Langhammer <jens@goauthentik.io>
fix API mixin license validity check (#11331)
2024-09-11 13:22:01 +00:00
2c6aa72f3c sources/ldap: fix missing search attribute (cherry-pick #11125) (#11340)
sources/ldap: fix missing search attribute (#11125)

* unrelated



* sources/ldap: fix ldap sync not requesting uniqueness attribute



* check object_uniqueness_field for none



---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Jens L. <jens@goauthentik.io>
2024-09-11 14:03:12 +02:00
bd0afef790 enterprise: show specific error if Install ID is invalid in license (cherry-pick #11317) (#11319)
enterprise: show specific error if Install ID is invalid in license (#11317)

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Jens L. <jens@goauthentik.io>
2024-09-10 19:38:45 +02:00
fc11cc0a1a core: fix permission check for scoped impersonation (cherry-pick #11315) (#11316)
core: fix permission check for scoped impersonation (#11315)

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Jens L. <jens@goauthentik.io>
2024-09-10 14:19:30 +02:00
fb78303e8f web/admin: fix notification property mapping forms (cherry-pick #11298) (#11300)
web/admin: fix notification property mapping forms (#11298)

* fix incorrect base class



* fix doclink url

closes #11276



* fix sidebar order in website



---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Jens L. <jens@goauthentik.io>
2024-09-09 19:27:29 +02:00
2ea04440db events: optimise marking events as seen (cherry-pick #11297) (#11299)
events: optimise marking events as seen (#11297)

* events: optimise marking events as seen



* add tests



---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Jens L. <jens@goauthentik.io>
2024-09-09 19:26:43 +02:00
96e1636be3 core: ensure all providers have correct priority (cherry-pick #11280) (#11281)
core: ensure all providers have correct priority (#11280)

follow up to #11267 which broke SAML lookup

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Jens L. <jens@goauthentik.io>
2024-09-08 16:09:09 +02:00
c546451a73 root: fix ensure `outpost_connection_discovery runs on worker startup (cherry-pick #11260) (#11270)
root: fix ensure `outpost_connection_discovery runs on worker startup (#11260)

* root: fix ensure outpost_connection_discovery runs on worker startup

Make outpost_connection_discovery a startup task for default_tenant to ensure it's ran during worker startup. Without this waiting for the 8 hour schedule to fire is required.

fixes: https://github.com/goauthentik/authentik/issues/10933



* format



---------

Signed-off-by: Anthony Rabbito <arabbito@coreweave.com>
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Anthony Rabbito <hello@anthonyrabbito.com>
Co-authored-by: Jens Langhammer <jens@goauthentik.io>
2024-09-07 21:54:30 +02:00
61778053b4 core: ensure proxy provider is correctly looked up (cherry-pick #11267) (#11269)
core: ensure proxy provider is correctly looked up (#11267)

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Jens L. <jens@goauthentik.io>
2024-09-07 21:53:30 +02:00
f5580d311d release: 2024.8.1 2024-09-07 16:14:54 +02:00
99d292bce0 web/users: show - if device was registered before we started saving the time (cherry-pick #11256) (#11257)
web/users: show - if device was registered before we started saving the time (#11256)

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Jens L. <jens@goauthentik.io>
2024-09-06 21:13:03 +02:00
b2801641bc internal: fix go paginator not setting page correctly (cherry-pick #11253) (#11255)
internal: fix go paginator not setting page correctly (#11253)

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Jens L. <jens@goauthentik.io>
2024-09-06 18:46:18 +02:00
bfaa1046b2 core: fix missing argument name escaping for property mapping (cherry-pick #11231) (#11252)
core: fix missing argument name escaping for property mapping (#11231)

* escape property mapping args



* improve display of error



* fix error handling, missing dry_run argument



* use different sanitisation



* update docs



---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Jens L. <jens@goauthentik.io>
2024-09-06 16:47:27 +02:00
95c30400cc providers/ldap: rework search_group migration to work with read replicas (cherry-pick #11228) (#11229)
providers/ldap: rework search_group migration to work with read replicas (#11228)

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Jens L. <jens@goauthentik.io>
2024-09-05 15:57:01 +02:00
e77480ee1d web/admin: improve error handling (cherry-pick #11212) (#11219)
web/admin: improve error handling (#11212)

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Jens L. <jens@goauthentik.io>
2024-09-05 13:48:28 +02:00
905800e535 providers/ldap: fix incorrect permission check for search access (cherry-pick #11217) (#11218)
providers/ldap: fix incorrect permission check for search access (#11217)

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Jens L. <jens@goauthentik.io>
2024-09-05 01:30:48 +02:00
fadeaef4c6 web/admin: fix missing Sync object button SCIM Provider (cherry-pick #11211) (#11213)
web/admin: fix missing Sync object button SCIM Provider (#11211)

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Jens L. <jens@goauthentik.io>
2024-09-04 21:34:34 +02:00
437efda649 website/docs: add note about terraform provider (cherry-pick #11206) (#11208)
website/docs: add note about terraform provider (#11206)

* website/docs: add note about terraform provider



* Update website/docs/releases/2024/v2024.8.md



---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Signed-off-by: Tana M Berry <tanamarieberry@yahoo.com>
Co-authored-by: Jens L. <jens@goauthentik.io>
Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
2024-09-04 19:50:00 +02:00
dd75d5f54b web/admin: fix misc dual select on different forms (#11203)
* fix prompt stage

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix identification stage

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix OAuth JWKS sources

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix oauth provider default scopes

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix outpost form

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix webauthn

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix transport form

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
# Conflicts:
#	web/src/admin/applications/wizard/methods/oauth/ak-application-wizard-authentication-by-oauth.ts
#	web/src/admin/applications/wizard/methods/proxy/AuthenticationByProxyPage.ts
2024-09-04 13:46:45 +02:00
392a2e582e core: bump cryptography from 43.0.0 to 43.0.1 (cherry-pick #11185) (#11202)
core: bump cryptography from 43.0.0 to 43.0.1 (#11185)

Bumps [cryptography](https://github.com/pyca/cryptography) from 43.0.0 to 43.0.1.
- [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pyca/cryptography/compare/43.0.0...43.0.1)

---
updated-dependencies:
- dependency-name: cryptography
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-04 12:27:54 +02:00
a1da183721 root: backport s3 storage changes (cherry-pick #11181) (#11183)
root: backport s3 storage changes (#11181)

re-add _strip_signing_parameters
removed in https://github.com/jschneier/django-storages/pull/1402
could probably be re-factored to use the same approach that PR uses

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Jens L. <jens@goauthentik.io>
2024-09-03 22:08:55 +02:00
feea2df0b1 core: fix change_user_type always requiring usernames (cherry-pick #11177) (#11178)
core: fix change_user_type always requiring usernames (#11177)

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Jens L. <jens@goauthentik.io>
2024-09-03 19:09:53 +02:00
b47acd8c76 web/admin: fix error in Outpost creation form (cherry-pick #11173) (#11175)
web/admin: fix error in Outpost creation form (#11173)

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Jens L. <jens@goauthentik.io>
2024-09-03 18:26:37 +02:00
6fd87d9ced providers/ldap: fix migration assuming search group is set (cherry-pick #11170) (#11172)
providers/ldap: fix migration assuming search group is set (#11170)

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Jens L. <jens@goauthentik.io>
2024-09-03 16:27:06 +02:00
acbb065808 website/docs: update release notes (#11151)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
# Conflicts:
#	website/docs/releases/2024/v2024.8.md
2024-09-03 14:05:18 +02:00
2fb097061d release: 2024.8.0 2024-09-02 14:14:03 +02:00
8962d17e03 web: fix dual-select with dynamic selection (cherry-pick #11133) (#11134)
web: fix dual-select with dynamic selection (#11133)

* web: fix dual-select with dynamic selection

For dynamic selection, the property name is `.selector` to message that it's a function the
API layer uses to select the elements.

A few bits of lint picked.

* web: added comment to clarify what the fallback selector does

Co-authored-by: Ken Sternberg <133134217+kensternberg-authentik@users.noreply.github.com>
2024-08-30 19:07:36 +02:00
8326e1490c ci: fix failing release attestation (cherry-pick #11107) (#11120)
ci: fix failing release attestation (#11107)

* ci: fix failing release attestation



* fix



---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Jens L. <jens@goauthentik.io>
2024-08-29 13:29:47 +02:00
091e4d3e4c enterprise: fix incorrect comparison for latest validity date (cherry-pick #11109) (#11110)
enterprise: fix incorrect comparison for latest validity date (#11109)

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Jens L. <jens@goauthentik.io>
2024-08-29 01:58:56 +02:00
6ee77edcbb website/docs: 2024.8 release notes: reword group sync disable and fix typo (cherry-pick #11103) (#11108)
website/docs: 2024.8 release notes: reword group sync disable and fix… (#11103)

Co-authored-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
2024-08-29 01:34:33 +02:00
763e2288bf release: 2024.8.0-rc2 2024-08-28 20:22:52 +02:00
9cdb177ca7 website/docs: a couple of minor rewrite things (#11099)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
# Conflicts:
#	website/docs/releases/2024/v2024.8.md
2024-08-28 20:22:21 +02:00
6070508058 providers/oauth2: audit_ignore last_login change for generated service account (cherry-pick #11085) (#11086)
providers/oauth2: audit_ignore last_login change for generated service account (#11085)

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Jens L. <jens@goauthentik.io>
2024-08-27 14:32:17 +02:00
ec13a5d84d release: 2024.8.0-rc1 2024-08-26 16:34:53 +02:00
057de82b01 schemas: fix XML Schema loading...for some reason?
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2024-08-26 16:34:47 +02:00
264 changed files with 10585 additions and 17850 deletions

View File

@ -1,5 +1,5 @@
[bumpversion] [bumpversion]
current_version = 2024.8.3 current_version = 2024.8.2
tag = True tag = True
commit = True commit = True
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)(?:-(?P<rc_t>[a-zA-Z-]+)(?P<rc_n>[1-9]\\d*))? parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)(?:-(?P<rc_t>[a-zA-Z-]+)(?P<rc_n>[1-9]\\d*))?

View File

@ -44,11 +44,9 @@ updates:
- "babel-*" - "babel-*"
eslint: eslint:
patterns: patterns:
- "@eslint/*"
- "@typescript-eslint/*" - "@typescript-eslint/*"
- "eslint-*"
- "eslint" - "eslint"
- "typescript-eslint" - "eslint-*"
storybook: storybook:
patterns: patterns:
- "@storybook/*" - "@storybook/*"
@ -56,12 +54,10 @@ updates:
esbuild: esbuild:
patterns: patterns:
- "@esbuild/*" - "@esbuild/*"
- "esbuild*"
rollup: rollup:
patterns: patterns:
- "@rollup/*" - "@rollup/*"
- "rollup-*" - "rollup-*"
- "rollup*"
swc: swc:
patterns: patterns:
- "@swc/*" - "@swc/*"

View File

@ -40,7 +40,7 @@ jobs:
run: | run: |
export VERSION=`node -e 'console.log(require("../gen-ts-api/package.json").version)'` export VERSION=`node -e 'console.log(require("../gen-ts-api/package.json").version)'`
npm i @goauthentik/api@$VERSION npm i @goauthentik/api@$VERSION
- uses: peter-evans/create-pull-request@v7 - uses: peter-evans/create-pull-request@v6
id: cpr id: cpr
with: with:
token: ${{ steps.generate_token.outputs.token }} token: ${{ steps.generate_token.outputs.token }}

View File

@ -120,12 +120,6 @@ jobs:
with: with:
flags: unit flags: unit
token: ${{ secrets.CODECOV_TOKEN }} token: ${{ secrets.CODECOV_TOKEN }}
- if: ${{ !cancelled() }}
uses: codecov/test-results-action@v1
with:
flags: unit
file: unittest.xml
token: ${{ secrets.CODECOV_TOKEN }}
test-integration: test-integration:
runs-on: ubuntu-latest runs-on: ubuntu-latest
timeout-minutes: 30 timeout-minutes: 30
@ -144,12 +138,6 @@ jobs:
with: with:
flags: integration flags: integration
token: ${{ secrets.CODECOV_TOKEN }} token: ${{ secrets.CODECOV_TOKEN }}
- if: ${{ !cancelled() }}
uses: codecov/test-results-action@v1
with:
flags: integration
file: unittest.xml
token: ${{ secrets.CODECOV_TOKEN }}
test-e2e: test-e2e:
name: test-e2e (${{ matrix.job.name }}) name: test-e2e (${{ matrix.job.name }})
runs-on: ubuntu-latest runs-on: ubuntu-latest
@ -202,12 +190,6 @@ jobs:
with: with:
flags: e2e flags: e2e
token: ${{ secrets.CODECOV_TOKEN }} token: ${{ secrets.CODECOV_TOKEN }}
- if: ${{ !cancelled() }}
uses: codecov/test-results-action@v1
with:
flags: e2e
file: unittest.xml
token: ${{ secrets.CODECOV_TOKEN }}
ci-core-mark: ci-core-mark:
needs: needs:
- lint - lint

View File

@ -45,6 +45,7 @@ jobs:
- working-directory: ${{ matrix.project }}/ - working-directory: ${{ matrix.project }}/
run: | run: |
npm ci npm ci
${{ matrix.extra_setup }}
- name: Generate API - name: Generate API
run: make gen-client-ts run: make gen-client-ts
- name: Lint - name: Lint

View File

@ -24,7 +24,7 @@ jobs:
- name: Setup authentik env - name: Setup authentik env
uses: ./.github/actions/setup uses: ./.github/actions/setup
- run: poetry run ak update_webauthn_mds - run: poetry run ak update_webauthn_mds
- uses: peter-evans/create-pull-request@v7 - uses: peter-evans/create-pull-request@v6
id: cpr id: cpr
with: with:
token: ${{ steps.generate_token.outputs.token }} token: ${{ steps.generate_token.outputs.token }}

View File

@ -42,7 +42,7 @@ jobs:
with: with:
githubToken: ${{ steps.generate_token.outputs.token }} githubToken: ${{ steps.generate_token.outputs.token }}
compressOnly: ${{ github.event_name != 'pull_request' }} compressOnly: ${{ github.event_name != 'pull_request' }}
- uses: peter-evans/create-pull-request@v7 - uses: peter-evans/create-pull-request@v6
if: "${{ github.event_name != 'pull_request' && steps.compress.outputs.markdown != '' }}" if: "${{ github.event_name != 'pull_request' && steps.compress.outputs.markdown != '' }}"
id: cpr id: cpr
with: with:

View File

@ -32,7 +32,7 @@ jobs:
poetry run ak compilemessages poetry run ak compilemessages
make web-check-compile make web-check-compile
- name: Create Pull Request - name: Create Pull Request
uses: peter-evans/create-pull-request@v7 uses: peter-evans/create-pull-request@v6
with: with:
token: ${{ steps.generate_token.outputs.token }} token: ${{ steps.generate_token.outputs.token }}
branch: extract-compile-backend-translation branch: extract-compile-backend-translation

View File

@ -94,7 +94,7 @@ RUN --mount=type=secret,id=GEOIPUPDATE_ACCOUNT_ID \
/bin/sh -c "/usr/bin/entry.sh || echo 'Failed to get GeoIP database, disabling'; exit 0" /bin/sh -c "/usr/bin/entry.sh || echo 'Failed to get GeoIP database, disabling'; exit 0"
# Stage 5: Python dependencies # Stage 5: Python dependencies
FROM ghcr.io/goauthentik/fips-python:3.12.6-slim-bookworm-fips-full AS python-deps FROM ghcr.io/goauthentik/fips-python:3.12.5-slim-bookworm-fips-full AS python-deps
ARG TARGETARCH ARG TARGETARCH
ARG TARGETVARIANT ARG TARGETVARIANT
@ -124,7 +124,7 @@ RUN --mount=type=bind,target=./pyproject.toml,src=./pyproject.toml \
pip install --force-reinstall /wheels/*" pip install --force-reinstall /wheels/*"
# Stage 6: Run # Stage 6: Run
FROM ghcr.io/goauthentik/fips-python:3.12.6-slim-bookworm-fips-full AS final-image FROM ghcr.io/goauthentik/fips-python:3.12.5-slim-bookworm-fips-full AS final-image
ARG VERSION ARG VERSION
ARG GIT_BUILD_HASH ARG GIT_BUILD_HASH

View File

@ -20,8 +20,8 @@ Even if the issue is not a CVE, we still greatly appreciate your help in hardeni
| Version | Supported | | Version | Supported |
| -------- | --------- | | -------- | --------- |
| 2024.4.x | ✅ |
| 2024.6.x | ✅ | | 2024.6.x | ✅ |
| 2024.8.x | ✅ |
## Reporting a Vulnerability ## Reporting a Vulnerability

View File

@ -2,7 +2,7 @@
from os import environ from os import environ
__version__ = "2024.8.3" __version__ = "2024.8.2"
ENV_GIT_HASH_KEY = "GIT_BUILD_HASH" ENV_GIT_HASH_KEY = "GIT_BUILD_HASH"

View File

@ -1,8 +1,10 @@
"""authentik admin tasks""" """authentik admin tasks"""
import re
from django.core.cache import cache from django.core.cache import cache
from django.core.validators import URLValidator
from django.db import DatabaseError, InternalError, ProgrammingError from django.db import DatabaseError, InternalError, ProgrammingError
from django.utils.translation import gettext_lazy as _
from packaging.version import parse from packaging.version import parse
from requests import RequestException from requests import RequestException
from structlog.stdlib import get_logger from structlog.stdlib import get_logger
@ -19,6 +21,8 @@ LOGGER = get_logger()
VERSION_NULL = "0.0.0" VERSION_NULL = "0.0.0"
VERSION_CACHE_KEY = "authentik_latest_version" VERSION_CACHE_KEY = "authentik_latest_version"
VERSION_CACHE_TIMEOUT = 8 * 60 * 60 # 8 hours VERSION_CACHE_TIMEOUT = 8 * 60 * 60 # 8 hours
# Chop of the first ^ because we want to search the entire string
URL_FINDER = URLValidator.regex.pattern[1:]
LOCAL_VERSION = parse(__version__) LOCAL_VERSION = parse(__version__)
@ -74,16 +78,10 @@ def update_latest_version(self: SystemTask):
context__new_version=upstream_version, context__new_version=upstream_version,
).exists(): ).exists():
return return
Event.new( event_dict = {"new_version": upstream_version}
EventAction.UPDATE_AVAILABLE, if match := re.search(URL_FINDER, data.get("stable", {}).get("changelog", "")):
message=_( event_dict["message"] = f"Changelog: {match.group()}"
"New version {version} available!".format( Event.new(EventAction.UPDATE_AVAILABLE, **event_dict).save()
version=upstream_version,
)
),
new_version=upstream_version,
changelog=data.get("stable", {}).get("changelog_url"),
).save()
except (RequestException, IndexError) as exc: except (RequestException, IndexError) as exc:
cache.set(VERSION_CACHE_KEY, VERSION_NULL, VERSION_CACHE_TIMEOUT) cache.set(VERSION_CACHE_KEY, VERSION_NULL, VERSION_CACHE_TIMEOUT)
self.set_error(exc) self.set_error(exc)

View File

@ -17,7 +17,6 @@ RESPONSE_VALID = {
"stable": { "stable": {
"version": "99999999.9999999", "version": "99999999.9999999",
"changelog": "See https://goauthentik.io/test", "changelog": "See https://goauthentik.io/test",
"changelog_url": "https://goauthentik.io/test",
"reason": "bugfix", "reason": "bugfix",
}, },
} }
@ -36,7 +35,7 @@ class TestAdminTasks(TestCase):
Event.objects.filter( Event.objects.filter(
action=EventAction.UPDATE_AVAILABLE, action=EventAction.UPDATE_AVAILABLE,
context__new_version="99999999.9999999", context__new_version="99999999.9999999",
context__message="New version 99999999.9999999 available!", context__message="Changelog: https://goauthentik.io/test",
).exists() ).exists()
) )
# test that a consecutive check doesn't create a duplicate event # test that a consecutive check doesn't create a duplicate event
@ -46,7 +45,7 @@ class TestAdminTasks(TestCase):
Event.objects.filter( Event.objects.filter(
action=EventAction.UPDATE_AVAILABLE, action=EventAction.UPDATE_AVAILABLE,
context__new_version="99999999.9999999", context__new_version="99999999.9999999",
context__message="New version 99999999.9999999 available!", context__message="Changelog: https://goauthentik.io/test",
) )
), ),
1, 1,

View File

@ -49,7 +49,6 @@ from authentik.policies.models import PolicyBindingModel
from authentik.root.middleware import ClientIPMiddleware from authentik.root.middleware import ClientIPMiddleware
from authentik.stages.email.utils import TemplateEmailMessage from authentik.stages.email.utils import TemplateEmailMessage
from authentik.tenants.models import Tenant from authentik.tenants.models import Tenant
from authentik.tenants.utils import get_current_tenant
LOGGER = get_logger() LOGGER = get_logger()
DISCORD_FIELD_LIMIT = 25 DISCORD_FIELD_LIMIT = 25
@ -59,11 +58,7 @@ NOTIFICATION_SUMMARY_LENGTH = 75
def default_event_duration(): def default_event_duration():
"""Default duration an Event is saved. """Default duration an Event is saved.
This is used as a fallback when no brand is available""" This is used as a fallback when no brand is available"""
try: return now() + timedelta(days=365)
tenant = get_current_tenant()
return now() + timedelta_from_string(tenant.event_retention)
except Tenant.DoesNotExist:
return now() + timedelta(days=365)
def default_brand(): def default_brand():
@ -250,6 +245,12 @@ class Event(SerializerModel, ExpiringModel):
if QS_QUERY in self.context["http_request"]["args"]: if QS_QUERY in self.context["http_request"]["args"]:
wrapped = self.context["http_request"]["args"][QS_QUERY] wrapped = self.context["http_request"]["args"][QS_QUERY]
self.context["http_request"]["args"] = cleanse_dict(QueryDict(wrapped)) self.context["http_request"]["args"] = cleanse_dict(QueryDict(wrapped))
if hasattr(request, "tenant"):
tenant: Tenant = request.tenant
# Because self.created only gets set on save, we can't use it's value here
# hence we set self.created to now and then use it
self.created = now()
self.expires = self.created + timedelta_from_string(tenant.event_retention)
if hasattr(request, "brand"): if hasattr(request, "brand"):
brand: Brand = request.brand brand: Brand = request.brand
self.brand = sanitize_dict(model_to_dict(brand)) self.brand = sanitize_dict(model_to_dict(brand))

View File

@ -13,7 +13,7 @@ from authentik.events.apps import SYSTEM_TASK_STATUS
from authentik.events.models import Event, EventAction, SystemTask from authentik.events.models import Event, EventAction, SystemTask
from authentik.events.tasks import event_notification_handler, gdpr_cleanup from authentik.events.tasks import event_notification_handler, gdpr_cleanup
from authentik.flows.models import Stage from authentik.flows.models import Stage
from authentik.flows.planner import PLAN_CONTEXT_OUTPOST, PLAN_CONTEXT_SOURCE, FlowPlan from authentik.flows.planner import PLAN_CONTEXT_SOURCE, FlowPlan
from authentik.flows.views.executor import SESSION_KEY_PLAN from authentik.flows.views.executor import SESSION_KEY_PLAN
from authentik.root.monitoring import monitoring_set from authentik.root.monitoring import monitoring_set
from authentik.stages.invitation.models import Invitation from authentik.stages.invitation.models import Invitation
@ -38,9 +38,6 @@ def on_user_logged_in(sender, request: HttpRequest, user: User, **_):
# Save the login method used # Save the login method used
kwargs[PLAN_CONTEXT_METHOD] = flow_plan.context[PLAN_CONTEXT_METHOD] kwargs[PLAN_CONTEXT_METHOD] = flow_plan.context[PLAN_CONTEXT_METHOD]
kwargs[PLAN_CONTEXT_METHOD_ARGS] = flow_plan.context.get(PLAN_CONTEXT_METHOD_ARGS, {}) kwargs[PLAN_CONTEXT_METHOD_ARGS] = flow_plan.context.get(PLAN_CONTEXT_METHOD_ARGS, {})
if PLAN_CONTEXT_OUTPOST in flow_plan.context:
# Save outpost context
kwargs[PLAN_CONTEXT_OUTPOST] = flow_plan.context[PLAN_CONTEXT_OUTPOST]
event = Event.new(EventAction.LOGIN, **kwargs).from_http(request, user=user) event = Event.new(EventAction.LOGIN, **kwargs).from_http(request, user=user)
request.session[SESSION_LOGIN_EVENT] = event request.session[SESSION_LOGIN_EVENT] = event

View File

@ -6,7 +6,6 @@ from django.db.models import Model
from django.test import TestCase from django.test import TestCase
from authentik.core.models import default_token_key from authentik.core.models import default_token_key
from authentik.events.models import default_event_duration
from authentik.lib.utils.reflection import get_apps from authentik.lib.utils.reflection import get_apps
@ -21,7 +20,7 @@ def model_tester_factory(test_model: type[Model]) -> Callable:
allowed = 0 allowed = 0
# Token-like objects need to lookup the current tenant to get the default token length # Token-like objects need to lookup the current tenant to get the default token length
for field in test_model._meta.fields: for field in test_model._meta.fields:
if field.default in [default_token_key, default_event_duration]: if field.default == default_token_key:
allowed += 1 allowed += 1
with self.assertNumQueries(allowed): with self.assertNumQueries(allowed):
str(test_model()) str(test_model())

View File

@ -23,7 +23,6 @@ from authentik.flows.models import (
in_memory_stage, in_memory_stage,
) )
from authentik.lib.config import CONFIG from authentik.lib.config import CONFIG
from authentik.outposts.models import Outpost
from authentik.policies.engine import PolicyEngine from authentik.policies.engine import PolicyEngine
from authentik.root.middleware import ClientIPMiddleware from authentik.root.middleware import ClientIPMiddleware
@ -33,7 +32,6 @@ PLAN_CONTEXT_SSO = "is_sso"
PLAN_CONTEXT_REDIRECT = "redirect" PLAN_CONTEXT_REDIRECT = "redirect"
PLAN_CONTEXT_APPLICATION = "application" PLAN_CONTEXT_APPLICATION = "application"
PLAN_CONTEXT_SOURCE = "source" PLAN_CONTEXT_SOURCE = "source"
PLAN_CONTEXT_OUTPOST = "outpost"
# Is set by the Flow Planner when a FlowToken was used, and the currently active flow plan # Is set by the Flow Planner when a FlowToken was used, and the currently active flow plan
# was restored. # was restored.
PLAN_CONTEXT_IS_RESTORED = "is_restored" PLAN_CONTEXT_IS_RESTORED = "is_restored"
@ -145,23 +143,10 @@ class FlowPlanner:
and not request.user.is_superuser and not request.user.is_superuser
): ):
raise FlowNonApplicableException() raise FlowNonApplicableException()
outpost_user = ClientIPMiddleware.get_outpost_user(request)
if self.flow.authentication == FlowAuthenticationRequirement.REQUIRE_OUTPOST: if self.flow.authentication == FlowAuthenticationRequirement.REQUIRE_OUTPOST:
outpost_user = ClientIPMiddleware.get_outpost_user(request)
if not outpost_user: if not outpost_user:
raise FlowNonApplicableException() raise FlowNonApplicableException()
if outpost_user:
outpost = Outpost.objects.filter(
# TODO: Since Outpost and user are not directly connected, we have to look up a user
# like this. This should ideally by in authentik/outposts/models.py
pk=outpost_user.username.replace("ak-outpost-", "")
).first()
if outpost:
return {
PLAN_CONTEXT_OUTPOST: {
"instance": outpost,
}
}
return {}
def plan(self, request: HttpRequest, default_context: dict[str, Any] | None = None) -> FlowPlan: def plan(self, request: HttpRequest, default_context: dict[str, Any] | None = None) -> FlowPlan:
"""Check each of the flows' policies, check policies for each stage with PolicyBinding """Check each of the flows' policies, check policies for each stage with PolicyBinding
@ -174,12 +159,11 @@ class FlowPlanner:
self._logger.debug( self._logger.debug(
"f(plan): starting planning process", "f(plan): starting planning process",
) )
context = default_context or {}
# Bit of a workaround here, if there is a pending user set in the default context # Bit of a workaround here, if there is a pending user set in the default context
# we use that user for our cache key # we use that user for our cache key
# to make sure they don't get the generic response # to make sure they don't get the generic response
if context and PLAN_CONTEXT_PENDING_USER in context: if default_context and PLAN_CONTEXT_PENDING_USER in default_context:
user = context[PLAN_CONTEXT_PENDING_USER] user = default_context[PLAN_CONTEXT_PENDING_USER]
else: else:
user = request.user user = request.user
# We only need to check the flow authentication if it's planned without a user # We only need to check the flow authentication if it's planned without a user
@ -187,13 +171,14 @@ class FlowPlanner:
# or if a flow is restarted due to `invalid_response_action` being set to # or if a flow is restarted due to `invalid_response_action` being set to
# `restart_with_context`, which can only happen if the user was already authorized # `restart_with_context`, which can only happen if the user was already authorized
# to use the flow # to use the flow
context.update(self._check_authentication(request)) self._check_authentication(request)
# First off, check the flow's direct policy bindings # First off, check the flow's direct policy bindings
# to make sure the user even has access to the flow # to make sure the user even has access to the flow
engine = PolicyEngine(self.flow, user, request) engine = PolicyEngine(self.flow, user, request)
engine.use_cache = self.use_cache engine.use_cache = self.use_cache
span.set_data("context", cleanse_dict(context)) if default_context:
engine.request.context.update(context) span.set_data("default_context", cleanse_dict(default_context))
engine.request.context.update(default_context)
engine.build() engine.build()
result = engine.result result = engine.result
if not result.passing: if not result.passing:
@ -210,12 +195,12 @@ class FlowPlanner:
key=cached_plan_key, key=cached_plan_key,
) )
# Reset the context as this isn't factored into caching # Reset the context as this isn't factored into caching
cached_plan.context = context cached_plan.context = default_context or {}
return cached_plan return cached_plan
self._logger.debug( self._logger.debug(
"f(plan): building plan", "f(plan): building plan",
) )
plan = self._build_plan(user, request, context) plan = self._build_plan(user, request, default_context)
if self.use_cache: if self.use_cache:
cache.set(cache_key(self.flow, user), plan, CACHE_TIMEOUT) cache.set(cache_key(self.flow, user), plan, CACHE_TIMEOUT)
if not plan.bindings and not self.allow_empty_flows: if not plan.bindings and not self.allow_empty_flows:

View File

@ -30,11 +30,6 @@ class TestHTTP(TestCase):
request = self.factory.get("/", HTTP_X_FORWARDED_FOR="127.0.0.2") request = self.factory.get("/", HTTP_X_FORWARDED_FOR="127.0.0.2")
self.assertEqual(ClientIPMiddleware.get_client_ip(request), "127.0.0.2") self.assertEqual(ClientIPMiddleware.get_client_ip(request), "127.0.0.2")
def test_forward_for_invalid(self):
"""Test invalid forward for"""
request = self.factory.get("/", HTTP_X_FORWARDED_FOR="foobar")
self.assertEqual(ClientIPMiddleware.get_client_ip(request), ClientIPMiddleware.default_ip)
def test_fake_outpost(self): def test_fake_outpost(self):
"""Test faked IP which is overridden by an outpost""" """Test faked IP which is overridden by an outpost"""
token = Token.objects.create( token = Token.objects.create(
@ -58,17 +53,6 @@ class TestHTTP(TestCase):
}, },
) )
self.assertEqual(ClientIPMiddleware.get_client_ip(request), "127.0.0.1") self.assertEqual(ClientIPMiddleware.get_client_ip(request), "127.0.0.1")
# Invalid, not a real IP
self.user.type = UserTypes.INTERNAL_SERVICE_ACCOUNT
self.user.save()
request = self.factory.get(
"/",
**{
ClientIPMiddleware.outpost_remote_ip_header: "foobar",
ClientIPMiddleware.outpost_token_header: token.key,
},
)
self.assertEqual(ClientIPMiddleware.get_client_ip(request), "127.0.0.1")
# Valid # Valid
self.user.type = UserTypes.INTERNAL_SERVICE_ACCOUNT self.user.type = UserTypes.INTERNAL_SERVICE_ACCOUNT
self.user.save() self.user.save()

View File

@ -1,23 +0,0 @@
# Generated by Django 5.0.9 on 2024-09-26 16:25
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("authentik_providers_oauth2", "0018_alter_accesstoken_expires_and_more"),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.AddIndex(
model_name="accesstoken",
index=models.Index(fields=["token"], name="authentik_p_token_4bc870_idx"),
),
migrations.AddIndex(
model_name="refreshtoken",
index=models.Index(fields=["token"], name="authentik_p_token_1a841f_idx"),
),
]

View File

@ -1,31 +0,0 @@
# Generated by Django 5.0.9 on 2024-09-27 14:50
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("authentik_providers_oauth2", "0019_accesstoken_authentik_p_token_4bc870_idx_and_more"),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.RemoveIndex(
model_name="accesstoken",
name="authentik_p_token_4bc870_idx",
),
migrations.RemoveIndex(
model_name="refreshtoken",
name="authentik_p_token_1a841f_idx",
),
migrations.AddIndex(
model_name="accesstoken",
index=models.Index(fields=["token", "provider"], name="authentik_p_token_f99422_idx"),
),
migrations.AddIndex(
model_name="refreshtoken",
index=models.Index(fields=["token", "provider"], name="authentik_p_token_a1d921_idx"),
),
]

View File

@ -376,9 +376,6 @@ class AccessToken(SerializerModel, ExpiringModel, BaseGrantModel):
_id_token = models.TextField() _id_token = models.TextField()
class Meta: class Meta:
indexes = [
models.Index(fields=["token", "provider"]),
]
verbose_name = _("OAuth2 Access Token") verbose_name = _("OAuth2 Access Token")
verbose_name_plural = _("OAuth2 Access Tokens") verbose_name_plural = _("OAuth2 Access Tokens")
@ -422,9 +419,6 @@ class RefreshToken(SerializerModel, ExpiringModel, BaseGrantModel):
_id_token = models.TextField(verbose_name=_("ID Token")) _id_token = models.TextField(verbose_name=_("ID Token"))
class Meta: class Meta:
indexes = [
models.Index(fields=["token", "provider"]),
]
verbose_name = _("OAuth2 Refresh Token") verbose_name = _("OAuth2 Refresh Token")
verbose_name_plural = _("OAuth2 Refresh Tokens") verbose_name_plural = _("OAuth2 Refresh Tokens")

View File

@ -29,6 +29,7 @@ class TesOAuth2Introspection(OAuthTestCase):
self.app = Application.objects.create( self.app = Application.objects.create(
name=generate_id(), slug=generate_id(), provider=self.provider name=generate_id(), slug=generate_id(), provider=self.provider
) )
self.app.save()
self.user = create_test_admin_user() self.user = create_test_admin_user()
self.auth = b64encode( self.auth = b64encode(
f"{self.provider.client_id}:{self.provider.client_secret}".encode() f"{self.provider.client_id}:{self.provider.client_secret}".encode()
@ -113,41 +114,6 @@ class TesOAuth2Introspection(OAuthTestCase):
}, },
) )
def test_introspect_invalid_provider(self):
"""Test introspection (mismatched provider and token)"""
provider: OAuth2Provider = OAuth2Provider.objects.create(
name=generate_id(),
authorization_flow=create_test_flow(),
redirect_uris="",
signing_key=create_test_cert(),
)
auth = b64encode(f"{provider.client_id}:{provider.client_secret}".encode()).decode()
token: AccessToken = AccessToken.objects.create(
provider=self.provider,
user=self.user,
token=generate_id(),
auth_time=timezone.now(),
_scope="openid user profile",
_id_token=json.dumps(
asdict(
IDToken("foo", "bar"),
)
),
)
res = self.client.post(
reverse("authentik_providers_oauth2:token-introspection"),
HTTP_AUTHORIZATION=f"Basic {auth}",
data={"token": token.token},
)
self.assertEqual(res.status_code, 200)
self.assertJSONEqual(
res.content.decode(),
{
"active": False,
},
)
def test_introspect_invalid_auth(self): def test_introspect_invalid_auth(self):
"""Test introspect (invalid auth)""" """Test introspect (invalid auth)"""
res = self.client.post( res = self.client.post(

View File

@ -46,10 +46,10 @@ class TokenIntrospectionParams:
if not provider: if not provider:
raise TokenIntrospectionError raise TokenIntrospectionError
access_token = AccessToken.objects.filter(token=raw_token, provider=provider).first() access_token = AccessToken.objects.filter(token=raw_token).first()
if access_token: if access_token:
return TokenIntrospectionParams(access_token, provider) return TokenIntrospectionParams(access_token, provider)
refresh_token = RefreshToken.objects.filter(token=raw_token, provider=provider).first() refresh_token = RefreshToken.objects.filter(token=raw_token).first()
if refresh_token: if refresh_token:
return TokenIntrospectionParams(refresh_token, provider) return TokenIntrospectionParams(refresh_token, provider)
LOGGER.debug("Token does not exist", token=raw_token) LOGGER.debug("Token does not exist", token=raw_token)

View File

@ -28,7 +28,7 @@ class ProxyDockerController(DockerController):
labels = super()._get_labels() labels = super()._get_labels()
labels["traefik.enable"] = "true" labels["traefik.enable"] = "true"
labels[f"traefik.http.routers.{traefik_name}-router.rule"] = ( labels[f"traefik.http.routers.{traefik_name}-router.rule"] = (
f"({' || '.join([f'Host({host})' for host in hosts])})" f"({' || '.join([f'Host(`{host}`)' for host in hosts])})"
f" && PathPrefix(`/outpost.goauthentik.io`)" f" && PathPrefix(`/outpost.goauthentik.io`)"
) )
labels[f"traefik.http.routers.{traefik_name}-router.tls"] = "true" labels[f"traefik.http.routers.{traefik_name}-router.tls"] = "true"

View File

@ -2,7 +2,6 @@
from collections.abc import Callable from collections.abc import Callable
from hashlib import sha512 from hashlib import sha512
from ipaddress import ip_address
from time import perf_counter, time from time import perf_counter, time
from typing import Any from typing import Any
@ -175,7 +174,6 @@ class ClientIPMiddleware:
def __init__(self, get_response: Callable[[HttpRequest], HttpResponse]): def __init__(self, get_response: Callable[[HttpRequest], HttpResponse]):
self.get_response = get_response self.get_response = get_response
self.logger = get_logger().bind()
def _get_client_ip_from_meta(self, meta: dict[str, Any]) -> str: def _get_client_ip_from_meta(self, meta: dict[str, Any]) -> str:
"""Attempt to get the client's IP by checking common HTTP Headers. """Attempt to get the client's IP by checking common HTTP Headers.
@ -187,16 +185,11 @@ class ClientIPMiddleware:
"HTTP_X_FORWARDED_FOR", "HTTP_X_FORWARDED_FOR",
"REMOTE_ADDR", "REMOTE_ADDR",
) )
try: for _header in headers:
for _header in headers: if _header in meta:
if _header in meta: ips: list[str] = meta.get(_header).split(",")
ips: list[str] = meta.get(_header).split(",") return ips[0].strip()
# Ensure the IP parses as a valid IP return self.default_ip
return str(ip_address(ips[0].strip()))
return self.default_ip
except ValueError as exc:
self.logger.debug("Invalid remote IP", exc=exc)
return self.default_ip
# FIXME: this should probably not be in `root` but rather in a middleware in `outposts` # FIXME: this should probably not be in `root` but rather in a middleware in `outposts`
# but for now it's fine # but for now it's fine
@ -228,16 +221,12 @@ class ClientIPMiddleware:
) )
return None return None
# Update sentry scope to include correct IP # Update sentry scope to include correct IP
sentry_user = Scope.get_isolation_scope()._user or {} user = Scope.get_isolation_scope()._user or {}
sentry_user["ip_address"] = delegated_ip user["ip_address"] = delegated_ip
Scope.get_isolation_scope().set_user(sentry_user) Scope.get_isolation_scope().set_user(user)
# Set the outpost service account on the request # Set the outpost service account on the request
setattr(request, self.request_attr_outpost_user, user) setattr(request, self.request_attr_outpost_user, user)
try: return delegated_ip
return str(ip_address(delegated_ip))
except ValueError as exc:
self.logger.debug("Invalid remote IP from Outpost", exc=exc)
return None
def _get_client_ip(self, request: HttpRequest | None) -> str: def _get_client_ip(self, request: HttpRequest | None) -> str:
"""Attempt to get the client's IP by checking common HTTP Headers. """Attempt to get the client's IP by checking common HTTP Headers.

View File

@ -3,7 +3,6 @@
from typing import Any from typing import Any
from django.core.cache import cache from django.core.cache import cache
from django.utils.translation import gettext_lazy as _
from drf_spectacular.utils import extend_schema, inline_serializer from drf_spectacular.utils import extend_schema, inline_serializer
from guardian.shortcuts import get_objects_for_user from guardian.shortcuts import get_objects_for_user
from rest_framework.decorators import action from rest_framework.decorators import action
@ -40,8 +39,9 @@ class LDAPSourceSerializer(SourceSerializer):
"""Get cached source connectivity""" """Get cached source connectivity"""
return cache.get(CACHE_KEY_STATUS + source.slug, None) return cache.get(CACHE_KEY_STATUS + source.slug, None)
def validate_sync_users_password(self, sync_users_password: bool) -> bool: def validate(self, attrs: dict[str, Any]) -> dict[str, Any]:
"""Check that only a single source has password_sync on""" """Check that only a single source has password_sync on"""
sync_users_password = attrs.get("sync_users_password", True)
if sync_users_password: if sync_users_password:
sources = LDAPSource.objects.filter(sync_users_password=True) sources = LDAPSource.objects.filter(sync_users_password=True)
if self.instance: if self.instance:
@ -49,31 +49,11 @@ class LDAPSourceSerializer(SourceSerializer):
if sources.exists(): if sources.exists():
raise ValidationError( raise ValidationError(
{ {
"sync_users_password": _( "sync_users_password": (
"Only a single LDAP Source with password synchronization is allowed" "Only a single LDAP Source with password synchronization is allowed"
) )
} }
) )
return sync_users_password
def validate(self, attrs: dict[str, Any]) -> dict[str, Any]:
"""Validate property mappings with sync_ flags"""
types = ["user", "group"]
for type in types:
toggle_value = attrs.get(f"sync_{type}s", False)
mappings_field = f"{type}_property_mappings"
mappings_value = attrs.get(mappings_field, [])
if toggle_value and len(mappings_value) == 0:
raise ValidationError(
{
mappings_field: _(
(
"When 'Sync {type}s' is enabled, '{type}s property "
"mappings' cannot be empty."
).format(type=type)
)
}
)
return super().validate(attrs) return super().validate(attrs)
class Meta: class Meta:
@ -186,12 +166,11 @@ class LDAPSourceViewSet(UsedByMixin, ModelViewSet):
for sync_class in SYNC_CLASSES: for sync_class in SYNC_CLASSES:
class_name = sync_class.name() class_name = sync_class.name()
all_objects.setdefault(class_name, []) all_objects.setdefault(class_name, [])
for page in sync_class(source).get_objects(size_limit=10): for obj in sync_class(source).get_objects(size_limit=10):
for obj in page: obj: dict
obj: dict obj.pop("raw_attributes", None)
obj.pop("raw_attributes", None) obj.pop("raw_dn", None)
obj.pop("raw_dn", None) all_objects[class_name].append(obj)
all_objects[class_name].append(obj)
return Response(data=all_objects) return Response(data=all_objects)

View File

@ -26,16 +26,17 @@ def sync_ldap_source_on_save(sender, instance: LDAPSource, **_):
"""Ensure that source is synced on save (if enabled)""" """Ensure that source is synced on save (if enabled)"""
if not instance.enabled: if not instance.enabled:
return return
ldap_connectivity_check.delay(instance.pk)
# Don't sync sources when they don't have any property mappings. This will only happen if: # Don't sync sources when they don't have any property mappings. This will only happen if:
# - the user forgets to set them or # - the user forgets to set them or
# - the source is newly created, this is the first save event # - the source is newly created, this is the first save event
# and the mappings are created with an m2m event # and the mappings are created with an m2m event
if instance.sync_users and not instance.user_property_mappings.exists(): if (
return not instance.user_property_mappings.exists()
if instance.sync_groups and not instance.group_property_mappings.exists(): or not instance.group_property_mappings.exists()
):
return return
ldap_sync_single.delay(instance.pk) ldap_sync_single.delay(instance.pk)
ldap_connectivity_check.delay(instance.pk)
@receiver(password_validate) @receiver(password_validate)

View File

@ -78,9 +78,7 @@ class MicrosoftActiveDirectory(BaseLDAPSynchronizer):
# /useraccountcontrol-manipulate-account-properties # /useraccountcontrol-manipulate-account-properties
uac_bit = attributes.get("userAccountControl", 512) uac_bit = attributes.get("userAccountControl", 512)
uac = UserAccountControl(uac_bit) uac = UserAccountControl(uac_bit)
is_active = ( is_active = UserAccountControl.ACCOUNTDISABLE not in uac
UserAccountControl.ACCOUNTDISABLE not in uac and UserAccountControl.LOCKOUT not in uac
)
if is_active != user.is_active: if is_active != user.is_active:
user.is_active = is_active user.is_active = is_active
user.save() user.save()

View File

@ -50,35 +50,3 @@ class LDAPAPITests(APITestCase):
} }
) )
self.assertFalse(serializer.is_valid()) self.assertFalse(serializer.is_valid())
def test_sync_users_mapping_empty(self):
"""Check that when sync_users is enabled, property mappings must be set"""
serializer = LDAPSourceSerializer(
data={
"name": "foo",
"slug": " foo",
"server_uri": "ldaps://1.2.3.4",
"bind_cn": "",
"bind_password": LDAP_PASSWORD,
"base_dn": "dc=foo",
"sync_users": True,
"user_property_mappings": [],
}
)
self.assertFalse(serializer.is_valid())
def test_sync_groups_mapping_empty(self):
"""Check that when sync_groups is enabled, property mappings must be set"""
serializer = LDAPSourceSerializer(
data={
"name": "foo",
"slug": " foo",
"server_uri": "ldaps://1.2.3.4",
"bind_cn": "",
"bind_password": LDAP_PASSWORD,
"base_dn": "dc=foo",
"sync_groups": True,
"group_property_mappings": [],
}
)
self.assertFalse(serializer.is_valid())

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -82,5 +82,3 @@ entries:
order: 10 order: 10
target: !KeyOf default-authentication-flow-password-binding target: !KeyOf default-authentication-flow-password-binding
policy: !KeyOf default-authentication-flow-password-optional policy: !KeyOf default-authentication-flow-password-optional
attrs:
failure_result: true

View File

@ -2,7 +2,7 @@
"$schema": "http://json-schema.org/draft-07/schema", "$schema": "http://json-schema.org/draft-07/schema",
"$id": "https://goauthentik.io/blueprints/schema.json", "$id": "https://goauthentik.io/blueprints/schema.json",
"type": "object", "type": "object",
"title": "authentik 2024.8.3 Blueprint schema", "title": "authentik 2024.8.2 Blueprint schema",
"required": [ "required": [
"version", "version",
"entries" "entries"

View File

@ -31,7 +31,7 @@ services:
volumes: volumes:
- redis:/data - redis:/data
server: server:
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2024.8.3} image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2024.8.2}
restart: unless-stopped restart: unless-stopped
command: server command: server
environment: environment:
@ -52,7 +52,7 @@ services:
- postgresql - postgresql
- redis - redis
worker: worker:
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2024.8.3} image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2024.8.2}
restart: unless-stopped restart: unless-stopped
command: worker command: worker
environment: environment:

10
go.mod
View File

@ -7,7 +7,7 @@ toolchain go1.23.0
require ( require (
beryju.io/ldap v0.1.0 beryju.io/ldap v0.1.0
github.com/coreos/go-oidc/v3 v3.11.0 github.com/coreos/go-oidc/v3 v3.11.0
github.com/getsentry/sentry-go v0.29.0 github.com/getsentry/sentry-go v0.28.1
github.com/go-http-utils/etag v0.0.0-20161124023236-513ea8f21eb1 github.com/go-http-utils/etag v0.0.0-20161124023236-513ea8f21eb1
github.com/go-ldap/ldap/v3 v3.4.8 github.com/go-ldap/ldap/v3 v3.4.8
github.com/go-openapi/runtime v0.28.0 github.com/go-openapi/runtime v0.28.0
@ -18,20 +18,20 @@ require (
github.com/gorilla/securecookie v1.1.2 github.com/gorilla/securecookie v1.1.2
github.com/gorilla/sessions v1.4.0 github.com/gorilla/sessions v1.4.0
github.com/gorilla/websocket v1.5.3 github.com/gorilla/websocket v1.5.3
github.com/jellydator/ttlcache/v3 v3.3.0 github.com/jellydator/ttlcache/v3 v3.2.1
github.com/mitchellh/mapstructure v1.5.0 github.com/mitchellh/mapstructure v1.5.0
github.com/nmcclain/asn1-ber v0.0.0-20170104154839-2661553a0484 github.com/nmcclain/asn1-ber v0.0.0-20170104154839-2661553a0484
github.com/pires/go-proxyproto v0.7.0 github.com/pires/go-proxyproto v0.7.0
github.com/prometheus/client_golang v1.20.4 github.com/prometheus/client_golang v1.20.2
github.com/redis/go-redis/v9 v9.6.1 github.com/redis/go-redis/v9 v9.6.1
github.com/sethvargo/go-envconfig v1.1.0 github.com/sethvargo/go-envconfig v1.1.0
github.com/sirupsen/logrus v1.9.3 github.com/sirupsen/logrus v1.9.3
github.com/spf13/cobra v1.8.1 github.com/spf13/cobra v1.8.1
github.com/stretchr/testify v1.9.0 github.com/stretchr/testify v1.9.0
github.com/wwt/guac v1.3.2 github.com/wwt/guac v1.3.2
goauthentik.io/api/v3 v3.2024083.1 goauthentik.io/api/v3 v3.2024064.1
golang.org/x/exp v0.0.0-20230210204819-062eb4c674ab golang.org/x/exp v0.0.0-20230210204819-062eb4c674ab
golang.org/x/oauth2 v0.23.0 golang.org/x/oauth2 v0.22.0
golang.org/x/sync v0.8.0 golang.org/x/sync v0.8.0
gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v2 v2.4.0
layeh.com/radius v0.0.0-20210819152912-ad72663a72ab layeh.com/radius v0.0.0-20210819152912-ad72663a72ab

20
go.sum
View File

@ -69,8 +69,8 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk=
github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/getsentry/sentry-go v0.29.0 h1:YtWluuCFg9OfcqnaujpY918N/AhCCwarIDWOYSBAjCA= github.com/getsentry/sentry-go v0.28.1 h1:zzaSm/vHmGllRM6Tpx1492r0YDzauArdBfkJRtY6P5k=
github.com/getsentry/sentry-go v0.29.0/go.mod h1:jhPesDAL0Q0W2+2YEuVOvdWmVtdsr1+jtBrlDEVWwLY= github.com/getsentry/sentry-go v0.28.1/go.mod h1:1fQZ+7l7eeJ3wYi82q5Hg8GqAPgefRq+FP/QhafYVgg=
github.com/go-asn1-ber/asn1-ber v1.5.5 h1:MNHlNMBDgEKD4TcKr36vQN68BA00aDfjIt3/bD50WnA= github.com/go-asn1-ber/asn1-ber v1.5.5 h1:MNHlNMBDgEKD4TcKr36vQN68BA00aDfjIt3/bD50WnA=
github.com/go-asn1-ber/asn1-ber v1.5.5/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= github.com/go-asn1-ber/asn1-ber v1.5.5/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
@ -200,8 +200,8 @@ github.com/jcmturner/gokrb5/v8 v8.4.4 h1:x1Sv4HaTpepFkXbt2IkL29DXRf8sOfZXo8eRKh6
github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs= github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs=
github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY= github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY=
github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc=
github.com/jellydator/ttlcache/v3 v3.3.0 h1:BdoC9cE81qXfrxeb9eoJi9dWrdhSuwXMAnHTbnBm4Wc= github.com/jellydator/ttlcache/v3 v3.2.1 h1:eS8ljnYY7BllYGkXw/TfczWZrXUu/CH7SIkC6ugn9Js=
github.com/jellydator/ttlcache/v3 v3.3.0/go.mod h1:bj2/e0l4jRnQdrnSTaGTsh4GSXvMjQcy41i7th0GVGw= github.com/jellydator/ttlcache/v3 v3.2.1/go.mod h1:bj2/e0l4jRnQdrnSTaGTsh4GSXvMjQcy41i7th0GVGw=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
@ -239,8 +239,8 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v1.20.4 h1:Tgh3Yr67PaOv/uTqloMsCEdeuFTatm5zIq5+qNN23vI= github.com/prometheus/client_golang v1.20.2 h1:5ctymQzZlyOON1666svgwn3s6IKWgfbjsejTMiXIyjg=
github.com/prometheus/client_golang v1.20.4/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= github.com/prometheus/client_golang v1.20.2/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
@ -299,8 +299,8 @@ go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y
go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
goauthentik.io/api/v3 v3.2024083.1 h1:OPo2VejMkS5WjYw5zIjfuxR9XUbTKs4m+sACrPKcm9U= goauthentik.io/api/v3 v3.2024064.1 h1:vxquklgDGD+nGFhWRAsQ7ezQKg17MRq6bzEk25fbsb4=
goauthentik.io/api/v3 v3.2024083.1/go.mod h1:zz+mEZg8rY/7eEjkMGWJ2DnGqk+zqxuybGCGrR2O4Kw= goauthentik.io/api/v3 v3.2024064.1/go.mod h1:zz+mEZg8rY/7eEjkMGWJ2DnGqk+zqxuybGCGrR2O4Kw=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
@ -388,8 +388,8 @@ golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4Iltr
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA=
golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=

View File

@ -29,4 +29,4 @@ func UserAgent() string {
return fmt.Sprintf("authentik@%s", FullVersion()) return fmt.Sprintf("authentik@%s", FullVersion())
} }
const VERSION = "2024.8.3" const VERSION = "2024.8.2"

View File

@ -65,11 +65,8 @@ type Server interface {
CryptoStore() *ak.CryptoStore CryptoStore() *ak.CryptoStore
} }
func init() { func NewApplication(p api.ProxyOutpostConfig, c *http.Client, server Server) (*Application, error) {
gob.Register(Claims{}) gob.Register(Claims{})
}
func NewApplication(p api.ProxyOutpostConfig, c *http.Client, server Server, oldApp *Application) (*Application, error) {
muxLogger := log.WithField("logger", "authentik.outpost.proxyv2.application").WithField("name", p.Name) muxLogger := log.WithField("logger", "authentik.outpost.proxyv2.application").WithField("name", p.Name)
externalHost, err := url.Parse(p.ExternalHost) externalHost, err := url.Parse(p.ExternalHost)
@ -140,15 +137,7 @@ func NewApplication(p api.ProxyOutpostConfig, c *http.Client, server Server, old
isEmbedded: isEmbedded, isEmbedded: isEmbedded,
} }
go a.authHeaderCache.Start() go a.authHeaderCache.Start()
if oldApp != nil && oldApp.sessions != nil { a.sessions = a.getStore(p, externalHost)
a.sessions = oldApp.sessions
} else {
sess, err := a.getStore(p, externalHost)
if err != nil {
return nil, err
}
a.sessions = sess
}
mux.Use(web.NewLoggingHandler(muxLogger, func(l *log.Entry, r *http.Request) *log.Entry { mux.Use(web.NewLoggingHandler(muxLogger, func(l *log.Entry, r *http.Request) *log.Entry {
c := a.getClaimsFromSession(r) c := a.getClaimsFromSession(r)
if c == nil { if c == nil {
@ -246,8 +235,9 @@ func NewApplication(p api.ProxyOutpostConfig, c *http.Client, server Server, old
// TODO: maybe create event for this? // TODO: maybe create event for this?
a.log.WithError(err).Warning("failed to compile SkipPathRegex") a.log.WithError(err).Warning("failed to compile SkipPathRegex")
continue continue
} else {
a.UnauthenticatedRegex = append(a.UnauthenticatedRegex, re)
} }
a.UnauthenticatedRegex = append(a.UnauthenticatedRegex, re)
} }
} }
return a, nil return a, nil

View File

@ -26,7 +26,7 @@ import (
const RedisKeyPrefix = "authentik_proxy_session_" const RedisKeyPrefix = "authentik_proxy_session_"
func (a *Application) getStore(p api.ProxyOutpostConfig, externalHost *url.URL) (sessions.Store, error) { func (a *Application) getStore(p api.ProxyOutpostConfig, externalHost *url.URL) sessions.Store {
maxAge := 0 maxAge := 0
if p.AccessTokenValidity.IsSet() { if p.AccessTokenValidity.IsSet() {
t := p.AccessTokenValidity.Get() t := p.AccessTokenValidity.Get()
@ -73,7 +73,7 @@ func (a *Application) getStore(p api.ProxyOutpostConfig, externalHost *url.URL)
// New default RedisStore // New default RedisStore
rs, err := redisstore.NewRedisStore(context.Background(), client) rs, err := redisstore.NewRedisStore(context.Background(), client)
if err != nil { if err != nil {
return nil, err a.log.WithError(err).Panic("failed to connect to redis")
} }
rs.KeyPrefix(RedisKeyPrefix) rs.KeyPrefix(RedisKeyPrefix)
@ -87,7 +87,7 @@ func (a *Application) getStore(p api.ProxyOutpostConfig, externalHost *url.URL)
}) })
a.log.Trace("using redis session backend") a.log.Trace("using redis session backend")
return rs, nil return rs
} }
dir := os.TempDir() dir := os.TempDir()
cs := sessions.NewFilesystemStore(dir) cs := sessions.NewFilesystemStore(dir)
@ -106,7 +106,7 @@ func (a *Application) getStore(p api.ProxyOutpostConfig, externalHost *url.URL)
cs.Options.MaxAge = maxAge cs.Options.MaxAge = maxAge
cs.Options.Path = "/" cs.Options.Path = "/"
a.log.WithField("dir", dir).Trace("using filesystem session backend") a.log.WithField("dir", dir).Trace("using filesystem session backend")
return cs, nil return cs
} }
func (a *Application) SessionName() string { func (a *Application) SessionName() string {

View File

@ -66,7 +66,6 @@ func newTestApplication() *Application {
}, },
http.DefaultClient, http.DefaultClient,
ts, ts,
nil,
) )
ts.apps = append(ts.apps, a) ts.apps = append(ts.apps, a)
return a return a

View File

@ -4,7 +4,6 @@ import (
"context" "context"
"fmt" "fmt"
"net/http" "net/http"
"net/url"
"github.com/getsentry/sentry-go" "github.com/getsentry/sentry-go"
"goauthentik.io/internal/constants" "goauthentik.io/internal/constants"
@ -38,21 +37,16 @@ func (ps *ProxyServer) Refresh() error {
), ),
), ),
} }
externalHost, err := url.Parse(provider.ExternalHost) a, err := application.NewApplication(provider, hc, ps)
if err != nil { existing, ok := ps.apps[a.Host]
ps.log.WithError(err).Warning("failed to parse URL, skipping provider")
continue
}
existing, ok := ps.apps[externalHost.Host]
a, err := application.NewApplication(provider, hc, ps, existing)
if ok { if ok {
existing.Stop() existing.Stop()
} }
if err != nil { if err != nil {
ps.log.WithError(err).Warning("failed to setup application") ps.log.WithError(err).Warning("failed to setup application")
continue } else {
apps[a.Host] = a
} }
apps[externalHost.Host] = a
} }
ps.apps = apps ps.apps = apps
ps.log.Debug("Swapped maps") ps.log.Debug("Swapped maps")

View File

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-09-25 00:08+0000\n" "POT-Creation-Date: 2024-08-18 00:08+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -18,11 +18,6 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: authentik/admin/tasks.py
#, python-brace-format
msgid "New version {version} available!"
msgstr ""
#: authentik/api/schema.py #: authentik/api/schema.py
msgid "Generic API Error" msgid "Generic API Error"
msgstr "" msgstr ""
@ -1849,10 +1844,6 @@ msgstr ""
msgid "Used recovery-link to authenticate." msgid "Used recovery-link to authenticate."
msgstr "" msgstr ""
#: authentik/sources/ldap/api.py
msgid "Only a single LDAP Source with password synchronization is allowed"
msgstr ""
#: authentik/sources/ldap/models.py #: authentik/sources/ldap/models.py
msgid "Server URI" msgid "Server URI"
msgstr "" msgstr ""

Binary file not shown.

View File

@ -19,7 +19,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-09-08 00:09+0000\n" "POT-Creation-Date: 2024-08-12 13:45+0000\n"
"PO-Revision-Date: 2022-09-26 16:47+0000\n" "PO-Revision-Date: 2022-09-26 16:47+0000\n"
"Last-Translator: Marc Schmitt, 2024\n" "Last-Translator: Marc Schmitt, 2024\n"
"Language-Team: French (https://app.transifex.com/authentik/teams/119923/fr/)\n" "Language-Team: French (https://app.transifex.com/authentik/teams/119923/fr/)\n"
@ -29,11 +29,6 @@ msgstr ""
"Language: fr\n" "Language: fr\n"
"Plural-Forms: nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n" "Plural-Forms: nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n"
#: authentik/admin/tasks.py
#, python-brace-format
msgid "New version {version} available!"
msgstr "Une nouvelle version {version} est disponible !"
#: authentik/api/schema.py #: authentik/api/schema.py
msgid "Generic API Error" msgid "Generic API Error"
msgstr "Erreur d'API Générique" msgstr "Erreur d'API Générique"
@ -1347,6 +1342,14 @@ msgstr "Impossible de résoudre l'application"
msgid "DN under which objects are accessible." msgid "DN under which objects are accessible."
msgstr "DN sous lequel les objets sont accessibles." msgstr "DN sous lequel les objets sont accessibles."
#: authentik/providers/ldap/models.py
msgid ""
"Users in this group can do search queries. If not set, every user can "
"execute search queries."
msgstr ""
"Les utilisateurs dans ce groupe peuvent faire des requêtes de recherche. Si "
"laissé vide, tous les utilisateurs peuvent faire des requêtes de recherche."
#: authentik/providers/ldap/models.py #: authentik/providers/ldap/models.py
msgid "" msgid ""
"The start for uidNumbers, this number is added to the user.pk to make sure " "The start for uidNumbers, this number is added to the user.pk to make sure "
@ -1393,10 +1396,6 @@ msgstr "Fournisseur LDAP"
msgid "LDAP Providers" msgid "LDAP Providers"
msgstr "Fournisseurs LDAP" msgstr "Fournisseurs LDAP"
#: authentik/providers/ldap/models.py
msgid "Search full LDAP directory"
msgstr "Rechercher dans l'annuaire LDAP complet"
#: authentik/providers/oauth2/id_token.py #: authentik/providers/oauth2/id_token.py
msgid "Based on the Hashed User ID" msgid "Based on the Hashed User ID"
msgstr "Basé sur le hash de l'ID utilisateur" msgstr "Basé sur le hash de l'ID utilisateur"
@ -1797,14 +1796,6 @@ msgstr "Mappage de propriété fournisseur Radius"
msgid "Radius Provider Property Mappings" msgid "Radius Provider Property Mappings"
msgstr "Mappages de propriété fournisseur Radius" msgstr "Mappages de propriété fournisseur Radius"
#: authentik/providers/saml/api/providers.py
msgid ""
"With a signing keypair selected, at least one of 'Sign assertion' and 'Sign "
"Response' must be selected."
msgstr ""
"Quand une clé de signature est sélectionnée, au moins l'un de « Signer les "
"assertions » et « Signer les réponses » doit être sélectionné."
#: authentik/providers/saml/api/providers.py #: authentik/providers/saml/api/providers.py
msgid "Invalid XML Syntax" msgid "Invalid XML Syntax"
msgstr "Syntaxe XML Invalide" msgstr "Syntaxe XML Invalide"
@ -1953,20 +1944,6 @@ msgstr ""
msgid "Signing Keypair" msgid "Signing Keypair"
msgstr "Paire de clés de Signature" msgstr "Paire de clés de Signature"
#: authentik/providers/saml/models.py authentik/sources/saml/models.py
msgid ""
"When selected, incoming assertions are encrypted by the IdP using the public"
" key of the encryption keypair. The assertion is decrypted by the SP using "
"the the private key."
msgstr ""
"Si activé, les assertions entrantes seront chiffrées par l'IdP avec la clé "
"publique de la paire de clé de chiffrement. L'assertion est déchiffrée par "
"le SP en utilisant la clé privée."
#: authentik/providers/saml/models.py authentik/sources/saml/models.py
msgid "Encryption Keypair"
msgstr "Paire de clés de chiffrement"
#: authentik/providers/saml/models.py #: authentik/providers/saml/models.py
msgid "Default relay_state value for IDP-initiated logins" msgid "Default relay_state value for IDP-initiated logins"
msgstr "Valeur par défaut de relay_state des connexions initiées par l'IdP" msgstr "Valeur par défaut de relay_state des connexions initiées par l'IdP"
@ -2489,6 +2466,20 @@ msgstr ""
"Paire de clés utilisées pour signer les réponses sortantes allant vers le " "Paire de clés utilisées pour signer les réponses sortantes allant vers le "
"fournisseur d'identité." "fournisseur d'identité."
#: authentik/sources/saml/models.py
msgid ""
"When selected, incoming assertions are encrypted by the IdP using the public"
" key of the encryption keypair. The assertion is decrypted by the SP using "
"the the private key."
msgstr ""
"Si activé, les assertions entrantes seront chiffrées par l'IdP avec la clé "
"publique de la paire de clé de chiffrement. L'assertion est déchiffrée par "
"le SP en utilisant la clé privée."
#: authentik/sources/saml/models.py
msgid "Encryption Keypair"
msgstr "Paire de clés de chiffrement"
#: authentik/sources/saml/models.py #: authentik/sources/saml/models.py
msgid "SAML Source" msgid "SAML Source"
msgstr "Source SAML" msgstr "Source SAML"

View File

@ -16,7 +16,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-08-18 00:08+0000\n" "POT-Creation-Date: 2024-08-15 00:09+0000\n"
"PO-Revision-Date: 2022-09-26 16:47+0000\n" "PO-Revision-Date: 2022-09-26 16:47+0000\n"
"Last-Translator: Anton Babenko, 2024\n" "Last-Translator: Anton Babenko, 2024\n"
"Language-Team: Russian (https://app.transifex.com/authentik/teams/119923/ru/)\n" "Language-Team: Russian (https://app.transifex.com/authentik/teams/119923/ru/)\n"
@ -739,7 +739,7 @@ msgstr "Правило Уведомления"
#: authentik/events/models.py #: authentik/events/models.py
msgid "Notification Rules" msgid "Notification Rules"
msgstr "Правила уведомлений" msgstr "Правило Уведомлений"
#: authentik/events/models.py #: authentik/events/models.py
msgid "Webhook Mapping" msgid "Webhook Mapping"
@ -1771,14 +1771,6 @@ msgstr "Сопоставление свойства Radius провайдера"
msgid "Radius Provider Property Mappings" msgid "Radius Provider Property Mappings"
msgstr "Сопоставление свойств Radius провайдера" msgstr "Сопоставление свойств Radius провайдера"
#: authentik/providers/saml/api/providers.py
msgid ""
"With a signing keypair selected, at least one of 'Sign assertion' and 'Sign "
"Response' must be selected."
msgstr ""
"При выборе пары ключей для подписи необходимо выбрать как минимум один из "
"вариантов: 'Подписывать утверждение' или 'Подписывать ответ'."
#: authentik/providers/saml/api/providers.py #: authentik/providers/saml/api/providers.py
msgid "Invalid XML Syntax" msgid "Invalid XML Syntax"
msgstr "Некорректный синтаксис XML" msgstr "Некорректный синтаксис XML"
@ -1926,21 +1918,6 @@ msgstr ""
msgid "Signing Keypair" msgid "Signing Keypair"
msgstr "Пара ключей для подписи" msgstr "Пара ключей для подписи"
#: authentik/providers/saml/models.py authentik/sources/saml/models.py
msgid ""
"When selected, incoming assertions are encrypted by the IdP using the public"
" key of the encryption keypair. The assertion is decrypted by the SP using "
"the the private key."
msgstr ""
"При выборе этого варианта, входящие утверждения шифруются поставщиком "
"идентификации (IdP) с использованием открытого ключа из пары ключей "
"шифрования. Утверждение расшифровывается поставщиком услуг (SP) с "
"использованием закрытого ключа."
#: authentik/providers/saml/models.py authentik/sources/saml/models.py
msgid "Encryption Keypair"
msgstr "Пара ключей шифрования"
#: authentik/providers/saml/models.py #: authentik/providers/saml/models.py
msgid "Default relay_state value for IDP-initiated logins" msgid "Default relay_state value for IDP-initiated logins"
msgstr "Значение relay_state по умолчанию для логинов, инициированных IDP" msgstr "Значение relay_state по умолчанию для логинов, инициированных IDP"
@ -2469,6 +2446,21 @@ msgstr ""
"Пара ключей, используемая для подписи исходящих ответов, направляемых " "Пара ключей, используемая для подписи исходящих ответов, направляемых "
"провайдеру идентификационных данных." "провайдеру идентификационных данных."
#: authentik/sources/saml/models.py
msgid ""
"When selected, incoming assertions are encrypted by the IdP using the public"
" key of the encryption keypair. The assertion is decrypted by the SP using "
"the the private key."
msgstr ""
"При выборе этого варианта, входящие утверждения шифруются поставщиком "
"идентификации (IdP) с использованием открытого ключа из пары ключей "
"шифрования. Утверждение расшифровывается поставщиком услуг (SP) с "
"использованием закрытого ключа."
#: authentik/sources/saml/models.py
msgid "Encryption Keypair"
msgstr "Пара ключей шифрования"
#: authentik/sources/saml/models.py #: authentik/sources/saml/models.py
msgid "SAML Source" msgid "SAML Source"
msgstr "Источник SAML" msgstr "Источник SAML"

Binary file not shown.

View File

@ -15,7 +15,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-09-25 00:08+0000\n" "POT-Creation-Date: 2024-08-18 00:08+0000\n"
"PO-Revision-Date: 2022-09-26 16:47+0000\n" "PO-Revision-Date: 2022-09-26 16:47+0000\n"
"Last-Translator: deluxghost, 2024\n" "Last-Translator: deluxghost, 2024\n"
"Language-Team: Chinese Simplified (https://app.transifex.com/authentik/teams/119923/zh-Hans/)\n" "Language-Team: Chinese Simplified (https://app.transifex.com/authentik/teams/119923/zh-Hans/)\n"
@ -25,11 +25,6 @@ msgstr ""
"Language: zh-Hans\n" "Language: zh-Hans\n"
"Plural-Forms: nplurals=1; plural=0;\n" "Plural-Forms: nplurals=1; plural=0;\n"
#: authentik/admin/tasks.py
#, python-brace-format
msgid "New version {version} available!"
msgstr "新版本 {version} 可用!"
#: authentik/api/schema.py #: authentik/api/schema.py
msgid "Generic API Error" msgid "Generic API Error"
msgstr "通用 API 错误" msgstr "通用 API 错误"
@ -1882,10 +1877,6 @@ msgstr "创建一个密钥,可用于恢复对 authentik 的访问权限。"
msgid "Used recovery-link to authenticate." msgid "Used recovery-link to authenticate."
msgstr "已使用恢复链接进行身份验证。" msgstr "已使用恢复链接进行身份验证。"
#: authentik/sources/ldap/api.py
msgid "Only a single LDAP Source with password synchronization is allowed"
msgstr "仅允许使用密码同步的单个 LDAP 源"
#: authentik/sources/ldap/models.py #: authentik/sources/ldap/models.py
msgid "Server URI" msgid "Server URI"
msgstr "服务器 URI" msgstr "服务器 URI"

Binary file not shown.

View File

@ -14,7 +14,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-09-25 00:08+0000\n" "POT-Creation-Date: 2024-08-18 00:08+0000\n"
"PO-Revision-Date: 2022-09-26 16:47+0000\n" "PO-Revision-Date: 2022-09-26 16:47+0000\n"
"Last-Translator: deluxghost, 2024\n" "Last-Translator: deluxghost, 2024\n"
"Language-Team: Chinese (China) (https://app.transifex.com/authentik/teams/119923/zh_CN/)\n" "Language-Team: Chinese (China) (https://app.transifex.com/authentik/teams/119923/zh_CN/)\n"
@ -24,11 +24,6 @@ msgstr ""
"Language: zh_CN\n" "Language: zh_CN\n"
"Plural-Forms: nplurals=1; plural=0;\n" "Plural-Forms: nplurals=1; plural=0;\n"
#: authentik/admin/tasks.py
#, python-brace-format
msgid "New version {version} available!"
msgstr "新版本 {version} 可用!"
#: authentik/api/schema.py #: authentik/api/schema.py
msgid "Generic API Error" msgid "Generic API Error"
msgstr "通用 API 错误" msgstr "通用 API 错误"
@ -1881,10 +1876,6 @@ msgstr "创建一个密钥,可用于恢复对 authentik 的访问权限。"
msgid "Used recovery-link to authenticate." msgid "Used recovery-link to authenticate."
msgstr "已使用恢复链接进行身份验证。" msgstr "已使用恢复链接进行身份验证。"
#: authentik/sources/ldap/api.py
msgid "Only a single LDAP Source with password synchronization is allowed"
msgstr "仅允许使用密码同步的单个 LDAP 源"
#: authentik/sources/ldap/models.py #: authentik/sources/ldap/models.py
msgid "Server URI" msgid "Server URI"
msgstr "服务器 URI" msgstr "服务器 URI"

View File

@ -1,5 +1,5 @@
{ {
"name": "@goauthentik/authentik", "name": "@goauthentik/authentik",
"version": "2024.8.3", "version": "2024.8.2",
"private": true "private": true
} }

569
poetry.lock generated
View File

@ -366,13 +366,13 @@ typing-extensions = ">=4.0.0"
[[package]] [[package]]
name = "bandit" name = "bandit"
version = "1.7.10" version = "1.7.9"
description = "Security oriented static analyser for python code." description = "Security oriented static analyser for python code."
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
{file = "bandit-1.7.10-py3-none-any.whl", hash = "sha256:665721d7bebbb4485a339c55161ac0eedde27d51e638000d91c8c2d68343ad02"}, {file = "bandit-1.7.9-py3-none-any.whl", hash = "sha256:52077cb339000f337fb25f7e045995c4ad01511e716e5daac37014b9752de8ec"},
{file = "bandit-1.7.10.tar.gz", hash = "sha256:59ed5caf5d92b6ada4bf65bc6437feea4a9da1093384445fed4d472acc6cff7b"}, {file = "bandit-1.7.9.tar.gz", hash = "sha256:7c395a436743018f7be0a4cbb0a4ea9b902b6d87264ddecf8cfdc73b4f78ff61"},
] ]
[package.dependencies] [package.dependencies]
@ -1134,49 +1134,46 @@ tests = ["django", "hypothesis", "pytest", "pytest-asyncio"]
[[package]] [[package]]
name = "debugpy" name = "debugpy"
version = "1.8.6" version = "1.8.5"
description = "An implementation of the Debug Adapter Protocol for Python" description = "An implementation of the Debug Adapter Protocol for Python"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
{file = "debugpy-1.8.6-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:30f467c5345d9dfdcc0afdb10e018e47f092e383447500f125b4e013236bf14b"}, {file = "debugpy-1.8.5-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:7e4d594367d6407a120b76bdaa03886e9eb652c05ba7f87e37418426ad2079f7"},
{file = "debugpy-1.8.6-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d73d8c52614432f4215d0fe79a7e595d0dd162b5c15233762565be2f014803b"}, {file = "debugpy-1.8.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4413b7a3ede757dc33a273a17d685ea2b0c09dbd312cc03f5534a0fd4d40750a"},
{file = "debugpy-1.8.6-cp310-cp310-win32.whl", hash = "sha256:e3e182cd98eac20ee23a00653503315085b29ab44ed66269482349d307b08df9"}, {file = "debugpy-1.8.5-cp310-cp310-win32.whl", hash = "sha256:dd3811bd63632bb25eda6bd73bea8e0521794cda02be41fa3160eb26fc29e7ed"},
{file = "debugpy-1.8.6-cp310-cp310-win_amd64.whl", hash = "sha256:e3a82da039cfe717b6fb1886cbbe5c4a3f15d7df4765af857f4307585121c2dd"}, {file = "debugpy-1.8.5-cp310-cp310-win_amd64.whl", hash = "sha256:b78c1250441ce893cb5035dd6f5fc12db968cc07f91cc06996b2087f7cefdd8e"},
{file = "debugpy-1.8.6-cp311-cp311-macosx_14_0_universal2.whl", hash = "sha256:67479a94cf5fd2c2d88f9615e087fcb4fec169ec780464a3f2ba4a9a2bb79955"}, {file = "debugpy-1.8.5-cp311-cp311-macosx_12_0_universal2.whl", hash = "sha256:606bccba19f7188b6ea9579c8a4f5a5364ecd0bf5a0659c8a5d0e10dcee3032a"},
{file = "debugpy-1.8.6-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fb8653f6cbf1dd0a305ac1aa66ec246002145074ea57933978346ea5afdf70b"}, {file = "debugpy-1.8.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db9fb642938a7a609a6c865c32ecd0d795d56c1aaa7a7a5722d77855d5e77f2b"},
{file = "debugpy-1.8.6-cp311-cp311-win32.whl", hash = "sha256:cdaf0b9691879da2d13fa39b61c01887c34558d1ff6e5c30e2eb698f5384cd43"}, {file = "debugpy-1.8.5-cp311-cp311-win32.whl", hash = "sha256:4fbb3b39ae1aa3e5ad578f37a48a7a303dad9a3d018d369bc9ec629c1cfa7408"},
{file = "debugpy-1.8.6-cp311-cp311-win_amd64.whl", hash = "sha256:43996632bee7435583952155c06881074b9a742a86cee74e701d87ca532fe833"}, {file = "debugpy-1.8.5-cp311-cp311-win_amd64.whl", hash = "sha256:345d6a0206e81eb68b1493ce2fbffd57c3088e2ce4b46592077a943d2b968ca3"},
{file = "debugpy-1.8.6-cp312-cp312-macosx_14_0_universal2.whl", hash = "sha256:db891b141fc6ee4b5fc6d1cc8035ec329cabc64bdd2ae672b4550c87d4ecb128"}, {file = "debugpy-1.8.5-cp312-cp312-macosx_12_0_universal2.whl", hash = "sha256:5b5c770977c8ec6c40c60d6f58cacc7f7fe5a45960363d6974ddb9b62dbee156"},
{file = "debugpy-1.8.6-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:567419081ff67da766c898ccf21e79f1adad0e321381b0dfc7a9c8f7a9347972"}, {file = "debugpy-1.8.5-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0a65b00b7cdd2ee0c2cf4c7335fef31e15f1b7056c7fdbce9e90193e1a8c8cb"},
{file = "debugpy-1.8.6-cp312-cp312-win32.whl", hash = "sha256:c9834dfd701a1f6bf0f7f0b8b1573970ae99ebbeee68314116e0ccc5c78eea3c"}, {file = "debugpy-1.8.5-cp312-cp312-win32.whl", hash = "sha256:c9f7c15ea1da18d2fcc2709e9f3d6de98b69a5b0fff1807fb80bc55f906691f7"},
{file = "debugpy-1.8.6-cp312-cp312-win_amd64.whl", hash = "sha256:e4ce0570aa4aca87137890d23b86faeadf184924ad892d20c54237bcaab75d8f"}, {file = "debugpy-1.8.5-cp312-cp312-win_amd64.whl", hash = "sha256:28ced650c974aaf179231668a293ecd5c63c0a671ae6d56b8795ecc5d2f48d3c"},
{file = "debugpy-1.8.6-cp38-cp38-macosx_14_0_x86_64.whl", hash = "sha256:df5dc9eb4ca050273b8e374a4cd967c43be1327eeb42bfe2f58b3cdfe7c68dcb"}, {file = "debugpy-1.8.5-cp38-cp38-macosx_12_0_x86_64.whl", hash = "sha256:3df6692351172a42af7558daa5019651f898fc67450bf091335aa8a18fbf6f3a"},
{file = "debugpy-1.8.6-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0a85707c6a84b0c5b3db92a2df685b5230dd8fb8c108298ba4f11dba157a615a"}, {file = "debugpy-1.8.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1cd04a73eb2769eb0bfe43f5bfde1215c5923d6924b9b90f94d15f207a402226"},
{file = "debugpy-1.8.6-cp38-cp38-win32.whl", hash = "sha256:538c6cdcdcdad310bbefd96d7850be1cd46e703079cc9e67d42a9ca776cdc8a8"}, {file = "debugpy-1.8.5-cp38-cp38-win32.whl", hash = "sha256:8f913ee8e9fcf9d38a751f56e6de12a297ae7832749d35de26d960f14280750a"},
{file = "debugpy-1.8.6-cp38-cp38-win_amd64.whl", hash = "sha256:22140bc02c66cda6053b6eb56dfe01bbe22a4447846581ba1dd6df2c9f97982d"}, {file = "debugpy-1.8.5-cp38-cp38-win_amd64.whl", hash = "sha256:a697beca97dad3780b89a7fb525d5e79f33821a8bc0c06faf1f1289e549743cf"},
{file = "debugpy-1.8.6-cp39-cp39-macosx_14_0_x86_64.whl", hash = "sha256:c1cef65cffbc96e7b392d9178dbfd524ab0750da6c0023c027ddcac968fd1caa"}, {file = "debugpy-1.8.5-cp39-cp39-macosx_12_0_x86_64.whl", hash = "sha256:0a1029a2869d01cb777216af8c53cda0476875ef02a2b6ff8b2f2c9a4b04176c"},
{file = "debugpy-1.8.6-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f1e60bd06bb3cc5c0e957df748d1fab501e01416c43a7bdc756d2a992ea1b881"}, {file = "debugpy-1.8.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e84c276489e141ed0b93b0af648eef891546143d6a48f610945416453a8ad406"},
{file = "debugpy-1.8.6-cp39-cp39-win32.whl", hash = "sha256:f7158252803d0752ed5398d291dee4c553bb12d14547c0e1843ab74ee9c31123"}, {file = "debugpy-1.8.5-cp39-cp39-win32.whl", hash = "sha256:ad84b7cde7fd96cf6eea34ff6c4a1b7887e0fe2ea46e099e53234856f9d99a34"},
{file = "debugpy-1.8.6-cp39-cp39-win_amd64.whl", hash = "sha256:3358aa619a073b620cd0d51d8a6176590af24abcc3fe2e479929a154bf591b51"}, {file = "debugpy-1.8.5-cp39-cp39-win_amd64.whl", hash = "sha256:7b0fe36ed9d26cb6836b0a51453653f8f2e347ba7348f2bbfe76bfeb670bfb1c"},
{file = "debugpy-1.8.6-py2.py3-none-any.whl", hash = "sha256:b48892df4d810eff21d3ef37274f4c60d32cdcafc462ad5647239036b0f0649f"}, {file = "debugpy-1.8.5-py2.py3-none-any.whl", hash = "sha256:55919dce65b471eff25901acf82d328bbd5b833526b6c1364bd5133754777a44"},
{file = "debugpy-1.8.6.zip", hash = "sha256:c931a9371a86784cee25dec8d65bc2dc7a21f3f1552e3833d9ef8f919d22280a"}, {file = "debugpy-1.8.5.zip", hash = "sha256:b2112cfeb34b4507399d298fe7023a16656fc553ed5246536060ca7bd0e668d0"},
] ]
[[package]] [[package]]
name = "deepmerge" name = "deepmerge"
version = "2.0" version = "1.1.1"
description = "A toolset for deeply merging Python dictionaries." description = "a toolset to deeply merge python dictionaries."
optional = false optional = false
python-versions = ">=3.8" python-versions = "*"
files = [ files = [
{file = "deepmerge-2.0-py3-none-any.whl", hash = "sha256:6de9ce507115cff0bed95ff0ce9ecc31088ef50cbdf09bc90a09349a318b3d00"}, {file = "deepmerge-1.1.1-py3-none-any.whl", hash = "sha256:7219dad9763f15be9dcd4bcb53e00f48e4eed6f5ed8f15824223eb934bb35977"},
{file = "deepmerge-2.0.tar.gz", hash = "sha256:5c3d86081fbebd04dd5de03626a0607b809a98fb6ccba5770b62466fe940ff20"}, {file = "deepmerge-1.1.1.tar.gz", hash = "sha256:53a489dc9449636e480a784359ae2aab3191748c920649551c8e378622f0eca4"},
] ]
[package.extras]
dev = ["black", "build", "mypy", "pytest", "pyupgrade", "twine", "validate-pyproject[all]"]
[[package]] [[package]]
name = "defusedxml" name = "defusedxml"
version = "0.7.1" version = "0.7.1"
@ -1207,13 +1204,13 @@ dev = ["PyTest", "PyTest-Cov", "bump2version (<1)", "sphinx (<2)", "tox"]
[[package]] [[package]]
name = "django" name = "django"
version = "5.0.9" version = "5.0.8"
description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design." description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design."
optional = false optional = false
python-versions = ">=3.10" python-versions = ">=3.10"
files = [ files = [
{file = "Django-5.0.9-py3-none-any.whl", hash = "sha256:f219576ba53be4e83f485130a7283f0efde06a9f2e3a7c3c5180327549f078fa"}, {file = "Django-5.0.8-py3-none-any.whl", hash = "sha256:333a7988f7ca4bc14d360d3d8f6b793704517761ae3813b95432043daec22a45"},
{file = "Django-5.0.9.tar.gz", hash = "sha256:6333870d342329b60174da3a60dbd302e533f3b0bb0971516750e974a99b5a39"}, {file = "Django-5.0.8.tar.gz", hash = "sha256:ebe859c9da6fead9c9ee6dbfa4943b04f41342f4cea2c4d8c978ef0d10694f2b"},
] ]
[package.dependencies] [package.dependencies]
@ -1287,13 +1284,13 @@ Django = ">=2.2"
[[package]] [[package]]
name = "django-model-utils" name = "django-model-utils"
version = "5.0.0" version = "4.5.1"
description = "Django model mixins and utilities" description = "Django model mixins and utilities"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
{file = "django_model_utils-5.0.0-py3-none-any.whl", hash = "sha256:fec78e6c323d565a221f7c4edc703f4567d7bb1caeafe1acd16a80c5ff82056b"}, {file = "django_model_utils-4.5.1-py3-none-any.whl", hash = "sha256:f1141fc71796242edeffed5ad53a8cc57f00d345eb5a3a63e3f69401cd562ee2"},
{file = "django_model_utils-5.0.0.tar.gz", hash = "sha256:041cdd6230d2fbf6cd943e1969318bce762272077f4ecd333ab2263924b4e5eb"}, {file = "django_model_utils-4.5.1.tar.gz", hash = "sha256:1220f22d9a467d53a1e0f4cda4857df0b2f757edf9a29955c42461988caa648a"},
] ]
[package.dependencies] [package.dependencies]
@ -1315,13 +1312,13 @@ django = ">=3"
[[package]] [[package]]
name = "django-pglock" name = "django-pglock"
version = "1.6.2" version = "1.6.0"
description = "Postgres locking routines and lock table access." description = "Postgres locking routines and lock table access."
optional = false optional = false
python-versions = "<4,>=3.8.0" python-versions = "<4,>=3.8.0"
files = [ files = [
{file = "django_pglock-1.6.2-py3-none-any.whl", hash = "sha256:abdb92531bf8cb36471dc9eb33ed163b06bd3323140d132ed4f308b9e5505f50"}, {file = "django_pglock-1.6.0-py3-none-any.whl", hash = "sha256:41c98d0bd3738d11e6eaefcc3e5146028f118a593ac58c13d663b751170f01de"},
{file = "django_pglock-1.6.2.tar.gz", hash = "sha256:05db998cab21556d4a307eac4b5db8e50f874f42b1a581560b3c54610fee6a1b"}, {file = "django_pglock-1.6.0.tar.gz", hash = "sha256:724450ecc9886f39af599c477d84ad086545a5373215ef7a670cd25faca25a61"},
] ]
[package.dependencies] [package.dependencies]
@ -1566,16 +1563,6 @@ files = [
setuptools = "*" setuptools = "*"
six = "*" six = "*"
[[package]]
name = "durationpy"
version = "0.7"
description = "Module for converting between datetime.timedelta and Go's Duration strings."
optional = false
python-versions = "*"
files = [
{file = "durationpy-0.7.tar.gz", hash = "sha256:8447c43df4f1a0b434e70c15a38d77f5c9bd17284bfc1ff1d430f233d5083732"},
]
[[package]] [[package]]
name = "email-validator" name = "email-validator"
version = "2.2.0" version = "2.2.0"
@ -1771,13 +1758,13 @@ grpcio-gcp = ["grpcio-gcp (>=0.2.2,<1.0.dev0)"]
[[package]] [[package]]
name = "google-api-python-client" name = "google-api-python-client"
version = "2.147.0" version = "2.142.0"
description = "Google API Client Library for Python" description = "Google API Client Library for Python"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
{file = "google_api_python_client-2.147.0-py2.py3-none-any.whl", hash = "sha256:c6ecfa193c695baa41e84562d8f8f244fcd164419eca3fc9fd7565646668f9b2"}, {file = "google_api_python_client-2.142.0-py2.py3-none-any.whl", hash = "sha256:266799082bb8301f423ec204dffbffb470b502abbf29efd1f83e644d36eb5a8f"},
{file = "google_api_python_client-2.147.0.tar.gz", hash = "sha256:e864c2cf61d34c00f05278b8bdb72b93b6fa34f0de9ead51d20435f3b65f91be"}, {file = "google_api_python_client-2.142.0.tar.gz", hash = "sha256:a1101ac9e24356557ca22f07ff48b7f61fa5d4b4e7feeef3bda16e5dcb86350e"},
] ]
[package.dependencies] [package.dependencies]
@ -2060,13 +2047,13 @@ files = [
[[package]] [[package]]
name = "importlib-metadata" name = "importlib-metadata"
version = "8.4.0" version = "8.0.0"
description = "Read metadata from Python packages" description = "Read metadata from Python packages"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
{file = "importlib_metadata-8.4.0-py3-none-any.whl", hash = "sha256:66f342cc6ac9818fc6ff340576acd24d65ba0b3efabb2b4ac08b598965a4a2f1"}, {file = "importlib_metadata-8.0.0-py3-none-any.whl", hash = "sha256:15584cf2b1bf449d98ff8a6ff1abef57bf20f3ac6454f431736cd3e660921b2f"},
{file = "importlib_metadata-8.4.0.tar.gz", hash = "sha256:9a547d3bc3608b025f93d403fdd1aae741c24fbb8314df4b155675742ce303c5"}, {file = "importlib_metadata-8.0.0.tar.gz", hash = "sha256:188bd24e4c346d3f0a933f275c2fec67050326a856b9a359881d7c2a697e8812"},
] ]
[package.dependencies] [package.dependencies]
@ -2253,18 +2240,17 @@ zookeeper = ["kazoo (>=2.8.0)"]
[[package]] [[package]]
name = "kubernetes" name = "kubernetes"
version = "31.0.0" version = "30.1.0"
description = "Kubernetes python client" description = "Kubernetes python client"
optional = false optional = false
python-versions = ">=3.6" python-versions = ">=3.6"
files = [ files = [
{file = "kubernetes-31.0.0-py2.py3-none-any.whl", hash = "sha256:bf141e2d380c8520eada8b351f4e319ffee9636328c137aa432bc486ca1200e1"}, {file = "kubernetes-30.1.0-py2.py3-none-any.whl", hash = "sha256:e212e8b7579031dd2e512168b617373bc1e03888d41ac4e04039240a292d478d"},
{file = "kubernetes-31.0.0.tar.gz", hash = "sha256:28945de906c8c259c1ebe62703b56a03b714049372196f854105afe4e6d014c0"}, {file = "kubernetes-30.1.0.tar.gz", hash = "sha256:41e4c77af9f28e7a6c314e3bd06a8c6229ddd787cad684e0ab9f69b498e98ebc"},
] ]
[package.dependencies] [package.dependencies]
certifi = ">=14.05.14" certifi = ">=14.05.14"
durationpy = ">=0.7"
google-auth = ">=1.0.1" google-auth = ">=1.0.1"
oauthlib = ">=3.2.2" oauthlib = ">=3.2.2"
python-dateutil = ">=2.5.3" python-dateutil = ">=2.5.3"
@ -2859,13 +2845,13 @@ dev = ["bumpver", "isort", "mypy", "pylint", "pytest", "yapf"]
[[package]] [[package]]
name = "msgraph-sdk" name = "msgraph-sdk"
version = "1.8.0" version = "1.5.4"
description = "The Microsoft Graph Python SDK" description = "The Microsoft Graph Python SDK"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
{file = "msgraph_sdk-1.8.0-py3-none-any.whl", hash = "sha256:22a8e4a63f989865228f66a54501bef8105909c7156fe0a079ca9b5296339cc2"}, {file = "msgraph_sdk-1.5.4-py3-none-any.whl", hash = "sha256:9ea349f30cc4a03edb587e26554c7a4839a38c2ef30d4b5396882fd2be82dcac"},
{file = "msgraph_sdk-1.8.0.tar.gz", hash = "sha256:1ac84bd47ea288a84f46f6c6d0c89d164ee3453b917615632652344538098314"}, {file = "msgraph_sdk-1.5.4.tar.gz", hash = "sha256:b0e146328d136d1db175938d8fc901f3bb32acf3ea6fe93c0dc7c5a0abc45e39"},
] ]
[package.dependencies] [package.dependencies]
@ -3039,49 +3025,49 @@ resolved_reference = "20d69d9cc50a0fef31605b46f06da0c94f1ec3cf"
[[package]] [[package]]
name = "opentelemetry-api" name = "opentelemetry-api"
version = "1.27.0" version = "1.26.0"
description = "OpenTelemetry Python API" description = "OpenTelemetry Python API"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
{file = "opentelemetry_api-1.27.0-py3-none-any.whl", hash = "sha256:953d5871815e7c30c81b56d910c707588000fff7a3ca1c73e6531911d53065e7"}, {file = "opentelemetry_api-1.26.0-py3-none-any.whl", hash = "sha256:7d7ea33adf2ceda2dd680b18b1677e4152000b37ca76e679da71ff103b943064"},
{file = "opentelemetry_api-1.27.0.tar.gz", hash = "sha256:ed673583eaa5f81b5ce5e86ef7cdaf622f88ef65f0b9aab40b843dcae5bef342"}, {file = "opentelemetry_api-1.26.0.tar.gz", hash = "sha256:2bd639e4bed5b18486fef0b5a520aaffde5a18fc225e808a1ac4df363f43a1ce"},
] ]
[package.dependencies] [package.dependencies]
deprecated = ">=1.2.6" deprecated = ">=1.2.6"
importlib-metadata = ">=6.0,<=8.4.0" importlib-metadata = ">=6.0,<=8.0.0"
[[package]] [[package]]
name = "opentelemetry-sdk" name = "opentelemetry-sdk"
version = "1.27.0" version = "1.26.0"
description = "OpenTelemetry Python SDK" description = "OpenTelemetry Python SDK"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
{file = "opentelemetry_sdk-1.27.0-py3-none-any.whl", hash = "sha256:365f5e32f920faf0fd9e14fdfd92c086e317eaa5f860edba9cdc17a380d9197d"}, {file = "opentelemetry_sdk-1.26.0-py3-none-any.whl", hash = "sha256:feb5056a84a88670c041ea0ded9921fca559efec03905dddeb3885525e0af897"},
{file = "opentelemetry_sdk-1.27.0.tar.gz", hash = "sha256:d525017dea0ccce9ba4e0245100ec46ecdc043f2d7b8315d56b19aff0904fa6f"}, {file = "opentelemetry_sdk-1.26.0.tar.gz", hash = "sha256:c90d2868f8805619535c05562d699e2f4fb1f00dbd55a86dcefca4da6fa02f85"},
] ]
[package.dependencies] [package.dependencies]
opentelemetry-api = "1.27.0" opentelemetry-api = "1.26.0"
opentelemetry-semantic-conventions = "0.48b0" opentelemetry-semantic-conventions = "0.47b0"
typing-extensions = ">=3.7.4" typing-extensions = ">=3.7.4"
[[package]] [[package]]
name = "opentelemetry-semantic-conventions" name = "opentelemetry-semantic-conventions"
version = "0.48b0" version = "0.47b0"
description = "OpenTelemetry Semantic Conventions" description = "OpenTelemetry Semantic Conventions"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
{file = "opentelemetry_semantic_conventions-0.48b0-py3-none-any.whl", hash = "sha256:a0de9f45c413a8669788a38569c7e0a11ce6ce97861a628cca785deecdc32a1f"}, {file = "opentelemetry_semantic_conventions-0.47b0-py3-none-any.whl", hash = "sha256:4ff9d595b85a59c1c1413f02bba320ce7ea6bf9e2ead2b0913c4395c7bbc1063"},
{file = "opentelemetry_semantic_conventions-0.48b0.tar.gz", hash = "sha256:12d74983783b6878162208be57c9effcb89dc88691c64992d70bb89dc00daa1a"}, {file = "opentelemetry_semantic_conventions-0.47b0.tar.gz", hash = "sha256:a8d57999bbe3495ffd4d510de26a97dadc1dace53e0275001b2c1b2f67992a7e"},
] ]
[package.dependencies] [package.dependencies]
deprecated = ">=1.2.6" deprecated = ">=1.2.6"
opentelemetry-api = "1.27.0" opentelemetry-api = "1.26.0"
[[package]] [[package]]
name = "orjson" name = "orjson"
@ -3172,13 +3158,13 @@ files = [
[[package]] [[package]]
name = "paramiko" name = "paramiko"
version = "3.5.0" version = "3.4.1"
description = "SSH2 protocol library" description = "SSH2 protocol library"
optional = false optional = false
python-versions = ">=3.6" python-versions = ">=3.6"
files = [ files = [
{file = "paramiko-3.5.0-py3-none-any.whl", hash = "sha256:1fedf06b085359051cd7d0d270cebe19e755a8a921cc2ddbfa647fb0cd7d68f9"}, {file = "paramiko-3.4.1-py3-none-any.whl", hash = "sha256:8e49fd2f82f84acf7ffd57c64311aa2b30e575370dc23bdb375b10262f7eac32"},
{file = "paramiko-3.5.0.tar.gz", hash = "sha256:ad11e540da4f55cedda52931f1a3f812a8238a7af7f62a60de538cd80bb28124"}, {file = "paramiko-3.4.1.tar.gz", hash = "sha256:8b15302870af7f6652f2e038975c1d2973f06046cb5d7d65355668b3ecbece0c"},
] ]
[package.dependencies] [package.dependencies]
@ -3215,13 +3201,13 @@ files = [
[[package]] [[package]]
name = "pdoc" name = "pdoc"
version = "14.7.0" version = "14.6.0"
description = "API Documentation for Python Projects" description = "API Documentation for Python Projects"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
{file = "pdoc-14.7.0-py3-none-any.whl", hash = "sha256:72377a907efc6b2c5b3c56b717ef34f11d93621dced3b663f3aede0b844c0ad2"}, {file = "pdoc-14.6.0-py3-none-any.whl", hash = "sha256:36c42c546a317d8e3e8c0b39645f24161374de0c7066ccaae76628d721e49ba5"},
{file = "pdoc-14.7.0.tar.gz", hash = "sha256:2d28af9c0acc39180744ad0543e4bbc3223ecba0d1302db315ec521c51f71f93"}, {file = "pdoc-14.6.0.tar.gz", hash = "sha256:6e98a24c5e0ca5d188397969cf82581836eaef13f172fc3820047bfe15c61c9a"},
] ]
[package.dependencies] [package.dependencies]
@ -3448,36 +3434,36 @@ files = [
[[package]] [[package]]
name = "psycopg" name = "psycopg"
version = "3.2.3" version = "3.2.1"
description = "PostgreSQL database adapter for Python" description = "PostgreSQL database adapter for Python"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
{file = "psycopg-3.2.3-py3-none-any.whl", hash = "sha256:644d3973fe26908c73d4be746074f6e5224b03c1101d302d9a53bf565ad64907"}, {file = "psycopg-3.2.1-py3-none-any.whl", hash = "sha256:ece385fb413a37db332f97c49208b36cf030ff02b199d7635ed2fbd378724175"},
{file = "psycopg-3.2.3.tar.gz", hash = "sha256:a5764f67c27bec8bfac85764d23c534af2c27b893550377e37ce59c12aac47a2"}, {file = "psycopg-3.2.1.tar.gz", hash = "sha256:dc8da6dc8729dacacda3cc2f17d2c9397a70a66cf0d2b69c91065d60d5f00cb7"},
] ]
[package.dependencies] [package.dependencies]
psycopg-c = {version = "3.2.3", optional = true, markers = "implementation_name != \"pypy\" and extra == \"c\""} psycopg-c = {version = "3.2.1", optional = true, markers = "implementation_name != \"pypy\" and extra == \"c\""}
typing-extensions = {version = ">=4.6", markers = "python_version < \"3.13\""} typing-extensions = ">=4.4"
tzdata = {version = "*", markers = "sys_platform == \"win32\""} tzdata = {version = "*", markers = "sys_platform == \"win32\""}
[package.extras] [package.extras]
binary = ["psycopg-binary (==3.2.3)"] binary = ["psycopg-binary (==3.2.1)"]
c = ["psycopg-c (==3.2.3)"] c = ["psycopg-c (==3.2.1)"]
dev = ["ast-comments (>=1.1.2)", "black (>=24.1.0)", "codespell (>=2.2)", "dnspython (>=2.1)", "flake8 (>=4.0)", "mypy (>=1.11)", "types-setuptools (>=57.4)", "wheel (>=0.37)"] dev = ["ast-comments (>=1.1.2)", "black (>=24.1.0)", "codespell (>=2.2)", "dnspython (>=2.1)", "flake8 (>=4.0)", "mypy (>=1.6)", "types-setuptools (>=57.4)", "wheel (>=0.37)"]
docs = ["Sphinx (>=5.0)", "furo (==2022.6.21)", "sphinx-autobuild (>=2021.3.14)", "sphinx-autodoc-typehints (>=1.12)"] docs = ["Sphinx (>=5.0)", "furo (==2022.6.21)", "sphinx-autobuild (>=2021.3.14)", "sphinx-autodoc-typehints (>=1.12)"]
pool = ["psycopg-pool"] pool = ["psycopg-pool"]
test = ["anyio (>=4.0)", "mypy (>=1.11)", "pproxy (>=2.7)", "pytest (>=6.2.5)", "pytest-cov (>=3.0)", "pytest-randomly (>=3.5)"] test = ["anyio (>=4.0)", "mypy (>=1.6)", "pproxy (>=2.7)", "pytest (>=6.2.5)", "pytest-cov (>=3.0)", "pytest-randomly (>=3.5)"]
[[package]] [[package]]
name = "psycopg-c" name = "psycopg-c"
version = "3.2.3" version = "3.2.1"
description = "PostgreSQL database adapter for Python -- C optimisation distribution" description = "PostgreSQL database adapter for Python -- C optimisation distribution"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
{file = "psycopg_c-3.2.3.tar.gz", hash = "sha256:06ae7db8eaec1a3845960fa7f997f4ccdb1a7a7ab8dc593a680bcc74e1359671"}, {file = "psycopg_c-3.2.1.tar.gz", hash = "sha256:2d09943cc8a855c42c1e23b4298957b7ce8f27bf3683258c52fd139f601f7cda"},
] ]
[[package]] [[package]]
@ -3518,121 +3504,120 @@ files = [
[[package]] [[package]]
name = "pydantic" name = "pydantic"
version = "2.9.2" version = "2.8.2"
description = "Data validation using Python type hints" description = "Data validation using Python type hints"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
{file = "pydantic-2.9.2-py3-none-any.whl", hash = "sha256:f048cec7b26778210e28a0459867920654d48e5e62db0958433636cde4254f12"}, {file = "pydantic-2.8.2-py3-none-any.whl", hash = "sha256:73ee9fddd406dc318b885c7a2eab8a6472b68b8fb5ba8150949fc3db939f23c8"},
{file = "pydantic-2.9.2.tar.gz", hash = "sha256:d155cef71265d1e9807ed1c32b4c8deec042a44a50a4188b25ac67ecd81a9c0f"}, {file = "pydantic-2.8.2.tar.gz", hash = "sha256:6f62c13d067b0755ad1c21a34bdd06c0c12625a22b0fc09c6b149816604f7c2a"},
] ]
[package.dependencies] [package.dependencies]
annotated-types = ">=0.6.0" annotated-types = ">=0.4.0"
email-validator = {version = ">=2.0.0", optional = true, markers = "extra == \"email\""} email-validator = {version = ">=2.0.0", optional = true, markers = "extra == \"email\""}
pydantic-core = "2.23.4" pydantic-core = "2.20.1"
typing-extensions = {version = ">=4.6.1", markers = "python_version < \"3.13\""} typing-extensions = {version = ">=4.6.1", markers = "python_version < \"3.13\""}
[package.extras] [package.extras]
email = ["email-validator (>=2.0.0)"] email = ["email-validator (>=2.0.0)"]
timezone = ["tzdata"]
[[package]] [[package]]
name = "pydantic-core" name = "pydantic-core"
version = "2.23.4" version = "2.20.1"
description = "Core functionality for Pydantic validation and serialization" description = "Core functionality for Pydantic validation and serialization"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
{file = "pydantic_core-2.23.4-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:b10bd51f823d891193d4717448fab065733958bdb6a6b351967bd349d48d5c9b"}, {file = "pydantic_core-2.20.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3acae97ffd19bf091c72df4d726d552c473f3576409b2a7ca36b2f535ffff4a3"},
{file = "pydantic_core-2.23.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4fc714bdbfb534f94034efaa6eadd74e5b93c8fa6315565a222f7b6f42ca1166"}, {file = "pydantic_core-2.20.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:41f4c96227a67a013e7de5ff8f20fb496ce573893b7f4f2707d065907bffdbd6"},
{file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63e46b3169866bd62849936de036f901a9356e36376079b05efa83caeaa02ceb"}, {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f239eb799a2081495ea659d8d4a43a8f42cd1fe9ff2e7e436295c38a10c286a"},
{file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed1a53de42fbe34853ba90513cea21673481cd81ed1be739f7f2efb931b24916"}, {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:53e431da3fc53360db73eedf6f7124d1076e1b4ee4276b36fb25514544ceb4a3"},
{file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cfdd16ab5e59fc31b5e906d1a3f666571abc367598e3e02c83403acabc092e07"}, {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f1f62b2413c3a0e846c3b838b2ecd6c7a19ec6793b2a522745b0869e37ab5bc1"},
{file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:255a8ef062cbf6674450e668482456abac99a5583bbafb73f9ad469540a3a232"}, {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5d41e6daee2813ecceea8eda38062d69e280b39df793f5a942fa515b8ed67953"},
{file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a7cd62e831afe623fbb7aabbb4fe583212115b3ef38a9f6b71869ba644624a2"}, {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d482efec8b7dc6bfaedc0f166b2ce349df0011f5d2f1f25537ced4cfc34fd98"},
{file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f09e2ff1f17c2b51f2bc76d1cc33da96298f0a036a137f5440ab3ec5360b624f"}, {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e93e1a4b4b33daed65d781a57a522ff153dcf748dee70b40c7258c5861e1768a"},
{file = "pydantic_core-2.23.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e38e63e6f3d1cec5a27e0afe90a085af8b6806ee208b33030e65b6516353f1a3"}, {file = "pydantic_core-2.20.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e7c4ea22b6739b162c9ecaaa41d718dfad48a244909fe7ef4b54c0b530effc5a"},
{file = "pydantic_core-2.23.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0dbd8dbed2085ed23b5c04afa29d8fd2771674223135dc9bc937f3c09284d071"}, {file = "pydantic_core-2.20.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4f2790949cf385d985a31984907fecb3896999329103df4e4983a4a41e13e840"},
{file = "pydantic_core-2.23.4-cp310-none-win32.whl", hash = "sha256:6531b7ca5f951d663c339002e91aaebda765ec7d61b7d1e3991051906ddde119"}, {file = "pydantic_core-2.20.1-cp310-none-win32.whl", hash = "sha256:5e999ba8dd90e93d57410c5e67ebb67ffcaadcea0ad973240fdfd3a135506250"},
{file = "pydantic_core-2.23.4-cp310-none-win_amd64.whl", hash = "sha256:7c9129eb40958b3d4500fa2467e6a83356b3b61bfff1b414c7361d9220f9ae8f"}, {file = "pydantic_core-2.20.1-cp310-none-win_amd64.whl", hash = "sha256:512ecfbefef6dac7bc5eaaf46177b2de58cdf7acac8793fe033b24ece0b9566c"},
{file = "pydantic_core-2.23.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:77733e3892bb0a7fa797826361ce8a9184d25c8dffaec60b7ffe928153680ba8"}, {file = "pydantic_core-2.20.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d2a8fa9d6d6f891f3deec72f5cc668e6f66b188ab14bb1ab52422fe8e644f312"},
{file = "pydantic_core-2.23.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b84d168f6c48fabd1f2027a3d1bdfe62f92cade1fb273a5d68e621da0e44e6d"}, {file = "pydantic_core-2.20.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:175873691124f3d0da55aeea1d90660a6ea7a3cfea137c38afa0a5ffabe37b88"},
{file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df49e7a0861a8c36d089c1ed57d308623d60416dab2647a4a17fe050ba85de0e"}, {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:37eee5b638f0e0dcd18d21f59b679686bbd18917b87db0193ae36f9c23c355fc"},
{file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ff02b6d461a6de369f07ec15e465a88895f3223eb75073ffea56b84d9331f607"}, {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:25e9185e2d06c16ee438ed39bf62935ec436474a6ac4f9358524220f1b236e43"},
{file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:996a38a83508c54c78a5f41456b0103c30508fed9abcad0a59b876d7398f25fd"}, {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:150906b40ff188a3260cbee25380e7494ee85048584998c1e66df0c7a11c17a6"},
{file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d97683ddee4723ae8c95d1eddac7c192e8c552da0c73a925a89fa8649bf13eea"}, {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ad4aeb3e9a97286573c03df758fc7627aecdd02f1da04516a86dc159bf70121"},
{file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:216f9b2d7713eb98cb83c80b9c794de1f6b7e3145eef40400c62e86cee5f4e1e"}, {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3f3ed29cd9f978c604708511a1f9c2fdcb6c38b9aae36a51905b8811ee5cbf1"},
{file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6f783e0ec4803c787bcea93e13e9932edab72068f68ecffdf86a99fd5918878b"}, {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b0dae11d8f5ded51699c74d9548dcc5938e0804cc8298ec0aa0da95c21fff57b"},
{file = "pydantic_core-2.23.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d0776dea117cf5272382634bd2a5c1b6eb16767c223c6a5317cd3e2a757c61a0"}, {file = "pydantic_core-2.20.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:faa6b09ee09433b87992fb5a2859efd1c264ddc37280d2dd5db502126d0e7f27"},
{file = "pydantic_core-2.23.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d5f7a395a8cf1621939692dba2a6b6a830efa6b3cee787d82c7de1ad2930de64"}, {file = "pydantic_core-2.20.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9dc1b507c12eb0481d071f3c1808f0529ad41dc415d0ca11f7ebfc666e66a18b"},
{file = "pydantic_core-2.23.4-cp311-none-win32.whl", hash = "sha256:74b9127ffea03643e998e0c5ad9bd3811d3dac8c676e47db17b0ee7c3c3bf35f"}, {file = "pydantic_core-2.20.1-cp311-none-win32.whl", hash = "sha256:fa2fddcb7107e0d1808086ca306dcade7df60a13a6c347a7acf1ec139aa6789a"},
{file = "pydantic_core-2.23.4-cp311-none-win_amd64.whl", hash = "sha256:98d134c954828488b153d88ba1f34e14259284f256180ce659e8d83e9c05eaa3"}, {file = "pydantic_core-2.20.1-cp311-none-win_amd64.whl", hash = "sha256:40a783fb7ee353c50bd3853e626f15677ea527ae556429453685ae32280c19c2"},
{file = "pydantic_core-2.23.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f3e0da4ebaef65158d4dfd7d3678aad692f7666877df0002b8a522cdf088f231"}, {file = "pydantic_core-2.20.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:595ba5be69b35777474fa07f80fc260ea71255656191adb22a8c53aba4479231"},
{file = "pydantic_core-2.23.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f69a8e0b033b747bb3e36a44e7732f0c99f7edd5cea723d45bc0d6e95377ffee"}, {file = "pydantic_core-2.20.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a4f55095ad087474999ee28d3398bae183a66be4823f753cd7d67dd0153427c9"},
{file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:723314c1d51722ab28bfcd5240d858512ffd3116449c557a1336cbe3919beb87"}, {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f9aa05d09ecf4c75157197f27cdc9cfaeb7c5f15021c6373932bf3e124af029f"},
{file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bb2802e667b7051a1bebbfe93684841cc9351004e2badbd6411bf357ab8d5ac8"}, {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e97fdf088d4b31ff4ba35db26d9cc472ac7ef4a2ff2badeabf8d727b3377fc52"},
{file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d18ca8148bebe1b0a382a27a8ee60350091a6ddaf475fa05ef50dc35b5df6327"}, {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bc633a9fe1eb87e250b5c57d389cf28998e4292336926b0b6cdaee353f89a237"},
{file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33e3d65a85a2a4a0dc3b092b938a4062b1a05f3a9abde65ea93b233bca0e03f2"}, {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d573faf8eb7e6b1cbbcb4f5b247c60ca8be39fe2c674495df0eb4318303137fe"},
{file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:128585782e5bfa515c590ccee4b727fb76925dd04a98864182b22e89a4e6ed36"}, {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26dc97754b57d2fd00ac2b24dfa341abffc380b823211994c4efac7f13b9e90e"},
{file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:68665f4c17edcceecc112dfed5dbe6f92261fb9d6054b47d01bf6371a6196126"}, {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:33499e85e739a4b60c9dac710c20a08dc73cb3240c9a0e22325e671b27b70d24"},
{file = "pydantic_core-2.23.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:20152074317d9bed6b7a95ade3b7d6054845d70584216160860425f4fbd5ee9e"}, {file = "pydantic_core-2.20.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:bebb4d6715c814597f85297c332297c6ce81e29436125ca59d1159b07f423eb1"},
{file = "pydantic_core-2.23.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9261d3ce84fa1d38ed649c3638feefeae23d32ba9182963e465d58d62203bd24"}, {file = "pydantic_core-2.20.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:516d9227919612425c8ef1c9b869bbbee249bc91912c8aaffb66116c0b447ebd"},
{file = "pydantic_core-2.23.4-cp312-none-win32.whl", hash = "sha256:4ba762ed58e8d68657fc1281e9bb72e1c3e79cc5d464be146e260c541ec12d84"}, {file = "pydantic_core-2.20.1-cp312-none-win32.whl", hash = "sha256:469f29f9093c9d834432034d33f5fe45699e664f12a13bf38c04967ce233d688"},
{file = "pydantic_core-2.23.4-cp312-none-win_amd64.whl", hash = "sha256:97df63000f4fea395b2824da80e169731088656d1818a11b95f3b173747b6cd9"}, {file = "pydantic_core-2.20.1-cp312-none-win_amd64.whl", hash = "sha256:035ede2e16da7281041f0e626459bcae33ed998cca6a0a007a5ebb73414ac72d"},
{file = "pydantic_core-2.23.4-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:7530e201d10d7d14abce4fb54cfe5b94a0aefc87da539d0346a484ead376c3cc"}, {file = "pydantic_core-2.20.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:0827505a5c87e8aa285dc31e9ec7f4a17c81a813d45f70b1d9164e03a813a686"},
{file = "pydantic_core-2.23.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:df933278128ea1cd77772673c73954e53a1c95a4fdf41eef97c2b779271bd0bd"}, {file = "pydantic_core-2.20.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:19c0fa39fa154e7e0b7f82f88ef85faa2a4c23cc65aae2f5aea625e3c13c735a"},
{file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cb3da3fd1b6a5d0279a01877713dbda118a2a4fc6f0d821a57da2e464793f05"}, {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa223cd1e36b642092c326d694d8bf59b71ddddc94cdb752bbbb1c5c91d833b"},
{file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:42c6dcb030aefb668a2b7009c85b27f90e51e6a3b4d5c9bc4c57631292015b0d"}, {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c336a6d235522a62fef872c6295a42ecb0c4e1d0f1a3e500fe949415761b8a19"},
{file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:696dd8d674d6ce621ab9d45b205df149399e4bb9aa34102c970b721554828510"}, {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7eb6a0587eded33aeefea9f916899d42b1799b7b14b8f8ff2753c0ac1741edac"},
{file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2971bb5ffe72cc0f555c13e19b23c85b654dd2a8f7ab493c262071377bfce9f6"}, {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:70c8daf4faca8da5a6d655f9af86faf6ec2e1768f4b8b9d0226c02f3d6209703"},
{file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8394d940e5d400d04cad4f75c0598665cbb81aecefaca82ca85bd28264af7f9b"}, {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e9fa4c9bf273ca41f940bceb86922a7667cd5bf90e95dbb157cbb8441008482c"},
{file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0dff76e0602ca7d4cdaacc1ac4c005e0ce0dcfe095d5b5259163a80d3a10d327"}, {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:11b71d67b4725e7e2a9f6e9c0ac1239bbc0c48cce3dc59f98635efc57d6dac83"},
{file = "pydantic_core-2.23.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7d32706badfe136888bdea71c0def994644e09fff0bfe47441deaed8e96fdbc6"}, {file = "pydantic_core-2.20.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:270755f15174fb983890c49881e93f8f1b80f0b5e3a3cc1394a255706cabd203"},
{file = "pydantic_core-2.23.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ed541d70698978a20eb63d8c5d72f2cc6d7079d9d90f6b50bad07826f1320f5f"}, {file = "pydantic_core-2.20.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:c81131869240e3e568916ef4c307f8b99583efaa60a8112ef27a366eefba8ef0"},
{file = "pydantic_core-2.23.4-cp313-none-win32.whl", hash = "sha256:3d5639516376dce1940ea36edf408c554475369f5da2abd45d44621cb616f769"}, {file = "pydantic_core-2.20.1-cp313-none-win32.whl", hash = "sha256:b91ced227c41aa29c672814f50dbb05ec93536abf8f43cd14ec9521ea09afe4e"},
{file = "pydantic_core-2.23.4-cp313-none-win_amd64.whl", hash = "sha256:5a1504ad17ba4210df3a045132a7baeeba5a200e930f57512ee02909fc5c4cb5"}, {file = "pydantic_core-2.20.1-cp313-none-win_amd64.whl", hash = "sha256:65db0f2eefcaad1a3950f498aabb4875c8890438bc80b19362cf633b87a8ab20"},
{file = "pydantic_core-2.23.4-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:d4488a93b071c04dc20f5cecc3631fc78b9789dd72483ba15d423b5b3689b555"}, {file = "pydantic_core-2.20.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:4745f4ac52cc6686390c40eaa01d48b18997cb130833154801a442323cc78f91"},
{file = "pydantic_core-2.23.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:81965a16b675b35e1d09dd14df53f190f9129c0202356ed44ab2728b1c905658"}, {file = "pydantic_core-2.20.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a8ad4c766d3f33ba8fd692f9aa297c9058970530a32c728a2c4bfd2616d3358b"},
{file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ffa2ebd4c8530079140dd2d7f794a9d9a73cbb8e9d59ffe24c63436efa8f271"}, {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41e81317dd6a0127cabce83c0c9c3fbecceae981c8391e6f1dec88a77c8a569a"},
{file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:61817945f2fe7d166e75fbfb28004034b48e44878177fc54d81688e7b85a3665"}, {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:04024d270cf63f586ad41fff13fde4311c4fc13ea74676962c876d9577bcc78f"},
{file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:29d2c342c4bc01b88402d60189f3df065fb0dda3654744d5a165a5288a657368"}, {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eaad4ff2de1c3823fddf82f41121bdf453d922e9a238642b1dedb33c4e4f98ad"},
{file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5e11661ce0fd30a6790e8bcdf263b9ec5988e95e63cf901972107efc49218b13"}, {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:26ab812fa0c845df815e506be30337e2df27e88399b985d0bb4e3ecfe72df31c"},
{file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d18368b137c6295db49ce7218b1a9ba15c5bc254c96d7c9f9e924a9bc7825ad"}, {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c5ebac750d9d5f2706654c638c041635c385596caf68f81342011ddfa1e5598"},
{file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ec4e55f79b1c4ffb2eecd8a0cfba9955a2588497d96851f4c8f99aa4a1d39b12"}, {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2aafc5a503855ea5885559eae883978c9b6d8c8993d67766ee73d82e841300dd"},
{file = "pydantic_core-2.23.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:374a5e5049eda9e0a44c696c7ade3ff355f06b1fe0bb945ea3cac2bc336478a2"}, {file = "pydantic_core-2.20.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:4868f6bd7c9d98904b748a2653031fc9c2f85b6237009d475b1008bfaeb0a5aa"},
{file = "pydantic_core-2.23.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5c364564d17da23db1106787675fc7af45f2f7b58b4173bfdd105564e132e6fb"}, {file = "pydantic_core-2.20.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:aa2f457b4af386254372dfa78a2eda2563680d982422641a85f271c859df1987"},
{file = "pydantic_core-2.23.4-cp38-none-win32.whl", hash = "sha256:d7a80d21d613eec45e3d41eb22f8f94ddc758a6c4720842dc74c0581f54993d6"}, {file = "pydantic_core-2.20.1-cp38-none-win32.whl", hash = "sha256:225b67a1f6d602de0ce7f6c1c3ae89a4aa25d3de9be857999e9124f15dab486a"},
{file = "pydantic_core-2.23.4-cp38-none-win_amd64.whl", hash = "sha256:5f5ff8d839f4566a474a969508fe1c5e59c31c80d9e140566f9a37bba7b8d556"}, {file = "pydantic_core-2.20.1-cp38-none-win_amd64.whl", hash = "sha256:6b507132dcfc0dea440cce23ee2182c0ce7aba7054576efc65634f080dbe9434"},
{file = "pydantic_core-2.23.4-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:a4fa4fc04dff799089689f4fd502ce7d59de529fc2f40a2c8836886c03e0175a"}, {file = "pydantic_core-2.20.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:b03f7941783b4c4a26051846dea594628b38f6940a2fdc0df00b221aed39314c"},
{file = "pydantic_core-2.23.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0a7df63886be5e270da67e0966cf4afbae86069501d35c8c1b3b6c168f42cb36"}, {file = "pydantic_core-2.20.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1eedfeb6089ed3fad42e81a67755846ad4dcc14d73698c120a82e4ccf0f1f9f6"},
{file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dcedcd19a557e182628afa1d553c3895a9f825b936415d0dbd3cd0bbcfd29b4b"}, {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:635fee4e041ab9c479e31edda27fcf966ea9614fff1317e280d99eb3e5ab6fe2"},
{file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5f54b118ce5de9ac21c363d9b3caa6c800341e8c47a508787e5868c6b79c9323"}, {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:77bf3ac639c1ff567ae3b47f8d4cc3dc20f9966a2a6dd2311dcc055d3d04fb8a"},
{file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:86d2f57d3e1379a9525c5ab067b27dbb8a0642fb5d454e17a9ac434f9ce523e3"}, {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ed1b0132f24beeec5a78b67d9388656d03e6a7c837394f99257e2d55b461611"},
{file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:de6d1d1b9e5101508cb37ab0d972357cac5235f5c6533d1071964c47139257df"}, {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c6514f963b023aeee506678a1cf821fe31159b925c4b76fe2afa94cc70b3222b"},
{file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1278e0d324f6908e872730c9102b0112477a7f7cf88b308e4fc36ce1bdb6d58c"}, {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10d4204d8ca33146e761c79f83cc861df20e7ae9f6487ca290a97702daf56006"},
{file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9a6b5099eeec78827553827f4c6b8615978bb4b6a88e5d9b93eddf8bb6790f55"}, {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2d036c7187b9422ae5b262badb87a20a49eb6c5238b2004e96d4da1231badef1"},
{file = "pydantic_core-2.23.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:e55541f756f9b3ee346b840103f32779c695a19826a4c442b7954550a0972040"}, {file = "pydantic_core-2.20.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9ebfef07dbe1d93efb94b4700f2d278494e9162565a54f124c404a5656d7ff09"},
{file = "pydantic_core-2.23.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a5c7ba8ffb6d6f8f2ab08743be203654bb1aaa8c9dcb09f82ddd34eadb695605"}, {file = "pydantic_core-2.20.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6b9d9bb600328a1ce523ab4f454859e9d439150abb0906c5a1983c146580ebab"},
{file = "pydantic_core-2.23.4-cp39-none-win32.whl", hash = "sha256:37b0fe330e4a58d3c58b24d91d1eb102aeec675a3db4c292ec3928ecd892a9a6"}, {file = "pydantic_core-2.20.1-cp39-none-win32.whl", hash = "sha256:784c1214cb6dd1e3b15dd8b91b9a53852aed16671cc3fbe4786f4f1db07089e2"},
{file = "pydantic_core-2.23.4-cp39-none-win_amd64.whl", hash = "sha256:1498bec4c05c9c787bde9125cfdcc63a41004ff167f495063191b863399b1a29"}, {file = "pydantic_core-2.20.1-cp39-none-win_amd64.whl", hash = "sha256:d2fe69c5434391727efa54b47a1e7986bb0186e72a41b203df8f5b0a19a4f669"},
{file = "pydantic_core-2.23.4-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f455ee30a9d61d3e1a15abd5068827773d6e4dc513e795f380cdd59932c782d5"}, {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a45f84b09ac9c3d35dfcf6a27fd0634d30d183205230a0ebe8373a0e8cfa0906"},
{file = "pydantic_core-2.23.4-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1e90d2e3bd2c3863d48525d297cd143fe541be8bbf6f579504b9712cb6b643ec"}, {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d02a72df14dfdbaf228424573a07af10637bd490f0901cee872c4f434a735b94"},
{file = "pydantic_core-2.23.4-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e203fdf807ac7e12ab59ca2bfcabb38c7cf0b33c41efeb00f8e5da1d86af480"}, {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d2b27e6af28f07e2f195552b37d7d66b150adbaa39a6d327766ffd695799780f"},
{file = "pydantic_core-2.23.4-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e08277a400de01bc72436a0ccd02bdf596631411f592ad985dcee21445bd0068"}, {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:084659fac3c83fd674596612aeff6041a18402f1e1bc19ca39e417d554468482"},
{file = "pydantic_core-2.23.4-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f220b0eea5965dec25480b6333c788fb72ce5f9129e8759ef876a1d805d00801"}, {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:242b8feb3c493ab78be289c034a1f659e8826e2233786e36f2893a950a719bb6"},
{file = "pydantic_core-2.23.4-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:d06b0c8da4f16d1d1e352134427cb194a0a6e19ad5db9161bf32b2113409e728"}, {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:38cf1c40a921d05c5edc61a785c0ddb4bed67827069f535d794ce6bcded919fc"},
{file = "pydantic_core-2.23.4-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:ba1a0996f6c2773bd83e63f18914c1de3c9dd26d55f4ac302a7efe93fb8e7433"}, {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:e0bbdd76ce9aa5d4209d65f2b27fc6e5ef1312ae6c5333c26db3f5ade53a1e99"},
{file = "pydantic_core-2.23.4-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:9a5bce9d23aac8f0cf0836ecfc033896aa8443b501c58d0602dbfd5bd5b37753"}, {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:254ec27fdb5b1ee60684f91683be95e5133c994cc54e86a0b0963afa25c8f8a6"},
{file = "pydantic_core-2.23.4-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:78ddaaa81421a29574a682b3179d4cf9e6d405a09b99d93ddcf7e5239c742e21"}, {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:407653af5617f0757261ae249d3fba09504d7a71ab36ac057c938572d1bc9331"},
{file = "pydantic_core-2.23.4-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:883a91b5dd7d26492ff2f04f40fbb652de40fcc0afe07e8129e8ae779c2110eb"}, {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:c693e916709c2465b02ca0ad7b387c4f8423d1db7b4649c551f27a529181c5ad"},
{file = "pydantic_core-2.23.4-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88ad334a15b32a791ea935af224b9de1bf99bcd62fabf745d5f3442199d86d59"}, {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b5ff4911aea936a47d9376fd3ab17e970cc543d1b68921886e7f64bd28308d1"},
{file = "pydantic_core-2.23.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:233710f069d251feb12a56da21e14cca67994eab08362207785cf8c598e74577"}, {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:177f55a886d74f1808763976ac4efd29b7ed15c69f4d838bbd74d9d09cf6fa86"},
{file = "pydantic_core-2.23.4-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:19442362866a753485ba5e4be408964644dd6a09123d9416c54cd49171f50744"}, {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:964faa8a861d2664f0c7ab0c181af0bea66098b1919439815ca8803ef136fc4e"},
{file = "pydantic_core-2.23.4-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:624e278a7d29b6445e4e813af92af37820fafb6dcc55c012c834f9e26f9aaaef"}, {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:4dd484681c15e6b9a977c785a345d3e378d72678fd5f1f3c0509608da24f2ac0"},
{file = "pydantic_core-2.23.4-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f5ef8f42bec47f21d07668a043f077d507e5bf4e668d5c6dfe6aaba89de1a5b8"}, {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f6d6cff3538391e8486a431569b77921adfcdef14eb18fbf19b7c0a5294d4e6a"},
{file = "pydantic_core-2.23.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:aea443fffa9fbe3af1a9ba721a87f926fe548d32cab71d188a6ede77d0ff244e"}, {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a6d511cc297ff0883bc3708b465ff82d7560193169a8b93260f74ecb0a5e08a7"},
{file = "pydantic_core-2.23.4.tar.gz", hash = "sha256:2584f7cf844ac4d970fba483a717dbe10c1c1c96a969bf65d61ffe94df1b2863"}, {file = "pydantic_core-2.20.1.tar.gz", hash = "sha256:26ca695eeee5f9f1aeeb211ffc12f10bcb6f71e2989988fda61dabd65db878d4"},
] ]
[package.dependencies] [package.dependencies]
@ -3776,13 +3761,13 @@ files = [
[[package]] [[package]]
name = "pytest" name = "pytest"
version = "8.3.3" version = "8.3.2"
description = "pytest: simple powerful testing with Python" description = "pytest: simple powerful testing with Python"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
{file = "pytest-8.3.3-py3-none-any.whl", hash = "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2"}, {file = "pytest-8.3.2-py3-none-any.whl", hash = "sha256:4ba08f9ae7dcf84ded419494d229b48d0903ea6407b030eaec46df5e6a73bba5"},
{file = "pytest-8.3.3.tar.gz", hash = "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181"}, {file = "pytest-8.3.2.tar.gz", hash = "sha256:c132345d12ce551242c87269de812483f5bcc87cdbb4722e48487ba194f9fdce"},
] ]
[package.dependencies] [package.dependencies]
@ -3796,13 +3781,13 @@ dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments
[[package]] [[package]]
name = "pytest-django" name = "pytest-django"
version = "4.9.0" version = "4.8.0"
description = "A Django plugin for pytest." description = "A Django plugin for pytest."
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
{file = "pytest_django-4.9.0-py3-none-any.whl", hash = "sha256:1d83692cb39188682dbb419ff0393867e9904094a549a7d38a3154d5731b2b99"}, {file = "pytest-django-4.8.0.tar.gz", hash = "sha256:5d054fe011c56f3b10f978f41a8efb2e5adfc7e680ef36fb571ada1f24779d90"},
{file = "pytest_django-4.9.0.tar.gz", hash = "sha256:8bf7bc358c9ae6f6fc51b6cebb190fe20212196e6807121f11bd6a3b03428314"}, {file = "pytest_django-4.8.0-py3-none-any.whl", hash = "sha256:ca1ddd1e0e4c227cf9e3e40a6afc6d106b3e70868fd2ac5798a22501271cd0c7"},
] ]
[package.dependencies] [package.dependencies]
@ -4210,29 +4195,29 @@ pyasn1 = ">=0.1.3"
[[package]] [[package]]
name = "ruff" name = "ruff"
version = "0.6.8" version = "0.6.2"
description = "An extremely fast Python linter and code formatter, written in Rust." description = "An extremely fast Python linter and code formatter, written in Rust."
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
{file = "ruff-0.6.8-py3-none-linux_armv6l.whl", hash = "sha256:77944bca110ff0a43b768f05a529fecd0706aac7bcce36d7f1eeb4cbfca5f0f2"}, {file = "ruff-0.6.2-py3-none-linux_armv6l.whl", hash = "sha256:5c8cbc6252deb3ea840ad6a20b0f8583caab0c5ef4f9cca21adc5a92b8f79f3c"},
{file = "ruff-0.6.8-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:27b87e1801e786cd6ede4ada3faa5e254ce774de835e6723fd94551464c56b8c"}, {file = "ruff-0.6.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:17002fe241e76544448a8e1e6118abecbe8cd10cf68fde635dad480dba594570"},
{file = "ruff-0.6.8-py3-none-macosx_11_0_arm64.whl", hash = "sha256:cd48f945da2a6334f1793d7f701725a76ba93bf3d73c36f6b21fb04d5338dcf5"}, {file = "ruff-0.6.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:3dbeac76ed13456f8158b8f4fe087bf87882e645c8e8b606dd17b0b66c2c1158"},
{file = "ruff-0.6.8-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:677e03c00f37c66cea033274295a983c7c546edea5043d0c798833adf4cf4c6f"}, {file = "ruff-0.6.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:094600ee88cda325988d3f54e3588c46de5c18dae09d683ace278b11f9d4d534"},
{file = "ruff-0.6.8-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9f1476236b3eacfacfc0f66aa9e6cd39f2a624cb73ea99189556015f27c0bdeb"}, {file = "ruff-0.6.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:316d418fe258c036ba05fbf7dfc1f7d3d4096db63431546163b472285668132b"},
{file = "ruff-0.6.8-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6f5a2f17c7d32991169195d52a04c95b256378bbf0de8cb98478351eb70d526f"}, {file = "ruff-0.6.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d72b8b3abf8a2d51b7b9944a41307d2f442558ccb3859bbd87e6ae9be1694a5d"},
{file = "ruff-0.6.8-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:5fd0d4b7b1457c49e435ee1e437900ced9b35cb8dc5178921dfb7d98d65a08d0"}, {file = "ruff-0.6.2-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:2aed7e243be68487aa8982e91c6e260982d00da3f38955873aecd5a9204b1d66"},
{file = "ruff-0.6.8-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f8034b19b993e9601f2ddf2c517451e17a6ab5cdb1c13fdff50c1442a7171d87"}, {file = "ruff-0.6.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d371f7fc9cec83497fe7cf5eaf5b76e22a8efce463de5f775a1826197feb9df8"},
{file = "ruff-0.6.8-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6cfb227b932ba8ef6e56c9f875d987973cd5e35bc5d05f5abf045af78ad8e098"}, {file = "ruff-0.6.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8f310d63af08f583363dfb844ba8f9417b558199c58a5999215082036d795a1"},
{file = "ruff-0.6.8-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ef0411eccfc3909269fed47c61ffebdcb84a04504bafa6b6df9b85c27e813b0"}, {file = "ruff-0.6.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7db6880c53c56addb8638fe444818183385ec85eeada1d48fc5abe045301b2f1"},
{file = "ruff-0.6.8-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:007dee844738c3d2e6c24ab5bc7d43c99ba3e1943bd2d95d598582e9c1b27750"}, {file = "ruff-0.6.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:1175d39faadd9a50718f478d23bfc1d4da5743f1ab56af81a2b6caf0a2394f23"},
{file = "ruff-0.6.8-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:ce60058d3cdd8490e5e5471ef086b3f1e90ab872b548814e35930e21d848c9ce"}, {file = "ruff-0.6.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:5b939f9c86d51635fe486585389f54582f0d65b8238e08c327c1534844b3bb9a"},
{file = "ruff-0.6.8-py3-none-musllinux_1_2_i686.whl", hash = "sha256:1085c455d1b3fdb8021ad534379c60353b81ba079712bce7a900e834859182fa"}, {file = "ruff-0.6.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:d0d62ca91219f906caf9b187dea50d17353f15ec9bb15aae4a606cd697b49b4c"},
{file = "ruff-0.6.8-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:70edf6a93b19481affd287d696d9e311388d808671bc209fb8907b46a8c3af44"}, {file = "ruff-0.6.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:7438a7288f9d67ed3c8ce4d059e67f7ed65e9fe3aa2ab6f5b4b3610e57e3cb56"},
{file = "ruff-0.6.8-py3-none-win32.whl", hash = "sha256:792213f7be25316f9b46b854df80a77e0da87ec66691e8f012f887b4a671ab5a"}, {file = "ruff-0.6.2-py3-none-win32.whl", hash = "sha256:279d5f7d86696df5f9549b56b9b6a7f6c72961b619022b5b7999b15db392a4da"},
{file = "ruff-0.6.8-py3-none-win_amd64.whl", hash = "sha256:ec0517dc0f37cad14a5319ba7bba6e7e339d03fbf967a6d69b0907d61be7a263"}, {file = "ruff-0.6.2-py3-none-win_amd64.whl", hash = "sha256:d9f3469c7dd43cd22eb1c3fc16926fb8258d50cb1b216658a07be95dd117b0f2"},
{file = "ruff-0.6.8-py3-none-win_arm64.whl", hash = "sha256:8d3bb2e3fbb9875172119021a13eed38849e762499e3cfde9588e4b4d70968dc"}, {file = "ruff-0.6.2-py3-none-win_arm64.whl", hash = "sha256:f28fcd2cd0e02bdf739297516d5643a945cc7caf09bd9bcb4d932540a5ea4fa9"},
{file = "ruff-0.6.8.tar.gz", hash = "sha256:a5bf44b1aa0adaf6d9d20f86162b34f7c593bfedabc51239953e446aefc8ce18"}, {file = "ruff-0.6.2.tar.gz", hash = "sha256:239ee6beb9e91feb8e0ec384204a763f36cb53fb895a1a364618c6abb076b3be"},
] ]
[[package]] [[package]]
@ -4271,13 +4256,13 @@ django-query = ["django (>=3.2)"]
[[package]] [[package]]
name = "selenium" name = "selenium"
version = "4.25.0" version = "4.23.1"
description = "Official Python bindings for Selenium WebDriver" description = "Official Python bindings for Selenium WebDriver"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
{file = "selenium-4.25.0-py3-none-any.whl", hash = "sha256:3798d2d12b4a570bc5790163ba57fef10b2afee958bf1d80f2a3cf07c4141f33"}, {file = "selenium-4.23.1-py3-none-any.whl", hash = "sha256:3a8d9f23dc636bd3840dd56f00c2739e32ec0c1e34a821dd553e15babef24477"},
{file = "selenium-4.25.0.tar.gz", hash = "sha256:95d08d3b82fb353f3c474895154516604c7f0e6a9a565ae6498ef36c9bac6921"}, {file = "selenium-4.23.1.tar.gz", hash = "sha256:128d099e66284437e7128d2279176ec7a06e6ec7426e167f5d34987166bd8f46"},
] ]
[package.dependencies] [package.dependencies]
@ -4290,13 +4275,13 @@ websocket-client = ">=1.8,<2.0"
[[package]] [[package]]
name = "sentry-sdk" name = "sentry-sdk"
version = "2.14.0" version = "2.13.0"
description = "Python client for Sentry (https://sentry.io)" description = "Python client for Sentry (https://sentry.io)"
optional = false optional = false
python-versions = ">=3.6" python-versions = ">=3.6"
files = [ files = [
{file = "sentry_sdk-2.14.0-py2.py3-none-any.whl", hash = "sha256:b8bc3dc51d06590df1291b7519b85c75e2ced4f28d9ea655b6d54033503b5bf4"}, {file = "sentry_sdk-2.13.0-py2.py3-none-any.whl", hash = "sha256:6beede8fc2ab4043da7f69d95534e320944690680dd9a963178a49de71d726c6"},
{file = "sentry_sdk-2.14.0.tar.gz", hash = "sha256:1e0e2eaf6dad918c7d1e0edac868a7bf20017b177f242cefe2a6bcd47955961d"}, {file = "sentry_sdk-2.13.0.tar.gz", hash = "sha256:8d4a576f7a98eb2fdb40e13106e41f330e5c79d72a68be1316e7852cf4995260"},
] ]
[package.dependencies] [package.dependencies]
@ -4667,13 +4652,13 @@ wsproto = ">=0.14"
[[package]] [[package]]
name = "twilio" name = "twilio"
version = "9.3.2" version = "9.2.3"
description = "Twilio API client and TwiML generator" description = "Twilio API client and TwiML generator"
optional = false optional = false
python-versions = ">=3.7.0" python-versions = ">=3.7.0"
files = [ files = [
{file = "twilio-9.3.2-py2.py3-none-any.whl", hash = "sha256:7fcb2da241d2264b17fbab9ac0ca829c0f0abe23ce6db15d4bb0d4d2d583f953"}, {file = "twilio-9.2.3-py2.py3-none-any.whl", hash = "sha256:76bfc39aa8d854510907cb7f9465814dfdea9e91ec199bb44f0785f05746f4cc"},
{file = "twilio-9.3.2.tar.gz", hash = "sha256:250fc6ce6960aa97a2e2ee7e718e3bc0e73d69731b97fe160ed2097f3cbeb5a8"}, {file = "twilio-9.2.3.tar.gz", hash = "sha256:da2255b5f3753cb3bf647fc6c50edbdb367ebc3cde6802806f6f863058a65f75"},
] ]
[package.dependencies] [package.dependencies]
@ -4684,13 +4669,13 @@ requests = ">=2.0.0"
[[package]] [[package]]
name = "twisted" name = "twisted"
version = "24.7.0" version = "24.3.0"
description = "An asynchronous networking framework written in Python" description = "An asynchronous networking framework written in Python"
optional = false optional = false
python-versions = ">=3.8.0" python-versions = ">=3.8.0"
files = [ files = [
{file = "twisted-24.7.0-py3-none-any.whl", hash = "sha256:734832ef98108136e222b5230075b1079dad8a3fc5637319615619a7725b0c81"}, {file = "twisted-24.3.0-py3-none-any.whl", hash = "sha256:039f2e6a49ab5108abd94de187fa92377abe5985c7a72d68d0ad266ba19eae63"},
{file = "twisted-24.7.0.tar.gz", hash = "sha256:5a60147f044187a127ec7da96d170d49bcce50c6fd36f594e60f4587eff4d394"}, {file = "twisted-24.3.0.tar.gz", hash = "sha256:6b38b6ece7296b5e122c9eb17da2eeab3d98a198f50ca9efd00fb03e5b4fd4ae"},
] ]
[package.dependencies] [package.dependencies]
@ -4699,26 +4684,55 @@ automat = ">=0.8.0"
constantly = ">=15.1" constantly = ">=15.1"
hyperlink = ">=17.1.1" hyperlink = ">=17.1.1"
idna = {version = ">=2.4", optional = true, markers = "extra == \"tls\""} idna = {version = ">=2.4", optional = true, markers = "extra == \"tls\""}
incremental = ">=24.7.0" incremental = ">=22.10.0"
pyopenssl = {version = ">=21.0.0", optional = true, markers = "extra == \"tls\""} pyopenssl = {version = ">=21.0.0", optional = true, markers = "extra == \"tls\""}
service-identity = {version = ">=18.1.0", optional = true, markers = "extra == \"tls\""} service-identity = {version = ">=18.1.0", optional = true, markers = "extra == \"tls\""}
twisted-iocpsupport = {version = ">=1.0.2,<2", markers = "platform_system == \"Windows\""}
typing-extensions = ">=4.2.0" typing-extensions = ">=4.2.0"
zope-interface = ">=5" zope-interface = ">=5"
[package.extras] [package.extras]
all-non-platform = ["appdirs (>=1.4.0)", "appdirs (>=1.4.0)", "bcrypt (>=3.1.3)", "bcrypt (>=3.1.3)", "cryptography (>=3.3)", "cryptography (>=3.3)", "cython-test-exception-raiser (>=1.0.2,<2)", "cython-test-exception-raiser (>=1.0.2,<2)", "h2 (>=3.0,<5.0)", "h2 (>=3.0,<5.0)", "hypothesis (>=6.56)", "hypothesis (>=6.56)", "idna (>=2.4)", "idna (>=2.4)", "priority (>=1.1.0,<2.0)", "priority (>=1.1.0,<2.0)", "pyhamcrest (>=2)", "pyhamcrest (>=2)", "pyopenssl (>=21.0.0)", "pyopenssl (>=21.0.0)", "pyserial (>=3.0)", "pyserial (>=3.0)", "pywin32 (!=226)", "pywin32 (!=226)", "service-identity (>=18.1.0)", "service-identity (>=18.1.0)"] all-non-platform = ["twisted[conch,http2,serial,test,tls]", "twisted[conch,http2,serial,test,tls]"]
conch = ["appdirs (>=1.4.0)", "bcrypt (>=3.1.3)", "cryptography (>=3.3)"] conch = ["appdirs (>=1.4.0)", "bcrypt (>=3.1.3)", "cryptography (>=3.3)"]
dev = ["coverage (>=7.5,<8.0)", "cython-test-exception-raiser (>=1.0.2,<2)", "hypothesis (>=6.56)", "pydoctor (>=23.9.0,<23.10.0)", "pyflakes (>=2.2,<3.0)", "pyhamcrest (>=2)", "python-subunit (>=1.4,<2.0)", "sphinx (>=6,<7)", "sphinx-rtd-theme (>=1.3,<2.0)", "towncrier (>=23.6,<24.0)", "twistedchecker (>=0.7,<1.0)"] dev = ["coverage (>=6b1,<7)", "pyflakes (>=2.2,<3.0)", "python-subunit (>=1.4,<2.0)", "twisted[dev-release]", "twistedchecker (>=0.7,<1.0)"]
dev-release = ["pydoctor (>=23.9.0,<23.10.0)", "pydoctor (>=23.9.0,<23.10.0)", "sphinx (>=6,<7)", "sphinx (>=6,<7)", "sphinx-rtd-theme (>=1.3,<2.0)", "sphinx-rtd-theme (>=1.3,<2.0)", "towncrier (>=23.6,<24.0)", "towncrier (>=23.6,<24.0)"] dev-release = ["pydoctor (>=23.9.0,<23.10.0)", "pydoctor (>=23.9.0,<23.10.0)", "sphinx (>=6,<7)", "sphinx (>=6,<7)", "sphinx-rtd-theme (>=1.3,<2.0)", "sphinx-rtd-theme (>=1.3,<2.0)", "towncrier (>=23.6,<24.0)", "towncrier (>=23.6,<24.0)"]
gtk-platform = ["appdirs (>=1.4.0)", "appdirs (>=1.4.0)", "bcrypt (>=3.1.3)", "bcrypt (>=3.1.3)", "cryptography (>=3.3)", "cryptography (>=3.3)", "cython-test-exception-raiser (>=1.0.2,<2)", "cython-test-exception-raiser (>=1.0.2,<2)", "h2 (>=3.0,<5.0)", "h2 (>=3.0,<5.0)", "hypothesis (>=6.56)", "hypothesis (>=6.56)", "idna (>=2.4)", "idna (>=2.4)", "priority (>=1.1.0,<2.0)", "priority (>=1.1.0,<2.0)", "pygobject", "pygobject", "pyhamcrest (>=2)", "pyhamcrest (>=2)", "pyopenssl (>=21.0.0)", "pyopenssl (>=21.0.0)", "pyserial (>=3.0)", "pyserial (>=3.0)", "pywin32 (!=226)", "pywin32 (!=226)", "service-identity (>=18.1.0)", "service-identity (>=18.1.0)"] gtk-platform = ["pygobject", "pygobject", "twisted[all-non-platform]", "twisted[all-non-platform]"]
http2 = ["h2 (>=3.0,<5.0)", "priority (>=1.1.0,<2.0)"] http2 = ["h2 (>=3.0,<5.0)", "priority (>=1.1.0,<2.0)"]
macos-platform = ["appdirs (>=1.4.0)", "appdirs (>=1.4.0)", "bcrypt (>=3.1.3)", "bcrypt (>=3.1.3)", "cryptography (>=3.3)", "cryptography (>=3.3)", "cython-test-exception-raiser (>=1.0.2,<2)", "cython-test-exception-raiser (>=1.0.2,<2)", "h2 (>=3.0,<5.0)", "h2 (>=3.0,<5.0)", "hypothesis (>=6.56)", "hypothesis (>=6.56)", "idna (>=2.4)", "idna (>=2.4)", "priority (>=1.1.0,<2.0)", "priority (>=1.1.0,<2.0)", "pyhamcrest (>=2)", "pyhamcrest (>=2)", "pyobjc-core", "pyobjc-core", "pyobjc-framework-cfnetwork", "pyobjc-framework-cfnetwork", "pyobjc-framework-cocoa", "pyobjc-framework-cocoa", "pyopenssl (>=21.0.0)", "pyopenssl (>=21.0.0)", "pyserial (>=3.0)", "pyserial (>=3.0)", "pywin32 (!=226)", "pywin32 (!=226)", "service-identity (>=18.1.0)", "service-identity (>=18.1.0)"] macos-platform = ["pyobjc-core", "pyobjc-core", "pyobjc-framework-cfnetwork", "pyobjc-framework-cfnetwork", "pyobjc-framework-cocoa", "pyobjc-framework-cocoa", "twisted[all-non-platform]", "twisted[all-non-platform]"]
mypy = ["appdirs (>=1.4.0)", "bcrypt (>=3.1.3)", "coverage (>=7.5,<8.0)", "cryptography (>=3.3)", "cython-test-exception-raiser (>=1.0.2,<2)", "h2 (>=3.0,<5.0)", "hypothesis (>=6.56)", "idna (>=2.4)", "mypy (>=1.8,<2.0)", "mypy-zope (>=1.0.3,<1.1.0)", "priority (>=1.1.0,<2.0)", "pydoctor (>=23.9.0,<23.10.0)", "pyflakes (>=2.2,<3.0)", "pyhamcrest (>=2)", "pyopenssl (>=21.0.0)", "pyserial (>=3.0)", "python-subunit (>=1.4,<2.0)", "pywin32 (!=226)", "service-identity (>=18.1.0)", "sphinx (>=6,<7)", "sphinx-rtd-theme (>=1.3,<2.0)", "towncrier (>=23.6,<24.0)", "twistedchecker (>=0.7,<1.0)", "types-pyopenssl", "types-setuptools"] mypy = ["mypy (>=1.8,<2.0)", "mypy-zope (>=1.0.3,<1.1.0)", "twisted[all-non-platform,dev]", "types-pyopenssl", "types-setuptools"]
osx-platform = ["appdirs (>=1.4.0)", "appdirs (>=1.4.0)", "bcrypt (>=3.1.3)", "bcrypt (>=3.1.3)", "cryptography (>=3.3)", "cryptography (>=3.3)", "cython-test-exception-raiser (>=1.0.2,<2)", "cython-test-exception-raiser (>=1.0.2,<2)", "h2 (>=3.0,<5.0)", "h2 (>=3.0,<5.0)", "hypothesis (>=6.56)", "hypothesis (>=6.56)", "idna (>=2.4)", "idna (>=2.4)", "priority (>=1.1.0,<2.0)", "priority (>=1.1.0,<2.0)", "pyhamcrest (>=2)", "pyhamcrest (>=2)", "pyobjc-core", "pyobjc-core", "pyobjc-framework-cfnetwork", "pyobjc-framework-cfnetwork", "pyobjc-framework-cocoa", "pyobjc-framework-cocoa", "pyopenssl (>=21.0.0)", "pyopenssl (>=21.0.0)", "pyserial (>=3.0)", "pyserial (>=3.0)", "pywin32 (!=226)", "pywin32 (!=226)", "service-identity (>=18.1.0)", "service-identity (>=18.1.0)"] osx-platform = ["twisted[macos-platform]", "twisted[macos-platform]"]
serial = ["pyserial (>=3.0)", "pywin32 (!=226)"] serial = ["pyserial (>=3.0)", "pywin32 (!=226)"]
test = ["cython-test-exception-raiser (>=1.0.2,<2)", "hypothesis (>=6.56)", "pyhamcrest (>=2)"] test = ["cython-test-exception-raiser (>=1.0.2,<2)", "hypothesis (>=6.56)", "pyhamcrest (>=2)"]
tls = ["idna (>=2.4)", "pyopenssl (>=21.0.0)", "service-identity (>=18.1.0)"] tls = ["idna (>=2.4)", "pyopenssl (>=21.0.0)", "service-identity (>=18.1.0)"]
windows-platform = ["appdirs (>=1.4.0)", "appdirs (>=1.4.0)", "bcrypt (>=3.1.3)", "bcrypt (>=3.1.3)", "cryptography (>=3.3)", "cryptography (>=3.3)", "cython-test-exception-raiser (>=1.0.2,<2)", "cython-test-exception-raiser (>=1.0.2,<2)", "h2 (>=3.0,<5.0)", "h2 (>=3.0,<5.0)", "hypothesis (>=6.56)", "hypothesis (>=6.56)", "idna (>=2.4)", "idna (>=2.4)", "priority (>=1.1.0,<2.0)", "priority (>=1.1.0,<2.0)", "pyhamcrest (>=2)", "pyhamcrest (>=2)", "pyopenssl (>=21.0.0)", "pyopenssl (>=21.0.0)", "pyserial (>=3.0)", "pyserial (>=3.0)", "pywin32 (!=226)", "pywin32 (!=226)", "pywin32 (!=226)", "pywin32 (!=226)", "service-identity (>=18.1.0)", "service-identity (>=18.1.0)", "twisted-iocpsupport (>=1.0.2)", "twisted-iocpsupport (>=1.0.2)"] windows-platform = ["pywin32 (!=226)", "pywin32 (!=226)", "twisted[all-non-platform]", "twisted[all-non-platform]"]
[[package]]
name = "twisted-iocpsupport"
version = "1.0.4"
description = "An extension for use in the twisted I/O Completion Ports reactor."
optional = false
python-versions = "*"
files = [
{file = "twisted-iocpsupport-1.0.4.tar.gz", hash = "sha256:858096c0d15e33f15ac157f455d8f86f2f2cdd223963e58c0f682a3af8362d89"},
{file = "twisted_iocpsupport-1.0.4-cp310-cp310-win32.whl", hash = "sha256:afa2b630797f9ed2f27f3d9f55e3f72b4244911e45a8c82756f44babbf0b243e"},
{file = "twisted_iocpsupport-1.0.4-cp310-cp310-win_amd64.whl", hash = "sha256:0058c963c8957bcd3deda62122e89953c9de1e867a274facc9b15dde1a9f31e8"},
{file = "twisted_iocpsupport-1.0.4-cp311-cp311-win32.whl", hash = "sha256:196f7c7ccad4ba4d1783b1c4e1d1b22d93c04275cd780bf7498d16c77319ad6e"},
{file = "twisted_iocpsupport-1.0.4-cp311-cp311-win_amd64.whl", hash = "sha256:4e5f97bcbabdd79cbaa969b63439b89801ea560f11d42b0a387634275c633623"},
{file = "twisted_iocpsupport-1.0.4-cp312-cp312-win32.whl", hash = "sha256:6081bd7c2f4fcf9b383dcdb3b3385d75a26a7c9d2be25b6950c3d8ea652d2d2d"},
{file = "twisted_iocpsupport-1.0.4-cp312-cp312-win_amd64.whl", hash = "sha256:76f7e67cec1f1d097d1f4ed7de41be3d74546e1a4ede0c7d56e775c4dce5dfb0"},
{file = "twisted_iocpsupport-1.0.4-cp36-cp36m-win32.whl", hash = "sha256:3d306fc4d88a6bcf61ce9d572c738b918578121bfd72891625fab314549024b5"},
{file = "twisted_iocpsupport-1.0.4-cp36-cp36m-win_amd64.whl", hash = "sha256:391ac4d6002a80e15f35adc4ad6056f4fe1c17ceb0d1f98ba01b0f4f917adfd7"},
{file = "twisted_iocpsupport-1.0.4-cp37-cp37m-win32.whl", hash = "sha256:0c1b5cf37f0b2d96cc3c9bc86fff16613b9f5d0ca565c96cf1f1fb8cfca4b81c"},
{file = "twisted_iocpsupport-1.0.4-cp37-cp37m-win_amd64.whl", hash = "sha256:3c5dc11d72519e55f727320e3cee535feedfaee09c0f0765ed1ca7badff1ab3c"},
{file = "twisted_iocpsupport-1.0.4-cp38-cp38-win32.whl", hash = "sha256:cc86c2ef598c15d824a243c2541c29459881c67fc3c0adb6efe2242f8f0ec3af"},
{file = "twisted_iocpsupport-1.0.4-cp38-cp38-win_amd64.whl", hash = "sha256:c27985e949b9b1a1fb4c20c71d315c10ea0f93fdf3ccdd4a8c158b5926edd8c8"},
{file = "twisted_iocpsupport-1.0.4-cp39-cp39-win32.whl", hash = "sha256:e311dfcb470696e3c077249615893cada598e62fa7c4e4ca090167bd2b7d331f"},
{file = "twisted_iocpsupport-1.0.4-cp39-cp39-win_amd64.whl", hash = "sha256:4574eef1f3bb81501fb02f911298af3c02fe8179c31a33b361dd49180c3e644d"},
{file = "twisted_iocpsupport-1.0.4-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:872747a3b64e2909aee59c803ccd0bceb9b75bf27915520ebd32d69687040fa2"},
{file = "twisted_iocpsupport-1.0.4-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:c2712b778bacf1db434e3e065adfed3db300754186a29aecac1efae9ef4bcaff"},
{file = "twisted_iocpsupport-1.0.4-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:7c66fa0aa4236b27b3c61cb488662d85dae746a6d1c7b0d91cf7aae118445adf"},
{file = "twisted_iocpsupport-1.0.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:300437af17396a945a58dcfffd77863303a8b6d9e65c6e81f1d2eed55b50d444"},
]
[[package]] [[package]]
name = "txaio" name = "txaio"
@ -4782,13 +4796,13 @@ files = [
[[package]] [[package]]
name = "urllib3" name = "urllib3"
version = "2.2.3" version = "2.2.2"
description = "HTTP library with thread-safe connection pooling, file post, and more." description = "HTTP library with thread-safe connection pooling, file post, and more."
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
{file = "urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac"}, {file = "urllib3-2.2.2-py3-none-any.whl", hash = "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472"},
{file = "urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9"}, {file = "urllib3-2.2.2.tar.gz", hash = "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168"},
] ]
[package.dependencies] [package.dependencies]
@ -4802,13 +4816,13 @@ zstd = ["zstandard (>=0.18.0)"]
[[package]] [[package]]
name = "uvicorn" name = "uvicorn"
version = "0.31.0" version = "0.30.6"
description = "The lightning-fast ASGI server." description = "The lightning-fast ASGI server."
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
{file = "uvicorn-0.31.0-py3-none-any.whl", hash = "sha256:cac7be4dd4d891c363cd942160a7b02e69150dcbc7a36be04d5f4af4b17c8ced"}, {file = "uvicorn-0.30.6-py3-none-any.whl", hash = "sha256:65fd46fe3fda5bdc1b03b94eb634923ff18cd35b2f084813ea79d1f103f711b5"},
{file = "uvicorn-0.31.0.tar.gz", hash = "sha256:13bc21373d103859f68fe739608e2eb054a816dea79189bc3ca08ea89a275906"}, {file = "uvicorn-0.30.6.tar.gz", hash = "sha256:4b15decdda1e72be08209e860a1e10e92439ad5b97cf44cc945fcbee66fc5788"},
] ]
[package.dependencies] [package.dependencies]
@ -4882,41 +4896,46 @@ files = [
[[package]] [[package]]
name = "watchdog" name = "watchdog"
version = "5.0.3" version = "4.0.2"
description = "Filesystem events monitoring" description = "Filesystem events monitoring"
optional = false optional = false
python-versions = ">=3.9" python-versions = ">=3.8"
files = [ files = [
{file = "watchdog-5.0.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:85527b882f3facda0579bce9d743ff7f10c3e1e0db0a0d0e28170a7d0e5ce2ea"}, {file = "watchdog-4.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ede7f010f2239b97cc79e6cb3c249e72962404ae3865860855d5cbe708b0fd22"},
{file = "watchdog-5.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:53adf73dcdc0ef04f7735066b4a57a4cd3e49ef135daae41d77395f0b5b692cb"}, {file = "watchdog-4.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a2cffa171445b0efa0726c561eca9a27d00a1f2b83846dbd5a4f639c4f8ca8e1"},
{file = "watchdog-5.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e25adddab85f674acac303cf1f5835951345a56c5f7f582987d266679979c75b"}, {file = "watchdog-4.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c50f148b31b03fbadd6d0b5980e38b558046b127dc483e5e4505fcef250f9503"},
{file = "watchdog-5.0.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f01f4a3565a387080dc49bdd1fefe4ecc77f894991b88ef927edbfa45eb10818"}, {file = "watchdog-4.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7c7d4bf585ad501c5f6c980e7be9c4f15604c7cc150e942d82083b31a7548930"},
{file = "watchdog-5.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:91b522adc25614cdeaf91f7897800b82c13b4b8ac68a42ca959f992f6990c490"}, {file = "watchdog-4.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:914285126ad0b6eb2258bbbcb7b288d9dfd655ae88fa28945be05a7b475a800b"},
{file = "watchdog-5.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d52db5beb5e476e6853da2e2d24dbbbed6797b449c8bf7ea118a4ee0d2c9040e"}, {file = "watchdog-4.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:984306dc4720da5498b16fc037b36ac443816125a3705dfde4fd90652d8028ef"},
{file = "watchdog-5.0.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:94d11b07c64f63f49876e0ab8042ae034674c8653bfcdaa8c4b32e71cfff87e8"}, {file = "watchdog-4.0.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:1cdcfd8142f604630deef34722d695fb455d04ab7cfe9963055df1fc69e6727a"},
{file = "watchdog-5.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:349c9488e1d85d0a58e8cb14222d2c51cbc801ce11ac3936ab4c3af986536926"}, {file = "watchdog-4.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d7ab624ff2f663f98cd03c8b7eedc09375a911794dfea6bf2a359fcc266bff29"},
{file = "watchdog-5.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:53a3f10b62c2d569e260f96e8d966463dec1a50fa4f1b22aec69e3f91025060e"}, {file = "watchdog-4.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:132937547a716027bd5714383dfc40dc66c26769f1ce8a72a859d6a48f371f3a"},
{file = "watchdog-5.0.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:950f531ec6e03696a2414b6308f5c6ff9dab7821a768c9d5788b1314e9a46ca7"}, {file = "watchdog-4.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:cd67c7df93eb58f360c43802acc945fa8da70c675b6fa37a241e17ca698ca49b"},
{file = "watchdog-5.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ae6deb336cba5d71476caa029ceb6e88047fc1dc74b62b7c4012639c0b563906"}, {file = "watchdog-4.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:bcfd02377be80ef3b6bc4ce481ef3959640458d6feaae0bd43dd90a43da90a7d"},
{file = "watchdog-5.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1021223c08ba8d2d38d71ec1704496471ffd7be42cfb26b87cd5059323a389a1"}, {file = "watchdog-4.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:980b71510f59c884d684b3663d46e7a14b457c9611c481e5cef08f4dd022eed7"},
{file = "watchdog-5.0.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:752fb40efc7cc8d88ebc332b8f4bcbe2b5cc7e881bccfeb8e25054c00c994ee3"}, {file = "watchdog-4.0.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:aa160781cafff2719b663c8a506156e9289d111d80f3387cf3af49cedee1f040"},
{file = "watchdog-5.0.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a2e8f3f955d68471fa37b0e3add18500790d129cc7efe89971b8a4cc6fdeb0b2"}, {file = "watchdog-4.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f6ee8dedd255087bc7fe82adf046f0b75479b989185fb0bdf9a98b612170eac7"},
{file = "watchdog-5.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b8ca4d854adcf480bdfd80f46fdd6fb49f91dd020ae11c89b3a79e19454ec627"}, {file = "watchdog-4.0.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0b4359067d30d5b864e09c8597b112fe0a0a59321a0f331498b013fb097406b4"},
{file = "watchdog-5.0.3-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:90a67d7857adb1d985aca232cc9905dd5bc4803ed85cfcdcfcf707e52049eda7"}, {file = "watchdog-4.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:770eef5372f146997638d737c9a3c597a3b41037cfbc5c41538fc27c09c3a3f9"},
{file = "watchdog-5.0.3-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:720ef9d3a4f9ca575a780af283c8fd3a0674b307651c1976714745090da5a9e8"}, {file = "watchdog-4.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:eeea812f38536a0aa859972d50c76e37f4456474b02bd93674d1947cf1e39578"},
{file = "watchdog-5.0.3-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:223160bb359281bb8e31c8f1068bf71a6b16a8ad3d9524ca6f523ac666bb6a1e"}, {file = "watchdog-4.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b2c45f6e1e57ebb4687690c05bc3a2c1fb6ab260550c4290b8abb1335e0fd08b"},
{file = "watchdog-5.0.3-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:560135542c91eaa74247a2e8430cf83c4342b29e8ad4f520ae14f0c8a19cfb5b"}, {file = "watchdog-4.0.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:10b6683df70d340ac3279eff0b2766813f00f35a1d37515d2c99959ada8f05fa"},
{file = "watchdog-5.0.3-py3-none-manylinux2014_aarch64.whl", hash = "sha256:dd021efa85970bd4824acacbb922066159d0f9e546389a4743d56919b6758b91"}, {file = "watchdog-4.0.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:f7c739888c20f99824f7aa9d31ac8a97353e22d0c0e54703a547a218f6637eb3"},
{file = "watchdog-5.0.3-py3-none-manylinux2014_armv7l.whl", hash = "sha256:78864cc8f23dbee55be34cc1494632a7ba30263951b5b2e8fc8286b95845f82c"}, {file = "watchdog-4.0.2-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:c100d09ac72a8a08ddbf0629ddfa0b8ee41740f9051429baa8e31bb903ad7508"},
{file = "watchdog-5.0.3-py3-none-manylinux2014_i686.whl", hash = "sha256:1e9679245e3ea6498494b3028b90c7b25dbb2abe65c7d07423ecfc2d6218ff7c"}, {file = "watchdog-4.0.2-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:f5315a8c8dd6dd9425b974515081fc0aadca1d1d61e078d2246509fd756141ee"},
{file = "watchdog-5.0.3-py3-none-manylinux2014_ppc64.whl", hash = "sha256:9413384f26b5d050b6978e6fcd0c1e7f0539be7a4f1a885061473c5deaa57221"}, {file = "watchdog-4.0.2-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:2d468028a77b42cc685ed694a7a550a8d1771bb05193ba7b24006b8241a571a1"},
{file = "watchdog-5.0.3-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:294b7a598974b8e2c6123d19ef15de9abcd282b0fbbdbc4d23dfa812959a9e05"}, {file = "watchdog-4.0.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:f15edcae3830ff20e55d1f4e743e92970c847bcddc8b7509bcd172aa04de506e"},
{file = "watchdog-5.0.3-py3-none-manylinux2014_s390x.whl", hash = "sha256:26dd201857d702bdf9d78c273cafcab5871dd29343748524695cecffa44a8d97"}, {file = "watchdog-4.0.2-py3-none-manylinux2014_aarch64.whl", hash = "sha256:936acba76d636f70db8f3c66e76aa6cb5136a936fc2a5088b9ce1c7a3508fc83"},
{file = "watchdog-5.0.3-py3-none-manylinux2014_x86_64.whl", hash = "sha256:0f9332243355643d567697c3e3fa07330a1d1abf981611654a1f2bf2175612b7"}, {file = "watchdog-4.0.2-py3-none-manylinux2014_armv7l.whl", hash = "sha256:e252f8ca942a870f38cf785aef420285431311652d871409a64e2a0a52a2174c"},
{file = "watchdog-5.0.3-py3-none-win32.whl", hash = "sha256:c66f80ee5b602a9c7ab66e3c9f36026590a0902db3aea414d59a2f55188c1f49"}, {file = "watchdog-4.0.2-py3-none-manylinux2014_i686.whl", hash = "sha256:0e83619a2d5d436a7e58a1aea957a3c1ccbf9782c43c0b4fed80580e5e4acd1a"},
{file = "watchdog-5.0.3-py3-none-win_amd64.whl", hash = "sha256:f00b4cf737f568be9665563347a910f8bdc76f88c2970121c86243c8cfdf90e9"}, {file = "watchdog-4.0.2-py3-none-manylinux2014_ppc64.whl", hash = "sha256:88456d65f207b39f1981bf772e473799fcdc10801062c36fd5ad9f9d1d463a73"},
{file = "watchdog-5.0.3-py3-none-win_ia64.whl", hash = "sha256:49f4d36cb315c25ea0d946e018c01bb028048023b9e103d3d3943f58e109dd45"}, {file = "watchdog-4.0.2-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:32be97f3b75693a93c683787a87a0dc8db98bb84701539954eef991fb35f5fbc"},
{file = "watchdog-5.0.3.tar.gz", hash = "sha256:108f42a7f0345042a854d4d0ad0834b741d421330d5f575b81cb27b883500176"}, {file = "watchdog-4.0.2-py3-none-manylinux2014_s390x.whl", hash = "sha256:c82253cfc9be68e3e49282831afad2c1f6593af80c0daf1287f6a92657986757"},
{file = "watchdog-4.0.2-py3-none-manylinux2014_x86_64.whl", hash = "sha256:c0b14488bd336c5b1845cee83d3e631a1f8b4e9c5091ec539406e4a324f882d8"},
{file = "watchdog-4.0.2-py3-none-win32.whl", hash = "sha256:0d8a7e523ef03757a5aa29f591437d64d0d894635f8a50f370fe37f913ce4e19"},
{file = "watchdog-4.0.2-py3-none-win_amd64.whl", hash = "sha256:c344453ef3bf875a535b0488e3ad28e341adbd5a9ffb0f7d62cefacc8824ef2b"},
{file = "watchdog-4.0.2-py3-none-win_ia64.whl", hash = "sha256:baececaa8edff42cd16558a639a9b0ddf425f93d892e8392a56bf904f5eff22c"},
{file = "watchdog-4.0.2.tar.gz", hash = "sha256:b4dfbb6c49221be4535623ea4474a4d6ee0a9cef4a80b20c28db4d858b64e270"},
] ]
[package.extras] [package.extras]

View File

@ -1,6 +1,6 @@
[tool.poetry] [tool.poetry]
name = "authentik" name = "authentik"
version = "2024.8.3" version = "2024.8.2"
description = "" description = ""
authors = ["authentik Team <hello@goauthentik.io>"] authors = ["authentik Team <hello@goauthentik.io>"]

View File

@ -1,7 +1,7 @@
openapi: 3.0.3 openapi: 3.0.3
info: info:
title: authentik title: authentik
version: 2024.8.3 version: 2024.8.2
description: Making authentication simple. description: Making authentication simple.
contact: contact:
email: hello@goauthentik.io email: hello@goauthentik.io

4
tests/wdio/.eslintignore Normal file
View File

@ -0,0 +1,4 @@
# don't ever lint node_modules
node_modules
# don't lint nyc coverage output
coverage

29
tests/wdio/.eslintrc.json Normal file
View File

@ -0,0 +1,29 @@
{
"env": {
"browser": true,
"es2021": true
},
"extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 12,
"sourceType": "module"
},
"plugins": ["@typescript-eslint"],
"rules": {
"indent": "off",
"linebreak-style": ["error", "unix"],
"quotes": ["error", "double", { "avoidEscape": true }],
"semi": ["error", "always"],
"@typescript-eslint/ban-ts-comment": "off",
"no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": [
"error",
{
"argsIgnorePattern": "^_",
"varsIgnorePattern": "^_",
"caughtErrorsIgnorePattern": "^_"
}
]
}
}

View File

@ -0,0 +1,26 @@
{
"env": {
"browser": true,
"es2021": true
},
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:sonarjs/recommended"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 12,
"sourceType": "module"
},
"plugins": ["@typescript-eslint", "sonarjs"],
"rules": {
"indent": "off",
"linebreak-style": ["error", "unix"],
"quotes": ["error", "double", { "avoidEscape": true }],
"semi": ["error", "always"],
"@typescript-eslint/ban-ts-comment": "off",
"sonarjs/cognitive-complexity": ["error", 9],
"sonarjs/no-nested-template-literals": "off"
}
}

View File

@ -1,84 +0,0 @@
import eslint from "@eslint/js";
import tsparser from "@typescript-eslint/parser";
import litconf from "eslint-plugin-lit";
import wcconf from "eslint-plugin-wc";
import globals from "globals";
import tseslint from "typescript-eslint";
export default [
// You would not believe how much this change has frustrated users: ["if an ignores key is used
// without any other keys in the configuration object, then the patterns act as global
// ignores"](https://eslint.org/docs/latest/use/configure/ignore)
{
ignores: [
"dist/",
// don't lint the cache
".wireit/",
// let packages have their own configurations
"packages/",
// don't ever lint node_modules
"node_modules/",
".storybook/*",
// don't lint build output (make sure it's set to your correct build folder name)
// don't lint nyc coverage output
"coverage/",
"src/locale-codes.ts",
"storybook-static/",
"src/locales/",
],
},
eslint.configs.recommended,
wcconf.configs["flat/recommended"],
litconf.configs["flat/recommended"],
...tseslint.configs.recommended,
{
languageOptions: {
parser: tsparser,
parserOptions: {
ecmaVersion: 12,
sourceType: "module",
},
},
files: ["src/**"],
rules: {
"no-unused-vars": "off",
"no-console": ["error", { allow: ["debug", "warn", "error"] }],
"@typescript-eslint/ban-ts-comment": "off",
"@typescript-eslint/no-unused-vars": [
"error",
{
argsIgnorePattern: "^_",
varsIgnorePattern: "^_",
caughtErrorsIgnorePattern: "^_",
},
],
},
},
{
languageOptions: {
parser: tsparser,
parserOptions: {
ecmaVersion: 12,
sourceType: "module",
},
globals: {
...globals.nodeBuiltin,
},
},
files: ["scripts/*.mjs", "*.ts", "*.mjs"],
rules: {
"no-unused-vars": "off",
// We WANT our scripts to output to the console!
"no-console": "off",
"@typescript-eslint/ban-ts-comment": "off",
"@typescript-eslint/no-unused-vars": [
"error",
{
argsIgnorePattern: "^_",
varsIgnorePattern: "^_",
caughtErrorsIgnorePattern: "^_",
},
],
},
},
];

File diff suppressed because it is too large Load Diff

View File

@ -1,44 +1,37 @@
{ {
"name": "@goauthentik/web-tests", "name": "@goauthentik/web-tests",
"dependencies": { "private": true,
"chromedriver": "^129.0.1", "type": "module",
"lockfile-lint": "^4.14.0",
"syncpack": "^13.0.0"
},
"devDependencies": { "devDependencies": {
"@eslint/js": "^9.11.1",
"@trivago/prettier-plugin-sort-imports": "^4.3.0", "@trivago/prettier-plugin-sort-imports": "^4.3.0",
"@types/mocha": "^10.0.8", "@typescript-eslint/eslint-plugin": "^7.17.0",
"@typescript-eslint/eslint-plugin": "^8.7.0", "@typescript-eslint/parser": "^7.17.0",
"@typescript-eslint/parser": "^8.7.0", "@wdio/cli": "^9.0.3",
"@wdio/cli": "^9.1.2", "@wdio/local-runner": "^9.0.1",
"@wdio/local-runner": "^9.1.2", "@wdio/mocha-framework": "^8.40.2",
"@wdio/mocha-framework": "^9.1.2", "@wdio/spec-reporter": "^8.39.0",
"@wdio/spec-reporter": "^9.1.2", "eslint": "^8.57.0",
"eslint-plugin-lit": "^1.14.0", "eslint-config-google": "^0.14.0",
"eslint-plugin-sonarjs": "^2.0.2", "eslint-plugin-sonarjs": "^1.0.3",
"eslint-plugin-wc": "^2.1.0",
"eslint": "^9.11.1",
"npm-run-all": "^4.1.5", "npm-run-all": "^4.1.5",
"prettier": "^3.3.3", "prettier": "^3.3.3",
"typescript-eslint": "^8.7.0", "ts-node": "^10.9.2",
"typescript": "^5.6.2", "typescript": "^5.5.4",
"wdio-wait-for": "^3.0.11" "wdio-wait-for": "^3.0.11"
}, },
"scripts": {
"wdio": "wdio run ./wdio.conf.ts",
"lint:precommit": "eslint --max-warnings 0 --config ./.eslintrc.precommit.json $(git status --porcelain . | grep '^[AM?][M?]' | cut -d'/' -f3- | grep -E '\\.(ts|js|tsx|jsx)$')",
"lint": "eslint . --max-warnings 0 --fix",
"lint:spelling": "codespell -D - -D $(git rev-parse --show-toplevel 2> /dev/null)/.github/codespell-dictionary.txt -I $(git rev-parse --show-toplevel 2> /dev/null)/.github/codespell-words.txt ./test -s",
"precommit": "run-s lint:precommit lint:spelling prettier",
"prettier-check": "prettier --check .",
"prettier": "prettier --write ."
},
"engines": { "engines": {
"node": ">=20" "node": ">=20"
}, },
"private": true, "dependencies": {
"scripts": { "chromedriver": "^128.0.0"
"lint": "eslint . --max-warnings 0 --fix", }
"lint:lockfile": "lockfile-lint --path package.json --type npm --allowed-hosts npm --validate-https",
"lint:package": "syncpack format -i ' '",
"lint:precommit": "eslint --max-warnings 0 --config ./.eslintrc.precommit.json $(git status --porcelain . | grep '^[AM?][M?]' | cut -d'/' -f3- | grep -E '\\.(ts|js|tsx|jsx)$')",
"lint:spelling": "codespell -D - -D $(git rev-parse --show-toplevel 2> /dev/null)/.github/codespell-dictionary.txt -I $(git rev-parse --show-toplevel 2> /dev/null)/.github/codespell-words.txt ./test -s",
"precommit": "run-s lint:precommit lint:spelling prettier",
"prettier": "prettier --write .",
"prettier-check": "prettier --check .",
"wdio": "wdio run ./wdio.conf.ts"
},
"type": "module"
} }

View File

@ -1,11 +1,25 @@
import Page from "../pageobjects/page.js"; import Page from "../pageobjects/page.js";
import { browser } from "@wdio/globals";
const CLICK_TIME_DELAY = 250;
export default class AdminPage extends Page { export default class AdminPage extends Page {
public async pageHeader() { public get pageHeader() {
return await $("ak-page-header").$('slot[name="header"]'); return $('>>>ak-page-header slot[name="header"]');
} }
async openApplicationsListPage() { async openApplicationsListPage() {
await this.open("if/admin/#/core/applications"); await this.open("if/admin/#/core/applications");
} }
public open(path: string) {
return browser.url(`http://localhost:9000/${path}`);
}
public pause(selector?: string) {
if (selector) {
return $(selector).waitForDisplayed();
}
return browser.pause(CLICK_TIME_DELAY);
}
} }

View File

@ -27,24 +27,24 @@ class ApplicationWizardView extends AdminPage {
radius = RadiusForm; radius = RadiusForm;
app = ApplicationForm; app = ApplicationForm;
async wizardTitle() { get wizardTitle() {
return await $("ak-wizard-frame").$(".pf-c-wizard__title"); return $(">>>ak-wizard-frame .pf-c-wizard__header h1.pf-c-title");
} }
async providerList() { get providerList() {
return await $("ak-application-wizard-authentication-method-choice"); return $(">>>ak-application-wizard-authentication-method-choice");
} }
async nextButton() { get nextButton() {
return await $("ak-wizard-frame").$("footer button.pf-m-primary"); return $(">>>ak-wizard-frame footer button.pf-m-primary");
} }
async getProviderType(type: string) { async getProviderType(type: string) {
return await this.providerList().$(`input[value="${type}"]`); return await this.providerList.$(`>>>input[value="${type}"]`);
} }
async successMessage() { get successMessage() {
return await $('[data-commit-state="success"]'); return $('>>>[data-commit-state="success"]');
} }
} }
@ -65,10 +65,8 @@ const providerValues: Pair[] = [
providerValues.forEach(([value, name]: Pair) => { providerValues.forEach(([value, name]: Pair) => {
Object.defineProperties(ApplicationWizardView.prototype, { Object.defineProperties(ApplicationWizardView.prototype, {
[name]: { [name]: {
get: async function () { get: function () {
return await ( return this.providerList.$(`>>>input[value="${value}"]`);
await this.providerList()
).$(`div[data-ouid-component-name="${value}"]`);
}, },
}, },
}); });

View File

@ -9,8 +9,8 @@ class ApplicationsListPage extends AdminPage {
* define selectors using getter methods * define selectors using getter methods
*/ */
async startWizardButton() { get startWizardButton() {
return await $("ak-application-wizard").$('button[slot="trigger"]'); return $('>>>ak-wizard-frame button[slot="trigger"]');
} }
async open() { async open() {

View File

@ -2,16 +2,16 @@ import Page from "../page.js";
import { $ } from "@wdio/globals"; import { $ } from "@wdio/globals";
export class ApplicationForm extends Page { export class ApplicationForm extends Page {
async name() { get name() {
return await $('ak-text-input[name="name"]').$("input"); return $('>>>ak-form-element-horizontal input[name="name"]');
} }
async uiSettings() { get uiSettings() {
return await $("ak-form-group").$('button[aria-label="UI Settings"]'); return $('>>>ak-form-group button[aria-label="UI Settings"]');
} }
async launchUrl() { get launchUrl() {
return await $('input[name="metaLaunchUrl"]'); return $('>>>input[name="metaLaunchUrl"]');
} }
} }

View File

@ -4,14 +4,14 @@ import { $ } from "@wdio/globals";
export class ForwardProxyForm extends Page { export class ForwardProxyForm extends Page {
async setAuthorizationFlow(selector: string) { async setAuthorizationFlow(selector: string) {
await this.searchSelect( await this.searchSelect(
'ak-flow-search[name="authorizationFlow"]', '>>>ak-flow-search[name="authorizationFlow"] input[type="text"]',
"authorizationFlow", "authorizationFlow",
selector, `button*=${selector}`,
); );
} }
get externalHost() { get externalHost() {
return $('input[name="externalHost"]'); return $('>>>input[name="externalHost"]');
} }
} }

View File

@ -1,11 +1,11 @@
import Page from "../page.js"; import Page from "../page.js";
export class LdapForm extends Page { export class LdapForm extends Page {
async setBindFlow() { async setBindFlow(selector: string) {
await this.searchSelect( await this.searchSelect(
'ak-search-select-view[name="authorizationFlow"]', '>>>ak-branded-flow-search[name="authorizationFlow"] input[type="text"]',
"authorizationFlow", "authorizationFlow",
"default-authentication-flow", `button*=${selector}`,
); );
} }
} }

View File

@ -4,14 +4,14 @@ import { $ } from "@wdio/globals";
export class OauthForm extends Page { export class OauthForm extends Page {
async setAuthorizationFlow(selector: string) { async setAuthorizationFlow(selector: string) {
await this.searchSelect( await this.searchSelect(
'ak-flow-search[name="authorizationFlow"]', '>>>ak-flow-search[name="authorizationFlow"] input[type="text"]',
"authorizationFlow", "authorizationFlow",
`${selector}`, `button*=${selector}`,
); );
} }
async providerName() { get providerName() {
return await $('ak-form-element-horizontal[name="name"]').$("input"); return $('>>>ak-form-element-horizontal[name="name"] input');
} }
} }

View File

@ -3,9 +3,9 @@ import Page from "../page.js";
export class RadiusForm extends Page { export class RadiusForm extends Page {
async setAuthenticationFlow(selector: string) { async setAuthenticationFlow(selector: string) {
await this.searchSelect( await this.searchSelect(
'ak-branded-flow-search[name="authorizationFlow"]', '>>>ak-branded-flow-search[name="authorizationFlow"] input[type="text"]',
"authorizationFlow", "authorizationFlow",
selector, `button*=${selector}`,
); );
} }
} }

View File

@ -4,14 +4,14 @@ import { $ } from "@wdio/globals";
export class SamlForm extends Page { export class SamlForm extends Page {
async setAuthorizationFlow(selector: string) { async setAuthorizationFlow(selector: string) {
await this.searchSelect( await this.searchSelect(
'ak-flow-search[name="authorizationFlow"]', '>>>ak-flow-search[name="authorizationFlow"] input[type="text"]',
"authorizationFlow", "authorizationFlow",
selector, `button*=${selector}`,
); );
} }
get acsUrl() { get acsUrl() {
return $('input[name="acsUrl"]'); return $('>>>input[name="acsUrl"]');
} }
} }

View File

@ -2,11 +2,11 @@ import Page from "../page.js";
export class ScimForm extends Page { export class ScimForm extends Page {
get url() { get url() {
return $('input[name="url"]'); return $('>>>input[name="url"]');
} }
get token() { get token() {
return $('input[name="token"]'); return $('>>>input[name="token"]');
} }
} }

View File

@ -4,18 +4,18 @@ import { $ } from "@wdio/globals";
export class TransparentProxyForm extends Page { export class TransparentProxyForm extends Page {
async setAuthorizationFlow(selector: string) { async setAuthorizationFlow(selector: string) {
await this.searchSelect( await this.searchSelect(
'ak-flow-search[name="authorizationFlow"]', '>>>ak-flow-search[name="authorizationFlow"] input[type="text"]',
"authorizationFlow", "authorizationFlow",
selector, `button*=${selector}`,
); );
} }
get externalHost() { get externalHost() {
return $('input[name="externalHost"]'); return $('>>>input[name="externalHost"]');
} }
get internalHost() { get internalHost() {
return $('input[name="internalHost"]'); return $('>>>input[name="internalHost"]');
} }
} }

View File

@ -9,20 +9,20 @@ class LoginPage extends Page {
/** /**
* Selectors * Selectors
*/ */
async inputUsername() { get inputUsername() {
return await $('input[name="uidField"]'); return $('>>>input[name="uidField"]');
} }
async inputPassword() { get inputPassword() {
return await $('input[name="password"]'); return $('>>>input[name="password"]');
} }
async btnSubmit() { get btnSubmit() {
return await $('button[type="submit"]'); return $('>>>button[type="submit"]');
} }
async authFailure() { get authFailure() {
return await $(".pf-m-error"); return $(">>>h4.pf-c-alert__title");
} }
/** /**
@ -30,15 +30,17 @@ class LoginPage extends Page {
*/ */
async username(username: string) { async username(username: string) {
await (await this.inputUsername()).setValue(username); await this.inputUsername.waitForClickable();
await (await this.btnSubmit()).waitForEnabled(); await this.inputUsername.setValue(username);
await (await this.btnSubmit()).click(); await this.btnSubmit.waitForEnabled();
await this.btnSubmit.click();
} }
async password(password: string) { async password(password: string) {
await (await this.inputPassword()).setValue(password); await this.inputPassword.waitForClickable();
await (await this.btnSubmit()).waitForEnabled(); await this.inputPassword.setValue(password);
await (await this.btnSubmit()).click(); await this.btnSubmit.waitForEnabled();
await this.btnSubmit.click();
} }
async login(username: string, password: string) { async login(username: string, password: string) {
@ -46,7 +48,7 @@ class LoginPage extends Page {
await this.pause(); await this.pause();
await this.password(password); await this.password(password);
await this.pause(); await this.pause();
await this.pause("div.header h1"); await this.pause(">>>div.header h1");
return UserLibraryPage; return UserLibraryPage;
} }

View File

@ -1,5 +1,4 @@
import { browser } from "@wdio/globals"; import { browser } from "@wdio/globals";
import { Key } from "webdriverio";
const CLICK_TIME_DELAY = 250; const CLICK_TIME_DELAY = 250;
@ -12,15 +11,15 @@ export default class Page {
* Opens a sub page of the page * Opens a sub page of the page
* @param path path of the sub page (e.g. /path/to/page.html) * @param path path of the sub page (e.g. /path/to/page.html)
*/ */
public async open(path: string) { public open(path: string) {
return await browser.url(`http://localhost:9000/${path}`); return browser.url(`http://localhost:9000/${path}`);
} }
public async pause(selector?: string) { public pause(selector?: string) {
if (selector) { if (selector) {
return await $(selector).waitForDisplayed(); return $(selector).waitForDisplayed();
} }
return await browser.pause(CLICK_TIME_DELAY); return browser.pause(CLICK_TIME_DELAY);
} }
/** /**
@ -34,20 +33,10 @@ export default class Page {
async searchSelect(searchSelector: string, managedSelector: string, buttonSelector: string) { async searchSelect(searchSelector: string, managedSelector: string, buttonSelector: string) {
const inputBind = await $(searchSelector); const inputBind = await $(searchSelector);
const inputMain = await inputBind.$('input[type="text"]'); await inputBind.click();
await inputMain.click(); const searchBlock = await $(`>>>div[data-managed-for="${managedSelector}"]`);
const searchBlock = await ( const target = searchBlock.$(buttonSelector);
await $(`div[data-managed-for="${managedSelector}"]`).$("ak-list-select") return await target.click();
).shadow$$("button");
let target: WebdriverIO.Element;
for (const button of searchBlock) {
if ((await button.getText()).includes(buttonSelector)) {
target = button;
break;
}
}
await (await target).click();
await browser.keys(Key.Tab);
} }
public async logout() { public async logout() {

View File

@ -9,13 +9,13 @@ class UserLibraryPage extends Page {
* define selectors using getter methods * define selectors using getter methods
*/ */
public async pageHeader() { public get pageHeader() {
return await $('h1[aria-level="1"]'); return $('>>>h1[aria-level="1"]');
} }
public async goToAdmin() { public async goToAdmin() {
await $('a[href="/if/admin"]').click(); await $('>>>a[href="/if/admin"]').click();
return await $("ak-admin-overview").waitForDisplayed(); await $(">>>ak-admin-overview").waitForDisplayed();
} }
} }

View File

@ -1,15 +0,0 @@
import LoginPage from "../pageobjects/login.page.js";
import { BAD_PASSWORD, GOOD_USERNAME } from "../utils/constants.js";
import { expect } from "@wdio/globals";
describe("Log into authentik", () => {
it("should fail on a bad password", async () => {
await LoginPage.open();
await LoginPage.username(GOOD_USERNAME);
await LoginPage.pause();
await LoginPage.password(BAD_PASSWORD);
const failure = await LoginPage.authFailure();
await expect(failure).toBeDisplayedInViewport();
await expect(failure).toHaveText("Invalid password");
});
});

View File

@ -1,15 +1,21 @@
import LoginPage from "../pageobjects/login.page.js"; import LoginPage from "../pageobjects/login.page.js";
import { BAD_USERNAME, GOOD_PASSWORD } from "../utils/constants.js"; import { BAD_PASSWORD, BAD_USERNAME, GOOD_USERNAME } from "../utils/constants.js";
import { expect } from "@wdio/globals"; import { expect } from "@wdio/globals";
describe("Log into authentik", () => { describe("Log into authentik", () => {
it("should fail on a bad username", async () => { it("should fail on a bad username", async () => {
await LoginPage.open(); await LoginPage.open();
await LoginPage.username(BAD_USERNAME); await LoginPage.username(BAD_USERNAME);
const failure = await LoginPage.authFailure;
expect(failure).toHaveText("Failed to authenticate.");
});
it("should fail on a bad password", async () => {
await LoginPage.open();
await LoginPage.username(GOOD_USERNAME);
await LoginPage.pause(); await LoginPage.pause();
await LoginPage.password(GOOD_PASSWORD); await LoginPage.password(BAD_PASSWORD);
const failure = await LoginPage.authFailure(); const failure = await LoginPage.authFailure;
await expect(failure).toBeDisplayedInViewport(); expect(failure).toHaveText("Failed to authenticate.");
await expect(failure).toHaveText("Invalid password");
}); });
}); });

View File

@ -10,27 +10,25 @@ async function reachTheProvider(title: string) {
await ApplicationsListPage.logout(); await ApplicationsListPage.logout();
await login(); await login();
await ApplicationsListPage.open(); await ApplicationsListPage.open();
await ApplicationsListPage.pause("ak-page-header"); await expect(await ApplicationsListPage.pageHeader).toHaveText("Applications");
await expect(await ApplicationsListPage.pageHeader()).toBeDisplayed();
await expect(await ApplicationsListPage.pageHeader()).toHaveText("Applications");
await (await ApplicationsListPage.startWizardButton()).click(); await ApplicationsListPage.startWizardButton.click();
await (await ApplicationWizardView.wizardTitle()).waitForDisplayed(); await ApplicationWizardView.wizardTitle.waitForDisplayed();
await expect(await ApplicationWizardView.wizardTitle()).toHaveText("New application"); await expect(await ApplicationWizardView.wizardTitle).toHaveText("New application");
await (await ApplicationWizardView.app.name()).setValue(`${title} - ${newPrefix}`); await ApplicationWizardView.app.name.setValue(`${title} - ${newPrefix}`);
await (await ApplicationWizardView.app.uiSettings()).scrollIntoView(); await ApplicationWizardView.app.uiSettings.scrollIntoView();
await (await ApplicationWizardView.app.uiSettings()).click(); await ApplicationWizardView.app.uiSettings.click();
await (await ApplicationWizardView.app.launchUrl()).scrollIntoView(); await ApplicationWizardView.app.launchUrl.scrollIntoView();
await (await ApplicationWizardView.app.launchUrl()).setValue("http://example.goauthentik.io"); await ApplicationWizardView.app.launchUrl.setValue("http://example.goauthentik.io");
await (await ApplicationWizardView.nextButton()).click(); await ApplicationWizardView.nextButton.click();
return await ApplicationWizardView.pause(); return await ApplicationWizardView.pause();
} }
async function getCommitMessage() { async function getCommitMessage() {
await (await ApplicationWizardView.successMessage()).waitForDisplayed(); await ApplicationWizardView.successMessage.waitForDisplayed();
return await ApplicationWizardView.successMessage(); return await ApplicationWizardView.successMessage;
} }
const SUCCESS_MESSAGE = "Your application has been saved"; const SUCCESS_MESSAGE = "Your application has been saved";
@ -40,97 +38,97 @@ describe("Configure Applications with the Application Wizard", () => {
it("Should configure a simple LDAP Application", async () => { it("Should configure a simple LDAP Application", async () => {
await reachTheProvider("New LDAP Application"); await reachTheProvider("New LDAP Application");
await (await ApplicationWizardView.providerList()).waitForDisplayed(); await ApplicationWizardView.providerList.waitForDisplayed();
await (await ApplicationWizardView.ldapProvider).scrollIntoView(); await ApplicationWizardView.ldapProvider.scrollIntoView();
await (await ApplicationWizardView.ldapProvider).click(); await ApplicationWizardView.ldapProvider.click();
await (await ApplicationWizardView.nextButton()).click(); await ApplicationWizardView.nextButton.click();
await ApplicationWizardView.pause(); await ApplicationWizardView.pause();
await ApplicationWizardView.ldap.setBindFlow("default-authentication-flow"); await ApplicationWizardView.ldap.setBindFlow("default-authentication-flow");
await (await ApplicationWizardView.nextButton()).click(); await ApplicationWizardView.nextButton.click();
await ApplicationWizardView.pause(); await ApplicationWizardView.pause();
await expect(await getCommitMessage()).toHaveText(SUCCESS_MESSAGE); await expect(getCommitMessage()).toHaveText(SUCCESS_MESSAGE);
}); });
it("Should configure a simple Oauth2 Application", async () => { it("Should configure a simple Oauth2 Application", async () => {
await reachTheProvider("New Oauth2 Application"); await reachTheProvider("New Oauth2 Application");
await (await ApplicationWizardView.providerList()).waitForDisplayed(); await ApplicationWizardView.providerList.waitForDisplayed();
await (await ApplicationWizardView.oauth2Provider).scrollIntoView(); await ApplicationWizardView.oauth2Provider.scrollIntoView();
await (await ApplicationWizardView.oauth2Provider).click(); await ApplicationWizardView.oauth2Provider.click();
await (await ApplicationWizardView.nextButton()).click(); await ApplicationWizardView.nextButton.click();
await ApplicationWizardView.pause(); await ApplicationWizardView.pause();
await ApplicationWizardView.oauth.setAuthorizationFlow(EXPLICIT_CONSENT); await ApplicationWizardView.oauth.setAuthorizationFlow(EXPLICIT_CONSENT);
await (await ApplicationWizardView.nextButton()).click(); await ApplicationWizardView.nextButton.click();
await ApplicationWizardView.pause(); await ApplicationWizardView.pause();
await expect(await getCommitMessage()).toHaveText(SUCCESS_MESSAGE); await expect(getCommitMessage()).toHaveText(SUCCESS_MESSAGE);
}); });
it("Should configure a simple SAML Application", async () => { it("Should configure a simple SAML Application", async () => {
await reachTheProvider("New SAML Application"); await reachTheProvider("New SAML Application");
await (await ApplicationWizardView.providerList()).waitForDisplayed(); await ApplicationWizardView.providerList.waitForDisplayed();
await (await ApplicationWizardView.samlProvider).scrollIntoView(); await ApplicationWizardView.samlProvider.scrollIntoView();
await (await ApplicationWizardView.samlProvider).click(); await ApplicationWizardView.samlProvider.click();
await (await ApplicationWizardView.nextButton()).click(); await ApplicationWizardView.nextButton.click();
await ApplicationWizardView.pause(); await ApplicationWizardView.pause();
await ApplicationWizardView.saml.setAuthorizationFlow(EXPLICIT_CONSENT); await ApplicationWizardView.saml.setAuthorizationFlow(EXPLICIT_CONSENT);
await ApplicationWizardView.saml.acsUrl.setValue("http://example.com:8000/"); await ApplicationWizardView.saml.acsUrl.setValue("http://example.com:8000/");
await (await ApplicationWizardView.nextButton()).click(); await ApplicationWizardView.nextButton.click();
await ApplicationWizardView.pause(); await ApplicationWizardView.pause();
await expect(await getCommitMessage()).toHaveText(SUCCESS_MESSAGE); await expect(getCommitMessage()).toHaveText(SUCCESS_MESSAGE);
}); });
it("Should configure a simple SCIM Application", async () => { it("Should configure a simple SCIM Application", async () => {
await reachTheProvider("New SCIM Application"); await reachTheProvider("New SCIM Application");
await (await ApplicationWizardView.providerList()).waitForDisplayed(); await ApplicationWizardView.providerList.waitForDisplayed();
await (await ApplicationWizardView.scimProvider).scrollIntoView(); await ApplicationWizardView.scimProvider.scrollIntoView();
await (await ApplicationWizardView.scimProvider).click(); await ApplicationWizardView.scimProvider.click();
await (await ApplicationWizardView.nextButton()).click(); await ApplicationWizardView.nextButton.click();
await ApplicationWizardView.pause(); await ApplicationWizardView.pause();
await ApplicationWizardView.scim.url.setValue("http://example.com:8000/"); await ApplicationWizardView.scim.url.setValue("http://example.com:8000/");
await ApplicationWizardView.scim.token.setValue("a-very-basic-token"); await ApplicationWizardView.scim.token.setValue("a-very-basic-token");
await (await ApplicationWizardView.nextButton()).click(); await ApplicationWizardView.nextButton.click();
await ApplicationWizardView.pause(); await ApplicationWizardView.pause();
await expect(await getCommitMessage()).toHaveText(SUCCESS_MESSAGE); await expect(getCommitMessage()).toHaveText(SUCCESS_MESSAGE);
}); });
it("Should configure a simple Radius Application", async () => { it("Should configure a simple Radius Application", async () => {
await reachTheProvider("New Radius Application"); await reachTheProvider("New Radius Application");
await (await ApplicationWizardView.providerList()).waitForDisplayed(); await ApplicationWizardView.providerList.waitForDisplayed();
await (await ApplicationWizardView.radiusProvider).scrollIntoView(); await ApplicationWizardView.radiusProvider.scrollIntoView();
await (await ApplicationWizardView.radiusProvider).click(); await ApplicationWizardView.radiusProvider.click();
await (await ApplicationWizardView.nextButton()).click(); await ApplicationWizardView.nextButton.click();
await ApplicationWizardView.pause(); await ApplicationWizardView.pause();
await ApplicationWizardView.radius.setAuthenticationFlow("default-authentication-flow"); await ApplicationWizardView.radius.setAuthenticationFlow("default-authentication-flow");
await (await ApplicationWizardView.nextButton()).click(); await ApplicationWizardView.nextButton.click();
await ApplicationWizardView.pause(); await ApplicationWizardView.pause();
await expect(await getCommitMessage()).toHaveText(SUCCESS_MESSAGE); await expect(getCommitMessage()).toHaveText(SUCCESS_MESSAGE);
}); });
it("Should configure a simple Transparent Proxy Application", async () => { it("Should configure a simple Transparent Proxy Application", async () => {
await reachTheProvider("New Transparent Proxy Application"); await reachTheProvider("New Transparent Proxy Application");
await (await ApplicationWizardView.providerList()).waitForDisplayed(); await ApplicationWizardView.providerList.waitForDisplayed();
await (await ApplicationWizardView.proxyProviderProxy).scrollIntoView(); await ApplicationWizardView.proxyProviderProxy.scrollIntoView();
await (await ApplicationWizardView.proxyProviderProxy).click(); await ApplicationWizardView.proxyProviderProxy.click();
await (await ApplicationWizardView.nextButton()).click(); await ApplicationWizardView.nextButton.click();
await ApplicationWizardView.pause(); await ApplicationWizardView.pause();
await ApplicationWizardView.transparentProxy.setAuthorizationFlow(EXPLICIT_CONSENT); await ApplicationWizardView.transparentProxy.setAuthorizationFlow(EXPLICIT_CONSENT);
@ -141,19 +139,19 @@ describe("Configure Applications with the Application Wizard", () => {
"http://internal.example.com", "http://internal.example.com",
); );
await (await ApplicationWizardView.nextButton()).click(); await ApplicationWizardView.nextButton.click();
await ApplicationWizardView.pause(); await ApplicationWizardView.pause();
await expect(await getCommitMessage()).toHaveText(SUCCESS_MESSAGE); await expect(getCommitMessage()).toHaveText(SUCCESS_MESSAGE);
}); });
it("Should configure a simple Forward Proxy Application", async () => { it("Should configure a simple Forward Proxy Application", async () => {
await reachTheProvider("New Forward Proxy Application"); await reachTheProvider("New Forward Proxy Application");
await (await ApplicationWizardView.providerList()).waitForDisplayed(); await ApplicationWizardView.providerList.waitForDisplayed();
await (await ApplicationWizardView.proxyProviderForwardsingle).scrollIntoView(); await ApplicationWizardView.proxyProviderForwardsingle.scrollIntoView();
await (await ApplicationWizardView.proxyProviderForwardsingle).click(); await ApplicationWizardView.proxyProviderForwardsingle.click();
await (await ApplicationWizardView.nextButton()).click(); await ApplicationWizardView.nextButton.click();
await ApplicationWizardView.pause(); await ApplicationWizardView.pause();
await ApplicationWizardView.forwardProxy.setAuthorizationFlow(EXPLICIT_CONSENT); await ApplicationWizardView.forwardProxy.setAuthorizationFlow(EXPLICIT_CONSENT);
@ -161,9 +159,9 @@ describe("Configure Applications with the Application Wizard", () => {
"http://external.example.com", "http://external.example.com",
); );
await (await ApplicationWizardView.nextButton()).click(); await ApplicationWizardView.nextButton.click();
await ApplicationWizardView.pause(); await ApplicationWizardView.pause();
await expect(await getCommitMessage()).toHaveText(SUCCESS_MESSAGE); await expect(getCommitMessage()).toHaveText(SUCCESS_MESSAGE);
}); });
}); });

View File

@ -6,5 +6,5 @@ import { expect } from "@wdio/globals";
export const login = async () => { export const login = async () => {
await LoginPage.open(); await LoginPage.open();
await LoginPage.login(GOOD_USERNAME, GOOD_PASSWORD); await LoginPage.login(GOOD_USERNAME, GOOD_PASSWORD);
await expect(await UserLibraryPage.pageHeader()).toHaveText("My applications"); await expect(UserLibraryPage.pageHeader).toHaveText("My applications");
}; };

View File

@ -3,7 +3,7 @@
"moduleResolution": "node", "moduleResolution": "node",
"module": "ESNext", "module": "ESNext",
"target": "es2022", "target": "es2022",
"types": ["node", "@wdio/globals/types", "expect-webdriverio", "@wdio/mocha-framework", "@types/mocha"], "types": ["node", "@wdio/globals/types", "expect-webdriverio", "@wdio/mocha-framework"],
"skipLibCheck": true, "skipLibCheck": true,
"noEmit": true, "noEmit": true,
"allowImportingTsExtensions": true, "allowImportingTsExtensions": true,

View File

@ -1,11 +1,19 @@
export const config: WebdriverIO.Config = { import type { Options } from "@wdio/types";
export const config: Options.Testrunner = {
// //
// ==================== // ====================
// Runner Configuration // Runner Configuration
// ==================== // ====================
// WebdriverIO supports running e2e tests as well as unit and component tests. // WebdriverIO supports running e2e tests as well as unit and component tests.
runner: "local", runner: "local",
tsConfigPath: "./tsconfig.json", autoCompileOpts: {
autoCompile: true,
tsNodeOpts: {
project: "./tsconfig.json",
transpileOnly: true,
},
},
// //
// ================== // ==================

View File

@ -0,0 +1,30 @@
{
"env": {
"browser": true,
"es2021": true
},
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:lit/recommended",
"plugin:custom-elements/recommended",
"plugin:storybook/recommended",
"plugin:sonarjs/recommended"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 12,
"sourceType": "module"
},
"plugins": ["@typescript-eslint", "lit", "custom-elements", "sonarjs"],
"rules": {
"indent": "off",
"linebreak-style": ["error", "unix"],
"quotes": ["error", "double", { "avoidEscape": true }],
"semi": ["error", "always"],
"@typescript-eslint/ban-ts-comment": "off",
"sonarjs/cognitive-complexity": ["warn", 9],
"sonarjs/no-duplicate-string": "off",
"sonarjs/no-nested-template-literals": "off"
}
}

9180
web/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -8,18 +8,18 @@
"@codemirror/lang-xml": "^6.1.0", "@codemirror/lang-xml": "^6.1.0",
"@codemirror/legacy-modes": "^6.4.1", "@codemirror/legacy-modes": "^6.4.1",
"@codemirror/theme-one-dark": "^6.1.2", "@codemirror/theme-one-dark": "^6.1.2",
"@floating-ui/dom": "^1.6.11", "@floating-ui/dom": "^1.6.9",
"@formatjs/intl-listformat": "^7.5.7", "@formatjs/intl-listformat": "^7.5.7",
"@fortawesome/fontawesome-free": "^6.6.0", "@fortawesome/fontawesome-free": "^6.6.0",
"@goauthentik/api": "^2024.8.3-1727449099", "@goauthentik/api": "^2024.6.3-1724414734",
"@lit/context": "^1.1.2", "@lit/context": "^1.1.2",
"@lit/localize": "^0.12.2", "@lit/localize": "^0.12.2",
"@lit/reactive-element": "^2.0.4", "@lit/reactive-element": "^2.0.4",
"@lit/task": "^1.0.1", "@lit/task": "^1.0.1",
"@open-wc/lit-helpers": "^0.7.0", "@open-wc/lit-helpers": "^0.7.0",
"@patternfly/elements": "^4.0.2", "@patternfly/elements": "^4.0.0",
"@patternfly/patternfly": "^4.224.2", "@patternfly/patternfly": "^4.224.2",
"@sentry/browser": "^8.32.0", "@sentry/browser": "^8.26.0",
"@webcomponents/webcomponentsjs": "^2.8.0", "@webcomponents/webcomponentsjs": "^2.8.0",
"base64-js": "^1.5.1", "base64-js": "^1.5.1",
"chart.js": "^4.4.4", "chart.js": "^4.4.4",
@ -32,13 +32,13 @@
"guacamole-common-js": "^1.5.0", "guacamole-common-js": "^1.5.0",
"lit": "^3.2.0", "lit": "^3.2.0",
"md-front-matter": "^1.0.4", "md-front-matter": "^1.0.4",
"mermaid": "^11.2.1", "mermaid": "^11.0.2",
"rapidoc": "^9.3.7", "rapidoc": "^9.3.4",
"showdown": "^2.1.0", "showdown": "^2.1.0",
"style-mod": "^4.1.2", "style-mod": "^4.1.2",
"ts-pattern": "^5.4.0", "ts-pattern": "^5.3.1",
"webcomponent-qr-code": "^1.2.0", "webcomponent-qr-code": "^1.2.0",
"yaml": "^2.5.1" "yaml": "^2.5.0"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.25.2", "@babel/core": "^7.25.2",
@ -49,48 +49,47 @@
"@babel/plugin-transform-runtime": "^7.25.4", "@babel/plugin-transform-runtime": "^7.25.4",
"@babel/preset-env": "^7.25.4", "@babel/preset-env": "^7.25.4",
"@babel/preset-typescript": "^7.24.7", "@babel/preset-typescript": "^7.24.7",
"@changesets/cli": "^2.27.8", "@changesets/cli": "^2.27.5",
"@custom-elements-manifest/analyzer": "^0.10.2", "@custom-elements-manifest/analyzer": "^0.10.2",
"@eslint/js": "^9.11.1", "@eslint/js": "^9.9.1",
"@genesiscommunitysuccess/custom-elements-lsp": "^5.0.3", "@genesiscommunitysuccess/custom-elements-lsp": "^5.0.3",
"@hcaptcha/types": "^1.0.4", "@hcaptcha/types": "^1.0.4",
"@jeysal/storybook-addon-css-user-preferences": "^0.2.0", "@jeysal/storybook-addon-css-user-preferences": "^0.2.0",
"@lit/localize-tools": "^0.8.0", "@lit/localize-tools": "^0.8.0",
"@rollup/plugin-replace": "^6.0.1", "@rollup/plugin-replace": "^5.0.7",
"@spotlightjs/spotlight": "^2.4.1", "@spotlightjs/spotlight": "^2.3.0",
"@storybook/addon-essentials": "^8.3.4", "@storybook/addon-essentials": "^8.2.9",
"@storybook/addon-links": "^8.3.4", "@storybook/addon-links": "^8.2.9",
"@storybook/api": "^7.6.17", "@storybook/api": "^7.6.17",
"@storybook/blocks": "^8.0.8", "@storybook/blocks": "^8.0.8",
"@storybook/manager-api": "^8.3.4", "@storybook/manager-api": "^8.2.9",
"@storybook/web-components": "^8.3.4", "@storybook/web-components": "^8.2.9",
"@storybook/web-components-vite": "^8.3.4", "@storybook/web-components-vite": "^8.2.9",
"@trivago/prettier-plugin-sort-imports": "^4.3.0", "@trivago/prettier-plugin-sort-imports": "^4.3.0",
"@types/chart.js": "^2.9.41", "@types/chart.js": "^2.9.41",
"@types/codemirror": "5.60.15", "@types/codemirror": "5.60.15",
"@types/eslint__js": "^8.42.3", "@types/eslint__js": "^8.42.3",
"@types/grecaptcha": "^3.0.9", "@types/grecaptcha": "^3.0.9",
"@types/guacamole-common-js": "1.5.2", "@types/guacamole-common-js": "1.5.2",
"@types/node": "^22.7.4",
"@types/showdown": "^2.0.6", "@types/showdown": "^2.0.6",
"@typescript-eslint/eslint-plugin": "^8.7.0", "@typescript-eslint/eslint-plugin": "^8.0.1",
"@typescript-eslint/parser": "^8.7.0", "@typescript-eslint/parser": "^8.0.1",
"@wdio/browser-runner": "^8.40.5", "@wdio/browser-runner": "^8.40.2",
"@wdio/cli": "^8.40.5", "@wdio/cli": "^8.40.2",
"@wdio/mocha-framework": "^9.1.0", "@wdio/mocha-framework": "^8.40.2",
"@wdio/spec-reporter": "^9.1.0", "@wdio/spec-reporter": "^8.36.1",
"babel-plugin-macros": "^3.1.0", "babel-plugin-macros": "^3.1.0",
"babel-plugin-tsconfig-paths": "^1.0.3", "babel-plugin-tsconfig-paths": "^1.0.3",
"chokidar": "^4.0.1", "chokidar": "^3.6.0",
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
"esbuild": "^0.24.0", "esbuild": "^0.23.1",
"eslint": "^9.11.1", "eslint": "^9.8.0",
"eslint-plugin-lit": "^1.14.0", "eslint-plugin-lit": "^1.14.0",
"eslint-plugin-sonarjs": "^1.0.4",
"eslint-plugin-wc": "^2.1.0", "eslint-plugin-wc": "^2.1.0",
"github-slugger": "^2.0.0", "github-slugger": "^2.0.0",
"glob": "^11.0.0", "glob": "^11.0.0",
"globals": "^15.9.0", "globals": "^15.9.0",
"knip": "^5.30.6",
"lit-analyzer": "^2.0.3", "lit-analyzer": "^2.0.3",
"npm-run-all": "^4.1.5", "npm-run-all": "^4.1.5",
"prettier": "^3.3.3", "prettier": "^3.3.3",
@ -105,24 +104,24 @@
"ts-lit-plugin": "^2.0.2", "ts-lit-plugin": "^2.0.2",
"ts-node": "^10.9.2", "ts-node": "^10.9.2",
"tslib": "^2.7.0", "tslib": "^2.7.0",
"turnstile-types": "^1.2.3", "turnstile-types": "^1.2.2",
"typescript": "^5.6.2", "typescript": "^5.5.4",
"typescript-eslint": "^8.7.0", "typescript-eslint": "^8.2.0",
"vite-tsconfig-paths": "^5.0.1", "vite-tsconfig-paths": "^5.0.1",
"wdio-wait-for": "^3.0.11", "wdio-wait-for": "^3.0.11",
"wireit": "^0.14.9" "wireit": "^0.14.8"
}, },
"engines": { "engines": {
"node": ">=20" "node": ">=20"
}, },
"license": "MIT", "license": "MIT",
"optionalDependencies": { "optionalDependencies": {
"@esbuild/darwin-arm64": "^0.24.0", "@esbuild/darwin-arm64": "^0.23.0",
"@esbuild/linux-amd64": "^0.18.11", "@esbuild/linux-amd64": "^0.18.11",
"@esbuild/linux-arm64": "^0.24.0", "@esbuild/linux-arm64": "^0.23.0",
"@rollup/rollup-darwin-arm64": "4.22.5", "@rollup/rollup-darwin-arm64": "4.21.0",
"@rollup/rollup-linux-arm64-gnu": "4.22.5", "@rollup/rollup-linux-arm64-gnu": "4.21.0",
"@rollup/rollup-linux-x64-gnu": "4.22.5" "@rollup/rollup-linux-x64-gnu": "4.21.0"
}, },
"private": true, "private": true,
"scripts": { "scripts": {
@ -135,7 +134,6 @@
"extract-locales": "wireit", "extract-locales": "wireit",
"format": "wireit", "format": "wireit",
"lint": "wireit", "lint": "wireit",
"lint:imports": "wireit",
"lint:lockfile": "wireit", "lint:lockfile": "wireit",
"lint:nightmare": "wireit", "lint:nightmare": "wireit",
"lint:package": "wireit", "lint:package": "wireit",
@ -150,7 +148,8 @@
"storybook:build": "wireit", "storybook:build": "wireit",
"storybook:build-import-map": "wireit", "storybook:build-import-map": "wireit",
"test": "wireit", "test": "wireit",
"test-watch": "wireit", "test-view": "wireit",
"test-watch": "npx wdio run ./wdio.conf.ts --autoCompileOpts.tsNodeOpts.project=tsconfig.test.json --watch",
"tsc": "wireit", "tsc": "wireit",
"watch": "run-s build-locales esbuild:watch" "watch": "run-s build-locales esbuild:watch"
}, },
@ -250,9 +249,6 @@
"lint:components": { "lint:components": {
"command": "lit-analyzer src" "command": "lit-analyzer src"
}, },
"lint:imports": {
"command": "knip --config scripts/knip.config.ts"
},
"lint:types": { "lint:types": {
"command": "tsc --noEmit -p .", "command": "tsc --noEmit -p .",
"dependencies": [ "dependencies": [
@ -262,7 +258,7 @@
"lint:lockfile": { "lint:lockfile": {
"__comment": "The lockfile-lint package does not have an option to ensure resolved hashes are set everywhere", "__comment": "The lockfile-lint package does not have an option to ensure resolved hashes are set everywhere",
"shell": true, "shell": true,
"command": "[ -z \"$(jq -r '.packages | to_entries[] | select((.key | contains(\"node_modules\")) and (.value | has(\"resolved\") | not)) | .key' < package-lock.json)\" ]" "command": "[ -z \"$(jq -r '.packages | to_entries[] | select((.key | startswith(\"node_modules\")) and (.value | has(\"resolved\") | not)) | .key' < package-lock.json)\" ]"
}, },
"lint:lockfiles": { "lint:lockfiles": {
"dependencies": [ "dependencies": [
@ -329,14 +325,14 @@
"command": "node scripts/build-storybook-import-maps.mjs" "command": "node scripts/build-storybook-import-maps.mjs"
}, },
"test": { "test": {
"command": "wdio ./wdio.conf.ts --logLevel=info", "command": "wdio run ./wdio.conf.ts --logLevel=warn",
"env": { "env": {
"CI": "true", "CI": "true",
"TS_NODE_PROJECT": "tsconfig.test.json" "TS_NODE_PROJECT": "tsconfig.test.json"
} }
}, },
"test-watch": { "test-view": {
"command": "wdio ./wdio.conf.ts", "command": "wdio run ./wdio.conf.ts",
"env": { "env": {
"TS_NODE_PROJECT": "tsconfig.test.json" "TS_NODE_PROJECT": "tsconfig.test.json"
} }

View File

@ -10,22 +10,22 @@
"weakmap-polyfill": "^2.0.4" "weakmap-polyfill": "^2.0.4"
}, },
"devDependencies": { "devDependencies": {
"@rollup/plugin-commonjs": "^28.0.0", "@rollup/plugin-commonjs": "^26.0.1",
"@rollup/plugin-node-resolve": "^15.3.0", "@rollup/plugin-node-resolve": "^15.2.3",
"@rollup/plugin-swc": "^0.4.0", "@rollup/plugin-swc": "^0.3.1",
"@swc/cli": "^0.4.0", "@swc/cli": "^0.4.0",
"@swc/core": "^1.7.28", "@swc/core": "^1.7.18",
"@trivago/prettier-plugin-sort-imports": "^4.3.0", "@trivago/prettier-plugin-sort-imports": "^4.3.0",
"@types/jquery": "^3.5.31", "@types/jquery": "^3.5.30",
"lockfile-lint": "^4.14.0", "lockfile-lint": "^4.14.0",
"prettier": "^3.3.2", "prettier": "^3.3.2",
"rollup": "^4.22.5", "rollup": "^4.21.0",
"rollup-plugin-copy": "^3.5.0", "rollup-plugin-copy": "^3.5.0",
"wireit": "^0.14.9" "wireit": "^0.14.8"
}, },
"license": "MIT", "license": "MIT",
"optionalDependencies": { "optionalDependencies": {
"@swc/core": "^1.7.28", "@swc/core": "^1.7.18",
"@swc/core-darwin-arm64": "^1.6.13", "@swc/core-darwin-arm64": "^1.6.13",
"@swc/core-darwin-x64": "^1.6.13", "@swc/core-darwin-x64": "^1.6.13",
"@swc/core-linux-arm-gnueabihf": "^1.6.13", "@swc/core-linux-arm-gnueabihf": "^1.6.13",

View File

@ -0,0 +1,67 @@
import { execFileSync } from "child_process";
import { ESLint } from "eslint";
import path from "path";
import process from "process";
// Code assumes this script is in the './web/scripts' folder.
const projectRoot = execFileSync("git", ["rev-parse", "--show-toplevel"], {
encoding: "utf8",
}).replace("\n", "");
process.chdir(path.join(projectRoot, "./web"));
const eslintConfig = {
fix: true,
overrideConfig: {
env: {
browser: true,
es2021: true,
},
extends: [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:lit/recommended",
"plugin:custom-elements/recommended",
"plugin:storybook/recommended",
"plugin:sonarjs/recommended",
],
parser: "@typescript-eslint/parser",
parserOptions: {
ecmaVersion: 12,
sourceType: "module",
project: true,
},
plugins: ["@typescript-eslint", "lit", "custom-elements", "sonarjs"],
ignorePatterns: ["authentik-live-tests/**", "./.storybook/**/*.ts"],
rules: {
"indent": "off",
"linebreak-style": ["error", "unix"],
"quotes": ["error", "double", { avoidEscape: true }],
"semi": ["error", "always"],
"@typescript-eslint/ban-ts-comment": "off",
"no-unused-vars": "off",
"sonarjs/cognitive-complexity": ["warn", 9],
"sonarjs/no-duplicate-string": "off",
"sonarjs/no-nested-template-literals": "off",
"@typescript-eslint/no-unused-vars": [
"error",
{
argsIgnorePattern: "^_",
varsIgnorePattern: "^_",
caughtErrorsIgnorePattern: "^_",
},
],
"no-console": ["error", { allow: ["debug", "warn", "error"] }],
},
},
};
const updated = ["./src/", "./build.mjs", "./scripts/*.mjs"];
const eslint = new ESLint(eslintConfig);
const results = await eslint.lintFiles(updated);
const formatter = await eslint.loadFormatter("stylish");
const resultText = formatter.format(results);
const errors = results.reduce((acc, result) => acc + result.errorCount, 0);
console.log(resultText);
process.exit(errors > 1 ? 1 : 0);

View File

@ -0,0 +1,94 @@
import { execFileSync } from "child_process";
import { ESLint } from "eslint";
import path from "path";
import process from "process";
// Code assumes this script is in the './web/scripts' folder.
const projectRoot = execFileSync("git", ["rev-parse", "--show-toplevel"], {
encoding: "utf8",
}).replace("\n", "");
process.chdir(path.join(projectRoot, "./web"));
const eslintConfig = {
fix: true,
overrideConfig: {
env: {
browser: true,
es2021: true,
},
extends: [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:lit/recommended",
"plugin:custom-elements/recommended",
"plugin:storybook/recommended",
"plugin:sonarjs/recommended",
],
parser: "@typescript-eslint/parser",
parserOptions: {
ecmaVersion: 12,
sourceType: "module",
project: true,
},
plugins: ["@typescript-eslint", "lit", "custom-elements", "sonarjs"],
ignorePatterns: ["authentik-live-tests/**", "./.storybook/**/*.ts"],
rules: {
"indent": "off",
"linebreak-style": ["error", "unix"],
"quotes": ["error", "double", { avoidEscape: true }],
"semi": ["error", "always"],
"@typescript-eslint/ban-ts-comment": "off",
"no-unused-vars": "off",
"sonarjs/cognitive-complexity": ["warn", 9],
"sonarjs/no-duplicate-string": "off",
"sonarjs/no-nested-template-literals": "off",
"@typescript-eslint/no-unused-vars": [
"error",
{
argsIgnorePattern: "^_",
varsIgnorePattern: "^_",
caughtErrorsIgnorePattern: "^_",
},
],
"no-console": ["error", { allow: ["debug", "warn", "error"] }],
},
},
};
const porcelainV1 = /^(..)\s+(.*$)/;
const gitStatus = execFileSync("git", ["status", "--porcelain", "."], { encoding: "utf8" });
const statuses = gitStatus.split("\n").reduce((acc, line) => {
const match = porcelainV1.exec(line.replace("\n"));
if (!match) {
return acc;
}
const [status, path] = Array.from(match).slice(1, 3);
return [...acc, [status, path.split("\x00")[0]]];
}, []);
const isModified = /^(M|\?|\s)(M|\?|\s)/;
const modified = (s) => isModified.test(s);
const isCheckable = /\.(ts|js|mjs)$/;
const checkable = (s) => isCheckable.test(s);
const ignored = /\/\.storybook\//;
const notIgnored = (s) => !ignored.test(s);
const updated = statuses.reduce(
(acc, [status, filename]) =>
modified(status) && checkable(filename) && notIgnored(filename)
? [...acc, path.join(projectRoot, filename)]
: acc,
[],
);
const eslint = new ESLint(eslintConfig);
const results = await eslint.lintFiles(updated);
const formatter = await eslint.loadFormatter("stylish");
const resultText = formatter.format(results);
const errors = results.reduce((acc, result) => acc + result.errorCount, 0);
console.log(resultText);
process.exit(errors > 1 ? 1 : 0);

View File

@ -1,6 +1,7 @@
import eslint from "@eslint/js"; import eslint from "@eslint/js";
import tsparser from "@typescript-eslint/parser"; import tsparser from "@typescript-eslint/parser";
import litconf from "eslint-plugin-lit"; import litconf from "eslint-plugin-lit";
import sonar from "eslint-plugin-sonarjs";
import wcconf from "eslint-plugin-wc"; import wcconf from "eslint-plugin-wc";
import globals from "globals"; import globals from "globals";
import tseslint from "typescript-eslint"; import tseslint from "typescript-eslint";
@ -8,9 +9,7 @@ import tseslint from "typescript-eslint";
const MAX_DEPTH = 4; const MAX_DEPTH = 4;
const MAX_NESTED_CALLBACKS = 4; const MAX_NESTED_CALLBACKS = 4;
const MAX_PARAMS = 5; const MAX_PARAMS = 5;
const MAX_COGNITIVE_COMPLEXITY = 9;
// Waiting for SonarJS to be compatible
// const MAX_COGNITIVE_COMPLEXITY = 9;
const rules = { const rules = {
"accessor-pairs": "error", "accessor-pairs": "error",
@ -129,11 +128,9 @@ const rules = {
"no-unused-vars": "off", "no-unused-vars": "off",
"no-console": ["error", { allow: ["debug", "warn", "error"] }], "no-console": ["error", { allow: ["debug", "warn", "error"] }],
// SonarJS is not yet compatible with ESLint 9. Commenting these out "sonarjs/cognitive-complexity": ["off", MAX_COGNITIVE_COMPLEXITY],
// until it is. "sonarjs/no-duplicate-string": "off",
// "sonarjs/cognitive-complexity": ["off", MAX_COGNITIVE_COMPLEXITY], "sonarjs/no-nested-template-literals": "off",
// "sonarjs/no-duplicate-string": "off",
// "sonarjs/no-nested-template-literals": "off",
"@typescript-eslint/ban-ts-comment": "off", "@typescript-eslint/ban-ts-comment": "off",
"@typescript-eslint/no-unused-vars": [ "@typescript-eslint/no-unused-vars": [
"error", "error",
@ -170,7 +167,7 @@ export default [
wcconf.configs["flat/recommended"], wcconf.configs["flat/recommended"],
litconf.configs["flat/recommended"], litconf.configs["flat/recommended"],
...tseslint.configs.recommended, ...tseslint.configs.recommended,
// sonar.configs.recommended, sonar.configs.recommended,
{ {
languageOptions: { languageOptions: {
parser: tsparser, parser: tsparser,

View File

@ -1,6 +1,7 @@
import eslint from "@eslint/js"; import eslint from "@eslint/js";
import tsparser from "@typescript-eslint/parser"; import tsparser from "@typescript-eslint/parser";
import litconf from "eslint-plugin-lit"; import litconf from "eslint-plugin-lit";
import sonar from "eslint-plugin-sonarjs";
import wcconf from "eslint-plugin-wc"; import wcconf from "eslint-plugin-wc";
import globals from "globals"; import globals from "globals";
import tseslint from "typescript-eslint"; import tseslint from "typescript-eslint";
@ -29,7 +30,7 @@ export default [
wcconf.configs["flat/recommended"], wcconf.configs["flat/recommended"],
litconf.configs["flat/recommended"], litconf.configs["flat/recommended"],
...tseslint.configs.recommended, ...tseslint.configs.recommended,
// sonar.configs.recommended, sonar.configs.recommended,
{ {
languageOptions: { languageOptions: {
parser: tsparser, parser: tsparser,
@ -42,11 +43,9 @@ export default [
rules: { rules: {
"no-unused-vars": "off", "no-unused-vars": "off",
"no-console": ["error", { allow: ["debug", "warn", "error"] }], "no-console": ["error", { allow: ["debug", "warn", "error"] }],
// SonarJS is not yet compatible with ESLint 9. Commenting these out "sonarjs/cognitive-complexity": ["off", 9],
// until it is. "sonarjs/no-duplicate-string": "off",
// "sonarjs/cognitive-complexity": ["off", 9], "sonarjs/no-nested-template-literals": "off",
// "sonarjs/no-duplicate-string": "off",
// "sonarjs/no-nested-template-literals": "off",
"@typescript-eslint/ban-ts-comment": "off", "@typescript-eslint/ban-ts-comment": "off",
"@typescript-eslint/no-unused-vars": [ "@typescript-eslint/no-unused-vars": [
"error", "error",

View File

@ -1,48 +0,0 @@
import { type KnipConfig } from "knip";
const config: KnipConfig = {
"entry": [
"./src/admin/AdminInterface/AdminInterface.ts",
"./src/user/UserInterface.ts",
"./src/flow/FlowInterface.ts",
"./src/standalone/api-browser/index.ts",
"./src/enterprise/rac/index.ts",
"./src/standalone/loading/index.ts",
"./src/polyfill/poly.ts",
],
"project": ["src/**/*.ts", "src/**/*.js", "./scripts/*.mjs", ".storybook/*.ts"],
// "ignore": ["src/**/*.test.ts", "src/**/*.stories.ts"],
// Prevent Knip from complaining about web components, which export their classes but also
// export their registration, and we don't always use both.
"ignoreExportsUsedInFile": true,
"typescript": {
config: ["tsconfig.json"],
},
"wireit": {
config: ["package.json"],
},
"storybook": {
config: [".storybook/{main,test-runner}.{js,ts}"],
entry: [
".storybook/{manager,preview}.{js,jsx,ts,tsx}",
"**/*.@(mdx|stories.@(mdx|js|jsx|mjs|ts|tsx))",
],
project: [".storybook/**/*.{js,jsx,ts,tsx}"],
},
"eslint": {
entry: [
"eslint.config.mjs",
"scripts/eslint.precommit.mjs",
"scripts/eslint.nightmare.mjs",
"scripts/eslint-precommit.mjs",
"scripts/eslint-nightmare.mjs",
"scripts/eslint.mjs",
],
config: ["package.json"],
},
"webdriver-io": {
config: ["wdio.conf.js"],
},
};
export default config;

File diff suppressed because it is too large Load Diff

View File

@ -4,7 +4,7 @@
"private": true, "private": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@goauthentik/api": "^2024.8.3-1727449099", "@goauthentik/api": "^2024.6.3-1724414734",
"base64-js": "^1.5.1", "base64-js": "^1.5.1",
"bootstrap": "^4.6.1", "bootstrap": "^4.6.1",
"formdata-polyfill": "^4.0.10", "formdata-polyfill": "^4.0.10",
@ -16,13 +16,13 @@
"watch": "rollup -w -c rollup.config.js --bundleConfigAsCjs" "watch": "rollup -w -c rollup.config.js --bundleConfigAsCjs"
}, },
"devDependencies": { "devDependencies": {
"@rollup/plugin-commonjs": "^28.0.0", "@rollup/plugin-commonjs": "^26.0.1",
"@rollup/plugin-node-resolve": "^15.3.0", "@rollup/plugin-node-resolve": "^15.2.3",
"@rollup/plugin-swc": "^0.4.0", "@rollup/plugin-swc": "^0.3.1",
"@swc/cli": "^0.4.0", "@swc/cli": "^0.4.0",
"@swc/core": "^1.7.28", "@swc/core": "^1.7.18",
"@types/jquery": "^3.5.31", "@types/jquery": "^3.5.30",
"rollup": "^4.22.5", "rollup": "^4.21.0",
"rollup-plugin-copy": "^3.5.0" "rollup-plugin-copy": "^3.5.0"
} }
} }

View File

@ -21,20 +21,10 @@ export class ApplicationWizardAuthenticationMethodChoice extends WithLicenseSumm
const selectedTypes = providerModelsList.filter( const selectedTypes = providerModelsList.filter(
(t) => t.formName === this.wizard.providerModel, (t) => t.formName === this.wizard.providerModel,
); );
// As a hack, the Application wizard has separate provider paths for our three types of
// proxy providers. This patch swaps the form we want to be directed to on page 3 from the
// modelName to the formName, so we get the right one. This information isn't modified
// or forwarded, so the proxy-plus-subtype is correctly mapped on submission.
const typesForWizard = providerModelsList.map((provider) => ({
...provider,
modelName: provider.formName,
}));
return providerModelsList.length > 0 return providerModelsList.length > 0
? html`<form class="pf-c-form pf-m-horizontal"> ? html`<form class="pf-c-form pf-m-horizontal">
<ak-wizard-page-type-create <ak-wizard-page-type-create
.types=${typesForWizard} .types=${providerModelsList}
layout=${TypeCreateWizardPageLayouts.grid} layout=${TypeCreateWizardPageLayouts.grid}
.selectedType=${selectedTypes.length > 0 ? selectedTypes[0] : undefined} .selectedType=${selectedTypes.length > 0 ? selectedTypes[0] : undefined}
@select=${(ev: CustomEvent<LocalTypeCreate>) => { @select=${(ev: CustomEvent<LocalTypeCreate>) => {

View File

@ -117,7 +117,7 @@ export class EventMatcherPolicyForm extends BasePolicyForm<EventMatcherPolicy> {
/> />
<p class="pf-c-form__helper-text"> <p class="pf-c-form__helper-text">
${msg( ${msg(
"Matches Event's Client IP (strict matching, for network matching use an Expression Policy).", "Matches Event's Client IP (strict matching, for network matching use an Expression Policy.",
)} )}
</p> </p>
</ak-form-element-horizontal> </ak-form-element-horizontal>

View File

@ -162,6 +162,7 @@ export class OAuth2ProviderFormPage extends BaseProviderForm<OAuth2Provider> {
<ak-flow-search <ak-flow-search
flowType=${FlowsInstancesListDesignationEnum.Authentication} flowType=${FlowsInstancesListDesignationEnum.Authentication}
.currentFlow=${provider?.authenticationFlow} .currentFlow=${provider?.authenticationFlow}
required
></ak-flow-search> ></ak-flow-search>
<p class="pf-c-form__helper-text"> <p class="pf-c-form__helper-text">
${msg("Flow used when a user access this provider and is not authenticated.")} ${msg("Flow used when a user access this provider and is not authenticated.")}
@ -170,7 +171,7 @@ export class OAuth2ProviderFormPage extends BaseProviderForm<OAuth2Provider> {
<ak-form-element-horizontal <ak-form-element-horizontal
name="authorizationFlow" name="authorizationFlow"
label=${msg("Authorization flow")} label=${msg("Authorization flow")}
required ?required=${true}
> >
<ak-flow-search <ak-flow-search
flowType=${FlowsInstancesListDesignationEnum.Authorization} flowType=${FlowsInstancesListDesignationEnum.Authorization}

View File

@ -327,7 +327,7 @@ export class LDAPSourceForm extends BaseSourceForm<LDAPSource> {
<ak-form-group> <ak-form-group>
<span slot="header"> ${msg("Additional settings")} </span> <span slot="header"> ${msg("Additional settings")} </span>
<div slot="body" class="pf-c-form"> <div slot="body" class="pf-c-form">
<ak-form-element-horizontal label=${msg("Parent Group")} name="syncParentGroup"> <ak-form-element-horizontal label=${msg("Group")} name="syncParentGroup">
<ak-search-select <ak-search-select
.fetchObjects=${async (query?: string): Promise<Group[]> => { .fetchObjects=${async (query?: string): Promise<Group[]> => {
const args: CoreGroupsListRequest = { const args: CoreGroupsListRequest = {

View File

@ -3,7 +3,7 @@ export const SUCCESS_CLASS = "pf-m-success";
export const ERROR_CLASS = "pf-m-danger"; export const ERROR_CLASS = "pf-m-danger";
export const PROGRESS_CLASS = "pf-m-in-progress"; export const PROGRESS_CLASS = "pf-m-in-progress";
export const CURRENT_CLASS = "pf-m-current"; export const CURRENT_CLASS = "pf-m-current";
export const VERSION = "2024.8.3"; export const VERSION = "2024.8.2";
export const TITLE_DEFAULT = "authentik"; export const TITLE_DEFAULT = "authentik";
export const ROUTE_SEPARATOR = ";"; export const ROUTE_SEPARATOR = ";";

View File

@ -155,7 +155,7 @@ select[multiple] option:checked {
background-color: var(--ak-dark-background-light); background-color: var(--ak-dark-background-light);
} }
.pf-c-form-control[readonly] { .pf-c-form-control[readonly] {
background-color: var(--ak-dark-background-light) !important; background-color: var(--ak-dark-background-light);
} }
.pf-c-switch__input:checked ~ .pf-c-switch__label { .pf-c-switch__input:checked ~ .pf-c-switch__label {
--pf-c-switch__input--checked__label--Color: var(--ak-dark-foreground); --pf-c-switch__input--checked__label--Color: var(--ak-dark-foreground);

View File

@ -513,14 +513,16 @@ ${JSON.stringify(value.new_value, null, 4)}</pre
} }
renderUpdateAvailable() { renderUpdateAvailable() {
let url = `https://github.com/goauthentik/authentik/releases/tag/version%2F${this.event.context.new_version}`;
if (this.event.context.changelog) {
url = this.event.context.changelog as string;
}
return html`<div class="pf-c-card__title">${msg("New version available")}</div> return html`<div class="pf-c-card__title">${msg("New version available")}</div>
<div class="pf-c-card__body"> <a
<a target="_blank" href=${url}> ${this.event.context.new_version} </a> target="_blank"
</div>`; href="https://github.com/goauthentik/authentik/releases/tag/version%2F${this.event
.context.new_version}"
>
${this.event.context.new_version}
</a>`;
// Action types which typically don't record any extra context.
// If context is not empty, we fall to the default response.
} }
renderLogin() { renderLogin() {

View File

@ -1,4 +1,4 @@
import { $, browser, expect } from "@wdio/globals"; import { $, browser } from "@wdio/globals";
import { slug } from "github-slugger"; import { slug } from "github-slugger";
import { Key } from "webdriverio"; import { Key } from "webdriverio";

View File

@ -2,7 +2,7 @@
import { AKElement } from "@goauthentik/elements/Base"; import { AKElement } from "@goauthentik/elements/Base";
import { bound } from "@goauthentik/elements/decorators/bound.js"; import { bound } from "@goauthentik/elements/decorators/bound.js";
import { CustomListenerElement } from "@goauthentik/elements/utils/eventEmitter"; import { CustomListenerElement } from "@goauthentik/elements/utils/eventEmitter";
import { $, browser, expect } from "@wdio/globals"; import { $, browser } from "@wdio/globals";
import { slug } from "github-slugger"; import { slug } from "github-slugger";
import { html, render } from "lit"; import { html, render } from "lit";

View File

@ -69,19 +69,9 @@ export class TypeCreateWizardPage extends WithLicenseSummary(WizardPage) {
} }
renderGrid(): TemplateResult { renderGrid(): TemplateResult {
return html`<div return html`<div class="pf-l-grid pf-m-gutter">
class="pf-l-grid pf-m-gutter"
data-ouid-component-type="ak-type-create-grid"
>
${this.types.map((type, idx) => { ${this.types.map((type, idx) => {
const requiresEnterprise = type.requiresEnterprise && !this.hasEnterpriseLicense; const requiresEnterprise = type.requiresEnterprise && !this.hasEnterpriseLicense;
// It's valid to pass in a local modelName or the full name with application
// part. If the latter, we only want the part after the dot to appear as our
// OUIA tag for test automation.
const componentName = type.modelName.includes(".")
? (type.modelName.split(".")[1] ?? "--unknown--")
: type.modelName;
return html`<div return html`<div
class="pf-l-grid__item pf-m-3-col pf-c-card ${requiresEnterprise class="pf-l-grid__item pf-m-3-col pf-c-card ${requiresEnterprise
? "pf-m-non-selectable-raised" ? "pf-m-non-selectable-raised"
@ -89,8 +79,6 @@ export class TypeCreateWizardPage extends WithLicenseSummary(WizardPage) {
? "pf-m-selected-raised" ? "pf-m-selected-raised"
: ""}" : ""}"
tabindex=${idx} tabindex=${idx}
data-ouid-component-type="ak-type-create-grid-card"
data-ouid-component-name=${componentName}
@click=${() => { @click=${() => {
if (requiresEnterprise) { if (requiresEnterprise) {
return; return;
@ -119,17 +107,10 @@ export class TypeCreateWizardPage extends WithLicenseSummary(WizardPage) {
} }
renderList(): TemplateResult { renderList(): TemplateResult {
return html`<form return html`<form class="pf-c-form pf-m-horizontal">
class="pf-c-form pf-m-horizontal"
data-ouid-component-type="ak-type-create-list"
>
${this.types.map((type) => { ${this.types.map((type) => {
const requiresEnterprise = type.requiresEnterprise && !this.hasEnterpriseLicense; const requiresEnterprise = type.requiresEnterprise && !this.hasEnterpriseLicense;
return html`<div return html`<div class="pf-c-radio">
class="pf-c-radio"
data-ouid-component-type="ak-type-create-list-card"
data-ouid-component-name=${type.modelName.split(".")[1] ?? "--unknown--"}
>
<input <input
class="pf-c-radio__input" class="pf-c-radio__input"
type="radio" type="radio"

Some files were not shown because too many files have changed in this diff Show More