-
Notifications
You must be signed in to change notification settings - Fork 13
Open
Description
Issue:
jmp login command dump a full error stack-trace when ClientConnectorCertificateError occur,
Cause:
Root CA certificate was not correctly defined by Python installation in local dev environment.
Fix:
It works after creating local Root CA Certificates or run script Install Certificates.command from Python installation package.
❯ uname -a
Darwin maboras-mac 25.2.0 Darwin Kernel Version 25.2.0: Tue Nov 18 21:09:56 PST 2025; root:xnu-12377.61.12~1/RELEASE_ARM64_T6041 arm64
❯ jmp version
Jumpstarter v0.1.dev2902+g5489b794d from /Users/maboras/rh_workspace/jumpstarter-dev/jumpstarter/python/packages/jumpstarter-cli-common (Python 3.13.11 (main, Dec 5 2025, 16:06:33) [Clang 17.0.0 (clang-1700.6.3.2)])
related to #57
stack-trace
╭─────────────────────────────── Traceback (most recent call last) ────────────────────────────────╮
│ /Users/maboras/.local/jumpstarter/venv/lib/python3.14/site-packages/aiohttp/connector.py:1313 in │
│ _wrap_create_connection │
│ │
│ 1310 │ │ │ │ │ and sys.version_info >= (3, 11) │
│ 1311 │ │ │ │ ): │
│ 1312 │ │ │ │ │ kwargs["ssl_shutdown_timeout"] = self._ssl_shutdown_timeout │
│ ❱ 1313 │ │ │ │ return await self._loop.create_connection(*args, **kwargs, sock=sock) │
│ 1314 │ │ except cert_errors as exc: │
│ 1315 │ │ │ raise ClientConnectorCertificateError(req.connection_key, exc) from exc │
│ 1316 │ │ except ssl_errors as exc: │
│ │
│ /Library/Frameworks/Python.framework/Versions/3.14/lib/python3.14/asyncio/base_events.py:1198 in │
│ create_connection │
│ │
│ 1195 │ │ │ │ raise ValueError( │
│ 1196 │ │ │ │ │ f'A Stream Socket was expected, got {sock!r}') │
│ 1197 │ │ │
│ ❱ 1198 │ │ transport, protocol = await self._create_connection_transport( │
│ 1199 │ │ │ sock, protocol_factory, ssl, server_hostname, │
│ 1200 │ │ │ ssl_handshake_timeout=ssl_handshake_timeout, │
│ 1201 │ │ │ ssl_shutdown_timeout=ssl_shutdown_timeout) │
│ │
│ /Library/Frameworks/Python.framework/Versions/3.14/lib/python3.14/asyncio/base_events.py:1231 in │
│ _create_connection_transport │
│ │
│ 1228 │ │ │ transport = self._make_socket_transport(sock, protocol, waiter) │
│ 1229 │ │ │
│ 1230 │ │ try: │
│ ❱ 1231 │ │ │ await waiter │
│ 1232 │ │ except: │
│ 1233 │ │ │ transport.close() │
│ 1234 │ │ │ raise │
│ │
│ /Library/Frameworks/Python.framework/Versions/3.14/lib/python3.14/asyncio/sslproto.py:581 in │
│ _on_handshake_complete │
│ │
│ 578 │ │ │ if handshake_exc is None: │
│ 579 │ │ │ │ self._set_state(SSLProtocolState.WRAPPED) │
│ 580 │ │ │ else: │
│ ❱ 581 │ │ │ │ raise handshake_exc │
│ 582 │ │ │ │
│ 583 │ │ │ peercert = sslobj.getpeercert() │
│ 584 │ │ except Exception as exc: │
│ │
│ /Library/Frameworks/Python.framework/Versions/3.14/lib/python3.14/asyncio/sslproto.py:563 in │
│ _do_handshake │
│ │
│ 560 │ │
│ 561 │ def _do_handshake(self): │
│ 562 │ │ try: │
│ ❱ 563 │ │ │ self._sslobj.do_handshake() │
│ 564 │ │ except SSLAgainErrors: │
│ 565 │ │ │ self._process_outgoing() │
│ 566 │ │ except ssl.SSLError as exc: │
│ │
│ /Library/Frameworks/Python.framework/Versions/3.14/lib/python3.14/ssl.py:951 in do_handshake │
│ │
│ 948 │ │
│ 949 │ def do_handshake(self): │
│ 950 │ │ """Start the SSL/TLS handshake.""" │
│ ❱ 951 │ │ self._sslobj.do_handshake() │
│ 952 │ │
│ 953 │ def unwrap(self): │
│ 954 │ │ """Start the SSL shutdown handshake.""" │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1081)
The above exception was the direct cause of the following exception:
╭─────────────────────────────── Traceback (most recent call last) ────────────────────────────────╮
│ /Users/maboras/.local/jumpstarter/bin/jmp:7 in <module> │
│ │
│ 4 if __name__ == '__main__': │
│ 5 │ if sys.argv[0].endswith('.exe'): │
│ 6 │ │ sys.argv[0] = sys.argv[0][:-4] │
│ ❱ 7 │ sys.exit(jmp()) │
│ 8 │
│ │
│ /Users/maboras/.local/jumpstarter/venv/lib/python3.14/site-packages/click/core.py:1485 in │
│ __call__ │
│ │
│ 1482 │ │
│ 1483 │ def __call__(self, *args: t.Any, **kwargs: t.Any) -> t.Any: │
│ 1484 │ │ """Alias for :meth:`main`.""" │
│ ❱ 1485 │ │ return self.main(*args, **kwargs) │
│ 1486 │
│ 1487 │
│ 1488 class _FakeSubclassCheck(type): │
│ │
│ /Users/maboras/.local/jumpstarter/venv/lib/python3.14/site-packages/click/core.py:1406 in main │
│ │
│ 1403 │ │ try: │
│ 1404 │ │ │ try: │
│ 1405 │ │ │ │ with self.make_context(prog_name, args, **extra) as ctx: │
│ ❱ 1406 │ │ │ │ │ rv = self.invoke(ctx) │
│ 1407 │ │ │ │ │ if not standalone_mode: │
│ 1408 │ │ │ │ │ │ return rv │
│ 1409 │ │ │ │ │ # it's not safe to `ctx.exit(rv)` here! │
│ │
│ /Users/maboras/.local/jumpstarter/venv/lib/python3.14/site-packages/click/core.py:1873 in invoke │
│ │
│ 1870 │ │ │ │ super().invoke(ctx) │
│ 1871 │ │ │ │ sub_ctx = cmd.make_context(cmd_name, args, parent=ctx) │
│ 1872 │ │ │ │ with sub_ctx: │
│ ❱ 1873 │ │ │ │ │ return _process_result(sub_ctx.command.invoke(sub_ctx)) │
│ 1874 │ │ │
│ 1875 │ │ # In chain mode we create the contexts step by step, but after the │
│ 1876 │ │ # base command has been invoked. Because at that point we do not │
│ │
│ /Users/maboras/.local/jumpstarter/venv/lib/python3.14/site-packages/click/core.py:1269 in invoke │
│ │
│ 1266 │ │ │ echo(style(message, fg="red"), err=True) │
│ 1267 │ │ │
│ 1268 │ │ if self.callback is not None: │
│ ❱ 1269 │ │ │ return ctx.invoke(self.callback, **ctx.params) │
│ 1270 │ │
│ 1271 │ def shell_complete(self, ctx: Context, incomplete: str) -> list[CompletionItem]: │
│ 1272 │ │ """Return a list of completions for the incomplete value. Looks │
│ │
│ /Users/maboras/.local/jumpstarter/venv/lib/python3.14/site-packages/click/core.py:824 in invoke │
│ │
│ 821 │ │ │
│ 822 │ │ with augment_usage_errors(self): │
│ 823 │ │ │ with ctx: │
│ ❱ 824 │ │ │ │ return callback(*args, **kwargs) │
│ 825 │ │
│ 826 │ def forward(self, cmd: Command, /, *args: t.Any, **kwargs: t.Any) -> t.Any: │
│ 827 │ │ """Similar to :meth:`invoke` but fills in default keyword │
│ │
│ /Users/maboras/.local/jumpstarter/venv/lib/python3.14/site-packages/jumpstarter_cli_common/oidc. │
│ py:36 in wrapper │
│ │
│ 33 │ ) │
│ 34 │ @wraps(f) │
│ 35 │ def wrapper(*args, **kwds): │
│ ❱ 36 │ │ return f(*args, **kwds) │
│ 37 │ │
│ 38 │ return wrapper │
│ 39 │
│ │
│ /Users/maboras/.local/jumpstarter/venv/lib/python3.14/site-packages/jumpstarter_cli_common/confi │
│ g.py:94 in wrapper │
│ │
│ 91 │ │ except Exception as e: │
│ 92 │ │ │ raise click.ClickException("Failed to load config: {}".format(e)) from e │
│ 93 │ │ │
│ ❱ 94 │ │ return f(*args, **kwds, config=config) │
│ 95 │ │
│ 96 │ return reduce(lambda w, opt: opt(w), options, wrapper) │
│ 97 │
│ │
│ /Users/maboras/.local/jumpstarter/venv/lib/python3.14/site-packages/jumpstarter_cli_common/block │
│ ing.py:8 in wrapper │
│ │
│ 5 def blocking(f): │
│ 6 │ @wraps(f) │
│ 7 │ def wrapper(*args, **kwargs): │
│ ❱ 8 │ │ return run(f(*args, **kwargs)) │
│ 9 │ │
│ 10 │ return wrapper │
│ 11 │
│ │
│ /Library/Frameworks/Python.framework/Versions/3.14/lib/python3.14/asyncio/runners.py:204 in run │
│ │
│ 201 │ │ │ "asyncio.run() cannot be called from a running event loop") │
│ 202 │ │
│ 203 │ with Runner(debug=debug, loop_factory=loop_factory) as runner: │
│ ❱ 204 │ │ return runner.run(main) │
│ 205 │
│ 206 │
│ 207 def _cancel_all_tasks(loop): │
│ │
│ /Library/Frameworks/Python.framework/Versions/3.14/lib/python3.14/asyncio/runners.py:127 in run │
│ │
│ 124 │ │ │
│ 125 │ │ self._interrupt_count = 0 │
│ 126 │ │ try: │
│ ❱ 127 │ │ │ return self._loop.run_until_complete(task) │
│ 128 │ │ except exceptions.CancelledError: │
│ 129 │ │ │ if self._interrupt_count > 0: │
│ 130 │ │ │ │ uncancel = getattr(task, "uncancel", None) │
│ │
│ /Library/Frameworks/Python.framework/Versions/3.14/lib/python3.14/asyncio/base_events.py:719 in │
│ run_until_complete │
│ │
│ 716 │ │ if not future.done(): │
│ 717 │ │ │ raise RuntimeError('Event loop stopped before Future completed.') │
│ 718 │ │ │
│ ❱ 719 │ │ return future.result() │
│ 720 │ │
│ 721 │ def stop(self): │
│ 722 │ │ """Stop running the event loop. │
│ │
│ /Users/maboras/.local/jumpstarter/venv/lib/python3.14/site-packages/jumpstarter_cli/login.py:135 │
│ in login │
│ │
│ 132 │ │ tokens = await oidc.password_grant(username, password) │
│ 133 │ else: │
│ 134 │ │ prompt = "login" if force else None │
│ ❱ 135 │ │ tokens = await oidc.authorization_code_grant(callback_port=callback_port, prompt │
│ 136 │ │
│ 137 │ config.token = tokens["access_token"] │
│ 138 │
│ │
│ /Users/maboras/.local/jumpstarter/venv/lib/python3.14/site-packages/jumpstarter_cli_common/oidc. │
│ py:86 in authorization_code_grant │
│ │
│ 83 │ │ ) │
│ 84 │ │
│ 85 │ async def authorization_code_grant(self, callback_port: int | None = None, prompt: s │
│ ❱ 86 │ │ config = await self.configuration() │
│ 87 │ │ │
│ 88 │ │ # Use provided port, fall back to env var, then default to 0 (OS picks) │
│ 89 │ │ if callback_port is not None: │
│ │
│ /Users/maboras/.local/jumpstarter/venv/lib/python3.14/site-packages/jumpstarter_cli_common/oidc. │
│ py:49 in configuration │
│ │
│ 46 │ │
│ 47 │ async def configuration(self): │
│ 48 │ │ async with aiohttp.ClientSession() as session: │
│ ❱ 49 │ │ │ async with session.get( │
│ 50 │ │ │ │ URL(self.issuer).joinpath(".well-known", "openid-configuration"), │
│ 51 │ │ │ │ raise_for_status=True, │
│ 52 │ │ │ ) as response: │
│ │
│ /Users/maboras/.local/jumpstarter/venv/lib/python3.14/site-packages/aiohttp/client.py:1510 in │
│ __aenter__ │
│ │
│ 1507 │ │ return self.__await__() │
│ 1508 │ │
│ 1509 │ async def __aenter__(self) -> _RetType: │
│ ❱ 1510 │ │ self._resp: _RetType = await self._coro │
│ 1511 │ │ return await self._resp.__aenter__() │
│ 1512 │ │
│ 1513 │ async def __aexit__( │
│ │
│ /Users/maboras/.local/jumpstarter/venv/lib/python3.14/site-packages/aiohttp/client.py:779 in │
│ _request │
│ │
│ 776 │ │ │ │ │ │ handler = _connect_and_send_request │
│ 777 │ │ │ │ │ │
│ 778 │ │ │ │ │ try: │
│ ❱ 779 │ │ │ │ │ │ resp = await handler(req) │
│ 780 │ │ │ │ │ # Client connector errors should not be retried │
│ 781 │ │ │ │ │ except ( │
│ 782 │ │ │ │ │ │ ConnectionTimeoutError, │
│ │
│ /Users/maboras/.local/jumpstarter/venv/lib/python3.14/site-packages/aiohttp/client.py:734 in │
│ _connect_and_send_request │
│ │
│ 731 │ │ │ │ │ │ # connection timeout │
│ 732 │ │ │ │ │ │ assert self._connector is not None │
│ 733 │ │ │ │ │ │ try: │
│ ❱ 734 │ │ │ │ │ │ │ conn = await self._connector.connect( │
│ 735 │ │ │ │ │ │ │ │ req, traces=traces, timeout=real_timeout │
│ 736 │ │ │ │ │ │ │ ) │
│ 737 │ │ │ │ │ │ except asyncio.TimeoutError as exc: │
│ │
│ /Users/maboras/.local/jumpstarter/venv/lib/python3.14/site-packages/aiohttp/connector.py:672 in │
│ connect │
│ │
│ 669 │ │ │ │ if traces: │
│ 670 │ │ │ │ │ for trace in traces: │
│ 671 │ │ │ │ │ │ await trace.send_connection_create_start() │
│ ❱ 672 │ │ │ │ proto = await self._create_connection(req, traces, timeout) │
│ 673 │ │ │ │ if traces: │
│ 674 │ │ │ │ │ for trace in traces: │
│ 675 │ │ │ │ │ │ await trace.send_connection_create_end() │
│ │
│ /Users/maboras/.local/jumpstarter/venv/lib/python3.14/site-packages/aiohttp/connector.py:1239 in │
│ _create_connection │
│ │
│ 1236 │ │ if req.proxy: │
│ 1237 │ │ │ _, proto = await self._create_proxy_connection(req, traces, timeout) │
│ 1238 │ │ else: │
│ ❱ 1239 │ │ │ _, proto = await self._create_direct_connection(req, traces, timeout) │
│ 1240 │ │ │
│ 1241 │ │ return proto │
│ 1242 │
│ │
│ /Users/maboras/.local/jumpstarter/venv/lib/python3.14/site-packages/aiohttp/connector.py:1611 in │
│ _create_direct_connection │
│ │
│ 1608 │ │ │ return transp, proto │
│ 1609 │ │ else: │
│ 1610 │ │ │ assert last_exc is not None │
│ ❱ 1611 │ │ │ raise last_exc │
│ 1612 │ │
│ 1613 │ async def _create_proxy_connection( │
│ 1614 │ │ self, req: ClientRequest, traces: List["Trace"], timeout: "ClientTimeout" │
│ │
│ /Users/maboras/.local/jumpstarter/venv/lib/python3.14/site-packages/aiohttp/connector.py:1580 in │
│ _create_direct_connection │
│ │
│ 1577 │ │ │ ) │
│ 1578 │ │ │ │
│ 1579 │ │ │ try: │
│ ❱ 1580 │ │ │ │ transp, proto = await self._wrap_create_connection( │
│ 1581 │ │ │ │ │ self._factory, │
│ 1582 │ │ │ │ │ timeout=timeout, │
│ 1583 │ │ │ │ │ ssl=sslcontext, │
│ │
│ /Users/maboras/.local/jumpstarter/venv/lib/python3.14/site-packages/aiohttp/connector.py:1315 in │
│ _wrap_create_connection │
│ │
│ 1312 │ │ │ │ │ kwargs["ssl_shutdown_timeout"] = self._ssl_shutdown_timeout │
│ 1313 │ │ │ │ return await self._loop.create_connection(*args, **kwargs, sock=sock) │
│ 1314 │ │ except cert_errors as exc: │
│ ❱ 1315 │ │ │ raise ClientConnectorCertificateError(req.connection_key, exc) from exc │
│ 1316 │ │ except ssl_errors as exc: │
│ 1317 │ │ │ raise ClientConnectorSSLError(req.connection_key, exc) from exc │
│ 1318 │ │ except OSError as exc: │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
ClientConnectorCertificateError: Cannot connect to host auth.redhat.com:443 ssl:True [SSLCertVerificationError: (1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1081)')]
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels