github CodesWhat/drydock v1.8.0-rc.6

latest release: v1.7.1-rc.1
pre-release4 hours ago

v1.8.0-rc.6

Full Changelog: v1.8.0-rc.5...v1.8.0-rc.6

[1.8.0-rc.6] - 2026-10-23

Warning

Release candidate for opt-in testing. SQLite changes the on-disk store. Stop Drydock and back up the complete store directory before upgrading from v1.7 or earlier. First startup imports existing JSON data into SQLite. Downgrading requires restoring the intended pre-upgrade JSON snapshot and any separate session file; changes made only in SQLite are not carried back. A fresh v1.8 installation has no pre-upgrade JSON snapshot. Start with a copy of your store and test containers.

This candidate includes the v1.8.0-rc.1 features, the v1.8.0-rc.2 fixes, and the v1.8.0-rc.3, v1.8.0-rc.4 and v1.8.0-rc.5 changes, and retains their upgrade warnings. The image no longer bundles Trivy or cosign, and Grype is now the default scanner. DD_SECURITY_BACKEND=auto runs Trivy and cosign in pinned worker containers, so if you set DD_SECURITY_SCANNER=trivy you will see a deprecation warning, and Drydock needs permission to create and attach containers on its Docker socket. Without that permission, use DD_SECURITY_BACKEND=remote with a Trivy server or mount a Trivy binary through DD_SECURITY_TRIVY_COMMAND. The Update Available notification rule now explains when it skips automatic actions (#1281). v1.8 GA is not released; v1.7.0 (GA 2026-10-19) is the latest stable release. RC6 has its own publication-based soak.

Security

  • Bump nodemailer to 10.0.10 (GHSA-39m8-27wv-hr27, used by the SMTP notification trigger) and the ip-address override to 10.7.4 (GHSA-rxp7-6hxx-x8q5), and the website's dompurify to 3.4.17 (GHSA-c6gr-qvv4-5v3f, GHSA-mrv2-3pqr-j5jr).
  • Bump the website and docs app to next 16.4.2 for GHSA-p3m5-59mp-jv5r and GHSA-2464-fhr4-w9xw (website only, not in the Drydock image).
  • OIDC bearer tokens are now opt-in and must be issued for Drydock's client. An Authorization: Bearer access token is only accepted when DD_AUTH_OIDC_{name}_BEARER=true, and then only if its aud contains the client ID (or a DD_AUTH_OIDC_{name}_BEARERAUDIENCES entry) or its azp/client_id equals it, or, for opaque tokens, RFC 7662 introspection returns an active token for this client. Setups that send OIDC access tokens to the API must set the variable. The browser login flow is unchanged (DR-10). See DEPRECATIONS.md.
  • Remove the vendored Trivy binary and the cosign package from the Docker image. Their Go module graphs produced findings Drydock could not patch independently, so .grype.yaml ignored both binary locations and the image scan never covered them. The file now carries no ignore rules, and every package in the image is gated.

Fixed

  • Trivy versions can no longer drift apart. The default Trivy worker had stayed on 0.72.0 while the image bundled 0.73.0; the image no longer bundles Trivy, so the worker default is the only Trivy pin, a test fails if another appears, and the release SBOM uses Syft.
  • The Update Available notification rule also gates automatic actions, and Drydock now says so. With that rule turned off, a batch action trigger (such as dockercompose) skipped every pending update with no log line and no reason in the UI, so updates sat there and never installed. The batch path now logs the rule being off, a group policy holding a container back, a threshold miss and a trigger-condition exclusion, in the same wording as the simple path. The container's update status also gets a soft "Update Available rule is off" reason that points at Settings > Notifications > Update Available; manual updates are unaffected.
  • The Security view now shows the scanner version, image digest, and vulnerability database or cache update time in each scanner's tooltip, using the asset details the API already returned.
  • Show the maturity countdown wherever a held update is listed. A candidate held by maturityMode: mature now shows the time left and its local unlock date and time in the container list and card tooltips, in a compact label next to the clock icon, and on the Updates Available dashboard widget, ticking once a minute from one shared clock. Previously only the container detail panels had it.
  • Show when a notification was last skipped. The container detail notification section already named the reason, and now also shows the local date and time of the last skip for each trigger.
  • Key the config sources map by the setting name for a secret-file entry. A _file (DD_X__FILE) entry was listed under DD_X__FILE at boot and under DD_X after a reload, while the docs showed DD_X; both now use DD_X. POST /api/v1/config/validate no longer reports an unchanged _file entry as changed, and the editors label a field set by an environment variable as environment-owned even when the file also has a _file entry for it. (CFG-1)
  • With watchall on, a slow replacement no longer leaves the renamed old container as a duplicate row that could take the replacement's retained update policy. The old container is skipped while its replacement stands, so the policy stays on the replacement (DR-147).
  • Send the update-pending-approval notification. The rule existed and could be enabled, but nothing dispatched to it, so enabling it did nothing. It now fires once when an update candidate enters the approval queue (not under update mode notify or with container actions disabled, where approving is refused), follows the rule's enabled flag, trigger selection, templates and batch modes like the other rules, and links to the queue row when DD_PUBLIC_URL is set. It is deduplicated on the queue row, so a re-seen pending candidate or a restart doesn't notify again. The rule still ships disabled.
  • Stop the Closing Keywords Guard from failing every dev to main sync PR. A sync head has main as its first parent, so the guard now checks only the sync commit's own message instead of the whole dev history since the branch cut (DR-100b).
  • Check very large GHCR repositories quickly. After a listing hits the 50-page limit once, Drydock lists only the tags pushed after the container's current tag for the next 24 hours instead of re-reading the first 50 pages on every check (REG-PERF-1, follow-up to #1453).
  • Keep a candidate that is below an auto action's threshold in the approval queue. With update mode auto and an action trigger set to AUTO=all with a minor threshold, a major update was marked auto-applied and dropped from the queue, yet the trigger never ran it. It now waits for approval, and the container's action policy reads manual instead of auto.
  • Set the document direction for right-to-left locales. Arabic now sets dir="rtl" on the page at boot and when you switch language (and back to ltr for the rest), and the app shell, tab bar, notification bell, detail panel and table headers use logical start/end spacing so the layout mirrors instead of staying left-anchored.
  • Keep anonymous volumes when recreating a container. Containers whose image declares a VOLUME with no named volume or bind mount, such as a default postgres or mysql setup, came back from an update with a fresh empty volume while the old one, with the data on it, was left orphaned. The docker and dockercompose actions now reattach the existing volume at the same path, as docker compose up does.
  • The Docker Compose action no longer overwrites an image set through a variable (image: ${IMAGE}, image: repo/app:${TAG}, ${REG}/app:${TAG:-1.0}) with a literal tag. It used to flatten the reference, which silently broke .env-driven setups, and it never updated .env. The update is now refused before any file write or container change, in previews and dry runs too, with an error that names the variable to update. An escaped $$ is still rewritten. Writing the new value back to .env is planned for v1.9.
  • Protect the SQLite store across upgrades and downgrades. Before applying a pending schema migration to an existing dd.sqlite, Drydock now writes a consistent dd.sqlite.pre-migration-v<version>-<timestamp> snapshot next to it (newest three kept) and stops startup with a clear error if it can't, rather than migrating without a restore point. A database migrated by a newer build is now refused by an older one with an error naming both schema versions and how to restore, instead of being opened. See Storage.
  • Docker Hub, Quay, Harbor and Azure Container Registry couldn't call the registry webhook at all. POST /api/v1/webhooks/registry only accepted an HMAC signature, and none of those four registries can produce Drydock's HMAC (Docker Hub and Quay can't sign or set headers, Harbor and ACR can only send a fixed auth header), so five of the six parsers were unreachable without a signing relay. A provider can now accept a static secret instead: in the URL path (/api/v1/webhooks/registry/<provider>/<secret>), in ?secret=, or as a static Authorization: Bearer <secret> header on /api/v1/webhooks/registry/<provider>. Set the secret with DD_SERVER_WEBHOOK_STATICSECRET (or DD_SERVER_WEBHOOK_REGISTRIES_<PROVIDER>_SECRET, both with __FILE support, 16 characters minimum) and choose the modes per provider with DD_SERVER_WEBHOOK_REGISTRIES_<PROVIDER>_MODES (hmac, path, query, bearer; default hmac, so nothing changes until you opt in). Secrets are compared in constant time and never logged (the path segment is masked and the query string dropped), failed attempts get a tighter rate limit than successful ones, and the bare /api/v1/webhooks/registry endpoint stays HMAC-only. URL secrets end up in registry-side logs, so use a dedicated, rotatable value. The webhooks docs now show the exact setup for each registry.
  • The update-status panel now shows the Manual and Blocked action policy badges, not only Auto, and the full-page associated-triggers rows carry the per-trigger policy tooltip and Auto badge like the other trigger lists.
  • Translate the remaining hard-coded UI strings and gate against new ones. Seven English literals are now localized in all 17 locales: the yes/no values in the container preview and compose-write rows, the "Page" and "unknown image" search subtitles, the preview-request fallback error, and a missing containerComponents.groupedViews.updateFailed key that rendered its raw key path when an update failed over SSE. New i18n specs fail CI when a key used in ui/src is absent from the English locale files (including dynamic t(\prefix.${x}`)` keys) and when a user-facing literal reaches a template expression, toast, dialog or label property outside a documented allowlist.
  • Translate the remaining hard-coded UI strings and gate against new ones. The "Page" search subtitle is now localized in all 17 locales, along with a missing containerComponents.groupedViews.updateFailed key that rendered its raw key path when an update failed over SSE. New i18n specs fail CI when a key used in ui/src is absent from the English locale files (including dynamic t(\prefix.${x}`)` keys) and when a user-facing literal reaches a template expression, toast, dialog or label property outside a documented allowlist.

Added

  • Decide several queued updates at once. The approval queue gets row checkboxes, a select-all box and a selection bar with Approve selected and Reject selected, backed by the new POST /api/v1/approvals/bulk (up to 200 ids, with approve, reject or defer as the action). Each id is decided exactly as its single-row route would decide it, so a row that would be refused on its own is reported in the rejected list with the same status and message and the rest still go through, and every decided row writes its own audit entry. Bulk approve requires the X-DD-Confirm-Action: approvals-bulk-approve header and a confirmation dialog in the UI that lists the hold reasons it overrides and skips hard-blocked rows, and uses the same containers:update scope as the single decisions.
  • Show recent notification skips per trigger. Open a notification trigger in the Triggers view, or a rule's assigned triggers in the Notifications view, and Recent skips lists the containers it skipped, newest first, with a readable reason and a link to each container. The same data is served by GET /api/v1/triggers/{type}/{name}/skips (and /{agent}/skips for agent triggers) under the read scope, paginated with limit (default 50, maximum 200) and offset, and documented in the OpenAPI spec. It reads the existing in-memory skip record, so there is no new storage.
  • Prometheus lockout counters drydock_auth_account_lockout_total and drydock_auth_ip_lockout_total, labelled by provider, increment once each time a login lockout starts. The existing drydock_auth_account_locked_total and drydock_auth_ip_locked_total gauges only show lockouts active at scrape time. The monitoring docs list the new counters and add an alert example and dashboard panel.
  • Category-specific trigger API routes that match the DD_ACTION_* / DD_NOTIFICATION_* split: /api/v1/actions (docker, dockercompose, portainer, command) and /api/v1/notification-triggers (every other provider). They list, get and run triggers with the same auth and response shapes as /api/v1/triggers, and a trigger of the other category returns 404. /api/v1/notifications stays the notification rules collection. The UI trigger service now uses the new routes, and the OpenAPI spec and API docs cover them.
  • Optional dashboard cards and a Recent Activity widget. The dashboard Customize panel now lists Images, Triggers and Watchers stat cards and a Recent Activity widget, all hidden by default so saved layouts look exactly as before. Images counts distinct images and how many have updates, Triggers splits configured actions from notifications, and Watchers shows the count with a red state when an agent-backed watcher is disconnected. Each card links to its view. Recent Activity shows the latest 10 audit entries (time, actor, action, target), links each row to the Audit view filtered to that container, fetches only while shown, and refreshes on container and update events plus a 60 second interval. Preferences schema moves to version 13 to hide the new widgets once for existing layouts.
  • The UI now shows a banner when the browser is offline or the Drydock server is unreachable, and clears it and refreshes the open views when the connection returns. While it's up, the dashboard and container views render the last known data with a "last updated" time, and update, start/stop, policy, rollback and delete actions are disabled with a tooltip. A 502, 503 or 504 from a reverse proxy counts as unreachable once a confirming request agrees, so one transient 503 doesn't flash the banner. The saved copy covers only a short list of safe read endpoints, is used only after the server can't be reached, expires after 24 hours, and is wiped on sign-out, sign-in and any 401. Also adds the missing apple-mobile-web-app-status-bar-style meta tag for the installed iOS app.

Deprecated

  • /api/v1/triggers is deprecated in favor of /api/v1/actions and /api/v1/notification-triggers. It keeps working and now sends Deprecation: true and a Link: <successor>; rel="successor-version" header, and logs a one-time warning per process. Removal is planned no earlier than v1.9.0 (see DEPRECATIONS.md).

Changed

  • Delete the container's updateOperation field and the SSE bridge that kept it in sync with the operations store (DR-89, slice 5). Every view already reads update progress from the store, and a new architecture test fails on any new use of the field. Behavior is unchanged.
  • Add an architecture test that fails on toast calls outside the update lifecycle layer (DR-90). Existing feedback toasts are allowlisted per file with a count that can only go down, update outcome toasts can only come from the operations store, and a toast binding can't be handed to a helper. Also drops an unused useToast() binding from ContainersView.
  • Containers that share a replaced container's network namespace or volumes now follow it. When Drydock updated a container that others attach to with network_mode: container:<id> or service:<name> (the Gluetun pattern) or volumes_from, those containers kept pointing at the removed container and lost their network, and restarting them failed with "joining network namespace of container: No such container". Drydock now recreates them against the new container, keeping the rest of their configuration.
  • Update images for services defined in included compose files. Compose records only the files named on the command line in the config_files label, never the ones pulled in with include:, so Drydock could not find a service defined in an included file and skipped the compose file rewrite. Drydock now follows include: entries (nested ones too) from the listed files, stays inside the allowed compose roots, and rewrites the file that defines the service. Services that inherit their image through extends are still left alone.
  • Scanners now run outside the image. DD_SECURITY_BACKEND has a new default, auto: for each provider Drydock runs a local command when DD_SECURITY_<PROVIDER>_COMMAND is set or the binary is on PATH, and a hardened, digest-pinned Docker worker otherwise. command, docker and remote mean what they did before, and remote stays Trivy-only. The release SBOM is now generated with Syft instead of Trivy, in the same SPDX 2.3 format.
  • Grype leads the docs, quick start and compose examples as the recommended scanner. An empty DD_SECURITY_SCANNER still means scanning is disabled.
  • DD_SECURITY_SCANNER=trivy or both with no Trivy binary on the machine keeps working through the pinned Trivy worker. Drydock logs one warning per process, counts it in the deprecation banner, and fails the scan with an error naming the three working setups (DD_SECURITY_SCANNER=grype, DD_SECURITY_BACKEND=remote with DD_SECURITY_TRIVY_SERVER, or a mounted binary set through DD_SECURITY_TRIVY_COMMAND) if Docker refuses to create or attach the worker. See DEPRECATIONS.md.
  • cosign signature verification is now a worker provider with the same hardening as the scanner workers: a pinned image, a read-only root filesystem, all capabilities dropped, no Docker socket, and an environment allowlist. It receives the target image's registry credentials the way Grype does, a DD_SECURITY_COSIGN_KEY file is passed to it by value, and DD_SECURITY_COSIGN_COMMAND is still honored. The new DD_SECURITY_COSIGN_WORKER_IMAGE overrides the image, and the Security view and POST /api/v1/server/security/assets/cosign/{pull,warm} manage it.
  • The scanner worker pins move to Grype 0.121.0, Syft 1.55.0, Trivy 0.76.1 and cosign 3.1.4, referenced from ghcr.io by tag and index digest. Renovate now tracks those constants.

Don't miss a new drydock release

NewReleases is sending notifications on new releases.