Compare commits

..

8 Commits

Author SHA1 Message Date
Ludeeus
c51496ad2f add missing id 2021-04-13 13:06:32 +00:00
Ludeeus
fbe409337b Add parrent_id 2021-04-13 12:55:20 +00:00
Ludeeus
443a43cc5b hex is str 2021-04-13 12:48:38 +00:00
Ludeeus
0e25fad1c0 Merge branch 'main' of github.com:home-assistant/supervisor into context 2021-04-13 12:44:45 +00:00
Ludeeus
488a2327fb Add name setter 2020-12-05 12:58:49 +00:00
Ludeeus
b99ed631c5 Add data to job 2020-12-05 12:44:17 +00:00
Ludeeus
726dd3a8f9 Merge branch 'main' of github.com:home-assistant/supervisor into context 2020-12-05 12:29:11 +00:00
Ludeeus
b94810d044 init 2020-11-27 16:10:39 +00:00
402 changed files with 9103 additions and 9768 deletions

View File

@@ -1,4 +1,4 @@
FROM mcr.microsoft.com/vscode/devcontainers/python:0-3.9
FROM mcr.microsoft.com/vscode/devcontainers/python:0-3.8
ENV DEBIAN_FRONTEND=noninteractive

View File

@@ -1,6 +1,8 @@
name: Bug Report Form
description: Report an issue related to the Home Assistant Supervisor.
about: Report an issue related to the Home Assistant Supervisor.
labels: bug
title: ""
issue_body: true
body:
- type: markdown
attributes:
@@ -88,11 +90,17 @@ body:
label: Anything in the Supervisor logs that might be useful for us?
description: >
The Supervisor logs can be found in the Supervisor panel -> System tab.
render: txt
- type: textarea
value: |
```txt
# Put your logs below this line
```
- type: markdown
attributes:
label: Additional information
description: >
value: |
## Additional information
- type: markdown
attributes:
value: |
If you have any additional information for us, use the field below.
Please note, you can attach screenshots or screen recordings here, by
dragging and dropping files in the field below.
Please note, you can attach screenshots or screen recordings here.

View File

@@ -35,7 +35,7 @@ on:
env:
BUILD_NAME: supervisor
BUILD_TYPE: supervisor
WHEELS_TAG: 3.9-alpine3.13
WHEELS_TAG: 3.8-alpine3.13
jobs:
init:
@@ -49,7 +49,7 @@ jobs:
requirements: ${{ steps.requirements.outputs.changed }}
steps:
- name: Checkout the repository
uses: actions/checkout@v2.3.4
uses: actions/checkout@v2
with:
fetch-depth: 0
@@ -71,7 +71,7 @@ jobs:
- name: Check if requirements files changed
id: requirements
run: |
if [[ "${{ steps.changed_files.outputs.all }}" =~ (requirements.txt|build.json) ]]; then
if [[ "${{ steps.changed_files.outputs.all }}" =~ requirements.txt ]]; then
echo "::set-output name=changed::true"
fi
@@ -84,7 +84,7 @@ jobs:
arch: ${{ fromJson(needs.init.outputs.architectures) }}
steps:
- name: Checkout the repository
uses: actions/checkout@v2.3.4
uses: actions/checkout@v2
with:
fetch-depth: 0
@@ -94,7 +94,7 @@ jobs:
with:
tag: ${{ env.WHEELS_TAG }}
arch: ${{ matrix.arch }}
wheels-host: wheels.hass.io
wheels-host: ${{ secrets.WHEELS_HOST }}
wheels-key: ${{ secrets.WHEELS_KEY }}
wheels-user: wheels
apk: "build-base;libffi-dev;openssl-dev;cargo"
@@ -109,14 +109,14 @@ jobs:
- name: Login to DockerHub
if: needs.init.outputs.publish == 'true'
uses: docker/login-action@v1.9.0
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login to GitHub Container Registry
if: needs.init.outputs.publish == 'true'
uses: docker/login-action@v1.9.0
uses: docker/login-action@v1
with:
registry: ghcr.io
username: ${{ secrets.GIT_USER }}
@@ -127,7 +127,7 @@ jobs:
run: echo "BUILD_ARGS=--test" >> $GITHUB_ENV
- name: Build supervisor
uses: home-assistant/builder@2021.05.0
uses: home-assistant/builder@2021.04.0
with:
args: |
$BUILD_ARGS \
@@ -135,6 +135,7 @@ jobs:
--target /data \
--with-codenotary "${{ secrets.VCN_USER }}" "${{ secrets.VCN_PASSWORD }}" "${{ secrets.VCN_ORG }}" \
--validate-from "${{ secrets.VCN_ORG }}" \
--validate-cache "${{ secrets.VCN_ORG }}" \
--generic ${{ needs.init.outputs.version }}
codenotary:
@@ -144,7 +145,7 @@ jobs:
steps:
- name: Checkout the repository
if: needs.init.outputs.publish == 'true'
uses: actions/checkout@v2.3.4
uses: actions/checkout@v2
with:
fetch-depth: 0
@@ -170,7 +171,7 @@ jobs:
steps:
- name: Checkout the repository
if: needs.init.outputs.publish == 'true'
uses: actions/checkout@v2.3.4
uses: actions/checkout@v2
- name: Initialize git
if: needs.init.outputs.publish == 'true'
@@ -191,14 +192,13 @@ jobs:
run_supervisor:
runs-on: ubuntu-latest
name: Run the Supervisor
needs: ["build", "codenotary", "init"]
needs: ["build", "codenotary"]
steps:
- name: Checkout the repository
uses: actions/checkout@v2.3.4
uses: actions/checkout@v2
- name: Build the Supervisor
if: needs.init.outputs.publish != 'true'
uses: home-assistant/builder@2021.05.0
uses: home-assistant/builder@2021.04.0
with:
args: |
--test \
@@ -206,12 +206,6 @@ jobs:
--target /data \
--generic runner
- name: Pull Supervisor
if: needs.init.outputs.publish == 'true'
run: |
docker pull homeassistant/amd64-hassio-supervisor:${{ needs.init.outputs.version }}
docker tag homeassistant/amd64-hassio-supervisor:${{ needs.init.outputs.version }} homeassistant/amd64-hassio-supervisor:runner
- name: Create the Supervisor
run: |
mkdir -p /tmp/supervisor/data
@@ -237,63 +231,22 @@ jobs:
SUPERVISOR=$(docker inspect --format='{{.NetworkSettings.IPAddress}}' hassio_supervisor)
ping="error"
while [ "$ping" != "ok" ]; do
ping=$(curl -sSL "http://$SUPERVISOR/supervisor/ping" | jq -r '.result')
ping=$(curl -sSL "http://$SUPERVISOR/supervisor/ping" | jq -r .result)
sleep 5
done
docker logs hassio_supervisor
- name: Check the Supervisor
run: |
echo "Checking supervisor info"
test=$(docker exec hassio_cli ha supervisor info --no-progress --raw-json | jq -r '.result')
test=$(docker exec hassio_cli ha supervisor info --no-progress --raw-json | jq -r .result)
if [ "$test" != "ok" ];then
docker logs hassio_supervisor
exit 1
fi
echo "Checking supervisor network info"
test=$(docker exec hassio_cli ha network info --no-progress --raw-json | jq -r '.result')
test=$(docker exec hassio_cli ha network info --no-progress --raw-json | jq -r .result)
if [ "$test" != "ok" ];then
docker logs hassio_supervisor
exit 1
fi
- name: Check the Store / Addon
run: |
echo "Install Core SSH Add-on"
test=$(docker exec hassio_cli ha addons install core_ssh --no-progress --raw-json | jq -r '.result')
if [ "$test" != "ok" ];then
docker logs hassio_supervisor
exit 1
fi
echo "Start Core SSH Add-on"
test=$(docker exec hassio_cli ha addons start core_ssh --no-progress --raw-json | jq -r '.result')
if [ "$test" != "ok" ];then
docker logs hassio_supervisor
exit 1
fi
- name: Check the Supervisor code sign
if: needs.init.outputs.publish == 'true'
run: |
echo "Enable Content-Trust"
test=$(docker exec hassio_cli ha supervisor options --content-trust=true --no-progress --raw-json | jq -r '.result')
if [ "$test" != "ok" ];then
docker logs hassio_supervisor
exit 1
fi
echo "Run supervisor health check"
test=$(docker exec hassio_cli ha resolution healthcheck --no-progress --raw-json | jq -r '.result')
if [ "$test" != "ok" ];then
docker logs hassio_supervisor
exit 1
fi
echo "Check supervisor unhealthy"
test=$(docker exec hassio_cli ha resolution info --no-progress --raw-json | jq -r '.data.unhealthy[]')
if [ "$test" != "" ];then
docker logs hassio_supervisor
exit 1
fi

View File

@@ -8,7 +8,7 @@ on:
pull_request: ~
env:
DEFAULT_PYTHON: 3.9
DEFAULT_PYTHON: 3.8
PRE_COMMIT_HOME: ~/.cache/pre-commit
jobs:
@@ -18,11 +18,11 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [3.9]
python-version: [3.8]
name: Prepare Python ${{ matrix.python-version }} dependencies
steps:
- name: Check out code from GitHub
uses: actions/checkout@v2.3.4
uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
id: python
uses: actions/setup-python@v2.2.2
@@ -66,7 +66,7 @@ jobs:
needs: prepare
steps:
- name: Check out code from GitHub
uses: actions/checkout@v2.3.4
uses: actions/checkout@v2
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
uses: actions/setup-python@v2.2.2
id: python
@@ -95,7 +95,7 @@ jobs:
needs: prepare
steps:
- name: Check out code from GitHub
uses: actions/checkout@v2.3.4
uses: actions/checkout@v2
- name: Register hadolint problem matcher
run: |
echo "::add-matcher::.github/workflows/matchers/hadolint.json"
@@ -110,7 +110,7 @@ jobs:
needs: prepare
steps:
- name: Check out code from GitHub
uses: actions/checkout@v2.3.4
uses: actions/checkout@v2
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
uses: actions/setup-python@v2.2.2
id: python
@@ -154,7 +154,7 @@ jobs:
needs: prepare
steps:
- name: Check out code from GitHub
uses: actions/checkout@v2.3.4
uses: actions/checkout@v2
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
uses: actions/setup-python@v2.2.2
id: python
@@ -186,7 +186,7 @@ jobs:
needs: prepare
steps:
- name: Check out code from GitHub
uses: actions/checkout@v2.3.4
uses: actions/checkout@v2
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
uses: actions/setup-python@v2.2.2
id: python
@@ -227,7 +227,7 @@ jobs:
needs: prepare
steps:
- name: Check out code from GitHub
uses: actions/checkout@v2.3.4
uses: actions/checkout@v2
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
uses: actions/setup-python@v2.2.2
id: python
@@ -271,7 +271,7 @@ jobs:
needs: prepare
steps:
- name: Check out code from GitHub
uses: actions/checkout@v2.3.4
uses: actions/checkout@v2
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
uses: actions/setup-python@v2.2.2
id: python
@@ -303,7 +303,7 @@ jobs:
needs: prepare
steps:
- name: Check out code from GitHub
uses: actions/checkout@v2.3.4
uses: actions/checkout@v2
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
uses: actions/setup-python@v2.2.2
id: python
@@ -343,11 +343,11 @@ jobs:
needs: prepare
strategy:
matrix:
python-version: [3.9]
python-version: [3.8]
name: Run tests Python ${{ matrix.python-version }}
steps:
- name: Check out code from GitHub
uses: actions/checkout@v2.3.4
uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2.2.2
id: python
@@ -405,7 +405,7 @@ jobs:
needs: pytest
steps:
- name: Check out code from GitHub
uses: actions/checkout@v2.3.4
uses: actions/checkout@v2
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
uses: actions/setup-python@v2.2.2
id: python
@@ -432,4 +432,4 @@ jobs:
coverage report
coverage xml
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v1.5.0
uses: codecov/codecov-action@v1.3.2

View File

@@ -11,7 +11,7 @@ jobs:
name: Release Drafter
steps:
- name: Checkout the repository
uses: actions/checkout@v2.3.4
uses: actions/checkout@v2
with:
fetch-depth: 0

View File

@@ -10,9 +10,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out code from GitHub
uses: actions/checkout@v2.3.4
uses: actions/checkout@v2
- name: Sentry Release
uses: getsentry/action-release@v1.1.5
uses: getsentry/action-release@v1.1
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_ORG: ${{ secrets.SENTRY_ORG }}

View File

@@ -9,7 +9,7 @@ jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v3.0.19
- uses: actions/stale@v3.0.18
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
days-before-stale: 60

View File

@@ -1,6 +1,6 @@
repos:
- repo: https://github.com/psf/black
rev: 21.5b1
rev: 20.8b1
hooks:
- id: black
args:

16
.vscode/tasks.json vendored
View File

@@ -4,7 +4,7 @@
{
"label": "Run Supervisor",
"type": "shell",
"command": "./scripts/supervisor.sh",
"command": "./scripts/run-supervisor.sh",
"group": {
"kind": "test",
"isDefault": true
@@ -15,6 +15,20 @@
},
"problemMatcher": []
},
{
"label": "Build Supervisor",
"type": "shell",
"command": "./scripts/build-supervisor.sh",
"group": {
"kind": "build",
"isDefault": true
},
"presentation": {
"reveal": "always",
"panel": "new"
},
"problemMatcher": []
},
{
"label": "Run Supervisor CLI",
"type": "shell",

View File

@@ -2,23 +2,17 @@
"image": "homeassistant/{arch}-hassio-supervisor",
"shadow_repository": "ghcr.io/home-assistant",
"build_from": {
"aarch64": "ghcr.io/home-assistant/aarch64-base-python:3.9-alpine3.13",
"armhf": "ghcr.io/home-assistant/armhf-base-python:3.9-alpine3.13",
"armv7": "ghcr.io/home-assistant/armv7-base-python:3.9-alpine3.13",
"amd64": "ghcr.io/home-assistant/amd64-base-python:3.9-alpine3.13",
"i386": "ghcr.io/home-assistant/i386-base-python:3.9-alpine3.13"
"aarch64": "ghcr.io/home-assistant/aarch64-base-python:3.8-alpine3.13",
"armhf": "ghcr.io/home-assistant/armhf-base-python:3.8-alpine3.13",
"armv7": "ghcr.io/home-assistant/armv7-base-python:3.8-alpine3.13",
"amd64": "ghcr.io/home-assistant/amd64-base-python:3.8-alpine3.13",
"i386": "ghcr.io/home-assistant/i386-base-python:3.8-alpine3.13"
},
"args": {
"VCN_VERSION": "0.9.4"
},
"labels": {
"io.hass.type": "supervisor",
"org.opencontainers.image.title": "Home Assistant Supervisor",
"org.opencontainers.image.description": "Container-based system for managing Home Assistant Core installation",
"org.opencontainers.image.source": "https://github.com/home-assistant/supervisor",
"org.opencontainers.image.authors": "The Home Assistant Authors",
"org.opencontainers.image.url": "https://www.home-assistant.io/",
"org.opencontainers.image.documentation": "https://www.home-assistant.io/docs/",
"org.opencontainers.image.licenses": "Apache License 2.0"
"org.opencontainers.image.source": "https://github.com/home-assistant/supervisor"
}
}

View File

@@ -37,7 +37,6 @@ disable=
too-many-return-statements,
too-many-statements,
unused-argument,
consider-using-with
[EXCEPTIONS]
overgeneral-exceptions=Exception

View File

@@ -1,20 +1,20 @@
aiohttp==3.7.4.post0
async_timeout==3.0.1
atomicwrites==1.4.0
attrs==21.2.0
awesomeversion==21.5.0
attrs==20.3.0
awesomeversion==21.4.0
brotli==1.0.9
cchardet==2.1.7
colorlog==5.0.1
colorlog==4.8.0
cpe==1.2.1
cryptography==3.4.6
debugpy==1.3.0
debugpy==1.2.1
docker==5.0.0
gitpython==3.1.17
jinja2==3.0.1
pulsectl==21.5.17
gitpython==3.1.14
jinja2==2.11.3
pulsectl==21.3.4
pytz==2021.1
pyudev==0.22.0
ruamel.yaml==0.15.100
sentry-sdk==1.1.0
sentry-sdk==1.0.0
voluptuous==0.12.1

View File

@@ -1,14 +1,14 @@
black==21.5b1
black==20.8b1
codecov==2.1.11
coverage==5.5
flake8-docstrings==1.6.0
flake8==3.9.2
pre-commit==2.13.0
pydocstyle==6.1.1
pylint==2.8.2
flake8==3.9.0
pre-commit==2.12.0
pydocstyle==6.0.0
pylint==2.7.4
pytest-aiohttp==0.3.0
pytest-asyncio==0.12.0 # NB!: Versions over 0.12.0 breaks pytest-aiohttp (https://github.com/aio-libs/pytest-aiohttp/issues/16)
pytest-cov==2.12.0
pytest-cov==2.11.1
pytest-timeout==1.4.2
pytest==6.2.4
pyupgrade==2.18.3
pytest==6.2.3
pyupgrade==2.12.0

28
scripts/build-supervisor.sh Executable file
View File

@@ -0,0 +1,28 @@
#!/bin/bash
source "${BASH_SOURCE[0]%/*}/common.sh"
set -eE
DOCKER_TIMEOUT=30
DOCKER_PID=0
function build_supervisor() {
docker pull homeassistant/amd64-builder:dev
docker run --rm \
--privileged \
-v /run/docker.sock:/run/docker.sock \
-v "$(pwd):/data" \
homeassistant/amd64-builder:dev \
--generic latest \
--target /data \
--test \
--amd64 \
--no-cache
}
echo "Build Supervisor"
start_docker
trap "stop_docker" ERR
build_supervisor

View File

@@ -4,9 +4,6 @@ function start_docker() {
local starttime
local endtime
update-alternatives --set iptables /usr/sbin/iptables-legacy || echo "Fails adjust iptables"
update-alternatives --set ip6tables /usr/sbin/iptables-legacy || echo "Fails adjust ip6tables"
echo "Starting docker."
dockerd 2> /dev/null &
DOCKER_PID=$!

View File

@@ -1,26 +1,12 @@
#!/bin/bash
source "${BASH_SOURCE[0]%/*}/common.sh"
source "${BASH_SOURCE[0]%/*}/build-supervisor.sh"
set -eE
DOCKER_TIMEOUT=30
DOCKER_PID=0
function build_supervisor() {
docker pull homeassistant/amd64-builder:dev
docker run --rm \
--privileged \
-v /run/docker.sock:/run/docker.sock \
-v "$(pwd):/data" \
homeassistant/amd64-builder:dev \
--generic latest \
--target /data \
--test \
--amd64 \
--no-cache
}
function cleanup_docker() {
echo "Cleaning up stopped containers..."

View File

@@ -426,20 +426,30 @@ class Addon(AddonModel):
@property
def devices(self) -> Set[Device]:
"""Extract devices from add-on options."""
options_schema = self.schema
with suppress(vol.Invalid):
options_schema.validate(self.options)
raw_schema = self.data[ATTR_SCHEMA]
if isinstance(raw_schema, bool) or not raw_schema:
return set()
return options_schema.devices
# Validate devices
options_validator = AddonOptions(self.coresys, raw_schema, self.name, self.slug)
with suppress(vol.Invalid):
options_validator(self.options)
return options_validator.devices
@property
def pwned(self) -> Set[str]:
"""Extract pwned data for add-on options."""
options_schema = self.schema
with suppress(vol.Invalid):
options_schema.validate(self.options)
raw_schema = self.data[ATTR_SCHEMA]
if isinstance(raw_schema, bool) or not raw_schema:
return set()
return options_schema.pwned
# Validate devices
options_validator = AddonOptions(self.coresys, raw_schema, self.name, self.slug)
with suppress(vol.Invalid):
options_validator(self.options)
return options_validator.pwned
def save_persist(self) -> None:
"""Save data of add-on."""
@@ -453,7 +463,7 @@ class Addon(AddonModel):
application = RE_WATCHDOG.match(url)
# extract arguments
t_port = int(application.group("t_port"))
t_port = application.group("t_port")
t_proto = application.group("t_proto")
s_prefix = application.group("s_prefix") or ""
s_suffix = application.group("s_suffix") or ""
@@ -477,8 +487,8 @@ class Addon(AddonModel):
# Make HTTP request
try:
url = f"{proto}://{self.ip_address}:{port}{s_suffix}"
async with self.sys_websession.get(
url, timeout=WATCHDOG_TIMEOUT, ssl=False
async with self.sys_websession_ssl.get(
url, timeout=WATCHDOG_TIMEOUT
) as req:
if req.status < 300:
return True
@@ -493,7 +503,7 @@ class Addon(AddonModel):
await self.sys_homeassistant.secrets.reload()
try:
options = self.schema.validate(self.options)
options = self.schema(self.options)
write_json_file(self.path_options, options)
except vol.Invalid as ex:
_LOGGER.error(

View File

@@ -9,7 +9,6 @@ from awesomeversion import AwesomeVersion
from ..const import (
ATTR_ARGS,
ATTR_BUILD_FROM,
ATTR_LABELS,
ATTR_SQUASH,
FILE_SUFFIX_CONFIGURATION,
META_ADDON,
@@ -47,12 +46,9 @@ class AddonBuild(FileConfiguration, CoreSysAttributes):
@property
def base_image(self) -> str:
"""Return base image for this add-on."""
if not self._data[ATTR_BUILD_FROM]:
return f"homeassistant/{self.sys_arch.default}-base:latest"
# Evaluate correct base image
arch = self.sys_arch.match(list(self._data[ATTR_BUILD_FROM].keys()))
return self._data[ATTR_BUILD_FROM][arch]
return self._data[ATTR_BUILD_FROM].get(
self.sys_arch.default, f"homeassistant/{self.sys_arch.default}-base:latest"
)
@property
def squash(self) -> bool:
@@ -64,11 +60,6 @@ class AddonBuild(FileConfiguration, CoreSysAttributes):
"""Return additional Docker build arguments."""
return self._data[ATTR_ARGS]
@property
def additional_labels(self) -> Dict[str, str]:
"""Return additional Docker labels."""
return self._data[ATTR_LABELS]
@property
def is_valid(self) -> bool:
"""Return true if the build env is valid."""
@@ -85,7 +76,7 @@ class AddonBuild(FileConfiguration, CoreSysAttributes):
"path": str(self.addon.path_location),
"tag": f"{self.addon.image}:{version!s}",
"pull": True,
"forcerm": not self.sys_dev,
"forcerm": True,
"squash": self.squash,
"labels": {
"io.hass.version": version,
@@ -93,7 +84,6 @@ class AddonBuild(FileConfiguration, CoreSysAttributes):
"io.hass.type": META_ADDON,
"io.hass.name": self._fix_label("name"),
"io.hass.description": self._fix_label("description"),
**self.additional_labels,
},
"buildargs": {
"BUILD_FROM": self.base_image,

View File

@@ -4,6 +4,7 @@ from pathlib import Path
from typing import Any, Awaitable, Dict, List, Optional
from awesomeversion import AwesomeVersion, AwesomeVersionException
import voluptuous as vol
from ..const import (
ATTR_ADVANCED,
@@ -531,16 +532,18 @@ class AddonModel(CoreSysAttributes, ABC):
return Path(self.path_location, "apparmor.txt")
@property
def schema(self) -> AddonOptions:
"""Return Addon options validation object."""
def schema(self) -> vol.Schema:
"""Create a schema for add-on options."""
raw_schema = self.data[ATTR_SCHEMA]
if isinstance(raw_schema, bool):
raw_schema = {}
return AddonOptions(self.coresys, raw_schema, self.name, self.slug)
return vol.Schema(
vol.All(dict, AddonOptions(self.coresys, raw_schema, self.name, self.slug))
)
@property
def schema_ui(self) -> Optional[List[Dict[any, any]]]:
def schema_ui(self) -> Optional[List[Dict[str, Any]]]:
"""Create a UI schema for add-on options."""
raw_schema = self.data[ATTR_SCHEMA]

View File

@@ -69,11 +69,6 @@ class AddonOptions(CoreSysAttributes):
self._name = name
self._slug = slug
@property
def validate(self) -> vol.Schema:
"""Create a schema for add-on options."""
return vol.Schema(vol.All(dict, self))
def __call__(self, struct):
"""Create schema validator for add-ons options."""
options = {}

View File

@@ -47,7 +47,6 @@ from ..const import (
ATTR_INIT,
ATTR_JOURNALD,
ATTR_KERNEL_MODULES,
ATTR_LABELS,
ATTR_LEGACY,
ATTR_LOCATON,
ATTR_MACHINE,
@@ -318,8 +317,9 @@ SCHEMA_BUILD_CONFIG = vol.Schema(
{vol.In(ARCH_ALL): vol.Match(RE_DOCKER_IMAGE_BUILD)}
),
vol.Optional(ATTR_SQUASH, default=False): vol.Boolean(),
vol.Optional(ATTR_ARGS, default=dict): vol.Schema({str: str}),
vol.Optional(ATTR_LABELS, default=dict): vol.Schema({str: str}),
vol.Optional(ATTR_ARGS, default=dict): vol.Schema(
{vol.Coerce(str): vol.Coerce(str)}
),
},
extra=vol.REMOVE_EXTRA,
)

View File

@@ -19,14 +19,13 @@ from .host import APIHost
from .info import APIInfo
from .ingress import APIIngress
from .jobs import APIJobs
from .middleware_security import SecurityMiddleware
from .multicast import APIMulticast
from .network import APINetwork
from .observer import APIObserver
from .os import APIOS
from .proxy import APIProxy
from .resolution import APIResoulution
from .security import APISecurity
from .security import SecurityMiddleware
from .services import APIServices
from .snapshots import APISnapshots
from .store import APIStore
@@ -83,7 +82,6 @@ class RestAPI(CoreSysAttributes):
self._register_snapshots()
self._register_supervisor()
self._register_store()
self._register_security()
await self.start()
@@ -148,18 +146,6 @@ class RestAPI(CoreSysAttributes):
]
)
def _register_security(self) -> None:
"""Register Security functions."""
api_security = APISecurity()
api_security.coresys = self.coresys
self.webapp.add_routes(
[
web.get("/security/info", api_security.info),
web.post("/security/options", api_security.options),
]
)
def _register_jobs(self) -> None:
"""Register Jobs functions."""
api_jobs = APIJobs()

View File

@@ -71,7 +71,6 @@ from ..const import (
ATTR_OPTIONS,
ATTR_PRIVILEGED,
ATTR_PROTECTED,
ATTR_PWNED,
ATTR_RATING,
ATTR_REPOSITORIES,
ATTR_REPOSITORY,
@@ -105,8 +104,9 @@ from ..const import (
from ..coresys import CoreSysAttributes
from ..docker.stats import DockerStats
from ..exceptions import APIError, APIForbidden, PwnedError, PwnedSecret
from ..utils.pwned import check_pwned_password
from ..validate import docker_ports
from .utils import api_process, api_process_raw, api_validate, json_loads
from .utils import api_process, api_process_raw, api_validate
_LOGGER: logging.Logger = logging.getLogger(__name__)
@@ -338,38 +338,30 @@ class APIAddons(CoreSysAttributes):
async def options_validate(self, request: web.Request) -> None:
"""Validate user options for add-on."""
addon = self._extract_addon_installed(request)
data = {ATTR_MESSAGE: "", ATTR_VALID: True, ATTR_PWNED: False}
options = await request.json(loads=json_loads) or addon.options
data = {ATTR_MESSAGE: "", ATTR_VALID: True}
# Validate config
options_schema = addon.schema
try:
options_schema.validate(options)
addon.schema(addon.options)
except vol.Invalid as ex:
data[ATTR_MESSAGE] = humanize_error(options, ex)
data[ATTR_MESSAGE] = humanize_error(addon.options, ex)
data[ATTR_VALID] = False
if not self.sys_security.pwned:
return data
# Validate security
if self.sys_config.force_security:
for secret in addon.pwned:
try:
await check_pwned_password(self.sys_websession, secret)
continue
except PwnedSecret:
data[ATTR_MESSAGE] = "Add-on use pwned secrets!"
except PwnedError as err:
data[
ATTR_MESSAGE
] = f"Error happening on pwned secrets check: {err!s}!"
# Pwned check
for secret in options_schema.pwned:
try:
await self.sys_security.verify_secret(secret)
continue
except PwnedSecret:
data[ATTR_PWNED] = True
except PwnedError:
data[ATTR_PWNED] = None
break
if self.sys_security.force and data[ATTR_PWNED] in (None, True):
data[ATTR_VALID] = False
if data[ATTR_PWNED] is None:
data[ATTR_MESSAGE] = "Error happening on pwned secrets check!"
else:
data[ATTR_MESSAGE] = "Add-on uses pwned secrets!"
data[ATTR_VALID] = False
break
return data
@@ -382,7 +374,7 @@ class APIAddons(CoreSysAttributes):
addon = self._extract_addon_installed(request)
try:
return addon.schema.validate(addon.options)
return addon.schema(addon.options)
except vol.Invalid:
raise APIError("Invalid configuration data for the add-on") from None

View File

@@ -1,200 +0,0 @@
"""Handle security part of this API."""
import logging
import re
from aiohttp.web import Request, RequestHandler, Response, middleware
from aiohttp.web_exceptions import HTTPForbidden, HTTPUnauthorized
from ..const import (
REQUEST_FROM,
ROLE_ADMIN,
ROLE_BACKUP,
ROLE_DEFAULT,
ROLE_HOMEASSISTANT,
ROLE_MANAGER,
CoreState,
)
from ..coresys import CoreSys, CoreSysAttributes
from .utils import api_return_error, excract_supervisor_token
_LOGGER: logging.Logger = logging.getLogger(__name__)
# fmt: off
# Block Anytime
BLACKLIST = re.compile(
r"^(?:"
r"|/homeassistant/api/hassio/.*"
r"|/core/api/hassio/.*"
r")$"
)
# Free to call or have own security concepts
NO_SECURITY_CHECK = re.compile(
r"^(?:"
r"|/homeassistant/api/.*"
r"|/homeassistant/websocket"
r"|/core/api/.*"
r"|/core/websocket"
r"|/supervisor/ping"
r")$"
)
# Observer allow API calls
OBSERVER_CHECK = re.compile(
r"^(?:"
r"|/.+/info"
r")$"
)
# Can called by every add-on
ADDONS_API_BYPASS = re.compile(
r"^(?:"
r"|/addons/self/(?!security|update)[^/]+"
r"|/addons/self/options/config"
r"|/info"
r"|/hardware/trigger"
r"|/services.*"
r"|/discovery.*"
r"|/auth"
r")$"
)
# Policy role add-on API access
ADDONS_ROLE_ACCESS = {
ROLE_DEFAULT: re.compile(
r"^(?:"
r"|/.+/info"
r"|/addons"
r")$"
),
ROLE_HOMEASSISTANT: re.compile(
r"^(?:"
r"|/core/.+"
r"|/homeassistant/.+"
r")$"
),
ROLE_BACKUP: re.compile(
r"^(?:"
r"|/snapshots.*"
r")$"
),
ROLE_MANAGER: re.compile(
r"^(?:"
r"|/addons(?:/[^/]+/(?!security).+|/reload)?"
r"|/audio/.+"
r"|/auth/cache"
r"|/cli/.+"
r"|/core/.+"
r"|/dns/.+"
r"|/docker/.+"
r"|/jobs/.+"
r"|/hardware/.+"
r"|/hassos/.+"
r"|/homeassistant/.+"
r"|/host/.+"
r"|/multicast/.+"
r"|/network/.+"
r"|/observer/.+"
r"|/os/.+"
r"|/resolution/.+"
r"|/snapshots.*"
r"|/store.*"
r"|/supervisor/.+"
r")$"
),
ROLE_ADMIN: re.compile(
r".*"
),
}
# fmt: on
class SecurityMiddleware(CoreSysAttributes):
"""Security middleware functions."""
def __init__(self, coresys: CoreSys):
"""Initialize security middleware."""
self.coresys: CoreSys = coresys
@middleware
async def system_validation(
self, request: Request, handler: RequestHandler
) -> Response:
"""Check if core is ready to response."""
if self.sys_core.state not in (
CoreState.STARTUP,
CoreState.RUNNING,
CoreState.FREEZE,
):
return api_return_error(
message=f"System is not ready with state: {self.sys_core.state.value}"
)
return await handler(request)
@middleware
async def token_validation(
self, request: Request, handler: RequestHandler
) -> Response:
"""Check security access of this layer."""
request_from = None
supervisor_token = excract_supervisor_token(request)
# Blacklist
if BLACKLIST.match(request.path):
_LOGGER.error("%s is blacklisted!", request.path)
raise HTTPForbidden()
# Ignore security check
if NO_SECURITY_CHECK.match(request.path):
_LOGGER.debug("Passthrough %s", request.path)
return await handler(request)
# Not token
if not supervisor_token:
_LOGGER.warning("No API token provided for %s", request.path)
raise HTTPUnauthorized()
# Home-Assistant
if supervisor_token == self.sys_homeassistant.supervisor_token:
_LOGGER.debug("%s access from Home Assistant", request.path)
request_from = self.sys_homeassistant
# Host
if supervisor_token == self.sys_plugins.cli.supervisor_token:
_LOGGER.debug("%s access from Host", request.path)
request_from = self.sys_host
# Observer
if supervisor_token == self.sys_plugins.observer.supervisor_token:
if not OBSERVER_CHECK.match(request.url):
_LOGGER.warning("%s invalid Observer access", request.path)
raise HTTPForbidden()
_LOGGER.debug("%s access from Observer", request.path)
request_from = self.sys_plugins.observer
# Add-on
addon = None
if supervisor_token and not request_from:
addon = self.sys_addons.from_token(supervisor_token)
# Check Add-on API access
if addon and ADDONS_API_BYPASS.match(request.path):
_LOGGER.debug("Passthrough %s from %s", request.path, addon.slug)
request_from = addon
elif addon and addon.access_hassio_api:
# Check Role
if ADDONS_ROLE_ACCESS[addon.hassio_role].match(request.path):
_LOGGER.info("%s access from %s", request.path, addon.slug)
request_from = addon
else:
_LOGGER.warning("%s no role for %s", request.path, addon.slug)
if request_from:
request[REQUEST_FROM] = request_from
return await handler(request)
_LOGGER.error("Invalid token for access %s", request.path)
raise HTTPForbidden()

View File

@@ -1,9 +1,9 @@
try {
new Function("import('/api/hassio/app/frontend_latest/entrypoint.f7e32a92.js')")();
new Function("import('/api/hassio/app/frontend_latest/entrypoint.4050b348.js')")();
} catch (err) {
var el = document.createElement('script');
el.src = '/api/hassio/app/frontend_es5/entrypoint.31c760ab.js';
el.src = '/api/hassio/app/frontend_es5/entrypoint.bcf8e8ff.js';
document.body.appendChild(el);
}

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
{"version":3,"file":"chunk.03b1407708a3c70f8eb1.js","sources":["webpack://home-assistant-frontend/chunk.03b1407708a3c70f8eb1.js"],"mappings":"AAAA","sourceRoot":""}

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
{"version":3,"file":"chunk.0a893a5a869ba682040b.js","sources":["webpack://home-assistant-frontend/chunk.0a893a5a869ba682040b.js"],"mappings":"AAAA","sourceRoot":""}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
{"version":3,"file":"chunk.1274df0d4f9b61110840.js","sources":["webpack://home-assistant-frontend/chunk.1274df0d4f9b61110840.js"],"mappings":"AAAA","sourceRoot":""}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
{"version":3,"file":"chunk.144785285e77c1827c0e.js","sources":["webpack://home-assistant-frontend/chunk.144785285e77c1827c0e.js"],"mappings":"AAAA","sourceRoot":""}

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
{"version":3,"file":"chunk.14b9f59fb8b277179b63.js","sources":["webpack://home-assistant-frontend/chunk.14b9f59fb8b277179b63.js"],"mappings":"AAAA","sourceRoot":""}

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
{"version":3,"file":"chunk.1e2dd1c788ee690c5db3.js","sources":["webpack://home-assistant-frontend/chunk.1e2dd1c788ee690c5db3.js"],"mappings":"AAAA","sourceRoot":""}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
{"version":3,"file":"chunk.23709353009814f6ec3d.js","sources":["webpack://home-assistant-frontend/chunk.23709353009814f6ec3d.js"],"mappings":"AAAA","sourceRoot":""}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
{"version":3,"file":"chunk.28ab065538efa89db557.js","sources":["webpack://home-assistant-frontend/chunk.28ab065538efa89db557.js"],"mappings":"AAAA","sourceRoot":""}

View File

@@ -1,2 +0,0 @@
(self.webpackChunkhome_assistant_frontend=self.webpackChunkhome_assistant_frontend||[]).push([[534],{68441:function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var l=new WeakMap;t.default=function(e){var t=l.get(e);return t||(t=Object.create(null),l.set(e,t)),t}},78643:function(e,t,l){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.PluralRules=void 0;var a=l(87480),n=l(64389),r=a.__importDefault(l(68441));function o(e,t){if(!(e instanceof u))throw new TypeError("Method Intl.PluralRules.prototype."+t+" called on incompatible receiver "+String(e))}function i(e,t,l,a){var n=a.IntegerDigits,r=a.NumberOfFractionDigits,o=a.FractionDigits;return u.localeData[e].fn(r?n+"."+o:n,"ordinal"===t)}var u=function(){function e(t,l){if(!(this&&this instanceof e?this.constructor:void 0))throw new TypeError("Intl.PluralRules must be called with 'new'");return n.InitializePluralRules(this,t,l,{availableLocales:e.availableLocales,relevantExtensionKeys:e.relevantExtensionKeys,localeData:e.localeData,getDefaultLocale:e.getDefaultLocale,getInternalSlots:r.default})}return e.prototype.resolvedOptions=function(){o(this,"resolvedOptions");var t=Object.create(null),l=r.default(this);return t.locale=l.locale,t.type=l.type,["minimumIntegerDigits","minimumFractionDigits","maximumFractionDigits","minimumSignificantDigits","maximumSignificantDigits"].forEach((function(e){var a=l[e];void 0!==a&&(t[e]=a)})),t.pluralCategories=a.__spreadArray([],e.localeData[t.locale].categories[t.type]),t},e.prototype.select=function(e){o(this,"select");var t=n.ToNumber(e);return n.ResolvePlural(this,t,{getInternalSlots:r.default,PluralRuleSelect:i})},e.prototype.toString=function(){return"[object Intl.PluralRules]"},e.supportedLocalesOf=function(t,l){return n.SupportedLocales(e.availableLocales,n.CanonicalizeLocaleList(t),l)},e.__addLocaleData=function(){for(var t=[],l=0;l<arguments.length;l++)t[l]=arguments[l];for(var a=0,n=t;a<n.length;a++){var r=n[a],o=r.data,i=r.locale;e.localeData[i]=o,e.availableLocales.add(i),e.__defaultLocale||(e.__defaultLocale=i)}},e.getDefaultLocale=function(){return e.__defaultLocale},e.localeData={},e.availableLocales=new Set,e.__defaultLocale="",e.relevantExtensionKeys=[],e.polyfilled=!0,e}();t.PluralRules=u;try{"undefined"!=typeof Symbol&&Object.defineProperty(u.prototype,Symbol.toStringTag,{value:"Intl.PluralRules",writable:!1,enumerable:!1,configurable:!0});try{Object.defineProperty(u,"length",{value:0,writable:!1,enumerable:!1,configurable:!0})}catch(c){}Object.defineProperty(u.prototype.constructor,"length",{value:0,writable:!1,enumerable:!1,configurable:!0}),Object.defineProperty(u.supportedLocalesOf,"length",{value:1,writable:!1,enumerable:!1,configurable:!0})}catch(s){}},25534:function(e,t,l){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var a=l(78643);l(27815).shouldPolyfill()&&Object.defineProperty(Intl,"PluralRules",{value:a.PluralRules,writable:!0,enumerable:!1,configurable:!0})},27815:function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.shouldPolyfill=void 0,t.shouldPolyfill=function(){return"undefined"==typeof Intl||!("PluralRules"in Intl)||"one"===new Intl.PluralRules("en",{minimumFractionDigits:2}).select(1)}}}]);
//# sourceMappingURL=chunk.28fb32d36188f80481fb.js.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"chunk.28fb32d36188f80481fb.js","sources":["webpack://home-assistant-frontend/chunk.28fb32d36188f80481fb.js"],"mappings":"AAAA","sourceRoot":""}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
{"version":3,"file":"chunk.2e5192dd0552c13e5623.js","sources":["webpack://home-assistant-frontend/chunk.2e5192dd0552c13e5623.js"],"mappings":"AAAA","sourceRoot":""}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,10 @@
/**
@license
Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at
http://polymer.github.io/LICENSE.txt The complete set of authors may be found at
http://polymer.github.io/AUTHORS.txt The complete set of contributors may be
found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by Google as
part of the polymer project is also subject to an additional IP rights grant
found at http://polymer.github.io/PATENTS.txt
*/

View File

@@ -0,0 +1 @@
{"version":3,"file":"chunk.3a2a2f6b4ddd0c4883f8.js","sources":["webpack://home-assistant-frontend/chunk.3a2a2f6b4ddd0c4883f8.js"],"mappings":";AAAA","sourceRoot":""}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
{"version":3,"file":"chunk.3a76f0ea2b0888f970db.js","sources":["webpack://home-assistant-frontend/chunk.3a76f0ea2b0888f970db.js"],"mappings":"AAAA","sourceRoot":""}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
{"version":3,"file":"chunk.3c156057c501c13568ee.js","sources":["webpack://home-assistant-frontend/chunk.3c156057c501c13568ee.js"],"mappings":"AAAA","sourceRoot":""}

View File

@@ -1 +0,0 @@
{"version":3,"file":"chunk.3e4f1650e26d55e933a8.js","sources":["webpack://home-assistant-frontend/chunk.3e4f1650e26d55e933a8.js"],"mappings":"AAAA","sourceRoot":""}

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
{"version":3,"file":"chunk.43b321e0aad0217c8441.js","sources":["webpack://home-assistant-frontend/chunk.43b321e0aad0217c8441.js"],"mappings":"AAAA","sourceRoot":""}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
{"version":3,"file":"chunk.480c85c27dcb0da9fc2a.js","sources":["webpack://home-assistant-frontend/chunk.480c85c27dcb0da9fc2a.js"],"mappings":"AAAA","sourceRoot":""}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
{"version":3,"file":"chunk.4e6beec37a57a13ae7aa.js","sources":["webpack://home-assistant-frontend/chunk.4e6beec37a57a13ae7aa.js"],"mappings":"AAAA","sourceRoot":""}

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
{"version":3,"file":"chunk.538953920415b56e91b4.js","sources":["webpack://home-assistant-frontend/chunk.538953920415b56e91b4.js"],"mappings":"AAAA","sourceRoot":""}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
{"version":3,"file":"chunk.555bab815b35ce22d731.js","sources":["webpack://home-assistant-frontend/chunk.555bab815b35ce22d731.js"],"mappings":"AAAA","sourceRoot":""}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,14 @@
/*! *****************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */

View File

@@ -0,0 +1 @@
{"version":3,"file":"chunk.69339833f81fc6a02f8b.js","sources":["webpack://home-assistant-frontend/chunk.69339833f81fc6a02f8b.js"],"mappings":";AAAA","sourceRoot":""}

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
{"version":3,"file":"chunk.777770ea47eb53322f9f.js","sources":["webpack://home-assistant-frontend/chunk.777770ea47eb53322f9f.js"],"mappings":"AAAA","sourceRoot":""}

File diff suppressed because one or more lines are too long

View File

@@ -1,14 +0,0 @@
/*! *****************************************************************************
Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
this file except in compliance with the License. You may obtain a copy of the
License at http://www.apache.org/licenses/LICENSE-2.0
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
MERCHANTABLITY OR NON-INFRINGEMENT.
See the Apache Version 2.0 License for specific language governing permissions
and limitations under the License.
***************************************************************************** */

View File

@@ -1 +0,0 @@
{"version":3,"file":"chunk.79a4fcb8f9ae3939760e.js","sources":["webpack://home-assistant-frontend/chunk.79a4fcb8f9ae3939760e.js"],"mappings":";AAAA","sourceRoot":""}

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
{"version":3,"file":"chunk.7c5f602fe5899e035790.js","sources":["webpack://home-assistant-frontend/chunk.7c5f602fe5899e035790.js"],"mappings":"AAAA","sourceRoot":""}

File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More