From f29ee24b727430348a90945c04404e9542bb385f Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sat, 18 Feb 2017 11:31:37 -0800 Subject: [PATCH] Do not allow config dependency (#6036) * Do not allow config dependency * Prevent config in discovery * Migrate to blacklist --- homeassistant/bootstrap.py | 10 ++++++++++ homeassistant/helpers/discovery.py | 10 ++++++++++ homeassistant/loader.py | 2 ++ tests/helpers/test_discovery.py | 18 ++++++++++++++++++ tests/test_bootstrap.py | 27 +++++++++++++++++++++++++++ 5 files changed, 67 insertions(+) diff --git a/homeassistant/bootstrap.py b/homeassistant/bootstrap.py index e2210f66662..c6709aea7cc 100644 --- a/homeassistant/bootstrap.py +++ b/homeassistant/bootstrap.py @@ -299,6 +299,10 @@ def async_prepare_setup_platform(hass: core.HomeAssistant, config, domain: str, # Load dependencies for component in getattr(platform, 'DEPENDENCIES', []): + if component in loader.DEPENDENCY_BLACKLIST: + raise HomeAssistantError( + '{} is not allowed to be a dependency.'.format(component)) + res = yield from async_setup_component(hass, component, config) if not res: _LOGGER.error( @@ -430,7 +434,13 @@ def async_from_config_dict(config: Dict[str, Any], service.HASS = hass # Setup the components + dependency_blacklist = loader.DEPENDENCY_BLACKLIST - set(components) + for domain in loader.load_order_components(components): + if domain in dependency_blacklist: + raise HomeAssistantError( + '{} is not allowed to be a dependency'.format(domain)) + yield from _async_setup_component(hass, domain, config) setup_lock.release() diff --git a/homeassistant/helpers/discovery.py b/homeassistant/helpers/discovery.py index de16a0b907d..db17b8926c1 100644 --- a/homeassistant/helpers/discovery.py +++ b/homeassistant/helpers/discovery.py @@ -10,6 +10,8 @@ import asyncio from homeassistant import bootstrap, core from homeassistant.const import ( ATTR_DISCOVERED, ATTR_SERVICE, EVENT_PLATFORM_DISCOVERED) +from homeassistant.exceptions import HomeAssistantError +from homeassistant.loader import DEPENDENCY_BLACKLIST from homeassistant.util.async import run_callback_threadsafe EVENT_LOAD_PLATFORM = 'load_platform.{}' @@ -56,6 +58,10 @@ def discover(hass, service, discovered=None, component=None, hass_config=None): def async_discover(hass, service, discovered=None, component=None, hass_config=None): """Fire discovery event. Can ensure a component is loaded.""" + if component in DEPENDENCY_BLACKLIST: + raise HomeAssistantError( + 'Cannot discover the {} component.'.format(component)) + if component is not None and component not in hass.config.components: did_lock = False setup_lock = hass.data.get('setup_lock') @@ -150,6 +156,10 @@ def async_load_platform(hass, component, platform, discovered=None, This method is a coroutine. """ + if component in DEPENDENCY_BLACKLIST: + raise HomeAssistantError( + 'Cannot discover the {} component.'.format(component)) + did_lock = False setup_lock = hass.data.get('setup_lock') if setup_lock and setup_lock.locked(): diff --git a/homeassistant/loader.py b/homeassistant/loader.py index 77b4da00f09..243de03ec92 100644 --- a/homeassistant/loader.py +++ b/homeassistant/loader.py @@ -30,6 +30,8 @@ if False: PREPARED = False +DEPENDENCY_BLACKLIST = set(('config',)) + # List of available components AVAILABLE_COMPONENTS = [] # type: List[str] diff --git a/tests/helpers/test_discovery.py b/tests/helpers/test_discovery.py index 628621e3c6e..b2f60cd0a2e 100644 --- a/tests/helpers/test_discovery.py +++ b/tests/helpers/test_discovery.py @@ -1,9 +1,13 @@ """Test discovery helpers.""" +import asyncio from collections import OrderedDict from unittest.mock import patch +import pytest + from homeassistant import loader, bootstrap from homeassistant.core import callback +from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers import discovery from homeassistant.util.async import run_coroutine_threadsafe @@ -197,3 +201,17 @@ class TestHelpersDiscovery: # test_component will only be setup once assert len(component_calls) == 1 + + +@asyncio.coroutine +def test_load_platform_forbids_config(): + """Test you cannot setup config component with load_platform.""" + with pytest.raises(HomeAssistantError): + yield from discovery.async_load_platform(None, 'config', 'zwave') + + +@asyncio.coroutine +def test_discover_forbids_config(): + """Test you cannot setup config component with load_platform.""" + with pytest.raises(HomeAssistantError): + yield from discovery.async_discover(None, None, None, 'config') diff --git a/tests/test_bootstrap.py b/tests/test_bootstrap.py index 565265b3e01..410f1636a88 100644 --- a/tests/test_bootstrap.py +++ b/tests/test_bootstrap.py @@ -1,15 +1,18 @@ """Test the bootstrapping.""" # pylint: disable=protected-access +import asyncio import os from unittest import mock import threading import logging import voluptuous as vol +import pytest from homeassistant.core import callback from homeassistant.const import EVENT_HOMEASSISTANT_START import homeassistant.config as config_util +from homeassistant.exceptions import HomeAssistantError from homeassistant import bootstrap, loader import homeassistant.util.dt as dt_util from homeassistant.helpers.config_validation import PLATFORM_SCHEMA @@ -440,3 +443,27 @@ class TestBootstrap: self.hass.start() assert call_order == [1, 1, 2] + + +@asyncio.coroutine +def test_component_cannot_depend_config(hass): + """Test config is not allowed to be a dependency.""" + loader.set_component( + 'test_component1', + MockModule('test_component1', dependencies=['config'])) + + with pytest.raises(HomeAssistantError): + yield from bootstrap.async_from_config_dict( + {'test_component1': None}, hass) + + +@asyncio.coroutine +def test_platform_cannot_depend_config(): + """Test config is not allowed to be a dependency.""" + loader.set_component( + 'test_component1.test', + MockPlatform('whatever', dependencies=['config'])) + + with pytest.raises(HomeAssistantError): + yield from bootstrap.async_prepare_setup_platform( + mock.MagicMock(), {}, 'test_component1', 'test')