mirror of
https://github.com/home-assistant/core.git
synced 2026-09-24 23:41:48 -05:00
Fix Teslemetry energy-site setup crash on encrypted RSA key (#181348)
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
co-authored by
Copilot Autofix powered by AI
parent
0cb25fe472
commit
81e0a244f8
@@ -333,9 +333,13 @@ async def _async_get_rsa_key_pem(hass: HomeAssistant) -> bytes:
|
||||
pem: bytes | None = hass.data.get(RSA_PARENT_KEY)
|
||||
if pem is None:
|
||||
path = hass.config.path(POWERWALL_KEY_FILE)
|
||||
await Teslemetry(
|
||||
session=async_get_clientsession(hass), access_token=""
|
||||
).get_rsa_private_key(path)
|
||||
try:
|
||||
await Teslemetry(
|
||||
session=async_get_clientsession(hass), access_token=""
|
||||
).get_rsa_private_key(path)
|
||||
except TypeError as err:
|
||||
# An encrypted PEM surfaces as TypeError from the cryptography loader.
|
||||
raise ValueError("RSA private key file is encrypted") from err
|
||||
pem = await hass.async_add_executor_job(Path(path).read_bytes)
|
||||
hass.data[RSA_PARENT_KEY] = pem
|
||||
return pem
|
||||
|
||||
@@ -273,7 +273,11 @@ class EnergySiteSubentryFlowHandler(ConfigSubentryFlow):
|
||||
session=async_get_clientsession(self.hass), access_token=""
|
||||
)
|
||||
try:
|
||||
await keyholder.get_rsa_private_key(path)
|
||||
try:
|
||||
await keyholder.get_rsa_private_key(path)
|
||||
except TypeError as err:
|
||||
# An encrypted PEM surfaces as TypeError from the cryptography loader.
|
||||
raise ValueError("RSA private key file is encrypted") from err
|
||||
self._key_pem = await self.hass.async_add_executor_job(
|
||||
Path(path).read_bytes
|
||||
)
|
||||
|
||||
@@ -1378,6 +1378,12 @@ async def test_pair_step_second_lookup_errors(
|
||||
ValueError,
|
||||
id="key_read_valueerror",
|
||||
),
|
||||
# An encrypted key PEM surfaces as TypeError from the cryptography loader.
|
||||
pytest.param(
|
||||
"homeassistant.components.teslemetry.config_flow.Teslemetry.get_rsa_private_key",
|
||||
TypeError,
|
||||
id="key_fetch_typeerror",
|
||||
),
|
||||
],
|
||||
)
|
||||
async def test_rsa_key_load_failure_aborts(
|
||||
|
||||
@@ -1418,6 +1418,65 @@ async def test_local_control_failure_falls_back_to_cloud(
|
||||
)
|
||||
|
||||
|
||||
async def test_local_control_encrypted_key_falls_back_to_cloud(
|
||||
hass: HomeAssistant,
|
||||
caplog: pytest.LogCaptureFixture,
|
||||
) -> None:
|
||||
"""Fall back to cloud control when RSA key loading reports an encrypted PEM."""
|
||||
entry = _entry_with_powerwall()
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
with (
|
||||
patch(
|
||||
"homeassistant.components.teslemetry.Teslemetry.get_rsa_private_key",
|
||||
side_effect=TypeError(
|
||||
"Password was not given but private key is encrypted"
|
||||
),
|
||||
),
|
||||
patch("homeassistant.components.teslemetry.PLATFORMS", []),
|
||||
caplog.at_level(logging.WARNING),
|
||||
):
|
||||
await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert entry.state is ConfigEntryState.LOADED
|
||||
energysite = entry.runtime_data.energysites[0]
|
||||
assert isinstance(energysite.api, EnergySite)
|
||||
assert not isinstance(energysite.api, EnergySiteRouter)
|
||||
assert energysite.can_local_control
|
||||
assert "falling back to cloud control" in caplog.text
|
||||
|
||||
|
||||
async def test_local_control_unexpected_typeerror_is_not_swallowed(
|
||||
hass: HomeAssistant,
|
||||
) -> None:
|
||||
"""A TypeError outside the key load is a real bug and must not degrade silently.
|
||||
|
||||
``_LOCAL_CONTROL_ERRORS`` deliberately excludes TypeError: only the key
|
||||
loader's encrypted-PEM TypeError is converted to ValueError. A TypeError
|
||||
from anywhere else in the resolve path (here, client construction) must
|
||||
fail setup rather than silently falling back to cloud control.
|
||||
"""
|
||||
entry = _entry_with_powerwall()
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
with (
|
||||
patch(
|
||||
"homeassistant.components.teslemetry._async_get_rsa_key_pem",
|
||||
return_value=_TEST_RSA_KEY_PEM,
|
||||
),
|
||||
patch(
|
||||
"homeassistant.components.teslemetry.PowerwallClient",
|
||||
side_effect=TypeError("unexpected argument"),
|
||||
),
|
||||
patch("homeassistant.components.teslemetry.PLATFORMS", []),
|
||||
):
|
||||
await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert entry.state is ConfigEntryState.SETUP_ERROR
|
||||
|
||||
|
||||
async def test_get_rsa_key_pem_generates_and_caches(hass: HomeAssistant) -> None:
|
||||
"""The RSA key is generated/read once, then served from the hass.data cache."""
|
||||
with (
|
||||
|
||||
Reference in New Issue
Block a user