Skip to content

Reinstall pre-fills the form with the previous install's non-secret answers - #805

Open
VijitSingh97 wants to merge 1 commit into
feat/phase2-bakery-imagefrom
feat/794-reinstall-prefill
Open

Reinstall pre-fills the form with the previous install's non-secret answers#805
VijitSingh97 wants to merge 1 commit into
feat/phase2-bakery-imagefrom
feat/794-reinstall-prefill

Conversation

@VijitSingh97

Copy link
Copy Markdown
Collaborator

Closes #794

On a fresh-start reinstall the operator re-answered everything the machine already knew, and a bench session lost its remote-Tari setting that way: the form defaulted Tari back to a local chain the operator never wanted.

What changes

Host side only (pithead, two functions beside the disk-installer helpers):

  • prefill_from_previous_install — when the published inventory holds exactly one disk in state pithead-with-data, mount its data partition read-only (-t ext4 -o ro,nosuid,nodev), read the previous pithead/config.json, strip the secrets, and publish the remainder as $spool/last-attempt.json — the exact channel the pre-seed path already fills and the state API already merges over the defaults. No container change, no frontend change, no second channel.
  • strip_config_secrets — every CONTROL_SECRET_PATHS leaf plus whole-object deletes for dashboard.auth, workers + the deprecated dashboard.workers (covers per-entry tokens in the variable-length list), telegram, healthchecks, notifications, ssh, and tari.spend_public_key. Wallet addresses, node modes/hosts, pool tier, timezone survive — the answers the operator came back for.

Fail open everywhere. No config, unreadable, oversized (>1 MiB), non-object JSON, ambiguous targets (two disks with data), failed mount, or a symlinked pithead//config.json (a crafted disk must not read the running host's files) — all mean the page opens blank and nothing blocks the install.

Fleet-stick hygiene. The pre-fill is derived fresh each installer boot: last-attempt.json is cleared before pre-seed/pre-fill runs, so machine 2 never opens on machine 1's answers. An operator pre-seed outranks the derived pre-fill. On wipe=keep nothing changes — the form collapses, no config crosses, and the pre-fill is left untouched.

Coverage (per docs/dev/testing-strategy.md tiers)

  • stack suite (host logic): strip covers every secret class via a single LEAK- marker sweep + keepers asserted; orchestration fail-open legs incl. both symlink-escape shapes. 1830 passed.
  • pytest server contracts: installer state serves a published pre-fill merged over defaults; broken pre-fill degrades to defaults with no error; keep submit leaves the pre-fill alone and writes only the install request. 63 passed.
  • KVM harness (tests/os/run.sh --phase install, reinstall leg): new assertions through the page's own state API — the first leg's wallet pre-fills, and no non-empty "password" appears in the state. Not runnable locally; lands with the next bench battery.

make lint green; dashboard coverage 96.55%, patch coverage 90%. Drive-by: ruff import sort in tests/service/test_data_service.py that was failing make lint on this branch.

The interplay with the upcoming role select is out of scope — this builds for today's form.

🤖 Generated with Claude Code

…ll's non-secret answers

On a fresh-start reinstall the operator re-answered everything the machine
already knew, and a bench session lost its remote-Tari setting that way: the
form defaulted Tari back to a local chain the operator never wanted.

The host (which already enumerates disks) now, when the inventory holds
exactly one disk carrying an install, mounts its data partition read-only,
reads the previous pithead/config.json, strips every secret and publishes the
remainder through the same last-attempt.json channel the pre-seed path fills.
The container never mounts anything; an operator pre-seed outranks the
derived pre-fill.

The strip (strip_config_secrets) removes every CONTROL_SECRET_PATHS leaf plus
the whole objects whose value is access: dashboard.auth, workers (and the
deprecated dashboard.workers), telegram, healthchecks, notifications, ssh,
and the view-key pair. Wallet addresses, node modes and hosts, the pool tier
survive — those are the answers the operator came back for.

Fail open everywhere: no config, unreadable, oversized, non-object JSON,
ambiguous targets (two disks with data), or a failed mount all mean the form
opens blank — nothing may block an install. Derived fresh each boot and
cleared first, so a fleet stick never carries machine 1's answers to
machine 2. On wipe=keep nothing changes: the survivor config wins and no
config crosses.

Coverage: stack-suite units for the strip (every secret class via one marker)
and the fail-open orchestration; wizard server contracts for pre-fill
serving, broken-pre-fill degradation, and keep leaving the pre-fill alone;
a KVM install-phase assertion (wallet pre-filled, no password in the state)
for the next bench battery. Drive-by: ruff import sort in
test_data_service.py that was failing make lint on the branch.

Closes #794

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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