mirror of
https://github.com/home-assistant/supervisor.git
synced 2025-09-14 23:49:36 +00:00
Compare commits
8 Commits
all-info-s
...
2023.06.4
Author | SHA1 | Date | |
---|---|---|---|
![]() |
c2123f0903 | ||
![]() |
9fbeb2a769 | ||
![]() |
3e0723ec24 | ||
![]() |
3e5f1d96b5 | ||
![]() |
be87082502 | ||
![]() |
f997e51249 | ||
![]() |
456316fdd4 | ||
![]() |
9a7d547394 |
79
.github/workflows/builder.yml
vendored
79
.github/workflows/builder.yml
vendored
@@ -83,6 +83,10 @@ jobs:
|
||||
name: Build ${{ matrix.arch }} supervisor
|
||||
needs: init
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
packages: write
|
||||
strategy:
|
||||
matrix:
|
||||
arch: ${{ fromJson(needs.init.outputs.architectures) }}
|
||||
@@ -119,12 +123,29 @@ jobs:
|
||||
with:
|
||||
type: ${{ env.BUILD_TYPE }}
|
||||
|
||||
- name: Login to DockerHub
|
||||
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
||||
if: needs.init.outputs.publish == 'true'
|
||||
uses: docker/login-action@v2.2.0
|
||||
uses: actions/setup-python@v4.6.1
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||
|
||||
- name: Install Cosign
|
||||
if: needs.init.outputs.publish == 'true'
|
||||
uses: sigstore/cosign-installer@v3.1.0
|
||||
with:
|
||||
cosign-release: "v2.0.2"
|
||||
|
||||
- name: Install dirhash and calc hash
|
||||
if: needs.init.outputs.publish == 'true'
|
||||
run: |
|
||||
pip3 install dirhash
|
||||
dir_hash="$(dirhash "${{ github.workspace }}/supervisor" -a sha256 --match "*.py")"
|
||||
echo "${dir_hash}" > rootfs/supervisor.sha256
|
||||
|
||||
- name: Sign supervisor SHA256
|
||||
if: needs.init.outputs.publish == 'true'
|
||||
run: |
|
||||
cosign sign-blob --yes rootfs/supervisor.sha256 --bundle rootfs/supervisor.sha256.sig
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
if: needs.init.outputs.publish == 'true'
|
||||
@@ -139,55 +160,17 @@ jobs:
|
||||
run: echo "BUILD_ARGS=--test" >> $GITHUB_ENV
|
||||
|
||||
- name: Build supervisor
|
||||
uses: home-assistant/builder@2023.06.0
|
||||
uses: home-assistant/builder@2023.06.1
|
||||
with:
|
||||
args: |
|
||||
$BUILD_ARGS \
|
||||
--${{ matrix.arch }} \
|
||||
--target /data \
|
||||
--cosign \
|
||||
--generic ${{ needs.init.outputs.version }}
|
||||
env:
|
||||
CAS_API_KEY: ${{ secrets.CAS_TOKEN }}
|
||||
|
||||
codenotary:
|
||||
name: CAS signature
|
||||
needs: init
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
if: needs.init.outputs.publish == 'true'
|
||||
uses: actions/checkout@v3.5.3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
||||
if: needs.init.outputs.publish == 'true'
|
||||
uses: actions/setup-python@v4.6.1
|
||||
with:
|
||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||
|
||||
- name: Set version
|
||||
if: needs.init.outputs.publish == 'true'
|
||||
uses: home-assistant/actions/helpers/version@master
|
||||
with:
|
||||
type: ${{ env.BUILD_TYPE }}
|
||||
|
||||
- name: Install dirhash and calc hash
|
||||
if: needs.init.outputs.publish == 'true'
|
||||
id: dirhash
|
||||
run: |
|
||||
pip3 install dirhash
|
||||
dir_hash="$(dirhash "${{ github.workspace }}/supervisor" -a sha256 --match "*.py")"
|
||||
echo "::set-output name=dirhash::${dir_hash}"
|
||||
|
||||
- name: Signing Source
|
||||
if: needs.init.outputs.publish == 'true'
|
||||
uses: home-assistant/actions/helpers/codenotary@master
|
||||
with:
|
||||
source: hash://${{ steps.dirhash.outputs.dirhash }}
|
||||
asset: supervisor-${{ needs.init.outputs.version }}
|
||||
token: ${{ secrets.CAS_TOKEN }}
|
||||
|
||||
version:
|
||||
name: Update version
|
||||
needs: ["init", "run_supervisor"]
|
||||
@@ -216,7 +199,7 @@ jobs:
|
||||
run_supervisor:
|
||||
runs-on: ubuntu-latest
|
||||
name: Run the Supervisor
|
||||
needs: ["build", "codenotary", "init"]
|
||||
needs: ["build", "init"]
|
||||
timeout-minutes: 60
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
@@ -224,7 +207,7 @@ jobs:
|
||||
|
||||
- name: Build the Supervisor
|
||||
if: needs.init.outputs.publish != 'true'
|
||||
uses: home-assistant/builder@2023.06.0
|
||||
uses: home-assistant/builder@2023.06.1
|
||||
with:
|
||||
args: |
|
||||
--test \
|
||||
@@ -236,7 +219,7 @@ jobs:
|
||||
if: needs.init.outputs.publish == 'true'
|
||||
run: |
|
||||
docker pull ghcr.io/home-assistant/amd64-hassio-supervisor:${{ needs.init.outputs.version }}
|
||||
docker tag ghcr.io/home-assistant/amd64-hassio-supervisor:${{ needs.init.outputs.version }} homeassistant/amd64-hassio-supervisor:runner
|
||||
docker tag ghcr.io/home-assistant/amd64-hassio-supervisor:${{ needs.init.outputs.version }} ghcr.io/home-assistant/amd64-hassio-supervisor:runner
|
||||
|
||||
- name: Create the Supervisor
|
||||
run: |
|
||||
@@ -253,7 +236,7 @@ jobs:
|
||||
-e SUPERVISOR_NAME=hassio_supervisor \
|
||||
-e SUPERVISOR_DEV=1 \
|
||||
-e SUPERVISOR_MACHINE="qemux86-64" \
|
||||
homeassistant/amd64-hassio-supervisor:runner
|
||||
ghcr.io/home-assistant/amd64-hassio-supervisor:runner
|
||||
|
||||
- name: Start the Supervisor
|
||||
run: docker start hassio_supervisor
|
||||
|
7
.github/workflows/ci.yaml
vendored
7
.github/workflows/ci.yaml
vendored
@@ -10,7 +10,6 @@ on:
|
||||
env:
|
||||
DEFAULT_PYTHON: "3.11"
|
||||
PRE_COMMIT_HOME: ~/.cache/pre-commit
|
||||
DEFAULT_CAS: v1.0.2
|
||||
|
||||
concurrency:
|
||||
group: "${{ github.workflow }}-${{ github.ref }}"
|
||||
@@ -351,10 +350,10 @@ jobs:
|
||||
id: python
|
||||
with:
|
||||
python-version: ${{ needs.prepare.outputs.python-version }}
|
||||
- name: Install CAS tools
|
||||
uses: home-assistant/actions/helpers/cas@master
|
||||
- name: Install Cosign
|
||||
uses: sigstore/cosign-installer@v3.1.0
|
||||
with:
|
||||
version: ${{ env.DEFAULT_CAS }}
|
||||
cosign-release: "v2.0.2"
|
||||
- name: Restore Python virtual environment
|
||||
id: cache-venv
|
||||
uses: actions/cache@v3.3.1
|
||||
|
17
Dockerfile
17
Dockerfile
@@ -7,7 +7,8 @@ ENV \
|
||||
CRYPTOGRAPHY_OPENSSL_NO_LEGACY=1
|
||||
|
||||
ARG \
|
||||
CAS_VERSION
|
||||
COSIGN_VERSION \
|
||||
BUILD_ARCH
|
||||
|
||||
# Install base
|
||||
WORKDIR /usr/src
|
||||
@@ -21,19 +22,9 @@ RUN \
|
||||
libpulse \
|
||||
musl \
|
||||
openssl \
|
||||
&& apk add --no-cache --virtual .build-dependencies \
|
||||
build-base \
|
||||
go \
|
||||
\
|
||||
&& git clone -b "v${CAS_VERSION}" --depth 1 \
|
||||
https://github.com/codenotary/cas \
|
||||
&& cd cas \
|
||||
&& make cas \
|
||||
&& mv cas /usr/bin/cas \
|
||||
\
|
||||
&& apk del .build-dependencies \
|
||||
&& rm -rf /root/go /root/.cache \
|
||||
&& rm -rf /usr/src/cas
|
||||
&& curl -Lso /usr/bin/cosign "https://github.com/home-assistant/cosign/releases/download/${COSIGN_VERSION}/cosign_${BUILD_ARCH}" \
|
||||
&& chmod a+x /usr/bin/cosign
|
||||
|
||||
# Install requirements
|
||||
COPY requirements.txt .
|
||||
|
@@ -1,5 +1,4 @@
|
||||
image: homeassistant/{arch}-hassio-supervisor
|
||||
shadow_repository: ghcr.io/home-assistant
|
||||
image: ghcr.io/home-assistant/{arch}-hassio-supervisor
|
||||
build_from:
|
||||
aarch64: ghcr.io/home-assistant/aarch64-base-python:3.11-alpine3.16
|
||||
armhf: ghcr.io/home-assistant/armhf-base-python:3.11-alpine3.16
|
||||
@@ -9,8 +8,11 @@ build_from:
|
||||
codenotary:
|
||||
signer: notary@home-assistant.io
|
||||
base_image: notary@home-assistant.io
|
||||
cosign:
|
||||
base_identity: https://github.com/home-assistant/docker-base/.*
|
||||
identity: https://github.com/home-assistant/supervisor/.*
|
||||
args:
|
||||
CAS_VERSION: 1.0.2
|
||||
COSIGN_VERSION: 2.0.2
|
||||
labels:
|
||||
io.hass.type: supervisor
|
||||
org.opencontainers.image.title: Home Assistant Supervisor
|
||||
|
@@ -20,7 +20,7 @@ pulsectl==23.5.2
|
||||
pyudev==0.24.1
|
||||
ruamel.yaml==0.17.21
|
||||
securetar==2023.3.0
|
||||
sentry-sdk==1.25.1
|
||||
sentry-sdk==1.26.0
|
||||
voluptuous==0.13.1
|
||||
dbus-fast==1.86.0
|
||||
typing_extensions==4.6.3
|
||||
|
@@ -9,7 +9,7 @@ pytest-aiohttp==1.0.4
|
||||
pytest-asyncio==0.18.3
|
||||
pytest-cov==4.1.0
|
||||
pytest-timeout==2.1.0
|
||||
pytest==7.3.2
|
||||
pytest==7.4.0
|
||||
pyupgrade==3.7.0
|
||||
time-machine==2.10.0
|
||||
typing_extensions==4.6.3
|
||||
|
@@ -1,4 +0,0 @@
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE03LvYuz79GTJx4uKp3w6NrSe5JZI
|
||||
iBtgzzYi0YQYtZO/r+xFpgDJEa0gLHkXtl94fpqrFiN89In83lzaszbZtA==
|
||||
-----END PUBLIC KEY-----
|
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"currentcontext": {
|
||||
"LcHost": "cas.codenotary.com",
|
||||
"LcPort": "443"
|
||||
},
|
||||
"schemaversion": 3,
|
||||
"users": null
|
||||
}
|
@@ -716,7 +716,7 @@ class Addon(AddonModel):
|
||||
"""
|
||||
if await self.instance.is_running():
|
||||
_LOGGER.warning("%s is already running!", self.slug)
|
||||
return
|
||||
return self._wait_for_startup()
|
||||
|
||||
# Access Token
|
||||
self.persist[ATTR_ACCESS_TOKEN] = secrets.token_hex(56)
|
||||
|
@@ -202,11 +202,18 @@ def initialize_system(coresys: CoreSys) -> None:
|
||||
_LOGGER.debug("Creating Supervisor media folder at '%s'", config.path_media)
|
||||
config.path_media.mkdir()
|
||||
|
||||
# Mounts folder
|
||||
# Mounts folders
|
||||
if not config.path_mounts.is_dir():
|
||||
_LOGGER.debug("Creating Supervisor mounts folder at '%s'", config.path_mounts)
|
||||
config.path_mounts.mkdir()
|
||||
|
||||
if not config.path_mounts_credentials.is_dir():
|
||||
_LOGGER.debug(
|
||||
"Creating Supervisor mounts credentials folder at '%s'",
|
||||
config.path_mounts_credentials,
|
||||
)
|
||||
config.path_mounts_credentials.mkdir(mode=0o600)
|
||||
|
||||
# Emergency folder
|
||||
if not config.path_emergency.is_dir():
|
||||
_LOGGER.debug(
|
||||
|
@@ -46,6 +46,7 @@ DNS_DATA = PurePath("dns")
|
||||
AUDIO_DATA = PurePath("audio")
|
||||
MEDIA_DATA = PurePath("media")
|
||||
MOUNTS_FOLDER = PurePath("mounts")
|
||||
MOUNTS_CREDENTIALS = PurePath(".mounts_credentials")
|
||||
EMERGENCY_DATA = PurePath("emergency")
|
||||
|
||||
DEFAULT_BOOT_TIME = datetime.utcfromtimestamp(0).isoformat()
|
||||
@@ -315,6 +316,16 @@ class CoreConfig(FileConfiguration):
|
||||
"""Return mounts path external for Docker."""
|
||||
return self.path_extern_supervisor / MOUNTS_FOLDER
|
||||
|
||||
@property
|
||||
def path_mounts_credentials(self) -> Path:
|
||||
"""Return mounts credentials folder."""
|
||||
return self.path_supervisor / MOUNTS_CREDENTIALS
|
||||
|
||||
@property
|
||||
def path_extern_mounts_credentials(self) -> PurePath:
|
||||
"""Return mounts credentials path external for Docker."""
|
||||
return self.path_extern_supervisor / MOUNTS_CREDENTIALS
|
||||
|
||||
@property
|
||||
def path_emergency(self) -> Path:
|
||||
"""Return emergency data folder."""
|
||||
|
@@ -10,7 +10,7 @@ SUPERVISOR_VERSION = "99.9.9dev"
|
||||
SERVER_SOFTWARE = f"HomeAssistantSupervisor/{SUPERVISOR_VERSION} aiohttp/{aiohttpversion} Python/{systemversion[0]}.{systemversion[1]}"
|
||||
|
||||
URL_HASSIO_ADDONS = "https://github.com/home-assistant/addons"
|
||||
URL_HASSIO_APPARMOR = "https://version.home-assistant.io/apparmor.txt"
|
||||
URL_HASSIO_APPARMOR = "https://version.home-assistant.io/apparmor_{channel}.txt"
|
||||
URL_HASSIO_VERSION = "https://version.home-assistant.io/{channel}.json"
|
||||
|
||||
SUPERVISOR_DATA = Path("/data")
|
||||
|
@@ -388,12 +388,38 @@ class CIFSMount(NetworkMount):
|
||||
options.append(f"vers={self.version}")
|
||||
|
||||
if self.username and self.password:
|
||||
options.extend([f"username={self.username}", f"password={self.password}"])
|
||||
options.append(f"credentials={self.path_extern_credentials.as_posix()}")
|
||||
else:
|
||||
options.append("guest")
|
||||
|
||||
return options
|
||||
|
||||
@property
|
||||
def path_credentials(self) -> Path:
|
||||
"""Path to credentials file."""
|
||||
return self.sys_config.path_mounts_credentials / self.name
|
||||
|
||||
@property
|
||||
def path_extern_credentials(self) -> PurePath:
|
||||
"""Path to credentials file external to Docker."""
|
||||
return self.sys_config.path_extern_mounts_credentials / self.name
|
||||
|
||||
async def mount(self) -> None:
|
||||
"""Mount using systemd."""
|
||||
if self.username and self.password:
|
||||
if not self.path_credentials.exists():
|
||||
self.path_credentials.touch(mode=0o600)
|
||||
|
||||
with self.path_credentials.open(mode="w") as cred_file:
|
||||
cred_file.write(f"username={self.username}\npassword={self.password}")
|
||||
|
||||
await super().mount()
|
||||
|
||||
async def unmount(self) -> None:
|
||||
"""Unmount using systemd."""
|
||||
self.path_credentials.unlink(missing_ok=True)
|
||||
await super().unmount()
|
||||
|
||||
|
||||
class NFSMount(NetworkMount):
|
||||
"""An NFS type mount."""
|
||||
|
@@ -34,8 +34,6 @@ RE_MOUNT_OPTION = re.compile(r"^[^,=]+$")
|
||||
VALIDATE_NAME = vol.Match(RE_MOUNT_NAME)
|
||||
VALIDATE_SERVER = vol.Match(RE_PATH_PART)
|
||||
VALIDATE_SHARE = vol.Match(RE_PATH_PART)
|
||||
VALIDATE_USERNAME = vol.Match(RE_MOUNT_OPTION)
|
||||
VALIDATE_PASSWORD = vol.Match(RE_MOUNT_OPTION)
|
||||
|
||||
_SCHEMA_BASE_MOUNT_CONFIG = vol.Schema(
|
||||
{
|
||||
@@ -57,8 +55,8 @@ SCHEMA_MOUNT_CIFS = _SCHEMA_MOUNT_NETWORK.extend(
|
||||
{
|
||||
vol.Required(ATTR_TYPE): MountType.CIFS.value,
|
||||
vol.Required(ATTR_SHARE): VALIDATE_SHARE,
|
||||
vol.Inclusive(ATTR_USERNAME, "basic_auth"): VALIDATE_USERNAME,
|
||||
vol.Inclusive(ATTR_PASSWORD, "basic_auth"): VALIDATE_PASSWORD,
|
||||
vol.Inclusive(ATTR_USERNAME, "basic_auth"): str,
|
||||
vol.Inclusive(ATTR_PASSWORD, "basic_auth"): str,
|
||||
vol.Optional(ATTR_VERSION, default=None): vol.Maybe(
|
||||
vol.Coerce(MountCifsVersion)
|
||||
),
|
||||
|
@@ -115,7 +115,7 @@ class Supervisor(CoreSysAttributes):
|
||||
|
||||
async def update_apparmor(self) -> None:
|
||||
"""Fetch last version and update profile."""
|
||||
url = URL_HASSIO_APPARMOR
|
||||
url = URL_HASSIO_APPARMOR.format(channel=self.sys_updater.channel.value)
|
||||
|
||||
# Fetch
|
||||
try:
|
||||
|
@@ -471,3 +471,22 @@ async def test_restore(
|
||||
start_task = await coresys.addons.restore(TEST_ADDON_SLUG, tarfile)
|
||||
|
||||
assert bool(start_task) is (status == "running")
|
||||
|
||||
|
||||
async def test_start_when_running(
|
||||
coresys: CoreSys,
|
||||
install_addon_ssh: Addon,
|
||||
container: MagicMock,
|
||||
caplog: pytest.LogCaptureFixture,
|
||||
) -> None:
|
||||
"""Test starting an addon without healthcheck."""
|
||||
container.status = "running"
|
||||
await install_addon_ssh.load()
|
||||
assert install_addon_ssh.state == AddonState.STARTED
|
||||
|
||||
caplog.clear()
|
||||
start_task = await install_addon_ssh.start()
|
||||
assert start_task
|
||||
await start_task
|
||||
|
||||
assert "local_ssh is already running" in caplog.text
|
||||
|
@@ -371,6 +371,7 @@ async def tmp_supervisor_data(coresys: CoreSys, tmp_path: Path) -> Path:
|
||||
coresys.config.path_emergency.mkdir()
|
||||
coresys.config.path_media.mkdir()
|
||||
coresys.config.path_mounts.mkdir()
|
||||
coresys.config.path_mounts_credentials.mkdir()
|
||||
coresys.config.path_backup.mkdir()
|
||||
coresys.config.path_tmp.mkdir()
|
||||
coresys.config.path_homeassistant.mkdir()
|
||||
|
@@ -3,6 +3,7 @@ from __future__ import annotations
|
||||
|
||||
import os
|
||||
from pathlib import Path
|
||||
import stat
|
||||
from typing import Any
|
||||
from unittest.mock import patch
|
||||
|
||||
@@ -78,8 +79,7 @@ async def test_cifs_mount(
|
||||
assert mount.where == Path("/mnt/data/supervisor/mounts/test")
|
||||
assert mount.local_where == tmp_supervisor_data / "mounts" / "test"
|
||||
assert mount.options == ["noserverino"] + expected_options + [
|
||||
f"username={mount_data['username']}",
|
||||
f"password={mount_data['password']}",
|
||||
"credentials=/mnt/data/supervisor/.mounts_credentials/test",
|
||||
]
|
||||
|
||||
assert not mount.local_where.exists()
|
||||
@@ -107,8 +107,7 @@ async def test_cifs_mount(
|
||||
["noserverino"]
|
||||
+ expected_options
|
||||
+ [
|
||||
f"username={mount_data['username']}",
|
||||
f"password={mount_data['password']}",
|
||||
"credentials=/mnt/data/supervisor/.mounts_credentials/test"
|
||||
]
|
||||
),
|
||||
),
|
||||
@@ -120,6 +119,19 @@ async def test_cifs_mount(
|
||||
[],
|
||||
)
|
||||
]
|
||||
assert mount.path_credentials.exists()
|
||||
with mount.path_credentials.open("r") as creds:
|
||||
assert creds.read().split("\n") == [
|
||||
f"username={mount_data['username']}",
|
||||
f"password={mount_data['password']}",
|
||||
]
|
||||
|
||||
cred_stat = mount.path_credentials.stat()
|
||||
assert not cred_stat.st_mode & stat.S_IRGRP
|
||||
assert not cred_stat.st_mode & stat.S_IROTH
|
||||
|
||||
await mount.unmount()
|
||||
assert not mount.path_credentials.exists()
|
||||
|
||||
|
||||
async def test_nfs_mount(
|
||||
@@ -279,7 +291,7 @@ async def test_unmount(
|
||||
systemd_service: SystemdService = all_dbus_services["systemd"]
|
||||
systemd_service.StopUnit.calls.clear()
|
||||
|
||||
mount = Mount.from_dict(
|
||||
mount: CIFSMount = Mount.from_dict(
|
||||
coresys,
|
||||
{
|
||||
"name": "test",
|
||||
|
@@ -3,13 +3,16 @@
|
||||
from datetime import timedelta
|
||||
from unittest.mock import AsyncMock, Mock, PropertyMock, patch
|
||||
|
||||
from aiohttp import ClientTimeout
|
||||
from aiohttp.client_exceptions import ClientError
|
||||
from awesomeversion import AwesomeVersion
|
||||
import pytest
|
||||
|
||||
from supervisor.const import UpdateChannel
|
||||
from supervisor.coresys import CoreSys
|
||||
from supervisor.docker.supervisor import DockerSupervisor
|
||||
from supervisor.exceptions import DockerError, SupervisorUpdateError
|
||||
from supervisor.host.apparmor import AppArmorControl
|
||||
from supervisor.resolution.const import ContextType, IssueType
|
||||
from supervisor.resolution.data import Issue
|
||||
from supervisor.supervisor import Supervisor
|
||||
@@ -83,3 +86,25 @@ async def test_update_failed(coresys: CoreSys, capture_exception: Mock):
|
||||
Issue(IssueType.UPDATE_FAILED, ContextType.SUPERVISOR)
|
||||
in coresys.resolution.issues
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"channel", [UpdateChannel.STABLE, UpdateChannel.BETA, UpdateChannel.DEV]
|
||||
)
|
||||
async def test_update_apparmor(
|
||||
coresys: CoreSys, channel: UpdateChannel, tmp_supervisor_data
|
||||
):
|
||||
"""Test updating apparmor."""
|
||||
coresys.updater.channel = channel
|
||||
with patch("supervisor.coresys.aiohttp.ClientSession.get") as get, patch.object(
|
||||
AppArmorControl, "load_profile"
|
||||
) as load_profile:
|
||||
get.return_value.__aenter__.return_value.status = 200
|
||||
get.return_value.__aenter__.return_value.text = AsyncMock(return_value="")
|
||||
await coresys.supervisor.update_apparmor()
|
||||
|
||||
get.assert_called_once_with(
|
||||
f"https://version.home-assistant.io/apparmor_{channel.value}.txt",
|
||||
timeout=ClientTimeout(total=10),
|
||||
)
|
||||
load_profile.assert_called_once()
|
||||
|
Reference in New Issue
Block a user