* 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>
Add check_oserror() method to ResolutionManager with an extensible
errno-to-unhealthy-reason mapping. Replace ~20 inline
`if err.errno == errno.EBADMSG` checks across 14 files with a single
call to self.sys_resolution.check_oserror(err). This makes it easy to
add handling for additional filesystem errors (e.g. EIO, ENOSPC) in
one place.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Migrate builder workflow to new builder actions
Migrate Supervisor image build to new builder actions. The resulting images
should be identical to those built by the builder.
Refs #6646 - does not implement multi-arch manifest publishing (will be done in
a follow-up)
* Update devcontainer version to 3
systemd only emits bus signals (including PropertiesChanged) when at
least one client has called Subscribe() on the Manager interface. On
regular HAOS systems, systemd-logind calls Subscribe which enables
signals for all bus clients. However, in environments without
systemd-logind (such as the Supervisor devcontainer with systemd), no
signals are emitted, causing the firewall unit wait to time out.
Explicitly calling Subscribe() has no downsides and makes it clear
that the Supervisor relies on these signals. There is no need to call
Unsubscribe() as systemd automatically tracks clients and stops
emitting signals when all subscribers have disconnected from the bus.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add iptables rules via a systemd transient unit to drop traffic
addressed to the bridge gateway IP from non-bridge interfaces.
The firewall manager waits for the transient unit to complete and
verifies success via D-Bus property change signals. On failure, the
system is marked unhealthy and host-network add-ons are prevented
from booting.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Further slow down automatic update rollout to reduce pressure on container
registry infrastructure (GHCR rate limiting). Plugins are staggered 2 minutes
apart starting at 12h, Supervisor moves from 12h to 24h.
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Slow down the automatic Supervisor update rollout to reduce pressure
on the container registry infrastructure (GHCR rate limiting).
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* Wait for addon startup task before unload to prevent data access race
Replace the cancel-based approach in unload() with an await of the outer
_wait_for_startup_task. The container removal and state change resolve the
startup event naturally, so we just need to ensure the task completes
before addon data is removed. This prevents a KeyError on self.name access
when _wait_for_startup times out after data has been removed.
Also simplify _wait_for_startup by removing the unnecessary inner task
wrapper — asyncio.wait_for can await the event directly.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Drop asyncio.sleep() in test_manager.py
* Only clear startup task reference if still the current task
Prevent a race where an older _wait_for_startup task's finally block
could wipe the reference to a newer task, causing unload() to skip
the await.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Reuse existing pending startup wait task when addon is already running
If start() is called while the addon is already running and a startup
wait task is still pending, return the existing task instead of creating
a new one.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
aiohttp's default max_msg_size of 4MB causes the ingress WebSocket proxy
to silently drop connections when an add-on sends messages larger than
that limit (e.g. Zigbee2MQTT's bridge/devices payload with many devices).
Setting max_msg_size=0 removes the limit on both the server-side
WebSocketResponse and the upstream ws_connect, fixing dropped connections
for add-ons that produce large WebSocket messages.
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: J. Nick Koston <nick@koston.org>