Skip to content

feat(appliance): two-tier reset + wedged-/data recovery - #862

Merged
VijitSingh97 merged 3 commits into
develop-v2from
fix/849-factory-reset
Aug 3, 2026
Merged

feat(appliance): two-tier reset + wedged-/data recovery#862
VijitSingh97 merged 3 commits into
develop-v2from
fix/849-factory-reset

Conversation

@VijitSingh97

Copy link
Copy Markdown
Collaborator

Two-tier reset + wedged-/data recovery

Closes #849. The appliance had neither reset tier and no way back from a corrupt /data on 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. Removes config.json and the files rendered from it (.env, Caddyfile), which re-arms the first-boot wizard (pithead-firstboot's ConditionPathExists=!config.json) and stands pithead-boot down. 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 stays uninstall). /data can't be reformatted while it's mounted (it holds the container store and the /var overlay'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 before data.mount. It's both the factory-reset executor and the recovery path. It reformats /data (and reseeds the dirs systemd-repart would — the /var overlay's upper/work) in exactly two cases:

  1. the factory-reset marker is present on the ESP, or
  2. the partition is unmountable even after an fsck -p repair.

Fail-safe guards (the load-bearing part):

  • A partition that mounts cleanly with no marker is never touched — the default verdict is skip.
  • Unmountable is not enough on its own: fsck -p runs 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.
  • If the boot disk's data partition can't be resolved, or isn't a block device yet (first boot), it does nothing.

Appliance surface

Console is the surfaced path today (root login at the console with the dashboard password — the resets are the appliance's uninstall equivalent). 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):

  • config-reset: preserves the chain + onion key, removes config/.env/Caddyfile, reboots only on the appliance, refuses when already unprovisioned, type-to-confirm.
  • factory-reset: appliance-only refusal, battery assertion that it arms the ESP marker and reboots, refuses when the ESP marker can't be written (and then does not reboot), type-to-confirm.
  • data_reset_decision unit: healthy→skip, wedged→reformat, fsck-repaired→skip, marker→reformat-requested.

🤖 Generated with Claude Code

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>
…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>
@VijitSingh97
VijitSingh97 merged commit 5324fb7 into develop-v2 Aug 3, 2026
16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant