Skip to content

fix(backend): move Docker client to the maintained moby client module#1935

Merged
jcfs merged 1 commit into
mainfrom
feature/analyse-and-fix-upst-4g5
Jul 24, 2026
Merged

fix(backend): move Docker client to the maintained moby client module#1935
jcfs merged 1 commit into
mainfrom
feature/analyse-and-fix-upst-4g5

Conversation

@jcfs

@jcfs jcfs commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Summary

Clears the five open Docker alerts on the Dependabot page by moving the backend off github.com/docker/docker, and corrects a stale rationale in the cargo-audit ignore list.

What the alerts actually are

Alert CVE Severity Vulnerable range Patched on docker/docker?
#141 CVE-2026-42306 high <= 28.5.2 never
#139 CVE-2026-41567 high <= 28.5.2 never
#140 CVE-2026-41568 medium <= 28.5.2 never
#68 CVE-2026-34040 high < 29.3.1 unreachable
#67 CVE-2026-33997 medium < 29.3.1 unreachable

There was no version bump available for any of them, and the reason is structural rather than a missing release. github.com/docker/docker stops at v28.5.2 — the last tag on that module path. Moby v29+ publishes under github.com/moby/moby/v2, and the API client was split into two standalone modules, github.com/moby/moby/client and github.com/moby/moby/api. So "upgrade to 29.3.1" is not something the old import path can express; the three <= 28.5.2 advisories list their fix under github.com/moby/moby/v2 instead.

All five are daemon-side defects — docker cp races, the archive endpoint, plugin authorization. We only ever imported client and api/types/*, so none of them were reachable from our code. But the module carries the whole daemon source, which is why Dependabot flags us, and it will keep doing so for every future daemon CVE.

Moving to the split client module fixes the class rather than the instances: the daemon source leaves the module graph, so these five resolve and future daemon advisories never reach us. It also drops six transitive dependencies (containerd/log, moby/sys/atomicwriter, moby/term, morikuni/aec, pkg/errors, gotest.tools/v3).

Migration notes

The new client takes an options struct per call and returns a result struct, so the wrapper rewrite is mostly mechanical. Genuine behaviour changes worth review:

  • Ports moved from docker/go-connections/nat to moby/api/types/network. network.Port is opaque and PortBinding.HostIP is a netip.Addr rather than a string. buildDockerPortBindings now returns an error for out-of-range container ports and unparseable host IPs, instead of handing the daemon a malformed request and getting an opaque failure back. An empty HostIP still maps to the zero address, which preserves Docker's publish-on-all-interfaces behaviour — there's a test pinning that.
  • DiskUsage needs Verbose: true for the daemon to return per-image and per-container records; without it only aggregates come back and the storage page would show empty lists. The flat LayersSize is now Images.TotalSize.
  • BuildCachePrune no longer has a KeepStorage field. We were setting both it and ReservedSpace to the same value; the client now derives the legacy keep-storage query parameter from ReservedSpace when talking to daemons on API <= 1.47, so the duplication goes away.
  • ImagesPrune is now ImagePrune.
  • Container state and health are typed string enums, and InspectResponse.Config / .State are pointers. Inspect mapping is extracted into applyContainerState and guards for nil rather than dereferencing blind.

github.com/creack/pty (1.1.21 → 1.1.24) and Microsoft/go-winio (0.4.21 → 0.6.2) moved as a consequence of minimal version selection.

API version negotiation is still on, so older daemons remain supported.

Second change: the glib note in audit.toml

While going through the remaining alerts I found the ignore entry for RUSTSEC-2024-0429 (glib 0.18.5) was justified with something that isn't true:

will resolve when Tauri migrates to webkit2gtk-4.1 which pulls glib >= 0.20.0

Tauri v2 is already on the webkit2gtk-4.1 bindings and still resolves glib to 0.18.5. The actual blocker is that gtk-rs/gtk3-rs — which publishes gtk, gdk, webkit2gtk and friends — was archived in March 2024, so no GTK3 release depending on glib >= 0.20 will ever exist. Tauri closed its own tracking issue as not_planned and targets GTK4 for v3, so waiting on that is a multi-year no-op.

The comment now says what's really going on. There is a way out, though: the unsound code is in glib, whose repo is active and still has a live 0.18 branch, and gtk 0.18.2's dependency is a caret requirement. A glib 0.18.6 would fix this for us on the next cargo update with no changes to anything archived. I've submitted that upstream — gtk-rs-core#2009 backports the two-character fix to 0.18, #2010 asks for the release. The advisory reproduces on rustc 1.97.1 and the 0.18 branch's own test suite SIGSEGVs in release mode, so it's a real crash rather than a theoretical unsoundness. We drop the ignore entry if and when 0.18.6 ships.

Testing

  • go build ./..., go vet ./..., go mod verify clean.
  • golangci-lint run ./internal/agent/docker/... --new-from-rev=<base> — 0 issues.
  • go test -race ./... — the only failures are the pre-existing TestServiceInitializeLocalRepository* set, which fail identically on a pristine main checkout in this environment (symlink resolution under a sandboxed TMPDIR). Untouched by this change.
  • New coverage in client_test.go for the port-binding validation paths, the all-interfaces case, and parseHostPort.
  • storage_test.go now asserts that DiskUsage requests Verbose, since forgetting it silently empties the storage page.

Still open after this

One alert remains: #178, glib, medium, and it stays open until the upstream release lands. Worth noting separately that Dependabot security updates are currently disabled on the repo and there is no .github/dependabot.yml, so nothing opens version-bump PRs on a schedule. That looked like it might be deliberate, so I've left it alone rather than turning it on in this PR.

Review in cubic

github.com/docker/docker is frozen at v28.5.2 — moby publishes v29+ under
github.com/moby/moby/v2, with the API client split out into the standalone
github.com/moby/moby/client and github.com/moby/moby/api modules. That leaves
five Dependabot alerts on the old module path with no reachable fix version:

  CVE-2026-42306  high    docker cp bind mount redirection      <= 28.5.2
  CVE-2026-41567  high    PUT /containers/{id}/archive          <= 28.5.2
  CVE-2026-41568  medium  docker cp symlink swap                <= 28.5.2
  CVE-2026-34040  high    AuthZ plugin bypass                   < 29.3.1
  CVE-2026-33997  medium  plugin privilege off-by-one           < 29.3.1

All five are daemon-side defects, and we only ever imported the client. Moving
to the split client module drops the daemon source out of the module graph
entirely, so these alerts resolve and future daemon advisories will not flag us
at all. It also trims six transitive dependencies.

The new client takes an options struct per call and returns a result struct, so
this is a mechanical rewrite of the wrapper. Behavioural notes:

- Ports moved from docker/go-connections/nat to moby/api/types/network, where
  Port is opaque and PortBinding.HostIP is a netip.Addr. buildDockerPortBindings
  now returns an error for out-of-range ports and unparseable host IPs instead
  of handing the daemon a malformed request. An empty HostIP still maps to the
  zero address, preserving "publish on all interfaces".
- DiskUsage needs Verbose to get per-image and per-container records; the
  aggregate LayersSize is now Images.TotalSize.
- BuildCachePrune no longer takes KeepStorage — the client derives the legacy
  keep-storage parameter from ReservedSpace for daemons on API <= 1.47.
- ImagesPrune is now ImagePrune.
- Container state and health are typed string enums, and InspectResponse.Config
  and .State are pointers, so inspect mapping guards for nil.

Also corrects the RUSTSEC-2024-0429 note in the cargo-audit ignore list. It
claimed the advisory resolves once Tauri moves to webkit2gtk-4.1, but Tauri v2
is already on those bindings and still resolves glib to 0.18.5; the real
blocker is that gtk3-rs is archived. Backport submitted upstream.
@coderabbitai

coderabbitai Bot commented Jul 24, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Summary by CodeRabbit

  • Bug Fixes
    • Improved Docker container lifecycle, image building, networking, and logging compatibility.
    • Added validation for container ports and host addresses to provide clearer errors for invalid configurations.
    • Improved handling of container state, health information, IP addresses, and published ports.
    • Improved disk usage reporting and cleanup of unused images and build cache.
  • Maintenance
    • Updated Docker integration components and security audit tracking.

Walkthrough

The backend Docker integration migrates container, networking, inspection, lifecycle, and storage operations to typed Moby client APIs. Tests update fakes and coverage for typed responses and port validation. Go dependencies and a desktop cargo-audit note are also updated.

Changes

Docker client migration

Layer / File(s) Summary
Typed client contracts and API wiring
apps/backend/go.mod, apps/backend/internal/agent/docker/client.go, apps/backend/internal/agent/docker/activity_test.go
Docker interfaces, construction, image operations, lifecycle calls, and test doubles adopt typed Moby client options and results.
Container creation and networking
apps/backend/internal/agent/docker/client.go, apps/backend/internal/agent/docker/client_test.go
Container port bindings now use typed network maps, validate ports and host addresses, and propagate invalid configuration errors.
Inspection and container state
apps/backend/internal/agent/docker/client.go, apps/backend/internal/agent/docker/client_test.go
Inspection, state mapping, IP and host-port lookup, waiting, listing, logs, and attachment use the newer typed API surface.
Storage usage and pruning
apps/backend/internal/agent/docker/storage.go, apps/backend/internal/agent/docker/storage_test.go
Disk usage and prune operations use typed options/results, with tests covering reports, filters, and updated storage fakes.

Cargo audit tracking note

Layer / File(s) Summary
Advisory tracking commentary
apps/desktop/src-tauri/.cargo/audit.toml
The glib advisory ignore commentary now documents the dependency chain, migration direction, and upstream tracking references.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

  • kdlbs/kandev#1926: Updates overlapping Go module dependency resolution in apps/backend/go.mod.

Suggested reviewers: carlosflorencio

Poem

I’m a rabbit with ports in a row,
Moby types make the bindings glow.
Containers inspect, then safely wait,
Pruning reports arrive in typed state.
Go modules hop; audit notes gleam—
A tidy burrow for Docker’s dream.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The body covers the goal, migration details, and testing, but it deviates from the template and omits the required Checklist section. Rewrite the body to match the template: add the Checklist section, remove the Summary heading, and keep Summary and Validation concise.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: replacing the backend Docker client with the maintained Moby client module.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/analyse-and-fix-upst-4g5

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@claude

claude Bot commented Jul 24, 2026

Copy link
Copy Markdown

Claude finished @jcfs's task in 1s —— View job


I'll analyze this and get back to you.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
apps/backend/internal/agent/docker/client.go (2)

274-315: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicate container/host config construction across CreateContainer and CreateContainerInteractive.

Both functions now repeat the same buildDockerPortBindings call + error wrap, mount building, containerCfg/hostCfg construction, and ContainerCreate invocation. Since this PR already touches both call sites to add error handling, consider extracting a shared helper (e.g. buildContainerCreateInputs(cfg ContainerConfig) (*container.Config, *container.HostConfig, error)) that both callers customize (interactive fields on top).

As per path instructions, apps/backend/**/*.go must "Keep functions within the configured quality limits... and no large duplicated blocks; extract helpers when limits are reached."

Also applies to: 743-790

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/backend/internal/agent/docker/client.go` around lines 274 - 315, Extract
the duplicated container and host configuration construction from
CreateContainer and CreateContainerInteractive into a shared helper such as
buildContainerCreateInputs, including mount and port-binding setup with
contextual error wrapping. Have both callers reuse the helper, then apply only
their interactive-specific configuration before invoking ContainerCreate,
preserving existing logging and error behavior.

Source: Path instructions


444-495: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Verify test coverage for the refactored inspection/state/IP/host-port helpers.

inspectContainer, applyContainerState (with its nil-State/nil-Config handling), the netip-validity IP selection in GetContainerIP, and the new parse/normalize path in GetContainerHostPort are new or materially changed logic. client_test.go's diff only adds coverage for buildDockerPortBindings, normalizeDockerHostIP, and parseHostPort — no visible tests exercise GetContainerInfo/GetContainerIP/GetContainerHostPort against the new typed inspect response (e.g. nil State/Config, invalid IPAddress).

As per coding guidelines, "Every code change must include tests for new or changed logic, except configuration files, generated code, and React component markup" for **/*.go files.

Also applies to: 507-532, 535-583

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/backend/internal/agent/docker/client.go` around lines 444 - 495, Add
client tests covering GetContainerInfo with nil State and Config, including
inspectContainer’s typed response handling; cover GetContainerIP selecting only
netip-valid addresses; and cover GetContainerHostPort’s parse/normalize behavior
with representative valid and invalid host-port inputs. Reuse existing test
helpers or fixtures where possible and preserve current error and zero-value
behavior.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@apps/backend/internal/agent/docker/client.go`:
- Around line 274-315: Extract the duplicated container and host configuration
construction from CreateContainer and CreateContainerInteractive into a shared
helper such as buildContainerCreateInputs, including mount and port-binding
setup with contextual error wrapping. Have both callers reuse the helper, then
apply only their interactive-specific configuration before invoking
ContainerCreate, preserving existing logging and error behavior.
- Around line 444-495: Add client tests covering GetContainerInfo with nil State
and Config, including inspectContainer’s typed response handling; cover
GetContainerIP selecting only netip-valid addresses; and cover
GetContainerHostPort’s parse/normalize behavior with representative valid and
invalid host-port inputs. Reuse existing test helpers or fixtures where possible
and preserve current error and zero-value behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 27730807-a651-4d92-864b-f68fc5661867

📥 Commits

Reviewing files that changed from the base of the PR and between f85b648 and b4df627.

⛔ Files ignored due to path filters (1)
  • apps/backend/go.sum is excluded by !**/*.sum
📒 Files selected for processing (7)
  • apps/backend/go.mod
  • apps/backend/internal/agent/docker/activity_test.go
  • apps/backend/internal/agent/docker/client.go
  • apps/backend/internal/agent/docker/client_test.go
  • apps/backend/internal/agent/docker/storage.go
  • apps/backend/internal/agent/docker/storage_test.go
  • apps/desktop/src-tauri/.cargo/audit.toml

@jcfs
jcfs merged commit 767cc89 into main Jul 24, 2026
59 of 60 checks passed
@jcfs
jcfs deleted the feature/analyse-and-fix-upst-4g5 branch July 24, 2026 22:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant