The compose process performs OCI artifact fetches in-process via
containerd's docker resolver, whose default transport only honors
HTTP_PROXY/HTTPS_PROXY/NO_PROXY env vars. Users behind PAC-only
corporate proxies hit i/o timeouts on `oci://` includes and on
`compose publish`.
When Docker Desktop is the active engine and exposes httpproxy.sock,
route the resolver through it (PAC-aware). Falls back to the default
transport when DD is unavailable or the socket is missing. Modeled on
docker/mcp-gateway PR #354.
Signed-off-by: Guillaume Lours <glours@users.noreply.github.com>
Add CLI hooks handler to show "What's next:" hints pointing to the
Docker Desktop Logs view after `docker logs`, `docker compose logs`,
and `docker compose up -d`.
Add `l` keyboard shortcut in the `compose up` navigation menu to
open the Logs view, gated on Docker Desktop feature flag and settings.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Guillaume Lours <glours@users.noreply.github.com>
Previously, Sync() only checked for fs.ErrNotExist when classifying
paths into copy vs delete. Non-NotExist stat errors (e.g. EACCES,
EIO) caused the condition to be false, falling through to the else
clause which incorrectly treated the path as copyable. This masked
real errors and led to cryptic failures downstream.
Restructure the condition into a three-way branch:
- err == nil → copy
- ErrNotExist → delete
- other errors → return immediately with context
This follows the pattern already used by entriesForPath() in the
same file.
Fixes#13654
Signed-off-by: Lidang Jiang <lidangjiang@gmail.com>
Signed-off-by: Lidang-Jiang <lidangjiang@gmail.com>
Before this, assertion libraries were mixed, sometimes
even in the same file.
git grep -l '"gotest.tools/v3/' | wc -l
75
git grep -l '"github.com/stretchr/testify' | wc -l
24
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Results of running the modernize command, with some minor changes
afterwards (removing the `contains` and `hasStatus` helper functions);
go install golang.org/x/tools/go/analysis/passes/modernize/cmd/modernize@latest
modernize -fix ./...
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Also update TestDefaultNetworkSettings:
Test that the network with the highest priority is returned as
"primary" network, and other networks as extra networks.
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Replace manual context creation with t.Context() which is automatically
cancelled when the test completes.
Go 1.24 modernization pattern.
Assisted-By: cagent
Signed-off-by: David Gageot <david.gageot@docker.com>
When using --env-file=~/.env, the tilde was not expanded to the user's
home directory. Instead, it was treated as a literal character and
resolved relative to the current working directory, resulting in errors
like "couldn't find env file: /current/dir/~/.env".
This adds an ExpandUser function that expands ~ to the home directory
before converting relative paths to absolute paths.
Fixes#13508
Signed-off-by: tensorworker <tensorworker@proton.me>
Most files already grouped imports into "stdlib -> other -> local",
but some files didn't. The gci formatter is similar to goimports, but
has better options to make sure imports are grouped in the expected
order (and to make sure no additional groups are present).
This formatter has a 'fix' function, so code can be re-formatted auto-
matically;
golangci-lint run -v --fix
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
The go-multierror Group is just a shallow wrapper around sync.WaitGroup;
https://github.com/hashicorp/go-multierror/blob/v1.1.1/group.go#L5-L38
This patch replaces the go-multierror.Group for a sync.WaitGroup (we
probably don't need to limit concurrency for this one) and stdlib multi-
errors.
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
The go-multierror Group is just a shallow wrapper around sync.WaitGroup;
https://github.com/hashicorp/go-multierror/blob/v1.1.1/group.go#L5-L38
It does not limit concurrency, but handles synchronisation to collect
all errors (if any) in a go-multierror.
This patch replaces the go-multierror.Group for a sync.ErrGroup (which
is slightly easier to use, and does allow for limiting concurrency if
wanted), and a basic slice with mutex to collect the errors and to produce
a stdlib multi-error through errors.Join
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Rewrite to remove the `github.com/docker/docker/registry` dependency,
which will not be included in the upcoming "api" and "client" modules,
and will not be a public package in the module used for the daemon itself.
1. don't call "/info" API endpoint to get default registry
The `IndexServerAddress` in the `/info` endpoint was added as part of the
initial Windows implementation of the engine. For legal reasons, Microsoft
Windows (and thus Docker images based on Windows) were not allowed to be
distributed through non-Microsoft infrastructure. As a temporary solution,
a dedicated "registry-win-tp3.docker.io" registry was created to serve
Windows images.
Using separate registries was not an ideal solution, and a more permanent
solution was created by introducing "foreign image layers" in the distribution
spec, after which the "registry-win-tp3.docker.io" ceased to exist, and
removed from the engine through docker/docker PR 21100.
However, the `ElectAuthServer` was left in place, quoting from that PR;
> make the client check which default registry the daemon uses is still
> more correct than leaving it up to the client, even if it won't technically
> matter after this PR. There may be some backward compatibility scenarios
> where `ElectAuthServer` [sic] is still helpful.
That comment was 10 Years ago, and the CLI stopped using this information,
as the default registry is not configurable, so in practice was a static
value. (see b4ca1c7368).
2. replace `ParseRepositoryInfo` and `GetAuthConfigKey` with local impl
The `ParseRepositoryInfo` function was originally implemented for use by
the daemon itself. It returns a `RepositoryInfo` struct that holds information
about the repository and the registry the repository can be found in.
As it was written for use by the daemon, it also was designed to be used
in combination with the daemon's configuration (such as mirrors, and
insecure registries). If no daemon configuration is present, which would
be the case when used in a CLI, it uses fallback logic as used in the daemon
to detect if the registry is running on a localhost / loopback address,
because such addresses are allowed to be "insecure" by default; this includes
resolving the IP-address of the host (if it's not an IP-address).
Unfortunately, these functions (and related types) were reused in the
CLI and many other places, which resulted in those types to be deeply
ingrained in interfaces and (external) code.
For compose; it was only used to get the "auth-config key" to use for
looking up auth information from the credentials store, which still
needs special handling for the "default" (docker hub) domain, which
unlike other image references doesn't use the hostname included in
the image reference for the actual registry (and key for storing
auth).
For those that want to follow along;
First, note that `GetAuthConfig` only requires a `registry.IndexInfo`, so not
the whole `RepositoryInfo` struct;
https://github.com/moby/moby/blob/v28.3.3/registry/types.go#L8-L24
From the `registry.IndexInfo` it only uses the `IsOfficial` and `Name` fields;
https://github.com/moby/moby/blob/v28.3.3/registry/config.go#L390-L395
But to get the `IndexInfo`, `ParseRepositoryInfo` is needed, which first
takes the image reference's "domain name" (e.g. `docker.io`);
https://github.com/moby/moby/blob/v28.3.3/registry/config.go#L421
This gets "normalized" for some cases where the `info.IndexServerAddress`
was incorrectly assumed to be the canonical domain for Docker Hub registry,
and which _does_ happen to also be accessible as a "v2" registry.
https://github.com/moby/moby/blob/v28.3.3/registry/config.go#L334-L341
After normalizing, it checks if it's a docker hub address ("docker.io"
after normalizing); Docker Hub is always required to use a secure
connection, so no detection happens, and the `Official` field is set
to indicate it's Docker Hub (this code path was already simplified
as historically it would try to find daemon configuration (or otherwise
use a default) for Mirror configuration;
https://github.com/moby/moby/blob/v28.3.3/registry/config.go#L420-L443
For non-Docker Hub registries, it also sets the name, and attempts
to detect if the registry is allowed to be "insecure";
https://github.com/moby/moby/blob/v28.3.3/registry/config.go#L435-L442
Which (as mentioned) involves parsing the address and, if needed, resolving
the hostname
https://github.com/moby/moby/blob/v28.3.3/registry/config.go#L445-L481
As `Insecure` is not used for looking up the auth-config key, all of the
above can be reduced to;
- Is the hostname obtained from the image reference "docker.io" (after normalizing)?
- If so, use the special `https://index.docker.io/v1/` as auth-config key (another horrible remnant)
- Otherwise use the hostname obtained from the image reference as-is
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Format the code with gofumpt to prevent my IDE from reformatting
every time I open a file. gofumpt provides a superset of gofmt,
so should not impact users that are not using gofumpt.
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
it fixes a repository creation issue when pushing the 1st time a Compose OCI artifact on the Hub
Signed-off-by: Guillaume Lours <705411+glours@users.noreply.github.com>
Previously the HTTP requests were sent with a generic Go-http-client
user-agent which made it hard to determine where the requests are
coming from. It's important that we can find clients so that they
can be updated if APIs change in future.
Signed-off-by: David Scott <dave@recoil.org>