mirror of
https://github.com/home-assistant/supervisor.git
synced 2026-04-02 16:22:51 +01:00
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>
137 lines
5.2 KiB
Python
137 lines
5.2 KiB
Python
"""Test docker login."""
|
|
|
|
import pytest
|
|
|
|
# pylint: disable=protected-access
|
|
from supervisor.coresys import CoreSys
|
|
from supervisor.docker.const import DOCKER_HUB, DOCKER_HUB_LEGACY
|
|
from supervisor.docker.interface import DockerInterface
|
|
from supervisor.docker.utils import get_registry_from_image
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("image_ref", "expected_registry"),
|
|
[
|
|
# No registry - Docker Hub images
|
|
("nginx", None),
|
|
("nginx:latest", None),
|
|
("library/nginx", None),
|
|
("library/nginx:latest", None),
|
|
("homeassistant/amd64-supervisor", None),
|
|
("homeassistant/amd64-supervisor:1.2.3", None),
|
|
# Registry with dot
|
|
("ghcr.io/homeassistant/amd64-supervisor", "ghcr.io"),
|
|
("ghcr.io/homeassistant/amd64-supervisor:latest", "ghcr.io"),
|
|
("myregistry.com/nginx", "myregistry.com"),
|
|
("registry.example.com/org/image:v1", "registry.example.com"),
|
|
("127.0.0.1/myimage", "127.0.0.1"),
|
|
# Registry with port
|
|
("myregistry:5000/myimage", "myregistry:5000"),
|
|
("localhost:5000/myimage", "localhost:5000"),
|
|
("registry.io:5000/org/app:v1", "registry.io:5000"),
|
|
# localhost special case
|
|
("localhost/myimage", "localhost"),
|
|
("localhost/myimage:tag", "localhost"),
|
|
# IPv6
|
|
("[::1]:5000/myimage", "[::1]:5000"),
|
|
("[2001:db8::1]:5000/myimage:tag", "[2001:db8::1]:5000"),
|
|
],
|
|
)
|
|
def test_get_registry_from_image(image_ref: str, expected_registry: str | None):
|
|
"""Test get_registry_from_image extracts registry from image reference.
|
|
|
|
Based on Docker's reference implementation:
|
|
vendor/github.com/distribution/reference/normalize.go
|
|
"""
|
|
assert get_registry_from_image(image_ref) == expected_registry
|
|
|
|
|
|
def test_no_credentials(coresys: CoreSys, test_docker_interface: DockerInterface):
|
|
"""Test no credentials."""
|
|
coresys.docker.config._data["registries"] = {
|
|
DOCKER_HUB: {"username": "Spongebob Squarepants", "password": "Password1!"}
|
|
}
|
|
credentials, image = test_docker_interface._get_credentials("ghcr.io/homeassistant")
|
|
assert not credentials
|
|
assert image == "ghcr.io/homeassistant"
|
|
|
|
credentials, image = test_docker_interface._get_credentials(
|
|
"ghcr.io/homeassistant/amd64-supervisor"
|
|
)
|
|
assert not credentials
|
|
assert image == "ghcr.io/homeassistant/amd64-supervisor"
|
|
|
|
|
|
def test_no_matching_credentials(
|
|
coresys: CoreSys, test_docker_interface: DockerInterface
|
|
):
|
|
"""Test no matching credentials."""
|
|
coresys.docker.config._data["registries"] = {
|
|
DOCKER_HUB: {"username": "Spongebob Squarepants", "password": "Password1!"}
|
|
}
|
|
credentials, image = test_docker_interface._get_credentials("ghcr.io/homeassistant")
|
|
assert not credentials
|
|
assert image == "ghcr.io/homeassistant"
|
|
|
|
credentials, image = test_docker_interface._get_credentials(
|
|
"ghcr.io/homeassistant/amd64-supervisor"
|
|
)
|
|
assert not credentials
|
|
assert image == "ghcr.io/homeassistant/amd64-supervisor"
|
|
|
|
|
|
def test_matching_credentials(coresys: CoreSys, test_docker_interface: DockerInterface):
|
|
"""Test matching credentials."""
|
|
coresys.docker.config._data["registries"] = {
|
|
"ghcr.io": {"username": "Octocat", "password": "Password1!"},
|
|
DOCKER_HUB: {"username": "Spongebob Squarepants", "password": "Password1!"},
|
|
}
|
|
|
|
credentials, image = test_docker_interface._get_credentials(
|
|
"ghcr.io/homeassistant/amd64-supervisor"
|
|
)
|
|
assert credentials["registry"] == "ghcr.io"
|
|
assert image == "ghcr.io/homeassistant/amd64-supervisor"
|
|
|
|
credentials, image = test_docker_interface._get_credentials(
|
|
"homeassistant/amd64-supervisor"
|
|
)
|
|
assert credentials["username"] == "Spongebob Squarepants"
|
|
assert credentials["registry"] == DOCKER_HUB
|
|
# Docker Hub images should be prefixed with docker.io/ for correct ServerAddress
|
|
assert image == f"{DOCKER_HUB}/homeassistant/amd64-supervisor"
|
|
|
|
|
|
def test_legacy_docker_hub_credentials(
|
|
coresys: CoreSys, test_docker_interface: DockerInterface
|
|
):
|
|
"""Test legacy hub.docker.com credentials are used for Docker Hub images."""
|
|
coresys.docker.config._data["registries"] = {
|
|
DOCKER_HUB_LEGACY: {"username": "LegacyUser", "password": "Password1!"},
|
|
}
|
|
|
|
credentials, image = test_docker_interface._get_credentials(
|
|
"homeassistant/amd64-supervisor"
|
|
)
|
|
assert credentials["username"] == "LegacyUser"
|
|
assert credentials["registry"] == DOCKER_HUB_LEGACY
|
|
assert image == f"{DOCKER_HUB}/homeassistant/amd64-supervisor"
|
|
|
|
|
|
def test_docker_hub_preferred_over_legacy(
|
|
coresys: CoreSys, test_docker_interface: DockerInterface
|
|
):
|
|
"""Test docker.io is preferred over legacy hub.docker.com when both exist."""
|
|
coresys.docker.config._data["registries"] = {
|
|
DOCKER_HUB: {"username": "NewUser", "password": "Password1!"},
|
|
DOCKER_HUB_LEGACY: {"username": "LegacyUser", "password": "Password2!"},
|
|
}
|
|
|
|
credentials, image = test_docker_interface._get_credentials(
|
|
"homeassistant/amd64-supervisor"
|
|
)
|
|
# docker.io should be preferred
|
|
assert credentials["username"] == "NewUser"
|
|
assert credentials["registry"] == DOCKER_HUB
|
|
assert image == f"{DOCKER_HUB}/homeassistant/amd64-supervisor"
|