1
0
mirror of https://github.com/home-assistant/supervisor.git synced 2026-04-02 00:07:16 +01:00

Reuse IMAGE_REGISTRY_REGEX for docker_image validation (#6667)

* 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>
This commit is contained in:
Stefan Agner
2026-03-30 18:33:11 +02:00
committed by GitHub
parent 1fd78dfc4e
commit be95349185
2 changed files with 50 additions and 3 deletions

View File

@@ -50,6 +50,7 @@ from .const import (
LogLevel,
UpdateChannel,
)
from .docker.utils import get_registry_from_image
from .utils.validate import validate_timezone
# Move to store.validate when addons_repository config removed
@@ -60,9 +61,46 @@ RE_REGISTRY = re.compile(r"^([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}$")
# pylint: disable=invalid-name
network_port = vol.All(vol.Coerce(int), vol.Range(min=1, max=65535))
wait_boot = vol.All(vol.Coerce(int), vol.Range(min=1, max=60))
docker_image = vol.Match(
r"^([a-z0-9][a-z0-9.\-]*(:[0-9]+)?/)*?([a-z0-9{][a-z0-9.\-_{}]*/)*?([a-z0-9{][a-z0-9.\-_{}]*)$"
)
# Path component pattern for Docker image names (supports {arch}/{machine} templates)
_RE_IMAGE_PATH_COMPONENT = re.compile(r"^[a-z0-9{][a-z0-9.\-_{}]*$")
def docker_image(image: str) -> str:
"""Validate a Docker image name without tag.
Tags are not allowed as the version/tag is managed separately.
Uses IMAGE_REGISTRY_REGEX from docker.utils for robust registry detection.
"""
if not image or not isinstance(image, str):
raise vol.Invalid(f"Expected a non-empty string for docker image, got: {image}")
# Extract registry if present (handles domains, IPv4/IPv6, ports, localhost)
registry = get_registry_from_image(image)
if registry:
# Registry must be lowercase
if registry != registry.lower():
raise vol.Invalid(f"Docker image registry must be lowercase: {image}")
path = image[len(registry) + 1 :] # Remove "registry/" prefix
else:
path = image
if not path:
raise vol.Invalid(f"Docker image has no name: {image}")
# Tags are not allowed - version is managed separately by the add-on system
if ":" in path:
raise vol.Invalid(f"Docker image must not contain a tag: {image}")
# Validate each path component (org/name)
for component in path.split("/"):
if not _RE_IMAGE_PATH_COMPONENT.match(component):
raise vol.Invalid(
f"Invalid Docker image path component '{component}' in: {image}"
)
return image
uuid_match = vol.Match(r"^[0-9a-f]{32}$")
sha256 = vol.Match(r"^[0-9a-f]{64}$")
token = vol.Match(r"^[0-9a-f]{32,256}$")

View File

@@ -25,14 +25,23 @@ IMAGE_NAME_GOOD = [
"homeassistant/amd64-homeassistant",
"ttl.sh/homeassistant",
"myreg.local:8080/homeassistant",
"localhost/myimage",
"localhost:5000/myimage",
"127.0.0.1/myimage",
"127.0.0.1:5000/org/myimage",
"[::1]:5000/myimage",
"dockeruser/nice-app-1.2",
"ghcr.io/blakeblackshear/frigate",
]
IMAGE_NAME_BAD = [
"ghcr.io/home-assistant/homeassistant:123",
"ghcr.io/blakeblackshear/frigate:stable-rocm",
".ghcr.io/home-assistant/homeassistant",
"HOMEASSISTANT/homeassistant",
"homeassistant/HOMEASSISTANT",
"homeassistant/_homeassistant",
"homeassistant/-homeassistant",
"GHCR.IO/home-assistant/homeassistant",
]