feat(appliance): two-tier reset + wedged-/data recovery - #862
Merged
Conversation
The appliance had no factory-reset or config-reset and no way back from a corrupt /data on a shell-less release image. Add both reset tiers as host-CLI commands and a boot-time recovery path. - config-reset: clear config.json + rendered files, re-arm the first-boot wizard, keep every data dir (chains, wallets, Tor onion keys, dashboard history). Reconfigure with no resync; the onion address survives. - factory-reset (appliance only): arm an ESP marker and reboot; pithead-data-reset reformats /data before it mounts, then the box comes up blank into the wizard. /data cannot be reformatted while mounted, so the wipe runs one layer down. - pithead-data-reset.service: the marker executor AND wedged-/data recovery — reformats /data before mount on an explicit request or when the partition is unmountable even after fsck. Fail-safe: a healthy, unmarked partition is never touched; fsck runs first so a dirty fs is repaired, not erased. Console is the surfaced appliance path (root login + dashboard password); a dashboard/removable-media trigger depends on the shell-less-parity work. Tests: stack-tier black-box for both commands (config-reset preserves chains, factory-reset arms-and-reboots, both gated by type-to-confirm, appliance-only guard) and a unit test for the reformat-vs-skip decision (healthy -> skip, wedged -> reformat, fsck-repaired -> skip). Closes #849 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
# Conflicts: # os/rootfs/Dockerfile
5 tasks
…ed-/data recovery data_reset_decision's STDOUT is its verdict, captured by the caller with $(...). log() wrote to stdout, so on the fsck path the captured value became the progress line PLUS the verdict, matched no case branch, and the recovery reformat silently never ran — a wedged box would stay wedged. Fails safe (never a wrong wipe) but the whole recovery half of the feature was dead. CI caught it; a local run had reported clean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two-tier reset + wedged-/data recovery
Closes #849. The appliance had neither reset tier and no way back from a corrupt
/dataon a shell-less release image (root login locked). This adds both tiers as host-CLI commands plus a boot-time recovery path.The two commands
pithead config-reset [-y]— the cheap tier. Removesconfig.jsonand the files rendered from it (.env,Caddyfile), which re-arms the first-boot wizard (pithead-firstboot'sConditionPathExists=!config.json) and standspithead-bootdown. Every data directory stays — chains, wallets, Tor onion keys, dashboard history — so reconfiguring costs no resync and the onion address survives. On the appliance it reboots into setup; elsewhere it prints how to reconfigure.pithead factory-reset [-y]— the deep tier, appliance-only (a normal install's clean exit staysuninstall)./datacan't be reformatted while it's mounted (it holds the container store and the/varoverlay's upper/work dirs), so the wipe runs one layer down: it arms a marker on the ESP (which survives the wipe) and reboots.Both are type-to-confirm unless
-y.Wedged-/data recovery
New early-boot unit
pithead-data-reset.service+ script, ordered beforedata.mount. It's both the factory-reset executor and the recovery path. It reformats/data(and reseeds the dirssystemd-repartwould — the/varoverlay's upper/work) in exactly two cases:fsck -prepair.Fail-safe guards (the load-bearing part):
skip.fsck -pruns first and we retry, so a merely dirty/transient fs is repaired, not erased. Only a genuinely unrecoverable partition is reformatted — and the alternative there is a bricked, shell-less box.Appliance surface
Console is the surfaced path today (root login at the console with the dashboard password — the resets are the appliance's
uninstallequivalent). A dashboard-button / removable-media trigger depends on the shell-less-parity work in #786 and is out of scope here.Tests
Stack-tier (
tests/stack/run.sh, docker/sudo/reboot stubbed):.env/Caddyfile, reboots only on the appliance, refuses when already unprovisioned, type-to-confirm.data_reset_decisionunit: healthy→skip, wedged→reformat, fsck-repaired→skip, marker→reformat-requested.🤖 Generated with Claude Code