hermes-agent/tests/hermes_cli/test_non_ascii_credential.py
kshitijk4poor 66827f8947 chore: prune unused imports and duplicate import redefinitions
Remove unused imports (F401) and duplicate/shadowed import
redefinitions (F811) across the codebase using ruff's safe
autofixes. No behavioral changes -- imports only.

- ~1400 safe autofixes applied across 644 files (net -1072 lines)
- __init__.py re-exports preserved (excluded from F401 removal so
  public re-export surfaces stay intact)
- Re-exports that are imported or monkeypatched by tests but look
  unused in their defining module are kept with explicit # noqa:
  F401 (gateway/run.py load_dotenv; run_agent re-exports from
  agent.message_sanitization, agent.context_compressor,
  agent.retry_utils, agent.prompt_builder, agent.process_bootstrap,
  agent.codex_responses_adapter)
- Unsafe F841 (unused-variable) fixes deliberately skipped -- those
  can change behavior when the RHS has side effects
- ruff lints remain disabled in pyproject.toml (only PLW1514 is
  selected); this is a one-time cleanup, not a config change

Verification:
- python -m compileall: clean
- pytest --collect-only: all 27161 tests collect (zero import errors)
- core entry points import clean (run_agent, model_tools, cli,
  toolsets, hermes_state, batch_runner, gateway)
- static scan: every name any test imports directly from an edited
  module still resolves
2026-05-28 22:26:25 -07:00

130 lines
5.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""Tests for non-ASCII credential detection and sanitization.
Covers the fix for issue #6843 — API keys containing Unicode lookalike
characters (e.g. ʋ U+028B instead of v) cause UnicodeEncodeError when
httpx tries to encode the Authorization header as ASCII.
"""
import os
from hermes_cli.config import _check_non_ascii_credential
class TestCheckNonAsciiCredential:
"""Tests for _check_non_ascii_credential()."""
def test_ascii_key_unchanged(self):
key = "sk-proj-" + "a" * 100
result = _check_non_ascii_credential("TEST_API_KEY", key)
assert result == key
def test_strips_unicode_v_lookalike(self, capsys):
"""The exact scenario from issue #6843: ʋ instead of v."""
key = "sk-proj-abc" + "ʋ" + "def" # \u028b
result = _check_non_ascii_credential("OPENROUTER_API_KEY", key)
assert result == "sk-proj-abcdef"
assert "ʋ" not in result
# Should print a warning
captured = capsys.readouterr()
assert "non-ASCII" in captured.err
def test_strips_multiple_non_ascii(self, capsys):
key = "sk-proj-aʋbécd"
result = _check_non_ascii_credential("OPENAI_API_KEY", key)
assert result == "sk-proj-abcd"
captured = capsys.readouterr()
assert "U+028B" in captured.err # reports the char
def test_empty_key(self):
result = _check_non_ascii_credential("TEST_KEY", "")
assert result == ""
def test_all_ascii_no_warning(self, capsys):
result = _check_non_ascii_credential("KEY", "all-ascii-value-123")
assert result == "all-ascii-value-123"
captured = capsys.readouterr()
assert captured.err == ""
class TestEnvLoaderSanitization:
"""Tests for _sanitize_loaded_credentials in env_loader."""
def test_strips_non_ascii_from_api_key(self, monkeypatch):
from hermes_cli.env_loader import _sanitize_loaded_credentials, _WARNED_KEYS
_WARNED_KEYS.discard("OPENROUTER_API_KEY")
monkeypatch.setenv("OPENROUTER_API_KEY", "sk-proj-abcʋdef")
_sanitize_loaded_credentials()
assert os.environ["OPENROUTER_API_KEY"] == "sk-proj-abcdef"
def test_strips_non_ascii_from_token(self, monkeypatch):
from hermes_cli.env_loader import _sanitize_loaded_credentials, _WARNED_KEYS
_WARNED_KEYS.discard("DISCORD_BOT_TOKEN")
monkeypatch.setenv("DISCORD_BOT_TOKEN", "tokénvalue")
_sanitize_loaded_credentials()
assert os.environ["DISCORD_BOT_TOKEN"] == "toknvalue"
def test_ignores_non_credential_vars(self, monkeypatch):
from hermes_cli.env_loader import _sanitize_loaded_credentials
monkeypatch.setenv("MY_UNICODE_VAR", "héllo wörld")
_sanitize_loaded_credentials()
# Not a credential suffix — should be left alone
assert os.environ["MY_UNICODE_VAR"] == "héllo wörld"
def test_ascii_credentials_untouched(self, monkeypatch):
from hermes_cli.env_loader import _sanitize_loaded_credentials
monkeypatch.setenv("OPENAI_API_KEY", "sk-proj-allascii123")
_sanitize_loaded_credentials()
assert os.environ["OPENAI_API_KEY"] == "sk-proj-allascii123"
def test_warns_to_stderr_when_stripping(self, monkeypatch, capsys):
"""Silent stripping masks bad keys as opaque provider 400s (see #6843 fallout).
Users must be told when a copy-paste artifact was removed so they
can re-copy the key if authentication fails.
"""
from hermes_cli.env_loader import _sanitize_loaded_credentials, _WARNED_KEYS
_WARNED_KEYS.discard("GOOGLE_API_KEY")
monkeypatch.setenv("GOOGLE_API_KEY", "AIzaSy\u200babcdef") # ZWSP mid-key
_sanitize_loaded_credentials()
assert os.environ["GOOGLE_API_KEY"] == "AIzaSyabcdef"
captured = capsys.readouterr()
assert "GOOGLE_API_KEY" in captured.err
assert "U+200B" in captured.err
assert "re-copy" in captured.err.lower()
def test_warning_fires_only_once_per_key(self, monkeypatch, capsys):
"""Repeated loads (user env + project env) must not double-warn."""
from hermes_cli.env_loader import _sanitize_loaded_credentials, _WARNED_KEYS
_WARNED_KEYS.discard("GEMINI_API_KEY")
monkeypatch.setenv("GEMINI_API_KEY", "AIza\u028bbad")
_sanitize_loaded_credentials()
first = capsys.readouterr().err
monkeypatch.setenv("GEMINI_API_KEY", "AIza\u028bbad2")
_sanitize_loaded_credentials()
second = capsys.readouterr().err
assert "GEMINI_API_KEY" in first
assert second == "" # no repeat warning
def test_ascii_control_chars_not_stripped(self, monkeypatch, capsys):
"""ASCII control bytes (e.g. ESC 0x1B from terminal paste) are NOT non-ASCII.
This is intentional — they're valid ASCII for HTTP headers even if the
provider rejects them. Documents the scope of the sanitizer.
"""
from hermes_cli.env_loader import _sanitize_loaded_credentials, _WARNED_KEYS
_WARNED_KEYS.clear()
monkeypatch.setenv("ANTHROPIC_API_KEY", "sk-ant\x1bapi-key")
_sanitize_loaded_credentials()
assert os.environ["ANTHROPIC_API_KEY"] == "sk-ant\x1bapi-key"
assert capsys.readouterr().err == ""