v1.6.0
Full Changelog: v1.6.0-rc.13...v1.6.0
[1.6.0] — 2026-08-11
Consolidates the 1.6.0-rc.1 … 1.6.0-rc.13 prereleases. Users upgrading from
1.5.2 get everything below; users already on 1.6.0-rc.13 receive no additional
runtime changes.
Added
- Portwing edge and agent integration matures into a first-class transport. Portwing 0.9.0+ agents work over either inbound Standard HTTP or dial-out Edge WebSocket transport, and drydock 1.6.0-rc.11+ recognizes Portwing's own Docker watcher marker to run native registry checks plus single/batch Docker updates controller-side (#632, #637, Portwing #76). Standard-mode agents can sign every request with Ed25519 (
DD_AGENT_{name}_AUTHMODE=ed25519, upgraded mid-series to signature version 2) instead of sending a shared secret. Edge agents stream live container logs and process deletes over the existing WS tunnel with correlated per-request IDs, pick their own display name (bound to their signing key so it can't be squatted), and are proactively disconnected when they stop answering pings. Theportwing/1.0edge endpoint is enabled by default (DD_EXPERIMENTAL_PORTWING=falseremains an emergency disable), backed by a real fleet-soak workflow that runs signed Portwing processes against production infrastructure on every PR and on a weekly schedule. - Declarative, three-tier update policy with a maturity stabilization gate (Discussion #307, Discussion #406, #320). Containers can declare
dd.updatePolicy.*labels (maturity mode/min-age, skip tags, skip digests) with watcher-level defaults and UI/API overrides, resolving through label → watcher default → persistent override precedence and surviving agent refresh, container recreation, and error-state rebuilds. A candidate held back bymaturityMode: matureis visible immediately with a live minute-by-minute countdown to its unlock time, and a newmaturity-clearednotification (backed by a 5-minute background sweep) announces the moment it clears instead of waiting for the next scan. Update Now remains available as an explicit soft-policy override. - Per-rule notification templates, bell preferences, and a new health-status event (Discussion #205, Discussion #198, Discussion #210). The Notifications view can override title/body/batch-title text per rule and provider with a live preview, and independently control which event categories reach the in-app bell — including a new
container-unhealthyrule (disabled by default) that fires off Docker health-check transitions. Bidirectional MQTT lets Home Assistant's Install button trigger a real drydock update through the normal eligibility/dispatch path, rate-limited per container and audited.dd.action.*/dd.notification.*labels are now strictly scoped to their own trigger category instead of one silently gating the other (#494). - Global update mode and an actionable Update Status panel (Discussion #325). Settings → General now selects one server-wide mode —
notify,manual, orauto— and the container side panel and detail view replace the old eligibility-badge stack with plain-language status plus a structured, deep-linking condition list covering all 16 eligibility reasons. Existing installs migrate toautoon upgrade so configured automatic updates keep working; fresh installs default tomanual(see Upgrade Notes). - Cross-device preference sync and a zero-dependency dashboard grid (Discussion #220, #281). An opt-in Sync across devices toggle stores the full UI preference set server-side per user and propagates changes to a user's other signed-in sessions in real time over SSE. The dashboard grid drops its
grid-layout-plusdependency for a deterministic CSS Grid implementation with edit-mode drag/reorder, bounded resizing, touch support, and per-breakpoint layout persistence. Audit, Security, Servers, and Watchers gain the same per-view column show/hide picker Containers and Agents already had. - More signal, less noise in update visibility. A pinned tag now surfaces the best newer same-family tag as a purely informational badge without making it an actionable update candidate (#498); a new Version Update filter isolates real semver bumps from digest-only churn on fleets that rebuild images daily (#538); and a startup warning flags minute-precise maintenance-window crons that only open their window for one minute per matching hour instead of the intended full range (Discussion #639).
- Opt-in wud-card/Homepage compatibility endpoints. With the unversioned
/api/*alias removed (see Removed, below),DD_COMPAT_WUDCARD=true(defaultfalse) mounts a narrow compatibility layer covering exactly the four endpoints the Home Assistant wud-card integration and Homepage'swhatsupdockerwidget call, reshaped into the bare-array response those integrations expect. (Discussion #469)
Changed
- Every major list view is responsive and consistent. Containers, Agents, Notifications, Security, Triggers, Watchers, Servers, Registries, Audit, and Auth now share one
DataTablewith a persisted per-view table⇄card toggle that auto-reflows to cards below ~640px; card views gained a sort control; and Source/Release-notes/Registry resource shortcuts render through one consistent 44px toolbar everywhere they appear (#498, Discussion #295). The Dashboard and Containers views no longer overflow horizontally on narrow phone screens. Update-status vocabulary was overhauled ("Digest update", "Security hold", neutral Major/Minor/Patch badges for informational-only updates), pinned reverted to being a tag property rather than an update status, and the maturity panel now shows exactly one countdown clock instead of two that could disagree with the gate (#556). Table polish across the series fixed pinned-column overlay clipping, a registry error overwriting the visible tag, sticky-column/auto-hide width miscalculation, and a clipped icon column. - Trigger taxonomy migration reaches its final warning stage. Every
DD_TRIGGER_*variable and the deprecateddd.trigger.include/dd.trigger.excludelabels still work in v1.6 but now log aterrorlevel ahead of removal in v1.7; useDD_ACTION_*/DD_NOTIFICATION_*and category-scoped labels, or runconfig migrate --source trigger. - Less duplicate work on the hot paths. Registry tag-list requests are shared across containers within a poll instead of being repeated per container; scheduled security scans and the shared log viewer avoid redundant store writes and re-renders; and transient registry network errors (timeouts, connection resets, DNS blips) now retry with backoff before a watch error is recorded.
- Base image bumped from Alpine 3.21 to 3.24, later rebased onto
node:24-alpineat Node 24.19.0 with a matching Trivy build-stage bump to 0.73.0, closing several HIGH/MEDIUM CVEs in the underlying image (#682).
Deprecated
GET /api/auth/methodsand the legacyGET /auth/strategiesresponse shape are deprecated in v1.6.0 (removal in v1.7.0 and v1.8.0 respectively). Both now log on every request and returnDeprecation/Sunsetheaders pointing callers at canonicalGET /api/v1/auth/status. See DEPRECATIONS.md.
Removed
- Unversioned
/api/*andWS /api/log/streamaliases are gone, returning410 Gone(or a rejected upgrade) instead of serving the request. This is a breaking change for integrations that hardcode the unversioned base path, notably the Home Assistant wud-card integration and Homepage'swhatsupdockerwidget — use theDD_COMPAT_WUDCARDshim above, or migrate to/api/v1/*directly. - Legacy v1.4-era authentication compatibility. Basic auth now accepts only argon2id hashes (
{SHA}, APR1/MD5, crypt, and plain-text hashes fail validation), and OIDC discovery now requireshttps://with no insecure HTTP workaround. - Legacy WUD configuration aliases, obsolete watcher switches, and legacy trigger-template variables.
WUD_*environment variables andwud.*labels are ignored (the migration CLI still recognizes them so existing files can be rewritten);DD_WATCHER_<name>_WATCHDIGEST/WATCHATSTARTare no longer configuration keys (usedd.watch.digest=true; startup watches always run); and$id/$name/$watcher/$kind/$semver/$local/$remote/$link/$countno longer populate in trigger templates. - Kafka
clientIdand token-only public-registry compatibility handling. Kafka validation accepts only lowercaseclientid, and malformed public-registry configurations (a barePUBLIC_TOKENwith noPUBLIC_LOGIN) now fail closed instead of silently falling back to anonymous pulls.
Fixed
- The maturity soak clock, update-policy overrides, and digest identity now survive the paths that used to reset them. Container recreation, agent report ingestion, watch errors, concurrent security scans, and manual rechecks each previously had at least one path that could silently restart a maturity countdown, drop a stored policy override, or roll back freshly detected update state — every one of those is closed, including the store's digest anchor now self-healing from a stale, multi-entry
RepoDigestsordering instead of trusting whichever entry happened to land first (#669). Notification dedup no longer fires a duplicate one-shot notification when a manual recheck returns drifted metadata for the same candidate, and containers with no available update are no longer ranked or filtered as though they had one. - Agent- and edge-specific reliability fixes. The container list no longer flashes a false "Agent Mismatch" during an agent's brief re-registration window; start/stop/restart/rollback return an explicit
501instead of an ambiguous404when an agent lacks lifecycle transport (#637); WebSocket log streams accept anonymous-auth sessions; and edgememoryGbnow reports binary GiB instead of decimal GB. - Operational fixes. The Star History chart is now self-hosted after the third-party chart services' outage (#671); the icon bundle no longer silently drops icons that became iconify aliases mid-series;
GET /api/v1/containers/backupsis reachable again (it was shadowed by the container router's own root handler); infrastructure-mode self-updates no longer fail to spawn their helper container on Docker Hub installs (#644); unchanged pending updates stop bloating the audit log on a timer; and the app and demo favicons match the v1.5.1 brand refresh (#439).
Security
- Anonymous access fails closed on upgrade, not just on fresh installs. An unconfigured or unconfirmed-anonymous instance now rejects protected API requests with
401instead of showing an open dashboard; setDD_ANONYMOUS_AUTH_CONFIRM=trueto keep an intentionally open instance working. - Transport and session hardening. HTTP notification triggers are hardened against SSRF (blocked cloud-metadata/link-local targets, contained redirects); WebSocket upgrades validate the complete origin instead of a host substring; the session cookie is renamed to
drydock.sid, signing every existing user out once;/storeand its contents are created owner-only (0700/0600); and icon CDN sources are pinned to exact upstream revisions instead of floating tags. - Ongoing dependency and base-image CVE sweeps ran throughout the series — notably Next.js 16.2.11 and React 19.2.8 on the documentation site,
fast-uri/ip-address/brace-expansionoverride advances, and the Node 24.19.0 + Trivy 0.73.0 bump in the final release candidate. See the individualrc.*entries below for full CVE detail.
Upgrade Notes
- Existing installs keep automatic updates; fresh installs start in manual mode. The new global
updateModesetting defaults tomanualonly when drydock creates a settings record for the first time; an existing record with noupdateModemigrates toauto, preserving pre-v1.6 behavior. Review Settings → General → Update mode after upgrading if you prefer notifier-only or manual-only operation. - A lone
dd.action.include/dd.action.exclude(ordd.notification.include/dd.notification.exclude) label stops filtering the other trigger category. If you relied on the pre-v1.6 cross-category leak (#494), previously-suppressed notification (or action) triggers may fire once on the first scan after upgrading. drydock logs a one-time warning per affected container naming the missing label; set the matching label to the same value to restore the previous filtering.
Documentation
- Podman/Docker socket security docs refreshed, and a full configuration/env-var and API/OpenAPI parity audit brought the docs and generated spec in line with the shipped
/api/v1surface, including the authentication component, registry webhook signature auth, notification outbox actions, bulk container updates, backup listing, and container summary/update-response details.
Note: the standard seven-day release-candidate soak was shortened for this release.
- Candidate age at promotion: 260253s (~3.0 days), short of the usual 7 days (604800s).
- Reason: Owner called GA early on 2026-08-12. rc.13 has soaked ~3 of the required 7 days; its fleet soak passed clean on 2026-08-09 and the candidate digest is byte-identical across GHCR, Docker Hub, and Quay. No open regressions against the v1.6.0 milestone.