backuplint 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. backuplint-1.0.0/Dockerfile.controller +64 -0
  2. backuplint-1.0.0/LICENSE +21 -0
  3. backuplint-1.0.0/MANIFEST.in +13 -0
  4. backuplint-1.0.0/PKG-INFO +318 -0
  5. backuplint-1.0.0/README.md +275 -0
  6. backuplint-1.0.0/SECURITY.md +28 -0
  7. backuplint-1.0.0/docker/agent-entrypoint.sh +66 -0
  8. backuplint-1.0.0/docker/agent-preflight.py +70 -0
  9. backuplint-1.0.0/docker/controller-entrypoint.sh +42 -0
  10. backuplint-1.0.0/docker/controller-healthcheck.py +60 -0
  11. backuplint-1.0.0/docker/controller-preflight.py +75 -0
  12. backuplint-1.0.0/pyproject.toml +78 -0
  13. backuplint-1.0.0/setup.cfg +4 -0
  14. backuplint-1.0.0/src/backuplint/__init__.py +3 -0
  15. backuplint-1.0.0/src/backuplint/__main__.py +6 -0
  16. backuplint-1.0.0/src/backuplint/audit.py +293 -0
  17. backuplint-1.0.0/src/backuplint/classify.py +109 -0
  18. backuplint-1.0.0/src/backuplint/cli.py +1444 -0
  19. backuplint-1.0.0/src/backuplint/compose.py +215 -0
  20. backuplint-1.0.0/src/backuplint/config.py +531 -0
  21. backuplint-1.0.0/src/backuplint/coverage.py +386 -0
  22. backuplint-1.0.0/src/backuplint/database.py +39 -0
  23. backuplint-1.0.0/src/backuplint/engine/__init__.py +22 -0
  24. backuplint-1.0.0/src/backuplint/engine/base.py +43 -0
  25. backuplint-1.0.0/src/backuplint/engine/factory.py +56 -0
  26. backuplint-1.0.0/src/backuplint/engine/restic_engine.py +139 -0
  27. backuplint-1.0.0/src/backuplint/engine/types.py +43 -0
  28. backuplint-1.0.0/src/backuplint/errors.py +11 -0
  29. backuplint-1.0.0/src/backuplint/events.py +253 -0
  30. backuplint-1.0.0/src/backuplint/fleet/__init__.py +19 -0
  31. backuplint-1.0.0/src/backuplint/fleet/agent.py +515 -0
  32. backuplint-1.0.0/src/backuplint/fleet/capabilities.py +266 -0
  33. backuplint-1.0.0/src/backuplint/fleet/certs.py +346 -0
  34. backuplint-1.0.0/src/backuplint/fleet/compat.py +104 -0
  35. backuplint-1.0.0/src/backuplint/fleet/controller.py +784 -0
  36. backuplint-1.0.0/src/backuplint/fleet/controller_store.py +1476 -0
  37. backuplint-1.0.0/src/backuplint/fleet/dashboard/__init__.py +14 -0
  38. backuplint-1.0.0/src/backuplint/fleet/dashboard/assurance.py +478 -0
  39. backuplint-1.0.0/src/backuplint/fleet/dashboard/auth.py +215 -0
  40. backuplint-1.0.0/src/backuplint/fleet/dashboard/config.py +31 -0
  41. backuplint-1.0.0/src/backuplint/fleet/dashboard/format.py +173 -0
  42. backuplint-1.0.0/src/backuplint/fleet/dashboard/http.py +562 -0
  43. backuplint-1.0.0/src/backuplint/fleet/dashboard/query.py +1288 -0
  44. backuplint-1.0.0/src/backuplint/fleet/dashboard/static/logo-mark-64.png +0 -0
  45. backuplint-1.0.0/src/backuplint/fleet/dashboard/static/logo-mark-white-64.png +0 -0
  46. backuplint-1.0.0/src/backuplint/fleet/dashboard/static/logo-mark.svg +4 -0
  47. backuplint-1.0.0/src/backuplint/fleet/dashboard/ui.py +1583 -0
  48. backuplint-1.0.0/src/backuplint/fleet/delivery.py +260 -0
  49. backuplint-1.0.0/src/backuplint/fleet/policy_apply.py +346 -0
  50. backuplint-1.0.0/src/backuplint/fleet/policy_store.py +1199 -0
  51. backuplint-1.0.0/src/backuplint/fleet/presence.py +44 -0
  52. backuplint-1.0.0/src/backuplint/fleet/protocol.py +178 -0
  53. backuplint-1.0.0/src/backuplint/fleet/provisioning.py +114 -0
  54. backuplint-1.0.0/src/backuplint/fleet/queue_policy.py +319 -0
  55. backuplint-1.0.0/src/backuplint/fleet/telemetry.py +264 -0
  56. backuplint-1.0.0/src/backuplint/fleet_config.py +44 -0
  57. backuplint-1.0.0/src/backuplint/install/__init__.py +50 -0
  58. backuplint-1.0.0/src/backuplint/install/deployment.py +29 -0
  59. backuplint-1.0.0/src/backuplint/install/detect.py +162 -0
  60. backuplint-1.0.0/src/backuplint/install/diagnostics.py +132 -0
  61. backuplint-1.0.0/src/backuplint/install/distro.py +85 -0
  62. backuplint-1.0.0/src/backuplint/install/executor.py +580 -0
  63. backuplint-1.0.0/src/backuplint/install/features.py +231 -0
  64. backuplint-1.0.0/src/backuplint/install/layout.py +296 -0
  65. backuplint-1.0.0/src/backuplint/install/manifest.py +137 -0
  66. backuplint-1.0.0/src/backuplint/install/packages.py +165 -0
  67. backuplint-1.0.0/src/backuplint/install/plan.py +226 -0
  68. backuplint-1.0.0/src/backuplint/install/profile.py +275 -0
  69. backuplint-1.0.0/src/backuplint/install/roles.py +99 -0
  70. backuplint-1.0.0/src/backuplint/install/support.py +86 -0
  71. backuplint-1.0.0/src/backuplint/install/systemd_units.py +148 -0
  72. backuplint-1.0.0/src/backuplint/install/wizard.py +143 -0
  73. backuplint-1.0.0/src/backuplint/integrity_state.py +206 -0
  74. backuplint-1.0.0/src/backuplint/models.py +45 -0
  75. backuplint-1.0.0/src/backuplint/paths.py +74 -0
  76. backuplint-1.0.0/src/backuplint/policy/__init__.py +27 -0
  77. backuplint-1.0.0/src/backuplint/policy/cli.py +400 -0
  78. backuplint-1.0.0/src/backuplint/policy/errors.py +7 -0
  79. backuplint-1.0.0/src/backuplint/policy/gitops.py +89 -0
  80. backuplint-1.0.0/src/backuplint/policy/resolve.py +79 -0
  81. backuplint-1.0.0/src/backuplint/policy/rollout.py +87 -0
  82. backuplint-1.0.0/src/backuplint/policy/schema.py +213 -0
  83. backuplint-1.0.0/src/backuplint/policy/settings.py +220 -0
  84. backuplint-1.0.0/src/backuplint/process.py +44 -0
  85. backuplint-1.0.0/src/backuplint/reporting.py +387 -0
  86. backuplint-1.0.0/src/backuplint/restic.py +494 -0
  87. backuplint-1.0.0/src/backuplint/restic_errors.py +175 -0
  88. backuplint-1.0.0/src/backuplint/restore_dest.py +256 -0
  89. backuplint-1.0.0/src/backuplint/restore_verify.py +416 -0
  90. backuplint-1.0.0/src/backuplint/schedule_config.py +181 -0
  91. backuplint-1.0.0/src/backuplint/schedule_lock.py +96 -0
  92. backuplint-1.0.0/src/backuplint/schedule_store.py +416 -0
  93. backuplint-1.0.0/src/backuplint/scheduler.py +591 -0
  94. backuplint-1.0.0/src/backuplint/secrets/__init__.py +65 -0
  95. backuplint-1.0.0/src/backuplint/secrets/errors.py +35 -0
  96. backuplint-1.0.0/src/backuplint/secrets/file_checks.py +193 -0
  97. backuplint-1.0.0/src/backuplint/secrets/ref.py +190 -0
  98. backuplint-1.0.0/src/backuplint/secrets/resolve.py +146 -0
  99. backuplint-1.0.0/src/backuplint/secrets/value.py +53 -0
  100. backuplint-1.0.0/src/backuplint/siem/__init__.py +35 -0
  101. backuplint-1.0.0/src/backuplint/siem/config.py +375 -0
  102. backuplint-1.0.0/src/backuplint/siem/event.py +571 -0
  103. backuplint-1.0.0/src/backuplint/siem/exporter.py +224 -0
  104. backuplint-1.0.0/src/backuplint/siem/queue.py +602 -0
  105. backuplint-1.0.0/src/backuplint/siem/runtime.py +241 -0
  106. backuplint-1.0.0/src/backuplint/siem/telemetry.py +129 -0
  107. backuplint-1.0.0/src/backuplint/siem/transport/__init__.py +6 -0
  108. backuplint-1.0.0/src/backuplint/siem/transport/base.py +78 -0
  109. backuplint-1.0.0/src/backuplint/siem/transport/https_json.py +186 -0
  110. backuplint-1.0.0/src/backuplint/sqlite_backup.py +530 -0
  111. backuplint-1.0.0/src/backuplint/sqlite_util.py +51 -0
  112. backuplint-1.0.0/src/backuplint/timeutil.py +100 -0
  113. backuplint-1.0.0/src/backuplint/volumes.py +43 -0
  114. backuplint-1.0.0/src/backuplint.egg-info/PKG-INFO +318 -0
  115. backuplint-1.0.0/src/backuplint.egg-info/SOURCES.txt +117 -0
  116. backuplint-1.0.0/src/backuplint.egg-info/dependency_links.txt +1 -0
  117. backuplint-1.0.0/src/backuplint.egg-info/entry_points.txt +2 -0
  118. backuplint-1.0.0/src/backuplint.egg-info/requires.txt +13 -0
  119. backuplint-1.0.0/src/backuplint.egg-info/top_level.txt +1 -0
@@ -0,0 +1,64 @@
1
+ # BackupLint fleet controller image (no Docker socket, no Restic, no Compose tooling).
2
+ # Build from the repository root:
3
+ # docker build -f Dockerfile.controller -t backuplint-controller:local .
4
+ #
5
+ # Durable CA/TLS/SQLite state must be mounted at /state (see docs/controller-container.md).
6
+
7
+ # Pin the Debian bookworm slim digest so release images are auditable.
8
+ # python:3.12-slim-bookworm @ 2026-09-19 (includes libpcre2 10.42-1+deb12u1).
9
+ FROM python:3.12-slim-bookworm@sha256:392307d22300de8b5986851a12d9176dfc0fc073e65bf6523ebd7dcbeb23564e
10
+
11
+ ARG BACKUPLINT_UID=10001
12
+ ARG BACKUPLINT_GID=10001
13
+ ARG BACKUPLINT_VERSION=1.0.0
14
+ ARG BACKUPLINT_REVISION=unknown
15
+
16
+ LABEL org.opencontainers.image.title="BackupLint Controller" \
17
+ org.opencontainers.image.description="HTTPS fleet controller (no Docker socket, no Restic)" \
18
+ org.opencontainers.image.source="https://github.com/Netryon/BackupLint" \
19
+ org.opencontainers.image.licenses="MIT" \
20
+ org.opencontainers.image.version="${BACKUPLINT_VERSION}" \
21
+ org.opencontainers.image.revision="${BACKUPLINT_REVISION}" \
22
+ org.opencontainers.image.vendor="BackupLint"
23
+
24
+ RUN apt-get update \
25
+ && apt-get install -y --no-install-recommends openssl ca-certificates \
26
+ && rm -rf /var/lib/apt/lists/* \
27
+ && groupadd --system --gid "${BACKUPLINT_GID}" backuplint \
28
+ && useradd --system --uid "${BACKUPLINT_UID}" --gid backuplint \
29
+ --home-dir /state --shell /usr/sbin/nologin backuplint
30
+
31
+ WORKDIR /app
32
+
33
+ # Copy metadata first for better layer caching, then application sources.
34
+ COPY pyproject.toml README.md LICENSE ./
35
+ COPY src ./src
36
+ COPY docker/controller-entrypoint.sh \
37
+ docker/controller-healthcheck.py \
38
+ docker/controller-preflight.py \
39
+ ./docker/
40
+
41
+ RUN pip install --no-cache-dir --upgrade pip \
42
+ && pip install --no-cache-dir . \
43
+ && chmod 755 \
44
+ /app/docker/controller-entrypoint.sh \
45
+ /app/docker/controller-healthcheck.py \
46
+ /app/docker/controller-preflight.py \
47
+ && mkdir -p /state \
48
+ && chown backuplint:backuplint /state \
49
+ && backuplint --version
50
+
51
+ ENV BACKUPLINT_CONTROLLER_DATA_DIR=/state \
52
+ BACKUPLINT_CONTROLLER_LISTEN=0.0.0.0:8443 \
53
+ BACKUPLINT_CONTROLLER_HOSTNAME=localhost \
54
+ HOME=/state \
55
+ TMPDIR=/tmp \
56
+ PYTHONUNBUFFERED=1
57
+
58
+ USER backuplint:backuplint
59
+ EXPOSE 8443
60
+
61
+ HEALTHCHECK --interval=30s --timeout=5s --start-period=15s --retries=3 \
62
+ CMD ["python", "/app/docker/controller-healthcheck.py"]
63
+
64
+ ENTRYPOINT ["/app/docker/controller-entrypoint.sh"]
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 BackupLint contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,13 @@
1
+ # Explicit sdist membership for release hygiene.
2
+ include LICENSE README.md pyproject.toml SECURITY.md
3
+ graft src
4
+ graft docker
5
+ include Dockerfile.controller
6
+ global-exclude *.py[cod] __pycache__ .DS_Store
7
+ prune docs
8
+ prune tests
9
+ prune test-lab
10
+ prune scripts
11
+ prune deploy
12
+ prune .github
13
+ exclude AGENT_*.md
@@ -0,0 +1,318 @@
1
+ Metadata-Version: 2.4
2
+ Name: backuplint
3
+ Version: 1.0.0
4
+ Summary: Check whether Docker Compose persistent data is covered by backup configuration
5
+ Author: BackupLint contributors
6
+ License: MIT License
7
+
8
+ Copyright (c) 2026 BackupLint contributors
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+
28
+ Requires-Python: >=3.11
29
+ Description-Content-Type: text/markdown
30
+ License-File: LICENSE
31
+ Requires-Dist: typer>=0.12
32
+ Requires-Dist: PyYAML>=6.0
33
+ Provides-Extra: dev
34
+ Requires-Dist: pytest>=8.0; extra == "dev"
35
+ Requires-Dist: hypothesis>=6.100; extra == "dev"
36
+ Requires-Dist: ruff>=0.6; extra == "dev"
37
+ Requires-Dist: bandit>=1.7; extra == "dev"
38
+ Requires-Dist: pip-audit>=2.7; extra == "dev"
39
+ Provides-Extra: browser
40
+ Requires-Dist: playwright>=1.40; extra == "browser"
41
+ Requires-Dist: pytest-playwright>=0.5; extra == "browser"
42
+ Dynamic: license-file
43
+
44
+ <p align="center">
45
+ <img src="docs/images/logo-mark-blue.svg" width="72" height="72" alt="BackupLint logo">
46
+ </p>
47
+
48
+ <h1 align="center">BackupLint</h1>
49
+
50
+ <p align="center"><strong>Find Docker data your backups missed before you discover it during a restore.</strong></p>
51
+
52
+ <p align="center"><em>Don’t just assume your backups work. Prove they work.</em></p>
53
+
54
+ BackupLint is an independent **backup-assurance** layer for Docker Compose stacks. It compares Compose mounts with your backup configuration and reports **PASS**, **WARN**, **FAIL**, or operational **ERROR**.
55
+
56
+ It is **not** a backup engine. It does not replace Restic, Borg, Kopia, or your backup jobs. For v1, **Restic is the only supported engine** when engine-backed checks are enabled. It does not SSH into hosts, delete data, or restore over live application files.
57
+
58
+ ```text
59
+ coverage ≠ integrity ≠ restore verification ≠ disaster recovery
60
+ presence (online / stale / offline) ≠ audit health
61
+ coverage FAIL ≠ repository-unavailable ERROR
62
+ ```
63
+
64
+ ## Choose your deployment
65
+
66
+ BackupLint is **one package**. Pick a role:
67
+
68
+ | Role | Use it when | What it does |
69
+ | --- | --- | --- |
70
+ | **Standalone** | One machine, local backup assurance only | Audits this machine. No fleet controller/dashboard and does not receive other agents. |
71
+ | **Agent** | This machine reports to an existing BackupLint controller | Audits locally and reports over mTLS. No controller/dashboard on this machine. |
72
+ | **Controller** | Dedicated central management node | Receives agent reports, hosts the optional dashboard, central policy, fleet state, and optional SIEM export. |
73
+ | **All-in-one** | The main server should audit itself **and** manage other agents | Runs local checks **and** the fleet controller/dashboard on the same machine. |
74
+
75
+ ```text
76
+ One server only → Standalone
77
+ Dedicated management server → Controller
78
+ Additional monitored servers → Agent
79
+ Main server + fleet management on one machine → All-in-one
80
+ ```
81
+
82
+ **Standalone vs all-in-one:** standalone never runs a controller. All-in-one does: it is a controller that also audits the host it runs on. Use standalone unless you need a fleet.
83
+
84
+ Details: [docs/installation.md](docs/installation.md), [docs/installation-profiles.md](docs/installation-profiles.md).
85
+
86
+ ## 60-second local check (standalone)
87
+
88
+ 1. Install the release wheel (see [Native install](#native--bare-metal-install)).
89
+ 2. Create `backuplint.yml` next to your Compose file:
90
+
91
+ ```yaml
92
+ backup_paths:
93
+ - /srv/docker
94
+ - /srv/app-config
95
+ ```
96
+
97
+ 3. Scan:
98
+
99
+ ```bash
100
+ backuplint scan compose.yml
101
+ backuplint scan compose.yml --config backuplint.yml --json
102
+ ```
103
+
104
+ ```text
105
+ BackupLint Audit
106
+
107
+ ✓ sonarr /srv/docker/sonarr protected
108
+ ✓ radarr /srv/docker/radarr protected
109
+ ✗ vaultwarden /srv/vaultwarden not protected
110
+
111
+ Result: FAIL
112
+ ```
113
+
114
+ ### Want fleet management?
115
+
116
+ Use **controller** on a management node (or **all-in-one** on the main server), then **agent** on every other host. See [Choose your deployment](#choose-your-deployment), [docs/fleet.md](docs/fleet.md), and [docs/dashboard.md](docs/dashboard.md).
117
+
118
+ ## What BackupLint needs from you
119
+
120
+ BackupLint does **not** require one broad privileged “admin account”. You supply only what each role needs.
121
+
122
+ ### Local audit (standalone, agent, or all-in-one)
123
+
124
+ - Compose file path
125
+ - BackupLint config (`backuplint.yml`)
126
+ - Expected backup paths
127
+ - Docker Engine + Compose plugin access when Compose discovery is used
128
+ - Restic repository location for Restic-backed checks
129
+ - Restic password via `password_file`, `RESTIC_PASSWORD`, or `RESTIC_PASSWORD_FILE` (`password_file` always wins). Passwords are never printed.
130
+
131
+ ### Controller
132
+
133
+ - Hostname/DNS name agents will use (certificate SAN)
134
+ - Listener address/port (typically `8443`)
135
+ - Controller state directory
136
+ - Dashboard operator password if the dashboard is enabled
137
+ - Optional SIEM endpoint/config
138
+
139
+ ### Agent
140
+
141
+ - Controller URL
142
+ - Unique agent ID from `enroll-token`
143
+ - One-time enrollment token
144
+ - Controller CA certificate
145
+ - Local Compose/config/Restic access required for the checks that agent will run
146
+
147
+ Enrollment:
148
+
149
+ - the **agent generates its private key locally**
150
+ - the controller signs a **CSR**
151
+ - the **agent private key is not copied to the controller**
152
+ - the enrollment token is **one-use**
153
+ - after enrollment, traffic is **mTLS**
154
+
155
+ Revoke with `backuplint controller revoke <agent_id>`.
156
+
157
+ ## Native / bare-metal install
158
+
159
+ Python **3.11+** (`venv`). Rocky/Alma 9: use `python3.11`. Docker Engine + Compose plugin for `scan`. Restic on `PATH` only if you enable engine-backed checks.
160
+
161
+ Download `backuplint-1.0.0-py3-none-any.whl` from the [v1.0.0 GitHub Release](https://github.com/Netryon/BackupLint/releases/tag/v1.0.0), then:
162
+
163
+ ```bash
164
+ python3 -m venv .venv
165
+ source .venv/bin/activate
166
+ pip install backuplint-1.0.0-py3-none-any.whl
167
+ backuplint --version
168
+ ```
169
+
170
+ Interactive native installer (directories, optional packages, systemd):
171
+
172
+ ```bash
173
+ sudo backuplint install --interactive --yes
174
+ ```
175
+
176
+ Unattended profile:
177
+
178
+ ```bash
179
+ sudo backuplint install --profile profile.yaml --non-interactive --yes
180
+ ```
181
+
182
+ Roles, layout, CSR enrollment, upgrades, uninstall: [docs/installation.md](docs/installation.md), [docs/native-installer.md](docs/native-installer.md).
183
+
184
+ ## Docker install
185
+
186
+ Official GHCR images are published for **linux/amd64**. Raspberry Pi 4 remains a native-install current-candidate platform.
187
+
188
+ ```bash
189
+ docker pull ghcr.io/netryon/backuplint-controller:1.0.0
190
+ docker pull ghcr.io/netryon/backuplint-agent:1.0.0
191
+ ```
192
+
193
+ The same images are also tagged `v1.0.0` and `latest` (stable 1.0.0 convenience tag). Prefer digest pinning in production; immutable digests are listed on the [v1.0.0 GitHub Release](https://github.com/Netryon/BackupLint/releases/tag/v1.0.0).
194
+
195
+ Controller and agent images run as **uid 10001**. Privileged mode is not required. A Docker socket is **not** required for heartbeat, enrollment, or policy. Compose discovery **inside** an agent container needs intentional host/Docker access (not the default).
196
+
197
+ Local source builds remain available as an advanced option:
198
+
199
+ ```bash
200
+ docker build -f Dockerfile.controller --build-arg BACKUPLINT_VERSION=1.0.0 -t backuplint-controller:1.0.0 .
201
+ docker build -f Dockerfile.agent --build-arg BACKUPLINT_VERSION=1.0.0 -t backuplint-agent:1.0.0 .
202
+ ```
203
+
204
+ [docs/docker.md](docs/docker.md)
205
+
206
+ ## Dashboard
207
+
208
+ Optional **read-only** UI on the controller (`https://…:8443/dashboard/`). Presence and audit health stay separate. The dashboard does not write policy.
209
+
210
+ v1 authentication: a **shared operator password**, stored as a **scrypt** hash. There is **no multi-user RBAC** and **no SSO** in v1.
211
+
212
+ ```bash
213
+ backuplint controller dashboard-password --data-dir ./bl-controller
214
+ backuplint controller run --data-dir ./bl-controller --listen 127.0.0.1:8443 --dashboard
215
+ ```
216
+
217
+ [docs/dashboard.md](docs/dashboard.md)
218
+
219
+ ## Screenshots
220
+
221
+ Public-safe demo fleet (synthetic labels).
222
+
223
+ ![Fleet health at a glance — presence and audit state remain separate.](docs/images/01-dashboard-fleet-overview.png)
224
+
225
+ ![A healthy agent stays online with a current PASS audit.](docs/images/02-dashboard-healthy-agent.png)
226
+
227
+ ![Coverage failures and operational repository errors are reported distinctly.](docs/images/03-dashboard-fail-error-mixed.png)
228
+
229
+ ![Historical assurance trends from real stored audit events.](docs/images/04-dashboard-history-trends.png)
230
+
231
+ ![Alerts with project/service deep links.](docs/images/06-dashboard-alerts.png)
232
+
233
+ ![SIEM export health is separate from backup assurance.](docs/images/08-dashboard-siem.png)
234
+
235
+ ![CLI coverage plus Restic integrity and isolated restore verification.](docs/images/07-cli-coverage-integrity.png)
236
+
237
+ ![BackupLint failing when Vaultwarden data is missing from backups](docs/demo/backup-audit-fail.gif)
238
+
239
+ ## Supported platforms (v1.0.0)
240
+
241
+ | Platform | Arch | Current-candidate |
242
+ | --- | --- | --- |
243
+ | Ubuntu | x86_64 | tested |
244
+ | Debian | x86_64 | tested |
245
+ | Rocky Linux 9 | x86_64 | tested |
246
+ | Fedora 43 | x86_64 | tested |
247
+ | Raspberry Pi 4 / Raspberry Pi OS | ARM64 | tested |
248
+ | Native controller + agent | — | tested |
249
+ | Container controller + agent, including mixed topologies | — | tested |
250
+
251
+ Raspberry Pi **3** is not a current-candidate proof. WSL2 is **unsupported**.
252
+
253
+ Controller sizing is evidence-backed **through 500 agents** (about **6–8 MB/agent/day** management-plane traffic at the tested 30s cadence). That **excludes Restic backup payload**. **Do not treat >500 agents as certified capacity.**
254
+
255
+ [docs/support-matrix.md](docs/support-matrix.md) · [docs/validation.md](docs/validation.md) · [docs/architecture.md](docs/architecture.md)
256
+
257
+ ## Security
258
+
259
+ Read-only diagnostics. No deletion of user data, no modification of backups, no secret printing from Compose, `.env`, or backup tools.
260
+
261
+ Container images: digest-pinned `python:3.12-slim-bookworm`, Trivy-reviewed, residual CVEs remain. **Not a “zero CVE” claim.** Agent: non-root uid 10001, unprivileged, no baked secrets.
262
+
263
+ [docs/security.md](docs/security.md) · [SECURITY.md](SECURITY.md)
264
+
265
+ ## Known limitations
266
+
267
+ - Named volume coverage depends on local `docker volume inspect`; missing volumes are **WARN**, not FAIL
268
+ - Cache/temporary mounts are skipped by path heuristics
269
+ - Restic coverage uses snapshot path roots, not file-level contents
270
+ - Database image warnings are advisory; filesystem coverage is not a consistent DB backup
271
+ - Isolated restore verification is not a disaster-recovery drill
272
+ - Unit tests alone are not production readiness
273
+
274
+ ## Documentation
275
+
276
+ | Topic | Doc |
277
+ | --- | --- |
278
+ | Native install | [docs/installation.md](docs/installation.md) |
279
+ | Native installer / systemd | [docs/native-installer.md](docs/native-installer.md) |
280
+ | Docker | [docs/docker.md](docs/docker.md) |
281
+ | Fleet / enrollment | [docs/fleet.md](docs/fleet.md) |
282
+ | Dashboard | [docs/dashboard.md](docs/dashboard.md) |
283
+ | Troubleshooting | [docs/troubleshooting.md](docs/troubleshooting.md) |
284
+ | Validation evidence | [docs/validation.md](docs/validation.md) |
285
+ | Release notes | [docs/release-notes-v1.0.0.md](docs/release-notes-v1.0.0.md) |
286
+
287
+ ## Feedback, bugs, and questions
288
+
289
+ Feedback is welcome. Please use the channel that matches what you need:
290
+
291
+ - **Bug report:** [open a bug report](https://github.com/Netryon/BackupLint/issues/new?template=bug_report.yml)
292
+ - **Feature request / improvement idea:** [request a feature](https://github.com/Netryon/BackupLint/issues/new?template=feature_request.yml)
293
+ - **Setup / usage question:** [ask a question](https://github.com/Netryon/BackupLint/issues/new?template=question.yml)
294
+ - **Security vulnerability:** use a [private GitHub Security Advisory](https://github.com/Netryon/BackupLint/security/advisories/new) — do **not** post secrets or vulnerability details in a public issue.
295
+
296
+ Before posting logs or configuration, remove passwords, tokens, private keys, internal hostnames/IPs, repository credentials, and personal data.
297
+
298
+ ## Development install
299
+
300
+ For contributors only (editable tree + test extras):
301
+
302
+ ```bash
303
+ git clone https://github.com/Netryon/BackupLint.git
304
+ cd BackupLint
305
+ python3 -m venv .venv
306
+ source .venv/bin/activate
307
+ pip install -e ".[dev]"
308
+ ruff check src tests
309
+ pytest -q tests/unit
310
+ ```
311
+
312
+ See [CONTRIBUTING.md](CONTRIBUTING.md).
313
+
314
+ ## License
315
+
316
+ [MIT](LICENSE) © 2026 BackupLint contributors.
317
+
318
+ [CONTRIBUTING.md](CONTRIBUTING.md) · [SECURITY.md](SECURITY.md)