Commit Graph

21 Commits

Author SHA1 Message Date
dillard c38cc47534 Release 0.9.6-beta.7 2026-10-14 13:14:46 +02:00
dillard dfd3f38d8c Backups to SMB no longer crawl; add occ backup:cancel
Each 30-second step opened the location again and read its list of
index files. Over SMB that cost a request per file, so on a large
repository opening took longer than the step: each step stored one
4 MiB pack and the list grew further. A first backup of nc01 to a
Storage Box over SMB managed 12 GiB in 35 hours.

occ backup:run and system cron now keep the repository open for the
whole run (reopened when another process took a step or the location
was edited), opening no longer counts towards the step's time, and
SMB folders are listed in one request.

occ backup:cancel stops a running backup: no new step starts and the
step in progress finishes first. A run of an earlier version, which
does not hold back its next step, is marked cancelled after two
minutes unless it is recording its snapshot.
2026-10-14 12:15:27 +02:00
dillard 8ed7455619 Release 0.9.5-beta.6 2026-10-12 14:27:39 +02:00
dillard c146d700e8 Merge branch 'main' into polish 2026-10-11 13:25:06 +02:00
dillard fe92ef70bf Release 0.9.4-beta.5 2026-10-09 11:58:52 +02:00
dillard bcfec17cfe README: WebDAV request timeout on slow uploads; deep verify no longer fetches per blob 2026-10-08 22:38:32 +02:00
dillard 65f14b4380 Merge branch 'main' into polish
# Conflicts:
#	CHANGELOG.md
2026-10-08 21:19:34 +02:00
dillard f4abfe0a8d Release 0.9.3-beta.4 2026-10-08 20:46:14 +02:00
dillard 9775cdc475 Locations: edit connection settings without losing the history
A changed password or host name could only be handled by adding a new
location, which starts an empty repository and, with a retention lock at
the provider, keeps the old one billed. Edit now changes a location in
place (web interface and occ backup:target:edit). The settings are only
saved when they lead to the same repository; a failed connection and a
missing repository give separate errors, and the folder is not created
while checking. Stored passwords are never sent to the browser: an empty
password field keeps the stored value.
2026-10-08 12:56:15 +02:00
dillard f415bab519 Verify, README: address review notes
An unreadable blob may still be a truncated pack, so don't rule out damage
in the verify message; README: Hetzner needs WebDAV/SMB and external
reachability enabled for the sub-account.
2026-10-08 01:11:21 +02:00
dillard 27eb0b32fc Release 0.9.2-beta.3 2026-10-08 01:00:52 +02:00
dillard b1d4f6a469 README: Hetzner Storage Box over WebDAV and SMB
Tested both on sub-accounts: works end to end; WebDAV needs an existing
root, SMB needs port 445 and the smbclient extension; fixed cost per run
and slow deep verify over remote storage.
2026-10-08 01:00:46 +02:00
dillard 8b2dca28e3 Release 0.9.1-beta.2 2026-10-07 17:47:40 +02:00
dillard 0eb23f56e7 README: note that key rotation for revoking old kits is on the backlog 2026-10-07 02:18:45 +02:00
dillard b89b5b5fa6 Document known limitations for the beta and record the review backlog
CI / unit (8.2) (push) Has been cancelled
CI / unit (8.3) (push) Has been cancelled
CI / unit (8.4) (push) Has been cancelled
CI / psalm (push) Has been cancelled
CI / integration (mariadb, 32) (push) Has been cancelled
CI / integration (mariadb, 33) (push) Has been cancelled
CI / integration (mariadb, 34) (push) Has been cancelled
CI / integration (mariadb, 35) (push) Has been cancelled
CI / integration (pgsql, 32) (push) Has been cancelled
CI / integration (pgsql, 33) (push) Has been cancelled
CI / integration (pgsql, 34) (push) Has been cancelled
CI / integration (pgsql, 35) (push) Has been cancelled
CI / integration (sqlite, 32) (push) Has been cancelled
CI / integration (sqlite, 33) (push) Has been cancelled
CI / integration (sqlite, 34) (push) Has been cancelled
CI / integration (sqlite, 35) (push) Has been cancelled
CI / integration-targets (push) Has been cancelled
CI / integration-user (32) (push) Has been cancelled
CI / integration-user (33) (push) Has been cancelled
CI / integration-user (34) (push) Has been cancelled
CI / integration-user (35) (push) Has been cancelled
CI / integration-full-restore (push) Has been cancelled
The open points from the pre-beta review are on the backlog in PLAN.md and
listed as known limitations in the README; none block 0.9.0-beta or 1.0.0.
The how-to warns against pointing a test server at a live location and
explains that removing a slot does not revoke access.
2026-10-07 00:19:46 +02:00
dillard 943c95bf07 Ask before installing user_migration; add the beta how-to
backup:user:backup and backup:user:restore now ask the administrator before
installing or enabling user_migration (or take --install-user-migration), so
nothing changes on the server without consent. The restore warns that
user_migration imports only its allowlisted app settings.

Also: a clear error for unknown locations instead of a raw database message;
prune reports the number of affected users, not the number of kept ones; and
--user-last rejects values that are not whole numbers. Adds docs/HOWTO.md and
updates the README and PLAN.md for the beta.
2026-10-06 16:57:56 +02:00
dillard 932f60bc5e Phase 2: FTP, SMB and NFS storage backends
CI / unit (8.2) (push) Has been cancelled
CI / unit (8.3) (push) Has been cancelled
CI / unit (8.4) (push) Has been cancelled
CI / psalm (push) Has been cancelled
CI / integration (mariadb, 32) (push) Has been cancelled
CI / integration (mariadb, 33) (push) Has been cancelled
CI / integration (mariadb, 34) (push) Has been cancelled
CI / integration (mariadb, 35) (push) Has been cancelled
CI / integration (pgsql, 32) (push) Has been cancelled
CI / integration (pgsql, 33) (push) Has been cancelled
CI / integration (pgsql, 34) (push) Has been cancelled
CI / integration (pgsql, 35) (push) Has been cancelled
CI / integration (sqlite, 32) (push) Has been cancelled
CI / integration (sqlite, 33) (push) Has been cancelled
CI / integration (sqlite, 34) (push) Has been cancelled
CI / integration (sqlite, 35) (push) Has been cancelled
CI / integration-targets (push) Has been cancelled
CI / integration-user (push) Has been cancelled
CI / integration-full-restore (push) Has been cancelled
No ng_backup code changes needed: files_external's generic backend/auth adapter (the same
ExternalStorageFactory/StorageBackend already used for S3/SFTP) already covers FTP and SMB, and
NFS was never a files_external backend to begin with (PLAN.md 3.5) -- the "local" backend plus an
admin-managed OS-level mount already does the job. This commit is test coverage and documentation.

tests/integration/targets-matrix.sh now also runs the full round trip against:
- FTP (stilliard/pure-ftpd). A first attempt with delfer/alpine-ftp-server (vsftpd) failed with a
  generic "create directory operation failed": files_external's FTP backend always builds
  absolute paths, which that server's chroot rejects even via plain php ftp_mkdir() with an
  absolute path (a relative path on the same server works fine) -- not a files_external or
  ng_backup bug, just a server-specific quirk, confirmed by switching test servers.
- SMB (dperson/samba), via a small Nextcloud image built on the fly with the smbclient PECL
  extension (libsmbclient-dev + pecl install), in its own temp directory as the build context
  (never /tmp directly). The backend *lists* as available with just the smbclient CLI binary too
  (files_external's shell-wrapped fallback), but that fallback's stream cannot seek, and ng_backup
  reads blobs back by byte range while backing up -- confirmed live, it fails the very first
  (small) backup with "Seek failed in packs/...". The native extension is genuinely required here,
  not just preferred.

README: new "Storage backend experiences" entries for both findings (and a pointer from the
"no extra PHP extensions" intro line, since SMB is the one real exception), plus NFS guidance
(mount it yourself, point the local backend at the mount point).

PLAN.md: FTP/SMB marked done; SMB/NFS testing on the user's own OMV instance stays open (internal,
not something CI can cover).

Local review (Codex + CodeRabbit) found three issues, all fixed: the README's first-pass SMB claim
("CLI tool is not enough") was imprecise about *why* -- it lists fine without the extension, it
just doesn't work for ng_backup's read pattern; the cleanup trap could abort before removing the
network if an earlier docker rm failed, and didn't remove the built image/Dockerfile; and the
Docker build used all of /tmp as its context instead of a dedicated directory.
2026-10-06 00:31:29 +02:00
dillard e7229626f8 Prepare the 0.1.0-alpha.1 release
CI / unit (8.2) (push) Has been cancelled
CI / unit (8.3) (push) Has been cancelled
CI / unit (8.4) (push) Has been cancelled
CI / psalm (push) Has been cancelled
CI / integration (mariadb, 32) (push) Has been cancelled
CI / integration (mariadb, 33) (push) Has been cancelled
CI / integration (mariadb, 34) (push) Has been cancelled
CI / integration (mariadb, 35) (push) Has been cancelled
CI / integration (pgsql, 32) (push) Has been cancelled
CI / integration (pgsql, 33) (push) Has been cancelled
CI / integration (pgsql, 34) (push) Has been cancelled
CI / integration (pgsql, 35) (push) Has been cancelled
CI / integration (sqlite, 32) (push) Has been cancelled
CI / integration (sqlite, 33) (push) Has been cancelled
CI / integration (sqlite, 34) (push) Has been cancelled
CI / integration (sqlite, 35) (push) Has been cancelled
CI / integration-targets (push) Has been cancelled
info.xml's version field is restricted by Nextcloud's own info.xsd to plain
numeric SemVer, no pre-release suffix, so the alpha/beta/rc stage from
PLAN.md's release table lives in the git tag and CHANGELOG instead; noted
that in PLAN.md so it isn't rediscovered later. Bumped the version, wrote
an honest description for an alpha (feature-complete for phase 1, not for
production), and added CHANGELOG.md.

README: new "Storage backend experiences" section, seeded with the Hetzner
Storage Box sub-account root-path quirk found while testing a real SFTP
target (root must be "home", not "/"), open for others to extend via PR.
2026-10-05 11:45:48 +02:00
dillard 131bb6178d Close remaining review gaps
- restore runs from the web are created under the location's exclusive
  lock, like backup runs
- raw restore writes to an unpredictable temporary name opened with
  exclusive create (never follows a planted symlink) and validates the
  path prefix; the restore service rejects non-canonical paths instead
  of trimming them (occ normalises user input before calling it)
- restore jobs report progress every minute, so a long restore is not
  taken for a dead one
- README: Object Lock turns deletions into delete markers
2026-10-02 11:25:22 +02:00
dillard d3aa07b106 M5: deletion delay with trash, passphrase slots, ransomware documentation
- removed snapshots go to a trash on the location and their data is only
  freed after the deletion delay, which is chosen when the key is created
  (default 7 days, 1-365) and cannot be changed afterwards; any admin can
  bring them back (occ backup:trash, backup:trash:restore, web UI)
- up to three passphrase slots open the same master key (like LUKS), so
  one person leaving or dying does not lock the company out; slot changes
  are written to every location, announced to all admins and require a
  new recovery kit confirmation, while backups keep running
- occ backup:key:slots, backup:key:slot:add|replace|remove; key init takes
  --label and --delete-delay-days
- web UI: deletion delay and first slot at key creation, slot management,
  trash per location with restore; all behind password confirmation
- README: key, slots (safe / CTO / head of IT), and protection against
  ransomware: object lock in compliance mode (e.g. 90 days), credentials
  without delete rights, provider snapshots, off-site copy
2026-10-02 03:01:44 +02:00
dillard 07e3d263b4 Phase 0: skeleton, streaming encryption (spike A)
Repository skeleton (app id ng_backup, AGPL-3.0-or-later), KeyRing with
KDF subkeys, keyed blob ids and Argon2id key wrapping, and StreamCipher
(secretstream XChaCha20-Poly1305, framed, bounded memory).

Spike A: 1 GiB round trip with memory_limit=64M, peak < 2 MiB, ~160/122
MiB/s; tampering, truncation, wrong key/passphrase are rejected.
2026-10-01 18:15:24 +02:00