Skip to content

v1.4.0#140

Merged
s-b-e-n-s-o-n merged 59 commits intomainfrom
release/v1.4.0-rc.12
Mar 12, 2026
Merged

v1.4.0#140
s-b-e-n-s-o-n merged 59 commits intomainfrom
release/v1.4.0-rc.12

Conversation

@s-b-e-n-s-o-n
Copy link
Contributor

Summary

v1.4.0 stable release — 102 commits since the last merge to main.

This is the culmination of 12 release candidates with extensive community QA testing. Major highlights:

  • Complete UI rewrite — Vue 3 + Tailwind CSS 4 with 6 themes, 7 icon libraries, 6 fonts, command palette, shared data components, and borderless redesign
  • Compose-native container updates — Docker Engine API integration replacing CLI shell-outs, with rename-first rollback and health gates
  • Dual-slot security scanning — Scan both current and update images with delta comparison
  • Notification rule management — Persistent rules with event types, trigger assignments, and UI management
  • Tag-family aware semver — Prevents cross-family downgrades (e.g., 5.1.420.04.1)
  • MQTT HASS improvements — entity_picture from icons, attribute filtering (include/exclude/preset), dd.display.picture label
  • mTLS support — Client certificate authentication for registries and MQTT brokers
  • PHC argon2id hashes — Standard $argon2id$v=19$... format accepted alongside Drydock format
  • Legacy hash upgrade path — SHA-1, APR1, DES crypt hashes accepted during v1.3→v1.4 upgrade
  • Config tab deep-linking — Shareable URLs for specific config tabs
  • Container-update audit — External lifecycle changes recorded in audit log
  • Demo site — Interactive MSW-powered demo at demo.drydock.codeswhat.com

Bug fixes from community reports

Breaking Changes

  • HASS_ATTRIBUTES default changed from full to short
  • API base path migrated to /api/v1/* (old /api/* aliased, removal in v2.0)
  • Agent-scoped routes reordered to /:type/:name/:agent
  • Default log format is now JSON

Full changelog: https://github.com/CodesWhat/drydock/blob/release/v1.4.0-rc.12/CHANGELOG.md

Test plan

  • All 2116 backend tests passing (100% coverage)
  • All 843 UI tests passing (100% coverage)
  • E2E Cucumber tests passing
  • Biome lint + qlty check clean
  • Lefthook pre-push pipeline green (6 stages)
  • QA E2E walkthrough — 11 scenarios verified via Playwright MCP:
    • Compose directory resolution
    • docker.io prefix preservation
    • Lowercase env var keys
    • Legacy hash login (SHA-1, APR1, DES crypt, plaintext)
    • TLS healthcheck
    • Log level propagation
    • Feature flags after login
    • Container-update audit events
    • MQTT HASS_ATTRIBUTES short preset
    • Trigger warn logging
    • Icon cache headers

@vercel
Copy link

vercel bot commented Mar 12, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
drydock-demo Ready Ready Preview, Comment Mar 12, 2026 5:27pm
drydock-website Ready Ready Preview, Comment Mar 12, 2026 5:27pm

@codecov
Copy link

codecov bot commented Mar 12, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

s-b-e-n-s-o-n and others added 25 commits March 12, 2026 13:17
Add CLIENTCERT and CLIENTKEY configuration options for self-hosted
registries that require mutual TLS authentication. Both options must
be provided together (enforced by Joi .and() constraint).

Supported registries: artifactory, custom, forgejo, gitea, harbor, nexus.

Based on #135 by @Waler with fixes:
- Fixed config key check (certfile → clientcert)
- Fixed typo (mutal → mutual)
- Added Custom registry schema support (was missing)
- Added full test coverage for mTLS agent and schema validation

Co-Authored-By: Waler <Waler89@googlemail.com>
Keep dashboard light/dark screenshots as a preview, remove the other
5 screenshot sections (containers, detail, security, login, mobile)
and replace with a prominent link to demo.drydock.codeswhat.com.
Large SBOM documents, scan vulnerabilities, container details, and
labels cause massive delays in Home Assistant when published via MQTT.
Change the default from full to short so new installations get a
performant experience out of the box. Users who need the full payload
can set DD_TRIGGER_MQTT_{name}_HASS_ATTRIBUTES=full explicitly.
The useServerFeatures composable fired a bootstrap fetch at app startup
before the user was authenticated. When the API returned 401, the catch
block set loaded=true which prevented any subsequent retry. After login,
container actions, delete, and other feature-gated UI elements were
permanently disabled for the session.

Move loaded=true into the success path so failed fetches leave loaded
as false, allowing autoLoad consumers to retry after authentication
completes.
… changes

Container start/stop/restart events from external tools (Portainer, CLI)
now generate container-update audit entries. Previously the Docker event
listener updated the container store but silently skipped audit logging,
so the audit trail only showed Drydock-initiated actions.

Subscribe to the existing containerUpdated event in the audit
subscriptions and emit a container-update entry with the new status.
The httpsAgent was only created when certfile was present (mTLS), which
meant providing only cafile to trust a private CA had no effect. Node.js
would use the default CA bundle and reject the self-signed certificate
chain. Now the httpsAgent is created when either cafile or certfile is
provided, matching the pattern used by BaseRegistry.

Also updates HTTPS auto-detection to consider cafile presence.

Fixes: #197
DD_LOG_LEVEL was correctly parsed but debug/trace messages were silently
dropped because pino multistream stream objects lacked an explicit level
property, defaulting each to 'info'. Now each stream inherits the
configured log level so all messages at or above that level are emitted.

Closes #134
Add origin check to the demo app's mockServiceWorker.js to prevent
cross-origin message injection. Add regression test to verify the
guard persists across MSW regenerations.
Traefik stack matches the Pangolin/Traefik setup used by community
testers. Nginx stack provides a baseline comparison. Both terminate
TLS with self-signed certs and forward standard proxy headers.

Includes compose trigger, container actions, and audit log testing.
Compose trigger has many silent failure paths logged at debug level,
making it nearly impossible to diagnose why a trigger reports success
but containers don't update. Promote key diagnostic messages:
- compose file mismatch skip → warn
- compose label inspect failure → warn
- no containers matched → new warn message
- "already up to date" → includes container names
Fallback icons were served with immutable cache headers, causing
browsers to cache the Docker placeholder permanently even after the
real icon becomes available from the provider.
…dates

When DD_TRIGGER_DOCKERCOMPOSE_*_FILE points to a directory instead of a
file, the compose trigger now probes for compose.yaml, compose.yml,
docker-compose.yaml, and docker-compose.yml inside that directory.

Also adds a no-op guard: trigger() now throws when updateAvailable=true
but no compose file mutations were applied, surfacing silent failures
instead of reporting false success.
Healthcheck now detects DD_SERVER_TLS_ENABLED and switches to
https://localhost with --insecure for the self-signed cert. Also fixes
trailing newline at end of Dockerfile.
Adds runtime verification for APR1/MD5 ($apr1$/$1$), DES crypt, and
plain-text htpasswd hashes alongside existing SHA-1 and argon2id
support. Schema validation relaxed to only reject malformed argon2id
prefixes — all other formats pass through to runtime verification.

SHA parseShaHash now decodes base64 and validates 20-byte digest length,
with buffer-to-buffer timingSafeEqual comparison matching argon2id path.

New deps: apache-md5 (MIT, 0 transitive), unix-crypt-td-js (BSD-3, 0
transitive) — both CJS-only, loaded via createRequire.

UI banner updated from SHA-specific to generic legacy hash wording.
…config

Env vars like DD_TRIGGER_DOCKERCOMPOSE_*_COMPOSEFILEONCE are lowercased
by the config parser but the Joi schema expected camelCase keys
(composeFileOnce, composeFileLabel, reconciliationMode, digestPinning).
Add Joi .rename() mappings from lowercase to camelCase for all four keys.
…se mutations

When a compose file uses an explicit docker.io/ prefix (e.g.
docker.io/collabora/code:25.04.9.1.1), the updated image reference now
preserves that prefix instead of stripping it to a bare library path.
Does not apply when the target already has a different registry host.
First-time demo visitors now see a theme matching their OS preference
instead of always defaulting to dark mode. Existing preferences are
preserved — the localStorage seed only applies when no dd-preferences
key exists yet.
The "Theme Editor" button in both inline and fullscreen demo modes now
navigates to /config?tab=appearance instead of /config, landing directly
on the Appearance tab rather than the default General tab.
Add entries to both CHANGELOG.md and the published docs changelog for
all rc.12 fixes: compose case-sensitivity, docker.io prefix, directory
resolution, TLS healthcheck, agent CAFILE, mTLS support, and SW origin
validation.
…heck, and compose trigger

- Basic auth: list all accepted legacy hash formats (SHA-1, APR1, MD5-crypt, DES crypt, plain)
- Server: document automatic HTTPS healthcheck when TLS is enabled
- Compose trigger: document directory resolution for FILE and case-insensitive env var keys
QA compose file with labeled services covering all 14 rc.12 fixes:
compose directory resolution, docker.io prefix, case-sensitivity,
legacy auth hashes, TLS healthcheck, log level, feature flags,
audit entries, MQTT attributes, trigger logging, and icon caching.
…t fallback

- Add blocklist for bcrypt ($2b$) and PHC argon2 patterns that would
  previously silently fall through to plaintext comparison
- Pin apache-md5 and unix-crypt-td-js to exact versions (removal in v1.6.0)
- Schema validation now rejects unsupported hash formats at startup
- Add comprehensive tests for bcrypt rejection, metadata classification,
  flaky hash parsing, and error paths in all legacy verifiers
- Remove pre-access guard from isCachedIconUsable; fs.stat alone suffices
- Update all icon test mocks to use stat rejection instead of access mock
- Add test verifying no access syscall during cache usability check
- Add tests for vanished entries and protected-only eviction scenarios
- DataCardGrid/DataListAccordion: assert no border on unselected items
- DetailPanel: find full-page button by icon-only pattern (no text)
- EmptyState/SecurityEmptyState: remove border assertions
- ConfigView: add useRouter mock with reactive replace for tab switching
- DashboardView: biome auto-format
- Add timeout to every pre-push command to prevent hangs
- Close stdin on qlty (</dev/null) to prevent interactive prompt hangs
- Clean-tree gate now warns about dirty files instead of blocking
  (parallel agents may have work in progress)
- Timeouts: clean-tree 10s, ts-nocheck 15s, biome 30s, qlty 60s,
  build+test 180s, e2e 120s, zizmor 30s
Parse $argon2id$v=19$m=...,t=...,p=...$salt$hash alongside the existing
Drydock format. Handles parameter order variations, padded/unpadded
base64url salt+hash, and rejects malformed argon2-looking hashes from
the plain fallback path.
CHANGELOG and basic auth docs now show the standard argon2 CLI command
as the primary hash-generation method, with Node.js as a secondary
option. Documents PHC-format support added in the previous commit.
…erflow

Allow setting a max-height on the scroll viewport when virtualScroll is
disabled, enabling bounded scroll areas for small row counts that don't
need virtualization.
…onent

Replace the split two-table pattern (fixed header + scrollable body) in
the "Updates Available" widget with the shared DataTable component using
the new maxHeight prop. Update tests to register the real DataTable and
query rows within the scoped widget element.
Recognize the users who helped test release candidates and report bugs:
RK62, flederohr, rj10rd, larueli, Waler, ElVit, nchieffo.
Cover base64 decoding boundaries, PHC parameter validation branches,
salt/hash minimum size checks, malformed argon2id prefix handling, and
flaky-hash dispatch paths for SHA and MD5 password verification.
Prevent port collisions when running parallel test suites and avoid
unnecessary HMR overhead in the test environment.
Replace verbose comment blocks with targeted mocks and assertions
for decodeBase64 empty-buffer branch, parsePhcArgon2Parameters
rejection paths, and SHA/MD5 verify dispatch edge cases.
- Clean-tree gate now hard-fails with file list and guidance instead
  of advisory warning — CI only sees committed state
- Qlty timeout increased from 60s to 2m based on measured baseline
  (23s warm cache, 72s cold cache)
The logo file was renamed from drydock.png to whale-logo.png but the
MQTT Home Assistant discovery payload still referenced the old filename,
resulting in a broken entity_picture attribute.
…lay.picture

Map icon prefixes to CDN picture URLs for Home Assistant discovery:
- sh:* → selfhst icons CDN (PNG)
- hl:* → homarr-labs dashboard-icons CDN (PNG)
- si:* → simple-icons CDN (SVG)
- http(s) URLs used directly as entity_picture
- dd.display.picture label overrides icon-derived picture
- Harden sanitizeIcon for non-string input and URL passthrough
Runs vitest --changed with --coverage.include scoped to staged .ts/.vue
files. Uses per-file thresholds (100% lines/functions/statements, 95%
branches) to catch coverage drops early without running the full suite.
Skips gracefully when no app/ui source files are staged.
- Move PHC argon2id entry from Unreleased to [1.4.0] Changed section
- Add 3 feat entries: HASS entity_picture, dd.display.picture, config tab deep-linking
- Add 6 fix entries: entity_picture URL, empty names, stale names, nested icons, colon prefixes, bouncer state
- Add 4 style entries: borderless UI, version alignment, expand button, sidebar indicator
- Add 1 security entry: unsupported hashes fail closed
- Add dd.display.picture label to watchers docs label table
- Add entity_picture callout to MQTT trigger docs
- Update MQTT example payload with current field names
Replace "MS Teams & Matrix triggers" with "Deprecation removals" since
Teams and Matrix triggers were delivered in v1.4.0, not v1.6.
…fication

Legacy SHA-1 hash verification intentionally uses sha1(password) to match
existing v1.3.x stored hashes during upgrade. This is not a new hashing
strategy — users are prompted to migrate to argon2id on login. Removal
planned for v1.6.0.
@s-b-e-n-s-o-n s-b-e-n-s-o-n merged commit d598c64 into main Mar 12, 2026
17 checks passed
@s-b-e-n-s-o-n s-b-e-n-s-o-n deleted the release/v1.4.0-rc.12 branch March 12, 2026 17:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants