From 4ceba01ab73f96a5d980f3cc032e74776c8fafa7 Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Tue, 18 Jul 2023 12:10:40 +0200 Subject: [PATCH] Prevent creating scripts which override script services (#96828) --- homeassistant/components/script/config.py | 23 ++++++++++++++- tests/components/config/test_script.py | 34 +++++++++++++++++++++++ tests/components/script/test_init.py | 9 ++++++ 3 files changed, 65 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/script/config.py b/homeassistant/components/script/config.py index 10c7f08484b..c11bb37294f 100644 --- a/homeassistant/components/script/config.py +++ b/homeassistant/components/script/config.py @@ -23,6 +23,10 @@ from homeassistant.const import ( CONF_SELECTOR, CONF_SEQUENCE, CONF_VARIABLES, + SERVICE_RELOAD, + SERVICE_TOGGLE, + SERVICE_TURN_OFF, + SERVICE_TURN_ON, ) from homeassistant.core import HomeAssistant from homeassistant.exceptions import HomeAssistantError @@ -57,6 +61,23 @@ _MINIMAL_SCRIPT_ENTITY_SCHEMA = vol.Schema( extra=vol.ALLOW_EXTRA, ) +_INVALID_OBJECT_IDS = { + SERVICE_RELOAD, + SERVICE_TURN_OFF, + SERVICE_TURN_ON, + SERVICE_TOGGLE, +} + +_SCRIPT_OBJECT_ID_SCHEMA = vol.All( + cv.slug, + vol.NotIn( + _INVALID_OBJECT_IDS, + ( + "A script's object_id must not be one of " + f"{', '.join(sorted(_INVALID_OBJECT_IDS))}" + ), + ), +) SCRIPT_ENTITY_SCHEMA = make_script_schema( { @@ -170,7 +191,7 @@ async def _async_validate_config_item( script_name = f"Script with alias '{config[CONF_ALIAS]}'" try: - cv.slug(object_id) + _SCRIPT_OBJECT_ID_SCHEMA(object_id) except vol.Invalid as err: _log_invalid_script(err, script_name, "has invalid object id", object_id) raise diff --git a/tests/components/config/test_script.py b/tests/components/config/test_script.py index 34f807e3cc5..86ea2cf9e7f 100644 --- a/tests/components/config/test_script.py +++ b/tests/components/config/test_script.py @@ -86,6 +86,40 @@ async def test_update_script_config( assert new_data["moon"] == {"alias": "Moon updated", "sequence": []} +@pytest.mark.parametrize("script_config", ({},)) +async def test_invalid_object_id( + hass: HomeAssistant, hass_client: ClientSessionGenerator, hass_config_store +) -> None: + """Test creating a script with an invalid object_id.""" + with patch.object(config, "SECTIONS", ["script"]): + await async_setup_component(hass, "config", {}) + + assert sorted(hass.states.async_entity_ids("script")) == [] + + client = await hass_client() + + hass_config_store["scripts.yaml"] = {} + + resp = await client.post( + "/api/config/script/config/turn_on", + data=json.dumps({"alias": "Turn on", "sequence": []}), + ) + await hass.async_block_till_done() + assert sorted(hass.states.async_entity_ids("script")) == [] + + assert resp.status == HTTPStatus.BAD_REQUEST + result = await resp.json() + assert result == { + "message": ( + "Message malformed: A script's object_id must not be one of " + "reload, toggle, turn_off, turn_on" + ) + } + + new_data = hass_config_store["scripts.yaml"] + assert new_data == {} + + @pytest.mark.parametrize("script_config", ({},)) @pytest.mark.parametrize( ("updated_config", "validation_error"), diff --git a/tests/components/script/test_init.py b/tests/components/script/test_init.py index cc41b6c404c..cddefc8d3dc 100644 --- a/tests/components/script/test_init.py +++ b/tests/components/script/test_init.py @@ -196,6 +196,15 @@ async def test_setup_with_invalid_configs( "has invalid object id", "invalid slug Bad Script", ), + ( + "turn_on", + {}, + "has invalid object id", + ( + "A script's object_id must not be one of " + "reload, toggle, turn_off, turn_on. Got 'turn_on'" + ), + ), ), ) async def test_bad_config_validation_critical(