async def test_approve(coresys: CoreSys, tmp_path):
    """Test check."""
    with patch("supervisor.config.CoreConfig.path_homeassistant", tmp_path):
        core_security = CheckCoreSecurity(coresys)
        coresys.core.state = CoreState.RUNNING
        coresys.homeassistant._data["version"] = None
        assert await core_security.approve_check()

        coresys.homeassistant._data["version"] = AwesomeVersion("2021.1.3")
        assert not await core_security.approve_check()

        coresys.homeassistant._data["version"] = AwesomeVersion("2021.1.2")
        assert not await core_security.approve_check()

        Path(coresys.config.path_homeassistant,
             "custom_components").mkdir(parents=True)
        assert await core_security.approve_check()
Exemplo n.º 2
0
 def new(data: dict[str, Any]):
     """Create a object from docker info."""
     return DockerInfo(
         AwesomeVersion(data.get("ServerVersion", "0.0.0")),
         data.get("Driver", "unknown"),
         data.get("LoggingDriver", "unknown"),
         data.get("CgroupVersion", "1"),
     )
Exemplo n.º 3
0
    def native_unit_of_measurement(self) -> str | None:
        """Return the unit of measurement of this entity."""
        set_req = self.gateway.const.SetReq
        if (AwesomeVersion(
                self.gateway.protocol_version) >= AwesomeVersion("1.5")
                and set_req.V_UNIT_PREFIX in self._values):
            custom_unit: str = self._values[set_req.V_UNIT_PREFIX]
            return custom_unit

        if set_req(self.value_type) == set_req.V_TEMP:
            if self.hass.config.units.is_metric:
                return TEMP_CELSIUS
            return TEMP_FAHRENHEIT

        if hasattr(self, "entity_description"):
            return self.entity_description.native_unit_of_measurement
        return None
Exemplo n.º 4
0
 def release_url(self) -> str | None:
     """URL to the full release notes of the latest version available."""
     version = AwesomeVersion(self.latest_version)
     if version.dev or version.strategy == AwesomeVersionStrategy.UNKNOWN:
         return "https://github.com/home-assistant/operating-system/commits/dev"
     return (
         f"https://github.com/home-assistant/operating-system/releases/tag/{version}"
     )
Exemplo n.º 5
0
    def resolve_from_root(cls, hass: HomeAssistant, root_module: ModuleType,
                          domain: str) -> Integration | None:
        """Resolve an integration from a root module."""
        for base in root_module.__path__:
            manifest_path = pathlib.Path(base) / domain / "manifest.json"

            if not manifest_path.is_file():
                continue

            try:
                manifest = json.loads(manifest_path.read_text())
            except ValueError as err:
                _LOGGER.error("Error parsing manifest.json file at %s: %s",
                              manifest_path, err)
                continue

            integration = cls(
                hass,
                f"{root_module.__name__}.{domain}",
                manifest_path.parent,
                manifest,
            )

            if integration.is_built_in:
                return integration

            _LOGGER.warning(CUSTOM_WARNING, integration.domain)
            if integration.version is None:
                _LOGGER.error(
                    "The custom integration '%s' does not have a "
                    "version key in the manifest file and was blocked from loading. "
                    "See https://developers.home-assistant.io/blog/2021/01/29/custom-integration-changes#versions for more details",
                    integration.domain,
                )
                return None
            try:
                AwesomeVersion(
                    integration.version,
                    [
                        AwesomeVersionStrategy.CALVER,
                        AwesomeVersionStrategy.SEMVER,
                        AwesomeVersionStrategy.SIMPLEVER,
                        AwesomeVersionStrategy.BUILDVER,
                        AwesomeVersionStrategy.PEP440,
                    ],
                )
            except AwesomeVersionException:
                _LOGGER.error(
                    "The custom integration '%s' does not have a "
                    "valid version key (%s) in the manifest file and was blocked from loading. "
                    "See https://developers.home-assistant.io/blog/2021/01/29/custom-integration-changes#versions for more details",
                    integration.domain,
                    integration.version,
                )
                return None
            return integration

        return None
Exemplo n.º 6
0
def version_tag(
    value: Union[str, None, int, float, AwesomeVersion]
) -> Optional[AwesomeVersion]:
    """Validate main version handling."""
    if value is None:
        return None
    if isinstance(value, AwesomeVersion):
        return value
    return AwesomeVersion(value)
Exemplo n.º 7
0
def validate_custom_integration_version(version: str) -> bool:
    """Validate the version of custom integrations."""
    return AwesomeVersion(version).strategy in (
        AwesomeVersionStrategy.CALVER,
        AwesomeVersionStrategy.SEMVER,
        AwesomeVersionStrategy.SIMPLEVER,
        AwesomeVersionStrategy.BUILDVER,
        AwesomeVersionStrategy.PEP440,
    )
Exemplo n.º 8
0
def test_version_scheme(version, strategy, dev, beta, modifier, modifier_type):
    """Test that the version matches the expected scheme."""
    version_object = AwesomeVersion(version)
    assert str(version_object) == version
    assert version_object.strategy == strategy
    assert version_object.dev == dev
    assert version_object.beta == beta
    assert version_object.modifier == modifier
    assert version_object.modifier_type == modifier_type
Exemplo n.º 9
0
async def test_docker_image_platform(coresys: CoreSys, cpu_arch: str,
                                     platform: str):
    """Test platform set correctly from arch."""
    with patch.object(coresys.docker.images,
                      "pull",
                      return_value=Mock(id="test:1.2.3")) as pull:
        instance = DockerInterface(coresys)
        await instance.install(AwesomeVersion("1.2.3"), "test", arch=cpu_arch)
        assert pull.call_count == 1
        assert pull.call_args == call("test:1.2.3", platform=platform)
Exemplo n.º 10
0
def test_modifier():
    handler = CompareHandlers(AwesomeVersion("1.0b1"), AwesomeVersion("1.0b0"))
    assert handler.check()

    handler = CompareHandlers(AwesomeVersion("1.0"), AwesomeVersion("1.0b0"))
    assert handler.check()

    handler = CompareHandlers(AwesomeVersion("1.0b0"), AwesomeVersion("1.0b1"))
    assert not handler.check()

    handler = CompareHandlers(AwesomeVersion("1.0b0"), AwesomeVersion("1.0"))
    assert not handler.check()
Exemplo n.º 11
0
 def get_mac_addr(self):
     """Increment the last byte of the mac address by one for FW>3.70."""
     if (self.bulb.host_firmware_version and
             AwesomeVersion(self.bulb.host_firmware_version) >= FIX_MAC_FW):
         octets = [
             int(octet, 16) for octet in self.bulb.mac_addr.split(":")
         ]
         octets[5] = (octets[5] + 1) % 256
         return ":".join(f"{octet:02x}" for octet in octets)
     return self.bulb.mac_addr
Exemplo n.º 12
0
def is_ha_supported() -> bool:
    """Return True, if current HA version is supported."""
    if AwesomeVersion(HA_VERSION) >= MIN_REQUIRED_HA_VERSION:
        return True

    _LOGGER.error(
        'Unsupported HA version! Please upgrade home assistant at least to "%s"',
        MIN_REQUIRED_HA_VERSION,
    )
    return False
Exemplo n.º 13
0
def _extract_version_from_server_response(server_response):
    """Attempt to extract version from server response."""
    try:
        return AwesomeVersion(
            server_response,
            ensure_strategy=AwesomeVersionStrategy.SIMPLEVER,
            find_first_match=True,
        )
    except AwesomeVersionException:
        return None
Exemplo n.º 14
0
async def coresys(loop, docker, network_manager, aiohttp_client,
                  run_dir) -> CoreSys:
    """Create a CoreSys Mock."""
    with patch("supervisor.bootstrap.initialize_system"), patch(
            "supervisor.bootstrap.setup_diagnostics"):
        coresys_obj = await initialize_coresys()

    # Mock save json
    coresys_obj._ingress.save_data = MagicMock()
    coresys_obj._auth.save_data = MagicMock()
    coresys_obj._updater.save_data = MagicMock()
    coresys_obj._config.save_data = MagicMock()
    coresys_obj._jobs.save_data = MagicMock()
    coresys_obj._resolution.save_data = MagicMock()
    coresys_obj._addons.data.save_data = MagicMock()
    coresys_obj._store.save_data = MagicMock()

    # Mock test client
    coresys_obj.arch._default_arch = "amd64"
    coresys_obj._machine = "qemux86-64"
    coresys_obj._machine_id = uuid4()

    # Mock host communication
    coresys_obj._dbus._network = network_manager

    # Mock docker
    coresys_obj._docker = docker

    # Set internet state
    coresys_obj.supervisor._connectivity = True
    coresys_obj.host.network._connectivity = True

    # Fix Paths
    su_config.ADDONS_CORE = Path(
        Path(__file__).parent.joinpath("fixtures"), "addons/core")
    su_config.ADDONS_LOCAL = Path(
        Path(__file__).parent.joinpath("fixtures"), "addons/local")
    su_config.ADDONS_GIT = Path(
        Path(__file__).parent.joinpath("fixtures"), "addons/git")

    # WebSocket
    coresys_obj.homeassistant.api.check_api_state = mock_async_return_true
    coresys_obj.homeassistant._websocket._client = AsyncMock(
        ha_version=AwesomeVersion("2021.2.4"))

    # Remove rate limiting decorator from fetch_data
    coresys_obj.updater.fetch_data = partial(
        unwrap(coresys_obj.updater.fetch_data), coresys_obj.updater)

    # Don't remove files/folders related to addons and stores
    with patch("supervisor.store.git.GitRepo._remove"):
        yield coresys_obj

    await coresys_obj.websession.close()
Exemplo n.º 15
0
 async def approve_check(self, reference: Optional[str] = None) -> bool:
     """Approve check if it is affected by issue."""
     try:
         if self.sys_homeassistant.version >= AwesomeVersion("2021.1.5"):
             return False
     except AwesomeVersionException:
         return True
     if not Path(self.sys_config.path_homeassistant,
                 "custom_components").exists():
         return False
     return True
Exemplo n.º 16
0
    def pending_update(self) -> bool:
        if not self.can_install:
            return False
        if self.data.installed:
            if self.data.selected_tag is not None:
                if self.data.selected_tag == self.data.default_branch:
                    if self.data.installed_commit != self.data.last_commit:
                        return True
                    return False
            if self.display_version_or_commit == "version":
                try:
                    return AwesomeVersion(self.display_available_version) > AwesomeVersion(
                        self.display_installed_version
                    )
                except AwesomeVersionException:
                    pass
            if self.display_installed_version != self.display_available_version:
                return True

        return False
Exemplo n.º 17
0
async def test_docker_image_default_platform(coresys: CoreSys):
    """Test platform set using supervisor arch when omitted."""
    with patch.object(type(coresys.supervisor), "arch",
                      PropertyMock(return_value="i386")), patch.object(
                          coresys.docker.images,
                          "pull",
                          return_value=Mock(id="test:1.2.3")) as pull:
        instance = DockerInterface(coresys)
        await instance.install(AwesomeVersion("1.2.3"), "test")
        assert pull.call_count == 1
        assert pull.call_args == call("test:1.2.3", platform="linux/386")
Exemplo n.º 18
0
    async def _async_update_data(self) -> dict[str, IntegrationAlert]:
        response = await async_get_clientsession(self.hass).get(
            "https://alerts.home-assistant.io/alerts.json",
            timeout=aiohttp.ClientTimeout(total=10),
        )
        alerts = await response.json()

        result = {}

        for alert in alerts:
            if "integrations" not in alert:
                continue

            if "homeassistant" in alert:
                if "affected_from_version" in alert["homeassistant"]:
                    affected_from_version = AwesomeVersion(
                        alert["homeassistant"]["affected_from_version"], )
                    if self.ha_version < affected_from_version:
                        continue
                if "resolved_in_version" in alert["homeassistant"]:
                    resolved_in_version = AwesomeVersion(
                        alert["homeassistant"]["resolved_in_version"], )
                    if self.ha_version >= resolved_in_version:
                        continue

            for integration in alert["integrations"]:
                if "package" not in integration:
                    continue

                if integration["package"] not in self.hass.config.components:
                    continue

                integration_alert = IntegrationAlert(
                    integration=integration["package"],
                    filename=alert["filename"],
                    date_updated=alert.get("date_updated"),
                )

                result[integration_alert.issue_id] = integration_alert

        return result
Exemplo n.º 19
0
 def __init__(self, hass: HomeAssistant) -> None:
     """Initialize the data updater."""
     super().__init__(
         hass,
         _LOGGER,
         name=DOMAIN,
         update_interval=UPDATE_INTERVAL,
     )
     self.ha_version = AwesomeVersion(
         __version__,
         ensure_strategy=AwesomeVersionStrategy.CALVER,
     )
Exemplo n.º 20
0
    async def check_new_version() -> Updater:
        """Check if a new version is available and report if one is."""
        newest, release_notes = await get_newest_version(
            hass, huuid, include_components)

        _LOGGER.debug("Fetched version %s: %s", newest, release_notes)

        # Skip on dev
        if "dev" in current_version:
            return Updater(False, "", "")

        # Load data from Supervisor
        if hass.components.hassio.is_hassio():
            core_info = hass.components.hassio.get_core_info()
            newest = core_info["version_latest"]

        # Validate version
        update_available = False
        if AwesomeVersion(newest) > AwesomeVersion(current_version):
            _LOGGER.debug(
                "The latest available version of Home Assistant is %s", newest)
            update_available = True
        elif AwesomeVersion(newest) == AwesomeVersion(current_version):
            _LOGGER.debug(
                "You are on the latest version (%s) of Home Assistant", newest)
        elif AwesomeVersion(newest) < AwesomeVersion(current_version):
            _LOGGER.debug(
                "Local version (%s) is newer than the latest available version (%s)",
                current_version,
                newest,
            )

        _LOGGER.debug("Update available: %s", update_available)

        return Updater(update_available, newest, release_notes)
Exemplo n.º 21
0
async def validate_input(hass: HomeAssistant, data: dict[str, str]) -> dict[str, str]:
    """Validate the user input allows us to connect.

    Data has the keys from STEP_USER_DATA_SCHEMA with values provided by the user.
    """
    api = PrusaLink(async_get_clientsession(hass), data["host"], data["api_key"])

    try:
        async with async_timeout.timeout(5):
            version = await api.get_version()

    except (asyncio.TimeoutError, ClientError) as err:
        _LOGGER.error("Could not connect to PrusaLink: %s", err)
        raise CannotConnect from err

    try:
        if AwesomeVersion(version["api"]) < AwesomeVersion("2.0.0"):
            raise NotSupported
    except AwesomeVersionException as err:
        raise NotSupported from err

    return {"title": version["hostname"]}
Exemplo n.º 22
0
def _validate_version(version: str) -> dict[str, str]:
    """Validate a version string from the user."""
    version_okay = True
    try:
        AwesomeVersion(
            version,
            [AwesomeVersionStrategy.SIMPLEVER, AwesomeVersionStrategy.SEMVER],
        )
    except AwesomeVersionStrategyException:
        version_okay = False

    if version_okay:
        return {}
    return {CONF_VERSION: "invalid_version"}
Exemplo n.º 23
0
def verify_version(value: str):
    """Verify the version."""
    version = AwesomeVersion(value)
    if version.strategy not in [
        AwesomeVersionStrategy.CALVER,
        AwesomeVersionStrategy.SEMVER,
        AwesomeVersionStrategy.SIMPLEVER,
        AwesomeVersionStrategy.BUILDVER,
        AwesomeVersionStrategy.PEP440,
    ]:
        raise vol.Invalid(
            f"'{version}' is not a valid version. This will cause a future version of Home Assistant to block this integration.",
        )
    return value
Exemplo n.º 24
0
def test_defaults(coresys):
    """Test event defaults."""
    coresys.config.diagnostics = True

    coresys.core.state = CoreState.RUNNING
    with patch("shutil.disk_usage", return_value=(42, 42, 2 * (1024.0**3))):
        filtered = filter_data(coresys, SAMPLE_EVENT, {})

    assert ["installation_type", "supervised"] in filtered["tags"]
    assert filtered["contexts"]["host"]["arch"] == "amd64"
    assert filtered["contexts"]["host"]["machine"] == "qemux86-64"
    assert filtered["contexts"]["versions"]["supervisor"] == AwesomeVersion(
        SUPERVISOR_VERSION)
    assert filtered["user"]["id"] == coresys.machine_id
Exemplo n.º 25
0
def _validate_version(version: str) -> dict[str, str]:
    """Validate a version string from the user."""
    version_okay = False
    with suppress(AwesomeVersionStrategyException):
        version_okay = bool(
            AwesomeVersion.ensure_strategy(
                version,
                [AwesomeVersionStrategy.SIMPLEVER, AwesomeVersionStrategy.SEMVER],
            )
        )

    if version_okay:
        return {}
    return {CONF_VERSION: "invalid_version"}
Exemplo n.º 26
0
 async def run_check(self) -> None:
     """Run check if not affected by issue."""
     try:
         if self.sys_homeassistant.version < AwesomeVersion("2021.1.5"):
             if Path(self.sys_config.path_homeassistant,
                     "custom_components").exists():
                 self.sys_resolution.create_issue(
                     IssueType.SECURITY,
                     ContextType.CORE,
                     reference=SecurityReference.
                     CUSTOM_COMPONENTS_BELOW_2021_1_5,
                     suggestions=[SuggestionType.EXECUTE_UPDATE],
                 )
     except (AwesomeVersionException, OSError):
         return
Exemplo n.º 27
0
def verify_version(value: str):
    """Verify the version."""
    try:
        AwesomeVersion(
            value,
            [
                AwesomeVersionStrategy.CALVER,
                AwesomeVersionStrategy.SEMVER,
                AwesomeVersionStrategy.SIMPLEVER,
                AwesomeVersionStrategy.BUILDVER,
                AwesomeVersionStrategy.PEP440,
            ],
        )
    except AwesomeVersionException:
        raise vol.Invalid(f"'{value}' is not a valid version.")
    return value
Exemplo n.º 28
0
def test_container():
    handler = CompareHandlers(AwesomeVersion("latest"),
                              AwesomeVersion("stable"))
    assert handler.check()

    handler = CompareHandlers(AwesomeVersion("latest"), AwesomeVersion("1"))
    assert handler.check()

    handler = CompareHandlers(AwesomeVersion("1.0.0"),
                              AwesomeVersion("stable"))
    assert not handler.check()
Exemplo n.º 29
0
    def device_info(self):
        """Return device information about NetDaemon."""
        info = {
            "identifiers": {(DOMAIN, ND_ID)},
            "name": NAME,
            "sw_version": INTEGRATION_VERSION,
            "manufacturer": "netdaemon.xyz",
        }
        # LEGACY can be removed when min HA version is 2021.12
        if AwesomeVersion(HA_VERSION) >= "2021.12.0b0":
            # pylint: disable=import-outside-toplevel
            from homeassistant.helpers.device_registry import DeviceEntryType

            info["entry_type"] = DeviceEntryType.SERVICE
        else:
            info["entry_type"] = "service"
        return info
Exemplo n.º 30
0
    def parse(self):
        """Logic to parse new version data."""
        self._version = self.data.get(DATA_INFO, {}).get(DATA_VERSION)

        versions = sorted(
            [
                version for version in self.data.get(DATA_RELEASES, [])
                if version.startswith("2")
            ],
            reverse=True,
        )
        for version in versions:
            version = AwesomeVersion(version)
            if self.channel == HaVersionChannel.STABLE and version.beta:
                continue
            self._version = version
            break