github CodesWhat/drydock v1.5.0-rc.23

pre-release3 hours ago

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 (commit fc34ffb9). 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 with Self-update requires the Docker socket to be bind-mounted whenever Drydock's watcher was configured with a TCP host. That is the normal setup when a Docker socket proxy (such as sockguard or docker-socket-proxy) mediates daemon access, so self-update was unavailable for those deployments even though every other container updated correctly. resolveHelperDockerConnection now inspects the watcher's Dockerode connection: a TCP host produces a TCP helper that is attached to Drydock's own Docker network (the container's NetworkMode is cloned so the helper can resolve the proxy by DNS) and receives DD_SELF_UPDATE_DOCKER_HOST / DD_SELF_UPDATE_DOCKER_PORT / DD_SELF_UPDATE_DOCKER_PROTOCOL instead of a socket bind mount; runSelfUpdateController builds 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 — see content/docs/current/configuration/self-update/index.mdx.

  • The per-container Update button is locked with a Self-update unavailable indicator when Drydock cannot update itself in the current deployment (commit cf777280). A new hard self-update-unavailable update-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.sock is not present in the container. The blocker locks the per-row Update button with an explanatory tooltip and makes POST /containers/:id/update return 409, 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 bypassed vue-i18n and rendered raw regardless of the active locale. The extraction sweep covers: AppLayout search scopes, group labels, section subtitles, and the five deprecation banner bodies (converted to <i18n-t> so embedded <code> elements stay translatable); ThemeToggle variant names; DataFilterBar view-mode names; DetailPanel size labels (S / M / L); update-kind labels (Major / Minor / Patch / Digest) in ContainerFullPageDetail and ContainerFullPageTabContent, which are now reactive computed maps so locale switches take effect without a page reload; tail/status labels and the stdout/stderr stream-type labels in ContainerLogs; action tooltips and button labels in ContainersGroupedViews; error messages and empty-state fallback labels across the Agents, Config, Registries, Triggers, Watchers, Notifications, NotificationOutbox, and Security views; and the WATCHING watcher-status badge, which was rendering the raw backend enum string. New keys land in en/appShell.json, en/containerComponents.json, en/listViews.json, en/sharedComponents.json, en/configView.json, en/agentsView.json, and en/notificationOutboxView.json. Non-translatable identifiers — the product name "Drydock" and format strings such as spdx-json / cyclonedx-json — are intentionally left as literals. Other locales pick up the new keys via the en fallback 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 previous resolveHelperDockerConnection logic 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.sock bind-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: findDockerSocketBind runs 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 used scroll-snap-type: y mandatory with 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 (the onUpdated hook, requestAnimationFrame scheduler, and ResizeObserver-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). The resource-usage widget's minH was 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). applyConstraints clamps 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.

  • AgentClient timers are now cleared when an agent is removed, preventing orphaned timeouts (commit 03bf7211). AgentClient maintains two setTimeout handles — stableConnectionTimer (arms 30 s after the SSE response arrives to reset the backoff counter) and reconnectTimer (fires the next reconnect attempt after the exponential-backoff delay). Neither was cancelled when removeAgent spliced 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 a startSse call against a client that was no longer tracked and leaking the associated resources. A new idempotent stop() method on AgentClient cancels both timers and nulls the handles; removeAgent now calls stop() 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_HOST was forwarded to Dockerode without sanitization. A new validateTcpDockerHost function 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 at INFO level so the connection target is auditable in the container logs. runSelfUpdateController was 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 (disableSocketRedirects remains socket-only).

  • OIDC error logs now redact RFC-1918 IP addresses and absolute filesystem paths (commit 9b79de77). The rc.22 getErrorChainMessage improvement walks error.cause chains 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. sanitizeOidcErrorMessage now 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.

Don't miss a new drydock release

NewReleases is sending notifications on new releases.