12 Commits
Author SHA1 Message Date
Alano Terblanche e22de3b574 fix(registry): use the https://dhi.io credentials key
Docker Desktop stores Docker Hardened Images credentials under https://dhi.io, so return that as the server address of dhi.io credentials, as StagingIndexServer does for the staging registry.

Signed-off-by: Alano Terblanche <[email protected]>
2026-10-07 14:24:28 +02:00
Alano Terblanche 81b6b59e79 feat(registry): use the Docker Desktop Hub session for dhi.io
Docker Hardened Images on dhi.io authenticate with Docker Hub accounts (the registry advertises service=registry.docker.io), so resolve dhi.io credentials from the production Docker Hub session as well, with dhi.io as the server address. Other registries, including look-alikes of dhi.io, still use the Docker CLI credentials.

Signed-off-by: Alano Terblanche <[email protected]>
2026-10-07 14:24:28 +02:00
Alano Terblanche a9f71c935c docs(registry): drop the isSessionUnavailable comment
Signed-off-by: Alano Terblanche <[email protected]>
2026-10-07 14:24:28 +02:00
Alano Terblanche e7a29a050b style(registry): lowercase the Docker Desktop fallback warning
Match the other compose log messages, which start lowercase.

Signed-off-by: Alano Terblanche <[email protected]>
2026-10-07 14:24:28 +02:00
Alano Terblanche 5ca76d57f8 refactor(registry): rename isExpectedMiss and trim comments
Rename isExpectedMiss to isSessionUnavailable, after what it reports, and shorten or drop doc comments in the Docker Desktop credentials provider.

Signed-off-by: Alano Terblanche <[email protected]>
2026-10-07 14:24:28 +02:00
Alano Terblanche dee031bb1d docs(registry): shorten the NewDesktopAuthProvider comment
Signed-off-by: Alano Terblanche <[email protected]>
2026-10-07 14:24:28 +02:00
Alano Terblanche 233a89f405 fix(registry): retry Docker Desktop a minute after a failed session lookup
A lookup that found no usable session disabled Desktop credentials for the rest of the process. That is right within one command, where retrying a hung engine would add the lookup timeout to every image, but the sessions are process wide and pkg/compose is also used as a library: in a long-running process a transient timeout, or signing in to Desktop later, was never picked up. Hold lookups off for a minute instead of for good.

Also name the expected-miss classification and test it, including dockerhub.ErrNoDefaultProfile, which wraps dockerhub.ErrNoSession.

Signed-off-by: Alano Terblanche <[email protected]>
2026-10-07 14:24:28 +02:00
Alano Terblanche 1a221b21e4 test(oci): drop TestNewResolver_SendsPasswordGrant
It covered the resolver credential mapping and containerd grant selection, neither changed by this PR. The token-as-password contract is asserted on the provider output and on the encoded X-Registry-Auth in internal/registry.

Signed-off-by: Alano Terblanche <[email protected]>
2026-10-07 14:24:28 +02:00
Alano Terblanche 171f9d0767 docs(registry): trim comments
Shorten the doc comments added for the Docker Desktop credentials provider to what the code does not already say, and drop them from the tests.

Signed-off-by: Alano Terblanche <[email protected]>
2026-10-07 14:24:28 +02:00
Alano Terblanche 2f92ff84a5 feat(registry): use the Docker Desktop staging session for the Hub staging registry
Docker Desktop keeps the Docker Hub staging session in separate secrets engine realms, read with dockerhub.Staging(). The environment is picked per registry host rather than with a global stage flag: the engine resolves docker.io to the production registry even when Desktop runs in stage mode, so the staging session is only used for registry-1-stage.docker.io and the production session only for the production Hub hosts. A token is never sent to the registry of the other environment.

Each environment has its own process-wide session and cache, and falls back to the Docker CLI config file independently. Staging credentials use https://registry-1-stage.docker.io/ as server address.

Signed-off-by: Alano Terblanche <[email protected]>
2026-10-07 14:24:28 +02:00
Alano Terblanche 816c83e401 fix(registry): read the Desktop session expiry from the token when claims lack it
The session payload may carry no claims, in which case the access token was reused for a minute without any expiry check, so an expired token could reach the registry and fail the pull instead of falling back. Read the exp claim from the JWT itself in that case. An expiry that cannot be read is still tolerated.

Signed-off-by: Alano Terblanche <[email protected]>
2026-10-07 14:24:28 +02:00
Alano Terblanche fd4dae8351 feat(registry): use the Docker Desktop Hub session for Docker Hub credentials
Docker Hub credentials are now read first from the session of the account signed in to Docker Desktop, through the Docker Desktop secrets engine (github.com/docker/secrets-engine/client), and from the Docker CLI config file and its credential helpers otherwise. Other registries keep using the config file only.

The OAuth access token is passed as the password of the signed-in account, never as an IdentityToken, which containerd sends as a refresh token. It flows unchanged to the engine in X-Registry-Auth and through the OCI resolver as an OAuth password grant.

Compose falls back to the config file when Desktop is not running, nobody is signed in, the session is expired or about to expire, or the lookup fails (the last logged as a warning). The session is shared process wide, cached until shortly before it expires, and an unusable session is not asked for again. Lookups are bounded by a 5s timeout, as the SDK applies none by default.

Used by pull, push, publish, config --resolve-image-digests, oci:// remote resources and dry-run. The classic builder and use_api_socket keep config file credentials, as a short-lived token copied into a container would go stale.

Signed-off-by: Alano Terblanche <[email protected]>
2026-10-07 14:24:28 +02:00