From c825c40c4d2b3d8708e77475b545553b1fc545b7 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Mon, 1 Oct 2018 19:07:48 +0200 Subject: [PATCH 1/5] Bump version 134 --- hassio/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hassio/const.py b/hassio/const.py index a9733cf86..cfe60cab6 100644 --- a/hassio/const.py +++ b/hassio/const.py @@ -2,7 +2,7 @@ from pathlib import Path from ipaddress import ip_network -HASSIO_VERSION = '133' +HASSIO_VERSION = '134' URL_HASSIO_ADDONS = "https://github.com/home-assistant/hassio-addons" URL_HASSIO_VERSION = \ From 33b615e40de2636f6314cce9031d4b8668f26a73 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Fri, 5 Oct 2018 13:48:29 +0200 Subject: [PATCH 2/5] Fix manager access to `/addons` (#738) --- hassio/api/security.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hassio/api/security.py b/hassio/api/security.py index 2377af769..c0239e05d 100644 --- a/hassio/api/security.py +++ b/hassio/api/security.py @@ -59,7 +59,7 @@ ADDONS_ROLE_ACCESS = { r"|/hardware/.+" r"|/hassos/.+" r"|/supervisor/.+" - r"|/addons/[^/]+/(?!security).+" + r"|/addons(?:/[^/]+/(?!security).+)?" r"|/snapshots.*" r")$" ), From 79dca1608e0583e399e575868c5d135fd78aac88 Mon Sep 17 00:00:00 2001 From: Jorim Tielemans Date: Sun, 7 Oct 2018 19:16:29 +0200 Subject: [PATCH 3/5] Fix machine 'odroid-c2' (#744) Odroid-cu2 does not exist AFAIK, it needs to be c2. --- hassio/addons/validate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hassio/addons/validate.py b/hassio/addons/validate.py index 0e25e365f..110e948f5 100644 --- a/hassio/addons/validate.py +++ b/hassio/addons/validate.py @@ -61,7 +61,7 @@ ARCH_ALL = [ MACHINE_ALL = [ 'intel-nuc', 'qemux86', 'qemux86-64', 'qemuarm', 'qemuarm-64', 'raspberrypi', 'raspberrypi2', 'raspberrypi3', 'raspberrypi3-64', - 'odroid-cu2', 'odroid-xu', + 'odroid-c2', 'odroid-xu', ] STARTUP_ALL = [ From da425a0530c79a70298e179d662e2559c7e9bd91 Mon Sep 17 00:00:00 2001 From: Franck Nijhof Date: Sun, 7 Oct 2018 19:17:06 +0200 Subject: [PATCH 4/5] Adds support for privilege DAC_READ_SEARCH (#743) * Adds support for privilege DAC_READ_SEARCH * :ambulance: Fixes security rating regarding privileges --- hassio/addons/utils.py | 8 +++++--- hassio/addons/validate.py | 3 ++- hassio/const.py | 1 + 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/hassio/addons/utils.py b/hassio/addons/utils.py index ac272ba46..47a3fd26f 100644 --- a/hassio/addons/utils.py +++ b/hassio/addons/utils.py @@ -7,7 +7,7 @@ import re from ..const import ( SECURITY_DISABLE, SECURITY_PROFILE, PRIVILEGED_NET_ADMIN, PRIVILEGED_SYS_ADMIN, PRIVILEGED_SYS_RAWIO, PRIVILEGED_SYS_PTRACE, - ROLE_ADMIN, ROLE_MANAGER) + PRIVILEGED_DAC_READ_SEARCH, ROLE_ADMIN, ROLE_MANAGER) RE_SHA1 = re.compile(r"[a-f0-9]{8}") @@ -29,8 +29,10 @@ def rating_security(addon): rating += 1 # Privileged options - if addon.privileged in (PRIVILEGED_NET_ADMIN, PRIVILEGED_SYS_ADMIN, - PRIVILEGED_SYS_RAWIO, PRIVILEGED_SYS_PTRACE): + if any(privilege in addon.privileged + for privilege in (PRIVILEGED_NET_ADMIN, PRIVILEGED_SYS_ADMIN, + PRIVILEGED_SYS_RAWIO, PRIVILEGED_SYS_PTRACE, + PRIVILEGED_DAC_READ_SEARCH)): rating += -1 # API Hass.io role diff --git a/hassio/addons/validate.py b/hassio/addons/validate.py index 110e948f5..a377b7958 100644 --- a/hassio/addons/validate.py +++ b/hassio/addons/validate.py @@ -23,7 +23,7 @@ from ..const import ( ATTR_MACHINE, PRIVILEGED_NET_ADMIN, PRIVILEGED_SYS_ADMIN, PRIVILEGED_SYS_RAWIO, PRIVILEGED_IPC_LOCK, PRIVILEGED_SYS_TIME, PRIVILEGED_SYS_NICE, - PRIVILEGED_SYS_RESOURCE, PRIVILEGED_SYS_PTRACE, + PRIVILEGED_SYS_RESOURCE, PRIVILEGED_SYS_PTRACE, PRIVILEGED_DAC_READ_SEARCH, ROLE_DEFAULT, ROLE_HOMEASSISTANT, ROLE_MANAGER, ROLE_ADMIN) from ..validate import NETWORK_PORT, DOCKER_PORTS, ALSA_DEVICE, UUID_MATCH from ..services.validate import DISCOVERY_SERVICES @@ -78,6 +78,7 @@ PRIVILEGED_ALL = [ PRIVILEGED_SYS_NICE, PRIVILEGED_SYS_RESOURCE, PRIVILEGED_SYS_PTRACE, + PRIVILEGED_DAC_READ_SEARCH, ] ROLE_ALL = [ diff --git a/hassio/const.py b/hassio/const.py index cfe60cab6..3db24b673 100644 --- a/hassio/const.py +++ b/hassio/const.py @@ -243,6 +243,7 @@ PRIVILEGED_SYS_TIME = 'SYS_TIME' PRIVILEGED_SYS_NICE = 'SYS_NICE' PRIVILEGED_SYS_RESOURCE = 'SYS_RESOURCE' PRIVILEGED_SYS_PTRACE = 'SYS_PTRACE' +PRIVILEGED_DAC_READ_SEARCH = 'DAC_READ_SEARCH' FEATURES_SHUTDOWN = 'shutdown' FEATURES_REBOOT = 'reboot' From 23f28b38e9c7e9d259eacd6225581bdfef0e665b Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Sun, 7 Oct 2018 23:50:18 +0200 Subject: [PATCH 5/5] small code cleanups (#740) * small code cleanups * Update __init__.py * Update homeassistant.py * Update __init__.py * Update homeassistant.py * Update homeassistant.py * Update __init__.py * fix list * Fix api call --- hassio/addons/addon.py | 2 +- hassio/api/addons.py | 21 +++++++++++---------- hassio/api/homeassistant.py | 2 -- hassio/docker/__init__.py | 15 ++++++++++----- hassio/homeassistant.py | 12 ++++++++++-- 5 files changed, 32 insertions(+), 20 deletions(-) diff --git a/hassio/addons/addon.py b/hassio/addons/addon.py index c9f81d547..2efbad2c9 100644 --- a/hassio/addons/addon.py +++ b/hassio/addons/addon.py @@ -355,7 +355,7 @@ class Addon(CoreSysAttributes): @property def privileged(self): """Return list of privilege.""" - return self._mesh.get(ATTR_PRIVILEGED) + return self._mesh.get(ATTR_PRIVILEGED, []) @property def apparmor(self): diff --git a/hassio/api/addons.py b/hassio/api/addons.py index 4b2ae3a21..2e7994ef0 100644 --- a/hassio/api/addons.py +++ b/hassio/api/addons.py @@ -24,6 +24,7 @@ from ..const import ( CONTENT_TYPE_PNG, CONTENT_TYPE_BINARY, CONTENT_TYPE_TEXT, REQUEST_FROM) from ..coresys import CoreSysAttributes from ..validate import DOCKER_PORTS, ALSA_DEVICE +from ..exceptions import APIError _LOGGER = logging.getLogger(__name__) @@ -59,10 +60,10 @@ class APIAddons(CoreSysAttributes): addon = self.sys_addons.get(addon_slug) if not addon: - raise RuntimeError("Addon does not exist") + raise APIError("Addon does not exist") if check_installed and not addon.is_installed: - raise RuntimeError("Addon is not installed") + raise APIError("Addon is not installed") return addon @@ -206,7 +207,7 @@ class APIAddons(CoreSysAttributes): stats = await addon.stats() if not stats: - raise RuntimeError("No stats available") + raise APIError("No stats available") return { ATTR_CPU_PERCENT: stats.cpu_percent, @@ -240,7 +241,7 @@ class APIAddons(CoreSysAttributes): try: addon.schema(options) except vol.Invalid as ex: - raise RuntimeError(humanize_error(options, ex)) from None + raise APIError(humanize_error(options, ex)) from None return asyncio.shield(addon.start()) @@ -256,7 +257,7 @@ class APIAddons(CoreSysAttributes): addon = self._extract_addon(request) if addon.last_version == addon.version_installed: - raise RuntimeError("No update available!") + raise APIError("No update available!") return asyncio.shield(addon.update()) @@ -271,7 +272,7 @@ class APIAddons(CoreSysAttributes): """Rebuild local build add-on.""" addon = self._extract_addon(request) if not addon.need_build: - raise RuntimeError("Only local build addons are supported") + raise APIError("Only local build addons are supported") return asyncio.shield(addon.rebuild()) @@ -286,7 +287,7 @@ class APIAddons(CoreSysAttributes): """Return icon from add-on.""" addon = self._extract_addon(request, check_installed=False) if not addon.with_icon: - raise RuntimeError("No icon found!") + raise APIError("No icon found!") with addon.path_icon.open('rb') as png: return png.read() @@ -296,7 +297,7 @@ class APIAddons(CoreSysAttributes): """Return logo from add-on.""" addon = self._extract_addon(request, check_installed=False) if not addon.with_logo: - raise RuntimeError("No logo found!") + raise APIError("No logo found!") with addon.path_logo.open('rb') as png: return png.read() @@ -306,7 +307,7 @@ class APIAddons(CoreSysAttributes): """Return changelog from add-on.""" addon = self._extract_addon(request, check_installed=False) if not addon.with_changelog: - raise RuntimeError("No changelog found!") + raise APIError("No changelog found!") with addon.path_changelog.open('r') as changelog: return changelog.read() @@ -316,7 +317,7 @@ class APIAddons(CoreSysAttributes): """Write to stdin of add-on.""" addon = self._extract_addon(request) if not addon.with_stdin: - raise RuntimeError("STDIN not supported by add-on") + raise APIError("STDIN not supported by add-on") data = await request.read() return await asyncio.shield(addon.write_stdin(data)) diff --git a/hassio/api/homeassistant.py b/hassio/api/homeassistant.py index 78d92b3f7..88dd89b0a 100644 --- a/hassio/api/homeassistant.py +++ b/hassio/api/homeassistant.py @@ -141,5 +141,3 @@ class APIHomeAssistant(CoreSysAttributes): result = await self.sys_homeassistant.check_config() if not result.valid: raise APIError(result.log) - - return True diff --git a/hassio/docker/__init__.py b/hassio/docker/__init__.py index 378a648f6..562615265 100644 --- a/hassio/docker/__init__.py +++ b/hassio/docker/__init__.py @@ -10,8 +10,12 @@ from ..const import SOCKET_DOCKER _LOGGER = logging.getLogger(__name__) -# pylint: disable=invalid-name -CommandReturn = attr.make_class('CommandReturn', ['exit_code', 'output']) + +@attr.s(frozen=True) +class CommandReturn: + """Return object from command run.""" + exit_code = attr.ib() + output = attr.ib() class DockerAPI: @@ -108,8 +112,9 @@ class DockerAPI: _LOGGER.error("Can't execute command: %s", err) return CommandReturn(None, b"") - # cleanup container - with suppress(docker.errors.DockerException): - container.remove(force=True) + finally: + # cleanup container + with suppress(docker.errors.DockerException): + container.remove(force=True) return CommandReturn(result.get('StatusCode'), output) diff --git a/hassio/homeassistant.py b/hassio/homeassistant.py index 717694923..f162f4947 100644 --- a/hassio/homeassistant.py +++ b/hassio/homeassistant.py @@ -31,8 +31,12 @@ _LOGGER = logging.getLogger(__name__) RE_YAML_ERROR = re.compile(r"homeassistant\.util\.yaml") -# pylint: disable=invalid-name -ConfigResult = attr.make_class('ConfigResult', ['valid', 'log'], frozen=True) + +@attr.s(frozen=True) +class ConfigResult: + """Return object from config check.""" + valid = attr.ib() + log = attr.ib() class HomeAssistant(JsonConfig, CoreSysAttributes): @@ -357,12 +361,16 @@ class HomeAssistant(JsonConfig, CoreSysAttributes): # if not valid if result.exit_code is None: + _LOGGER.error("Fatal error on config check!") raise HomeAssistantError() # parse output log = convert_to_ascii(result.output) if result.exit_code != 0 or RE_YAML_ERROR.search(log): + _LOGGER.error("Invalid Home Assistant config found!") return ConfigResult(False, log) + + _LOGGER.info("Home Assistant config is valid") return ConfigResult(True, log) async def ensure_access_token(self):