From 8d775caaaca1502d04ad9f8378df8b3c5d9c6e43 Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Mon, 29 Apr 2019 22:45:53 +0200 Subject: [PATCH] Always print invalid configuration data (#21972) * Always print invalide configuration data * Print offending data as yaml * Revert "Print offending data as yaml" This reverts commit 01721a21a9ff918ed2c8595151ebfe55eb2f7d36. * Do not print sensitive data * Print MQTT topic * Add line break * Review comments * review comments --- homeassistant/components/mqtt/discovery.py | 12 +++- homeassistant/helpers/config_validation.py | 68 +++++++++++++++------- 2 files changed, 59 insertions(+), 21 deletions(-) diff --git a/homeassistant/components/mqtt/discovery.py b/homeassistant/components/mqtt/discovery.py index 4c1427d7e15..d9efd9123e7 100644 --- a/homeassistant/components/mqtt/discovery.py +++ b/homeassistant/components/mqtt/discovery.py @@ -210,6 +210,12 @@ def clear_discovery_hash(hass, discovery_hash): del hass.data[ALREADY_DISCOVERED][discovery_hash] +class MQTTConfig(dict): + """Dummy class to allow adding attributes.""" + + pass + + async def async_start(hass: HomeAssistantType, discovery_topic, hass_config, config_entry=None) -> bool: """Initialize of MQTT Discovery.""" @@ -236,7 +242,7 @@ async def async_start(hass: HomeAssistantType, discovery_topic, hass_config, object_id, payload) return - payload = dict(payload) + payload = MQTTConfig(payload) for key in list(payload.keys()): abbreviated_key = key @@ -264,6 +270,10 @@ async def async_start(hass: HomeAssistantType, discovery_topic, hass_config, discovery_hash = (component, discovery_id) if payload: + # Attach MQTT topic to the payload, used for debug prints + setattr(payload, '__configuration_source__', + "MQTT (topic: '{}')".format(topic)) + if CONF_PLATFORM in payload and 'schema' not in payload: platform = payload[CONF_PLATFORM] if (component in DEPRECATED_PLATFORM_TO_SCHEMA and diff --git a/homeassistant/helpers/config_validation.py b/homeassistant/helpers/config_validation.py index a954d01856e..1f139704e5f 100644 --- a/homeassistant/helpers/config_validation.py +++ b/homeassistant/helpers/config_validation.py @@ -1,5 +1,6 @@ """Helpers for config validation using voluptuous.""" import inspect +import json import logging import os import re @@ -15,11 +16,11 @@ from pkg_resources import parse_version import homeassistant.util.dt as dt_util from homeassistant.const import ( - CONF_PLATFORM, CONF_SCAN_INTERVAL, TEMP_CELSIUS, TEMP_FAHRENHEIT, - CONF_ALIAS, CONF_ENTITY_ID, CONF_VALUE_TEMPLATE, WEEKDAYS, - CONF_CONDITION, CONF_BELOW, CONF_ABOVE, CONF_TIMEOUT, SUN_EVENT_SUNSET, - SUN_EVENT_SUNRISE, CONF_UNIT_SYSTEM_IMPERIAL, CONF_UNIT_SYSTEM_METRIC, - ENTITY_MATCH_ALL, CONF_ENTITY_NAMESPACE, __version__) + CONF_ABOVE, CONF_ALIAS, CONF_BELOW, CONF_CONDITION, CONF_ENTITY_ID, + CONF_ENTITY_NAMESPACE, CONF_NAME, CONF_PLATFORM, CONF_SCAN_INTERVAL, + CONF_UNIT_SYSTEM_IMPERIAL, CONF_UNIT_SYSTEM_METRIC, CONF_VALUE_TEMPLATE, + CONF_TIMEOUT, ENTITY_MATCH_ALL, SUN_EVENT_SUNRISE, SUN_EVENT_SUNSET, + TEMP_CELSIUS, TEMP_FAHRENHEIT, WEEKDAYS, __version__) from homeassistant.core import valid_entity_id, split_entity_id from homeassistant.exceptions import TemplateError from homeassistant.helpers import template as template_helper @@ -677,26 +678,53 @@ class HASchema(vol.Schema): self.extra = vol.PREVENT_EXTRA # This is a legacy config, print warning - extra_key_errs = [err for err in orig_err.errors + extra_key_errs = [err.path[-1] for err in orig_err.errors if err.error_message == 'extra keys not allowed'] - if extra_key_errs: - msg = "Your configuration contains extra keys " \ - "that the platform does not support.\n" \ - "Please remove " - submsg = ', '.join('[{}]'.format(err.path[-1]) for err in - extra_key_errs) - submsg += '. ' - if hasattr(data, '__config_file__'): - submsg += " (See {}, line {}). ".format( - data.__config_file__, data.__line__) - msg += submsg - logging.getLogger(__name__).warning(msg) - INVALID_EXTRA_KEYS_FOUND.append(submsg) - else: + + if not extra_key_errs: # This should not happen (all errors should be extra key # errors). Let's raise the original error anyway. raise orig_err + WHITELIST = [ + re.compile(CONF_NAME), + re.compile(CONF_PLATFORM), + re.compile('.*_topic'), + ] + + msg = "Your configuration contains extra keys " \ + "that the platform does not support.\n" \ + "Please remove " + submsg = ', '.join('[{}]'.format(err) for err in + extra_key_errs) + submsg += '. ' + + # Add file+line information, if available + if hasattr(data, '__config_file__'): + submsg += " (See {}, line {}). ".format( + data.__config_file__, data.__line__) + + # Add configuration source information, if available + if hasattr(data, '__configuration_source__'): + submsg += "\nConfiguration source: {}. ".format( + data.__configuration_source__) + redacted_data = {} + + # Print configuration causing the error, but filter any potentially + # sensitive data + for k, v in data.items(): + if (any(regex.match(k) for regex in WHITELIST) or + k in extra_key_errs): + redacted_data[k] = v + else: + redacted_data[k] = '' + submsg += "\nOffending data: {}".format( + json.dumps(redacted_data)) + + msg += submsg + logging.getLogger(__name__).warning(msg) + INVALID_EXTRA_KEYS_FOUND.append(submsg) + # Return legacy validated config return validated