diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 5e277ea..864d687 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,17 +1,14 @@ -# See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.202.5/containers/python-3/.devcontainer/base.Dockerfile - -# [Choice] Python version (use -bullseye variants on local arm64/Apple Silicon): 3, 3.10, 3.9, 3.8, 3.7, 3.6, 3-bullseye, 3.10-bullseye, 3.9-bullseye, 3.8-bullseye, 3.7-bullseye, 3.6-bullseye, 3-buster, 3.10-buster, 3.9-buster, 3.8-buster, 3.7-buster, 3.6-buster -ARG VARIANT="" -FROM mcr.microsoft.com/vscode/devcontainers/python:1-${VARIANT} +# https://github.com/devcontainers/images/tree/main/src/python +FROM mcr.microsoft.com/vscode/devcontainers/python:3-3.14-trixie # Add postgresql repository RUN set -eu; \ mkdir -p /etc/apt/keyrings; \ wget --quiet -O /etc/apt/keyrings/pgdg.asc https://www.postgresql.org/media/keys/ACCC4CF8.asc; \ - sh -c 'echo "deb [signed-by=/etc/apt/keyrings/pgdg.asc] https://apt.postgresql.org/pub/repos/apt bookworm-pgdg main" > /etc/apt/sources.list.d/pgdg.list' + sh -c 'echo "deb [signed-by=/etc/apt/keyrings/pgdg.asc] https://apt.postgresql.org/pub/repos/apt $(lsb_release --codename --short)-pgdg main" > /etc/apt/sources.list.d/pgdg.list' RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ - && apt-get -y install --no-install-recommends mariadb-client postgresql-client-16 + && apt-get -y install --no-install-recommends mariadb-client postgresql-client-18 RUN pip install pip-tools LABEL jan-di.database-backup.instance_id="devcontainer" diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index a91927d..a35af93 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,21 +1,10 @@ // For format details, see https://aka.ms/devcontainer.json. For config options, see the README at: // https://github.com/microsoft/vscode-dev-containers/tree/v0.202.5/containers/python-3 { - "name": "Python 3", - "runArgs": [ - "--init" - ], + "name": "Docker Database Backup", "build": { "dockerfile": "Dockerfile", - "context": "..", - "args": { - // Update 'VARIANT' to pick a Python version: 3, 3.10, 3.9, 3.8, 3.7, 3.6 - // Append -bullseye or -buster to pin to an OS version. - // Use -bullseye variants on local on arm64/Apple Silicon. - "VARIANT": "3.12-bookworm", - // Options - "NODE_VERSION": "none" - } + "context": "." }, // Set *default* container specific settings.json values on container create. "customizations": { @@ -47,13 +36,12 @@ ], } }, - // Use 'forwardPorts' to make a list of ports inside the container available locally. - // "forwardPorts": [], - // Use 'postCreateCommand' to run commands after the container is created. "postCreateCommand": "pip-sync", - // Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. "features": { - "ghcr.io/devcontainers/features/docker-outside-of-docker:1": {} + "ghcr.io/devcontainers/features/docker-outside-of-docker:1": { + "moby": "false" + } }, + // root required for pip-sync to install packages globally "remoteUser": "root" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index a977b85..4c46c29 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added +- Decryption script and instructions in README + +### Fixed +- No encryption key specified + +### Changed + +- Updated dependencies +- Switch from debian bookworm to debian trixie +- Switch from python 3.12 to python 3.14 + +### Removed + ## [1.0.0] - 2024-06-01 ### Added diff --git a/Dockerfile b/Dockerfile index ca32a1d..07ed5f3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM docker.io/library/python:3.12.7-bookworm +FROM docker.io/library/python:3.14-trixie LABEL jan-di.database-backup.instance_id="default" @@ -6,7 +6,7 @@ LABEL jan-di.database-backup.instance_id="default" RUN set -eu; \ mkdir -p /etc/apt/keyrings; \ wget --quiet -O /etc/apt/keyrings/pgdg.asc https://www.postgresql.org/media/keys/ACCC4CF8.asc; \ - sh -c 'echo "deb [signed-by=/etc/apt/keyrings/pgdg.asc] https://apt.postgresql.org/pub/repos/apt bookworm-pgdg main" > /etc/apt/sources.list.d/pgdg.list' + sh -c 'echo "deb [signed-by=/etc/apt/keyrings/pgdg.asc] https://apt.postgresql.org/pub/repos/apt trixie-pgdg main" > /etc/apt/sources.list.d/pgdg.list' ENV PYTHONFAULTHANDLER=1 \ PYTHONUNBUFFERED=1 @@ -14,7 +14,7 @@ ENV PYTHONFAULTHANDLER=1 \ # Install apt packages RUN set -eux; \ apt-get update; \ - apt-get install -y mariadb-client postgresql-client-16 tzdata; \ + apt-get install -y mariadb-client postgresql-client-18 tzdata; \ apt-get clean; \ rm -rf /var/lib/apt/lists/*; \ mkdir -p /dump diff --git a/README.md b/README.md index cfb6b6b..291ba89 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Docker Image Tags: Supported Architectures: `amd64`, `arm64` Supported Databases: -- Postgres (<= 16) +- Postgres (<= 18) - MariaDB - MySQL @@ -106,6 +106,7 @@ services: - SCHEDULE=600 - GLOBAL_PASSWORD=secret-password volumes: + - /path/to/dump:/dump - /var/run/docker.sock:/var/run/docker.sock database1: # well known database image @@ -125,6 +126,15 @@ services: - jan-di.database-backup.password=other-password ``` +## Decryption + +To decrypt dump files that were encrypted with this service, you can use the following command: + +```bash +docker run --rm -v /path/to/dump:/dump ghcr.io/jan-di/database-backup decrypt.py /dump/encrypted-dump.sql.aes /dump/decrypted-dump.sql your-encryption-key +``` + + ## Credits - Thanks to [@foorschtbar](https://github.com/foorschtbar) for many feature contributions diff --git a/decrypt.py b/decrypt.py new file mode 100644 index 0000000..dde28a7 --- /dev/null +++ b/decrypt.py @@ -0,0 +1,21 @@ +import sys +import pyAesCrypt + + +def decrypt_file(input_file, output_file, password): + try: + pyAesCrypt.decryptFile(input_file, output_file, password) + print(f"Decryption successful: {output_file}") + except Exception as e: + print(f"Decryption failed: {e}") + + +if __name__ == "__main__": + if len(sys.argv) != 4: + print("Usage: python decrypt.py ") + sys.exit(1) + input_file = sys.argv[1] + output_file = sys.argv[2] + password = sys.argv[3] + + decrypt_file(input_file, output_file, password) diff --git a/requirements.in b/requirements.in index 4565936..b073be7 100644 --- a/requirements.in +++ b/requirements.in @@ -1,6 +1,6 @@ docker~=7.1 -humanize~=4.10 +humanize~=4.15 requests~=2.32 pyaescrypt~=6.1 -croniter~=2.0 -tempora~=5.6 \ No newline at end of file +croniter~=6.0 +tempora~=5.8 \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 8b8a38e..920d2b0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,46 +1,48 @@ # -# This file is autogenerated by pip-compile with Python 3.12 +# This file is autogenerated by pip-compile with Python 3.14 # by the following command: # # pip-compile # -certifi==2024.2.2 +certifi==2026.1.4 # via requests -cffi==1.16.0 +cffi==2.0.0 # via cryptography -charset-normalizer==3.3.2 +charset-normalizer==3.4.4 # via requests -croniter==2.0.7 +croniter==6.0.0 # via -r requirements.in -cryptography==42.0.7 +cryptography==46.0.3 # via pyaescrypt docker==7.1.0 # via -r requirements.in -humanize==4.10.0 +humanize==4.15.0 # via -r requirements.in -idna==3.7 +idna==3.11 # via requests -jaraco-functools==4.0.1 +jaraco-functools==4.4.0 # via tempora -more-itertools==10.2.0 +more-itertools==10.8.0 # via jaraco-functools pyaescrypt==6.1.1 # via -r requirements.in -pycparser==2.22 +pycparser==2.23 # via cffi python-dateutil==2.9.0.post0 + # via + # croniter + # tempora +pytz==2025.2 # via croniter -pytz==2024.1 - # via croniter -requests==2.32.3 +requests==2.32.5 # via # -r requirements.in # docker -six==1.16.0 +six==1.17.0 # via python-dateutil -tempora==5.6.0 +tempora==5.8.1 # via -r requirements.in -urllib3==2.2.1 +urllib3==2.6.3 # via # docker # requests diff --git a/src/backup.py b/src/backup.py index 37e9915..902d7ff 100644 --- a/src/backup.py +++ b/src/backup.py @@ -207,7 +207,7 @@ def run(self): logging.debug("> Encrypting dump") encrypted_dump_file = f"{dump_file}.aes" - if database.encryption_key is None: + if not database.encryption_key: logging.error( "> FAILED: No encryption key specified!") failed = True