From 692d34a13cc211c5a495408ff61d374314977aa8 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Tue, 28 Feb 2023 19:57:05 +0100 Subject: [PATCH] Handle OSError / Filesystem corruptions (#4127) * Handle OSError / Filesystem corruptions * Fix tests --- supervisor/resolution/const.py | 1 + .../resolution/evaluations/source_mods.py | 20 +++++++++++++------ supervisor/utils/codenotary.py | 5 ++++- tests/resolution/test_evaluation.py | 4 ++-- 4 files changed, 21 insertions(+), 9 deletions(-) diff --git a/supervisor/resolution/const.py b/supervisor/resolution/const.py index 9373236ac..c8f1e0409 100644 --- a/supervisor/resolution/const.py +++ b/supervisor/resolution/const.py @@ -69,6 +69,7 @@ class IssueType(str, Enum): CORRUPT_DOCKER = "corrupt_docker" CORRUPT_REPOSITORY = "corrupt_repository" + CORRUPT_FILESYSTEM = "corrupt_filesystem" DNS_LOOP = "dns_loop" DNS_SERVER_FAILED = "dns_server_failed" DNS_SERVER_IPV6_ERROR = "dns_server_ipv6_error" diff --git a/supervisor/resolution/evaluations/source_mods.py b/supervisor/resolution/evaluations/source_mods.py index 67a8067d2..fd13e5493 100644 --- a/supervisor/resolution/evaluations/source_mods.py +++ b/supervisor/resolution/evaluations/source_mods.py @@ -6,7 +6,7 @@ from ...const import CoreState from ...coresys import CoreSys from ...exceptions import CodeNotaryError, CodeNotaryUntrusted from ...utils.codenotary import calc_checksum_path_sourcecode -from ..const import UnsupportedReason +from ..const import ContextType, IssueType, UnsupportedReason from .base import EvaluateBase _SUPERVISOR_SOURCE = Path("/usr/src/supervisor/supervisor") @@ -36,17 +36,25 @@ class EvaluateSourceMods(EvaluateBase): """Return a list of valid states when this evaluation can run.""" return [CoreState.RUNNING] - async def evaluate(self) -> None: + async def evaluate(self) -> bool: """Run evaluation.""" if not self.sys_security.content_trust: _LOGGER.warning("Disabled content-trust, skipping evaluation") - return + return False # Calculate sume of the sourcecode - checksum = await self.sys_run_in_executor( - calc_checksum_path_sourcecode, _SUPERVISOR_SOURCE - ) + try: + checksum = await self.sys_run_in_executor( + calc_checksum_path_sourcecode, _SUPERVISOR_SOURCE + ) + except OSError as err: + self.sys_resolution.create_issue( + IssueType.CORRUPT_FILESYSTEM, ContextType.SYSTEM + ) + _LOGGER.error("Can't calculate checksum of source code: %s", err) + return False + # Validate checksum try: await self.sys_security.verify_own_content(checksum) except CodeNotaryUntrusted: diff --git a/supervisor/utils/codenotary.py b/supervisor/utils/codenotary.py index 3e614d227..79546405a 100644 --- a/supervisor/utils/codenotary.py +++ b/supervisor/utils/codenotary.py @@ -36,7 +36,10 @@ def calc_checksum(data: str | bytes) -> str: def calc_checksum_path_sourcecode(folder: Path) -> str: - """Calculate checksum for a path source code.""" + """Calculate checksum for a path source code. + + Need catch OSError. + """ return dirhash(folder.as_posix(), "sha256", match=["*.py"]) diff --git a/tests/resolution/test_evaluation.py b/tests/resolution/test_evaluation.py index ee2973de4..222e0f5e7 100644 --- a/tests/resolution/test_evaluation.py +++ b/tests/resolution/test_evaluation.py @@ -13,9 +13,9 @@ async def test_evaluate_system_error(coresys: CoreSys, capture_exception: Mock): with patch( "supervisor.resolution.evaluations.source_mods.calc_checksum_path_sourcecode", - side_effect=OSError, + side_effect=RuntimeError, ): await coresys.resolution.evaluate.evaluate_system() capture_exception.assert_called_once() - assert check_exception_chain(capture_exception.call_args[0][0], OSError) + assert check_exception_chain(capture_exception.call_args[0][0], RuntimeError)