#9928 Nightly test failure in webui tests related to certificates
Opened by frenaud. Modified

Issue

Two nightly webui tests failed this week, both related to certificates:
- test_webui/test_user.py::test_user::test_certificate_serial (Run)

self = <ipatests.test_webui.test_user.test_user object at 0x7f06a3be6140>
    @screenshot
    def test_certificate_serial(self):
        """Test long certificate serial no
        Long certificate serial no were shown in scientific notation
        at user details page. This test checks that it is no longer shown
        in scientific notation
        related:https://pagure.io/freeipa/issue/8754
        """
        if not self.has_ca():
            self.skip('CA is not configured')
        self.init_app()
        self.add_record(user.ENTITY, user.DATA2)
        self.wait()
        self.close_notifications()
        self.navigate_to_record(user.PKEY2)
        self.add_cert_to_record(user.USER_CERT, user.PKEY2, save=False)
        # check if the cert serial is 264374074076456325397645183544606453821
>       self.assert_text(
            'div[name="cert-serial-num"]',
            '264374074076456325397645183544606453821'
        )
self       = <ipatests.test_webui.test_user.test_user object at 0x7f06a3be6140>
test_webui/test_user.py:375: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
test_webui/ui_driver.py:2093: in assert_text
    text = self.get_text(selector, parent)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        parent     = None
        selector   = 'div[name="cert-serial-num"]'
        self       = <ipatests.test_webui.test_user.test_user object at 0x7f06a3be6140>
        value      = '264374074076456325397645183544606453821'
test_webui/ui_driver.py:1076: in get_text
    el = self.find(selector, By.CSS_SELECTOR, parent, strict=True)
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        parent     = <selenium.webdriver.remote.webelement.WebElement (session="6768849a-9842-43ff-ab43-079331590e8a", element="224cd6c8-a39f-4ae4-8afc-722b67056cd3")>
        selector   = 'div[name="cert-serial-num"]'
        self       = <ipatests.test_webui.test_user.test_user object at 0x7f06a3be6140>
test_webui/ui_driver.py:129: in wrapped
    return fn(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^
        args       = (<ipatests.test_webui.test_user.test_user object at 0x7f06a3be6140>, 'div[name="cert-serial-num"]', 'css selector', <s...ebelement.WebElement (session="6768849a-9842-43ff-ab43-079331590e8a", element="224cd6c8-a39f-4ae4-8afc-722b67056cd3")>)
        fn         = <function UI_driver.find at 0x7f06a3c4a980>
        kwargs     = {'strict': True}
        self       = <ipatests.test_webui.test_user.test_user object at 0x7f06a3be6140>
test_webui/ui_driver.py:318: in find
    result = func(by, expression)
             ^^^^^^^^^^^^^^^^^^^^
        by         = 'css selector'
        context    = <selenium.webdriver.remote.webelement.WebElement (session="6768849a-9842-43ff-ab43-079331590e8a", element="224cd6c8-a39f-4ae4-8afc-722b67056cd3")>
        expression = 'div[name="cert-serial-num"]'
        func       = <bound method WebElement.find_element of <selenium.webdriver.remote.webelement.WebElement (session="6768849a-9842-43ff-ab43-079331590e8a", element="224cd6c8-a39f-4ae4-8afc-722b67056cd3")>>
        many       = False
        method_name = 'find_element'
        self       = <ipatests.test_webui.test_user.test_user object at 0x7f06a3be6140>
        strict     = True
/usr/local/lib/python3.14/site-packages/selenium/webdriver/remote/webelement.py:417: in find_element
    return self._execute(Command.FIND_CHILD_ELEMENT, {"using": by, "value": value})["value"]
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        by         = 'css selector'
        self       = <selenium.webdriver.remote.webelement.WebElement (session="6768849a-9842-43ff-ab43-079331590e8a", element="224cd6c8-a39f-4ae4-8afc-722b67056cd3")>
        value      = 'div[name="cert-serial-num"]'
/usr/local/lib/python3.14/site-packages/selenium/webdriver/remote/webelement.py:395: in _execute
    return self._parent.execute(command, params)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        command    = 'findChildElement'
        params     = {'id': '224cd6c8-a39f-4ae4-8afc-722b67056cd3', 'using': 'css selector', 'value': 'div[name="cert-serial-num"]'}
        self       = <selenium.webdriver.remote.webelement.WebElement (session="6768849a-9842-43ff-ab43-079331590e8a", element="224cd6c8-a39f-4ae4-8afc-722b67056cd3")>
/usr/local/lib/python3.14/site-packages/selenium/webdriver/remote/webdriver.py:354: in execute
    self.error_handler.check_response(response)
        driver_command = 'findChildElement'
        params     = {'using': 'css selector', 'value': 'div[name="cert-serial-num"]'}
        response   = {'status': 404, 'value': '{"value":{"error":"no such element","message":"Unable to locate element: div[name=\\"cert-se.../content/shared/webdriver/Errors.sys.mjs:555:5\\ndom.find/</<@chrome://remote/content/shared/DOM.sys.mjs:136:16\\n"}}'}
        self       = <selenium.webdriver.firefox.webdriver.WebDriver (session="6768849a-9842-43ff-ab43-079331590e8a")>
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
self = <selenium.webdriver.remote.errorhandler.ErrorHandler object at 0x7f06a3bfb290>
response = {'status': 404, 'value': '{"value":{"error":"no such element","message":"Unable to locate element: div[name=\\"cert-se.../content/shared/webdriver/Errors.sys.mjs:555:5\\ndom.find/</<@chrome://remote/content/shared/DOM.sys.mjs:136:16\\n"}}'}
    def check_response(self, response: Dict[str, Any]) -> None:
        """Checks that a JSON response from the WebDriver does not have an
        error.
        :Args:
         - response - The JSON response from the WebDriver server as a dictionary
           object.
        :Raises: If the response contains an error message.
        """
        status = response.get("status", None)
        if not status or status == ErrorCode.SUCCESS:
            return
        value = None
        message = response.get("message", "")
        screen: str = response.get("screen", "")
        stacktrace = None
        if isinstance(status, int):
            value_json = response.get("value", None)
            if value_json and isinstance(value_json, str):
                import json
                try:
                    value = json.loads(value_json)
                    if len(value) == 1:
                        value = value["value"]
                    status = value.get("error", None)
                    if not status:
                        status = value.get("status", ErrorCode.UNKNOWN_ERROR)
                        message = value.get("value") or value.get("message")
                        if not isinstance(message, str):
                            value = message
                            message = message.get("message")
                    else:
                        message = value.get("message", None)
                except ValueError:
                    pass
        exception_class: Type[WebDriverException]
        e = ErrorCode()
        error_codes = [item for item in dir(e) if not item.startswith("__")]
        for error_code in error_codes:
            error_info = getattr(ErrorCode, error_code)
            if isinstance(error_info, list) and status in error_info:
                exception_class = getattr(ExceptionMapping, error_code, WebDriverException)
                break
        else:
            exception_class = WebDriverException
        if not value:
            value = response["value"]
        if isinstance(value, str):
            raise exception_class(value)
        if message == "" and "message" in value:
            message = value["message"]
        screen = None  # type: ignore[assignment]
        if "screen" in value:
            screen = value["screen"]
        stacktrace = None
        st_value = value.get("stackTrace") or value.get("stacktrace")
        if st_value:
            if isinstance(st_value, str):
                stacktrace = st_value.split("\n")
            else:
                stacktrace = []
                try:
                    for frame in st_value:
                        line = frame.get("lineNumber", "")
                        file = frame.get("fileName", "<anonymous>")
                        if line:
                            file = f"{file}:{line}"
                        meth = frame.get("methodName", "<anonymous>")
                        if "className" in frame:
                            meth = f"{frame['className']}.{meth}"
                        msg = "    at %s (%s)"
                        msg = msg % (meth, file)
                        stacktrace.append(msg)
                except TypeError:
                    pass
        if exception_class == UnexpectedAlertPresentException:
            alert_text = None
            if "data" in value:
                alert_text = value["data"].get("text")
            elif "alert" in value:
                alert_text = value["alert"].get("text")
            raise exception_class(message, screen, stacktrace, alert_text)  # type: ignore[call-arg]  # mypy is not smart enough here
>       raise exception_class(message, screen, stacktrace)
E       selenium.common.exceptions.NoSuchElementException: Message: Unable to locate element: div[name="cert-serial-num"]; For documentation on this error, please visit: https://www.selenium.dev/documentation/webdriver/troubleshooting/errors#no-such-element-exception
E       Stacktrace:
E       RemoteError@chrome://remote/content/shared/RemoteError.sys.mjs:8:8
E       WebDriverError@chrome://remote/content/shared/webdriver/Errors.sys.mjs:202:5
E       NoSuchElementError@chrome://remote/content/shared/webdriver/Errors.sys.mjs:555:5
E       dom.find/</<@chrome://remote/content/shared/DOM.sys.mjs:136:16
e          = <selenium.webdriver.remote.errorhandler.ErrorCode object at 0x7f06a3922350>
error_code = 'NO_SUCH_ELEMENT'
error_codes = ['ELEMENT_CLICK_INTERCEPTED', 'ELEMENT_IS_NOT_SELECTABLE', 'ELEMENT_NOT_INTERACTABLE', 'ELEMENT_NOT_VISIBLE', 'IME_ENGINE_ACTIVATION_FAILED', 'IME_NOT_AVAILABLE', ...]
error_info = [7, 'no such element']
exception_class = <class 'selenium.common.exceptions.NoSuchElementException'>
json       = <module 'json' from '/usr/lib64/python3.14/json/__init__.py'>
message    = 'Unable to locate element: div[name="cert-serial-num"]'
response   = {'status': 404, 'value': '{"value":{"error":"no such element","message":"Unable to locate element: div[name=\\"cert-se.../content/shared/webdriver/Errors.sys.mjs:555:5\\ndom.find/</<@chrome://remote/content/shared/DOM.sys.mjs:136:16\\n"}}'}
screen     = None
self       = <selenium.webdriver.remote.errorhandler.ErrorHandler object at 0x7f06a3bfb290>
st_value   = 'RemoteError@chrome://remote/content/shared/RemoteError.sys.mjs:8:8\nWebDriverError@chrome://remote/content/shared/web...remote/content/shared/webdriver/Errors.sys.mjs:555:5\ndom.find/</<@chrome://remote/content/shared/DOM.sys.mjs:136:16\n'
stacktrace = ['RemoteError@chrome://remote/content/shared/RemoteError.sys.mjs:8:8', 'WebDriverError@chrome://remote/content/shared/...e/content/shared/webdriver/Errors.sys.mjs:555:5', 'dom.find/</<@chrome://remote/content/shared/DOM.sys.mjs:136:16', '']
status     = 'no such element'
value      = {'error': 'no such element', 'message': 'Unable to locate element: div[name="cert-serial-num"]', 'stacktrace': 'Remote...emote/content/shared/webdriver/Errors.sys.mjs:555:5\ndom.find/</<@chrome://remote/content/shared/DOM.sys.mjs:136:16\n'}
value_json = '{"value":{"error":"no such element","message":"Unable to locate element: div[name=\\"cert-serial-num\\"]","stacktrace...e/content/shared/webdriver/Errors.sys.mjs:555:5\\ndom.find/</<@chrome://remote/content/shared/DOM.sys.mjs:136:16\\n"}}'
/usr/local/lib/python3.14/site-packages/selenium/webdriver/remote/errorhandler.py:229: NoSuchElementException
  • test_webui/test_host.py::test_host::test_arbitrary_certificates (Run)
self = <ipatests.test_webui.test_host.test_host object at 0x7f6158633e10>
    @screenshot
    def test_arbitrary_certificates(self):
        """
        Test managing host arbitrary certificate.
        """
        self.init_app()
        self.add_record(ENTITY, self.data)
        self.navigate_to_record(self.pkey)
        # check whether certificate section is present
        self.assert_visible("div[name='certificate']")
        # add certificate
        self.button_click('add', parents_css_sel="div[name='certificate']")
        self.assert_dialog('cert-add-dialog')
        cert = generate_certificate(self.pkey)
        self.fill_textarea('new_cert', cert)
        self.dialog_button_click('ok')
>       self.assert_visible("div.certificate-widget")
cert       = '-----BEGIN CERTIFICATE-----\nMIIDBDCCAeygAwIBAgIUcbtzbU0zPA1SGHSc3aIAnr3PyY0wDQYJKoZIhvcNAQEL\nBQAwJjEkMCIGA1UEAwwbaG...U1tCFkMSp\nT/fmGzX6d9xDINPy6+z68ilkBkcYvY20c7XlThfN0yPY/tdyrlmTCxcmOpUJ2Tbj\nwhEWhrpy7wg=\n-----END CERTIFICATE-----\n'
self       = <ipatests.test_webui.test_host.test_host object at 0x7f6158633e10>
test_webui/test_host.py:277: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
test_webui/ui_driver.py:2204: in assert_visible
    el = self.find(selector, By.CSS_SELECTOR, parent, strict=True)
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        negative   = False
        parent     = <selenium.webdriver.remote.webelement.WebElement (session="939a1f39-e53e-4456-8b0f-749e88575559", element="faba9f18-b632-47d6-81d2-b16d577bf85a")>
        selector   = 'div.certificate-widget'
        self       = <ipatests.test_webui.test_host.test_host object at 0x7f6158633e10>
test_webui/ui_driver.py:129: in wrapped
    return fn(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^
        args       = (<ipatests.test_webui.test_host.test_host object at 0x7f6158633e10>, 'div.certificate-widget', 'css selector', <seleni...ebelement.WebElement (session="939a1f39-e53e-4456-8b0f-749e88575559", element="faba9f18-b632-47d6-81d2-b16d577bf85a")>)
        fn         = <function UI_driver.find at 0x7f6158522cf0>
        kwargs     = {'strict': True}
        self       = <ipatests.test_webui.test_host.test_host object at 0x7f6158633e10>
test_webui/ui_driver.py:318: in find
    result = func(by, expression)
             ^^^^^^^^^^^^^^^^^^^^
        by         = 'css selector'
        context    = <selenium.webdriver.remote.webelement.WebElement (session="939a1f39-e53e-4456-8b0f-749e88575559", element="faba9f18-b632-47d6-81d2-b16d577bf85a")>
        expression = 'div.certificate-widget'
        func       = <bound method WebElement.find_element of <selenium.webdriver.remote.webelement.WebElement (session="939a1f39-e53e-4456-8b0f-749e88575559", element="faba9f18-b632-47d6-81d2-b16d577bf85a")>>
        many       = False
        method_name = 'find_element'
        self       = <ipatests.test_webui.test_host.test_host object at 0x7f6158633e10>
        strict     = True
/usr/local/lib/python3.14/site-packages/selenium/webdriver/remote/webelement.py:417: in find_element
    return self._execute(Command.FIND_CHILD_ELEMENT, {"using": by, "value": value})["value"]
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        by         = 'css selector'
        self       = <selenium.webdriver.remote.webelement.WebElement (session="939a1f39-e53e-4456-8b0f-749e88575559", element="faba9f18-b632-47d6-81d2-b16d577bf85a")>
        value      = 'div.certificate-widget'
/usr/local/lib/python3.14/site-packages/selenium/webdriver/remote/webelement.py:395: in _execute
    return self._parent.execute(command, params)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        command    = 'findChildElement'
        params     = {'id': 'faba9f18-b632-47d6-81d2-b16d577bf85a', 'using': 'css selector', 'value': 'div.certificate-widget'}
        self       = <selenium.webdriver.remote.webelement.WebElement (session="939a1f39-e53e-4456-8b0f-749e88575559", element="faba9f18-b632-47d6-81d2-b16d577bf85a")>
/usr/local/lib/python3.14/site-packages/selenium/webdriver/remote/webdriver.py:354: in execute
    self.error_handler.check_response(response)
        driver_command = 'findChildElement'
        params     = {'using': 'css selector', 'value': 'div.certificate-widget'}
        response   = {'status': 404, 'value': '{"value":{"error":"no such element","message":"Unable to locate element: div.certificate-wid.../content/shared/webdriver/Errors.sys.mjs:555:5\\ndom.find/</<@chrome://remote/content/shared/DOM.sys.mjs:136:16\\n"}}'}
        self       = <selenium.webdriver.firefox.webdriver.WebDriver (session="939a1f39-e53e-4456-8b0f-749e88575559")>
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
self = <selenium.webdriver.remote.errorhandler.ErrorHandler object at 0x7f615830c7d0>
response = {'status': 404, 'value': '{"value":{"error":"no such element","message":"Unable to locate element: div.certificate-wid.../content/shared/webdriver/Errors.sys.mjs:555:5\\ndom.find/</<@chrome://remote/content/shared/DOM.sys.mjs:136:16\\n"}}'}
    def check_response(self, response: Dict[str, Any]) -> None:
        """Checks that a JSON response from the WebDriver does not have an
        error.
        :Args:
         - response - The JSON response from the WebDriver server as a dictionary
           object.
        :Raises: If the response contains an error message.
        """
        status = response.get("status", None)
        if not status or status == ErrorCode.SUCCESS:
            return
        value = None
        message = response.get("message", "")
        screen: str = response.get("screen", "")
        stacktrace = None
        if isinstance(status, int):
            value_json = response.get("value", None)
            if value_json and isinstance(value_json, str):
                import json
                try:
                    value = json.loads(value_json)
                    if len(value) == 1:
                        value = value["value"]
                    status = value.get("error", None)
                    if not status:
                        status = value.get("status", ErrorCode.UNKNOWN_ERROR)
                        message = value.get("value") or value.get("message")
                        if not isinstance(message, str):
                            value = message
                            message = message.get("message")
                    else:
                        message = value.get("message", None)
                except ValueError:
                    pass
        exception_class: Type[WebDriverException]
        e = ErrorCode()
        error_codes = [item for item in dir(e) if not item.startswith("__")]
        for error_code in error_codes:
            error_info = getattr(ErrorCode, error_code)
            if isinstance(error_info, list) and status in error_info:
                exception_class = getattr(ExceptionMapping, error_code, WebDriverException)
                break
        else:
            exception_class = WebDriverException
        if not value:
            value = response["value"]
        if isinstance(value, str):
            raise exception_class(value)
        if message == "" and "message" in value:
            message = value["message"]
        screen = None  # type: ignore[assignment]
        if "screen" in value:
            screen = value["screen"]
        stacktrace = None
        st_value = value.get("stackTrace") or value.get("stacktrace")
        if st_value:
            if isinstance(st_value, str):
                stacktrace = st_value.split("\n")
            else:
                stacktrace = []
                try:
                    for frame in st_value:
                        line = frame.get("lineNumber", "")
                        file = frame.get("fileName", "<anonymous>")
                        if line:
                            file = f"{file}:{line}"
                        meth = frame.get("methodName", "<anonymous>")
                        if "className" in frame:
                            meth = f"{frame['className']}.{meth}"
                        msg = "    at %s (%s)"
                        msg = msg % (meth, file)
                        stacktrace.append(msg)
                except TypeError:
                    pass
        if exception_class == UnexpectedAlertPresentException:
            alert_text = None
            if "data" in value:
                alert_text = value["data"].get("text")
            elif "alert" in value:
                alert_text = value["alert"].get("text")
            raise exception_class(message, screen, stacktrace, alert_text)  # type: ignore[call-arg]  # mypy is not smart enough here
>       raise exception_class(message, screen, stacktrace)
E       selenium.common.exceptions.NoSuchElementException: Message: Unable to locate element: div.certificate-widget; For documentation on this error, please visit: https://www.selenium.dev/documentation/webdriver/troubleshooting/errors#no-such-element-exception
E       Stacktrace:
E       RemoteError@chrome://remote/content/shared/RemoteError.sys.mjs:8:8
E       WebDriverError@chrome://remote/content/shared/webdriver/Errors.sys.mjs:202:5
E       NoSuchElementError@chrome://remote/content/shared/webdriver/Errors.sys.mjs:555:5
E       dom.find/</<@chrome://remote/content/shared/DOM.sys.mjs:136:16
e          = <selenium.webdriver.remote.errorhandler.ErrorCode object at 0x7f61583c8590>
error_code = 'NO_SUCH_ELEMENT'
error_codes = ['ELEMENT_CLICK_INTERCEPTED', 'ELEMENT_IS_NOT_SELECTABLE', 'ELEMENT_NOT_INTERACTABLE', 'ELEMENT_NOT_VISIBLE', 'IME_ENGINE_ACTIVATION_FAILED', 'IME_NOT_AVAILABLE', ...]
error_info = [7, 'no such element']
exception_class = <class 'selenium.common.exceptions.NoSuchElementException'>
json       = <module 'json' from '/usr/lib64/python3.14/json/__init__.py'>
message    = 'Unable to locate element: div.certificate-widget'
response   = {'status': 404, 'value': '{"value":{"error":"no such element","message":"Unable to locate element: div.certificate-wid.../content/shared/webdriver/Errors.sys.mjs:555:5\\ndom.find/</<@chrome://remote/content/shared/DOM.sys.mjs:136:16\\n"}}'}
screen     = None
self       = <selenium.webdriver.remote.errorhandler.ErrorHandler object at 0x7f615830c7d0>
st_value   = 'RemoteError@chrome://remote/content/shared/RemoteError.sys.mjs:8:8\nWebDriverError@chrome://remote/content/shared/web...remote/content/shared/webdriver/Errors.sys.mjs:555:5\ndom.find/</<@chrome://remote/content/shared/DOM.sys.mjs:136:16\n'
stacktrace = ['RemoteError@chrome://remote/content/shared/RemoteError.sys.mjs:8:8', 'WebDriverError@chrome://remote/content/shared/...e/content/shared/webdriver/Errors.sys.mjs:555:5', 'dom.find/</<@chrome://remote/content/shared/DOM.sys.mjs:136:16', '']
status     = 'no such element'
value      = {'error': 'no such element', 'message': 'Unable to locate element: div.certificate-widget', 'stacktrace': 'RemoteError...emote/content/shared/webdriver/Errors.sys.mjs:555:5\ndom.find/</<@chrome://remote/content/shared/DOM.sys.mjs:136:16\n'}
value_json = '{"value":{"error":"no such element","message":"Unable to locate element: div.certificate-widget","stacktrace":"Remote...e/content/shared/webdriver/Errors.sys.mjs:555:5\\ndom.find/</<@chrome://remote/content/shared/DOM.sys.mjs:136:16\\n"}}'
/usr/local/lib/python3.14/site-packages/selenium/webdriver/remote/errorhandler.py:229: NoSuchElementException

Steps to Reproduce

Run nightly webui tests

Actual behavior

The test does not find the Certificate in the host/user entry

Expected behavior

Should succeed

Version/Release/Distribution

freeipa-server-4.14.0.dev202601261120+gitf6de50195-0.fc44.x86_64


Hi @dhanina

Could you have a look at this issue as it started happening after commit 999caf9 Fix cert-find retrieval and I wonder if it may be related

Metadata Update from @dhanina:
- Issue assigned to dhanina

Reproducer:

CERT="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"
ipa user-add test_user --first=test --last=user --certificate=$CERT
ipa cert-find users=test_user

I think this can be fixed by editing the change here: https://github.com/freeipa/freeipa/pull/7899/changes#diff-f5f363864d6bcb7f6ec950dc4a7935066f88763b5398d858d3f9d4b7a8be1ad3R1988-R1990

Metadata Update from @dhanina:
- Custom field on_review adjusted to https://github.com/freeipa/freeipa/pull/8111

Metadata Update from @dhanina:
- Custom field rhbz adjusted to https://issues.redhat.com/browse/RHEL-150104

Metadata