Require admin for the mqtt.publish and mqtt.dump actions (#182045)

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: frenck <195327+frenck@users.noreply.github.com>
This commit is contained in:
Franck Nijhof
2026-09-14 07:48:43 +02:00
committed by GitHub
co-authored by copilot-swe-agent[bot] frenck
parent 7ee22de22c
commit ce436dda45
2 changed files with 82 additions and 4 deletions
+4 -3
View File
@@ -370,8 +370,8 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
message_expiry_interval=message_expiry_interval,
)
hass.services.async_register(
DOMAIN, SERVICE_PUBLISH, async_publish_service, schema=MQTT_PUBLISH_SCHEMA
async_register_admin_service(
hass, DOMAIN, SERVICE_PUBLISH, async_publish_service, MQTT_PUBLISH_SCHEMA
)
async def async_dump_service(call: ServiceCall) -> None:
@@ -395,7 +395,8 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
ev.async_call_later(hass, call.data["duration"], finish_dump)
hass.services.async_register(
async_register_admin_service(
hass,
DOMAIN,
SERVICE_DUMP,
async_dump_service,
+78 -1
View File
@@ -37,7 +37,12 @@ from homeassistant.const import (
STATE_UNKNOWN,
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
from homeassistant.exceptions import (
HomeAssistantError,
ServiceValidationError,
Unauthorized,
UnknownUser,
)
from homeassistant.helpers import (
device_registry as dr,
entity_registry as er,
@@ -56,6 +61,7 @@ from tests.common import (
MockEntity,
MockEntityPlatform,
MockMqttReasonCode,
MockUser,
async_capture_events,
async_fire_mqtt_message,
async_fire_time_changed,
@@ -1113,6 +1119,77 @@ async def test_dump_service(
assert writes[0][1][0] == ["bla/1,test1\n", "bla/2,test2\n"]
ADMIN_SERVICE_CALLS = [
pytest.param(
mqtt.SERVICE_PUBLISH,
{mqtt.ATTR_TOPIC: "test/topic", mqtt.ATTR_PAYLOAD: "payload"},
id="publish",
),
pytest.param(mqtt.SERVICE_DUMP, {"topic": "bla/#", "duration": 3}, id="dump"),
]
@pytest.mark.parametrize(("service", "service_data"), ADMIN_SERVICE_CALLS)
async def test_admin_service_as_admin(
hass: HomeAssistant,
mqtt_mock_entry: MqttMockHAClientGenerator,
hass_admin_user: MockUser,
service: str,
service_data: dict[str, Any],
) -> None:
"""Test an admin user can call the action."""
await mqtt_mock_entry()
await hass.services.async_call(
mqtt.DOMAIN,
service,
service_data,
blocking=True,
context=ha.Context(user_id=hass_admin_user.id),
)
@pytest.mark.parametrize(("service", "service_data"), ADMIN_SERVICE_CALLS)
async def test_admin_service_as_non_admin(
hass: HomeAssistant,
mqtt_mock_entry: MqttMockHAClientGenerator,
hass_read_only_user: MockUser,
service: str,
service_data: dict[str, Any],
) -> None:
"""Test a non-admin user cannot call the action."""
await mqtt_mock_entry()
with pytest.raises(Unauthorized):
await hass.services.async_call(
mqtt.DOMAIN,
service,
service_data,
blocking=True,
context=ha.Context(user_id=hass_read_only_user.id),
)
@pytest.mark.parametrize(("service", "service_data"), ADMIN_SERVICE_CALLS)
async def test_admin_service_as_unknown_user(
hass: HomeAssistant,
mqtt_mock_entry: MqttMockHAClientGenerator,
service: str,
service_data: dict[str, Any],
) -> None:
"""Test a user that no longer exists cannot call the action."""
await mqtt_mock_entry()
with pytest.raises(UnknownUser):
await hass.services.async_call(
mqtt.DOMAIN,
service,
service_data,
blocking=True,
context=ha.Context(user_id="i-am-not-a-user"),
)
async def test_mqtt_ws_remove_discovered_device(
hass: HomeAssistant,
device_registry: dr.DeviceRegistry,