v1.5.0-rc.23
[1.5.0-rc.23] — 2026-05-16
Added
-
Self-update now works when Drydock reaches the Docker daemon over a TCP host, not only through a bind-mounted
/var/run/docker.sock(commitfc34ffb9). The self-update helper container — the short-lived container that outlives Drydock to stop the old instance, health-check the replacement, and commit or roll back — was hardcoded to a bind-mounted Unix socket and aborted withSelf-update requires the Docker socket to be bind-mountedwhenever Drydock's watcher was configured with a TCPhost. That is the normal setup when a Docker socket proxy (such as sockguard ordocker-socket-proxy) mediates daemon access, so self-update was unavailable for those deployments even though every other container updated correctly.resolveHelperDockerConnectionnow inspects the watcher's Dockerode connection: a TCP host produces a TCP helper that is attached to Drydock's own Docker network (the container'sNetworkModeis cloned so the helper can resolve the proxy by DNS) and receivesDD_SELF_UPDATE_DOCKER_HOST/DD_SELF_UPDATE_DOCKER_PORT/DD_SELF_UPDATE_DOCKER_PROTOCOLinstead of a socket bind mount;runSelfUpdateControllerbuilds a TCP Dockerode client from those variables and skips the socket-only API-version probe and redirect guard. The bind-mounted-socket path is unchanged. When self-update runs through a filtering socket proxy the Drydock container must carry the proxy's ownership label so the helper is permitted to stop and replace it — seecontent/docs/current/configuration/self-update/index.mdx. -
The per-container Update button is locked with a
Self-update unavailableindicator when Drydock cannot update itself in the current deployment (commitcf777280). A new hardself-update-unavailableupdate-eligibility blocker is raised for the Drydock self-container when an update is available but self-update can run neither over a bind-mounted socket nor a TCP host — i.e. the watcher uses a Unix socket and/var/run/docker.sockis not present in the container. The blocker locks the per-row Update button with an explanatory tooltip and makesPOST /containers/:id/updatereturn409, instead of the previous behaviour where the button appeared actionable and the update failed mid-flight with a socket error. Deployments that reach Docker over TCP report self-update as available, so the button is unaffected there. The check fails open: when the watcher cannot be resolved the blocker is not raised. -
i18n coverage extended to the remaining hardcoded UI strings across 28 components (discussion #329, commit
1b65e591). A full audit of all 82 UI components found approximately 110 English strings that bypassedvue-i18nand rendered raw regardless of the active locale. The extraction sweep covers:AppLayoutsearch scopes, group labels, section subtitles, and the five deprecation banner bodies (converted to<i18n-t>so embedded<code>elements stay translatable);ThemeTogglevariant names;DataFilterBarview-mode names;DetailPanelsize labels (S / M / L); update-kind labels (Major/Minor/Patch/Digest) inContainerFullPageDetailandContainerFullPageTabContent, which are now reactivecomputedmaps so locale switches take effect without a page reload; tail/status labels and the stdout/stderr stream-type labels inContainerLogs; action tooltips and button labels inContainersGroupedViews; error messages and empty-state fallback labels across the Agents, Config, Registries, Triggers, Watchers, Notifications, NotificationOutbox, and Security views; and theWATCHINGwatcher-status badge, which was rendering the raw backend enum string. New keys land inen/appShell.json,en/containerComponents.json,en/listViews.json,en/sharedComponents.json,en/configView.json,en/agentsView.json, anden/notificationOutboxView.json. Non-translatable identifiers — the product name "Drydock" and format strings such asspdx-json/cyclonedx-json— are intentionally left as literals. Other locales pick up the new keys via theenfallback immediately and will receive human translations on the next Crowdin sync.
Changed
- Self-update helper now prefers the bind-mounted Docker socket over a TCP watcher connection (commit
aa828d88). The previousresolveHelperDockerConnectionlogic checked the watcher's TCP modem first, meaning that any deployment where Drydock was configured with a TCP host (e.g. routing through a socket proxy) would always route the helper through that proxy — even when the target container itself had/var/run/docker.sockbind-mounted. For infrastructure updates (dd.update.mode=infrastructure), where the container being replaced is the socket proxy, this is fatal: the helper relies on the proxy being up, but the update stops it. The resolution order is now inverted:findDockerSocketBindruns first, and if the target container carries a socket bind the helper uses that direct socket path regardless of the watcher's TCP configuration. The TCP path is preserved as the fallback for pure socket-less deployments where Drydock reaches Docker exclusively over a remote host.
Fixed
-
Dashboard Host Status widget no longer auto-scrolls to the last host when the host list changes (commit
cbe815a6). The full-mode host list usedscroll-snap-type: y mandatorywith a measured tail spacer. Whenever the host-row set changed — a watcher or agent added, removed, or renamed, or a full-to-compact mode transition — Chromium re-snapped to the last row's snap point, leaving only the final host visible above a large empty gap. The scroll-snap classes (snap-y,snap-mandatory,snap-start), the dynamic tail-spacer element, and the measurement machinery behind it (theonUpdatedhook,requestAnimationFramescheduler, andResizeObserver-triggered recompute) have all been removed. The content-aware full/compact sizing that keeps whole rows visible was already sufficient; the snapping added no functional value and actively fought the layout on every data change. -
Dashboard Resource Usage widget minimum height raised so per-container CPU and Memory lists stay visible (commit
59719757). Theresource-usagewidget'sminHwas set to 3 grid units (approximately 122 px), which falls below the 180 px threshold at which the per-container lists collapse out of view. The minimum is now 7 grid units (approximately 306 px).applyConstraintsclamps any saved layout item that is below the new minimum on load, so existing dashboard configurations with a shrunken resource-usage widget are silently corrected on the next render rather than persisting an unusable layout. -
AgentClienttimers are now cleared when an agent is removed, preventing orphaned timeouts (commit03bf7211).AgentClientmaintains twosetTimeouthandles —stableConnectionTimer(arms 30 s after the SSE response arrives to reset the backoff counter) andreconnectTimer(fires the next reconnect attempt after the exponential-backoff delay). Neither was cancelled whenremoveAgentspliced the client out of the manager's list. An agent removed mid-reconnect-cycle or mid-stability-window would keep an armed timer alive indefinitely, potentially triggering astartSsecall against a client that was no longer tracked and leaking the associated resources. A new idempotentstop()method onAgentClientcancels both timers and nulls the handles;removeAgentnow callsstop()on each matching client before splicing it.
Security
-
TCP Docker host is validated before the self-update controller passes it to Dockerode (commit
441b4358).DD_SELF_UPDATE_DOCKER_HOSTwas forwarded to Dockerode without sanitization. A newvalidateTcpDockerHostfunction rejects values that contain a URL scheme prefix (tcp://,http://,https://, or any<scheme>://form), a userinfo segment (@), whitespace, or path separators (/or\), throwing a descriptive error before any network connection is attempted. This prevents an environment variable or compose-file value from inadvertently injecting a path or URL component that Dockerode would interpret in an unexpected way. The validated host and resolved port are also logged atINFOlevel so the connection target is auditable in the container logs.runSelfUpdateControllerwas additionally refactored to remove a control-flow asymmetry: socket and TCP paths previously diverged into separate Dockerode-construct-and-run blocks; they now share a single tail (disableSocketRedirectsremains socket-only). -
OIDC error logs now redact RFC-1918 IP addresses and absolute filesystem paths (commit
9b79de77). The rc.22getErrorChainMessageimprovement walkserror.causechains up to depth 5 and appends the results to OIDC warn logs, which is the right diagnostic behaviour — but TLS and connection errors in Node/undici frequently include private network addresses (e.g.connect ECONNREFUSED 10.0.0.5:2376) and absolute filesystem paths (e.g.error loading /etc/ssl/certs/ca-bundle.pem) that should not appear in logs shipped to centralised observability systems.sanitizeOidcErrorMessagenow applies two additional redaction passes after the existing URL and bearer-token passes: RFC-1918 IPv4 ranges (10.x, 172.16–31.x, 192.168.x) with an optional port are replaced with[internal-addr]; absolute Unix filesystem paths of two or more segments are replaced with[path]. Public IP addresses are not redacted so legitimate DNS and routing errors remain actionable. The new passes run on the fully-assembled error-chain string, so they cover nested cause messages as well as the top-level error.