fix(agent,gateway,doctor): add SSL CA cert bundle fail-fast guard
A stale certifi CA bundle after a partial `hermes update` used to crash
the agent on the first outbound HTTPS call with a raw traceback and
trap the gateway in a retry loop.
This patch:
* Adds `agent/errors.py` with a typed `SSLConfigurationError`
* Adds `agent/ssl_guard.py` with a `verify_ca_bundle()` pre-flight
that asserts the bundle exists, is non-trivial in size, and can build
a working SSLContext. On macOS, it falls back to the system trust
store when the bundle is empty but the system store is healthy
(covers corporate proxies / MDM setups).
* Wires the guard into `run_agent.py` and `gateway/run.py` right
after the `hermes_bootstrap` import, inside a try/except so a bug
in the guard itself can never prevent startup.
* Adds a `SSL / CA Certificates` section to `hermes_cli doctor` so
users can detect the failure with one command.
* Adds unit tests covering the healthy, missing, empty, skip-env, and
macOS-fallback paths.
* Adds an RCA document describing the failure mode and the recovery
path (`pip install -e .`).
When the bundle is broken the user sees:
\u26a0\ufe0f SSL certificate bundle issue detected.
Run: pip install -e .
`HERMES_SKIP_SSL_GUARD=1` disables the check for sandboxed
environments that ship their own trust store.
This commit is contained in:
+21
-1
@@ -306,6 +306,23 @@ def _check_s6_supervision(issues: list[str]) -> None:
|
||||
)
|
||||
|
||||
|
||||
def check_certificates() -> None:
|
||||
"""Verify the certifi CA bundle is loadable.
|
||||
|
||||
Surfaces the SSLConfigurationError user-friendly path before they hit
|
||||
a wall of tracebacks on the first outbound HTTPS call.
|
||||
"""
|
||||
try:
|
||||
from agent.ssl_guard import verify_ca_bundle_with_fallback
|
||||
from agent.errors import SSLConfigurationError
|
||||
verify_ca_bundle_with_fallback()
|
||||
check_ok("SSL CA certificate bundle is valid")
|
||||
except SSLConfigurationError as e:
|
||||
check_fail("SSL CA certificate bundle is broken", str(e))
|
||||
except Exception as e:
|
||||
check_warn("SSL certificate check skipped", str(e))
|
||||
|
||||
|
||||
def _check_gateway_service_linger(issues: list[str]) -> None:
|
||||
"""Warn when a systemd user gateway service will stop after logout.
|
||||
|
||||
@@ -567,7 +584,10 @@ def run_doctor(args):
|
||||
# Detect drift between pyproject.toml and hermes_cli/__init__.py versions
|
||||
# (a git conflict resolution can silently revert one but not the other).
|
||||
_check_version_consistency(issues)
|
||||
|
||||
|
||||
_section("SSL / CA Certificates")
|
||||
check_certificates()
|
||||
|
||||
_section("Required Packages")
|
||||
required_packages = [
|
||||
("openai", "OpenAI SDK"),
|
||||
|
||||
Reference in New Issue
Block a user