1
0
mirror of https://github.com/home-assistant/core.git synced 2026-05-08 17:49:37 +01:00

Restrict homematic.set_install_mode service to admins (#169203)

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: balloob <1444314+balloob@users.noreply.github.com>
This commit is contained in:
Paulus Schoutsen
2026-04-28 12:00:13 -04:00
committed by GitHub
parent eaf72106f8
commit de4e1c444e
2 changed files with 72 additions and 3 deletions
@@ -26,7 +26,9 @@ from homeassistant.const import (
)
from homeassistant.core import HomeAssistant, ServiceCall
from homeassistant.helpers import config_validation as cv, discovery
from homeassistant.helpers.service import async_register_admin_service
from homeassistant.helpers.typing import ConfigType
from homeassistant.util.async_ import run_callback_threadsafe
from .const import (
ATTR_ADDRESS,
@@ -381,12 +383,15 @@ def setup(hass: HomeAssistant, config: ConfigType) -> bool:
homematic.setInstallMode(interface, t=time, mode=mode, address=address)
hass.services.register(
run_callback_threadsafe(
hass.loop,
async_register_admin_service,
hass,
DOMAIN,
SERVICE_SET_INSTALL_MODE,
_service_handle_install_mode,
schema=SCHEMA_SERVICE_SET_INSTALL_MODE,
)
SCHEMA_SERVICE_SET_INSTALL_MODE,
).result()
def _service_put_paramset(service: ServiceCall) -> None:
"""Service to call the putParamset method on a HomeMatic connection."""
+64
View File
@@ -0,0 +1,64 @@
"""Tests for the Homematic integration."""
from unittest.mock import MagicMock, patch
import pytest
from homeassistant.components.homematic.const import (
ATTR_INTERFACE,
DATA_HOMEMATIC,
SERVICE_SET_INSTALL_MODE,
)
from homeassistant.core import Context, HomeAssistant
from homeassistant.exceptions import Unauthorized
from homeassistant.setup import async_setup_component
from tests.common import MockUser
DOMAIN = "homematic"
BASE_CONFIG = {DOMAIN: {"hosts": {"ccu2": {"host": "127.0.0.1"}}}}
@pytest.fixture
async def setup_homematic(hass: HomeAssistant) -> None:
"""Set up the homematic component."""
with patch(
"homeassistant.components.homematic.HMConnection",
return_value=MagicMock(),
):
await async_setup_component(hass, DOMAIN, BASE_CONFIG)
await hass.async_block_till_done()
async def test_set_install_mode_admin_allowed(
hass: HomeAssistant,
setup_homematic: None,
hass_admin_user: MockUser,
) -> None:
"""Test that admin users can call set_install_mode."""
await hass.services.async_call(
DOMAIN,
SERVICE_SET_INSTALL_MODE,
{ATTR_INTERFACE: "ccu2"},
blocking=True,
context=Context(user_id=hass_admin_user.id),
)
hass.data[DATA_HOMEMATIC].setInstallMode.assert_called_once_with(
"ccu2", t=60, mode=1, address=None
)
async def test_set_install_mode_non_admin_rejected(
hass: HomeAssistant,
setup_homematic: None,
hass_read_only_user: MockUser,
) -> None:
"""Test that non-admin users cannot call set_install_mode."""
with pytest.raises(Unauthorized):
await hass.services.async_call(
DOMAIN,
SERVICE_SET_INSTALL_MODE,
{ATTR_INTERFACE: "ccu2"},
blocking=True,
context=Context(user_id=hass_read_only_user.id),
)