mirror of
https://github.com/home-assistant/supervisor.git
synced 2025-07-11 19:26:28 +00:00
Rework fixups & Add integrity (#3614)
* Rework fixups & Add integrity * Fix tests * fix test v2 * Protect ddos
This commit is contained in:
parent
ae00ea178d
commit
942b5e6150
@ -12,3 +12,4 @@ pytest-cov==3.0.0
|
|||||||
pytest-timeout==2.1.0
|
pytest-timeout==2.1.0
|
||||||
pytest==7.1.2
|
pytest==7.1.2
|
||||||
pyupgrade==2.32.1
|
pyupgrade==2.32.1
|
||||||
|
time-machine==2.6.0
|
||||||
|
@ -89,4 +89,5 @@ class SuggestionType(str, Enum):
|
|||||||
EXECUTE_RELOAD = "execute_reload"
|
EXECUTE_RELOAD = "execute_reload"
|
||||||
EXECUTE_REMOVE = "execute_remove"
|
EXECUTE_REMOVE = "execute_remove"
|
||||||
EXECUTE_STOP = "execute_stop"
|
EXECUTE_STOP = "execute_stop"
|
||||||
|
EXECUTE_INTEGRITY = "execute_integrity"
|
||||||
REGISTRY_LOGIN = "registry_login"
|
REGISTRY_LOGIN = "registry_login"
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
"""Helpers to fixup the system."""
|
"""Helpers to fixup the system."""
|
||||||
|
from importlib import import_module
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from ..coresys import CoreSys, CoreSysAttributes
|
from ..coresys import CoreSys, CoreSysAttributes
|
||||||
@ -6,11 +7,7 @@ from ..jobs.const import JobCondition
|
|||||||
from ..jobs.decorator import Job
|
from ..jobs.decorator import Job
|
||||||
from .data import Suggestion
|
from .data import Suggestion
|
||||||
from .fixups.base import FixupBase
|
from .fixups.base import FixupBase
|
||||||
from .fixups.clear_full_backup import FixupClearFullBackup
|
from .validate import get_valid_modules
|
||||||
from .fixups.create_full_backup import FixupCreateFullBackup
|
|
||||||
from .fixups.store_execute_reload import FixupStoreExecuteReload
|
|
||||||
from .fixups.store_execute_remove import FixupStoreExecuteRemove
|
|
||||||
from .fixups.store_execute_reset import FixupStoreExecuteReset
|
|
||||||
|
|
||||||
_LOGGER: logging.Logger = logging.getLogger(__name__)
|
_LOGGER: logging.Logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -21,26 +18,22 @@ class ResolutionFixup(CoreSysAttributes):
|
|||||||
def __init__(self, coresys: CoreSys) -> None:
|
def __init__(self, coresys: CoreSys) -> None:
|
||||||
"""Initialize the suggestion class."""
|
"""Initialize the suggestion class."""
|
||||||
self.coresys = coresys
|
self.coresys = coresys
|
||||||
|
self._fixups: dict[str, FixupBase] = {}
|
||||||
|
|
||||||
self._create_full_backup = FixupCreateFullBackup(coresys)
|
self._load()
|
||||||
self._clear_full_backup = FixupClearFullBackup(coresys)
|
|
||||||
self._store_execute_reset = FixupStoreExecuteReset(coresys)
|
def _load(self):
|
||||||
self._store_execute_reload = FixupStoreExecuteReload(coresys)
|
"""Load all checks."""
|
||||||
self._store_execute_remove = FixupStoreExecuteRemove(coresys)
|
package = f"{__package__}.fixups"
|
||||||
|
for module in get_valid_modules("fixups"):
|
||||||
|
fixup_module = import_module(f"{package}.{module}")
|
||||||
|
fixup = fixup_module.setup(self.coresys)
|
||||||
|
self._fixups[fixup.slug] = fixup
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def all_fixes(self) -> list[FixupBase]:
|
def all_fixes(self) -> list[FixupBase]:
|
||||||
"""Return a list of all fixups.
|
"""Return a list of all fixups."""
|
||||||
|
return list(self._fixups.values())
|
||||||
Order can be important!
|
|
||||||
"""
|
|
||||||
return [
|
|
||||||
self._create_full_backup,
|
|
||||||
self._clear_full_backup,
|
|
||||||
self._store_execute_reload,
|
|
||||||
self._store_execute_reset,
|
|
||||||
self._store_execute_remove,
|
|
||||||
]
|
|
||||||
|
|
||||||
@Job(conditions=[JobCondition.HEALTHY, JobCondition.RUNNING])
|
@Job(conditions=[JobCondition.HEALTHY, JobCondition.RUNNING])
|
||||||
async def run_autofix(self) -> None:
|
async def run_autofix(self) -> None:
|
||||||
|
@ -71,3 +71,8 @@ class FixupBase(ABC, CoreSysAttributes):
|
|||||||
def auto(self) -> bool:
|
def auto(self) -> bool:
|
||||||
"""Return if a fixup can be apply as auto fix."""
|
"""Return if a fixup can be apply as auto fix."""
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@property
|
||||||
|
def slug(self) -> str:
|
||||||
|
"""Return the check slug."""
|
||||||
|
return self.__class__.__module__.rsplit(".", maxsplit=1)[-1]
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
import logging
|
import logging
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
|
from ...coresys import CoreSys
|
||||||
from ...exceptions import (
|
from ...exceptions import (
|
||||||
ResolutionFixupError,
|
ResolutionFixupError,
|
||||||
ResolutionFixupJobError,
|
ResolutionFixupJobError,
|
||||||
@ -16,6 +17,11 @@ from .base import FixupBase
|
|||||||
_LOGGER: logging.Logger = logging.getLogger(__name__)
|
_LOGGER: logging.Logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def setup(coresys: CoreSys) -> FixupBase:
|
||||||
|
"""Check setup function."""
|
||||||
|
return FixupStoreExecuteReload(coresys)
|
||||||
|
|
||||||
|
|
||||||
class FixupStoreExecuteReload(FixupBase):
|
class FixupStoreExecuteReload(FixupBase):
|
||||||
"""Storage class for fixup."""
|
"""Storage class for fixup."""
|
||||||
|
|
||||||
|
@ -2,14 +2,19 @@
|
|||||||
import logging
|
import logging
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from supervisor.exceptions import ResolutionFixupError, StoreError, StoreNotFound
|
from ...coresys import CoreSys
|
||||||
|
from ...exceptions import ResolutionFixupError, StoreError, StoreNotFound
|
||||||
from ..const import ContextType, IssueType, SuggestionType
|
from ..const import ContextType, IssueType, SuggestionType
|
||||||
from .base import FixupBase
|
from .base import FixupBase
|
||||||
|
|
||||||
_LOGGER: logging.Logger = logging.getLogger(__name__)
|
_LOGGER: logging.Logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def setup(coresys: CoreSys) -> FixupBase:
|
||||||
|
"""Check setup function."""
|
||||||
|
return FixupStoreExecuteRemove(coresys)
|
||||||
|
|
||||||
|
|
||||||
class FixupStoreExecuteRemove(FixupBase):
|
class FixupStoreExecuteRemove(FixupBase):
|
||||||
"""Storage class for fixup."""
|
"""Storage class for fixup."""
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
import logging
|
import logging
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
|
from ...coresys import CoreSys
|
||||||
from ...exceptions import (
|
from ...exceptions import (
|
||||||
ResolutionFixupError,
|
ResolutionFixupError,
|
||||||
ResolutionFixupJobError,
|
ResolutionFixupJobError,
|
||||||
@ -17,6 +18,11 @@ from .base import FixupBase
|
|||||||
_LOGGER: logging.Logger = logging.getLogger(__name__)
|
_LOGGER: logging.Logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def setup(coresys: CoreSys) -> FixupBase:
|
||||||
|
"""Check setup function."""
|
||||||
|
return FixupStoreExecuteReset(coresys)
|
||||||
|
|
||||||
|
|
||||||
class FixupStoreExecuteReset(FixupBase):
|
class FixupStoreExecuteReset(FixupBase):
|
||||||
"""Storage class for fixup."""
|
"""Storage class for fixup."""
|
||||||
|
|
||||||
|
@ -3,13 +3,19 @@ import logging
|
|||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from ...backups.const import BackupType
|
from ...backups.const import BackupType
|
||||||
|
from ...coresys import CoreSys
|
||||||
from ..const import MINIMUM_FULL_BACKUPS, ContextType, IssueType, SuggestionType
|
from ..const import MINIMUM_FULL_BACKUPS, ContextType, IssueType, SuggestionType
|
||||||
from .base import FixupBase
|
from .base import FixupBase
|
||||||
|
|
||||||
_LOGGER: logging.Logger = logging.getLogger(__name__)
|
_LOGGER: logging.Logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class FixupClearFullBackup(FixupBase):
|
def setup(coresys: CoreSys) -> FixupBase:
|
||||||
|
"""Check setup function."""
|
||||||
|
return FixupSystemClearFullBackup(coresys)
|
||||||
|
|
||||||
|
|
||||||
|
class FixupSystemClearFullBackup(FixupBase):
|
||||||
"""Storage class for fixup."""
|
"""Storage class for fixup."""
|
||||||
|
|
||||||
async def process_fixup(self, reference: Optional[str] = None) -> None:
|
async def process_fixup(self, reference: Optional[str] = None) -> None:
|
@ -2,13 +2,19 @@
|
|||||||
import logging
|
import logging
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
|
from ...coresys import CoreSys
|
||||||
from ..const import ContextType, SuggestionType
|
from ..const import ContextType, SuggestionType
|
||||||
from .base import FixupBase
|
from .base import FixupBase
|
||||||
|
|
||||||
_LOGGER: logging.Logger = logging.getLogger(__name__)
|
_LOGGER: logging.Logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class FixupCreateFullBackup(FixupBase):
|
def setup(coresys: CoreSys) -> FixupBase:
|
||||||
|
"""Check setup function."""
|
||||||
|
return FixupSystemCreateFullBackup(coresys)
|
||||||
|
|
||||||
|
|
||||||
|
class FixupSystemCreateFullBackup(FixupBase):
|
||||||
"""Storage class for fixup."""
|
"""Storage class for fixup."""
|
||||||
|
|
||||||
async def process_fixup(self, reference: Optional[str] = None) -> None:
|
async def process_fixup(self, reference: Optional[str] = None) -> None:
|
66
supervisor/resolution/fixups/system_execute_integrity.py
Normal file
66
supervisor/resolution/fixups/system_execute_integrity.py
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
"""Helpers to check and fix issues with free space."""
|
||||||
|
from datetime import timedelta
|
||||||
|
import logging
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
from ...coresys import CoreSys
|
||||||
|
from ...exceptions import ResolutionFixupError, ResolutionFixupJobError
|
||||||
|
from ...jobs.const import JobCondition, JobExecutionLimit
|
||||||
|
from ...jobs.decorator import Job
|
||||||
|
from ...security.const import ContentTrustResult
|
||||||
|
from ..const import ContextType, IssueType, SuggestionType
|
||||||
|
from .base import FixupBase
|
||||||
|
|
||||||
|
_LOGGER: logging.Logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def setup(coresys: CoreSys) -> FixupBase:
|
||||||
|
"""Check setup function."""
|
||||||
|
return FixupSystemExecuteIntegrity(coresys)
|
||||||
|
|
||||||
|
|
||||||
|
class FixupSystemExecuteIntegrity(FixupBase):
|
||||||
|
"""Storage class for fixup."""
|
||||||
|
|
||||||
|
@Job(
|
||||||
|
conditions=[JobCondition.INTERNET_SYSTEM],
|
||||||
|
on_condition=ResolutionFixupJobError,
|
||||||
|
limit=JobExecutionLimit.THROTTLE,
|
||||||
|
throttle_period=timedelta(hours=8),
|
||||||
|
)
|
||||||
|
async def process_fixup(self, reference: Optional[str] = None) -> None:
|
||||||
|
"""Initialize the fixup class."""
|
||||||
|
result = await self.sys_security.integrity_check()
|
||||||
|
|
||||||
|
if ContentTrustResult.FAILED in (result.core, result.supervisor):
|
||||||
|
raise ResolutionFixupError()
|
||||||
|
|
||||||
|
for plugin in result.plugins:
|
||||||
|
if plugin != ContentTrustResult.FAILED:
|
||||||
|
continue
|
||||||
|
raise ResolutionFixupError()
|
||||||
|
|
||||||
|
for addon in result.addons:
|
||||||
|
if addon != ContentTrustResult.FAILED:
|
||||||
|
continue
|
||||||
|
raise ResolutionFixupError()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def suggestion(self) -> SuggestionType:
|
||||||
|
"""Return a SuggestionType enum."""
|
||||||
|
return SuggestionType.EXECUTE_INTEGRITY
|
||||||
|
|
||||||
|
@property
|
||||||
|
def context(self) -> ContextType:
|
||||||
|
"""Return a ContextType enum."""
|
||||||
|
return ContextType.SYSTEM
|
||||||
|
|
||||||
|
@property
|
||||||
|
def issues(self) -> list[IssueType]:
|
||||||
|
"""Return a IssueType enum list."""
|
||||||
|
return [IssueType.TRUST]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def auto(self) -> bool:
|
||||||
|
"""Return if a fixup can be apply as auto fix."""
|
||||||
|
return True
|
@ -17,7 +17,7 @@ from ..exceptions import (
|
|||||||
SecurityJobError,
|
SecurityJobError,
|
||||||
)
|
)
|
||||||
from ..jobs.decorator import Job, JobCondition, JobExecutionLimit
|
from ..jobs.decorator import Job, JobCondition, JobExecutionLimit
|
||||||
from ..resolution.const import ContextType, IssueType
|
from ..resolution.const import ContextType, IssueType, SuggestionType
|
||||||
from ..utils.codenotary import cas_validate
|
from ..utils.codenotary import cas_validate
|
||||||
from ..utils.common import FileConfiguration
|
from ..utils.common import FileConfiguration
|
||||||
from ..utils.pwned import check_pwned_password
|
from ..utils.pwned import check_pwned_password
|
||||||
@ -78,6 +78,11 @@ class Security(FileConfiguration, CoreSysAttributes):
|
|||||||
except CodeNotaryError:
|
except CodeNotaryError:
|
||||||
if self.force:
|
if self.force:
|
||||||
raise
|
raise
|
||||||
|
self.sys_resolution.create_issue(
|
||||||
|
IssueType.TRUST,
|
||||||
|
ContextType.SYSTEM,
|
||||||
|
suggestions=[SuggestionType.EXECUTE_INTEGRITY],
|
||||||
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
async def verify_own_content(self, checksum: str) -> None:
|
async def verify_own_content(self, checksum: str) -> None:
|
||||||
|
@ -6,30 +6,43 @@ from supervisor.const import CoreState
|
|||||||
from supervisor.coresys import CoreSys
|
from supervisor.coresys import CoreSys
|
||||||
from supervisor.resolution.const import ContextType, SuggestionType
|
from supervisor.resolution.const import ContextType, SuggestionType
|
||||||
from supervisor.resolution.data import Suggestion
|
from supervisor.resolution.data import Suggestion
|
||||||
|
from supervisor.resolution.validate import get_valid_modules
|
||||||
|
|
||||||
|
|
||||||
async def test_check_autofix(coresys: CoreSys):
|
async def test_check_autofix(coresys: CoreSys):
|
||||||
"""Test check for setup."""
|
"""Test check for setup."""
|
||||||
coresys.core.state = CoreState.RUNNING
|
coresys.core.state = CoreState.RUNNING
|
||||||
|
|
||||||
coresys.resolution.fixup._create_full_backup.process_fixup = AsyncMock()
|
coresys.resolution.fixup._fixups[
|
||||||
|
"system_create_full_backup"
|
||||||
|
].process_fixup = AsyncMock()
|
||||||
|
|
||||||
with patch(
|
with patch(
|
||||||
"supervisor.resolution.fixups.create_full_backup.FixupCreateFullBackup.auto",
|
"supervisor.resolution.fixups.system_create_full_backup.FixupSystemCreateFullBackup.auto",
|
||||||
return_value=True,
|
return_value=True,
|
||||||
):
|
):
|
||||||
await coresys.resolution.fixup.run_autofix()
|
await coresys.resolution.fixup.run_autofix()
|
||||||
|
|
||||||
coresys.resolution.fixup._create_full_backup.process_fixup.assert_not_called()
|
coresys.resolution.fixup._fixups[
|
||||||
|
"system_create_full_backup"
|
||||||
|
].process_fixup.assert_not_called()
|
||||||
|
|
||||||
coresys.resolution.suggestions = Suggestion(
|
coresys.resolution.suggestions = Suggestion(
|
||||||
SuggestionType.CREATE_FULL_BACKUP, ContextType.SYSTEM
|
SuggestionType.CREATE_FULL_BACKUP, ContextType.SYSTEM
|
||||||
)
|
)
|
||||||
with patch(
|
with patch(
|
||||||
"supervisor.resolution.fixups.create_full_backup.FixupCreateFullBackup.auto",
|
"supervisor.resolution.fixups.system_create_full_backup.FixupSystemCreateFullBackup.auto",
|
||||||
return_value=True,
|
return_value=True,
|
||||||
):
|
):
|
||||||
await coresys.resolution.fixup.run_autofix()
|
await coresys.resolution.fixup.run_autofix()
|
||||||
|
|
||||||
coresys.resolution.fixup._create_full_backup.process_fixup.assert_called_once()
|
coresys.resolution.fixup._fixups[
|
||||||
|
"system_create_full_backup"
|
||||||
|
].process_fixup.assert_called_once()
|
||||||
assert len(coresys.resolution.suggestions) == 0
|
assert len(coresys.resolution.suggestions) == 0
|
||||||
|
|
||||||
|
|
||||||
|
def test_dynamic_fixup_loader(coresys: CoreSys):
|
||||||
|
"""Test dynamic fixup loader, this ensures that all fixups have defined a setup function."""
|
||||||
|
for fixup in get_valid_modules("fixups"):
|
||||||
|
assert fixup in coresys.resolution.fixup._fixups
|
||||||
|
@ -10,13 +10,15 @@ from supervisor.const import ATTR_DATE, ATTR_SLUG, ATTR_TYPE
|
|||||||
from supervisor.coresys import CoreSys
|
from supervisor.coresys import CoreSys
|
||||||
from supervisor.resolution.const import ContextType, SuggestionType
|
from supervisor.resolution.const import ContextType, SuggestionType
|
||||||
from supervisor.resolution.data import Suggestion
|
from supervisor.resolution.data import Suggestion
|
||||||
from supervisor.resolution.fixups.clear_full_backup import FixupClearFullBackup
|
from supervisor.resolution.fixups.system_clear_full_backup import (
|
||||||
|
FixupSystemClearFullBackup,
|
||||||
|
)
|
||||||
from supervisor.utils.dt import utcnow
|
from supervisor.utils.dt import utcnow
|
||||||
|
|
||||||
|
|
||||||
async def test_fixup(coresys: CoreSys, tmp_path):
|
async def test_fixup(coresys: CoreSys, tmp_path):
|
||||||
"""Test fixup."""
|
"""Test fixup."""
|
||||||
clear_full_backup = FixupClearFullBackup(coresys)
|
clear_full_backup = FixupSystemClearFullBackup(coresys)
|
||||||
|
|
||||||
assert not clear_full_backup.auto
|
assert not clear_full_backup.auto
|
||||||
|
|
@ -5,12 +5,14 @@ from unittest.mock import AsyncMock
|
|||||||
from supervisor.coresys import CoreSys
|
from supervisor.coresys import CoreSys
|
||||||
from supervisor.resolution.const import ContextType, SuggestionType
|
from supervisor.resolution.const import ContextType, SuggestionType
|
||||||
from supervisor.resolution.data import Suggestion
|
from supervisor.resolution.data import Suggestion
|
||||||
from supervisor.resolution.fixups.create_full_backup import FixupCreateFullBackup
|
from supervisor.resolution.fixups.system_create_full_backup import (
|
||||||
|
FixupSystemCreateFullBackup,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
async def test_fixup(coresys: CoreSys):
|
async def test_fixup(coresys: CoreSys):
|
||||||
"""Test fixup."""
|
"""Test fixup."""
|
||||||
create_full_backup = FixupCreateFullBackup(coresys)
|
create_full_backup = FixupSystemCreateFullBackup(coresys)
|
||||||
|
|
||||||
assert not create_full_backup.auto
|
assert not create_full_backup.auto
|
||||||
|
|
68
tests/resolution/fixup/test_system_execute_integrity.py
Normal file
68
tests/resolution/fixup/test_system_execute_integrity.py
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
"""Test evaluation base."""
|
||||||
|
# pylint: disable=import-error,protected-access
|
||||||
|
from datetime import timedelta
|
||||||
|
from unittest.mock import AsyncMock
|
||||||
|
|
||||||
|
import time_machine
|
||||||
|
|
||||||
|
from supervisor.coresys import CoreSys
|
||||||
|
from supervisor.resolution.const import ContextType, IssueType, SuggestionType
|
||||||
|
from supervisor.resolution.data import Issue, Suggestion
|
||||||
|
from supervisor.resolution.fixups.system_execute_integrity import (
|
||||||
|
FixupSystemExecuteIntegrity,
|
||||||
|
)
|
||||||
|
from supervisor.security.const import ContentTrustResult, IntegrityResult
|
||||||
|
from supervisor.utils.dt import utcnow
|
||||||
|
|
||||||
|
|
||||||
|
async def test_fixup(coresys: CoreSys):
|
||||||
|
"""Test fixup."""
|
||||||
|
system_execute_integrity = FixupSystemExecuteIntegrity(coresys)
|
||||||
|
|
||||||
|
assert system_execute_integrity.auto
|
||||||
|
|
||||||
|
coresys.resolution.suggestions = Suggestion(
|
||||||
|
SuggestionType.EXECUTE_INTEGRITY, ContextType.SYSTEM
|
||||||
|
)
|
||||||
|
coresys.resolution.issues = Issue(IssueType.TRUST, ContextType.SYSTEM)
|
||||||
|
|
||||||
|
coresys.security.integrity_check = AsyncMock(
|
||||||
|
return_value=IntegrityResult(
|
||||||
|
ContentTrustResult.PASS,
|
||||||
|
ContentTrustResult.PASS,
|
||||||
|
{"audio": ContentTrustResult.PASS},
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
await system_execute_integrity()
|
||||||
|
|
||||||
|
assert coresys.security.integrity_check.called
|
||||||
|
assert len(coresys.resolution.suggestions) == 0
|
||||||
|
assert len(coresys.resolution.issues) == 0
|
||||||
|
|
||||||
|
|
||||||
|
async def test_fixup_error(coresys: CoreSys):
|
||||||
|
"""Test fixup."""
|
||||||
|
system_execute_integrity = FixupSystemExecuteIntegrity(coresys)
|
||||||
|
|
||||||
|
assert system_execute_integrity.auto
|
||||||
|
|
||||||
|
coresys.resolution.suggestions = Suggestion(
|
||||||
|
SuggestionType.EXECUTE_INTEGRITY, ContextType.SYSTEM
|
||||||
|
)
|
||||||
|
coresys.resolution.issues = Issue(IssueType.TRUST, ContextType.SYSTEM)
|
||||||
|
|
||||||
|
coresys.security.integrity_check = AsyncMock(
|
||||||
|
return_value=IntegrityResult(
|
||||||
|
ContentTrustResult.FAILED,
|
||||||
|
ContentTrustResult.PASS,
|
||||||
|
{"audio": ContentTrustResult.PASS},
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
with time_machine.travel(utcnow() + timedelta(hours=24)):
|
||||||
|
await system_execute_integrity()
|
||||||
|
|
||||||
|
assert coresys.security.integrity_check.called
|
||||||
|
assert len(coresys.resolution.suggestions) == 1
|
||||||
|
assert len(coresys.resolution.issues) == 1
|
Loading…
x
Reference in New Issue
Block a user