Commit Graph
5783 Commits
Author SHA1 Message Date
Stefan AgnerandClaude Opus 4.8 dd2bd88d1e Queue Home Assistant Core restart/stop behind a running start
The home_assistant_core job group used GROUP_REJECT for start, stop and
restart, so a restart (or stop) requested while Core is still starting was
rejected outright with "Another job is running for job group
home_assistant_core".

This breaks legitimate early restarts. For example, when Core applies a
reverted HTTP config it restarts itself during startup, which Supervisor
refused. Switch stop and restart to GROUP_QUEUE so such requests wait for
the in-progress start to finish and then run, instead of failing. start
keeps GROUP_REJECT; reentrant same-group calls (e.g. rebuild -> start) are
unaffected as the job group already allows them.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 13:41:36 +02:00
f49b81840e Add app-based mapping options for app configs (#6992)
* Rename addon map options to app equivalents

* Add tests for apps/addons default mount targets

* Fixes from feedback

* Fix tests and clean up validation logic a bit

* Update supervisor/apps/validate.py

* Apply suggestions from code review

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Stefan Agner <stefan@agner.ch>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026.07.1
2026-07-08 12:54:34 +02:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
c78cccf7dc Bump mypy from 2.1.0 to 2.2.0 (#7010)
Bumps [mypy](https://github.com/python/mypy) from 2.1.0 to 2.2.0.
- [Changelog](https://github.com/python/mypy/blob/master/CHANGELOG.md)
- [Commits](https://github.com/python/mypy/compare/v2.1.0...v2.2.0)

---
updated-dependencies:
- dependency-name: mypy
  dependency-version: 2.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-08 10:36:48 +02:00
3f58d33d9f Check OSError for known filesystem issues on cleanup unlinks (#7007)
Follow-up to review feedback on #7003 and #7004: when removing the
hosts file in CoreDNS.reset() or cleaning up a backup tarfile in
BackupManager.import_backup(), pass any OSError to
sys_resolution.check_oserror() so known filesystem issues (e.g.
EBADMSG) mark the system unhealthy early. For the backup paths the
check only applies to local locations (default and cloud backup),
matching the existing handling in remove() and _copy_to_location().

This also covers the second unlink in import_backup() (cleanup after
a failed load) and stops OSError from bubbling out of both cleanup
paths unhandled to the job: the error is now logged, and the method
still returns None or raises the original BackupInvalidError.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 20:30:43 +02:00
312e0c0e78 Only report systemd unit failures to Sentry on Home Assistant OS (#7009)
* Only run systemd unit failure check on Home Assistant OS

The systemd unit failure check added in #6976 creates a repair issue and
reports to Sentry for any failed unit on the host. On supervised
installations the first week of the 2026.07.0 rollout surfaced failed
units like gdm.service, tomcat8.service or isc-dhcp-server.service which
are unrelated to Home Assistant and not actionable for us. Skip the
check entirely when not running on Home Assistant OS, like the multiple
data disks check already does.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Keep creating issues on supervised, only skip the Sentry report

Per review, failed host units can still be useful information for the
admin of a supervised system, so keep creating resolution issues there.
Only the Sentry report is limited to Home Assistant OS, there is nothing
we can do about units of a supervised installation.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 20:27:02 +02:00
d08a9ee01d Ignore NetworkManager-wait-online.service unit failures (#7008)
The systemd unit failure check added in #6976 creates a repair issue and
reports to Sentry for any failed unit. NetworkManager-wait-online.service
is a oneshot unit which ends up in failed state whenever the network is
not up in time at boot. Within the first week of the 2026.07.0 rollout
this unit alone is one of the most frequent Sentry reports of this check
(72 users). Home Assistant works offline, so the failure is transient
and not actionable; skip the unit like the firewall service.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 19:13:11 +02:00
83d15aadcc Track installed OS update pending reboot activation (#7006)
* Track installed OS update pending reboot activation

Since #6982 the OS update no longer reboots the host automatically, so the
system keeps running the old version until the user reboots. In that window
the update kept being offered: need_update compares the running OS version,
which only changes on reboot. Requesting the same update again re-downloaded
and reinstalled the full image. Worse, a Supervisor restart in that window
dropped the in-memory REBOOT_REQUIRED issue and canceled the pending update
altogether, because mark_healthy marks the booted slot active on startup,
reverting the primary boot slot set by the rauc install.

Track the installed version awaiting a reboot as version_pending and expose
it in /os/info. A successful install sets it, updating again to that version
is rejected with a hint to reboot, and need_update no longer reports true for
an update that is already installed. On load, the pending state is recovered
from rauc by comparing the primary boot slot (via a new GetPrimary D-Bus
wrapper) with the booted slot, re-creating the REBOOT_REQUIRED issue as well.
mark_healthy now skips marking the booted slot active while an update is
pending.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Split pending update detection condition

Fix pylint R0916 (too-many-boolean-expressions) by splitting the guard in
_detect_pending_update into a slot data validity check and the actual
pending update check.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Report pending OS update as current version in /os/info

The Core update entity derives update availability by comparing version
with version_latest from /os/info, so it keeps offering an update that is
already installed until the system is rebooted. Report an installed update
pending activation as the current version so existing Core releases
reflect update availability correctly. Once Core consumes version_pending,
this can be limited to Core versions predating that support.

The hassos field of the root /info endpoint keeps reporting the running
version, Core only uses it as a HAOS presence check.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 18:45:18 +02:00
5bc795d2f2 Migrate simple attrs classes to stdlib dataclasses (#7005)
* Migrate simple attrs classes to stdlib dataclasses

Several plain data-holder classes still used the attrs library while
newer code in the project uses stdlib dataclasses. Convert
EventListener, Issue, Suggestion, HealthChanged, SupportedChanged,
Device, Message, HostEntry, ServiceInfo, WhoamiData and the scheduler
_Task to @dataclass, and switch the attr.evolve/attr.asdict call sites
to dataclasses.replace/asdict.

Field semantics are preserved: eq=False maps to compare=False,
hash=False and default factories map directly, and the frozen/slots
flags are kept, so equality, hashing and copy behavior are unchanged.
The jobs module keeps using attrs for its validators and setter hooks,
which have no stdlib dataclass equivalent.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Add slots to remaining dataclasses, freeze HostEntry

Address review feedback: ServiceInfo, Message and HostEntry kept the
flags of their attrs originals, which did not use slots. Enable slots
on all three. HostEntry instances are never mutated after creation, so
it can also be frozen. Message cannot be frozen because Discovery.send
updates the config field of an existing message when an app re-sends
a discovery message with changed configuration.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 18:38:31 +02:00
cae78036a4 Run blocking hosts unlink in executor in CoreDNS.reset (#7003)
CoreDNS.reset() called Path.unlink() directly on the hosts file, which
performs blocking file I/O on the event loop. The sibling write_hosts()
method in the same module already offloads its file write via
self.sys_run_in_executor(). Run the unlink in the executor as well for
consistency, keeping the existing OSError suppression.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026.07.0
2026-07-06 19:13:45 +02:00
f1d5bf43e6 Run blocking tarfile unlink in executor on backup import (#7004)
In BackupManager.import_backup(), the cleanup after a failed consolidate
called the blocking Path.unlink() directly on the event loop, while the
same tarfile removal elsewhere in the module already runs via
self.sys_run_in_executor(). Move this unlink to the executor as well for
consistency.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 19:13:03 +02:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
118380ccd2 Bump setuptools from 82.0.1 to 83.0.0 (#7001)
Bumps [setuptools](https://github.com/pypa/setuptools) from 82.0.1 to 83.0.0.
- [Release notes](https://github.com/pypa/setuptools/releases)
- [Changelog](https://github.com/pypa/setuptools/blob/main/NEWS.rst)
- [Commits](https://github.com/pypa/setuptools/compare/v82.0.1...v83.0.0)

---
updated-dependencies:
- dependency-name: setuptools
  dependency-version: 83.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-06 18:40:53 +02:00
4ba15fe965 Use local wheels for editable Supervisor install (#7002)
The editable install of the Supervisor package resolves its build backend
(setuptools, pinned via build-system.requires in pyproject.toml) in an
isolated build environment. Unlike the runtime requirements install, this
step was not given the locally built wheels, so it resolved build
dependencies solely from the configured package indexes.

When a pinned build dependency is newer than what the Home Assistant
musllinux wheels index currently carries (e.g. a Dependabot setuptools
bump), uv's default first-index strategy never falls through to PyPI and
the editable install fails with "No solution found".

Pass the locally built wheels via --find-links, mirroring the runtime
requirements step, so the isolated build environment can satisfy build
dependencies from them.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-06 18:31:14 +02:00
François MartinandGitHub 6ffd8d3e93 Fix backup delete error message (#7000) 2026-07-06 14:44:38 +02:00
Mike DegatanoandGitHub 35542d5bcc Replace addon with app in docker container names for apps (#6997)
* Support dual app/addon log identifiers during migration

* Use single journald epoch query for dual app identifiers

* Add API-keyed container epoch error handling

* Template CONTAINER_LOG_EPOCH via extra fields
2026-07-03 15:44:22 +02:00
4452eb9eca Don't roll back Core update when frontend probe can't connect over SSL (#6990)
* Don't roll back Core update when frontend probe can't connect over SSL

The post-update frontend probe added in #6811 connects to Core's
internal address as a plain external HTTP/WebSocket client. When Core is
configured with `ssl_peer_certificate` it requires mutual TLS, so it
resets the unauthenticated probe connection during the handshake. The
probe reported this as a failure and triggered a rollback even though
the update succeeded and the frontend was reachable through the user's
authenticated reverse proxy.

Supervisor only knows whether Core uses SSL, not whether a peer
certificate is required, so it can't tell mutual TLS apart from plain
HTTPS up front. Instead, distinguish how a probe fails: a bad response
(non-200, non-HTML, or a missing WebSocket auth_required frame) means
the endpoint is reachable but genuinely broken and still fails the
update; an inability to connect at all only triggers a rollback when
Core is not using SSL. When the probes can't connect while SSL is on, we
can't rule out mutual TLS rejecting us, so we fall back to a plain TCP
reachability check and otherwise rely on the component check.

This keeps the full HTML and WebSocket verification for plain HTTPS
setups while no longer rolling back updates for mutual-TLS deployments.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Roll back on frontend probe timeout instead of tolerating it under SSL

Mutual TLS (`ssl_peer_certificate`) rejects an unauthenticated connection
within a few handshake packets, so it surfaces as an immediate connection
reset, never as a timeout. Mapping a probe timeout to NO_RESPONSE therefore
granted it the mutual-TLS tolerance (the TCP reachability fallback) it should
not get: a probe that times out reached the listener but never answered,
which points to a genuinely hung frontend.

Map connect and request timeouts to BAD_RESPONSE so they still roll back the
update, and reserve NO_RESPONSE for connection resets and disconnects, the
actual mutual-TLS signal.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-03 15:41:42 +02:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
4a31c2af4c Bump coverage from 7.14.3 to 7.15.0 (#6998)
Bumps [coverage](https://github.com/coveragepy/coveragepy) from 7.14.3 to 7.15.0.
- [Release notes](https://github.com/coveragepy/coveragepy/releases)
- [Changelog](https://github.com/coveragepy/coveragepy/blob/main/CHANGES.rst)
- [Commits](https://github.com/coveragepy/coveragepy/compare/7.14.3...7.15.0)

---
updated-dependencies:
- dependency-name: coverage
  dependency-version: 7.15.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-03 10:07:14 +02:00
Mike DegatanoandGitHub 0ab08d0137 Refactor addon wording in non-compat comments (#6996) 2026-07-02 23:37:26 +02:00
Franck NijhofGitHubStefan Agnercopilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
618e1bfd8e Use zip() instead of range(len()) for paired iteration (#6961)
* Use zip() instead of range(len()) for paired iteration

Three list comprehensions paired a list with its asyncio.gather()
results by index using range(len(...)). Iterate the pairs directly with
zip() instead, which is clearer and drops the manual indexing. The
gather results match their input list in order and length, so the
behavior is unchanged.

* Update supervisor/backups/manager.py

Co-authored-by: Stefan Agner <stefan@agner.ch>

* Fix ruff format: wrap long zip() line in backups/manager.py

---------

Co-authored-by: Stefan Agner <stefan@agner.ch>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
2026-07-02 23:00:32 +02:00
84ad6b9446 Reject apps mapping a dynamic ingress port range port (#6989)
Dynamic ingress port selection (ingress_port: 0) picks a random port
from the 62000-65500 range and hands it to the app to listen on for
ingress. That port is reached over the internal Docker network only.

If an app also maps a container port from that range to the host, the
dynamically chosen ingress port could coincide with it. The ingress
endpoint would then be reachable directly on the host, bypassing ingress
authentication.

Reject such configs during validation instead: an app using dynamic
ingress port selection must not map a port from the dynamic ingress port
range itself. The range bounds are extracted into INGRESS_DYNAMIC_PORT_MIN
and INGRESS_DYNAMIC_PORT_MAX constants shared between the validator and
the allocator.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 11:42:14 +02:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
8f026ccd03 Bump sentry-sdk from 2.63.0 to 2.64.0 (#6991)
Bumps [sentry-sdk](https://github.com/getsentry/sentry-python) from 2.63.0 to 2.64.0.
- [Release notes](https://github.com/getsentry/sentry-python/releases)
- [Changelog](https://github.com/getsentry/sentry-python/blob/master/CHANGELOG.md)
- [Commits](https://github.com/getsentry/sentry-python/compare/2.63.0...2.64.0)

---
updated-dependencies:
- dependency-name: sentry-sdk
  dependency-version: 2.64.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-01 11:31:20 +02:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
200ad8a1e0 Bump home-assistant/wheels from 2026.06.0 to 2026.07.0 (#6988)
Bumps [home-assistant/wheels](https://github.com/home-assistant/wheels) from 2026.06.0 to 2026.07.0.
- [Release notes](https://github.com/home-assistant/wheels/releases)
- [Commits](https://github.com/home-assistant/wheels/compare/34957438948e0b3dcde73c77750643dadae594f5...9e17ab1ed5c4c79d8b61e29fa63de25ca2710716)

---
updated-dependencies:
- dependency-name: home-assistant/wheels
  dependency-version: 2026.07.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-30 14:51:19 +02:00
Mike DegatanoandGitHub a483d4a503 Make /os/update stop auto-rebooting after OS update (#6982)
* Make OS update require explicit reboot

* Avoid protected OS field access in API update tests
2026-06-30 14:49:24 +02:00
Mike DegatanoandGitHub a2fdcd43a4 Add unhealthy reasons for fsck failures and issues for other systemd failures (#6976)
* Add systemd ListUnitsFiltered support

* Add unhealthy reasons for fsck failures and issues for other systemd failures
2026-06-30 14:49:08 +02:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
c2d8ba0579 Bump actions/cache from 6.0.0 to 6.1.0 (#6986)
Bumps [actions/cache](https://github.com/actions/cache) from 6.0.0 to 6.1.0.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/2c8a9bd7457de244a408f35966fab2fb45fda9c8...55cc8345863c7cc4c66a329aec7e433d2d1c52a9)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-version: 6.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-30 13:20:59 +02:00
Mike DegatanoandGitHub 5c65da8a19 Refine Docker timeout handling and add regression tests (#6970)
* Refine Docker timeout handling and add regression tests

* Add network exception path tests for Docker manager

* Add timeout-path tests for Docker app and network

* Remove unnecessary timeout=None overrides from pull calls and tests
2026-06-26 15:15:10 +02:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
35f7d4fe53 Bump release-drafter/release-drafter from 7.4.0 to 7.5.1 (#6980)
Bumps [release-drafter/release-drafter](https://github.com/release-drafter/release-drafter) from 7.4.0 to 7.5.1.
- [Release notes](https://github.com/release-drafter/release-drafter/releases)
- [Commits](https://github.com/release-drafter/release-drafter/compare/ed4bc48ec97379be2258e7b7ac2624a3e26ab809...4d75298e00d9e34c483e5ff8c68d0ea1c1940c1e)

---
updated-dependencies:
- dependency-name: release-drafter/release-drafter
  dependency-version: 7.5.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-26 10:50:22 +02:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
c6c8e5a65e Bump ruff from 0.15.19 to 0.15.20 (#6981)
Bumps [ruff](https://github.com/astral-sh/ruff) from 0.15.19 to 0.15.20.
- [Release notes](https://github.com/astral-sh/ruff/releases)
- [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md)
- [Commits](https://github.com/astral-sh/ruff/compare/0.15.19...0.15.20)

---
updated-dependencies:
- dependency-name: ruff
  dependency-version: 0.15.20
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-26 09:55:13 +02:00
efc24f8e97 Run the mypy pre-commit hook the same way as CI (#6977)
mypy is a whole-program checker, but the pre-commit hook passed only the
changed files (with pass_filenames on) and added --ignore-missing-imports,
neither of which matches the CI command (mypy supervisor).

Passing only the changed files gives results that differ from a full run,
and because pre-commit splits a long file list and runs the hook
concurrently, the parallel mypy processes race on the shared SQLite cache
that is enabled by default since mypy 2.0 and crash with intermittent
INTERNAL ERRORs (python/mypy#21525). --ignore-missing-imports is also
redundant: the [tool.mypy] config already disables the import-not-found
and import-untyped error codes.

Set pass_filenames: false so the hook always checks the whole supervisor
package in a single invocation, add require_serial: true as a safeguard,
and drop --ignore-missing-imports so the hook matches mypy supervisor.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 17:27:46 +02:00
Mike DegatanoandGitHub 9d02546054 Require PR template in agent instructions (#6972) 2026-06-24 10:31:56 +02:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
9a13466357 Bump ruff from 0.15.18 to 0.15.19 (#6975)
Bumps [ruff](https://github.com/astral-sh/ruff) from 0.15.18 to 0.15.19.
- [Release notes](https://github.com/astral-sh/ruff/releases)
- [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md)
- [Commits](https://github.com/astral-sh/ruff/compare/0.15.18...0.15.19)

---
updated-dependencies:
- dependency-name: ruff
  dependency-version: 0.15.19
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-24 09:46:16 +02:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
ef163f9c80 Bump actions/setup-python from 6.2.0 to 6.3.0 (#6974)
Bumps [actions/setup-python](https://github.com/actions/setup-python) from 6.2.0 to 6.3.0.
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](https://github.com/actions/setup-python/compare/a309ff8b426b58ec0e2a45f0f869d46889d02405...ece7cb06caefa5fff74198d8649806c4678c61a1)

---
updated-dependencies:
- dependency-name: actions/setup-python
  dependency-version: 6.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-24 09:45:55 +02:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
1c22296ca3 Bump actions/cache from 5.0.5 to 6.0.0 (#6973)
Bumps [actions/cache](https://github.com/actions/cache) from 5.0.5 to 6.0.0.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/27d5ce7f107fe9357f9df03efb73ab90386fccae...2c8a9bd7457de244a408f35966fab2fb45fda9c8)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-version: 6.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-24 09:45:35 +02:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
32fad046e5 Bump coverage from 7.14.2 to 7.14.3 (#6969)
Bumps [coverage](https://github.com/coveragepy/coveragepy) from 7.14.2 to 7.14.3.
- [Release notes](https://github.com/coveragepy/coveragepy/releases)
- [Changelog](https://github.com/coveragepy/coveragepy/blob/main/CHANGES.rst)
- [Commits](https://github.com/coveragepy/coveragepy/compare/7.14.2...7.14.3)

---
updated-dependencies:
- dependency-name: coverage
  dependency-version: 7.14.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-23 19:58:44 +02:00
Franck NijhofandGitHub ee438155f8 List backup locations in parallel on reload (#6964)
BackupManager.reload listed the backup files of each location one after
another, awaiting a location's directory check and glob before starting
the next. With several locations (local, cloud backup, network mounts) a
slow or network-backed location held up listing all the others.

List the backup files of all locations concurrently with asyncio.gather
instead. Each listing already handles its own errors, and the results
are paired back with their location in order, so the behavior is
unchanged.
2026-06-23 16:32:26 +02:00
Mike DegatanoandGitHub 00c48a88ea Improve port conflict detection and resolution across Core and apps (#6916)
* Finalize port conflict handling and test coverage

* Fix port conflict regressions and align resolution tests

* Simplify port conflict detection: remove app options validation and manager helper

* Refactor approve_check and process_fixup to accept typed Issue/Suggestion objects

* Remove core port conflict detection; keep app startup handling

* Remove unused code

* Auto-dismiss issue on app start and remove more dead code
2026-06-23 16:26:56 +02:00
Mike DegatanoandGitHub 098867bbe2 Handle Docker status-check failures in Home Assistant API paths (#6955)
* Handle Docker status-check failures in Home Assistant API paths

* Remove empty timeout msg from error
2026-06-23 10:14:35 -04:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
637f3cdd4e Bump coverage from 7.14.1 to 7.14.2 (#6968)
Bumps [coverage](https://github.com/coveragepy/coveragepy) from 7.14.1 to 7.14.2.
- [Release notes](https://github.com/coveragepy/coveragepy/releases)
- [Changelog](https://github.com/coveragepy/coveragepy/blob/main/CHANGES.rst)
- [Commits](https://github.com/coveragepy/coveragepy/compare/7.14.1...7.14.2)

---
updated-dependencies:
- dependency-name: coverage
  dependency-version: 7.14.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-22 09:10:12 +02:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
d6dbb283f9 Bump deepmerge from 2.0 to 2.1.0 (#6967)
Bumps [deepmerge](https://github.com/toumorokoshi/deepmerge) from 2.0 to 2.1.0.
- [Release notes](https://github.com/toumorokoshi/deepmerge/releases)
- [Commits](https://github.com/toumorokoshi/deepmerge/compare/v2.0...v2.1.0)

---
updated-dependencies:
- dependency-name: deepmerge
  dependency-version: 2.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-22 09:10:01 +02:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
3788e5952f Bump pytest from 9.1.0 to 9.1.1 (#6966)
Bumps [pytest](https://github.com/pytest-dev/pytest) from 9.1.0 to 9.1.1.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/9.1.0...9.1.1)

---
updated-dependencies:
- dependency-name: pytest
  dependency-version: 9.1.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-22 09:02:16 +02:00
Franck NijhofandGitHub cd08532c2f Use a set for backup app slug lookups when removing delta apps (#6962)
remove_delta_apps checked membership against the app_list property for
every installed app. That property rebuilds a list on each access, so
the check rebuilt and linearly scanned it once per installed app.
Resolve the slugs into a set once before the loop for constant-time
membership checks. Behavior is unchanged.
2026-06-19 14:06:06 +02:00
Franck NijhofandGitHub cb4023569e Precompute bind mount paths in folder backup filter (#6956)
The per-file exclusion filter in folder backups looped over
sys_mounts.bound_mounts for every file. That property rebuilds a list
from a dict on each call, so backing up a folder with many files meant
rebuilding the list and scanning it linearly once per file.

Bind mounts don't change during a backup, so resolve the set of paths to
skip once up front and turn the per-file check into a single set
membership test.
2026-06-19 09:51:04 +02:00
Franck NijhofandGitHub 3c9af57d26 Allow slashes in add-on repository branch names (#6957)
Add-on repositories can pin a branch with the "url#branch" syntax. The
branch part of the repository regex only accepted word characters,
hyphens and dots, so a branch with a slash like "feature/hot-new-stuff"
failed to match and the repository was rejected as invalid.

Git branch names commonly use prefixes such as "feature/" or "fix/", so
allow slashes in the captured branch name.
2026-06-19 09:45:00 +02:00
dependabot[bot]andGitHub 5b52ea7a4c Bump actions/checkout from 6.0.3 to 7.0.0 (#6959)
Signed-off-by: dependabot[bot] <support@github.com>
2026-06-19 08:41:34 +02:00
dependabot[bot]andGitHub 04a03996d7 Bump ruff from 0.15.17 to 0.15.18 (#6960)
Signed-off-by: dependabot[bot] <support@github.com>
2026-06-19 08:41:18 +02:00
1857753e22 Redact app options in info for unprivileged apps (#6953)
The `/addons/{slug}/info` endpoint returned the target app's user options,
which can contain secrets such as passwords and API keys. The security
middleware grants every role (including the default role) access to any
`/.+/info` path, so an installed app with `hassio_api: true` and the default
role could read another app's options simply by requesting its info.

Redact the options field in info_data() unless the caller is entitled to see
it: Home Assistant Core (and other non-app internals), the app reading its
own info, or an app with the manager or admin role. Other apps reading a
different app's info now receive an empty options dict while all non-secret
metadata stays available for discovery. This mirrors the existing self-only
restriction on the dedicated /options/config endpoint.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-18 14:54:57 +02:00
95bb8fe6ab Make Core.shutdown idempotent and safe to call concurrently (#6891)
* Make Core.shutdown idempotent and safe to call concurrently

After #6887, Core.shutdown() now runs in the SIGTERM path during host
shutdown in addition to the existing host.control reboot/shutdown and
backup restore paths. Multiple concurrent callers were possible (e.g.
SIGTERM arriving while a reboot API call is mid-flight), so __main__.py
debounced the signal handler by stashing the in-flight task in a single-
element list and bailing out on the second SIGTERM.

Move the idempotency into Core.shutdown() itself, where it belongs:

- A second call while shutdown is in progress awaits the in-flight
  shutdown via an asyncio.Event rather than re-running the sequence.
- Calls during STOPPING/CLOSE return early (Supervisor is already going
  away; the work is moot).
- Calls during STARTING_STATES (INITIALIZE/STARTUP/SETUP) return early
  too. There is nothing coherent to gracefully stop before startup
  completes, and on the SIGTERM-during-startup path the caller cancels
  startup_task first, so waiting for it to complete would deadlock.
- The sequence is wrapped in try/finally so the completion event is set
  even when an inner step raises.

With that in place the closure workaround in __main__.py collapses to a
plain coresys.create_task(stop_supervisor()): repeat SIGTERMs spawn
extra tasks but each just observes the in-flight shutdown and waits.

Tests cover the four state branches and confirm the event is reset
between repeated shutdown cycles (backup restore re-enters RUNNING).

* Split Core.shutdown() into teardown_services + shutdown

PR feedback (@mdegat01) flagged the "supports repeated use" comment on
_shutdown_event.clear() as describing a use case that does not exist.
Investigating, the real source of confusion is that the old shutdown()
did two different things stitched together:

  - Stop user-facing containers (add-ons + Home Assistant Core), which
    backup restore uses while leaving the host alone.
  - Run the full shutdown ceremony (state transition to SHUTDOWN, stop
    plugins), which only the SIGTERM signal handler and the host
    reboot/power-off API want.

That dispatch was implemented with an asymmetric state transition
("only set SHUTDOWN if state == RUNNING") and a plugin-shutdown gate
("only stop plugins if state in (STOPPING, SHUTDOWN)"). It worked but
made the intent of each branch hard to read, broke the reentrancy
guard on the restore path (state never reaches SHUTDOWN, so concurrent
callers fall through every early return), and forced the misleading
"repeated cycles" framing on the event handling.

Split into two methods with one job each:

  - teardown_services(): stop add-ons + Home Assistant Core. Does not
    change Core state and does not stop plugins. Backup restore calls
    this directly so HA Core's watchdog stays registered (it only
    disables on transitions into CLOSING_STATES) and plugins keep
    running for the restore body to use.
  - shutdown(): real shutdown ceremony. Unconditionally transitions to
    SHUTDOWN, calls teardown_services(), then stops plugins. The
    reentrancy guard (state == SHUTDOWN -> await event) now works
    correctly because every caller transitions state on entry. One-shot
    per process lifetime; no clear() needed.

Update backups/manager.py:867 to call teardown_services() instead.
remove_homeassistant_container moves to teardown_services() since
restore is the only caller that passes it.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* Release shutdown waiters when set_state() is cancelled

PR feedback from Copilot: set_state() updates Core._state synchronously
(line 84 in core.py) before awaiting _write_run_state(). If the
shutdown task is cancelled while awaiting that write, in-memory state
is already SHUTDOWN but the function exits before entering the
try/finally that sets _shutdown_event. Any concurrent or later
shutdown() caller then sees state == SHUTDOWN and blocks forever on
_shutdown_event.wait().

Move the set_state(SHUTDOWN) call inside the try so finally always
runs and releases waiters. CancelledError still propagates to the
caller after finally as expected; we just no longer leak the lock.

Add a regression test that simulates cancellation inside
_write_run_state() and asserts both that state has moved to SHUTDOWN
and that _shutdown_event is set.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-17 17:21:03 +02:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
5110f78edf Bump sentry-sdk from 2.62.0 to 2.63.0 (#6952)
Bumps [sentry-sdk](https://github.com/getsentry/sentry-python) from 2.62.0 to 2.63.0.
- [Release notes](https://github.com/getsentry/sentry-python/releases)
- [Changelog](https://github.com/getsentry/sentry-python/blob/master/CHANGELOG.md)
- [Commits](https://github.com/getsentry/sentry-python/compare/2.62.0...2.63.0)

---
updated-dependencies:
- dependency-name: sentry-sdk
  dependency-version: 2.63.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-17 10:23:03 +02:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
dcb31f3f9f Bump release-drafter/release-drafter from 7.3.1 to 7.4.0 (#6951)
Bumps [release-drafter/release-drafter](https://github.com/release-drafter/release-drafter) from 7.3.1 to 7.4.0.
- [Release notes](https://github.com/release-drafter/release-drafter/releases)
- [Commits](https://github.com/release-drafter/release-drafter/compare/693d20e7c1ce1a81d3a41962f85914253b518449...ed4bc48ec97379be2258e7b7ac2624a3e26ab809)

---
updated-dependencies:
- dependency-name: release-drafter/release-drafter
  dependency-version: 7.4.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-17 10:22:11 +02:00
81e235376e Fix typos repo-wide and add codespell pre-commit hook (#6949)
* Fix typos in comments, docstrings and log messages

Correct 39 spelling mistakes across comments, docstrings and log/error
message strings throughout the package (e.g. "conection" -> "connection",
"Incomming" -> "Incoming", "Rasie" -> "Raise"). All changes are confined
to human-readable text; no identifiers, attributes or D-Bus contracts are
touched, so there is no behavior change. Found with codespell.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Fix typos in tests and CI workflow

Correct spelling mistakes in test comments, docstrings and data, plus one
in the builder workflow, so the whole tree is clean for the codespell hook
added next. The assertion in test_network_manager.py is updated to match
the corrected "Unknown error while processing" log message in the source.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Add codespell pre-commit hook

Wire up codespell so spelling mistakes in comments, docstrings and strings
are caught automatically. The vendored frontend panel is excluded, and
"hass" and "astroid" are added to the ignore list as known false positives
(the Home Assistant abbreviation and the pylint dependency package).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Address review feedback

Improve grammar in several of the touched comments and docstrings: use the
plural "ignore conditions" for the list-returning property, add the missing
auxiliary verb and fix agreement in the timezone-filter comment, fix
"backups ... use" agreement, and reword "underlay" to "underlying" in the
arch module docstring.

Also drop the "*.json" skip from the codespell hook. It was carried over
from another project but is unnecessary here (all tracked JSON is clean),
and skipping it would needlessly leave translation and data JSON unchecked.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Reword onboarding comment

"overflight" was a literal calque of the German "überflogen"; use the
idiomatic "skimmed through" instead.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026.06.2
2026-06-16 14:09:16 +02:00
dae48c62e4 Treat mount errors as API errors instead of unexpected failures (#6946)
Mount failures generally reflect user configuration or host conditions
(unreachable server, wrong credentials, ...) rather than a Supervisor
bug. As a plain HassioError, MountError reached the generic error branch
of api_process, which logged a full traceback as an "Unexpected error
during API call" and captured the exception to Sentry. The mount reload
path already encoded the opposite intent by explicitly skipping Sentry
for MountError.

Make MountError an APIError so mount failures are surfaced as client-side
errors with their explicit message, without a traceback or Sentry noise,
matching the existing JobException handling. MountNotFound additionally
inherits from APINotFound so it returns a 404 instead of a 400.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 09:32:22 +02:00