From 40d87a9d32e4993e6c6e67cec84c5e48f0a589dc Mon Sep 17 00:00:00 2001 From: Andras Schmelczer Date: Sat, 24 Jan 2026 16:14:50 +0000 Subject: [PATCH 01/15] Respect gitignores --- Dockerfile | 1 + src/backup.sh | 34 +++++++++++++++++++++++++++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 0df578d..d7d343e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,6 +8,7 @@ RUN apk --no-cache add \ openssh \ bash \ coreutils \ + git \ borgbackup=1.4.0-r0 COPY src /src diff --git a/src/backup.sh b/src/backup.sh index bb85da5..07fea08 100755 --- a/src/backup.sh +++ b/src/backup.sh @@ -30,12 +30,44 @@ fi btrfs subvolume snapshot /btrfs-root /snapshot cd "/snapshot/btrfs-root$BACKUP_RELATIVE_PATH" + +# Generate exclusions for git-untracked files if enabled +EXCLUDE_ARGS="--exclude-from /exclude.conf" +if [ "${IGNORE_GIT_UNTRACKED:-false}" = "true" ]; then + echo "Generating exclusions for git-untracked files..." + GIT_EXCLUDE_FILE=$(mktemp) + + # Find all git repositories and list their untracked files + find . -name .git -type d 2>/dev/null | while read gitdir; do + repo_dir=$(dirname "$gitdir") + ( + cd "$repo_dir" + # Get untracked files (respecting .gitignore) + git ls-files --others --exclude-standard 2>/dev/null | while read file; do + # Output path relative to backup root + echo "${repo_dir#./}/$file" + done + ) + done > "$GIT_EXCLUDE_FILE" + + excluded_count=$(wc -l < "$GIT_EXCLUDE_FILE") + echo "Found $excluded_count git-untracked files to exclude" + + EXCLUDE_ARGS="$EXCLUDE_ARGS --exclude-from $GIT_EXCLUDE_FILE" +fi + borg create --stats \ --list \ --filter=AMCE \ --files-cache=ctime,size,inode \ --compression=zstd,12 \ - --exclude-from /exclude.conf ::"{hostname}-{now:%Y-%m-%dT%H:%M:%S}" . + $EXCLUDE_ARGS ::"{hostname}-{now:%Y-%m-%dT%H:%M:%S}" . + +# Clean up temporary exclude file +if [ -n "$GIT_EXCLUDE_FILE" ] && [ -f "$GIT_EXCLUDE_FILE" ]; then + rm -f "$GIT_EXCLUDE_FILE" +fi + cd - borg prune --list --stats \ From 909f7fbb6d1c09740576374452f72f8649312333 Mon Sep 17 00:00:00 2001 From: Andras Schmelczer Date: Sat, 24 Jan 2026 16:15:04 +0000 Subject: [PATCH 02/15] Fix healtcheck again --- src/backup-wrapper.sh | 9 ++++++++- src/schedule.sh | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/backup-wrapper.sh b/src/backup-wrapper.sh index 5e99c17..a423edb 100755 --- a/src/backup-wrapper.sh +++ b/src/backup-wrapper.sh @@ -37,9 +37,16 @@ configure_environment() { } main() { + # Clear health log at start - only a fully successful run should be marked healthy + rm -f /health/backup_completion_time.log + if [ -n "$BORG_REPO" ]; then # fallback case if multi-target backup isn't needed - execute_script + if execute_script; then + date > /health/backup_completion_time.log + else + echo "Skipping completion log due to backup failure" + fi else local index=0 local configurations_found=false diff --git a/src/schedule.sh b/src/schedule.sh index c7c4cdd..4956b0a 100755 --- a/src/schedule.sh +++ b/src/schedule.sh @@ -10,7 +10,7 @@ get_log_file_name() { echo "/backup-logs/backup_$(date +%Y)_week_$(date +%U).log" } -echo "Starting schedule script at `date`" | log_message +echo "Starting schedule script at $(date)" | log_message while true; do exec /src/backup-wrapper.sh 2>&1 | log_message From c65b29f039cf5effafd91ada42f0586144216a62 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Jan 2026 00:34:20 +0000 Subject: [PATCH 03/15] Bump alpine from 3.21.3 to 3.23.3 Bumps alpine from 3.21.3 to 3.23.3. --- updated-dependencies: - dependency-name: alpine dependency-version: 3.23.3 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 0df578d..744bc0a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine:3.21.3 +FROM alpine:3.23.3 # this is the default, but just to be explicit USER root From c445ea95821f9f90787a69c24590f7182e76595c Mon Sep 17 00:00:00 2001 From: Andras Schmelczer Date: Sun, 15 Mar 2026 14:21:08 +0000 Subject: [PATCH 04/15] Add checks --- .github/workflows/shellcheck.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 .github/workflows/shellcheck.yml diff --git a/.github/workflows/shellcheck.yml b/.github/workflows/shellcheck.yml new file mode 100644 index 0000000..5536ea1 --- /dev/null +++ b/.github/workflows/shellcheck.yml @@ -0,0 +1,18 @@ +name: ShellCheck + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + shellcheck: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Run ShellCheck + uses: ludeeus/action-shellcheck@master + with: + scandir: './src' From 99bf0f857fb09603c2aa0a66241079824e3b399b Mon Sep 17 00:00:00 2001 From: Andras Schmelczer Date: Sun, 15 Mar 2026 14:21:26 +0000 Subject: [PATCH 05/15] Clean up --- src/backup-wrapper.sh | 13 ++++--------- src/backup.sh | 23 +++++++++++------------ src/healthcheck.sh | 2 +- 3 files changed, 16 insertions(+), 22 deletions(-) diff --git a/src/backup-wrapper.sh b/src/backup-wrapper.sh index a423edb..f4bc61b 100755 --- a/src/backup-wrapper.sh +++ b/src/backup-wrapper.sh @@ -1,6 +1,6 @@ #!/bin/bash -echo "Starting backup wrapper script at `date`" +echo "Starting backup wrapper script at $(date)" execute_script() { echo "Executing script with:" @@ -28,18 +28,13 @@ configure_environment() { done # optional variables - for var in BORG_REMOTE_PATH; do - local indexed_var_name="${var}_${index}" - export $var="${!indexed_var_name}" - done + local indexed_var_name="BORG_REMOTE_PATH_${index}" + export BORG_REMOTE_PATH="${!indexed_var_name}" [[ $all_vars_set == true ]] } main() { - # Clear health log at start - only a fully successful run should be marked healthy - rm -f /health/backup_completion_time.log - if [ -n "$BORG_REPO" ]; then # fallback case if multi-target backup isn't needed if execute_script; then @@ -74,4 +69,4 @@ main() { main -echo "Finished backup wrapper script at `date`" +echo "Finished backup wrapper script at $(date)" diff --git a/src/backup.sh b/src/backup.sh index 07fea08..f2b053b 100755 --- a/src/backup.sh +++ b/src/backup.sh @@ -5,15 +5,14 @@ KEEP_WEEKLY=${KEEP_WEEKLY:-3} KEEP_MONTHLY=${KEEP_MONTHLY:-48} KEEP_YEARLY=${KEEP_YEARLY:-10} -echo "Starting backup script at `date`" +echo "Starting backup script at $(date)" export BORG_RSH='ssh -oBatchMode=yes' # https://borgbackup.readthedocs.io/en/stable/usage/notes.html#ssh-batch-mode # break any stale locks in case the script was interrupted borg break-lock -borg info # test whether we have a valid repository -if [ $? -ne 0 ]; then +if ! borg info; then echo "Borg info returned a non-zero status. Initializing Borg..." borg init --encryption=repokey fi @@ -32,18 +31,18 @@ btrfs subvolume snapshot /btrfs-root /snapshot cd "/snapshot/btrfs-root$BACKUP_RELATIVE_PATH" # Generate exclusions for git-untracked files if enabled -EXCLUDE_ARGS="--exclude-from /exclude.conf" +EXCLUDE_ARGS=(--exclude-from /exclude.conf) if [ "${IGNORE_GIT_UNTRACKED:-false}" = "true" ]; then echo "Generating exclusions for git-untracked files..." GIT_EXCLUDE_FILE=$(mktemp) # Find all git repositories and list their untracked files - find . -name .git -type d 2>/dev/null | while read gitdir; do + find . -name .git -type d 2>/dev/null | while read -r gitdir; do repo_dir=$(dirname "$gitdir") ( cd "$repo_dir" # Get untracked files (respecting .gitignore) - git ls-files --others --exclude-standard 2>/dev/null | while read file; do + git ls-files --others --exclude-standard 2>/dev/null | while read -r file; do # Output path relative to backup root echo "${repo_dir#./}/$file" done @@ -53,7 +52,7 @@ if [ "${IGNORE_GIT_UNTRACKED:-false}" = "true" ]; then excluded_count=$(wc -l < "$GIT_EXCLUDE_FILE") echo "Found $excluded_count git-untracked files to exclude" - EXCLUDE_ARGS="$EXCLUDE_ARGS --exclude-from $GIT_EXCLUDE_FILE" + EXCLUDE_ARGS+=(--exclude-from "$GIT_EXCLUDE_FILE") fi borg create --stats \ @@ -61,7 +60,7 @@ borg create --stats \ --filter=AMCE \ --files-cache=ctime,size,inode \ --compression=zstd,12 \ - $EXCLUDE_ARGS ::"{hostname}-{now:%Y-%m-%dT%H:%M:%S}" . + "${EXCLUDE_ARGS[@]}" ::"{hostname}-{now:%Y-%m-%dT%H:%M:%S}" . # Clean up temporary exclude file if [ -n "$GIT_EXCLUDE_FILE" ] && [ -f "$GIT_EXCLUDE_FILE" ]; then @@ -71,10 +70,10 @@ fi cd - borg prune --list --stats \ - --keep-daily=$KEEP_DAILY \ - --keep-weekly=$KEEP_WEEKLY \ - --keep-monthly=$KEEP_MONTHLY \ - --keep-yearly=$KEEP_YEARLY + --keep-daily="$KEEP_DAILY" \ + --keep-weekly="$KEEP_WEEKLY" \ + --keep-monthly="$KEEP_MONTHLY" \ + --keep-yearly="$KEEP_YEARLY" borg compact --threshold=5 --cleanup-commits --verbose --progress diff --git a/src/healthcheck.sh b/src/healthcheck.sh index ba73b99..255ba29 100755 --- a/src/healthcheck.sh +++ b/src/healthcheck.sh @@ -7,7 +7,7 @@ if [ -f /health/backup_completion_time.log ]; then backup_time=$(date --file /health/backup_completion_time.log +%s) age_in_seconds=$((current_time - backup_time)) - if [ ${age_in_seconds} -lt ${MAX_BACKUP_AGE_SECONDS} ]; then + if [ ${age_in_seconds} -lt "${MAX_BACKUP_AGE_SECONDS}" ]; then echo "Backup completed within the last ${MAX_BACKUP_AGE_SECONDS} seconds. Healthcheck passed." exit 0 fi From 202ea7356c1e70b47c83eca0405985614bae41f1 Mon Sep 17 00:00:00 2001 From: Andras Schmelczer Date: Sun, 22 Mar 2026 17:39:45 +0000 Subject: [PATCH 06/15] Small clean up --- README.md | 2 +- docker-compose.yml | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 87dfd8f..d86a23a 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ Over the past 2 years, this backup setup has enabled me to successfully restore - **Scheduled Backups**: Automates backups according to a defined schedule. - **Log Rotation**: Maintains weekly logs of all backup activities. - **Multi-Repository Backups**: Allows backups to multiple BorgBackup repositories simultaneously. -- **Healtcheck**: The healthcheck is based on the time of the last successful backup. +- **Healthcheck**: The healthcheck is based on the time of the last successful backup. ### Multi-target backups diff --git a/docker-compose.yml b/docker-compose.yml index 5f4b028..7c56ea5 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,7 +3,6 @@ services: image: ghcr.io/schmelczer/backup-container:latest container_name: backup init: true - tty: true environment: - TZ=Europe/London - SLEEP_TIME=1h # we will wait an hour between backups From 5d49069b7b70eaf5e913bdb232de25a12be89f96 Mon Sep 17 00:00:00 2001 From: Andras Schmelczer Date: Sun, 22 Mar 2026 17:39:50 +0000 Subject: [PATCH 07/15] Safer default --- config/ssh_config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/ssh_config b/config/ssh_config index 7017c33..a8ed7dd 100644 --- a/config/ssh_config +++ b/config/ssh_config @@ -1,4 +1,4 @@ Host * - StrictHostKeyChecking no + StrictHostKeyChecking accept-new ServerAliveInterval 30 ServerAliveCountMax 3 From 8bc697a7f4ca47b4ee9ccbbbb094e1764393088a Mon Sep 17 00:00:00 2001 From: Andras Schmelczer Date: Sun, 22 Mar 2026 17:40:02 +0000 Subject: [PATCH 08/15] Migrate to forgejo --- .forgejo/workflows/docker-publish.yml | 58 +++++++++++++++++++++++++++ .forgejo/workflows/shellcheck.yml | 19 +++++++++ 2 files changed, 77 insertions(+) create mode 100644 .forgejo/workflows/docker-publish.yml create mode 100644 .forgejo/workflows/shellcheck.yml diff --git a/.forgejo/workflows/docker-publish.yml b/.forgejo/workflows/docker-publish.yml new file mode 100644 index 0000000..4d2b812 --- /dev/null +++ b/.forgejo/workflows/docker-publish.yml @@ -0,0 +1,58 @@ +name: Docker + +on: + push: + branches: [ "main" ] + # Publish semver tags as releases. + tags: [ 'v*.*.*' ] + pull_request: + branches: [ "main" ] + +env: + REGISTRY: ${{ forgejo.server_url }} + IMAGE_NAME: ${{ forgejo.repository }} + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: https://code.forgejo.org/actions/checkout@v4 + + # Set up BuildKit Docker container builder to be able to build + # multi-platform images and export cache + # https://github.com/docker/setup-buildx-action + - name: Set up Docker Buildx + uses: https://github.com/docker/setup-buildx-action@v3 + + # Login against the Forgejo container registry except on PR + # https://github.com/docker/login-action + - name: Log into registry ${{ env.REGISTRY }} + if: forgejo.event_name != 'pull_request' + uses: https://github.com/docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ forgejo.actor }} + password: ${{ secrets.FORGEJO_TOKEN }} + + # Extract metadata (tags, labels) for Docker + # https://github.com/docker/metadata-action + - name: Extract Docker metadata + id: meta + uses: https://github.com/docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + + # Build and push Docker image with Buildx (don't push on PR) + # https://github.com/docker/build-push-action + - name: Build and push Docker image + id: build-and-push + uses: https://github.com/docker/build-push-action@v5 + with: + context: . + push: ${{ forgejo.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + diff --git a/.forgejo/workflows/shellcheck.yml b/.forgejo/workflows/shellcheck.yml new file mode 100644 index 0000000..196a617 --- /dev/null +++ b/.forgejo/workflows/shellcheck.yml @@ -0,0 +1,19 @@ +name: ShellCheck + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + shellcheck: + runs-on: ubuntu-latest + steps: + - uses: https://code.forgejo.org/actions/checkout@v4 + + - name: Install ShellCheck + run: apt-get update && apt-get install -y shellcheck + + - name: Run ShellCheck + run: find ./src -name '*.sh' -exec shellcheck {} + From bfea98db6153f5412d5966225bc8e0804d259a32 Mon Sep 17 00:00:00 2001 From: Andras Schmelczer Date: Sun, 22 Mar 2026 17:40:57 +0000 Subject: [PATCH 09/15] Don't start unhealthy --- src/healthcheck.sh | 15 +++++++++++++-- src/schedule.sh | 1 + 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/healthcheck.sh b/src/healthcheck.sh index 255ba29..c4cb69d 100755 --- a/src/healthcheck.sh +++ b/src/healthcheck.sh @@ -2,15 +2,26 @@ set -e +MAX_BACKUP_AGE_SECONDS="${MAX_BACKUP_AGE_SECONDS:-86400}" + if [ -f /health/backup_completion_time.log ]; then current_time=$(date +%s) backup_time=$(date --file /health/backup_completion_time.log +%s) age_in_seconds=$((current_time - backup_time)) - - if [ ${age_in_seconds} -lt "${MAX_BACKUP_AGE_SECONDS}" ]; then + + if [ "${age_in_seconds}" -lt "${MAX_BACKUP_AGE_SECONDS}" ]; then echo "Backup completed within the last ${MAX_BACKUP_AGE_SECONDS} seconds. Healthcheck passed." exit 0 fi +elif [ -f /health/container_start_time.log ]; then + current_time=$(date +%s) + start_time=$(date --file /health/container_start_time.log +%s) + age_in_seconds=$((current_time - start_time)) + + if [ "${age_in_seconds}" -lt "${MAX_BACKUP_AGE_SECONDS}" ]; then + echo "No backup completed yet, but container started less than ${MAX_BACKUP_AGE_SECONDS} seconds ago. Healthcheck passed." + exit 0 + fi fi echo "Backup not completed within the last ${MAX_BACKUP_AGE_SECONDS} seconds. Healthcheck failed." diff --git a/src/schedule.sh b/src/schedule.sh index 4956b0a..1ca95b1 100755 --- a/src/schedule.sh +++ b/src/schedule.sh @@ -11,6 +11,7 @@ get_log_file_name() { } echo "Starting schedule script at $(date)" | log_message +date > /health/container_start_time.log while true; do exec /src/backup-wrapper.sh 2>&1 | log_message From fd581ef877589d39041dfecdbed7044acba3e84e Mon Sep 17 00:00:00 2001 From: Andras Schmelczer Date: Sun, 22 Mar 2026 17:41:30 +0000 Subject: [PATCH 10/15] Always clean up --- src/backup.sh | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/src/backup.sh b/src/backup.sh index f2b053b..11a6611 100755 --- a/src/backup.sh +++ b/src/backup.sh @@ -17,18 +17,29 @@ if ! borg info; then borg init --encryption=repokey fi -# The above command will fail if the repo hasn't been already initialized, +# The above command will fail if the repo hasn't been already initialized, # so we can ignore the return status. However, if any of the commands below fail, # we want to stop the script immediately. set -e +cleanup() { + if [ -n "${GIT_EXCLUDE_FILE:-}" ] && [ -f "$GIT_EXCLUDE_FILE" ]; then + rm -f "$GIT_EXCLUDE_FILE" + fi + if [ -d "/snapshot/btrfs-root" ]; then + cd / + btrfs subvolume delete /snapshot/btrfs-root || true + fi +} +trap cleanup EXIT + if [ -d "/snapshot/btrfs-root" ]; then btrfs subvolume delete /snapshot/btrfs-root fi btrfs subvolume snapshot /btrfs-root /snapshot -cd "/snapshot/btrfs-root$BACKUP_RELATIVE_PATH" +cd "/snapshot/btrfs-root${BACKUP_RELATIVE_PATH:-}" # Generate exclusions for git-untracked files if enabled EXCLUDE_ARGS=(--exclude-from /exclude.conf) @@ -37,12 +48,12 @@ if [ "${IGNORE_GIT_UNTRACKED:-false}" = "true" ]; then GIT_EXCLUDE_FILE=$(mktemp) # Find all git repositories and list their untracked files - find . -name .git -type d 2>/dev/null | while read -r gitdir; do + find . -name .git -type d | while read -r gitdir; do repo_dir=$(dirname "$gitdir") ( cd "$repo_dir" # Get untracked files (respecting .gitignore) - git ls-files --others --exclude-standard 2>/dev/null | while read -r file; do + git ls-files --others --exclude-standard | while read -r file; do # Output path relative to backup root echo "${repo_dir#./}/$file" done @@ -62,11 +73,6 @@ borg create --stats \ --compression=zstd,12 \ "${EXCLUDE_ARGS[@]}" ::"{hostname}-{now:%Y-%m-%dT%H:%M:%S}" . -# Clean up temporary exclude file -if [ -n "$GIT_EXCLUDE_FILE" ] && [ -f "$GIT_EXCLUDE_FILE" ]; then - rm -f "$GIT_EXCLUDE_FILE" -fi - cd - borg prune --list --stats \ @@ -76,6 +82,3 @@ borg prune --list --stats \ --keep-yearly="$KEEP_YEARLY" borg compact --threshold=5 --cleanup-commits --verbose --progress - -btrfs subvolume delete /snapshot/btrfs-root - From 31bc548fdd250cb16d40df9b535f78d696618e0c Mon Sep 17 00:00:00 2001 From: Andras Schmelczer Date: Sun, 22 Mar 2026 17:41:39 +0000 Subject: [PATCH 11/15] Lint --- src/backup-wrapper.sh | 2 +- src/schedule.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/backup-wrapper.sh b/src/backup-wrapper.sh index f4bc61b..feb0219 100755 --- a/src/backup-wrapper.sh +++ b/src/backup-wrapper.sh @@ -20,7 +20,7 @@ configure_environment() { for var in BORG_PASSPHRASE BORG_REPO; do local indexed_var_name="${var}_${index}" if [[ -n "${!indexed_var_name}" ]]; then - export $var="${!indexed_var_name}" + export "$var"="${!indexed_var_name}" else all_vars_set=false break diff --git a/src/schedule.sh b/src/schedule.sh index 1ca95b1..9aaf1f3 100755 --- a/src/schedule.sh +++ b/src/schedule.sh @@ -14,7 +14,7 @@ echo "Starting schedule script at $(date)" | log_message date > /health/container_start_time.log while true; do - exec /src/backup-wrapper.sh 2>&1 | log_message + /src/backup-wrapper.sh 2>&1 | log_message echo "Sleeping for $SLEEP_TIME" | log_message # Using a simple sleep loop to schedule backups instead of cron to avoid concurrency issues From 7e7653518e115443f2448f597a554f100b1997b3 Mon Sep 17 00:00:00 2001 From: Andras Schmelczer Date: Mon, 23 Mar 2026 07:41:06 +0000 Subject: [PATCH 12/15] Try fixing CI --- .forgejo/workflows/docker-publish.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.forgejo/workflows/docker-publish.yml b/.forgejo/workflows/docker-publish.yml index 4d2b812..9b6839d 100644 --- a/.forgejo/workflows/docker-publish.yml +++ b/.forgejo/workflows/docker-publish.yml @@ -15,7 +15,10 @@ env: jobs: build: - runs-on: ubuntu-latest + runs-on: ubuntu-docker + container: + volumes: + - /var/run/docker.sock:/var/run/docker.sock steps: - name: Checkout repository From 642796f85b7278fcbf9976ba7e459780c6d45e0e Mon Sep 17 00:00:00 2001 From: Andras Schmelczer Date: Thu, 21 May 2026 21:17:20 +0100 Subject: [PATCH 13/15] Fix borg remote path usage --- src/backup-wrapper.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/backup-wrapper.sh b/src/backup-wrapper.sh index feb0219..577f7dd 100755 --- a/src/backup-wrapper.sh +++ b/src/backup-wrapper.sh @@ -29,7 +29,11 @@ configure_environment() { # optional variables local indexed_var_name="BORG_REMOTE_PATH_${index}" - export BORG_REMOTE_PATH="${!indexed_var_name}" + if [[ -n "${!indexed_var_name}" ]]; then + export BORG_REMOTE_PATH="${!indexed_var_name}" + else + unset BORG_REMOTE_PATH + fi [[ $all_vars_set == true ]] } From c30ca25a77924f3c93e5cb53828cbdee0e6b54a6 Mon Sep 17 00:00:00 2001 From: Andras Schmelczer Date: Fri, 22 May 2026 06:57:55 +0100 Subject: [PATCH 14/15] Change publishing --- .forgejo/workflows/docker-publish.yml | 51 +++++---------- .github/workflows/docker-publish.yml | 90 --------------------------- .github/workflows/shellcheck.yml | 18 ------ 3 files changed, 15 insertions(+), 144 deletions(-) delete mode 100644 .github/workflows/docker-publish.yml delete mode 100644 .github/workflows/shellcheck.yml diff --git a/.forgejo/workflows/docker-publish.yml b/.forgejo/workflows/docker-publish.yml index 9b6839d..19c0509 100644 --- a/.forgejo/workflows/docker-publish.yml +++ b/.forgejo/workflows/docker-publish.yml @@ -3,7 +3,6 @@ name: Docker on: push: branches: [ "main" ] - # Publish semver tags as releases. tags: [ 'v*.*.*' ] pull_request: branches: [ "main" ] @@ -16,46 +15,26 @@ jobs: build: runs-on: ubuntu-docker - container: - volumes: - - /var/run/docker.sock:/var/run/docker.sock steps: - name: Checkout repository uses: https://code.forgejo.org/actions/checkout@v4 - # Set up BuildKit Docker container builder to be able to build - # multi-platform images and export cache - # https://github.com/docker/setup-buildx-action - - name: Set up Docker Buildx - uses: https://github.com/docker/setup-buildx-action@v3 - - # Login against the Forgejo container registry except on PR - # https://github.com/docker/login-action - - name: Log into registry ${{ env.REGISTRY }} + - name: Log into registry if: forgejo.event_name != 'pull_request' - uses: https://github.com/docker/login-action@v3 - with: - registry: ${{ env.REGISTRY }} - username: ${{ forgejo.actor }} - password: ${{ secrets.FORGEJO_TOKEN }} + run: echo "${{ secrets.FORGEJO_TOKEN }}" | docker login ${{ env.REGISTRY }} -u ${{ forgejo.actor }} --password-stdin - # Extract metadata (tags, labels) for Docker - # https://github.com/docker/metadata-action - - name: Extract Docker metadata - id: meta - uses: https://github.com/docker/metadata-action@v5 - with: - images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} - - # Build and push Docker image with Buildx (don't push on PR) - # https://github.com/docker/build-push-action - - name: Build and push Docker image - id: build-and-push - uses: https://github.com/docker/build-push-action@v5 - with: - context: . - push: ${{ forgejo.event_name != 'pull_request' }} - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} + - name: Build Docker image + run: | + TAG="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest" + if [ "${{ forgejo.ref_type }}" = "tag" ]; then + VERSION="${{ forgejo.ref_name }}" + docker build -t "$TAG" -t "${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${VERSION}" . + else + docker build -t "$TAG" . + fi + - name: Push Docker image + if: forgejo.event_name != 'pull_request' + run: | + docker push --all-tags "${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}" diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml deleted file mode 100644 index 1df91f6..0000000 --- a/.github/workflows/docker-publish.yml +++ /dev/null @@ -1,90 +0,0 @@ -name: Docker - -on: - push: - branches: [ "main" ] - # Publish semver tags as releases. - tags: [ 'v*.*.*' ] - pull_request: - branches: [ "main" ] - -env: - # Use docker.io for Docker Hub if empty - REGISTRY: ghcr.io - # github.repository as / - IMAGE_NAME: ${{ github.repository }} - -jobs: - build: - - runs-on: ubuntu-latest - permissions: - contents: read - packages: write - # This is used to complete the identity challenge - # with sigstore/fulcio when running outside of PRs. - id-token: write - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - # Install the cosign tool except on PR - # https://github.com/sigstore/cosign-installer - - name: Install cosign - if: github.event_name != 'pull_request' - uses: sigstore/cosign-installer@59acb6260d9c0ba8f4a2f9d9b48431a222b68e20 #v3.5.0 - with: - cosign-release: 'v2.2.4' - - # Set up BuildKit Docker container builder to be able to build - # multi-platform images and export cache - # https://github.com/docker/setup-buildx-action - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0 - - # Login against a Docker registry except on PR - # https://github.com/docker/login-action - - name: Log into registry ${{ env.REGISTRY }} - if: github.event_name != 'pull_request' - uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0 - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - # Extract metadata (tags, labels) for Docker - # https://github.com/docker/metadata-action - - name: Extract Docker metadata - id: meta - uses: docker/metadata-action@96383f45573cb7f253c731d3b3ab81c87ef81934 # v5.0.0 - with: - images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} - - # Build and push Docker image with Buildx (don't push on PR) - # https://github.com/docker/build-push-action - - name: Build and push Docker image - id: build-and-push - uses: docker/build-push-action@0565240e2d4ab88bba5387d719585280857ece09 # v5.0.0 - with: - context: . - push: ${{ github.event_name != 'pull_request' }} - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - cache-from: type=gha - cache-to: type=gha,mode=max - - # Sign the resulting Docker image digest except on PRs. - # This will only write to the public Rekor transparency log when the Docker - # repository is public to avoid leaking data. If you would like to publish - # transparency data even for private images, pass --force to cosign below. - # https://github.com/sigstore/cosign - - name: Sign the published Docker image - if: ${{ github.event_name != 'pull_request' }} - env: - # https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions#using-an-intermediate-environment-variable - TAGS: ${{ steps.meta.outputs.tags }} - DIGEST: ${{ steps.build-and-push.outputs.digest }} - # This step uses the identity token to provision an ephemeral certificate - # against the sigstore community Fulcio instance. - run: echo "${TAGS}" | xargs -I {} cosign sign --yes {}@${DIGEST} diff --git a/.github/workflows/shellcheck.yml b/.github/workflows/shellcheck.yml deleted file mode 100644 index 5536ea1..0000000 --- a/.github/workflows/shellcheck.yml +++ /dev/null @@ -1,18 +0,0 @@ -name: ShellCheck - -on: - push: - branches: [main] - pull_request: - branches: [main] - -jobs: - shellcheck: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - name: Run ShellCheck - uses: ludeeus/action-shellcheck@master - with: - scandir: './src' From c8cb561df5460bc5e23109283d1069f216a38fe0 Mon Sep 17 00:00:00 2001 From: Andras Schmelczer Date: Fri, 22 May 2026 08:05:25 +0100 Subject: [PATCH 15/15] Run on self-hosted runner --- .forgejo/workflows/docker-publish.yml | 4 +--- .forgejo/workflows/shellcheck.yml | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/.forgejo/workflows/docker-publish.yml b/.forgejo/workflows/docker-publish.yml index 19c0509..59016b5 100644 --- a/.forgejo/workflows/docker-publish.yml +++ b/.forgejo/workflows/docker-publish.yml @@ -13,9 +13,7 @@ env: jobs: build: - - runs-on: ubuntu-docker - + runs-on: docker steps: - name: Checkout repository uses: https://code.forgejo.org/actions/checkout@v4 diff --git a/.forgejo/workflows/shellcheck.yml b/.forgejo/workflows/shellcheck.yml index 196a617..df53432 100644 --- a/.forgejo/workflows/shellcheck.yml +++ b/.forgejo/workflows/shellcheck.yml @@ -8,7 +8,7 @@ on: jobs: shellcheck: - runs-on: ubuntu-latest + runs-on: docker steps: - uses: https://code.forgejo.org/actions/checkout@v4