github CodesWhat/drydock v1.7.0-rc.9

pre-release5 hours ago

v1.7.0-rc.9

Full Changelog: v1.6.1-rc.7...v1.7.0-rc.9

[1.7.0-rc.9] — 2026-09-03

Security

  • fflate override added in e2e/ for CVE-2026-45820. @smithy/middleware-compression pins fflate at 0.8.1 exactly, so the fix had to come through an npm override; fflate now resolves to 0.8.3 in e2e/package-lock.json, which is the only workspace that carried the vulnerable range. Lockfile-only change, no runtime code touched.

Fixed

  • watchFromCron() had no re-entrancy guard, so overlapping scans on a large fleet fired the same trigger multiple times for one update. A full scan can take minutes, and the cron schedule, the docker-events debounce, the discovery-settle timer, and the startup timer could all start one while the previous scan was still running. Each overlapping call ran its own watch(), and a tag first seen mid-burst passed the once=true history check in every one of them before any of them recorded it, so a trigger like Telegram fired once per overlapping scan for the same update. watchFromCron() is now single-flight: a request while a scan is running does not start a second one, it records that a rescan was requested, and exactly one follow-up scan runs once the current scan finishes, so a docker event that arrives mid-scan is not lost. A scan that never settles cannot wedge later ticks either: the in-flight scan is raced against a deadline, and when it fires every caller waiting on that scan, the one that started it and any that coalesced into it, resolves to an empty result and the next tick starts a fresh scan. The "Cron started" log line now also names what triggered the scan (schedule, docker-event, discovery-settle, startup, or maintenance-window). Reported by @tarzan77cz in #972.
  • A once=true trigger re-fired hours later for a tag update it had already announced, whenever a registry rate-limited the accompanying digest lookup. The notification-history hash for a tag-kind update included the digest and, when the digest was absent, the image's created timestamp. A transient Digest watch failed (429) dropped the digest for that scan only, so created swapped into the hash on the failed scan and back out once the digest lookup next succeeded, and the once history stopped matching an update it had already sent. The hash for a tag-kind update on a container with digest watching configured is now keyed on the tag alone, so a digest lookup failing or succeeding does not change it; a container without digest watching configured keeps the original created fallback, and digest-kind updates stay keyed on the digest. Concurrent evaluations of the same history key are also now atomic within the process: the check and the reservation happen in the same synchronous step, so two overlapping scans evaluating the same result cannot both pass the check and both send, which is why one trigger could fire four times in the same millisecond while another skipped. After upgrading, a container with digest watching enabled, a tag update already pending, and once=true whose stored hash came from a scan where the digest lookup had succeeded re-notifies exactly once, because the stored hash format changed; every scan after that stays stable. Reported by @tarzan77cz in #972.
  • Two deprecation banner strings in the UI still described the legacy DD_TRIGGER_* env vars and the curl-based healthcheck override as active with a future removal. Both were removed outright in v1.7.0; legacyConfigBody and curlHealthcheckBody (all 17 locales) now say so instead of pointing at a deadline that already passed. The curl banner's {bin} slot also rendered the compose migration snippet with a single $, which compose expands from the host environment before the container starts; doubled it to $${DD_SERVER_PORT:-3000} to match the corrected DEPRECATIONS.md snippet.
  • The marketing site's Get Started snippets deployed an instance that never became healthy. Neither the docker run quick-start nor the hardened compose preset configured any authentication, so the instance ended up with zero registered auth strategies, which is a deliberate fail-closed state: /health stays 503 forever and there's no way to log in. Both presets also skipped a /store volume, so container state and audit history didn't survive a restart. The quick preset now sets DD_ANONYMOUS_AUTH_CONFIRM=true, the hardened preset sets DD_AUTH_BASIC_ADMIN_USER/HASH, and both mount drydock-store:/store.

Documentation

  • A docs audit turned up a batch of claims in the README, DEPRECATIONS.md, and the configuration/triggers/registries/API/monitoring/agents docs that no longer matched this tree's code. Compose examples that mangled a pasted argon2id hash and omitted the /store volume; translated READMEs with mistranslated provider names and a backwards roadmap pointer; a deprecation entry using the wrong removal-status label plus four missing DEPRECATIONS.md entries; hook, threshold, and rollback documentation describing behavior the code doesn't have (a major threshold letting digest-only updates through unfiltered, an allowlist that's exact-match rather than basename, a third rollback path that doesn't exist); trigger docs missing template variables and shared config keys; registry docs describing a routing mechanism and a rate-limit scope that don't exist and missing the public.ecr.aws rate row; API docs with a stale audit action list, wrong log-filter semantics, a nonexistent SSE event, and a rate limit bypass that isn't real; and feature docs conflating the docker trigger's health gate with dd.rollback.auto, describing a malformed signing key as a graceful skip when it crashes the controller, and framing a fail-closed /health 503 as a transient startup state. All of it corrected against this tree's actual code, not against v1.8's.

Don't miss a new drydock release

NewReleases is sending notifications on new releases.