From acaafbfc7652b2e61d4cb05fdf592f871705a6e8 Mon Sep 17 00:00:00 2001 From: modem7 Date: Sat, 27 Jun 2026 13:11:36 +0100 Subject: [PATCH 1/5] Warn when borgmatic is run directly instead of via borgmatic-start borgmatic-start traps SIGTERM/INT/HUP and forwards signals to the borgmatic process. Running borgmatic directly (e.g. docker exec) bypasses this, meaning a container stop during a backup won't be handled gracefully. Implementation: - Rename the pip-installed borgmatic binary to borgmatic.bin - Add a wrapper at borgmatic that checks for BORGMATIC_VIA_START env var and prints a warning if absent, then exec's borgmatic.bin - Set BORGMATIC_VIA_START=1 in borgmatic-start to suppress the warning Co-Authored-By: Claude Sonnet 4.6 --- CHANGELOG.md | 6 ++++++ Dockerfile | 1 + root/usr/local/bin/borgmatic | 9 +++++++++ root/usr/local/bin/borgmatic-start | 2 +- 4 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 root/usr/local/bin/borgmatic diff --git a/CHANGELOG.md b/CHANGELOG.md index e31a342..db94b74 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/). +## 2026-06-27 (continued 8) + +### Added + +- Warning when borgmatic is run directly via `docker exec` instead of through `borgmatic-start`. Running directly bypasses the SIGTERM/INT/HUP signal forwarding that `borgmatic-start` provides, which can leave a backup mid-run if the container is stopped. The warning is suppressed when called via `borgmatic-start`. + ## 2026-06-27 (continued 7) ### Changed diff --git a/Dockerfile b/Dockerfile index 6d85f28..2891799 100755 --- a/Dockerfile +++ b/Dockerfile @@ -78,6 +78,7 @@ RUN --mount=type=cache,id=pip,target=/root/.cache,sharing=locked \ python3 -m pip install -U pip python3 -m pip install -Ur requirements.txt apk add --no-cache -U borgmatic-bash-completion + mv /usr/local/bin/borgmatic /usr/local/bin/borgmatic.bin EOF COPY --chmod=744 --link root/ / diff --git a/root/usr/local/bin/borgmatic b/root/usr/local/bin/borgmatic new file mode 100644 index 0000000..7e5af25 --- /dev/null +++ b/root/usr/local/bin/borgmatic @@ -0,0 +1,9 @@ +#!/command/with-contenv bash +# Wrapper around the borgmatic binary. +# Warns when borgmatic is invoked directly rather than via borgmatic-start, +# which means SIGTERM/INT/HUP signals will not be forwarded gracefully. +if [ -z "${BORGMATIC_VIA_START}" ]; then + echo "WARNING: borgmatic is running directly, not via borgmatic-start." \ + "Signal handling (SIGTERM/INT/HUP) will not be forwarded to borgmatic." >&2 +fi +exec /usr/local/bin/borgmatic.bin "$@" diff --git a/root/usr/local/bin/borgmatic-start b/root/usr/local/bin/borgmatic-start index 3fff03b..91301f8 100644 --- a/root/usr/local/bin/borgmatic-start +++ b/root/usr/local/bin/borgmatic-start @@ -2,6 +2,6 @@ trap 'echo "[borgmatic] Caught signal, forwarding to borgmatic (PID $borgmatic_pid)..."; kill -TERM $borgmatic_pid 2>/dev/null' TERM INT HUP -borgmatic "$@" & +BORGMATIC_VIA_START=1 borgmatic "$@" & borgmatic_pid=$! wait $borgmatic_pid From e8a3f9dd2808f0864d2c73e4361afe3bcf48e060 Mon Sep 17 00:00:00 2001 From: modem7 Date: Sat, 27 Jun 2026 13:14:04 +0100 Subject: [PATCH 2/5] Add hadolint ignore for pip RUN step (DL3013, DL3018, DL3042) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DL3013: pip install -U pip is intentionally unpinned (always want latest pip) DL3018: borgmatic-bash-completion unpinned (tracks borgmatic version from Alpine) DL3042: --no-cache-dir omitted intentionally — using BuildKit cache mount instead Co-Authored-By: Claude Sonnet 4.6 --- Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Dockerfile b/Dockerfile index 2891799..5b2d721 100755 --- a/Dockerfile +++ b/Dockerfile @@ -72,6 +72,7 @@ EOF COPY --link requirements.txt / +# hadolint ignore=DL3013,DL3018,DL3042 RUN --mount=type=cache,id=pip,target=/root/.cache,sharing=locked \ < Date: Sat, 27 Jun 2026 13:16:38 +0100 Subject: [PATCH 3/5] Fix borgmatic wrapper shebang: use env bash not with-contenv with-contenv reads /run/s6/container_environment which doesn't exist when borgmatic is run directly (--entrypoint or docker exec before s6 init). The wrapper is a thin passthrough and doesn't need the s6 container environment. Co-Authored-By: Claude Sonnet 4.6 --- root/usr/local/bin/borgmatic | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/root/usr/local/bin/borgmatic b/root/usr/local/bin/borgmatic index 7e5af25..f462369 100644 --- a/root/usr/local/bin/borgmatic +++ b/root/usr/local/bin/borgmatic @@ -1,4 +1,4 @@ -#!/command/with-contenv bash +#!/usr/bin/env bash # Wrapper around the borgmatic binary. # Warns when borgmatic is invoked directly rather than via borgmatic-start, # which means SIGTERM/INT/HUP signals will not be forwarded gracefully. From 9753bbf59e6a8f2d4e47d823fdfcd5e6112ee12b Mon Sep 17 00:00:00 2001 From: modem7 Date: Sat, 27 Jun 2026 13:20:42 +0100 Subject: [PATCH 4/5] Fix CI version test sentinel: wait for 'Time Zone:' not 'borgmatic' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The borgmatic wrapper now prints a WARNING containing 'borgmatic' before s6 init completes. The CI test was polling for 'borgmatic' in logs as a readiness signal, which fired immediately on the warning — before svc-cron/run had printed the version table. 'Time Zone:' only appears at the end of the version table, making it a reliable sentinel that the container is fully initialised. Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/CI.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index ae064a1..2f22526 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -307,7 +307,7 @@ jobs: run: | docker run -d --name test-versions -e CRON=false ${{ env.IMAGE }} timeout 30 bash -c \ - 'until docker logs test-versions 2>&1 | grep -q "borgmatic"; do sleep 1; done' + 'until docker logs test-versions 2>&1 | grep -q "Time Zone:"; do sleep 1; done' logs=$(docker logs test-versions 2>&1) echo "$logs" echo "$logs" | grep -qE "borg [0-9]" || { echo "borg version missing"; exit 1; } From 5e7373266b58c21b430a64d11fc7ee5e40ad15f0 Mon Sep 17 00:00:00 2001 From: modem7 Date: Sat, 27 Jun 2026 13:23:41 +0100 Subject: [PATCH 5/5] Fix spurious warning in svc-cron/run: call borgmatic.bin for version check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit borgmatic --version at startup hits the wrapper which emits the BORGMATIC_VIA_START warning, since s6 init is not a backup run. Use borgmatic.bin directly for the version display — the wrapper warning is only meaningful for actual backup invocations. Co-Authored-By: Claude Sonnet 4.6 --- root/etc/s6-overlay/s6-rc.d/svc-cron/run | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/root/etc/s6-overlay/s6-rc.d/svc-cron/run b/root/etc/s6-overlay/s6-rc.d/svc-cron/run index 08af146..1c90051 100644 --- a/root/etc/s6-overlay/s6-rc.d/svc-cron/run +++ b/root/etc/s6-overlay/s6-rc.d/svc-cron/run @@ -2,7 +2,7 @@ # Version variables borgver=$(borg --version) -borgmaticver=$(borgmatic --version) +borgmaticver=$(borgmatic.bin --version) apprisever=$(apprise --version | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+') pythonver=$(python3 --version | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+')