Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
126 commits
Select commit Hold shift + click to select a range
7f8dffc
build: update pyproject.toml to python 3.14
samidalouche Feb 16, 2026
13a69dc
feat: Implement basic backup functionality
samidalouche Feb 16, 2026
6535abe
build: use in-project virtualenvs
samidalouche Feb 18, 2026
54ae1c6
doc: improve README and create CLAUDE.md
samidalouche Feb 18, 2026
a9534b9
refactor: reimplement the models using pydantic
samidalouche Feb 18, 2026
4f68d22
refactor: remove or simplify the custom validators in the pydantic mo…
samidalouche Feb 18, 2026
5cfc657
refactor: pass now as a parameter instead of mocking it in tests
samidalouche Feb 18, 2026
4a082c2
refactor: type the reasons instead of using strings
samidalouche Feb 18, 2026
8913953
refactor: rearrange config logic into config and configloader modules
samidalouche Feb 19, 2026
39188a5
refactor: move status models to status and output models to output
samidalouche Feb 19, 2026
0adb69e
refactor: use match over if /else
samidalouche Feb 19, 2026
f032013
refactor: Prefer comprehensions and built-in functions (map, filter) …
samidalouche Feb 19, 2026
0954ece
feat: add checks for the existence of rsync and btrfs-tools locally a…
samidalouche Feb 19, 2026
0071897
feat: accumulate all errors during checks instead of short-circuiting
samidalouche Feb 19, 2026
369529e
refactor: introduce the concept of DestinationSyncEndpoint
samidalouche Feb 19, 2026
aa33e4a
feat: define the rsync servers at the top-level to make them reusable
samidalouche Feb 19, 2026
31aba2f
feat: add support for rsync filters
samidalouche Feb 19, 2026
d43dc21
feat: add --delete-excluded and --safe-links to the list of default r…
samidalouche Feb 19, 2026
a394171
feat: add ability to override rysnc settings
samidalouche Feb 19, 2026
d05ab7c
fix: make all shell calls safe with space/special-character-containin…
samidalouche Feb 19, 2026
bf02ba9
refactor: move all checks to the status module
samidalouche Feb 19, 2026
b8a5981
feat: rsync quiet output by default. Pass -v[vv] to the CLI to make r…
samidalouche Feb 19, 2026
86cb163
feat: add ability to override SSH server connect timeout
samidalouche Feb 19, 2026
44c5d81
build: replace custom docker code by testcontainers
samidalouche Feb 19, 2026
10d3242
feat: when using human output, directly stream rsync output to the co…
samidalouche Feb 19, 2026
d11e14e
refactor: Move SyncResult to runner module
samidalouche Feb 19, 2026
36248f6
feat: add check that destination is on btrfs subvolume when btrfs sna…
samidalouche Feb 19, 2026
eb82b50
feat: improve cli.status command to return exit code 1 when there are…
samidalouche Feb 19, 2026
a0ff1f4
refactor: improve typing of cli._load_or_exit
samidalouche Feb 19, 2026
3254b73
feat: When executing the cli.run command, display the status before r…
samidalouche Feb 19, 2026
d3a64d4
feat: display status using Typer RichTable
samidalouche Feb 19, 2026
87b63b2
refactor: name -> slug
samidalouche Feb 19, 2026
89045ff
refactor: prefer explicit if/else over implicit else
samidalouche Feb 19, 2026
d1c7ef3
feat: add sync options to status output
samidalouche Feb 19, 2026
de7723d
feat: add troubleshoot command to guide the user through the setup/tr…
samidalouche Feb 20, 2026
5932322
feat: add additional checks for btrfs-snapshot-enabled destinations
samidalouche Feb 20, 2026
e4a8544
feat: add ssh key setup instructions to troubleshooting messages
samidalouche Feb 20, 2026
7c7df81
feat: add support for enforcing btrfs-snapshot retention policies
samidalouche Feb 20, 2026
8d21601
feat: add testcli app to help with manual testing
samidalouche Feb 20, 2026
bd7736d
refactor: build test configs using the models, not YAML strings
samidalouche Feb 20, 2026
743ec6a
fix: use user_subvol_rm_allowed mount option instead of setcap to get…
samidalouche Feb 20, 2026
8eaca14
feat: add check for user_subvol_rm_allowed mount option
samidalouche Feb 20, 2026
b86a0e6
refactor: move test_checks tests to test_status
samidalouche Feb 20, 2026
93a2792
feat: update `output` and `testdata` to properly handle with SyncReas…
samidalouche Feb 20, 2026
c1436e2
refactor: stylistic changes to `runner.run_all_syncs`
samidalouche Feb 20, 2026
986ded3
refactor: stylistic changes to `output`
samidalouche Feb 20, 2026
0864cb5
feat: add checks for stat and findmnt tools
samidalouche Feb 20, 2026
640b37a
refactor: do not hardcode indents in strings, compute the indent at t…
samidalouche Feb 20, 2026
98de06f
refactor: directly use the OutputFormat type in `cli` args
samidalouche Feb 20, 2026
0a111e7
refactor: rename ssb to dab
samidalouche Feb 20, 2026
e952c41
refactor: testcli - Do not hardcode indents in strings, compute the i…
samidalouche Feb 20, 2026
5b4bd6d
build: Switch to mise over asdf
samidalouche Feb 21, 2026
4d30e83
build: implement simple mise-based CI workflow
samidalouche Feb 21, 2026
0670f12
build: rename dab-testcli to dab-test
samidalouche Feb 21, 2026
f08fe07
build: Improve project description
samidalouche Feb 21, 2026
ac6bacf
build: enable poetry-dynamic-versioning
samidalouche Feb 21, 2026
6db85ca
feat: add release and publish workflows
samidalouche Feb 21, 2026
5b0aeb2
doc: Refine the project description
samidalouche Feb 21, 2026
fd8297b
refactor: rename project to nbkp (Nomad Backup)
samidalouche Feb 22, 2026
59a91e9
doc: Improve Philosophy
samidalouche Feb 22, 2026
dce5972
build: update dependency typer to v0.24.1
samidalouche Feb 22, 2026
b9ab66b
doc: moved TODO from README to "High-Level Priorities" Github issue
samidalouche Feb 22, 2026
e9ba79c
doc: clean-up mise/poetry venv instructions and add github cli auth i…
samidalouche Feb 22, 2026
85b6c37
doc: add some conventions related to Github workflows
samidalouche Feb 22, 2026
625c2f8
build: include the markdown files in the python sdist for PyPI
samidalouche Feb 22, 2026
598deae
Revert "build: include the markdown files in the python sdist for PyPI"
samidalouche Feb 22, 2026
5bef5e1
build: Include license in pyproject.toml
samidalouche Feb 22, 2026
cdc39cd
doc: improve README for PyPI
samidalouche Feb 22, 2026
5512d56
doc: clean-up README to be PyPI-ready
samidalouche Feb 22, 2026
947052e
build: add check-links workflow
samidalouche Feb 22, 2026
e81253f
doc: add mention about Github branch protection rules for `main`
samidalouche Feb 22, 2026
5ca1695
doc: Improve conventions
samidalouche Feb 22, 2026
8f044dd
feat: add progress and spinners to give some feedback to the user
samidalouche Feb 22, 2026
3959d08
feat: make it possible to generate big files with testcli seed, to te…
samidalouche Feb 22, 2026
3877afe
refactor: move runner and rsync modules to sync
samidalouche Feb 22, 2026
08c8802
refactor: move config and configloader to config.protocol and config.…
samidalouche Feb 22, 2026
11d5d96
refactor: move ssh to the sync module
samidalouche Feb 22, 2026
8cbf5cc
refactor: Move btrfs to sync
samidalouche Feb 22, 2026
fd78a3e
refactor: move ssh to top-level `remote` module
samidalouche Feb 22, 2026
a424442
refactor: swap the ssh module by a fabric-based implementation
samidalouche Feb 22, 2026
98fe2e2
refactor: replace the test ssh-keygen functionality with paramiko
samidalouche Feb 23, 2026
b9c09c7
fix: honor --syncs in status checks when running the syncs
samidalouche Feb 23, 2026
bd8ac55
feat: add `sh` command to "compile" nbkp lgoic + config into a shell …
samidalouche Feb 23, 2026
f63954e
feat: use big files by default in testcli:seed
samidalouche Feb 23, 2026
3b1e4f3
doc: add comments to ssh-options in concepts.md
samidalouche Feb 23, 2026
ca02387
feat: add --relative-src and --relative-dst flags to the `sh` command
samidalouche Feb 23, 2026
7ab1f54
feat: testcli:seed - poetry install instead of poetry run for each co…
samidalouche Feb 23, 2026
432e3d5
fix: testcli:seed - generate backup.sh in the seed tmp folder and use…
samidalouche Feb 23, 2026
9fc637f
feat: nbkp-test - include dry-run marker
samidalouche Feb 23, 2026
77e35a2
refactor: improve scriptgen readability by introducing a jinja templa…
samidalouche Feb 23, 2026
1ce5da9
refactor: rename and simplify the generation of RSYNC_* runtime varia…
samidalouche Feb 23, 2026
f58399e
feat: add --prune to `run` command
samidalouche Feb 24, 2026
4ad5459
feat: add missing short form options
samidalouche Feb 24, 2026
8bcc789
feat: Display actionable error messages for config errors
samidalouche Feb 24, 2026
ade50c7
feat: testcli:output - use rule to emphasise the titles
samidalouche Feb 24, 2026
a4b4353
refactor: testcli - move imports to top-level
samidalouche Feb 24, 2026
87ceb0d
refactor: --allow-removable-devices -> --no-strict
samidalouche Feb 24, 2026
a076665
refactor: status -> check
samidalouche Feb 24, 2026
0ffa55e
refactor: move test_* to packages matching the code itself
samidalouche Feb 24, 2026
6e63d77
feat: add config show command
samidalouche Feb 24, 2026
ac472a0
feat: implement nbkp-test seed --docker
samidalouche Feb 24, 2026
58588cf
feat: testcli: drastically improve formatting
samidalouche Feb 24, 2026
01bb5df
feat: improve output of troubleshoot / testcli:output commands
samidalouche Feb 24, 2026
f40b60f
feat: introduce location awareness and multiple ssh endpoints per rem…
samidalouche Feb 24, 2026
a5286d5
doc: improve the conventions
samidalouche Feb 24, 2026
0783823
feat: add support for the hard-link-snapshots strategy when btrfs is …
samidalouche Feb 24, 2026
dd8badb
refactor: Remove Config.location (dead code)
samidalouche Feb 24, 2026
62014e7
feat: add support for multiple proxy jumps
samidalouche Feb 24, 2026
735bc75
fix: resolve the endpoint hosts using paramiko and the user's config
samidalouche Feb 24, 2026
eeb1379
fix: output - Location -> URI to better represent what is displayed
samidalouche Feb 24, 2026
537ecb3
feat: add bastion functionality to nbkp-test seed --docker and integr…
samidalouche Feb 25, 2026
b685264
feat: improve output of the checks
samidalouche Feb 25, 2026
ce2562a
build: add types-paramiko dev dependency to get rid of ignore[import-…
samidalouche Feb 25, 2026
7e1d935
feat: support multiple locations per endpoint + multiple locations fi…
samidalouche Feb 26, 2026
4e8b2ac
feat: compute dependencies between syncs when sync endpoints are shar…
samidalouche Feb 26, 2026
4436bc3
feat: replace --verbose by --progress=none|overall|per-file|full
samidalouche Feb 26, 2026
bdaf6db
fix: display Syncing {slug} on sync start when we do not use the spinner
samidalouche Feb 26, 2026
f8a143d
feat: add --partial-dir=.rsync-partial to default rsync options
samidalouche Feb 26, 2026
c73e542
feat: add support for --compress and --checksum
samidalouche Feb 26, 2026
69c6185
feat: display rsync commands that will be executed
samidalouche Feb 26, 2026
6f27cc7
feat: nbkp-test:seed - add proper remote-to-local sync (currently sho…
samidalouche Feb 26, 2026
da55aee
fix: tear down the test network when using seed --docker
samidalouche Feb 26, 2026
7c90016
fix: fix the remote_to_local test to represent the actual use case
samidalouche Feb 26, 2026
51d6a84
fix: remove ssh key volume mapping which is now unneeeded and breaks CI
samidalouche Feb 26, 2026
60dbccd
refactor: refactor integration tests to use /srv/backups/ and /srv/bt…
samidalouche Feb 26, 2026
389d53a
refactor: share more of the docker test helpers
samidalouche Feb 26, 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
32 changes: 32 additions & 0 deletions .github/workflows/check-links.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: check-links

on:
# Manually trigger the workflow using
# gh workflow run check-links.yml # --ref <branch>
# gh run list --workflow check-links.yml # --branch <branch>
workflow_dispatch:
repository_dispatch:
schedule:
- cron: "00 18 * * 1"

jobs:
linkChecker:
runs-on: ubuntu-latest
permissions:
issues: write # required for peter-evans/create-issue-from-file
steps:
- uses: actions/checkout@v5

- name: Link Checker
id: lychee
uses: lycheeverse/lychee-action@v2
with:
fail: false

- name: Create Issue From File
if: steps.lychee.outputs.exit_code != 0
uses: peter-evans/create-issue-from-file@v5
with:
title: Link Checker Report
content-filepath: ./lychee/out.md
labels: report, automated issue
56 changes: 56 additions & 0 deletions .github/workflows/publish-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
name: publish-test

# This workflow is used to test the publish workflow without actually publishing to PyPI.

# Differences with the publish workflow:
# - It is triggered manually instead of being triggered by the release workflow and/or tags.
# - It publishes to https://test.pypi.org/ instead of https://pypi.org/,
# which is a separate instance of the Python Package Index that allows trying distribution tools and processes without affecting the real index
# - It enables verbose: true in the pypa/gh-action-pypi-publish action to get more detailed logs for debugging
# - It uses POETRY_DYNAMIC_VERSIONING_BYPASS to bypass the dynamic versioning and use a static version that is accepted by Test PyPI,
# since Test PyPI (and PyPI) reject local versions (+hash) generated by poetry-dynamic-versioning in the absence of tags.
#
# Also keep in mind that OIDC authentication does not work with shared workflows,
# so the code essentially needs to be duplicated in the `publish.yml` and `publish-test.yml` workflows.

on:
# The workflow is usually triggered when the release workflow completes, but it can also be re-triggered manually if needed using
# gh workflow run publish-test.yml --ref <tag>
# gh run list --workflow publish-test.yml
workflow_dispatch:
repository_dispatch:

env:
MISE_EXPERIMENTAL: true
# Test PyPI (and PyPI) reject local versions (+hash) generated by poetry-dynamic-versioning in the absence of tags.
# So the simplest approach for testing is to override the version with a static one that is accepted by Test PyPI.
POETRY_DYNAMIC_VERSIONING_BYPASS: "0.0.1.dev0"

jobs:
ci:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v6
- uses: jdx/mise-action@v3
- run: mise run ci-build
pypi-publish:
name: Upload release to Test PyPI
runs-on: ubuntu-latest
environment:
name: testpypi
# cosmetic URL displayed in the GitHub UI for the environment,
# not to be confused with the repository-url used by the pypa/gh-action-pypi-publish action,
# which is the actual URL of the repository where the package is published
url: https://test.pypi.org/p/nbkp/
permissions:
id-token: write # IMPORTANT: this permission is mandatory for trusted publishing
steps:
- uses: actions/checkout@v6
- uses: jdx/mise-action@v3
- run: mise run ci-build
- name: Publish package distributions to Test PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
repository-url: https://test.pypi.org/legacy/
verbose: true
50 changes: 50 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
name: publish

# Test this workflow by making similar changes to `publish-test.yml` and triggering it manually
#
# OIDC authentication does not work with shared workflows,
# so the code essentially needs to be duplicated in the `publish.yml` and `publish-test.yml` workflows.

on:
push:
tags:
- 'v*'
# Tags created by a workflow using GITHUB_TOKEN do not trigger other workflows
workflow_run:
workflows: ["release"]
types:
- completed
# The workflow is usually triggered when the release workflow completes, but it can also be re-triggered manually if needed using
# gh workflow run publish.yml --ref <tag>
# gh run list --workflow publish.yml
workflow_dispatch:
repository_dispatch:

env:
MISE_EXPERIMENTAL: true

jobs:
ci:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v6
- uses: jdx/mise-action@v3
- run: mise run ci-build
pypi-publish:
name: Upload release to PyPI
runs-on: ubuntu-latest
environment:
name: pypi
# cosmetic URL displayed in the GitHub UI for the environment,
# not to be confused with the repository-url used by the pypa/gh-action-pypi-publish action,
# which is the actual URL of the repository where the package is published
url: https://pypi.org/p/nbkp/
permissions:
id-token: write # IMPORTANT: this permission is mandatory for trusted publishing
steps:
- uses: actions/checkout@v6
- uses: jdx/mise-action@v3
- run: mise run ci-build
- name: Publish package distributions to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
27 changes: 27 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: release
on:
# Manually trigger the workflow using
# gh workflow run release.yml # --ref <branch>
# gh run list --workflow release.yml
workflow_dispatch:
repository_dispatch:
# push:
# branches:
# - main

jobs:
bump-version:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Bump version and push tag
id: tag-version
uses: mathieudutour/github-tag-action@v6.2
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
- name: Create a GitHub release
uses: ncipollo/release-action@v1
with:
tag: ${{ steps.tag-version.outputs.new_tag }}
name: ${{ steps.tag-version.outputs.new_tag }}
body: ${{ steps.tag-version.outputs.changelog }}
38 changes: 38 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: test

on:
# Manually trigger the workflow using
# gh workflow run test.yml # --ref <branch>
# gh run list --workflow test.yml # --branch <branch>
workflow_dispatch:
repository_dispatch:
pull_request:
push:
tags:
- "*"
branches:
- "main"

# concurrency:
# group: ${{ github.workflow }}-${{ github.ref }}
# cancel-in-progress: true

concurrency:
# On main/release, we don't want any jobs cancelled so the sha is used to name the group
# On PR branches, we cancel the job if new commits are pushed
# Additionally, we want the workflow for each aggregate project to run independently
# More info: https://stackoverflow.com/a/68422069/253468
group: ${{ github.workflow }}-${{ (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master' || github.ref == 'refs/heads/release' ) && format('{0}-main-{1}', github.workflow, github.sha) || format('{0}-main-{1}', github.workflow, github.ref) }}
cancel-in-progress: true

env:
MISE_EXPERIMENTAL: true

jobs:
test:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v6
- uses: jdx/mise-action@v3
- run: mise run ci-test
1 change: 0 additions & 1 deletion .tool-versions

This file was deleted.

23 changes: 23 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Architecture

Detailed overview of the architecture, design patterns, and execution flow: @docs/architecture.md

## Concepts

Explanations of key concepts such as volumes, syncs, and the configuration model: @docs/concepts.md

## Conventions

Coding conventions, testing practices, and other guidelines for contributing to the codebase: @docs/conventions.md

## Build & Test Commands

Instructions on how to run unit and integration tests, as well as formatting and linting checks: @docs/building-and-testing.md

## Releasing and Publishing

Instructions on how to create new releases and publish the package to PyPI: @docs/releasing-and-publishing.md
41 changes: 0 additions & 41 deletions Makefile

This file was deleted.

Loading