Repository navigation
WolfStack v24.7.28
v24.7.28: WolfRouter — auto-recover from "trailing characters" torn write
klasSponsor escalation (Discord 2026-05-27): every node in his 14-node
cluster stuck in WolfRouter recovery mode after upgrade, with parse
error "trailing characters at line 50 column 1" and only the just-
quarantined .broken-* snapshot listed — no .bak.* rolling backups to
fall back to.
Diagnosis: the corruption pre-dated v24.7.8 (which introduced unique
tmp-suffix saves to prevent future torn writes), so the rolling-
backup chain never started. v24.7.9's auto-recovery had nothing to
adopt. Operator was stuck with manual recovery on every node — exactly
the failure mode v24.7.9 was meant to retire.
Insight: a torn-write config has the more-recent writer's COMPLETE
JSON value at the start of the file, followed by stale bytes from the
earlier writer. The operator's real config IS in the file, just
followed by garbage. serde_json::Deserializer's streaming iterator
parses the first complete value and reports byte_offset() at its end
— anything after is the trailing junk we discard.
New self-heal step runs BEFORE the rolling-backup walk:
- Naive parse fails with "trailing characters at line N column 1".
- Stream-parse the first complete RouterConfig value; if it parses,
stripping the trailing bytes is safe (we know exactly where the
first value ended). - Write the cleaned bytes back to disk via unique-suffix tmp +
atomic rename so the next restart loads cleanly without re-
running this recovery. - Surface the action as a RecoveredFromTornWrite outcome (same UI
banner shape as AutoRecovered) so the operator can audit.
Safety: we only attempt this when the serde error contains
"trailing characters". Any other parse error (missing field, type
mismatch, unknown enum variant) falls through to the rolling-backup
recovery — the trailing-garbage parser would happily eat a struct-
incompatible config and pretend it succeeded, which is the silent-
wipe failure mode v24.7.0 was added to prevent.
klas's cluster: restart wolfstack on each node and the configs self-
heal. Original (full) file preserved as config.json.broken-* for
forensics.
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— static musl binaries (Linux x86_64 and ARM64 / Raspberry Pi 4+).wolfstack-<arch>.cosign.bundle— cosign signature bundle (cert + signature + Rekor entry).SHA256SUMS— checksums for both binaries.
For per-version history see CHANGELOG.md.