fix(compose-doctor): recognize Docker socket proxy topologies (#1791)

* fix(compose-doctor): recognize Docker socket proxy topologies

Classify dedicated socket proxies separately from direct docker.sock mounts so Doctor no longer recommends adopting a proxy the stack already uses. Closes #1790.

* fix(compose-doctor): widen socket proxy detection and flag writable proxy sockets

Close the remaining gaps in socket proxy topology handling: a service that
points at a proxy through a tcp:// endpoint on its command line (how Traefik
and friends do it) now gets the client note, proxy API group flags are read
for any truthy value rather than a literal 1, and underscore or dot separated
proxy names are recognized.

Two cases that previously slipped through now surface: a service classified
as a proxy purely by name or image but mounting docker.sock read-write is
reported as high, and a proxy on the implicit default network or on a network
the rendered model does not describe counts as non-internal. A direct socket
mount alongside an existing proxy now names that proxy in its fix.

* fix(compose-doctor): require corroboration before a service name classifies a socket proxy

A service name is free text the author controls, so on its own it could move a
writable docker.sock mount out of the high direct-mount finding. A known proxy
image is an artifact identity and still stands alone; a proxy-shaped name now
counts only alongside an observable fact, a read-only socket or a scoped API
group key.

* fix(compose-doctor): tighten socket-proxy detection against live upstream behavior

Require proxy API flags to be exactly 1 (matching tecnativa and linuxserver
images), count only those enabled flags when classifying a proxy, extract
tcp hosts from DOCKER_HOST instead of treating key presence as a proxy client,
and correlate each client note to one proxy instance by both name and shared
network. Soften the published-port finding so it claims reachability rather
than Docker API exposure for unrelated ports.
This commit is contained in:
Anso
2026-08-08 01:32:26 -04:00
committed by GitHub
parent 5c52ae26eb
commit bb98cba1f2
13 changed files with 996 additions and 29 deletions
@@ -132,7 +132,8 @@ describe('buildMounts', () => {
{ type: 'bind', source: '/app/stack/conf', target: '/conf', readOnly: true },
{ type: 'named', source: 'shared', target: '/s', readOnly: false },
],
privileged: false, hasHealthcheck: true, composeHealthcheck: 'active', envKeys: [], networks: [], extraHosts: [], labelKeys: [],
privileged: false, hasHealthcheck: true, composeHealthcheck: 'active',
envKeys: [], enabledProxyApiFlags: [], dockerEndpointHosts: [], networks: [], extraHosts: [], labelKeys: [],
},
],
networks: {},
@@ -161,7 +162,8 @@ describe('assembleStorageInventory', () => {
projectName: 'a', services: [{
name: 'app', ports: [], binds: [], namedVolumes: [],
storageMounts: [{ type: 'named', source: 'db', target: '/db', readOnly: false }],
privileged: false, hasHealthcheck: true, composeHealthcheck: 'active', envKeys: [], networks: [], extraHosts: [], labelKeys: [],
privileged: false, hasHealthcheck: true, composeHealthcheck: 'active',
envKeys: [], enabledProxyApiFlags: [], dockerEndpointHosts: [], networks: [], extraHosts: [], labelKeys: [],
}], networks: {}, volumes: {},
};
expect(assembleStorageInventory('a', stateful, null, new Map()).stateful).toBe(true);
@@ -178,7 +180,8 @@ describe('assembleStorageInventory', () => {
projectName: 'a', services: [{
name: 'app', ports: [], binds: [], namedVolumes: [],
storageMounts: [{ type: 'bind', source: '/var/run/docker.sock', target: '/var/run/docker.sock', readOnly: false }],
privileged: false, hasHealthcheck: true, composeHealthcheck: 'active', envKeys: [], networks: [], extraHosts: [], labelKeys: [],
privileged: false, hasHealthcheck: true, composeHealthcheck: 'active',
envKeys: [], enabledProxyApiFlags: [], dockerEndpointHosts: [], networks: [], extraHosts: [], labelKeys: [],
}], networks: {}, volumes: {},
};
expect(assembleStorageInventory('a', socketOnly, null, new Map()).stateful).toBe(false);