WolfStack v25.20.0
v25.20.0: backup retention actually prunes a PBS datastore, and a failing backup finally tells you
Retention did nothing at all on PBS. delete_backup_file() carried
StorageType::Pbs => {} on the assumption that PBS reclaims space via its own
prune + garbage-collect schedule. That holds for a self-managed PBS where the
operator configured a prune job, and is simply false for a hosted datastore
that has none: retention: 7 trimmed only WolfStack's own index, so the UI
showed 7 while the datastore kept every snapshot ever written. A four-node
fleet on retention 7 was found holding 15-19 snapshots per group across 18
days, having filled a 2 TB datastore to 100% and failed every backup for the
previous 8 days. Retention now prunes the groups a schedule owns.
Retention was also counted per SCHEDULE rather than per target, so a schedule
covering 11 containers with retention 7 kept 7 records in total and could not
hold even one complete night — the surviving set was 3 containers from one
night plus 4 from the night before, the rest already deleted. It is now per
target: keep 7 means seven backups of each thing.
A failing backup was invisible. last_run is stamped even when every target in
the run fails, so backup_stale stayed silent for 8 days while the fleet had no
backups at all. The new backup_failed finding reads the per-target status and
error that backups.json was already recording, and fires Critical when a whole
run failed, High when it partly failed.
Every node wrote its config backup as the literal config-wolfstack-.tar.gz,
which maps to the backup-id "wolfstack" — so every node in a fleet shared the
single PBS group host/wolfstack (67 snapshots from four machines). That makes a
restore ambiguous and per-group retention destructive. The archive path now
scopes the id by hostname, as the file-level path already did. Where two
schedules still share a group, the group keeps the largest retention any of
them asks for rather than letting the stricter one delete the looser one's
snapshots.
Store and restore had drifted on how they derive a PBS backup type: Docker
archives were written as "ct" and looked up as "host", so a Docker PBS backup
could not be restored. Both now use one helper.
Note that PBS prune unlinks snapshot indexes; space returns only when garbage
collection runs, which on a hosted datastore is often the provider's job and
not permitted to a backup token.
Co-Authored-By: CodeWolf paul@wolf.uk.com
Co-Authored-By: Wolf Software Systems Ltd paul@wolf.uk.com
Verifying this release
Each binary is signed via cosign keyless OIDC (no key distribution — signing identity is the GitHub Actions workflow itself, anchored to the Sigstore Fulcio CA and the Rekor transparency log) and ships with a SLSA build provenance attestation.
Verify the cosign signature:
cosign verify-blob \
--bundle wolfstack-x86_64.cosign.bundle \
--certificate-identity-regexp 'https://github.com/wolfsoftwaresystemsltd/WolfStack/\.github/workflows/release\.yml@.*' \
--certificate-oidc-issuer 'https://token.actions.githubusercontent.com' \
wolfstack-x86_64
Verify the build provenance:
gh attestation verify wolfstack-x86_64 --repo wolfsoftwaresystemsltd/WolfStack
Verify the SHA-256 checksum:
sha256sum -c SHA256SUMS
Artifacts
wolfstack-x86_64/wolfstack-aarch64/wolfstack-armv7— static musl binaries (Linux x86_64, ARM64 / Raspberry Pi 4+, and 32-bit ARM).wolfstack-<arch>.cosign.bundle— cosign signature bundle (cert + signature + Rekor entry).SHA256SUMS— checksums for both binaries.
For per-version history see CHANGELOG.md.