Skip to content

v1.7.0-rc.2

Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 21 Aug 06:35
efcfe04

v1.7.0-rc.2

Full Changelog: v1.7.0-rc.1...v1.7.0-rc.2

[1.7.0-rc.2] — 2026-08-20

Added

  • Action-policy resolution is surfaced on the API and UI (spec-6.0.1-action-policy.md, slice 5). GET /api/v1/containers and SSE container payloads now include an actionPolicy object (state: blocked/manual/auto, plus triggerId and, when blocked, reason) on updateEligibility, reflecting the winning action trigger's resolved verdict for that container independent of whether it produced a blocker. GET /api/v1/containers/{id}/triggers gains a per-trigger resolvedState field with the same three values, so every candidate action trigger's individual verdict is visible, not just the winner. The container list/detail UI shows a new Auto badge (Update Status panel, full-page Actions tab, side panel trigger rows) wherever a container's or trigger's resolved state is auto, with tooltips explaining the blocked/manual/auto states. New dd.action.auto container label and onauto AUTO mode: under AUTO=onauto, dd.action.include keeps granting manual access but automatic dispatch additionally requires a dd.action.auto match, letting a container opt into manual-only access without picking up automatic execution. Drydock now logs a startup WARN for any action trigger left on AUTO=oninclude that has dd.action.include-matching containers with no corresponding dd.action.auto label (would silently drop to manual-only if switched to onauto), and a second WARN when a trigger is on AUTO=none but a container carries an inert dd.action.auto label for it. Docs: new dd.action.auto label and onauto value are documented on the labels reference, triggers configuration, and update-eligibility pages, including a callout on all three clarifying that AUTO=none/AUTO=all also set the baseline access default (not just automatic execution) — AUTO=none still opens manual access to every container, AUTO=all opens both.
  • Greptile second-opinion review, summoned behind a label. A new thin caller workflow, .github/workflows/greptile.yml, fires only on pull_request: labeled events for the second-opinion label and calls the org's reusable CodesWhat/.github greptile-summon.yml workflow (pinned to a frozen commit SHA, no floating ref) to post one @greptileai review request per exact PR head. CodeRabbit stays the automatic review lane; Greptile is opt-in only, for security-sensitive diffs, large refactors, or a tiebreaker when CodeRabbit and the author disagree. .coderabbit.yaml gains a labeling_instructions entry so CodeRabbit can auto-apply the second-opinion label itself when those criteria hit, in addition to a human applying it manually. (#751)
  • release-cut.yml can now cut a maintenance patch from a retired dev branch without touching the cosign signing identity. A new optional source_ref input (e.g. dev/v1.6) builds and releases from that branch's tip instead of main HEAD, for a patch on a line main has already moved past (v1.6.1 after main is on v1.7). The workflow itself still only ever dispatches from refs/heads/main, so the published cosign OIDC identity is unaffected. source_ref is bounded hard — it must be an exact dev/vX.Y branch that exists on origin, share release_tag's line, not be the active (highest) dev line, and pair with a nonzero patch version — and the main-sync drift guard is skipped rather than failed, since there's no drift claim to make against a line main has already superseded. Left empty, every normal cut is unchanged. See RELEASING.md's new "Maintenance cuts" section for the full precondition list, including the manual ci-verify.yml/e2e-playwright.yml dispatch required before cutting.

Changed

  • Documented the container SBOM attestation in the release-verification guide. release-cut.yml has generated and attested a signed SPDX 2.3 SBOM for every release container image since the v1.5 hardening batch, but content/docs/current/guides/verifying-releases never told readers how to check it. Added a "Verify the container SBOM attestation" section with the gh attestation verify --predicate-type https://spdx.dev/Document/v2.3 command the workflow itself uses, and a note on the human-readable drydock-${TAG}.image.spdx.json copy attached to each release. No workflow change — the SBOM and build-provenance attestations, and their in-workflow verification, already met the house SLSA Build L2 / SBOM-attestation standard; only the user-facing documentation was missing. (#759)
  • Dropped the trivy qlty plugin in favor of Grype. Grype already owns the vuln-scanning surface (.github/workflows/security-grype.yml); trivy's qlty-plugin config driver only ever ran its DS*/KSV* Dockerfile misconfiguration checks, which checkov already covers (the checkov:skip=CKV_DOCKER_3 comment on Dockerfile line 1, with matching rationale in .trivyignore.yaml for the standalone trivy binary the image ships at runtime — a separate concern, untouched here). Removed the [[plugin]] name = "trivy" block and the trivy:DS002/trivy:DS-0002 triage entry from .qlty/qlty.toml; trufflehog stays as-is. (#753)
  • Faster initial load on the login screen. The app's logo asset had drifted 4x oversized and was still being base64-inlined into the parse-blocking entry chunk (~640KB, reachable before authentication). It's now correctly sized and served as a separately cacheable file, cutting the entry chunk's gzipped size roughly in half and no longer re-downloading on every release. (#805)
  • BREAKING: the Home Assistant MQTT topic layout now includes an agent/<name> segment by default for agent-owned containers. Announced in v1.5.x and scheduled for v1.7.0. Multi-agent deployments previously collided on shared watcher names; the corrected layout scopes topics, sensor counts, and discovery cleanup per agent. Home Assistant references to the old topic paths must be re-pointed. Set DD_NOTIFICATION_MQTT_<name>_HASS_AGENTTOPICSEGMENT=false to keep the old layout temporarily. Drydock does not retroactively clean up the old, pre-upgrade discovery entities. They remain retained on the broker and show up in Home Assistant as orphaned, frozen-at-last-state duplicates until manually removed.

Fixed

  • Dependency-group admission no longer loses restart context when an upstream member is rejected. A restart-only dependent whose upstream was rejected during admission was previously misclassified as a normal update in wave 0 instead of being restarted after its dependency finished (or skipped if it never ran). The original admission batch is now carried through dispatch and API annotation so rejected members no longer corrupt the graph for their accepted dependents. (#718)
  • Docker Compose updates no longer carry forward stale image-inherited environment defaults. A compose refresh could leave an old image's default environment value in place after updating to a new image with a different default, even though explicit runtime overrides on the container were always respected correctly. (#736, closes #734)
  • Stashed update-policy overrides now survive drydock's own self-update. The updatePolicyRetentionCache that lets a recreated container inherit its predecessor's policy overrides lived only in process memory and was silently lost on the exact restart caused by a self-update. It now persists write-through to the store and rehydrates at startup, mirroring the same fix already applied to the maturity-clock cache. (#743, fixes #565)

Fixed

  • Drydock no longer reports "Up to date" when an update check failed. A registry error while verifying a candidate's digest discarded the newer tag that had already been found, and the UI presented the result as a confirmed "no update available." A check that could not complete now surfaces as an explicitly unknown status instead of a negative answer. This also covers transient registry failures reported separately. (#814, #808)
  • A single malformed container no longer zeroes out an entire agent inventory sync. AgentClient.processAuthoritativeContainers() — the loop driving both the standard-mode handshake (_doHandshake(), every initial load and reconnect) and edge-mode handleContainerSync() (every dd:container_sync frame) — had no per-container error isolation, unlike the sibling SSE watcher-snapshot path. One container that threw while building its report (for example, during controller-side SBOM document offload) aborted the whole batch before any container reached the store, so a single bad container could make an otherwise-healthy fleet's inventory sync silently report zero containers. Each container in the batch is now processed independently, matching the existing isolation pattern in handleWatcherSnapshotEvent(): a failure is logged with the container id and the batch continues with the rest. A batch where every container fails now also logs a single proportionate warning, since a silently empty result was what let this go unnoticed for a release cycle. Found while investigating #802; this closes the isolation gap but does not confirm the SBOM path as that issue's trigger — Portwing does not currently send security.sbom on its container wire format, so #802 remains open pending its actual root cause.
  • Nested OCI image indexes now resolve to the real image manifest. An image whose per-platform entry is itself an index, which is what Buildx produces when SBOM or provenance attestations are enabled, failed with Unexpected error; no manifest found and left the container unable to complete a digest check. Drydock now follows the nested index to the platform's actual manifest, bounded to three levels, and correctly ignores the attestation manifest alongside it. (#814)

Removed

  • Retired the self-hosted star-history provider and the Warpchart embed that replaced it, in favor of a committed SVG chart. The self-hosted /api/star-history route read process.env.GITHUB_TOKEN at request time, and since that variable was always unset in production, it served a placeholder "check back shortly" SVG at HTTP 200 instead of erroring. Nothing ever went red, so the chart silently never rendered for as long as the route existed. Deleted the route handler, its SVG-rendering and request-resolution libraries, and the homepage StarHistory card. Warpchart was adopted next as its replacement, then retired again days later once that decision reversed. Both now give way to docs/assets/star-history.svg, a chart built from GitHub's own stargazer timestamps and committed straight into the repo: it needs no runtime secret and cannot return a placeholder at HTTP 200, so a stale chart is visible and a missing one is a broken image, not a silent failure. Regeneration is handled by a scheduled shared workflow landing separately. All seven README language variants now point at the committed SVG instead of an external chart service.
  • BREAKING: trigger-excluded and trigger-not-included are now hard blockers, ending the v1.5.0–v1.6.x soft-severity grace period (spec-6.0.1-action-policy.md, slice 6 — see DEPRECATIONS.md). Previously, a container filtered out by dd.action.exclude/dd.action.include (or the legacy dd.trigger.* labels) showed a Trigger filtered/Trigger excluded pill but still let a manual Update click through after a confirm-modal warning. As of this release both reasons are hard: the Update button is locked, and the API rejects a manual update request with the blocker's 409 message instead of queuing it — matching every other hard eligibility gate. This ships together with, and not before, the per-action execution policy (dd.action.auto label, AUTO=onauto trigger mode) landed across slices 1-5, so the manual-only escape hatch isn't removed without a replacement path: an operator who wants a container to stay manually updatable while excluded from automatic dispatch now expresses that with AUTO=onauto plus dd.action.include (or dd.action.auto), rather than relying on the soft bypass. AUTO=oninclude's existing meaning is unchanged — a matching dd.action.include label still grants both manual and automatic access under that mode.
  • Removed the unversioned GET /api/auth/methods alias. Deprecated since v1.6.0 and scheduled for removal in v1.7.0, it now returns 410 like the rest of the unversioned /api/* surface. Use GET /api/v1/auth/status instead.

Removed

  • Removed curl from the Docker image. Deprecated since v1.5.x with removal scheduled for v1.7.0. The image's own healthcheck has used the compiled /bin/healthcheck binary since v1.5.0; user-defined HEALTHCHECK overrides that shell out to curl will stop working and should switch to test: /bin/healthcheck $${DD_SERVER_PORT:-3000} (the doubled $ is compose escaping) or drop the override. Drydock now also logs a startup warning naming the container when it detects that its own healthcheck override still shells out to curl (in addition to the existing UI banner).

Security

  • Scoped the Grype image gate around CVE-2026-14456 (openssl/libssl3/libcrypto3, Alpine 3.24) pending an upstream fix. ci-verify.yml's grype-image job started failing --fail-on high after this CVE (CWE-770, unbounded memory growth in OpenSSL's QUIC server incoming-channel-queue handling) entered the Grype DB; the packages are pinned at 3.5.7-r0 and no Alpine branch — 3.24-stable or edge — has repackaged the upstream 3.5.8 fix yet. Drydock links these libs only as a TLS client (the openssl CLI and Node's own TLS stack) for registry queries and the healthcheck, never as a QUIC/HTTP3 server, so the vulnerable path isn't reachable; OpenSSL's own advisory rates the flaw Low, versus the generic CVSS 7.5 the gate scores. Added a CVE-scoped (not location-scoped) .grype.yaml ignore entry for exactly this CVE on these three package names, so a different HIGH/CRITICAL finding in openssl still fails the gate. Two removal triggers: bump the Dockerfile's pinned openssl= version once Alpine ships >= 3.5.8 for 3.24, or 2026-11-17 (90 days out) regardless.
  • Closed a remote-property-injection path in the container list's URL query sync. ContainersView's query-normalization helper wrote URL-controlled keys onto a plain object with bracket notation, which could in principle let a crafted __proto__ query key reach the object's prototype chain. It now accumulates entries in a Map and materializes the result with Object.fromEntries, closing the vulnerability class rather than just suppressing the scanner finding. (#750)

Documentation

  • Retroactively documented the WUD_AGENT_SECRET/WUD_AGENT_SECRET_FILE removal. v1.6.0-rc.1 silently dropped agent mode's DD_AGENT_SECRET ?? WUD_AGENT_SECRET fallback (and the _FILE equivalent) with no deprecation period, and it was never recorded in the v1.6.0 changelog entry or DEPRECATIONS.md at the time. An agent configured with only the legacy WUD_AGENT_SECRET went from authenticating to a startup failure whose message doesn't name the variable actually set. See the new DEPRECATIONS.md entry.