Commit Graph
110 Commits
Author SHA1 Message Date
Guillaume LoursandClaude Sonnet 5 467fa8ccc9 fix: share --parallel budget across down's ops and up's log-attach
down's outer ops dispatch bounded only how many ops ran concurrently,
separate from the semaphore already shared by image removal -- a
single network plus --rmi could spend up to 2x the configured
budget. Network and volume removal now share that same semaphore.

up's post-attach log streaming called ContainerInspect directly and
passed no limiter to doLogContainer, unlike `compose logs --follow`'s
equivalent path, so it never shared --parallel's budget either.

The plan executor also held a node's slot for its whole dependency
wait instead of just its own work, and internal/sync/tar.go's file
sync used a hardcoded cap of 16 instead of --parallel.

Signed-off-by: Guillaume Lours <[email protected]>
Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-10-01 16:02:14 +02:00
Nicolas De LoofandClaude Fable 5 e96ca020f2 build(deps): adopt compose-go jobs and the container-spec layering
compose-spec/compose-go#866 is merged: jobs top-level element, container
specification layered as ContainerSpec/WorkloadSpec, pre_start hooks
carrying the full container specification resolved at load time. Bump
to the merged head and adapt in the same movement — composite literals
setting moved fields wrap them into the embedded ContainerSpec /
WorkloadSpec (promoted field access was already source-compatible, so
this is literal-only, no behavior change), and pre_start handling is
typed against PreStartHook.

Co-Authored-By: Claude Fable 5 <[email protected]>
Signed-off-by: Nicolas De Loof <[email protected]>
2026-09-21 16:35:20 +02:00
hiroto.toyoda 548be16595 fix(publish): report OCI fallback as a bool, not the OCI version
Signed-off-by: hiroto.toyoda <[email protected]>
2026-09-15 14:54:03 +02:00
hiroto.toyoda f8e64299b4 fix(publish): warn when push falls back from OCI 1.1 to OCI 1.0
Signed-off-by: hiroto.toyoda <[email protected]>
2026-09-15 14:54:03 +02:00
Sebastiaan van Stijn 063ef45da1 golangci-lint: enable perfsprint linter
Signed-off-by: Sebastiaan van Stijn <[email protected]>
2026-09-10 10:25:34 +02:00
hiroto.toyoda 1ebdc06c18 feat(tracing): surface otel shutdown errors via --debug
OTel SDK/exporter errors already go through docker/cli's own
otel.SetErrorHandler(debug.OTELErrorHandler), installed by the plugin
framework at startup. Our own handler, installed at package init time,
was always clobbered before any command ran (plugin.Run() sets its handler
after all inits execute), so it never had any effect - verified by tracing
the exact call order and reproducing the flag behavior against a built
binary.

Drop that dead handler along with the COMPOSE_OTEL_DEBUG env var it
introduced. The one genuinely-discarded error (the tracer shutdown/flush
error in wrapRunE) now goes through logrus like everything else in the
codebase: it's already gated by --debug/-D via logrus's own level, so no
explicit check is needed.

Signed-off-by: hiroto.toyoda <[email protected]>
2026-09-02 17:12:12 +02:00
Nicolas De Loof a472f714d5 registry: encode credentials with moby's authconfig package
EncodedAuth now delegates the X-Registry-Auth wire encoding to
moby/api/pkg/authconfig (same module, already required) instead of
hand-rolling the JSON+base64url pair, and push.go reuses it instead of
its own copy. The CLI and moby AuthConfig structs are field-for-field
identical, so a direct type conversion bridges them.

The explicit GetAuthConfigKey normalization drops out of EncodedAuth:
docker/cli's configfile.GetAuthConfig normalizes the Docker Hub domain
itself. It remains for the OCI resolver, whose credential callback
receives the network host actually contacted (registry-1.docker.io),
which the configfile does not map.

Signed-off-by: Nicolas De Loof <[email protected]>
2026-08-25 17:27:26 +02:00
Nicolas De Loof 84dcd428ca remove buildx as a Go dependency
buildx was imported for two narrow purposes, both replaced by
docker/cli machinery compose already uses elsewhere:

- storeutil.GetProxyConfig -> configfile.ParseProxyConfig, the same
  lookup docker build uses (also picks up ALL_PROXY and lowercase
  variants)
- the dry-run image resolver (buildx builder + imagetools) -> a
  DistributionInspect through the daemon with credentials from the CLI
  config file, i.e. the same path a real pull/push would take; the
  encoded-auth helper moves to internal/registry, shared with pull.go

bake is unaffected: it already execs the buildx CLI plugin. Dropping
the module also drops the transitive aws-sdk-go-v2 footprint
(-328 lines of go.sum).

Signed-off-by: Nicolas De Loof <[email protected]>
2026-08-25 17:27:26 +02:00
Endika Iglesias f519180b95 fix(watch): sync into a symlinked directory instead of failing
Signed-off-by: Endika Iglesias <[email protected]>
2026-08-18 17:25:13 +02:00
Guillaume Lours cda9f2044f fix(oci): fetch artifact layers from blobs endpoint, not via Resolve
Pulling an oci:// resource resolved each layer digest through the
registry manifests endpoint, which answers 500 when the digest points
to a non-manifest blob. containerd v2.3.0+ (pulled in by buildx v0.36
and buildkit v0.32) no longer falls back to the blobs endpoint unless
manifests returned 404, so publish/pull of compose artifacts broke.
Fetch layers directly with the descriptors already listed in the
manifest instead of resolving them again.

Signed-off-by: Guillaume Lours <[email protected]>
2026-08-03 14:56:34 +02:00
Guillaume Lours e87f7b79df fix(oci): route authorizer token fetches through provided transport
The transport passed to NewResolver was applied only via
docker.WithClient. Pass it via docker.WithAuthClient too so the
authorizer's OAuth token fetches use it instead of http.DefaultClient.

Signed-off-by: Guillaume Lours <[email protected]>
2026-06-25 15:38:37 +02:00
Domantas PetrauskasandClaude Opus 4.8 0afb4c8c4c fix(publish): bypass Docker Desktop proxy for loopback registries
`docker compose publish` routed all registry traffic through Docker
Desktop's HTTP proxy. Publishing to a registry on localhost therefore
failed on Windows with:

    proxyconnect tcp: open ./pipe/dockerHttpProxy: The system cannot
    find the path specified.

even though `docker push`/`docker pull` worked against the same registry.

Two bugs in internal/desktop/proxy.go:

1. No loopback bypass. ProxyTransport forced every request through the
   Docker Desktop proxy and its DialContext always dialed the proxy
   socket, so loopback targets could never connect directly. Proxy
   selection now bypasses the proxy only for loopback targets
   (localhost, 127.0.0.0/8, ::1); all other registry traffic stays
   routed through Docker Desktop's PAC-aware proxy so Desktop keeps
   ownership of proxy decisions (e.g. enterprise-managed proxies). The
   local process NO_PROXY/no_proxy is deliberately not honored, so a
   broad value such as * or .corp cannot bypass centrally managed
   proxy policy.

2. Malformed Windows pipe path. The proxy named-pipe endpoint was
   hardcoded as npipe://./pipe/..., yielding the relative path
   ./pipe/dockerHttpProxy. It is now derived from the engine endpoint,
   preserving its namespace. Docker Desktop reports the backslash form
   npipe://\\.\pipe\docker_cli, so the derivation uses LastIndexAny to
   handle both backslash and forward-slash forms.

Publishing to localhost now connects directly like `docker push`, while
every non-loopback registry still goes through the Docker Desktop proxy.

Fixes #13824

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Signed-off-by: Domantas Petrauskas <[email protected]>
2026-06-15 21:18:19 +02:00
Sebastiaan van Stijn df75f82a6b chore(deps): github.com/docker/buildx v0.34.1, buildkit v0.30.0
Signed-off-by: Sebastiaan van Stijn <[email protected]>
2026-06-15 12:45:57 +02:00
Guillaume Lours c59e13cde5 feat: pre-filter Desktop Logs view by Compose project
Pass the active project name as the appId query parameter on the
docker-desktop://dashboard/logs deep link, both from the post-command
hint (compose up -d, compose logs) and the interactive nav menu
('l' key during compose up). The hook subprocess re-runs compose-go's
project loader so the name matches what the parent computed; it skips
the appId when -p, -f, --project-directory, --workdir, or --env-file
is set, since the hook payload does not carry their values. docker
logs stays unfiltered: the CLI hook contract does not expose the
positional container id.

Signed-off-by: Guillaume Lours <[email protected]>
2026-05-18 17:28:03 +02:00
Guillaume Lours 554a2ba3e8 refactor: drop Desktop beta-settings check; gate hint on LogsTab flag
Docker Desktop is removing the "Enable Logs view" beta setting, so drop
the /app/settings check and rely on /features alone. With the setting
gate gone, the compose hook subprocess would print the Logs view hint
regardless of LogsTab; add a flag check in handleHook. Consolidate
engine-label discovery and feature-flag evaluation into internal/desktop.

Signed-off-by: Guillaume Lours <[email protected]>
2026-05-18 17:28:03 +02:00
Guillaume Lours 66c21c3b6c fix: route OCI artifact pulls through Docker Desktop HTTP proxy
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 <[email protected]>
2026-05-18 10:53:23 +02:00
Guillaume LoursandClaude Opus 4.6 182defa8aa feat: add Docker Desktop Logs view hints and navigation shortcut
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) <[email protected]>
Signed-off-by: Guillaume Lours <[email protected]>
2026-04-10 15:26:08 +02:00
Guillaume Lours ba417e4392 use new moby/moby modules instead of docker/docker dependency
Signed-off-by: Guillaume Lours <[email protected]>
2026-04-08 08:50:50 +02:00
Lidang-Jiang 63601ebbb3 test: migrate tar_test.go from testify to gotest.tools/v3
Signed-off-by: Lidang-Jiang <[email protected]>
2026-04-03 12:29:07 +02:00
Lidang-Jiang 6ce3fb57a8 fix: return error on non-ErrNotExist stat failures in Tar.Sync()
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 <[email protected]>
Signed-off-by: Lidang-Jiang <[email protected]>
2026-04-03 12:29:07 +02:00
Sebastiaan van Stijn 92a7ac1fa2 fix mixed assertion libraries in tests
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 <[email protected]>
2026-03-31 17:32:51 +02:00
Sebastiaan van Stijn f9828dfab9 modernize some code
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 <[email protected]>
2026-02-12 15:31:35 +01:00
Sebastiaan van Stijn bfb5511d0d go.mod: bump github.com/moby/moby/api v1.53.0, moby/client v0.2.2
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 <[email protected]>
2026-02-11 12:32:37 +01:00
David Gageot 093205121c test: replace context.Background()/context.TODO() with t.Context()
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 <[email protected]>
2026-01-20 11:34:11 +01:00
tensorworker 02b606ef8e use go-compose instead Signed-off-by: tensorworker <[email protected]>
Signed-off-by: tensorworker <[email protected]>
2026-01-15 08:24:20 +01:00
tensorworker 9856802945 fix: expand tilde in --env-file paths to user home directory
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 <[email protected]>
2026-01-15 08:24:20 +01:00
zjumathcode 13d70b1c11 refactor: replace interface{} with any for clarity and modernization
Signed-off-by: zjumathcode <[email protected]>
2025-12-02 08:41:49 +01:00
Sebastiaan van Stijn dc66e6bad1 golangci-lint: use gci formatter instead of goimports
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 <[email protected]>
2025-12-01 12:21:50 +01:00
Nicolas De Loof 2b4543935c next release will be major version v5.x
Signed-off-by: Nicolas De Loof <[email protected]>
2025-11-13 09:32:43 +01:00
Nicolas De Loof 7eb5adeef6 introduce --insecure-registry, reserved for testing purpose
Signed-off-by: Nicolas De Loof <[email protected]>
2025-11-06 16:17:21 +01:00
Nicolas De Loof e59150baa8 fix OCI compose override support
Signed-off-by: Nicolas De Loof <[email protected]>
2025-10-23 12:04:37 +02:00
Nicolas De Loof e25265dd55 remove unused code to only rely on api.Service
Signed-off-by: Nicolas De Loof <[email protected]>
2025-10-20 14:53:04 +02:00
Paul Thiele 157617480a fix race-condition bug in publish command
Signed-off-by: Paul Thiele <[email protected]>
2025-10-16 09:24:57 +02:00
Nicolas De Loof 07602f2070 publish Compose application as compose.yaml + images
Signed-off-by: Nicolas De Loof <[email protected]>
2025-10-03 10:59:57 +02:00
Nicolas De Loof fa08127456 use containerd client for OCI operations
Signed-off-by: Nicolas De Loof <[email protected]>
2025-09-30 12:03:46 +02:00
Nicolas De Loof 8978c1027d use containerd registry client
Signed-off-by: Nicolas De Loof <[email protected]>
2025-09-26 18:45:07 +02:00
Sebastiaan van Stijn 5165b0f814 internal/tracing: replace go-multierror.Group with sync.WaitGroup
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 <[email protected]>
2025-08-25 11:22:25 +02:00
Sebastiaan van Stijn 93dd1a4558 internal/sync: replace go-multierror.Group with golang.org/x/sync/errgroup
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 <[email protected]>
2025-08-25 11:22:25 +02:00
Sebastiaan van Stijn fc66da06db pkg/compose: simplify getting auth-config key
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 https://github.com/docker/cli/commit/b4ca1c7368daeead400fcc1b8f2d61951a0d9d1e).

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 <[email protected]>
2025-08-05 10:08:23 +02:00
Guillaume Lours efc939dcee add info about models usage to OpenTelemetry spans
Signed-off-by: Guillaume Lours <[email protected]>
2025-07-24 16:01:28 +02:00
atagtm f7ee9c8a0c feat(os): add FreeBSD support
Signed-off-by: atagtm <[email protected]>
2025-07-11 10:44:45 +02:00
mountdisk b046a5ef72 chore: fix some minor issues in the comments
Signed-off-by: mountdisk <[email protected]>
2025-07-02 07:31:00 +02:00
Nicolas De Loof 6fa173124a (reactoring) avoid a global variable by introducing logConsumer decorator
Signed-off-by: Nicolas De Loof <[email protected]>
2025-07-01 12:29:05 +02:00
Jeff Carter 0f9e6ab832 Fix the generated manifest for compose artifacts so that the empty config is not added as a layer.
Signed-off-by: Jeff Carter <[email protected]>
2025-06-11 16:51:51 +02:00
tongjicoder 2e71440bee refactor: use slices.Contains to simplify code
Signed-off-by: tongjicoder <[email protected]>
2025-05-27 11:45:26 +02:00
Guillaume Lours f5491328bb remove support of Synchronize File Shares integration with Docker Desktop
Signed-off-by: Guillaume Lours <[email protected]>
2025-04-22 15:29:23 +02:00
Sebastiaan van Stijn 13cd780f30 migrate to use github.com/moby/go-archive
Signed-off-by: Sebastiaan van Stijn <[email protected]>
2025-04-17 13:28:49 +02:00
Adel Sevastianov 846161d447 Fix linting issue with resp.Body.Close()
Signed-off-by: Adel Sevastianov <[email protected]>
2025-04-09 15:25:53 +02:00
Adel Sevastianov 0bcc629fbe refactor: improve Desktop client structure
Signed-off-by: Adel Sevastianov <[email protected]>
2025-04-09 15:25:53 +02:00
Sebastiaan van StijnandNicolas De Loof cf2fc2005c go.mod: docker/docker, docker/cli v28.0.0, buildx v0.21.1
full diff:

- https://github.com/docker/docker/compare/v27.5.1...v28.0.0
- https://github.com/docker/cli/compare/v27.5.1...v28.0.0
- https://github.com/docker/buildx/compare/v0.20.1...v0.21.1

Co-authored-by: Nicolas De Loof <[email protected]>
Signed-off-by: Sebastiaan van Stijn <[email protected]>
2025-02-21 15:23:25 +01:00