Skip to content

web: fix lock#14705

Merged
BeryJu merged 1 commit intomainfrom
web/fix-package-lock
May 27, 2025
Merged

web: fix lock#14705
BeryJu merged 1 commit intomainfrom
web/fix-package-lock

Conversation

@BeryJu
Copy link
Member

@BeryJu BeryJu commented May 26, 2025

Details

REPLACE ME


Checklist

  • Local tests pass (ak test authentik/)
  • The code has been formatted (make lint-fix)

If an API change has been made

  • The API schema has been updated (make gen-build)

If changes to the frontend have been made

  • The code has been formatted (make web)

If applicable

  • The documentation has been updated
  • The documentation has been formatted (make website)

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
@BeryJu BeryJu requested a review from a team as a code owner May 26, 2025 21:54
@netlify
Copy link

netlify bot commented May 26, 2025

Deploy Preview for authentik-docs canceled.

Name Link
🔨 Latest commit 4d8eaf0
🔍 Latest deploy log https://app.netlify.com/projects/authentik-docs/deploys/6834e30bc8e2a8000851d478

@netlify
Copy link

netlify bot commented May 26, 2025

Deploy Preview for authentik-storybook ready!

Name Link
🔨 Latest commit 4d8eaf0
🔍 Latest deploy log https://app.netlify.com/projects/authentik-storybook/deploys/6834e30b1133ab0008efcaf9
😎 Deploy Preview https://deploy-preview-14705--authentik-storybook.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 May 26, 2025

❌ 1 Tests Failed:

Tests completed Failed Passed Skipped
1806 1 1805 2
View the full list of 1 ❄️ flaky tests
tests.e2e.test_source_saml.TestSourceSAML::test_idp_post_auto_enroll_auth

Flake rate in main: 37.50% (Passed 40 times, Failed 24 times)

Stack Traces | 229s run time
self = <tests.e2e.test_source_saml.TestSourceSAML testMethod=test_idp_post_auto_enroll_auth>
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:329: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

args = (<tests.e2e.test_source_saml.TestSourceSAML testMethod=test_idp_post_auto_enroll_auth>,)
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_source_saml.TestSourceSAML testMethod=test_idp_post_auto_enroll_auth>,)
kwargs = {}, file = 'default/flow-default-source-pre-authentication.yaml'
content = 'version: 1\nmetadata:\n  name: Default - Source pre-authentication flow\nentries:\n- attrs:\n    designation: stage_c...    authentication: none\n  identifiers:\n    slug: default-source-pre-authentication\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: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <tests.e2e.test_source_saml.TestSourceSAML testMethod=test_idp_post_auto_enroll_auth>

    @retry()
    @apply_blueprint(
        "default/flow-default-authentication-flow.yaml",
        "default/flow-default-invalidation-flow.yaml",
    )
    @apply_blueprint(
        "default/flow-default-source-authentication.yaml",
        "default/flow-default-source-enrollment.yaml",
        "default/flow-default-source-pre-authentication.yaml",
    )
    def test_idp_post_auto_enroll_auth(self):
        """test SAML Source With post binding (auto redirect)"""
        # Bootstrap all needed objects
        authentication_flow = Flow.objects.get(slug="default-source-authentication")
        enrollment_flow = Flow.objects.get(slug="default-source-enrollment")
        pre_authentication_flow = Flow.objects.get(slug="default-source-pre-authentication")
        keypair = CertificateKeyPair.objects.create(
            name=generate_id(),
            certificate_data=IDP_CERT,
            key_data=IDP_KEY,
        )
    
        source = SAMLSource.objects.create(
            name=generate_id(),
            slug=self.slug,
            authentication_flow=authentication_flow,
            enrollment_flow=enrollment_flow,
            pre_authentication_flow=pre_authentication_flow,
            issuer="entity-id",
            sso_url=f"http://{self.host}:.../saml2/idp/SSOService.php",
            binding_type=SAMLBindingTypes.POST_AUTO,
            signing_kp=keypair,
        )
        ident_stage = IdentificationStage.objects.first()
        ident_stage.sources.set([source])
        ident_stage.save()
    
        self.driver.get(self.live_server_url)
    
        flow_executor = self.get_shadow_root("ak-flow-executor")
        identification_stage = self.get_shadow_root("ak-stage-identification", flow_executor)
        wait = WebDriverWait(identification_stage, self.wait_timeout)
    
        wait.until(
            ec.presence_of_element_located(
                (By.CSS_SELECTOR, ".pf-c-login__main-footer-links-item > button")
            )
        )
        identification_stage.find_element(
            By.CSS_SELECTOR, ".pf-c-login__main-footer-links-item > button"
        ).click()
    
        # Now we should be at the IDP, wait for the username field
        self.wait.until(ec.presence_of_element_located((By.ID, "username")))
        self.driver.find_element(By.ID, "username").send_keys("user1")
        self.driver.find_element(By.ID, "password").send_keys("user1pass")
        self.driver.find_element(By.ID, "password").send_keys(Keys.ENTER)
    
        # Wait until we're logged in
        self.wait_for_url(self.if_user_url())
    
        self.assert_user(
            User.objects.exclude(username="akadmin")
            .exclude(username__startswith="ak-outpost")
            .exclude_anonymous()
            .exclude(pk=self.user.pk)
            .first()
        )
    
        # Clear all cookies and log in again
        self.driver.delete_all_cookies()
        self.driver.get(self.live_server_url)
    
        flow_executor = self.get_shadow_root("ak-flow-executor")
        identification_stage = self.get_shadow_root("ak-stage-identification", flow_executor)
        wait = WebDriverWait(identification_stage, self.wait_timeout)
    
        wait.until(
            ec.presence_of_element_located(
                (By.CSS_SELECTOR, ".pf-c-login__main-footer-links-item > button")
            )
        )
        identification_stage.find_element(
            By.CSS_SELECTOR, ".pf-c-login__main-footer-links-item > button"
        ).click()
    
        # Now we should be at the IDP, wait for the username field
>       self.wait.until(ec.presence_of_element_located((By.ID, "username")))

tests/e2e/test_source_saml.py:414: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <selenium.webdriver.support.wait.WebDriverWait (session="6e095f40aa49ab61765e682be8c1177f")>
method = <function presence_of_element_located.<locals>._predicate at 0x7f79864477e0>
message = ''

    def until(self, method: Callable[[D], Union[Literal[False], T]], message: str = "") -> T:
        """Wait until the method returns a value that is not False.
    
        Calls the method provided with the driver as an argument until the
        return value does not evaluate to ``False``.
    
        Parameters:
        -----------
        method: callable(WebDriver)
            - A callable object that takes a WebDriver instance as an argument.
    
        message: str
            - Optional message for :exc:`TimeoutException`
    
        Return:
        -------
        object: T
            - The result of the last call to `method`
    
        Raises:
        -------
        TimeoutException
            - If 'method' does not return a truthy value within the WebDriverWait
            object's timeout
    
        Example:
        --------
        >>> from selenium.webdriver.common.by import By
        >>> from selenium.webdriver.support.ui import WebDriverWait
        >>> from selenium.webdriver.support import expected_conditions as EC
    
        # Wait until an element is visible on the page
        >>> wait = WebDriverWait(driver, 10)
        >>> element = wait.until(EC.visibility_of_element_located((By.ID, "exampleId")))
        >>> print(element.text)
        """
        screen = None
        stacktrace = None
    
        end_time = time.monotonic() + self._timeout
        while True:
            try:
                value = method(self._driver)
                if value:
                    return value
            except self._ignored_exceptions as exc:
                screen = getattr(exc, "screen", None)
                stacktrace = getattr(exc, "stacktrace", None)
            if time.monotonic() > end_time:
                break
            time.sleep(self._poll)
>       raise TimeoutException(message, screen, stacktrace)
E       selenium.common.exceptions.TimeoutException: Message: 
E       Stacktrace:
E       #0 0x5614c283971a <unknown>
E       #1 0x5614c22dc0a0 <unknown>
E       #2 0x5614c232d9b0 <unknown>
E       #3 0x5614c232dba1 <unknown>
E       #4 0x5614c237bea4 <unknown>
E       #5 0x5614c23533cd <unknown>
E       #6 0x5614c23792a0 <unknown>
E       #7 0x5614c2353173 <unknown>
E       #8 0x5614c231fd4b <unknown>
E       #9 0x5614c23209b1 <unknown>
E       #10 0x5614c27fe8cb <unknown>
E       #11 0x5614c28027ca <unknown>
E       #12 0x5614c27e6622 <unknown>
E       #13 0x5614c2803354 <unknown>
E       #14 0x5614c27cb45f <unknown>
E       #15 0x5614c28274f8 <unknown>
E       #16 0x5614c28276d6 <unknown>
E       #17 0x5614c2838586 <unknown>
E       #18 0x7fdf80e03aa4 <unknown>
E       #19 0x7fdf80e90a34 __clone

.venv/lib/python3.13.../webdriver/support/wait.py:146: TimeoutException

During handling of the above exception, another exception occurred:

self = <tests.e2e.test_source_saml.TestSourceSAML testMethod=test_idp_post_auto_enroll_auth>
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:329: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

args = (<tests.e2e.test_source_saml.TestSourceSAML testMethod=test_idp_post_auto_enroll_auth>,)
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_source_saml.TestSourceSAML testMethod=test_idp_post_auto_enroll_auth>,)
kwargs = {}, file = 'default/flow-default-source-pre-authentication.yaml'
content = 'version: 1\nmetadata:\n  name: Default - Source pre-authentication flow\nentries:\n- attrs:\n    designation: stage_c...    authentication: none\n  identifiers:\n    slug: default-source-pre-authentication\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: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <tests.e2e.test_source_saml.TestSourceSAML testMethod=test_idp_post_auto_enroll_auth>

    @retry()
    @apply_blueprint(
        "default/flow-default-authentication-flow.yaml",
        "default/flow-default-invalidation-flow.yaml",
    )
    @apply_blueprint(
        "default/flow-default-source-authentication.yaml",
        "default/flow-default-source-enrollment.yaml",
        "default/flow-default-source-pre-authentication.yaml",
    )
    def test_idp_post_auto_enroll_auth(self):
        """test SAML Source With post binding (auto redirect)"""
        # Bootstrap all needed objects
        authentication_flow = Flow.objects.get(slug="default-source-authentication")
        enrollment_flow = Flow.objects.get(slug="default-source-enrollment")
        pre_authentication_flow = Flow.objects.get(slug="default-source-pre-authentication")
        keypair = CertificateKeyPair.objects.create(
            name=generate_id(),
            certificate_data=IDP_CERT,
            key_data=IDP_KEY,
        )
    
        source = SAMLSource.objects.create(
            name=generate_id(),
            slug=self.slug,
            authentication_flow=authentication_flow,
            enrollment_flow=enrollment_flow,
            pre_authentication_flow=pre_authentication_flow,
            issuer="entity-id",
            sso_url=f"http://{self.host}:.../saml2/idp/SSOService.php",
            binding_type=SAMLBindingTypes.POST_AUTO,
            signing_kp=keypair,
        )
        ident_stage = IdentificationStage.objects.first()
        ident_stage.sources.set([source])
        ident_stage.save()
    
        self.driver.get(self.live_server_url)
    
        flow_executor = self.get_shadow_root("ak-flow-executor")
        identification_stage = self.get_shadow_root("ak-stage-identification", flow_executor)
        wait = WebDriverWait(identification_stage, self.wait_timeout)
    
        wait.until(
            ec.presence_of_element_located(
                (By.CSS_SELECTOR, ".pf-c-login__main-footer-links-item > button")
            )
        )
        identification_stage.find_element(
            By.CSS_SELECTOR, ".pf-c-login__main-footer-links-item > button"
        ).click()
    
        # Now we should be at the IDP, wait for the username field
        self.wait.until(ec.presence_of_element_located((By.ID, "username")))
        self.driver.find_element(By.ID, "username").send_keys("user1")
        self.driver.find_element(By.ID, "password").send_keys("user1pass")
        self.driver.find_element(By.ID, "password").send_keys(Keys.ENTER)
    
        # Wait until we're logged in
        self.wait_for_url(self.if_user_url())
    
        self.assert_user(
            User.objects.exclude(username="akadmin")
            .exclude(username__startswith="ak-outpost")
            .exclude_anonymous()
            .exclude(pk=self.user.pk)
            .first()
        )
    
        # Clear all cookies and log in again
        self.driver.delete_all_cookies()
        self.driver.get(self.live_server_url)
    
        flow_executor = self.get_shadow_root("ak-flow-executor")
        identification_stage = self.get_shadow_root("ak-stage-identification", flow_executor)
        wait = WebDriverWait(identification_stage, self.wait_timeout)
    
        wait.until(
            ec.presence_of_element_located(
                (By.CSS_SELECTOR, ".pf-c-login__main-footer-links-item > button")
            )
        )
        identification_stage.find_element(
            By.CSS_SELECTOR, ".pf-c-login__main-footer-links-item > button"
        ).click()
    
        # Now we should be at the IDP, wait for the username field
>       self.wait.until(ec.presence_of_element_located((By.ID, "username")))

tests/e2e/test_source_saml.py:414: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <selenium.webdriver.support.wait.WebDriverWait (session="6974b5536d70af46acbb24c1acfb1fc1")>
method = <function presence_of_element_located.<locals>._predicate at 0x7f7986409f80>
message = ''

    def until(self, method: Callable[[D], Union[Literal[False], T]], message: str = "") -> T:
        """Wait until the method returns a value that is not False.
    
        Calls the method provided with the driver as an argument until the
        return value does not evaluate to ``False``.
    
        Parameters:
        -----------
        method: callable(WebDriver)
            - A callable object that takes a WebDriver instance as an argument.
    
        message: str
            - Optional message for :exc:`TimeoutException`
    
        Return:
        -------
        object: T
            - The result of the last call to `method`
    
        Raises:
        -------
        TimeoutException
            - If 'method' does not return a truthy value within the WebDriverWait
            object's timeout
    
        Example:
        --------
        >>> from selenium.webdriver.common.by import By
        >>> from selenium.webdriver.support.ui import WebDriverWait
        >>> from selenium.webdriver.support import expected_conditions as EC
    
        # Wait until an element is visible on the page
        >>> wait = WebDriverWait(driver, 10)
        >>> element = wait.until(EC.visibility_of_element_located((By.ID, "exampleId")))
        >>> print(element.text)
        """
        screen = None
        stacktrace = None
    
        end_time = time.monotonic() + self._timeout
        while True:
            try:
                value = method(self._driver)
                if value:
                    return value
            except self._ignored_exceptions as exc:
                screen = getattr(exc, "screen", None)
                stacktrace = getattr(exc, "stacktrace", None)
            if time.monotonic() > end_time:
                break
            time.sleep(self._poll)
>       raise TimeoutException(message, screen, stacktrace)
E       selenium.common.exceptions.TimeoutException: Message: 
E       Stacktrace:
E       #0 0x55c62254a71a <unknown>
E       #1 0x55c621fed0a0 <unknown>
E       #2 0x55c62203e9b0 <unknown>
E       #3 0x55c62203eba1 <unknown>
E       #4 0x55c62208cea4 <unknown>
E       #5 0x55c6220643cd <unknown>
E       #6 0x55c62208a2a0 <unknown>
E       #7 0x55c622064173 <unknown>
E       #8 0x55c622030d4b <unknown>
E       #9 0x55c6220319b1 <unknown>
E       #10 0x55c62250f8cb <unknown>
E       #11 0x55c6225137ca <unknown>
E       #12 0x55c6224f7622 <unknown>
E       #13 0x55c622514354 <unknown>
E       #14 0x55c6224dc45f <unknown>
E       #15 0x55c6225384f8 <unknown>
E       #16 0x55c6225386d6 <unknown>
E       #17 0x55c622549586 <unknown>
E       #18 0x7f8b92f80aa4 <unknown>
E       #19 0x7f8b9300da34 __clone

.venv/lib/python3.13.../webdriver/support/wait.py:146: TimeoutException

During handling of the above exception, another exception occurred:

self = <unittest.case._Outcome object at 0x7f7986b4cb90>
test_case = <tests.e2e.test_source_saml.TestSourceSAML testMethod=test_idp_post_auto_enroll_auth>
subTest = False

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

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

self = <tests.e2e.test_source_saml.TestSourceSAML testMethod=test_idp_post_auto_enroll_auth>
result = <TestCaseFunction test_idp_post_auto_enroll_auth>

    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.3........./x64/lib/python3.13/unittest/case.py:651: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <tests.e2e.test_source_saml.TestSourceSAML testMethod=test_idp_post_auto_enroll_auth>
method = <bound method TestSourceSAML.test_idp_post_auto_enroll_auth of <tests.e2e.test_source_saml.TestSourceSAML testMethod=test_idp_post_auto_enroll_auth>>

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

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

self = <tests.e2e.test_source_saml.TestSourceSAML testMethod=test_idp_post_auto_enroll_auth>
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)
    
        except tuple(exceptions) as exc:
            count += 1
            if count > max_retires:
                logger.debug("Exceeded retry count", exc=exc, test=self)
    
                raise exc
            logger.debug("Retrying on error", exc=exc, test=self)
            self.tearDown()
            self._post_teardown()
            self._pre_setup()
            self.setUp()
>           return wrapper(self, *args, **kwargs)

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

self = <tests.e2e.test_source_saml.TestSourceSAML testMethod=test_idp_post_auto_enroll_auth>
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)
    
        except tuple(exceptions) as exc:
            count += 1
            if count > max_retires:
                logger.debug("Exceeded retry count", exc=exc, test=self)
    
                raise exc
            logger.debug("Retrying on error", exc=exc, test=self)
            self.tearDown()
            self._post_teardown()
            self._pre_setup()
            self.setUp()
>           return wrapper(self, *args, **kwargs)

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

self = <tests.e2e.test_source_saml.TestSourceSAML testMethod=test_idp_post_auto_enroll_auth>
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)
    
        except tuple(exceptions) as exc:
            count += 1
            if count > max_retires:
                logger.debug("Exceeded retry count", exc=exc, test=self)
    
>               raise exc

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

self = <tests.e2e.test_source_saml.TestSourceSAML testMethod=test_idp_post_auto_enroll_auth>
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:329: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

args = (<tests.e2e.test_source_saml.TestSourceSAML testMethod=test_idp_post_auto_enroll_auth>,)
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_source_saml.TestSourceSAML testMethod=test_idp_post_auto_enroll_auth>,)
kwargs = {}, file = 'default/flow-default-source-pre-authentication.yaml'
content = 'version: 1\nmetadata:\n  name: Default - Source pre-authentication flow\nentries:\n- attrs:\n    designation: stage_c...    authentication: none\n  identifiers:\n    slug: default-source-pre-authentication\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: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <tests.e2e.test_source_saml.TestSourceSAML testMethod=test_idp_post_auto_enroll_auth>

    @retry()
    @apply_blueprint(
        "default/flow-default-authentication-flow.yaml",
        "default/flow-default-invalidation-flow.yaml",
    )
    @apply_blueprint(
        "default/flow-default-source-authentication.yaml",
        "default/flow-default-source-enrollment.yaml",
        "default/flow-default-source-pre-authentication.yaml",
    )
    def test_idp_post_auto_enroll_auth(self):
        """test SAML Source With post binding (auto redirect)"""
        # Bootstrap all needed objects
        authentication_flow = Flow.objects.get(slug="default-source-authentication")
        enrollment_flow = Flow.objects.get(slug="default-source-enrollment")
        pre_authentication_flow = Flow.objects.get(slug="default-source-pre-authentication")
        keypair = CertificateKeyPair.objects.create(
            name=generate_id(),
            certificate_data=IDP_CERT,
            key_data=IDP_KEY,
        )
    
        source = SAMLSource.objects.create(
            name=generate_id(),
            slug=self.slug,
            authentication_flow=authentication_flow,
            enrollment_flow=enrollment_flow,
            pre_authentication_flow=pre_authentication_flow,
            issuer="entity-id",
            sso_url=f"http://{self.host}:.../saml2/idp/SSOService.php",
            binding_type=SAMLBindingTypes.POST_AUTO,
            signing_kp=keypair,
        )
        ident_stage = IdentificationStage.objects.first()
        ident_stage.sources.set([source])
        ident_stage.save()
    
        self.driver.get(self.live_server_url)
    
        flow_executor = self.get_shadow_root("ak-flow-executor")
        identification_stage = self.get_shadow_root("ak-stage-identification", flow_executor)
        wait = WebDriverWait(identification_stage, self.wait_timeout)
    
        wait.until(
            ec.presence_of_element_located(
                (By.CSS_SELECTOR, ".pf-c-login__main-footer-links-item > button")
            )
        )
        identification_stage.find_element(
            By.CSS_SELECTOR, ".pf-c-login__main-footer-links-item > button"
        ).click()
    
        # Now we should be at the IDP, wait for the username field
        self.wait.until(ec.presence_of_element_located((By.ID, "username")))
        self.driver.find_element(By.ID, "username").send_keys("user1")
        self.driver.find_element(By.ID, "password").send_keys("user1pass")
        self.driver.find_element(By.ID, "password").send_keys(Keys.ENTER)
    
        # Wait until we're logged in
        self.wait_for_url(self.if_user_url())
    
        self.assert_user(
            User.objects.exclude(username="akadmin")
            .exclude(username__startswith="ak-outpost")
            .exclude_anonymous()
            .exclude(pk=self.user.pk)
            .first()
        )
    
        # Clear all cookies and log in again
        self.driver.delete_all_cookies()
        self.driver.get(self.live_server_url)
    
        flow_executor = self.get_shadow_root("ak-flow-executor")
        identification_stage = self.get_shadow_root("ak-stage-identification", flow_executor)
        wait = WebDriverWait(identification_stage, self.wait_timeout)
    
        wait.until(
            ec.presence_of_element_located(
                (By.CSS_SELECTOR, ".pf-c-login__main-footer-links-item > button")
            )
        )
        identification_stage.find_element(
            By.CSS_SELECTOR, ".pf-c-login__main-footer-links-item > button"
        ).click()
    
        # Now we should be at the IDP, wait for the username field
>       self.wait.until(ec.presence_of_element_located((By.ID, "username")))

tests/e2e/test_source_saml.py:414: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <selenium.webdriver.support.wait.WebDriverWait (session="61a84ab2507d98e2442ad18ced351400")>
method = <function presence_of_element_located.<locals>._predicate at 0x7f797c856480>
message = ''

    def until(self, method: Callable[[D], Union[Literal[False], T]], message: str = "") -> T:
        """Wait until the method returns a value that is not False.
    
        Calls the method provided with the driver as an argument until the
        return value does not evaluate to ``False``.
    
        Parameters:
        -----------
        method: callable(WebDriver)
            - A callable object that takes a WebDriver instance as an argument.
    
        message: str
            - Optional message for :exc:`TimeoutException`
    
        Return:
        -------
        object: T
            - The result of the last call to `method`
    
        Raises:
        -------
        TimeoutException
            - If 'method' does not return a truthy value within the WebDriverWait
            object's timeout
    
        Example:
        --------
        >>> from selenium.webdriver.common.by import By
        >>> from selenium.webdriver.support.ui import WebDriverWait
        >>> from selenium.webdriver.support import expected_conditions as EC
    
        # Wait until an element is visible on the page
        >>> wait = WebDriverWait(driver, 10)
        >>> element = wait.until(EC.visibility_of_element_located((By.ID, "exampleId")))
        >>> print(element.text)
        """
        screen = None
        stacktrace = None
    
        end_time = time.monotonic() + self._timeout
        while True:
            try:
                value = method(self._driver)
                if value:
                    return value
            except self._ignored_exceptions as exc:
                screen = getattr(exc, "screen", None)
                stacktrace = getattr(exc, "stacktrace", None)
            if time.monotonic() > end_time:
                break
            time.sleep(self._poll)
>       raise TimeoutException(message, screen, stacktrace)
E       selenium.common.exceptions.TimeoutException: Message: 
E       Stacktrace:
E       #0 0x561838b7b71a <unknown>
E       #1 0x56183861e0a0 <unknown>
E       #2 0x56183866f9b0 <unknown>
E       #3 0x56183866fba1 <unknown>
E       #4 0x5618386bdea4 <unknown>
E       #5 0x5618386953cd <unknown>
E       #6 0x5618386bb2a0 <unknown>
E       #7 0x561838695173 <unknown>
E       #8 0x561838661d4b <unknown>
E       #9 0x5618386629b1 <unknown>
E       #10 0x561838b408cb <unknown>
E       #11 0x561838b447ca <unknown>
E       #12 0x561838b28622 <unknown>
E       #13 0x561838b45354 <unknown>
E       #14 0x561838b0d45f <unknown>
E       #15 0x561838b694f8 <unknown>
E       #16 0x561838b696d6 <unknown>
E       #17 0x561838b7a586 <unknown>
E       #18 0x7ffaa7803aa4 <unknown>
E       #19 0x7ffaa7890a34 __clone

.venv/lib/python3.13.../webdriver/support/wait.py:146: TimeoutException

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 c6333f9 into main May 27, 2025
95 of 97 checks passed
@BeryJu BeryJu deleted the web/fix-package-lock branch May 27, 2025 01:28
kensternberg-authentik added a commit that referenced this pull request Jun 6, 2025
* main: (27 commits)
  lib/sync/outgoing: sync in parallel (#14697)
  core, web: update translations (#14707)
  tests/e2e: fix flaky SAML Source test (#14708)
  web: fix lock (#14705)
  Update packages-npm-publish.yml (#14702)
  website/integrations: coder: fix typo (#14514)
  ci: Update packages-npm-publish.yml (#14701)
  web: bump the swc group across 2 directories with 12 updates (#14623)
  web: Use engine available on Github Actions. (#14699)
  web: bump the rollup group across 1 directory with 4 updates (#14682)
  ci: test with postgres 17 (#13967)
  web: bump knip from 5.33.0 to 5.58.0 in /web (#14685)
  web: bump fuse.js from 7.0.0 to 7.1.0 in /web (#14687)
  web: bump @formatjs/intl-listformat from 7.5.7 to 7.7.11 in /web (#14689)
  root: do not use /bin/bash directly (#14698)
  website/integrations: minio: notice about sso deprecation on CE (#14679)
  core: bump cryptography from 44.0.3 to 45.0.3 (#14690)
  core: bump django-tenants from 3.7.0 to 3.8.0 (#14691)
  core: bump astral-sh/uv from 0.7.7 to 0.7.8 (#14681)
  core: bump axllent/mailpit from v1.25.0 to v1.25.1 in /tests/e2e (#14693)
  ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant