fix: Address code review findings for v2.4.0

- Fix 404 accepted as valid API response in config_flow validation (both ConfigFlow and OptionsFlow)
- Sanitize catch-all exception in config_flow (str(e) → "unknown" error key)
- Add exception chaining (from err) to ConfigEntryNotReady raise
- Replace datetime.now() with dt_util.utcnow() for HA timezone convention
- Add defensive raise after retry loop in api_client._make_request
- Remove unused CONF_API_KEY/CONF_NAME imports from const.py
- Restore google-genai dependency in manifest (required for Gemini provider)
This commit is contained in:
SMKRV
2026-03-12 01:26:31 +03:00
parent 998103ce73
commit 63c5c7c51e
5 changed files with 11 additions and 8 deletions
+3 -3
View File
@@ -9,7 +9,6 @@ The HA Text AI integration.
from __future__ import annotations from __future__ import annotations
import logging import logging
from datetime import datetime
from typing import Any, Dict from typing import Any, Dict
import asyncio import asyncio
@@ -22,6 +21,7 @@ from homeassistant.core import HomeAssistant, ServiceCall, SupportsResponse
from homeassistant.exceptions import ConfigEntryNotReady, HomeAssistantError from homeassistant.exceptions import ConfigEntryNotReady, HomeAssistantError
from homeassistant.helpers import config_validation as cv from homeassistant.helpers import config_validation as cv
from homeassistant.helpers import aiohttp_client from homeassistant.helpers import aiohttp_client
from homeassistant.util import dt as dt_util
from .coordinator import HATextAICoordinator from .coordinator import HATextAICoordinator
from .api_client import APIClient from .api_client import APIClient
@@ -140,7 +140,7 @@ async def async_setup(hass: HomeAssistant, config: Dict[str, Any]) -> bool:
"model_used": call.data.get("model", ""), "model_used": call.data.get("model", ""),
"instance": call.data["instance"], "instance": call.data["instance"],
"question": call.data["question"], "question": call.data["question"],
"timestamp": datetime.now().isoformat(), "timestamp": dt_util.utcnow().isoformat(),
"success": False, "success": False,
"error": "Service call failed" "error": "Service call failed"
} }
@@ -266,7 +266,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
endpoint = validate_endpoint(raw_endpoint) endpoint = validate_endpoint(raw_endpoint)
except ValueError as err: except ValueError as err:
_LOGGER.error("Invalid API endpoint %s: %s", raw_endpoint, err) _LOGGER.error("Invalid API endpoint %s: %s", raw_endpoint, err)
raise ConfigEntryNotReady(f"Invalid API endpoint: {err}") raise ConfigEntryNotReady(f"Invalid API endpoint: {err}") from err
# API key can now be updated via options # API key can now be updated via options
api_key = config.get(CONF_API_KEY, entry.data.get(CONF_API_KEY)) api_key = config.get(CONF_API_KEY, entry.data.get(CONF_API_KEY))
instance_name = entry.data.get(CONF_NAME, entry.entry_id) instance_name = entry.data.get(CONF_NAME, entry.entry_id)
@@ -138,6 +138,8 @@ class APIClient:
raise raise
await asyncio.sleep(2 ** attempt) await asyncio.sleep(2 ** attempt)
raise HomeAssistantError("API request failed after all retries")
async def create( async def create(
self, self,
model: str, model: str,
+3 -3
View File
@@ -306,7 +306,7 @@ class HATextAIConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
vol.Required(CONF_API_ENDPOINT, default=input_copy.get(CONF_API_ENDPOINT, get_default_endpoint(self._provider))): str, vol.Required(CONF_API_ENDPOINT, default=input_copy.get(CONF_API_ENDPOINT, get_default_endpoint(self._provider))): str,
# Other fields remain the same # Other fields remain the same
}), }),
errors={"base": str(e)} errors={"base": "unknown"}
) )
# All validation passed, create the entry # All validation passed, create the entry
@@ -378,7 +378,7 @@ class HATextAIConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
if response.status == 401: if response.status == 401:
self._errors["base"] = "invalid_auth" self._errors["base"] = "invalid_auth"
return False return False
elif response.status not in [200, 404]: elif response.status != 200:
self._errors["base"] = "cannot_connect" self._errors["base"] = "cannot_connect"
return False return False
return True return True
@@ -514,7 +514,7 @@ class OptionsFlowHandler(config_entries.OptionsFlow):
if response.status == 401: if response.status == 401:
self._errors["base"] = "invalid_auth" self._errors["base"] = "invalid_auth"
return False return False
elif response.status not in [200, 404]: elif response.status != 200:
self._errors["base"] = "cannot_connect" self._errors["base"] = "cannot_connect"
return False return False
return True return True
+1 -1
View File
@@ -9,7 +9,7 @@ Constants for the HA text AI integration.
import os import os
import json import json
from typing import Final from typing import Final
from homeassistant.const import Platform, CONF_API_KEY, CONF_NAME from homeassistant.const import Platform
import logging import logging
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
+2 -1
View File
@@ -12,7 +12,8 @@
"loggers": ["custom_components.ha_text_ai"], "loggers": ["custom_components.ha_text_ai"],
"requirements": [ "requirements": [
"aiofiles>=23.0.0", "aiofiles>=23.0.0",
"aiohttp>=3.8.0" "aiohttp>=3.8.0",
"google-genai>=1.16.0"
], ],
"single_config_entry": false, "single_config_entry": false,
"version": "2.4.0" "version": "2.4.0"