Files
hermes-agent/agent/ssl_verify.py
ethernet 1c8fae6180 fix(pm): preserve runtime and user state across failure paths
Keep downloads bound to their remote representation and publish through
atomic destination-local staging. Serialize shared partial ownership.

Keep explicit CA trust scoped to provider probes. Preserve checkpoint
history and edited files, validate all profile inputs before dependency
publication, and separate data removal from installed runtime ownership.

Exclude machine-specific PM state from portable transfers. Keep plugin
files and nested skill tools intact. Preserve native test isolation.

Focused native Windows receipts cover the individual repairs and their
integration. This commit does not claim a full-suite or release build.
2026-09-09 15:17:08 -04:00

141 lines
5.1 KiB
Python

"""TLS trust for Hermes. One authority, one trust source.
Trust comes from the platform verifier via ``truststore``: CryptoAPI on
Windows, Security.framework on macOS, and OpenSSL's own store (with a
distro candidate sweep) on Linux. That is the machine's real answer to
"is this chain valid", so a corporate MITM root installed by MDM, an
internal CA, and a locked-down NixOS box all work with no configuration.
``install_truststore()`` runs once at process start and patches
``ssl.SSLContext`` process-wide, so every stack that builds a default
context inherits it — httpx, requests/urllib3, aiohttp, AND the stdlib
``urllib.request`` call sites (the llama.cpp engine download among them)
that a certifi-only or requests-only approach never reached.
The only thing above the platform store is EXPLICIT PER-PROVIDER CONFIG:
``ssl_ca_cert`` (a self-signed or internal endpoint's bundle) and
``ssl_verify: false`` (local development). Those are deliberate
statements about one endpoint, not an ambient guess about the machine.
"""
from __future__ import annotations
import logging
import ssl
import threading
from pathlib import Path
from typing import Any, Optional
logger = logging.getLogger(__name__)
_installed: bool | None = None
def install_truststore() -> bool:
"""Point every default SSLContext at the OS trust store. Idempotent.
Returns True when the platform verifier is in force. A False return
means truststore could not load (an unsupported platform, or a
stripped payload); TLS still works off OpenSSL's compiled-in paths,
it just won't see certificates the OS trusts.
Call before the first HTTPS client is constructed.
"""
global _installed
if _installed is not None:
return _installed
try:
import truststore
truststore.inject_into_ssl()
_installed = True
logger.debug("TLS trust: platform store (truststore)")
except Exception as exc: # noqa: BLE001 — never break startup over TLS setup
_installed = False
logger.warning(
"truststore unavailable (%s); falling back to OpenSSL's default "
"trust paths. Certificates trusted only by the OS store — a "
"corporate root, for instance — will not verify.",
exc,
)
return _installed
def _coerce_insecure(ssl_verify: Any) -> bool:
if ssl_verify is False:
return True
if isinstance(ssl_verify, str) and ssl_verify.strip().lower() in {"false", "0", "no", "off"}:
return True
return False
_CA_CONTEXTS: dict[str | None, ssl.SSLContext] = {}
_CA_CONTEXTS_LOCK = threading.Lock()
def _shared_context(ca_path: str | None) -> ssl.SSLContext:
"""A stable context identity lets clients reuse the existing transport pool."""
with _CA_CONTEXTS_LOCK:
ctx = _CA_CONTEXTS.get(ca_path)
if ctx is None:
if ca_path is not None:
from truststore._ssl_constants import _original_SSLContext
# An explicit bundle replaces OS trust, not augments it.
# PROTOCOL_TLS_CLIENT sets hostname checking and CERT_REQUIRED;
# assigning the original class's properties after injection recurses.
ctx = _original_SSLContext(ssl.PROTOCOL_TLS_CLIENT)
ctx.load_verify_locations(cafile=ca_path)
else:
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
if not _installed:
ctx.load_default_certs()
_CA_CONTEXTS[ca_path] = ctx
return ctx
def resolve_httpx_verify(
*,
ca_bundle: Optional[str] = None,
ssl_verify: Any = None,
base_url: str = "",
) -> bool | ssl.SSLContext:
"""Resolve ``verify`` for an HTTP client.
1. ``ssl_verify: false`` — verification off (local development only)
2. explicit ``ca_bundle`` (the provider's ``ssl_ca_cert``) — that
bundle INSTEAD of the platform store, for an endpoint whose chain
the machine has no reason to trust
3. ``True`` — the platform store, via the process-wide install
``base_url`` only labels the insecure-mode warning.
"""
install_truststore()
if _coerce_insecure(ssl_verify):
logger.warning(
"TLS certificate verification DISABLED (ssl_verify: false) for %s — "
"this is intended for local development only and is unsafe on any "
"network you do not fully control.",
base_url or "a custom provider endpoint",
)
return False
effective_ca = (ca_bundle or "").strip()
if effective_ca:
path = Path(effective_ca).expanduser()
if path.is_file():
return _shared_context(str(path.resolve()))
logger.warning(
"ssl_ca_cert path does not exist: %s — using the OS trust store instead",
effective_ca,
)
# HTTPX reads CA env vars before the injected verifier gets control. Pass
# the platform context directly so stale paths cannot break construction;
# proxy environment handling remains enabled.
import os
if os.environ.get("SSL_CERT_FILE") or os.environ.get("SSL_CERT_DIR"):
return _shared_context(None)
return True