Skip to content

Berthly 1.1.0

Choose a tag to compare

@henrywang henrywang released this 23 Jul 07:57
· 38 commits to main since this release

What's Changed

Berthly 1.1.0 is a feature release: automatic update detection for running
containers/images, drag-and-drop builds, and a round of security hardening,
on top of six days of bug fixes and infrastructure work since 1.0.1.

New features

  • Watchtower-style recreate with the latest image — Berthly now detects
    when a pulled image's registry has published a newer digest than your
    local copy (or than a running container's pinned digest), badges the
    affected Images/Compute rows, and can recreate a container from the
    updated image while preserving its configuration and volumes. The
    confirm sheet discloses that the container's writable layer is
    discarded. A new per-host "insecure registry" memory lets the background
    update checker and recreate's own pull reuse HTTP for registries you've
    already trusted elsewhere (Pull/Push/Run/Sign-in/Machine Create), with a
    Settings section to review or forget remembered hosts.
  • Drag-and-drop builds — drop a Dockerfile/Containerfile (including
    common prefix/suffix variants) from Finder onto the main window or
    sidebar to open the Build sheet pre-filled with the resolved context and
    path. Symlink-safe: the dropped item's visible name is validated, but
    only the resolved target is used for the actual paths.
  • Push from the image row context menu — "Push…" is now reachable via
    right-click, not just ImageDetailView's toolbar.

Security hardening (#17)

  • Verify Apple-signed installer packages for both installs and upgrades.
  • Restrict privileged DNS execution to a trusted root-owned Apple binary
    and a system-only PATH.
  • Bound build logs, clean up builder event loops, and serialize
    timed-out pushes.
  • Make CID and persisted app-state files owner-only and non-overwriting.
  • Warn users against placing secrets in persisted build arguments.

Fixes

  • Insecure-registry sign-in on a non-standard HTTP port now mirrors
    container registry login's own host/port handling — it previously
    failed because the raw host:port string skipped the scheme override.
  • Deleting a network row via its context menu crashed the app (AppKit
    "layout engine changed during its own layout pass," thrown while the row
    animated out of the sidebar List) — reproduced against a real daemon,
    not just mocks, and fixed.
  • Builder/Image/Volume rows could silently stay stale after a daemon-side
    state change because their custom Equatable conformances didn't cover
    every rendered field (a builder staying "Running" after Stop was the
    reported case; the fix audited and widened every model in
    Core/Models.swift, not just that one).
  • Starting a stopped container while its Terminal tab was selected could
    freeze the row at half height — the terminal's focus grab landed mid
    row-insert animation; focus is now deferred until the animation
    completes.
  • "Check for Updates" briefly looked like it was spinning inside the
    adjacent Refresh button — both were icon-only and visually fused into
    the same toolbar capsule; it now stays labeled while checking.
  • Removed redundant UI: the Registries scope strip (duplicated the
    Keychain info banner), the ⌘K palette's Refresh entry (duplicated ⌘R),
    and made toolbar Build/Pull contextual to Compute/Images instead of
    always visible.

Performance

  • Image metadata (arch/size/created/inspect data) is now cached by content
    digest instead of being fully re-decoded from the content store on every
    5-second poll tick — a digest is decoded at most once per poll even when
    multiple references (retags) share it, with stale entries evicted when
    their digest disappears.

Infrastructure

  • Adopted SwiftLint at zero findings, gated in CI (--strict, so any new
    warning fails the build).
  • Added a CodeQL advanced-setup workflow with a manual Swift build (the
    default autobuild can't handle Berthly's Xcode 26 / Metal toolchain /
    SPM requirements) plus a workflow-analysis job.
  • Added a ShellCheck CI job; fixed the real issues it caught in
    smoke.sh.
  • Branded, drag-to-install DMG layout replacing the bare Finder-default
    window.
  • Expanded test coverage substantially: context-menu, System page, image
    archive, large-inventory (correctness + performance), and several new
    E2E journeys (Tag→Save→Load round-trip, Copy Files, log streaming,
    restart/kill, credentialed push/pull, Watchtower recreate).

Testing

This release shipped only after its gate run passed on the release commit:

  • 497 unit tests passed — 90% line coverage of the pure
    logic layer
    (Berthly/Core models, mapping, and planning; 50%
    including the daemon/terminal I/O plumbing, which the end-to-end suite
    exercises against a real daemon instead).
  • 72 UI tests (deterministic mock-daemon XCUITest) and
    18 real-daemon end-to-end journeys guard the UI wiring and the
    daemon integration. SwiftUI view bodies are covered by these suites, not
    unit tests, by design.

Full Changelog: v1.0.1...v1.1.0