Skip to content

enterprise/reports: improve export list, confirmation (cherry-pick #18981 to version-2025.12)#19010

Merged
BeryJu merged 1 commit intoversion-2025.12from
cherry-pick/18981-to-version-2025.12
Dec 22, 2025
Merged

enterprise/reports: improve export list, confirmation (cherry-pick #18981 to version-2025.12)#19010
BeryJu merged 1 commit intoversion-2025.12from
cherry-pick/18981-to-version-2025.12

Conversation

@authentik-automation
Copy link
Contributor

Cherry-pick of #18981 to version-2025.12 branch.

Original PR: #18981
Original Author: @BeryJu
Cherry-picked commit: 7fa28c6

* enterprise/reports: use verbose name for model label

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

* add confirmation for export

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

* update docs

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

* remove duplicated api

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

* fix duplicate

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

* fix search query not updated

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

* exclude page & page size

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

* improve query display

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

* fix user display

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

* exclude unset params

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

* Apply suggestions from code review

Co-authored-by: Teffen Ellis <592134+GirlBossRush@users.noreply.github.com>
Signed-off-by: Jens L. <jens@beryju.org>

* more code style

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

* format

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

* fix types

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

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Signed-off-by: Jens L. <jens@beryju.org>
Co-authored-by: Teffen Ellis <592134+GirlBossRush@users.noreply.github.com>
@netlify
Copy link

netlify bot commented Dec 22, 2025

Deploy Preview for authentik-integrations ready!

Name Link
🔨 Latest commit 1a792f4
🔍 Latest deploy log https://app.netlify.com/projects/authentik-integrations/deploys/69499da4d08c0d0008be816d
😎 Deploy Preview https://deploy-preview-19010--authentik-integrations.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@netlify
Copy link

netlify bot commented Dec 22, 2025

Deploy Preview for authentik-docs ready!

Name Link
🔨 Latest commit 1a792f4
🔍 Latest deploy log https://app.netlify.com/projects/authentik-docs/deploys/69499da4374a370008aca84a
😎 Deploy Preview https://deploy-preview-19010--authentik-docs.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@codecov
Copy link

codecov bot commented Dec 22, 2025

❌ 1 Tests Failed:

Tests completed Failed Passed Skipped
2856 1 2855 2
View the top 1 failed test(s) by shortest run time
tests.e2e.test_provider_oidc_implicit.TestProviderOAuth2OIDCImplicit::test_authorization_consent_implied
Stack Traces | 17.3s run time
self = <unittest.case._Outcome object at 0x7f9c74ec3bf0>
test_case = <tests.e2e.test_provider_oidc_implicit.TestProviderOAuth2OIDCImplicit testMethod=test_authorization_consent_implied>
subTest = False

    @contextlib.contextmanager
    def testPartExecutor(self, test_case, subTest=False):
        old_success = self.success
        self.success = True
        try:
>           yield

.../hostedtoolcache/Python/3.13.11............/x64/lib/python3.13/unittest/case.py:58: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <tests.e2e.test_provider_oidc_implicit.TestProviderOAuth2OIDCImplicit testMethod=test_authorization_consent_implied>
result = <TestCaseFunction test_authorization_consent_implied>

    def run(self, result=None):
        if result is None:
            result = self.defaultTestResult()
            startTestRun = getattr(result, 'startTestRun', None)
            stopTestRun = getattr(result, 'stopTestRun', None)
            if startTestRun is not None:
                startTestRun()
        else:
            stopTestRun = None
    
        result.startTest(self)
        try:
            testMethod = getattr(self, self._testMethodName)
            if (getattr(self.__class__, "__unittest_skip__", False) or
                getattr(testMethod, "__unittest_skip__", False)):
                # If the class or method was skipped.
                skip_why = (getattr(self.__class__, '__unittest_skip_why__', '')
                            or getattr(testMethod, '__unittest_skip_why__', ''))
                _addSkip(result, self, skip_why)
                return result
    
            expecting_failure = (
                getattr(self, "__unittest_expecting_failure__", False) or
                getattr(testMethod, "__unittest_expecting_failure__", False)
            )
            outcome = _Outcome(result)
            start_time = time.perf_counter()
            try:
                self._outcome = outcome
    
                with outcome.testPartExecutor(self):
                    self._callSetUp()
                if outcome.success:
                    outcome.expecting_failure = expecting_failure
                    with outcome.testPartExecutor(self):
>                       self._callTestMethod(testMethod)

.../hostedtoolcache/Python/3.13.11............/x64/lib/python3.13/unittest/case.py:651: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <tests.e2e.test_provider_oidc_implicit.TestProviderOAuth2OIDCImplicit testMethod=test_authorization_consent_implied>
method = <bound method TestProviderOAuth2OIDCImplicit.test_authorization_consent_implied of <tests.e2e.test_provider_oidc_implicit.TestProviderOAuth2OIDCImplicit testMethod=test_authorization_consent_implied>>

    def _callTestMethod(self, method):
>       if method() is not None:

.../hostedtoolcache/Python/3.13.11............/x64/lib/python3.13/unittest/case.py:606: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <tests.e2e.test_provider_oidc_implicit.TestProviderOAuth2OIDCImplicit testMethod=test_authorization_consent_implied>
args = (), kwargs = {}

    @wraps(func)
    def wrapper(self: TransactionTestCase, *args, **kwargs):
        """Run test again if we're below max_retries, including tearDown and
        setUp. Otherwise raise the error"""
        nonlocal count
        try:
>           return func(self, *args, **kwargs)

tests/e2e/utils.py:492: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

args = (<tests.e2e.test_provider_oidc_implicit.TestProviderOAuth2OIDCImplicit testMethod=test_authorization_consent_implied>,)
kwargs = {}, file = 'default/flow-default-invalidation-flow.yaml'
content = 'version: 1\nmetadata:\n  name: Default - Invalidation flow\nentries:\n- attrs:\n    designation: invalidation\n    na...0\n    stage: !KeyOf default-invalidation-logout\n    target: !KeyOf flow\n  model: authentik_flows.flowstagebinding\n'

    @wraps(func)
    def wrapper(*args, **kwargs):
        for file in files:
            content = BlueprintInstance(path=file).retrieve()
            Importer.from_string(content).apply()
>       return func(*args, **kwargs)

.../blueprints/tests/__init__.py:25: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

args = (<tests.e2e.test_provider_oidc_implicit.TestProviderOAuth2OIDCImplicit testMethod=test_authorization_consent_implied>,)
kwargs = {}
file = 'default/flow-default-provider-authorization-implicit-consent.yaml'
content = 'version: 1\nmetadata:\n  name: Default - Provider authorization flow (implicit consent)\nentries:\n- attrs:\n    desi...henticated\n  identifiers:\n    slug: default-provider-authorization-implicit-consent\n  model: authentik_flows.flow\n'

    @wraps(func)
    def wrapper(*args, **kwargs):
        for file in files:
            content = BlueprintInstance(path=file).retrieve()
            Importer.from_string(content).apply()
>       return func(*args, **kwargs)

.../blueprints/tests/__init__.py:25: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

args = (<tests.e2e.test_provider_oidc_implicit.TestProviderOAuth2OIDCImplicit testMethod=test_authorization_consent_implied>,)
kwargs = {}, file = 'system/providers-oauth2.yaml'
content = 'version: 1\nmetadata:\n  labels:\n    blueprints.goauthentik.io/system: "true"\n  name: System - OAuth2 Provider - Sc... application the ability to access the authentik API\n        # on behalf of the authorizing user\n        return {}\n'

    @wraps(func)
    def wrapper(*args, **kwargs):
        for file in files:
            content = BlueprintInstance(path=file).retrieve()
            Importer.from_string(content).apply()
>       return func(*args, **kwargs)

.../blueprints/tests/__init__.py:25: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

args = (<tests.e2e.test_provider_oidc_implicit.TestProviderOAuth2OIDCImplicit testMethod=test_authorization_consent_implied>,)
kwargs = {}, config = <AuthentikCryptoConfig: authentik_crypto>

    @wraps(func)
    def wrapper(*args, **kwargs):
        config = apps.get_app_config(app_name)
        if isinstance(config, ManagedAppConfig):
            config._on_startup_callback(None)
>       return func(*args, **kwargs)

.../blueprints/tests/__init__.py:43: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <tests.e2e.test_provider_oidc_implicit.TestProviderOAuth2OIDCImplicit testMethod=test_authorization_consent_implied>

    @retry()
    @apply_blueprint(
        "default/flow-default-authentication-flow.yaml",
        "default/flow-default-invalidation-flow.yaml",
    )
    @apply_blueprint("default/flow-default-provider-authorization-implicit-consent.yaml")
    @apply_blueprint("system/providers-oauth2.yaml")
    @reconcile_app("authentik_crypto")
    def test_authorization_consent_implied(self):
        """test OpenID Provider flow (default authorization flow with implied consent)"""
        sleep(1)
        # Bootstrap all needed objects
        authorization_flow = Flow.objects.get(
            slug="default-provider-authorization-implicit-consent"
        )
        provider = OAuth2Provider.objects.create(
            name=self.application_slug,
            client_type=ClientTypes.CONFIDENTIAL,
            client_id=self.client_id,
            client_secret=self.client_secret,
            signing_key=create_test_cert(),
            redirect_uris=[
                RedirectURI(RedirectURIMatchingMode.STRICT, "http://localhost:9009/implicit/")
            ],
            authorization_flow=authorization_flow,
        )
        provider.property_mappings.set(
            ScopeMapping.objects.filter(
                scope_name__in=[
                    SCOPE_OPENID,
                    SCOPE_OPENID_EMAIL,
                    SCOPE_OPENID_PROFILE,
                    SCOPE_OFFLINE_ACCESS,
                ]
            )
        )
        provider.save()
        Application.objects.create(
            name=self.application_slug,
            slug=self.application_slug,
            provider=provider,
        )
        self.setup_client()
    
        self.driver.get("http://localhost:9009/implicit/")
        self.wait.until(ec.title_contains("authentik"))
        self.login()
    
>       body = self.parse_json_content()

tests/e2e/test_provider_oidc_implicit.py:153: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <tests.e2e.test_provider_oidc_implicit.TestProviderOAuth2OIDCImplicit testMethod=test_authorization_consent_implied>
context = None, timeout = 10

    def parse_json_content(
        self, context: WebElement | None = None, timeout: float | None = 10
    ) -> JSONType:
        """
        Parse JSON from a Selenium element's text content.
    
        If `context` is not provided, defaults to the <body> element.
        Raises a clear test failure if the element isn't found, the text doesn't appear
        within `timeout` seconds, or the text is not valid JSON.
        """
        use_body = context is None
        wait_timeout = timeout or self.wait_timeout
    
        def get_context() -> WebElement:
            """Get or refresh the context element."""
            if use_body:
                return self.driver.find_element(By.TAG_NAME, "body")
            return context
    
        def get_text_safely() -> str:
            """Get element text, re-finding element if stale."""
            for _ in range(5):
                try:
                    return get_context().text.strip()
                except StaleElementReferenceException:
                    sleep(0.5)
            return get_context().text.strip()
    
        def get_inner_html_safely() -> str:
            """Get innerHTML, re-finding element if stale."""
            for _ in range(5):
                try:
                    return get_context().get_attribute("innerHTML") or ""
                except StaleElementReferenceException:
                    sleep(0.5)
            return get_context().get_attribute("innerHTML") or ""
    
        try:
            get_context()
        except NoSuchElementException:
            self.fail(
                f"No element found (defaulted to <body>). Current URL: {self.driver.current_url}"
            )
    
        wait = WebDriverWait(self.driver, wait_timeout)
    
        try:
            wait.until(lambda d: len(get_text_safely()) != 0)
        except TimeoutException:
            snippet = get_text_safely()[:500].replace("\n", " ")
            self.fail(
                f"Timed out waiting for element text to appear at {self.driver.current_url}. "
                f"Current content: {snippet or '<empty>'}"
            )
    
        body_text = get_text_safely()
        inner_html = get_inner_html_safely()
    
        if "redirecting" in inner_html.lower():
            try:
                wait.until(lambda d: "redirecting" not in get_inner_html_safely().lower())
            except TimeoutException:
                snippet = get_text_safely()[:500].replace("\n", " ")
                inner_html = get_inner_html_safely()
    
                self.fail(
                    f"Timed out waiting for redirect to finish at {self.driver.current_url}. "
                    f"Current content: {snippet or '<empty>'}"
                    f"{inner_html or '<empty>'}"
                )
    
            inner_html = get_inner_html_safely()
            body_text = get_text_safely()
    
        snippet = body_text[:500].replace("\n", " ")
    
        if not body_text.startswith("{") and not body_text.startswith("["):
>           self.fail(
                f"Expected JSON content but got non-JSON text at {self.driver.current_url}: "
                f"{snippet or '<empty>'}"
                f"{inner_html or '<empty>'}"
            )

tests/e2e/utils.py:319: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <tests.e2e.test_provider_oidc_implicit.TestProviderOAuth2OIDCImplicit testMethod=test_authorization_consent_implied>
msg = 'Expected JSON content but got non-JSON text at http://10.1.0.161:.../if/flow/default-authentication-flow/?client_id...ntication-flow"></ak-flow-inspector>\n            </div>\n        </div>\n    </div>\n\n\n        \n        \n    \n\n'

    def fail(self, msg=None):
        """Fail immediately, with the given message."""
>       raise self.failureException(msg)
E       AssertionError: Expected JSON content but got non-JSON text at http://10.1.0.161:.../if/flow/default-authentication-flow/?client_id=zSUZgTcE6OiYNUrw7W8xcswi17g7TeYzcTw39taz&redirect_uri=http%3A%2F%2Flocalhost%3A9009%2Fimplicit%2F&response_type=id_token+token&scope=openid++profile+email&state=60daf86111ec442f882668f3bd07af95&nonce=7ff29e2ecfb240489e85dcb063846778&next=%2Fapplication%2Fo%2Fauthorize%2F%3Fclient_id%3DzSUZgTcE6OiYNUrw7W8xcswi17g7TeYzcTw39taz%26redirect_uri%3Dhttp%253A%252F%252Flocalhost%253A9009%252Fimplicit%252F%26response_type%3Did_token%2520token%26scope%3Dopenid%2520%2520profile%2520email%26state%3D60daf86111ec442f882668f3bd07af95%26nonce%3D7ff29e2ecfb240489e85dcb063846778: Chinese Simplified (简体中文) Chinese Traditional (繁體中文) Czech (Čeština) Dutch (Nederlands) English Finnish (Suomi) French (Français) German (Deutsch) Italian (Italiano) Japanese (日本語) Korean (한국어) Polish (Polski) Portuguese (Português) Russian (Русский) Spanish (Español) Turkish (Türkçe) Welcome to authentik! 51qNEc4aAIsuHwazDjk5 Not you? Password Form actions Continue Powered by authentik
E               
E       <ak-skip-to-content></ak-skip-to-content>
E       <ak-message-container theme="light"></ak-message-container>
E       
E       <div class="pf-c-page__drawer">
E           <div class="pf-c-drawer pf-m-collapsed" id="flow-drawer">
E               <div class="pf-c-drawer__main">
E                   <div class="pf-c-drawer__content">
E                       <div class="pf-c-drawer__body">
E                               <ak-flow-executor slug="default-authentication-flow" class="pf-c-login" data-layout="stacked" data-test-id="interface-root" theme="light">
E                                   
E       
E       <div class="ak-c-placeholder" id="ak-placeholder" slot="placeholder">
E           <span class="pf-c-spinner" role="progressbar" aria-valuetext="Loading...">
E               <span class="pf-c-spinner__clipper"></span>
E               <span class="pf-c-spinner__lead-ball"></span>
E               <span class="pf-c-spinner__tail-ball"></span>
E           </span>
E       </div>
E       
E       
E                                   <ak-brand-links slot="footer" exportparts="list:brand-links-list, list-item:brand-links-list-item" role="contentinfo" aria-label="Site footer" class="pf-c-login__footer pf-m-dark" theme="light"></ak-brand-links>
E                               </ak-flow-executor>
E                           </div>
E                       </div>
E       
E                       <ak-flow-inspector id="flow-inspector" data-registration="lazy" class="pf-c-drawer__panel pf-m-width-33" slug="default-authentication-flow"></ak-flow-inspector>
E                   </div>
E               </div>
E           </div>

.../hostedtoolcache/Python/3.13.11............/x64/lib/python3.13/unittest/case.py:732: AssertionError

To view more test analytics, go to the Test Analytics Dashboard
📋 Got 3 mins? Take this short survey to help us improve Test Analytics.

@BeryJu BeryJu merged commit 3d8d3bb into version-2025.12 Dec 22, 2025
73 of 83 checks passed
@BeryJu BeryJu deleted the cherry-pick/18981-to-version-2025.12 branch December 22, 2025 19:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant