* Use Unix socket for Supervisor to Core communication
Switch internal Supervisor-to-Core HTTP and WebSocket communication
from TCP (port 8123) to a Unix domain socket.
The existing /run/supervisor directory on the host (already mounted
at /run/os inside the Supervisor container) is bind-mounted into the
Core container at /run/supervisor. Core receives the socket path via
the SUPERVISOR_CORE_API_SOCKET environment variable, creates the
socket there, and Supervisor connects to it via aiohttp.UnixConnector
at /run/os/core.sock.
Since the Unix socket is only reachable by processes on the same host,
requests arriving over it are implicitly trusted and authenticated as
the existing Supervisor system user. This removes the token round-trip
where Supervisor had to obtain and send Bearer tokens on every Core
API call. WebSocket connections are likewise authenticated implicitly,
skipping the auth_required/auth handshake.
Key design decisions:
- Version-gated by CORE_UNIX_SOCKET_MIN_VERSION so older Core
versions transparently continue using TCP with token auth
- LANDINGPAGE is explicitly excluded (not a CalVer version)
- Hard-fails with a clear error if the socket file is unexpectedly
missing when Unix socket communication is expected
- WSClient.connect() for Unix socket (no auth) and
WSClient.connect_with_auth() for TCP (token auth) separate the
two connection modes cleanly
- Token refresh always uses the TCP websession since it is inherently
a TCP/Bearer-auth operation
- Logs which transport (Unix socket vs TCP) is being used on first
request
Closes#6626
Related Core PR: home-assistant/core#163907
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Close WebSocket on handshake failure and validate auth_required
Ensure the underlying WebSocket connection is closed before raising
when the handshake produces an unexpected message. Also validate that
the first TCP message is auth_required before sending credentials.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Fix pylint protected-access warnings in tests
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Check running container env before using Unix socket
Split use_unix_socket into two properties to handle the Supervisor
upgrade transition where Core is still running with a container
started by the old Supervisor (without SUPERVISOR_CORE_API_SOCKET):
- supports_unix_socket: version check only, used when creating the
Core container to decide whether to set the env var
- use_unix_socket: version check + running container env check, used
for communication decisions
This ensures TCP fallback during the upgrade transition while still
hard-failing if the socket is missing after Supervisor configured
Core to use it.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Improve Core API communication logging and error handling
- Remove transport log from make_request that logged before Core
container was attached, causing misleading connection logs
- Log "Connected to Core via ..." once on first successful API response
in get_api_state, when the transport is actually known
- Remove explicit socket existence check from session property, let
aiohttp UnixConnector produce natural connection errors during
Core startup (same as TCP connection refused)
- Add validation in get_core_state matching get_config pattern
- Restore make_request docstring
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Guard Core API requests with container running check
Add is_running() check to make_request and connect_websocket so no
HTTP or WebSocket connection is attempted when the Core container is
not running. This avoids misleading connection attempts during
Supervisor startup before Core is ready.
Also make use_unix_socket raise if container metadata is not available
instead of silently falling back to TCP. This is a defensive check
since is_running() guards should prevent reaching this state.
Add attached property to DockerInterface to expose whether container
metadata has been loaded.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Reset Core API connection state on container stop
Listen for Core container STOPPED/FAILED events to reset the
connection state: clear the _core_connected flag so the transport
is logged again on next successful connection, and close any stale
Unix socket session.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Only mount /run/supervisor if we use it
* Fix pytest errors
* Remove redundant is_running check from ingress panel update
The is_running() guard in update_hass_panel is now redundant since
make_request checks is_running() internally. Also mock is_running
in the websession test fixture since tests using it need make_request
to proceed past the container running check.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Bind mount /run/supervisor to Supervisor /run/os
Home Assistant OS (as well as the Supervised run scripts) bind mount
/run/supervisor to /run/os in Supervisor. Since we reuse this location
for the communication socket between Supervisor and Core, we need to
also bind mount /run/supervisor to Supervisor /run/os in CI.
* Wrap WebSocket handshake errors in HomeAssistantAPIError
Unexpected exceptions during the WebSocket handshake (KeyError,
ValueError, TypeError from malformed messages) are now wrapped in
HomeAssistantAPIError inside WSClient.connect/connect_with_auth.
This means callers only need to catch HomeAssistantAPIError.
Remove the now-unnecessary except (RuntimeError, ValueError,
TypeError) from proxy _websocket_client and add a proper error
message to the APIError per review feedback.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Narrow WebSocket handshake exception handling
Replace broad `except Exception` with specific exception types that
can actually occur during the WebSocket handshake: KeyError (missing
dict keys), ValueError (bad JSON), TypeError (non-text WS message),
aiohttp.ClientError (connection errors), and TimeoutError. This
avoids silently wrapping programming errors into HomeAssistantAPIError.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Remove unused create_mountpoint from MountBindOptions
The field was added but never used. The /run/supervisor host path
is guaranteed to exist since HAOS creates it for the Supervisor
container mount, so auto-creating the mountpoint is unnecessary.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Clear stale access token before raising on final retry
Move token clear before the attempt check in connect_websocket so
the stale token is always discarded, even when raising on the final
attempt. Without this, the next call would reuse the cached bad token
via _ensure_access_token's fast path, wasting a round-trip.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Add tests for Unix socket communication and Core API
Add tests for the new Unix socket communication path and improve
existing test coverage:
- Version-based supports_unix_socket and env-based use_unix_socket
- api_url/ws_url transport selection
- Connection lifecycle: connected log after restart, ignoring
unrelated container events
- get_api_state/check_api_state parameterized across versions,
responses, and error cases
- make_request is_running guard and TCP flow with real token fetch
- connect_websocket for both Unix and TCP (with token verification)
- WSClient.connect/connect_with_auth handshake success, errors,
cleanup on failure, and close with pending futures
Consolidate existing tests into parameterized form and drop synthetic
tests that covered very little.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Clean up old add-on builder images after build
After a Docker engine update, the add-on builder image (docker:*-cli)
is pulled with a new version tag, leaving old versions behind. Clean
up old builder images after each successful add-on build using the
existing cleanup_old_images method.
The cleanup is done after build because cleanup_old_images needs the
current image to exist, and the builder image is only pulled on first
build (in run_command) after a Docker engine update.
Also change ADDON_BUILDER_IMAGE to use the short name "docker" instead
of the canonical "docker.io/library/docker", as Docker stores images
under the short name and the reference filter in cleanup_old_images
does not match the canonical form.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Fix tests for short builder image name
Update test assertions to use the short "docker" image name
instead of the canonical "docker.io/library/docker".
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Improve Docker network test coverage and infrastructure
Add test cases for enable_ipv6=None (no user setting) to
test_network_recreation, verifying existing behavior where None
leaves the network unchanged. Use pytest.param with descriptive IDs
for better test readability.
Add create_network_mock side_effect to the docker fixture so network
creation returns realistic metadata built from the provided params.
Remove redundant manual create mock setups from individual tests.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Enable IPv6 on Supervisor network by default for all installations
Previously, IPv6 was only enabled by default for new installations
(when enable_ipv6 config was None). Existing installations with
IPv4-only networks were left unchanged unless the user explicitly
set enable_ipv6 to true.
Now, when no explicit IPv6 setting exists, the network is migrated
to dual-stack on next boot. The same safety checks apply: migration
is blocked if user containers are running and requires a reboot.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Consolidate Supervisor auto-update into updater reload task
The separate _update_supervisor task (24h interval) was redundant since
_reload_updater (previously ~7.5h interval) already triggered the same
update when a new version was found. This meant Supervisor updates were
effectively checked every 7.5h, undermining the intent of #6633 and
#6638 to reduce update frequency and registry pressure.
Merge the two code paths into one: _reload_updater now directly calls
_auto_update_supervisor (with the same job conditions) when a new
version is detected. The reload interval is increased from ~7.5h to 24h
to match the originally intended update cadence.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Add regression test for scheduled supervisor auto-update
Verify that the scheduled reload_updater task triggers exactly one
supervisor update when a new version is available. Uses event loop
time patching to simulate the 24h interval firing.
This guards against the previous bug where a separate _update_supervisor
task ran on its own schedule, causing duplicate update attempts.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Let OSError propagate during backup creation
Securetar's create_tar context manager uses a two-phase header write:
on enter it writes a placeholder tar header (size unknown), and on exit
_finalize_tar_entry seeks back to rewrite the header with the actual
size. If an OSError (e.g. ENOSPC) occurs mid-write, the inner tar entry
is left with truncated data and a placeholder header. Continuing to
write more entries on top of this produces a structurally invalid tar
file that cannot be restored.
Previously, _folder_save wrapped OSError as BackupError, which
store_folders then caught and swallowed — allowing the backup to
continue writing to an already corrupt outer tar. Similarly,
_create_finalize silently swallowed OSError when writing backup.json,
and the finally block in create() could raise a secondary OSError from
_close_outer_tarfile that replaced the original exception.
Securetar already distinguishes read vs write errors: read-side errors
(e.g. permission denied on a source file) are wrapped as AddFileError
(non-fatal, skip the file), while write-side OSError propagates as-is.
With this change, write-side OSError is wrapped as BackupFatalError
(a BackupError subclass) instead of plain BackupError. This ensures:
- store_folders/store_addons do not swallow it (they only catch
BackupError, and re-raise BackupFatalError explicitly).
- The job decorator handles it as a HassioError (no extra Sentry
event). Letting OSError bubble up raw would cause the job decorator
to treat it as an unhandled exception, capturing it to Sentry and
wrapping it as JobException — producing more Sentry noise, not less.
- _do_backup catches it via `except BackupError` and deletes the
incomplete backup file. This is the correct behavior since the tar
is structurally corrupt and not restorable.
Changes:
- Add BackupFatalError exception for write-side I/O errors.
- In create(), use except/else instead of finally so that finalization
is skipped when an error already occurred during yield. This prevents
a secondary exception from _close_outer_tarfile replacing the
original error.
- In _create_finalize, raise BackupFatalError on OSError instead of
swallowing it.
- In _folder_save, wrap OSError as BackupFatalError (not BackupError).
- In store_folders, re-raise BackupFatalError instead of swallowing.
- In store_supervisor_config, wrap OSError as BackupFatalError.
Fixes SUPERVISOR-B53
Fixes SUPERVISOR-1FAJ
Fixes SUPERVISOR-BJ4
Fixes SUPERVISOR-18KS
Fixes SUPERVISOR-1HE6
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Rename BackupFatalError to BackupFatalIOError
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Wait for systemd-timesyncd to stop before setting time
The previous 1-second sleep was not always enough for
systemd-timesyncd to fully stop, causing timedated to still reject
the set_time call with "Automatic time synchronization is enabled".
Instead, listen for the unit's ActiveState D-Bus property to become
inactive before proceeding, with a 10-second timeout.
Refs SUPERVISOR-92R
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Add wait_for_active_state helper to SystemdUnit
Centralize the repeated pattern of listening for D-Bus
PropertiesChanged signals to wait for a systemd unit's ActiveState
to reach a target state. Refactor core.py, host/firewall.py, and
mounts/mount.py to use the new helper.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Test time sync with active-to-inactive state transition
Exercise the actual wait_for_active_state signal-driven transition
in the time sync test: start the mock unit as "active" and drive it
to "inactive" via a PropertiesChanged signal, rather than starting
it as "inactive" which would make the wait a no-op.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Bump securetar from 2026.2.0 to 2026.4.1
Bumps [securetar](https://github.com/pvizeli/securetar) from 2026.2.0 to 2026.4.1.
- [Release notes](https://github.com/pvizeli/securetar/releases)
- [Commits](https://github.com/pvizeli/securetar/compare/2026.2.0...2026.4.1)
---
updated-dependencies:
- dependency-name: securetar
dependency-version: 2026.4.1
dependency-type: direct:production
update-type: version-update:semver-minor
...
Signed-off-by: dependabot[bot] <support@github.com>
* Avoid using SecureTarFile path attribute
Avoid using SecureTarFile path attribute which can be None. Instead,
introduce tar_path which can't be None and move backup existence check
before creating the SecureTarFile instance.
---------
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Stefan Agner <stefan@agner.ch>
* Change addons to apps in all user-facing strings
* Fix grammar in errors
* Apply suggestions from code review
Co-authored-by: Jan Čermák <sairon@users.noreply.github.com>
* Apply suggestions from code review
Co-authored-by: Stefan Agner <stefan@agner.ch>
---------
Co-authored-by: Jan Čermák <sairon@users.noreply.github.com>
Co-authored-by: Stefan Agner <stefan@agner.ch>
Explicitly allow Python 3.14 syntax for except clauses with multiple
exceptions without parentheses. Despite calling out Python 3.14, AI
commonly suggests to change this syntax.
* Make app builds work without build.yaml
The builds are moving build configuration into the Dockerfile itself (base
image defaults via `ARG`, labels via `LABEL`). This change makes `build.yaml`
optional for local app builds while preserving backward compatibility for apps
that still define it.
Key changes:
* Track whether `build.yaml` was found, log a warning if it is.
* Skip `BUILD_FROM` build arg when no build file exists, letting the
Dockerfile's own `ARG BUILD_FROM=...` default take effect.
* Always include all configured registry credentials in docker config instead
of matching only the base image's registry.
* Only set `io.hass.name` and `io.hass.description` labels when non-empty, as
they could be defined in the Dockerfile directly.
* Log a deprecation warning when `build.yaml` is present.
Refs home-assistant/epics#33
* Add-on -> app
* Remove FileConfiguration from AddonBuild base classes
Since we're deprecating usage of build.yaml, stop abusing the
FileConfiguration class for parsing the build file. The AddonBuild class
has been rewritten to be populated from the config file in an async
factory class method instead of in the overloaded load_file. While
cleaning up, the squash property has been removed as it's no longer used
anywhere and only the warning is printed if it's present in the parsed
config.
* Use sets for unhealthy and unsupported reasons
The unhealthy and unsupported reason collections in ResolutionManager
are unique by nature and used manual deduplication with list operations.
Convert them to sets for a more natural data structure fit.
At serialization boundaries (REST API and WebSocket events), use
sorted() to ensure deterministic output order.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Fix set usage in Sentry filter and test
The unhealthy set in the Sentry filter context needs sorted() for
serialization, and the test was using list subscript on the set.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The custom warning_handler sends warnings to Sentry via
capture_exception. When the Sentry SDK's own HTTP transport triggers a
warning (e.g. urllib3 InsecureRequestWarning due to broken CA certs),
this creates a self-inducing feedback loop: the warning is captured,
sent to Sentry, which triggers another warning, and so on.
Skip capture_exception for warnings originating from Sentry SDK
background threads (identified by the "sentry-sdk." thread name
prefix). Warnings are still logged normally via _LOGGER.warning.
A dedicated test validates that the SDK's BackgroundWorker thread uses
the expected naming convention, so any future SDK change will be caught.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Update devcontainer.json settings to work with the new systemd-based
devcontainer image (v4).
- Bump image tag to 4-supervisor to get the systemd-enabled image
- Set overrideCommand to false so the image's CMD (/sbin/init) runs
as PID 1 instead of being replaced by VS Code's default sleep command
- Set remoteUser to vscode to preserve the non-root shell experience
(required when overrideCommand is false, since VS Code no longer
injects its own user-switching wrapper)
- Add /var/lib/containerd volume mount because modern Docker uses the
containerd snapshotter, which stores layer data outside
/var/lib/docker
- Add tmpfs on /tmp to match typical systemd expectations and avoid
leftover state across container restarts
* Fix version/requirements parsing in setup.py, set version in Dockerfile
Remove the step patching const.py with detected version in CI and do
this during Dockerfile version from BUILD_VERSION argument instead.
Also, fix parsing of the version in `setup.py` - it wasn't working
because it was splitting the files on "/n" instead of newlines,
resulting in all Python packages installed having version string set to
`9999.9.9.dev9999` instead of the expected version.
(Note: setuptools are doing a version string normalization, so the
installed package has stripped leading zeroes and the second component
is `9` instead of the literal `09` used in default string in all places.
Fixing this is out of scope of this change as the ideal solution would
be to change the versioning schema but it should be noted.)
Lastly, clean up builder.yaml environment variables (crane is not used
anymore after #6679).
* Generate setuptools-compatible version for PR builds
For PR builds, we're using plain commit SHA as the version. This is
perfectly fine for Docker tags but it's not acceptable for Python
package version. By fixing the setup.py bug this error surfaced. Work it
around by setting the Package version to the string we used previously
suffixed by the commit SHA as build metadata (delimited by `+`).
When only the workflow changes, CI doesn't trigger rebuild when the PR
is merged to the `main` branch. Since it's a legitimate build trigger,
add it to the paths list.
The manifest step was failing because the image name wasn't set in the
env. Also we can standardize the workflow by using the shared matrix
prepare step.
* Remove CLI command hint from unknown error messages
Since #6303 introduced specific error messages for many cases,
the generic "check with 'ha supervisor logs'" hint in unknown
error messages is no longer as useful. Remove the CLI command
part while keeping the "Check supervisor logs for details" rider.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Use consistently "Supervisor logs" with capitalization
Co-authored-by: Jan Čermák <sairon@users.noreply.github.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Jan Čermák <sairon@users.noreply.github.com>
Publish multi-arch manifest (`hassio-supervisor` image) after the build
finishes. The step's `needs` are intentionally not matching `version`
step, as the build itself publishes the arch-prefixed image already, so
only build is needed for the manifest to be published as well.
Closes#6646
In #6347 we dropped the build for deprecated architectures and started
re-tagging of Supervisor 2025.11.5 images to make them available through
the tag of the latest version. This was to provide some interim period
of graceful handling of updates for devices which were not online at the
time when Supervisor dropped support for these architectures. As the
support was dropped almost 4 months ago already, the majority of users
should have hopefully migrated. The rest will now see Supervisor failing
to update with no message about architecture drop if they update from a
too old version. Since the re-tagged version also reported a failure to
update, the impact isn't so bad.
The "crypto" field in backup.json was introduced alongside encryption
support in 2018 to indicate the algorithm (aes128). Over time,
encryption moved into securetar and the field became write-only
metadata — no code reads it to make decisions. With securetar v3, the
field is now actively misleading since the actual encryption algorithm
differs from what "crypto": "aes128" suggests. Remove ATTR_CRYPTO and
CRYPTO_AES128 constants, stop writing "crypto" to new backups, and use
vol.Remove to silently strip the key when loading old backups that
still contain it.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Add specific error message for registry authentication failures
When a Docker image pull fails with 401 Unauthorized and registry
credentials are configured, raise DockerRegistryAuthError instead of
a generic DockerError. This surfaces a clear message to the user
("Docker registry authentication failed for <registry>. Check your
registry credentials") instead of "An unknown error occurred with
addon <name>".
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Add tests for registry authentication error handling
Test that a 401 during image pull raises DockerRegistryAuthError when
credentials are configured, and falls back to generic DockerError
when no credentials are present.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Add tests for addon install/update/rebuild auth failure handling
Test that DockerRegistryAuthError propagates correctly through
addon install, update, and rebuild paths without being wrapped
in a generic AddonUnknownError.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Include Docker registry configurations in backups
Docker registry credentials were removed from backup metadata in a prior
change to avoid exposing secrets in unencrypted data. Now that the encrypted
supervisor.tar inner archive exists, add docker.json alongside mounts.json
to securely backup and restore registry configurations.
On restore, registries from the backup are merged with any existing ones.
Old backups without docker.json are handled gracefully.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Increase test coverage by testing more error paths
* Address review feedback for Docker registry backup
Remove unnecessary dict() copy when serializing registries for backup
since the property already returns a dict.
Change DockerConfig.registries to use direct key access instead of
.get() with a default. The schema guarantees the key exists, and
.get() with a default would return a detached temporary dict that
silently discards updates.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Reuse IMAGE_REGISTRY_REGEX for docker_image validation
Replace the monolithic regex in docker_image validator with a
function-based approach that reuses get_registry_from_image() from
docker.utils for robust registry detection. This properly handles
domains, IPv4/IPv6 addresses, ports, and localhost while still
rejecting tags (managed separately by the add-on system).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Address review feedback: reorder checks for efficiency
Check falsy value before isinstance, and empty path before tag check,
as suggested in PR review.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
aiodocker derives ServerAddress for X-Registry-Auth by doing
image.partition("/"). For Docker Hub images like
"homeassistant/amd64-supervisor", this extracts "homeassistant"
(the namespace) instead of "docker.io" (the registry).
With the classic graphdriver image store, ServerAddress was never
checked and credentials were sent regardless. With the containerd
image store (default since Docker v29 / HAOS 15), the resolver
compares ServerAddress against the actual registry host and silently
drops credentials on mismatch, falling back to anonymous access.
Fix by prefixing Docker Hub images with "docker.io/" when registry
credentials are configured, so aiodocker sets ServerAddress correctly.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Added support for negative numbers in options
* Do not allow -. as float
* Added tests for integers and floats in options.
* Fixed ruff errors
* Added tests for outside of int/float limits
Besides file not found also catch "Too many levels of symbolic links"
which can happen when there are symbolic link loops in the add-on/apps
repository.
Also improve error handling in the repository update process to catch
OSError when checking for local modifications and raise a specific
error that can be handled appropriately.
Fixes SUPERVISOR-1FJ0
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* Include network storage mount configurations in backups
When creating backups, now stores mount configurations (CIFS/NFS shares)
including server, share, credentials, and other settings. When restoring
from a backup, mount configurations are automatically restored.
This fixes the issue where network storage definitions for backups
were lost after restoring from a backup, requiring users to manually
reconfigure their network storage mounts.
Changes:
- Add ATTR_MOUNTS schema to backup validation
- Add store_mounts() method to save mount configs during backup
- Add restore_mounts() method to restore mount configs during restore
- Add MOUNTS stage to backup/restore job stages
- Update BackupManager to call mount backup/restore methods
- Add tests for mount backup/restore functionality
Fixes home-assistant/core#148663
* Address reviewer feedback for mount backup/restore
Changes based on PR review:
- Store mount configs in encrypted mounts.tar instead of unencrypted
backup metadata (security fix for passwords)
- Separate mount restore into config save + async activation tasks
(mounts activate in background, failures don't block restore)
- Add replace_default_backup_mount parameter to control whether to
overwrite existing default mount setting
- Remove unnecessary broad exception handler for default mount setter
- Simplify schema: ATTR_MOUNTS is now just a boolean flag since
actual data is in the encrypted tar file
- Update tests to reflect new async API and return types
* Fix code review issues in mount backup/restore
- Add bind mount handling for MEDIA and SHARE usage types in
_activate_restored_mount() to mirror MountManager.create_mount()
- Fix double save_data() call by using needs_save flag
- Import MountUsage const for usage type checks
* Add pylint disable comments for protected member access
* Tighten broad exception handlers in mount backup restore
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Address second round of reviewer feedback
- Catch OSError separately and check errno.EBADMSG for drive health
- Validate mounts JSON against SCHEMA_MOUNTS_CONFIG before importing
- Use mount_data[ATTR_NAME] instead of .get("name", "unknown")
- Overwrite existing mounts on restore instead of skipping
- Move restore_mount/activate logic to MountManager (no more
protected-access in Backup)
- Drop unused replace_default_backup_mount parameter
- Fix test_backup_progress: add mounts stage to expected events
- Fix test_store_mounts: avoid create_mount which requires dbus
* Rename mounts.tar to supervisor.tar for generic supervisor config
Rename the inner tar from mounts.tar to supervisor.tar so it can hold
multiple config files (mounts.json now, docker credentials later).
Rename store_mounts/restore_mounts to store_supervisor_config/
restore_supervisor_config and update stage names accordingly.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Fix pylint protected-access and test timeouts in backup tests
- Add pylint disable comment for _mounts protected access in test_backup.py
- Mock restore_supervisor_config in test_full_backup_to_mount and
test_partial_backup_to_mount to avoid D-Bus mount activation during
restore that causes timeouts in the test environment
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Address agners review feedback
- Change create_inner_tar() to create_tar() per #6575
- Remove "r" argument from SecureTarFile (now read-only by default)
- Change warning to info for missing mounts tar (old backups won't have it)
- Narrow exception handler to (MountError, vol.Invalid, KeyError, OSError)
* Update supervisor/backups/backup.py
* Address agners feedback: remove metadata flag, add mount feature check
- Remove ATTR_SUPERVISOR boolean flag from backup metadata; instead
check for physical presence of supervisor.tar (like folder backups)
- Remove has_supervisor_config property
- Always attempt supervisor config restore (tar existence check handles it)
- Add HostFeature.MOUNT check in _activate_restored_mount before
attempting to activate mounts on systems without mount support
---------
Co-authored-by: Stefan Agner <stefan@agner.ch>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Mike Degatano <michael.degatano@gmail.com>