• v0.8.12 8f26cc2f93

    v0.8.12
    All checks were successful
    CI / Build / Publish / Shellcheck (push) Successful in 8s
    CI / Build / Publish / Validate CHANGELOG structure (push) Successful in 4s
    CI / Build / Publish / Bats unit tests (push) Successful in 7s
    CI / Build / Publish / PR build & smoke test (push) Has been skipped
    CI / Build / Publish / Round-trip + scheduler smoke (push) Successful in 3m24s
    CI / Build / Publish / Build multi-arch and push (push) Successful in 17m1s
    CI / Build / Publish / Reconcile releases across registries (push) Successful in 1m22s
    CI / Build / Publish / Workflow summary (push) Successful in 2s
    Stable

    Cody Bryant released this 2026-07-06 20:45:19 -07:00 | 55 commits to main since this release

    Changed

    • Replaced the in-container Debian cron daemon with supercronic for scheduled backups (CRON_SCHEDULE). supercronic runs jobs as the container user instead of forking with setgid, so the SETGID capability is no longer required and has been removed from the documented hardened cap set (compose.yaml, README.md) — the set is now DAC_OVERRIDE + CHOWN + FOWNER. It also passes the container environment straight through (Debian cron scrubs it). The entrypoint validates the schedule with supercronic -test (fail-fast on a malformed CRON_SCHEDULE) and runs supercronic backgrounded so the SIGTERM graceful-stop path is preserved. Added tzdata so a non-UTC TZ resolves. A new CI scheduler smoke test asserts a job fires under cap_drop: ALL with no SETGID. Action for hardened deployments: drop SETGID from your cap_add when you upgrade to this image.
    • Consolidated the per-storage-type credential and URL construction — previously duplicated across the primary-backup, add-copy, and restore code paths — into two shared helpers in config-loader.sh: build_storage_url and export_duplicacy_storage_secrets. No behavior change. Adds bats coverage of the DUPLICACY_<NAME>_* credential mapping across all four storage types (the surface the 0.8.10/0.8.11 do-spaces incidents traced to), so a single definition is now the source of truth for both backup and restore.

    Fixed

    • Restore silently lost original file ownership under the recommended hardened cap set: the example compose.yaml / README.md did cap_drop: ALL and added back only DAC_OVERRIDE + SETGID, but restore preserves ownership by default (-ignore-owner is opt-in) and Duplicacy recreates the original UID/GID via chown(), which requires CAP_CHOWN (and CAP_FOWNER to set mode/timestamps on other-UID files). DAC_OVERRIDE bypasses permission checks but not chown, so a restore completed with every file owned by root. Added CHOWN + FOWNER to the documented cap set. (Default Docker caps already include CHOWN; this only affected the hardened cap_drop: ALL template.)
    Downloads