feat: normalize base_url and strip credentials from logs

New url_util.py (deliberately separate from the vendored files, so a
future upstream re-sync never conflicts with it): normalize_base_url
strips whitespace/trailing slashes and rejects non-http(s) or hostless
URLs; sanitize_url_for_logging masks embedded basic-auth credentials
for Task 7's discovery logging.

Wires normalization into config_flow.validate_input before the client
is built, with a new invalid_base_url form error.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01739Seac5eMAfNwFeiwV5r4
This commit is contained in:
Adam SmithandClaude Sonnet 5 committed 2026-09-17 17:53:10 -04:00
1 parent 564c52159f
commit 914c89dc6b
4 files changed
+86

No files matched your search

@@ -103,6 +103,7 @@ from .const import (
UNSUPPORTED_PRIORITY_SERVICE_TIERS_MODELS,
UNSUPPORTED_WEB_SEARCH_MODELS,
)
from .url_util import InvalidBaseURL, normalize_base_url
_LOGGER = logging.getLogger(__name__)
@@ -119,6 +120,7 @@ async def validate_input(hass: HomeAssistant, data: dict[str, Any]) -> None:
Data has the keys from STEP_USER_DATA_SCHEMA with values provided by the user.
"""
data[CONF_BASE_URL] = normalize_base_url(data[CONF_BASE_URL])
client = openai.AsyncOpenAI(
api_key=data[CONF_API_KEY],
base_url=data[CONF_BASE_URL],
@@ -145,6 +147,8 @@ class OpenAIConfigFlow(ConfigFlow, domain=DOMAIN):
self._async_abort_entries_match(user_input)
try:
await validate_input(self.hass, user_input)
except InvalidBaseURL:
errors["base"] = "invalid_base_url"
except openai.APIConnectionError:
errors["base"] = "cannot_connect"
except openai.AuthenticationError: