Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
8a35bf4
chore(repo): scaffolded BackupHelper package and toolchain
karlspace Jul 6, 2026
0d7f88c
feat(config): added layered configuration and archive foundation
karlspace Jul 6, 2026
e0d5f12
feat(sources): added pluggable source/destination engines and retention
karlspace Jul 6, 2026
9097d3a
feat(runner): added backup/restore orchestration, notifications and CLI
karlspace Jul 6, 2026
19b8887
build(docker): added multi-stage image, compose example and docs
karlspace Jul 6, 2026
07aeb07
ci: added release pipeline and dependabot config
karlspace Jul 6, 2026
dfbba67
feat(runner): added keep_local toggle and consistent prune timestamps
karlspace Jul 6, 2026
ed7fd5d
ci: adopted the BAUER GROUP automation-templates pipeline
karlspace Jul 6, 2026
83dde94
docs: added comprehensive documentation and example configs
karlspace Jul 6, 2026
c45cbd4
build: reworked compose examples and .env.example to the fleet standard
karlspace Jul 6, 2026
a7af261
fix(database): update PostgreSQL data volume path to /var/lib/postgresql
karlspace Jul 7, 2026
9fe9455
chore: enforced LF line endings via .gitattributes
karlspace Jul 7, 2026
a021ece
fix(ci): corrected GHCR image name to the CS-BackupHelper convention
karlspace Jul 7, 2026
db91206
fix(sources): named the postgres component after its database
karlspace Jul 7, 2026
7c7e8f3
build: added a turnkey local development stack
karlspace Jul 7, 2026
9bf1d5e
fix(ci): scoped compose validation to the sidecar file
karlspace Jul 7, 2026
5559173
fix(sources): decompressed DB dumps before piping to the restore client
karlspace Jul 7, 2026
ed914ec
test: added an end-to-end engine test matrix
karlspace Jul 7, 2026
1fef519
test: replaced a secret-looking fixture value to satisfy secret scanning
karlspace Jul 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
.git
.gitignore
.venv
venv
**/__pycache__
**/*.pyc
.pytest_cache
.mypy_cache
.ruff_cache
.coverage
htmlcov
/data
*.env
!.env.example
.vscode
.idea
*.md
!README.md
20 changes: 20 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# EditorConfig — https://editorconfig.org
# Reinforces the LF policy from .gitattributes at the editor level.
root = true

[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
indent_style = space
indent_size = 4

[*.{yml,yaml,json,toml}]
indent_size = 2

[*.md]
trim_trailing_whitespace = false

[Makefile]
indent_style = tab
73 changes: 73 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# =============================================================================
# BackupHelper — Example Environment
# =============================================================================
# Copy to .env and adjust. These variables drive docker-compose.yml (and the
# sidecar example). They are substituted by Compose into the inline
# BACKUP_CONFIG_JSON; secrets referenced as $${VAR} are resolved by the
# container at runtime, not baked into the rendered config.
#
# BackupHelper accepts config three ways (highest precedence first):
# 1. discrete nested env (BACKUP_JOBS__0__RETENTION__COUNT=30)
# 2. BACKUP_CONFIG_JSON / BACKUP_CONFIG_JSON_BASE64 (inline, no host file)
# 3. BACKUP_CONFIG_FILE=/config/backup.json (mounted file)
# See docs/configuration.md for the full reference.
# =============================================================================

# ── Stack identity ───────────────────────────────────────────────────────────
STACK_NAME=app
TIME_ZONE=Etc/UTC

# ── Image ────────────────────────────────────────────────────────────────────
BACKUP_IMAGE=ghcr.io/bauer-group/cs-backuphelper/backuphelper
BACKUP_VERSION=latest
POSTGRES_IMAGE=postgres
POSTGRES_VERSION=18-alpine

# ── Database being backed up ─────────────────────────────────────────────────
DB_NAME=app
DB_USER=app
DB_PASSWORD=change-me-please

# What to back up (filesystem source in the standalone example)
UPLOADS_PATH=app-uploads

# ── Schedule / retention ─────────────────────────────────────────────────────
BACKUP_CRON=15 3 * * *
BACKUP_ON_STARTUP=false
BACKUP_RETENTION_COUNT=14
BACKUP_RETENTION_AGE_DAYS=90

# ── Off-site S3 target (leave empty to keep backups local-only) ──────────────
BACKUP_S3_ENDPOINT=
BACKUP_S3_BUCKET=
BACKUP_S3_ACCESS_KEY=
BACKUP_S3_SECRET_KEY=
BACKUP_S3_REGION=eu-central-1
BACKUP_S3_PREFIX=app/

# ── Optional client-side encryption before off-site upload ───────────────────
# none | age | gpg (age/gpg need a recipient; see docs/encryption.md)
BACKUP_ENCRYPTION_MODE=none
BACKUP_ENCRYPTION_RECIPIENT=

# ── Notifications ────────────────────────────────────────────────────────────
# JSON array of channels: email, webhook, teams, slack, discord, ntfy, healthchecks
BACKUP_ALERT_CHANNELS=[]
BACKUP_ALERT_LEVEL=warnings
BACKUP_WEBHOOK_URL=
BACKUP_WEBHOOK_SECRET=
BACKUP_TEAMS_WEBHOOK=
BACKUP_HEALTHCHECKS_URL=

# ── Logging / resources ──────────────────────────────────────────────────────
BACKUP_LOG_LEVEL=INFO
BACKUP_LOG_FORMAT=console
BACKUP_CPU_LIMIT=1.0
BACKUP_MEM_LIMIT=512M

# ── Sidecar example only (docker-compose.sidecar.yml) ────────────────────────
APP_NETWORK=app
SOURCE_S3_ENDPOINT=http://minio:9000
SOURCE_S3_BUCKET=app
SOURCE_S3_ACCESS_KEY=app
SOURCE_S3_SECRET_KEY=change-me
54 changes: 54 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# =============================================================================
# Line endings — enforce LF consistently across all platforms.
# -----------------------------------------------------------------------------
# This is a Linux-container project: the image, shell, Python and every config
# file run on Linux, so LF is mandatory. `eol=lf` makes Git store AND check out
# LF regardless of the contributor's core.autocrlf setting, which also silences
# the "LF will be replaced by CRLF" warnings on Windows.
# =============================================================================

# Default: treat everything as text and normalize to LF in the working tree.
* text=auto eol=lf

# ── Source & config (must always be LF) ──────────────────────────────────────
*.py text eol=lf
*.pyi text eol=lf
*.sh text eol=lf
*.bash text eol=lf
*.yml text eol=lf
*.yaml text eol=lf
*.json text eol=lf
*.toml text eol=lf
*.cfg text eol=lf
*.ini text eol=lf
*.md text eol=lf
*.txt text eol=lf
*.env text eol=lf

# Dotfiles / files without an extension
.gitignore text eol=lf
.gitattributes text eol=lf
.dockerignore text eol=lf
.editorconfig text eol=lf
.env.example text eol=lf
Dockerfile text eol=lf
Dockerfile.* text eol=lf
*.Dockerfile text eol=lf
CODEOWNERS text eol=lf

# ── Binary (never normalize) ─────────────────────────────────────────────────
*.png binary
*.jpg binary
*.jpeg binary
*.gif binary
*.ico binary
*.webp binary
*.pdf binary
*.gz binary
*.tgz binary
*.tar binary
*.zip binary
*.dump binary
*.age binary
*.gpg binary
*.whl binary
16 changes: 16 additions & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# This is the CODEOWNERS file for the repository.
# It defines who is responsible (owner) for reviewing changes to certain files or folders.
# When someone opens a pull request that modifies these files,
# GitHub will automatically request a review from the listed owners.

# Syntax:
# pattern owner(s)
# - Patterns work like .gitignore rules (wildcards, folders, extensions).
# - Owners can be GitHub usernames (@username) or organization teams (@org/team).
# - Multiple owners can be assigned, separated by spaces.

# -------------------------------------------------------------------
# Default rule: assign all files (*) in the repository to @bauer-group/core.
# This means every pull request will automatically request a review from you,
# unless a more specific rule matches first.
* @bauer-group/core
17 changes: 17 additions & 0 deletions .github/config/docker-base-image-monitor/base-images.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"$schema": "https://raw.githubusercontent.com/bauer-group/automation-templates/main/.github/config/docker-base-image-monitor/docker-base-images.schema.json",
"_description": "BackupHelper — the central backup image. The monitor tracks the base image digest and triggers a release when it moves, so the published image stays current on security patches.",
"images": [
{
"name": "python-alpine",
"image": "python",
"tag": "3.14-alpine",
"variable": "PYTHON_ALPINE_DIGEST",
"description": "Base image for the BackupHelper engine (./Dockerfile)"
}
],
"settings": {
"commit-prefix": "chore(deps)",
"auto-create-variables": true
}
}
21 changes: 21 additions & 0 deletions .github/config/release/semantic-release.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"branches": ["main"],
"plugins": [
"@semantic-release/commit-analyzer",
"@semantic-release/release-notes-generator",
[
"@semantic-release/changelog",
{
"changelogFile": "CHANGELOG.md"
}
],
[
"@semantic-release/git",
{
"assets": ["CHANGELOG.md"],
"message": "chore(release): ${nextRelease.version}\n\n${nextRelease.notes}"
}
],
"@semantic-release/github"
]
}
75 changes: 75 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# =============================================================================
# Dependabot Configuration
# =============================================================================
# Watches:
# 1. GitHub Actions versions (workflows pinned to @main pull module updates)
# 2. The Python runtime dependencies (pyproject.toml)
# 3. The base image inside ./Dockerfile (python:3.14-alpine)
# 4. Image references inside docker-compose*.yml files
#
# Base-image tag bumps here (e.g. python:3.14-alpine → 3.15-alpine) surface as
# PRs and are auto-merged by docker-maintenance.yml. Pure digest drift on the
# existing tag is handled by check-base-images.yml (daily cron).
# =============================================================================

version: 2
updates:
# GitHub Actions
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
day: "sunday"
time: "06:30"
timezone: "Etc/UTC"
labels:
- "dependencies"
- "github-actions"
- "dependabot"
commit-message:
prefix: "chore(ci)"

# Python runtime + test dependencies
- package-ecosystem: "pip"
directory: "/"
schedule:
interval: "weekly"
day: "sunday"
time: "06:30"
timezone: "Etc/UTC"
labels:
- "dependencies"
- "python"
- "dependabot"
commit-message:
prefix: "chore(deps)"

# Base image (python:3.14-alpine in ./Dockerfile)
- package-ecosystem: "docker"
directory: "/"
schedule:
interval: "weekly"
day: "sunday"
time: "06:30"
timezone: "Etc/UTC"
labels:
- "dependencies"
- "docker"
- "dependabot"
commit-message:
prefix: "chore(docker)"

# docker-compose example images
- package-ecosystem: "docker-compose"
directory: "/"
schedule:
interval: "weekly"
day: "sunday"
time: "06:30"
timezone: "Etc/UTC"
labels:
- "dependencies"
- "docker"
- "dependabot"
commit-message:
prefix: "chore(deps)"
33 changes: 33 additions & 0 deletions .github/workflows/ai-issue-summary.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: 🤖 Issue AI Summary

on:
issues:
types: [opened]

pull_request_target:
types: [opened]

permissions:
issues: write
pull-requests: write
contents: read
models: read

jobs:
summarize-new-issue:
name: 🧠 Generate AI Summary
if: github.event_name == 'issues' || github.event_name == 'pull_request_target'
uses: bauer-group/automation-templates/.github/workflows/modules-ai-issue-summary.yml@main
with:
summary-type: "technical"
add-labels: true
add-priority: true
translate: ""
comment-template: |
## AI Analysis

{summary}

---
*This summary was automatically generated by AI to help with triage and may not be 100% accurate.*
secrets: inherit
24 changes: 24 additions & 0 deletions .github/workflows/check-base-images.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: "🔄 Check Base Image Updates"

on:
schedule:
# Daily at 10:00 UTC (11:00 CET / 12:00 CEST)
- cron: '0 10 * * *'

workflow_dispatch:
inputs:
dry-run:
description: 'only check for updates without creating commits or releases'
type: boolean
default: false

jobs:
check-updates:
name: Check for Base Image Updates
uses: bauer-group/automation-templates/.github/workflows/modules-docker-base-image-monitor.yml@main
with:
config-file: '.github/config/docker-base-image-monitor/base-images.json'
dry-run: ${{ inputs.dry-run || false }}
target-workflow: 'docker-release.yml'
target-workflow-inputs: '{"force-release": "true"}'
secrets: inherit
29 changes: 29 additions & 0 deletions .github/workflows/docker-maintenance.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# =============================================================================
# Docker Maintenance — Auto-merge Dependabot PRs (base image)
# =============================================================================
# When Dependabot opens a PR bumping the base image in ./Dockerfile
# (python:3.14-alpine), this workflow auto-approves and merges it after
# validation passes, which then triggers docker-release.yml to build and push
# the updated image.
# =============================================================================

name: 🔧 Docker Maintenance

on:
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
paths:
- 'Dockerfile'

permissions:
contents: write
pull-requests: write

jobs:
maintenance:
name: Auto-merge Dependabot PRs
uses: bauer-group/automation-templates/.github/workflows/docker-maintenance-dependabot.yml@main
with:
merge-method: 'squash'
auto-approve: true
secrets: inherit
Loading
Loading