Repository navigation
[BUG] DockerHub:Registry has an unclear, partly hidden meaning and is barely validated #268
Description
Summary
The README describes DockerUpdateGuard:DockerHub:Registry as the "Registry host handled by the Docker Hub integration", but the key does not decide which registries the Docker Hub client serves: that host list is hard-coded. In reality it does two unrelated things: it gates the Docker Hub account listing (and the current-user lookup), and, when set to an absolute URL whose host is not a Docker Hub host, it silently replaces the Docker Hub web API base address given by ApiBaseUrl. Validation only checks that it is non-empty. Operators cannot predict the effect of the key, and a value meant as "my registry" quietly breaks discovery or redirects authenticated Docker Hub API traffic.
Area
docs/areas/registries.md(added in [Docs] Describe the current behavior by area #263): Choice of client per registry, Docker Hub account discovery, Configuration reload, Limits and errors- Security area: None directly. Note that the redirect of the API base address also redirects the bearer token derived from
DockerHub:Pat(Secrets in configuration), which is one more reason to remove that path.
Current behavior
- Default and description:
src/DockerUpdateGuard/Configuration/DockerHubOptions.cs:10-13(Registry="docker.io", summary "Registry host name");README.md:108("Registry host handled by the Docker Hub integration", required). - Which registries the Docker Hub client serves is fixed in
IsSupportedDockerHubHost(src/DockerUpdateGuard/DockerHub/DockerHubClient.cs:354-364:docker.io,index.docker.io,registry-1.docker.io,hub.docker.com,docker.com,www.docker.com) and evaluated against the image reference's registry (CanHandle:1334-1337,GetTagAsync:1189, …).DockerHub:Registryplays no role there. - Gate for account discovery:
GetCurrentUserAsync(:1020-1025) andGetRepositoriesAsync(:1068-1073) answer unsupported whenDockerHub:Registryis not a Docker Hub host;DockerHubAccountImageDiscoveryService(src/DockerUpdateGuard/Images/DockerHubAccountImageDiscoveryService.cs:268-275) then ends the run without changes. Discovered repositories are always stored under registrydocker.io(ParseRepository,DockerHubClient.cs:321-322), whateverRegistrysays. - Hidden override of the API base address:
DockerHubClient.GetBaseUri(:127-144):used once at startup forif (Uri.TryCreate(options.Registry, UriKind.Absolute, out var absoluteUri)) { if (IsSupportedDockerHubHost(absoluteUri.Host)) { return apiBaseUri; } return absoluteUri; // Registry replaces ApiBaseUrl }
HttpClient.BaseAddress(src/DockerUpdateGuard/ServiceCollectionExtensions.cs:73-79). - Validation:
src/DockerUpdateGuard/Configuration/DockerUpdateGuardOptionsValidator.cs:69-72only requires a non-empty value.
Failure scenarios
DockerHub:Registry = ghcr.io(an operator thinking "the registry I use"): account discovery is silently unsupported forever; the only trace is a log entry.DockerHub:Registry = https://registry.example.internal(absolute URL): account discovery is unsupported and every Docker Hub web API call (tags, repositories, login with the PAT) goes tohttps://registry.example.internal/instead ofApiBaseUrl, without any warning.
Expected behavior
Decision (product manager): DockerHub:Registry has one clear meaning. It only identifies the registry host for Docker Hub account discovery. The Docker Hub web API base address is set only through DockerHub:ApiBaseUrl.
DockerHub:Registrynever changes any request URL;GetBaseUrireturnsApiBaseUrlregardless ofRegistry.- Validation at startup:
Registrymust be a host name (not a URL, no scheme, path or port) that is one of the Docker Hub hosts the client supports, compared case-insensitively. Any other value fails startup with a message naming the key and the allowed values (for example "'DockerUpdateGuard:DockerHub:Registry' must be a Docker Hub registry host (docker.io, index.docker.io, registry-1.docker.io, hub.docker.com)"). - The value is trimmed; the default stays
docker.io. - The account listing's unsupported branch for a non-Docker-Hub
Registrystays as a defensive check for a reloaded configuration, but is no longer a normal, silent operating state. - README, the options XML doc and the area document describe the key with this meaning.
Acceptance criteria
-
DockerHubClient.GetBaseUrireturnsApiBaseUrlfor everyRegistryvalue, including an absolute non-Docker-Hub URL. -
DockerUpdateGuardOptionsValidatorrejectsRegistryvalues that are absolute URLs, contain a path or port, or are not Docker Hub hosts; acceptsdocker.io(any case, surrounding whitespace) and the other Docker Hub hosts. - Unit tests (MSTest, names per
docs/UNIT_TESTS.md), for exampleDockerHubClientGetBaseUriAbsoluteNonDockerHubRegistryReturnsApiBaseUrl,DockerUpdateGuardOptionsValidatorDockerHubRegistryNonDockerHubHostFailsValidation,DockerUpdateGuardOptionsValidatorDockerHubRegistryAbsoluteUrlFailsValidation,DockerUpdateGuardOptionsValidatorDockerHubRegistryDockerHubHostPassesValidation; existingDockerHubClientGetBaseUri…tests (src/Tests/DockerUpdateGuard.Tests/DockerHubClientTests.cs:73,:91) are adjusted to the new rule. - README configuration reference (
README.md:108-109):Registrydescribed as "Docker Hub registry host used for account discovery (a Docker Hub host such asdocker.io)";ApiBaseUrlas the only way to change the Docker Hub web API address. -
DockerHubOptionsXML docs updated accordingly. - Format, build, tests, Analyzer gate and Coverage gate from
.squad/stack.mdpass. - The area document
docs/areas/registries.mddescribes the new behavior and its Known gaps entry for this issue is removed.
Implementation notes
- Affected:
DockerHubClient.GetBaseUri(simplify tonew Uri(options.ApiBaseUrl)or remove it and useApiBaseUrldirectly inServiceCollectionExtensions),DockerUpdateGuardOptionsValidator.ValidateDockerHubOptions,DockerHubOptions,README.md, possiblydocs/ARCHITECTURE.md(Configuration model) andINSTALL.mdif they mention the key. - Reuse the Docker Hub host list for validation instead of duplicating it: expose a static check (for example make
DockerHubClient.SupportsRegistrythe single source, or move the list to a small static helper used by both the client and the validator).docker.com/www.docker.comare in the client's list today but are not registries. Recommendation: accept the full existing list to avoid breaking existing configurations. - Breaking change for operators who used an absolute URL in
Registryto point the web API somewhere else: startup now fails with a clear message, and they move the URL toApiBaseUrl. Mention this in the PR description. src/Tests/DockerUpdateGuard.Tests/DockerUpdateGuardOptionsValidatorTests.cs:403-407already asserts that the development configuration sample uses a supported Docker Hub registry; keep it green.appsettings.jsonkeeps"Registry": "docker.io"; no migration.- Must not change: which registries the Docker Hub client serves (the fixed host list, evaluated on the image reference); discovered repositories stay stored under
docker.io;ApiBaseUrlstays fixed at startup.
Related
- PR [Docs] Describe the current behavior by area #263 (area documents)
Generated by Claude Code
Activity