name: Build supervisor on: workflow_dispatch: inputs: channel: description: "Channel" required: true default: "dev" version: description: "Version" required: true publish: description: "Publish" required: true default: "false" stable: description: "Stable" required: true default: "false" pull_request: branches: ["main"] release: types: ["published"] push: branches: ["main"] paths: - "rootfs/**" - "supervisor/**" - build.yaml - Dockerfile - requirements.txt - setup.py env: DEFAULT_PYTHON: "3.12" BUILD_NAME: supervisor BUILD_TYPE: supervisor concurrency: group: "${{ github.workflow }}-${{ github.ref }}" cancel-in-progress: true jobs: init: name: Initialize build runs-on: ubuntu-latest outputs: architectures: ${{ steps.info.outputs.architectures }} version: ${{ steps.version.outputs.version }} channel: ${{ steps.version.outputs.channel }} publish: ${{ steps.version.outputs.publish }} requirements: ${{ steps.requirements.outputs.changed }} steps: - name: Checkout the repository uses: actions/checkout@v4.2.1 with: fetch-depth: 0 - name: Get information id: info uses: home-assistant/actions/helpers/info@master - name: Get version id: version uses: home-assistant/actions/helpers/version@master with: type: ${{ env.BUILD_TYPE }} - name: Get changed files id: changed_files if: steps.version.outputs.publish == 'false' uses: masesgroup/retrieve-changed-files@v3.0.0 - name: Check if requirements files changed id: requirements run: | if [[ "${{ steps.changed_files.outputs.all }}" =~ (requirements.txt|build.yaml) ]]; then echo "changed=true" >> "$GITHUB_OUTPUT" fi build: 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) }} steps: - name: Checkout the repository uses: actions/checkout@v4.2.1 with: fetch-depth: 0 - name: Write env-file if: needs.init.outputs.requirements == 'true' run: | ( # Fix out of memory issues with rust echo "CARGO_NET_GIT_FETCH_WITH_CLI=true" ) > .env_file - name: Build wheels if: needs.init.outputs.requirements == 'true' uses: home-assistant/wheels@2024.07.1 with: abi: cp312 tag: musllinux_1_2 arch: ${{ matrix.arch }} wheels-key: ${{ secrets.WHEELS_KEY }} apk: "libffi-dev;openssl-dev;yaml-dev" skip-binary: aiohttp env-file: true requirements: "requirements.txt" - name: Set version if: needs.init.outputs.publish == 'true' uses: home-assistant/actions/helpers/version@master with: type: ${{ env.BUILD_TYPE }} - name: Set up Python ${{ env.DEFAULT_PYTHON }} if: needs.init.outputs.publish == 'true' uses: actions/setup-python@v5.2.0 with: python-version: ${{ env.DEFAULT_PYTHON }} - name: Install Cosign if: needs.init.outputs.publish == 'true' uses: sigstore/cosign-installer@v3.7.0 with: cosign-release: "v2.4.0" - name: Install dirhash and calc hash if: needs.init.outputs.publish == 'true' run: | pip3 install setuptools 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' uses: docker/login-action@v3.3.0 with: registry: ghcr.io username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} - name: Set build arguments if: needs.init.outputs.publish == 'false' run: echo "BUILD_ARGS=--test" >> $GITHUB_ENV - name: Build supervisor uses: home-assistant/builder@2024.08.2 with: args: | $BUILD_ARGS \ --${{ matrix.arch }} \ --target /data \ --cosign \ --generic ${{ needs.init.outputs.version }} env: CAS_API_KEY: ${{ secrets.CAS_TOKEN }} version: name: Update version needs: ["init", "run_supervisor"] runs-on: ubuntu-latest steps: - name: Checkout the repository if: needs.init.outputs.publish == 'true' uses: actions/checkout@v4.2.1 - name: Initialize git if: needs.init.outputs.publish == 'true' uses: home-assistant/actions/helpers/git-init@master with: name: ${{ secrets.GIT_NAME }} email: ${{ secrets.GIT_EMAIL }} token: ${{ secrets.GIT_TOKEN }} - name: Update version file if: needs.init.outputs.publish == 'true' uses: home-assistant/actions/helpers/version-push@master with: key: ${{ env.BUILD_NAME }} version: ${{ needs.init.outputs.version }} channel: ${{ needs.init.outputs.channel }} run_supervisor: runs-on: ubuntu-latest name: Run the Supervisor needs: ["build", "init"] timeout-minutes: 60 steps: - name: Checkout the repository uses: actions/checkout@v4.2.1 - name: Build the Supervisor if: needs.init.outputs.publish != 'true' uses: home-assistant/builder@2024.08.2 with: args: | --test \ --amd64 \ --target /data \ --generic runner - name: Pull Supervisor 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 }} ghcr.io/home-assistant/amd64-hassio-supervisor:runner - name: Create the Supervisor run: | mkdir -p /tmp/supervisor/data docker create --name hassio_supervisor \ --privileged \ --security-opt seccomp=unconfined \ --security-opt apparmor=unconfined \ -v /run/docker.sock:/run/docker.sock \ -v /run/dbus:/run/dbus \ -v /tmp/supervisor/data:/data \ -v /etc/machine-id:/etc/machine-id:ro \ -e SUPERVISOR_SHARE="/tmp/supervisor/data" \ -e SUPERVISOR_NAME=hassio_supervisor \ -e SUPERVISOR_DEV=1 \ -e SUPERVISOR_MACHINE="qemux86-64" \ ghcr.io/home-assistant/amd64-hassio-supervisor:runner - name: Start the Supervisor run: docker start hassio_supervisor - name: Wait for Supervisor to come up run: | SUPERVISOR=$(docker inspect --format='{{.NetworkSettings.IPAddress}}' hassio_supervisor) ping="error" while [ "$ping" != "ok" ]; do ping=$(curl -sSL "http://$SUPERVISOR/supervisor/ping" | jq -r '.result') sleep 5 done - name: Check the Supervisor run: | echo "Checking supervisor info" test=$(docker exec hassio_cli ha supervisor info --no-progress --raw-json | jq -r '.result') if [ "$test" != "ok" ]; then exit 1 fi echo "Checking supervisor network info" test=$(docker exec hassio_cli ha network info --no-progress --raw-json | jq -r '.result') if [ "$test" != "ok" ]; then 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 exit 1 fi # Make sure it actually installed test=$(docker exec hassio_cli ha addons info core_ssh --no-progress --raw-json | jq -r '.data.version') if [[ "$test" == "null" ]]; then 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 exit 1 fi # Make sure its state is started test="$(docker exec hassio_cli ha addons info core_ssh --no-progress --raw-json | jq -r '.data.state')" if [ "$test" != "started" ]; then 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 security options --content-trust=true --no-progress --raw-json | jq -r '.result') if [ "$test" != "ok" ]; then 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 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 exit 1 fi echo "Check supervisor supported" test=$(docker exec hassio_cli ha resolution info --no-progress --raw-json | jq -r '.data.unsupported[]') if [[ "$test" =~ source_mods ]]; then exit 1 fi - name: Create full backup id: backup run: | test=$(docker exec hassio_cli ha backups new --no-progress --raw-json) if [ "$(echo $test | jq -r '.result')" != "ok" ]; then exit 1 fi echo "slug=$(echo $test | jq -r '.data.slug')" >> "$GITHUB_OUTPUT" - name: Uninstall SSH add-on run: | test=$(docker exec hassio_cli ha addons uninstall core_ssh --no-progress --raw-json | jq -r '.result') if [ "$test" != "ok" ]; then exit 1 fi - name: Restart supervisor run: | test=$(docker exec hassio_cli ha supervisor restart --no-progress --raw-json | jq -r '.result') if [ "$test" != "ok" ]; then exit 1 fi - name: Wait for Supervisor to come up run: | SUPERVISOR=$(docker inspect --format='{{.NetworkSettings.IPAddress}}' hassio_supervisor) ping="error" while [ "$ping" != "ok" ]; do ping=$(curl -sSL "http://$SUPERVISOR/supervisor/ping" | jq -r '.result') sleep 5 done - name: Restore SSH add-on from backup run: | test=$(docker exec hassio_cli ha backups restore ${{ steps.backup.outputs.slug }} --addons core_ssh --no-progress --raw-json | jq -r '.result') if [ "$test" != "ok" ]; then exit 1 fi # Make sure it actually installed test=$(docker exec hassio_cli ha addons info core_ssh --no-progress --raw-json | jq -r '.data.version') if [[ "$test" == "null" ]]; then exit 1 fi # Make sure its state is started test="$(docker exec hassio_cli ha addons info core_ssh --no-progress --raw-json | jq -r '.data.state')" if [ "$test" != "started" ]; then exit 1 fi - name: Restore SSL directory from backup run: | test=$(docker exec hassio_cli ha backups restore ${{ steps.backup.outputs.slug }} --folders ssl --no-progress --raw-json | jq -r '.result') if [ "$test" != "ok" ]; then exit 1 fi - name: Get supervisor logs on failiure if: ${{ cancelled() || failure() }} run: docker logs hassio_supervisor