mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-04-28 06:51:16 +08:00
fix: fall back to default certs when CA bundle path doesn't exist (#7352)
_resolve_verify() returned stale CA bundle paths from auth.json without checking if the file exists. When a user logs into Nous Portal on their host (where SSL_CERT_FILE points to a valid cert), that path gets persisted in auth.json. Running hermes model later in Docker where the host path doesn't exist caused FileNotFoundError bubbling up as 'Could not verify credentials: [Errno 2] No such file or directory'. Now _resolve_verify validates the path exists before returning it. If missing, logs a warning and falls back to True (default certifi-based TLS verification).
This commit is contained in:
@@ -1513,7 +1513,15 @@ def _resolve_verify(
|
|||||||
if effective_insecure:
|
if effective_insecure:
|
||||||
return False
|
return False
|
||||||
if effective_ca:
|
if effective_ca:
|
||||||
return str(effective_ca)
|
ca_path = str(effective_ca)
|
||||||
|
if not os.path.isfile(ca_path):
|
||||||
|
import logging
|
||||||
|
logging.getLogger("hermes.auth").warning(
|
||||||
|
"CA bundle path does not exist: %s — falling back to default certificates",
|
||||||
|
ca_path,
|
||||||
|
)
|
||||||
|
return True
|
||||||
|
return ca_path
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
"""Regression tests for Nous OAuth refresh + agent-key mint interactions."""
|
"""Regression tests for Nous OAuth refresh + agent-key mint interactions."""
|
||||||
|
|
||||||
import json
|
import json
|
||||||
|
import os
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
@@ -10,6 +11,80 @@ import pytest
|
|||||||
from hermes_cli.auth import AuthError, get_provider_auth_state, resolve_nous_runtime_credentials
|
from hermes_cli.auth import AuthError, get_provider_auth_state, resolve_nous_runtime_credentials
|
||||||
|
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# _resolve_verify: CA bundle path validation
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
|
||||||
|
class TestResolveVerifyFallback:
|
||||||
|
"""Verify _resolve_verify falls back to True when CA bundle path doesn't exist."""
|
||||||
|
|
||||||
|
def test_missing_ca_bundle_in_auth_state_falls_back(self):
|
||||||
|
from hermes_cli.auth import _resolve_verify
|
||||||
|
|
||||||
|
result = _resolve_verify(auth_state={
|
||||||
|
"tls": {"insecure": False, "ca_bundle": "/nonexistent/ca-bundle.pem"},
|
||||||
|
})
|
||||||
|
assert result is True
|
||||||
|
|
||||||
|
def test_valid_ca_bundle_in_auth_state_is_returned(self, tmp_path):
|
||||||
|
from hermes_cli.auth import _resolve_verify
|
||||||
|
|
||||||
|
ca_file = tmp_path / "ca-bundle.pem"
|
||||||
|
ca_file.write_text("fake cert")
|
||||||
|
result = _resolve_verify(auth_state={
|
||||||
|
"tls": {"insecure": False, "ca_bundle": str(ca_file)},
|
||||||
|
})
|
||||||
|
assert result == str(ca_file)
|
||||||
|
|
||||||
|
def test_missing_ssl_cert_file_env_falls_back(self, monkeypatch):
|
||||||
|
from hermes_cli.auth import _resolve_verify
|
||||||
|
|
||||||
|
monkeypatch.setenv("SSL_CERT_FILE", "/nonexistent/ssl-cert.pem")
|
||||||
|
monkeypatch.delenv("HERMES_CA_BUNDLE", raising=False)
|
||||||
|
result = _resolve_verify(auth_state={"tls": {}})
|
||||||
|
assert result is True
|
||||||
|
|
||||||
|
def test_missing_hermes_ca_bundle_env_falls_back(self, monkeypatch):
|
||||||
|
from hermes_cli.auth import _resolve_verify
|
||||||
|
|
||||||
|
monkeypatch.setenv("HERMES_CA_BUNDLE", "/nonexistent/hermes-ca.pem")
|
||||||
|
monkeypatch.delenv("SSL_CERT_FILE", raising=False)
|
||||||
|
result = _resolve_verify(auth_state={"tls": {}})
|
||||||
|
assert result is True
|
||||||
|
|
||||||
|
def test_insecure_takes_precedence_over_missing_ca(self):
|
||||||
|
from hermes_cli.auth import _resolve_verify
|
||||||
|
|
||||||
|
result = _resolve_verify(
|
||||||
|
insecure=True,
|
||||||
|
auth_state={"tls": {"ca_bundle": "/nonexistent/ca.pem"}},
|
||||||
|
)
|
||||||
|
assert result is False
|
||||||
|
|
||||||
|
def test_no_ca_bundle_returns_true(self, monkeypatch):
|
||||||
|
from hermes_cli.auth import _resolve_verify
|
||||||
|
|
||||||
|
monkeypatch.delenv("HERMES_CA_BUNDLE", raising=False)
|
||||||
|
monkeypatch.delenv("SSL_CERT_FILE", raising=False)
|
||||||
|
result = _resolve_verify(auth_state={"tls": {}})
|
||||||
|
assert result is True
|
||||||
|
|
||||||
|
def test_explicit_ca_bundle_param_missing_falls_back(self):
|
||||||
|
from hermes_cli.auth import _resolve_verify
|
||||||
|
|
||||||
|
result = _resolve_verify(ca_bundle="/nonexistent/explicit-ca.pem")
|
||||||
|
assert result is True
|
||||||
|
|
||||||
|
def test_explicit_ca_bundle_param_valid_is_returned(self, tmp_path):
|
||||||
|
from hermes_cli.auth import _resolve_verify
|
||||||
|
|
||||||
|
ca_file = tmp_path / "explicit-ca.pem"
|
||||||
|
ca_file.write_text("fake cert")
|
||||||
|
result = _resolve_verify(ca_bundle=str(ca_file))
|
||||||
|
assert result == str(ca_file)
|
||||||
|
|
||||||
|
|
||||||
def _setup_nous_auth(
|
def _setup_nous_auth(
|
||||||
hermes_home: Path,
|
hermes_home: Path,
|
||||||
*,
|
*,
|
||||||
|
|||||||
Reference in New Issue
Block a user