Commit Graph
6043 Commits
Author SHA1 Message Date
dependabot[bot] e9491499f1 build(deps): bump golang.org/x/sys from 0.47.0 to 0.48.0
Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.47.0 to 0.48.0.
- [Commits](https://github.com/golang/sys/compare/v0.47.0...v0.48.0)

---
updated-dependencies:
- dependency-name: golang.org/x/sys
  dependency-version: 0.48.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
2026-09-09 17:50:05 +02:00
Nicolas De LoofandClaude Fable 5 68d9b510cc fix(display): reset the screen after degraded out-of-operation lines
A plain line printed outside any operation lands below the tracked
block, so the block is no longer directly above the cursor. Reset the
screen so the next operation repaints a fresh block instead of moving
the cursor over rows that shifted — the same reason unsuspend resets
after buildkit output.

Suggested-by: Guillaume Lours <[email protected]>
Co-Authored-By: Claude Fable 5 <[email protected]>
Signed-off-by: Nicolas De Loof <[email protected]>
2026-09-09 16:50:05 +02:00
Nicolas De LoofandClaude Fable 5 1a3bb4f6f5 refactor(display): address review feedback on the term renderer
- layoutFrame clips its output to the terminal height: height==1 no
  longer overflows with header + more-marker
- the two status-to-color switches merge into eventColor(status, def)
- the clear-suspension sequence extracts into unsuspend()
- tests drive a manually-advanced fake clock through the injected
  now(), and the cancel test loses its settling sleep — Done waits for
  the refresh goroutine itself
- roots, per-parent children and the completed count are maintained
  incrementally by apply(), so a 100ms tick with an unchanged tree no
  longer rescans every task
- the frame<0 clamp in spinGlyph drops: time comes from the writer's
  single clock and never regresses; the invariant is documented on the
  model
- Start's retire-previous-cycle comment spells out that cancellation
  only guarantees the old goroutine will exit, not that it already has

Co-Authored-By: Claude Fable 5 <[email protected]>
Signed-off-by: Nicolas De Loof <[email protected]>
2026-09-09 16:50:05 +02:00
Nicolas De Loof d82edca1c2 fix(display): harden termWriter lifecycle against review findings on #14119
Transposes the applicable findings from the review of the ttyWriter fix
(#14119) to the rewritten renderer:

- Done waits for the refresh goroutine to exit (outside the lock), so
  nothing can repaint after Done returns and output printed right after
  an operation cannot be garbled by a stray frame
- a nested Start retires the previous cycle instead of leaking its
  refresh goroutine until the parent context is cancelled
- build suspension no longer leaks across cycles: Start resets it and
  starts a fresh block below whatever buildkit wrote
- drop the dead strings.ToLower in startDependencies: the unexported
  start only reads projectName when no Project is passed

The remaining findings are structural to this rewrite: Done is a single
critical section, and per-cycle context cancellation replaces the
doneSignal handshake.

Signed-off-by: Nicolas De Loof <[email protected]>
2026-09-09 16:50:05 +02:00
Nicolas De LoofandClaude Fable 5 136763181b fix(display): clip the header line to the terminal width like every other row
The "[+] op N/M" header was the one line bypassing renderSegs, so on a
very narrow terminal it could wrap and desync the cursor arithmetic the
rest of the design guarantees against. Route it through the same clip
and cover degenerate widths (8, 12 cells) in the invariant test.

Co-Authored-By: Claude Fable 5 <[email protected]>
Signed-off-by: Nicolas De Loof <[email protected]>
2026-09-09 16:50:05 +02:00
Nicolas De LoofandClaude Fable 5 9fc38cce0e refactor(display): rebuild the TTY progress renderer on a model/layout/screen split
The TTY renderer accumulated display-corruption fixes (truncation of
details, then progress sizes, then task ids; timer alignment; rune-based
measurement) that each patched one symptom of the same structural gap:
nothing guaranteed a rendered line fits the terminal, and once a line
wraps, cursor arithmetic desyncs and the block corrupts.

Replace it with three separable units:

- tty_model.go: pure event reducer with an injected clock, preserving
  first-parent-wins updates, monotonic progress and header counters
- tty_layout.go: pure (model, size, now) -> lines function; all widths
  are measured in terminal cells (go-runewidth, so CJK is correct) on
  plain text before coloring, and every line is clipped to the terminal
  width by construction, status text included
- tty_screen.go: diff-based repaint; unchanged rows are skipped,
  identical frames write nothing, a frame is a single Write; a shrinking
  terminal abandons the block instead of moving the cursor over reflowed
  rows

The writer coordinates them behind a mutex and stops the refresh
goroutine through context cancellation, so Done cannot block when the
operation context was cancelled first (Ctrl-C during pull). The spinner
frame is derived from the clock instead of advancing on every call, and
truncation can no longer split multi-byte runes. Visual output is
unchanged: the snapshot test reproduces the previous renderer's golden
output character for character.

Co-Authored-By: Claude Fable 5 <[email protected]>
Signed-off-by: Nicolas De Loof <[email protected]>
2026-09-09 16:50:05 +02:00
Guillaume Lours 8018a96fde feat(compose): warn on unsupported compose-file attributes
Compose silently ignored several spec-valid attributes it doesn't
honor outside Swarm mode: deploy.update_config, credential_spec,
ports[].mode: host, and others had no visible effect on a plain
`docker compose up`.

Detection is wired into compose-go's loader as a fail-closed
allowlist: every attribute path the schema declares, minus the
handful this runtime deliberately doesn't implement, plus a few
value-conditional checks for attributes only unsupported for one
specific value. A newly-specified attribute gets flagged
automatically, with no corresponding code change needed here.

Depends on an unreleased compose-go change; go.mod carries a
temporary replace to a fork branch until it's released.

Signed-off-by: Guillaume Lours <[email protected]>
2026-09-09 16:32:04 +02:00
Sebastiaan van Stijn db9a43d7c1 fix(deps): github.com/moby/sys/userns v0.2.1
userns: fix user-namespace detection on OpenVZ, where namespace inode
numbers are virtualized.

full diff: https://github.com/moby/sys/compare/userns/v0.2.0...userns/v0.2.1

Signed-off-by: Sebastiaan van Stijn <[email protected]>
2026-09-09 08:03:13 +02:00
Sebastiaan van Stijn 460cf3c429 golangci-lint: set e2e build-tag to prevent false "unused" positives
Signed-off-by: Sebastiaan van Stijn <[email protected]>
2026-09-08 15:55:48 +02:00
Sebastiaan van Stijn f03c1b7cfb remove jonboulle/clockwork for testing/synctest
The fake clock is only used by tests to control the debounce timer,
but requires carrying a clock abstraction through production code.

Use the standard time package for the debounce ticker and use
testing/synctest to control time in tests instead.

This removes the clock from composeService and BatchDebounceEvents,
and eliminates the clockwork dependency from the watch implementation.

Signed-off-by: Sebastiaan van Stijn <[email protected]>
2026-09-08 15:55:48 +02:00
Nicolas De Loof a255af9368 feat(provider): get-service-config provider request
Providers could not see the definition of the service they manage:
options had to be duplicated between the compose file and the provider,
or the provider had to re-resolve the model on its own.

A provider may now emit {"type": "get-service-config"} on stdout;
compose answers on the provider's stdin with one JSON line holding the
resolved canonical configuration of the provider's own service,
straight from the in-memory model. The message can be repeated; each
occurrence is answered with one line. Detection is by construction: a
compose that predates the message aborts on it and never writes to
stdin, so the provider treats EOF as 'unsupported, upgrade compose'.

The example provider demonstrates the round trip, backed by an e2e
scenario; unit tests drive executePlugin against a helper-process
provider and cover the injection.

Signed-off-by: Nicolas De Loof <[email protected]>
2026-09-08 14:53:14 +02:00
Nicolas De Loof 75331cd042 fix(build): hand unresolved 'auto' progress mode to bake
display.Mode resolves "auto" against stderr — the stream Compose's own
progress renders to — so `compose build >/dev/null` in an interactive
terminal resolves to "tty". Bake reuses that mode for a display writing
to stdout, and buildkit's progressui hard-fails in tty mode when the
stream is not a console.

Pass the unresolved "auto" to bake unless the user explicitly asked for
tty: progressui then probes the actual output stream and degrades to
plain by itself when stdout is redirected. An explicit --progress=tty
keeps failing loudly on a non-terminal, as `buildx bake` does. This
also revives the BUILDKIT_PROGRESS override in doBuildBake, which only
applies to AutoMode and could no longer trigger.

Fixes #14182

Signed-off-by: Nicolas De Loof <[email protected]>
2026-09-07 14:11:12 +02:00
dependabot[bot] 9943e1d220 build(deps): bump softprops/action-gh-release from 3.0.2 to 3.0.3
Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 3.0.2 to 3.0.3.
- [Release notes](https://github.com/softprops/action-gh-release/releases)
- [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md)
- [Commits](https://github.com/softprops/action-gh-release/compare/3d0d9888cb7fd7b750713d6e236d1fcb99157228...efb35369e0ad2afab669f228072c1b0d510eae64)

---
updated-dependencies:
- dependency-name: softprops/action-gh-release
  dependency-version: 3.0.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
2026-09-07 13:55:01 +02:00
Sebastiaan van Stijn 7c808c29c3 fix(deps): github.com/containerd/containerd/v2 v2.3.5
full diff: https://github.com/containerd/containerd/compare/v2.3.4...v2.3.5

Security Updates

- [**CVE-2026-53495**](https://github.com/containerd/containerd/security/advisories/GHSA-7jxh-36q5-gcqv)
- [**GHSA-rp3h-jf77-q9p4**](https://github.com/containerd/containerd/security/advisories/GHSA-rp3h-jf77-q9p4)

Image Distribution

- Apply hardening to strip sensitive authentication headers when fetching descriptor URLs

Runtime

- Avoid hangs and data races when streaming container standard I/O in CRI
- Fix missing error messages in OpenTelemetry trace attributes
- Fix user and group lookup failures in container rootfs containing symlinked /etc/passwd or /etc/group
- Fix configuration loading error when drop-in configuration files have a higher version than the root configuration
- Avoid containerd startup hangs when loading shims
- Add context to error when shim delete times out
- Fix Windows Server 2022 container compatibility on host builds newer than the latest LTSC

Snapshotters

- Fix unpack failure for EROFS images containing the erofs OS feature

Signed-off-by: Sebastiaan van Stijn <[email protected]>
2026-09-07 10:01:37 +02:00
Guillaume Lours 5f94fb0aa4 bump compose-go to version v2.15.0
Signed-off-by: Guillaume Lours <[email protected]>
v5.5.1
2026-09-03 17:28:21 +02:00
hiroto.toyoda 20717bab83 fix(down): spare dangling images of orphaned services, like their tagged image
`down --rmi` removed every dangling image for the project unconditionally,
while its tagged-image counterpart (ImagesToPrune) already skips a service
no longer in the project unless --remove-orphans is set. `down --rmi local`
on a project with an orphaned service therefore kept the tagged image but
deleted its dangling ones - an inconsistent result for one command.

Extract the "list a project's dangling images, remove what a keep predicate
doesn't spare, tolerate individual failures" logic - which down.go and
watch.go's pruneDanglingImagesOnRebuild had each partially and divergently
implemented - into one shared composeService.removeDanglingImages,
parallelized via errgroup like the rest of the codebase's bulk removals.
down.go's keep now mirrors ImagesToPrune's own RemoveOrphans/GetService
check; watch.go keeps its existing built-IDs check, behavior unchanged.

The removal fan-out now also honors --parallel via eg.SetLimit(s.maxConcurrency),
matching push.go/pull.go, instead of always running unbounded. Fixed
TestWatch_Sync's composeService{} literal to set maxConcurrency: -1
(NewComposeService's own default) - the zero value means "allow zero
concurrent goroutines" to errgroup, not "unlimited", and was silently
relying on maxConcurrency being unused before this change.

Signed-off-by: hiroto.toyoda <[email protected]>
2026-09-03 16:00:29 +02:00
hiroto.toyoda a966bad33a fix(down): spare dangling images of orphaned services, like their tagged image
`down --rmi` removed every dangling image for the project unconditionally,
while its tagged-image counterpart (ImagesToPrune) already skips a service
no longer in the project unless --remove-orphans is set. `down --rmi local`
on a project with an orphaned service therefore kept the tagged image but
deleted its dangling ones - an inconsistent result for one command.

Extract the "list a project's dangling images, remove what a keep predicate
doesn't spare, tolerate individual failures" logic - which down.go and
watch.go's pruneDanglingImagesOnRebuild had each partially and divergently
implemented - into one shared composeService.removeDanglingImages,
parallelized via errgroup like the rest of the codebase's bulk removals.
down.go's keep now mirrors ImagesToPrune's own RemoveOrphans/GetService
check; watch.go keeps its existing built-IDs check, behavior unchanged.

Signed-off-by: hiroto.toyoda <[email protected]>
2026-09-03 16:00:29 +02:00
Guillaume Lours a896529193 fix(bridge): confirm before wiping non-empty convert output dir
`bridge convert -o <dir>` unconditionally ran `os.RemoveAll` on the
output directory and discarded any error, so a typo (`-o .`, `-o
$PWD`, `-o ~`) silently destroyed unrelated user data.

An empty or missing output directory is still created silently, but a
non-empty one now requires explicit confirmation (prompted
interactively, or via the new `--yes` flag for scripts/CI) before
being wiped.

Signed-off-by: Guillaume Lours <[email protected]>
2026-09-03 14:38:41 +02:00
Sebastiaan van Stijn 98c49ed13a build(deps): golang.org/x/crypto v0.56.0
full diff: https://github.com/golang/crypto/compare/v0.55.0...v0.56.0

We have tagged version v0.56.0 of golang.org/x/crypto in
order to address the following security issues:
- ssh: prevent DoS on deadlocked established channel
  Previously, after a channel has been established, a
  malicious peer could send crafted messages that would
  deadlock the entire connection.
  Now, we handle all RFC 4254 channel messages; global
  requests are handled explicitly. Then, treat all other
  messages as a protocol error and tear the connection
  down instead of buffering and blocking.
  Thanks to Will Mortensen for reporting this issue.
  This is CVE-2026-56855 and Go issue https://go.dev/issue/81317.
- ssh: prevent DoS on deadlocked undecided channel
  Previously, a channel registered in the mux's chanList is
  not usable until it is established. A malicious peer was
  able flood the channel's incomingRequests, deadlocking the
  entire connection.
  Now, we add an atomic established state, set when a channel
  becomes usable. Until such a time, handlePacket drops every
  packet other than the open confirmation/failure, without
  blocking and without tearing down the connection.
  Thanks to Will Mortensen for reporting this issue.
  This is CVE-2026-78662 and Go issue https://go.dev/issue/81316.

Signed-off-by: Sebastiaan van Stijn <[email protected]>
2026-09-03 07:50:39 +02:00
Sebastiaan van Stijn 5284c987b6 feat(deps): github.com/moby/buildkit v0.33.0
Signed-off-by: Sebastiaan van Stijn <[email protected]>
2026-09-02 18:54:23 +02:00
Sebastiaan van Stijn 70da291c66 build(deps): github.com/gofrs/flock v0.13.1
Signed-off-by: Sebastiaan van Stijn <[email protected]>
2026-09-02 18:54:23 +02:00
Sebastiaan van Stijn b237fe15f3 build(deps): go.opentelemetry.io/otel v1.46.0, contrib v0.71.0
Signed-off-by: Sebastiaan van Stijn <[email protected]>
2026-09-02 18:54:23 +02:00
Sebastiaan van Stijn 59664734c3 Update to go1.26.8
- https://github.com/golang/go/issues?q=milestone%3AGo1.26.7+label%3ACherryPickApproved
- https://github.com/golang/go/issues?q=milestone%3AGo1.26.8+label%3ACherryPickApproved
- full diff: https://github.com/golang/go/compare/go1.26.6...go1.26.8

Signed-off-by: Sebastiaan van Stijn <[email protected]>
2026-09-02 18:44:40 +02:00
Ricardo Branco 4121ec7d13 test(e2e): bump compose-bridge images to v0.0.7
v0.0.6 dropped the Egress policyType/block from generated
NetworkPolicy manifests since it blocked CoreDNS traffic; update
the fixtures to match.

Signed-off-by: Ricardo Branco <[email protected]>
2026-09-02 18:21:19 +02:00
Ricardo Branco 63f4764184 test(e2e): bump compose-bridge images to v0.0.7
v0.0.3 had a mis-published multi-arch manifest, causing exec format
errors on non-amd64 architectures.

Fixed upstream in docker/compose-bridge-transformer@665f67e.

Signed-off-by: Ricardo Branco <[email protected]>
2026-09-02 18:21:19 +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
dependabot[bot] d0c384aeae build(deps): bump github/codeql-action/upload-sarif
Bumps [github/codeql-action/upload-sarif](https://github.com/github/codeql-action) from 4.37.7 to 4.37.9.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd...cdf488f595d80d6e07e03d4674febd5ab45fa938)

---
updated-dependencies:
- dependency-name: github/codeql-action/upload-sarif
  dependency-version: 4.37.9
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
2026-09-02 15:37:36 +02:00
Guillaume Lours 05066c2418 fix(watch): stop swallowing SetRecursive errors via nolint
Split SetRecursive into the existing per-GOOS watcher files instead of
a runtime check + nolint: the non-Windows stub never calls the
always-failing SetRecursive, and Windows failures now propagate as a
real error instead of silently downgrading to non-recursive.

Addresses review from thaJeztah on #14164.

Signed-off-by: Guillaume Lours <[email protected]>
2026-09-02 15:07:08 +02:00
Nicolas De Loof 70e17bfc66 build: bump golangci-lint to v2.13.2
- migrate gomodguard to gomodguard_v2 (gomodguard is deprecated since
  v2.13 and warns on every run); same blocked modules, flat-list schema
- silence SA4023 in watcher_naive.go: tilt-dev/fsnotify SetRecursive
  only succeeds on Windows, so on any single GOOS the newer staticcheck
  proves the err == nil comparison constant — the cross-platform code
  is correct, the finding is per-GOOS

Signed-off-by: Nicolas De Loof <[email protected]>
2026-09-02 09:18:25 +02:00
Nicolas De Loof 2be4e2d656 fix(plugins): honor PATHEXT for provider lookup on Windows
The PATH fallback of provider discovery appended a hardcoded ".exe" on
Windows, restricting providers to compiled binaries. exec.LookPath
already implements Windows executable resolution (PATHEXT), which finds
.exe but also .com/.bat/.cmd scripts — the suffix only narrowed the
lookup. Drop the executable() indirection and look up the bare name.

Note this only affects the PATH fallback: the docker CLI plugin channel
(docker-<name>) keeps requiring .exe on Windows, per docker/cli plugin
candidate rules.

Fixes #14157

Signed-off-by: Nicolas De Loof <[email protected]>
2026-09-01 17:23:39 +02:00
Nicolas De Loof b3284911a3 refactor: NewGraph stops mutating the project
Building the dependency graph silently deleted unresolvable optional
depends_on references from the caller's project — and since DependsOn
is a map, even from projects sharing it. What later readers observed
depended on how many graphs had been built before them.

The pruning becomes an explicit step, applied once where the project
consumed by the engines is established — create and start — before the
graph, the dependency waits and the com.docker.compose.depends_on
label read the model, using Project.WithoutUnresolvedOptionalDependencies
introduced by compose-spec/compose-go#922 (go.mod bumped to the
post-merge commit). NewGraph now just skips the edge; required dangling
references still flow to its existing errors (naming the profiles that
would enable the dependency).

No behavior change; epic #14081, Lot 0 step 4 — precondition for a
canonical project object across plan phases.

Signed-off-by: Nicolas De Loof <[email protected]>
2026-09-01 10:19:10 +02:00
Nicolas De Loof 081ca8f645 chore(compose): orphan semantics stated where up and down diverge
A container is orphaned when it is a one-off (compose run) that FINISHED
its task, or when it carries the project labels but its service is not
defined by the compose model — the typical leftover after the compose
file was edited. A still-RUNNING one-off is somebody's live session:
'up --remove-orphans' cleans up leftovers and must never kill it.
'down --remove-orphans' is the explicit stop-the-application action, so
it DOES take running one-offs down — through the per-service removal
loop, not the orphan branch.

That asymmetry was implemented but stated nowhere: isOrphaned's comment
only mentioned the model-absent half, down.go removed running one-offs
as an unexplained side effect of including one-offs in the listing, and
the observed-state collection silently dropped running one-offs with no
hint it was deliberate. No behavior change — the semantics are now
written at all three sites and pinned by tests: the predicate matrix,
the observed-state classification (a running one-off is neither a
service replica nor an orphan), and down's single stop+remove path for
a running one-off of a declared service.

Closes item C.4 of #14074.

Signed-off-by: Nicolas De Loof <[email protected]>
2026-08-31 17:09:19 +02:00
Guillaume Lours e7c766fe3d fix(compose): reject unknown subcommands under bridge/transformations
bridgeCommand and transformersCommand had no RunE, so an unknown
subcommand (e.g. "bridge zzz") fell through cobra's default
non-Runnable path: help printed, exit 0. Scripts couldn't distinguish
a typo from success. Mirrors the same fix already shipped on the
compose root command.

Signed-off-by: Guillaume Lours <[email protected]>
2026-08-31 17:08:47 +02:00
hiroto.toyoda 727fa0e67d test(build): re-enable wrong ssh key id test
moby/buildkit#5558, which this test was disabled for, is fixed and
released well before the buildkit v0.26.3 currently vendored here.
Verified the re-enabled case passes (3 consecutive runs).

Signed-off-by: hiroto.toyoda <[email protected]>
2026-08-28 09:39:00 +02:00
Nicolas De Loof 720da68475 chore(compose): comments state behavior, not history
Eleven comments in the reconciler and its neighbors justified decisions
by pointing at code that no longer exists ('matching the previous
ensureNetwork behavior', 'same way as convergence.go:138-160' — lines
that today hold unrelated code) instead of stating the behavior and its
reason. A reader following those pointers finds nothing, or worse,
something else.

Each is rewritten as a self-contained behavioral statement. Two carry
real weight:
- reconcileService's up-to-date branch now says explicitly that
  starting containers is NOT the plan's job (a separate start phase in
  start.go does it) — the previous wording invited 'fixing' the
  StateCreated case;
- sortContainers now documents that its ordering IS the scale-down
  policy (the tail it produces is what i >= expected trims), instead of
  referencing stale line numbers.

Part of #14074 (A: the code misdescribes its own structure).

Signed-off-by: Nicolas De Loof <[email protected]>
2026-08-27 12:14:54 +02:00
Nicolas De Loof e801d5fc77 chore(compose): rename convergence.go, whose convergence engine no longer exists
The convergence type this file was named after was removed in fbea647b9,
but the file kept its name and its doc comment ('convergence manages
service's container lifecycle') ended up attached to the unrelated
getScale(). Anyone asked to 'change the convergence logic' lands here,
while the actual reconciliation lives in reconcile.go.

The file is renamed to service_containers.go with a header stating what
it really contains: the per-service container helpers shared by both
lifecycle engines (naming, service-reference resolution, dependency
waiting, container creation, startup). getScale gets a doc comment that
describes getScale.

Part of #14074 (A: the code misdescribes its own structure).

Signed-off-by: Nicolas De Loof <[email protected]>
2026-08-27 11:48:19 +02:00
Sebastiaan van Stijn f3b0d952fd fix(deps): google.golang.org/grpc v1.83.2
Both v1.83.1 and v1.83.2 are security releases; update to keep the
scanners happy.

full diff: https://github.com/grpc/grpc-go/compare/v1.82.0...v1.83.2

Signed-off-by: Sebastiaan van Stijn <[email protected]>
2026-08-27 11:21:32 +02:00
Sebastiaan van Stijn ea5ff1896e chore(deps): github.com/sirupsen/logrus v1.10.2
update to reduce some transitive dependencies

Signed-off-by: Sebastiaan van Stijn <[email protected]>
2026-08-27 11:21:32 +02:00
Nicolas De Loof 27b9995270 test(docs): compile the sdk.md examples
The fenced Go blocks in docs/sdk.md become real code under
docs/examples/sdk, built by the ordinary module build: API drift now
breaks compilation. A unit test pins the markdown to the compiled
files byte-for-byte (first block = main.go from its package clause
down, second block = customService's body), so wording drift breaks
the test instead of silently rotting the docs.

Epic #14074, section G.

Signed-off-by: Nicolas De Loof <[email protected]>
2026-08-27 11:21:03 +02:00
Nicolas De Loof 926a61b4f7 docs(contributing): legibility guidelines — comments state behavior, not history
The 'why, history and context' guidance was how the section-A findings of
epic #14074 were born: comments justifying code by referencing since-
deleted code. Rule 4 now asks for behavioral statements, and a Legibility
section spells out the map-must-stay-truthful rules for comments, file
names and error messages.

Signed-off-by: Nicolas De Loof <[email protected]>
2026-08-27 11:17:14 +02:00
Nicolas De Loof 8fbda262bb build: error messages name the real remedy, not a removed builder
The classic-builder rejections said 'set DOCKER_BUILDKIT=1 to use
BuildKit', a leftover from the internal BuildKit builder removed in
af579ebd4. Since then BuildKit builds go through the buildx plugin:
compose falls back to the classic builder when BuildKit is disabled
(DOCKER_BUILDKIT=0) OR when buildx is not installed — so the advertised
fix does nothing for users who are simply missing buildx.

The five messages now state the actual requirement (buildx installed,
DOCKER_BUILDKIT not forced to 0), and the silent-fallback warning when
buildx is missing now says what the fallback implies instead of a bare
'requires buildx plugin to be installed'.

Part of #14074 (A: the code misdescribes its own structure).

Signed-off-by: Nicolas De Loof <[email protected]>
2026-08-27 11:05:09 +02:00
Nicolas De Loof 7af58e3626 test(e2e): gate the e2e suite behind the build tag the docs already promise
AGENTS.md documents 'Test unit: go test ./pkg/...' and 'E2E tests:
go test -tags e2e ./pkg/e2e/'. Both statements were false: no file in
pkg/e2e carried an e2e build constraint, so the -tags flag was a no-op
and the 'unit' command actually launched the full e2e suite — requiring
a Docker daemon and the locally built binary, creating and destroying
containers, for up to 20 minutes. CI only avoided this by grepping e2e
out of the package list (Dockerfile).

Every *_test.go in pkg/e2e now carries //go:build e2e (merged with the
existing !windows constraints), and the Makefile e2e targets pass the
tag. The documented commands become true:
- go test ./pkg/...          -> pkg/e2e reports [no test files]
- go test -tags e2e ./pkg/e2e -> runs the suite

AGENTS.md now also states the daemon/binary prerequisites explicitly.

Part of #14074 (A: the code misdescribes its own structure).

Signed-off-by: Nicolas De Loof <[email protected]>
2026-08-27 11:02:07 +02:00
Nicolas De Loof 7b63e4fa33 docs(sdk): document the EventProcessor API that actually exists
sdk.md advertised a 'progress' package (progress.NewTTYWriter,
NewPlainWriter, NewJSONWriter, NewQuietWriter) that does not exist in
the repository, and typed WithEventProcessor against it. Anyone
following the doc writes code that cannot compile — or recreates the
phantom package.

The section now points at the real surface: api.EventProcessor, the
silent-by-default behavior when no processor is configured, and the
CLI's actual renderers in cmd/display (Full, Plain, JSON, Quiet) with
their real signatures.

Part of #14074 (A: the code misdescribes its own structure).

Signed-off-by: Nicolas De Loof <[email protected]>
2026-08-27 10:57:44 +02:00
Guillaume Lours 03ad3cc1c2 fix(build): honor provenance/sbom false in per-service bake attest
When a service set `build.provenance: false` (or `sbom: false`), the
bake attest entry was silently omitted (the field is `omitempty`),
so BuildKit applied its defaults and attached a provenance attestation
anyway. The attestation changes the manifest-list digest on every build,
which caused containers to be needlessly recreated on `up --build`.

Emit `"type=<t>,disabled=true"` instead, which BuildKit's
`Attest.UnmarshalText` parses as `Disabled:true` and forwards to
BuildKit as an explicit disable signal.

Extract `appendAttest` to avoid duplicating the three-branch switch
for both provenance and sbom.

Fixes #14111

Signed-off-by: Guillaume Lours <[email protected]>
2026-08-25 17:46:03 +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
Guillaume Lours 6d3d68c1fa fix(display): stop ttyWriter.Done from hanging after context cancel
Fixes #14114: Done() blocked forever once the render goroutine had
already exited via ctx.Done() (e.g. after SIGTERM), since it sent on an
unbuffered channel with nobody left to receive.

Closing the channel instead of sending never blocks, but a bare close()
panics the moment ttyWriter runs a second Start/Done cycle on the same
shared bus - which already happens today (run's nested create/start,
publish's nested push, rm --stop's sequential stop then remove). Start
now hands out a fresh, once-only-closable signal each cycle instead of
a single shared channel, and run/publish stop opening a redundant
nested bracket around calls already inside one.

Signed-off-by: Guillaume Lours <[email protected]>
2026-08-25 11:38:50 +02:00
hiroto.toyoda 8ddbdc41a2 fix(watch): match Dockerfile/compose ignore patterns by literal name and basename
Signed-off-by: hiroto.toyoda <[email protected]>
2026-08-24 14:48:22 +02:00
hiroto.toyoda 11d4aadf4f fix(watch): exclude Dockerfile and compose files from initial sync
Signed-off-by: hiroto.toyoda <[email protected]>
2026-08-24 14:48:22 +02:00
Guillaume Lours f729794270 docs(hooks): document pre_start hook container retention and cleanup
- compose_down.md: note that retained pre_start hook containers (those
  kept after a hook failure for post-mortem) are automatically removed
  by compose down, with the label filter to list them beforehand.
- compose_up.md: note the retention behavior on pre_start hook failure,
  how to inspect the retained container, and that it is cleaned up on
  the next compose up or compose down.

Signed-off-by: Guillaume Lours <[email protected]>
2026-08-20 18:57:02 +02:00