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.
141 lines
5.1 KiB
Python
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
|