[1.4] core: services: commander: Keep .ssh keys on settings reset (backport #3677 + fix) - #4120
Merged
patrickelectric merged 4 commits intoAug 11, 2026
Conversation
joaoantoniocardoso
force-pushed
the
fix/1.4-reset-settings-preserve-ssh-keys
branch
from
August 11, 2026 18:43
6e6f9df to
2b24e07
Compare
Automated PR Review0. Summary
Backports #3677 to No further comments, nice job 👍 Generated by PR Review Bot. This is advisory, a human reviewer must still approve. |
Signed-off-by: Patrick José Pereira <patrickelectric@gmail.com> (cherry picked from commit 3bdec9b)
joaoantoniocardoso
force-pushed
the
fix/1.4-reset-settings-preserve-ssh-keys
branch
from
August 11, 2026 18:53
2b24e07 to
f83d4f9
Compare
joaoantoniocardoso
marked this pull request as draft
August 11, 2026 18:59
Signed-off-by: Patrick José Pereira <patrickelectric@gmail.com> (cherry picked from commit ee1f27f)
joaoantoniocardoso
force-pushed
the
fix/1.4-reset-settings-preserve-ssh-keys
branch
from
August 11, 2026 19:01
f83d4f9 to
768ae7e
Compare
joaoantoniocardoso
marked this pull request as ready for review
August 11, 2026 19:05
4 tasks
Importing general.py in the new test_general.py pulled general.py and commands.py into the coverage measurement for the first time, dropping total coverage below the 75% gate (72.43% in CI). Cover the remaining general.py helpers (host OS detection, file deletion, lsof-based open checks, local identifiers, device id) to clear the gate. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> (cherry picked from commit eb85a93)
Reset Settings wiped /root/.config/.ssh, which holds the keypair used to run commands on the host. Without it every host command falls back to sshpass with the default password, breaking every commander feature on vehicles where that password was changed.
joaoantoniocardoso
force-pushed
the
fix/1.4-reset-settings-preserve-ssh-keys
branch
from
August 11, 2026 19:15
768ae7e to
3998b45
Compare
patrickelectric
approved these changes
Aug 11, 2026
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.
Fixes #3440
Backport of #3677 plus the
.sshfix on top.Problem
Reset Settingsdeletes everything under/root/.config. On 1.4 it only rescuesbootstrap/startup.jsonafterwards, so everything else goes, including:/root/.config/.ssh— the keypair commander uses to run commands on the host. Once it is gone,run_command()falls back tosshpasswith the default password (SSH_USER/SSH_PASSWORD), so every commander-backed feature breaks on any vehicle where the default password was changed, and a reboot does not recover it.ardupilot-manager,bag-of-holdingandkraken— which is why a reset followed by a reboot leaves a vehicle with installed extensions in a broken state (see the discussion in The Restart Settings is removing the default ssh keys #3440).Master already fixed the second half in #3677, which was never backported.
Changes
delete_everything(path, ignore=[...]), so callers can protect paths that must survive a wipe. Conflict resolution keeps 1.4's.gzhandling.ardupilot-manager,bag-of-holding,bootstrapandkrakeninstead of copyingstartup.jsonthrough/tmp.commonwealth.utils.general, which is where theignorebehaviour is tested. 1.4 has notest_general.py, so the file is created at 1.4's path. Three tests are dropped because they target helpers that only exist on master (_file_is_open_logic_lsof,_file_is_open_command,file_is_open_async), andtest_delete_everything_streamno longer holds the.gzfile open, because on 1.4 the.gzspecial case lives indelete_everythingrather than indelete_everything_stream. Thetest_get_cpu_typeblock is not included: it comes from 1a9bde2, which also changes Compute Module detection and is unrelated to this PR./root/.config/.sshto the ignore list.After this, 1.4's
reset_settingsis identical to master's apart from the.sshentry, which is the same change proposed in #4122 — so the two branches converge instead of diverging.Preserving is used instead of regenerating so the key is never absent, and the private key never has to be copied through
/tmp. The public half in/home/pi/.ssh/authorized_keyswas never removed by reset anyway, so deleting the private key only ever broke auth while leaving a stale entry behind.Complements #3898, which adds the recovery path (
setup_ssh()on startup) — this PR stops the key from being destroyed in the first place.Test plan
Verified on a Raspberry Pi running
1.4.4-beta.15, by running this code in the container:POST /commander/v1.0/settings/resetleaves/root/.config/.sshempty, and the next host command logsFailed to run command with SSH key ... trying with sshpassssh -i /root/.config/.ssh/id_rsa(no fallback)ardupilot-manager,bag-of-holding,bootstrapandkrakenall survive the reset, andbootstrap/startup.jsonis still present/root/.config/beaconis deletedpytest core/libs/commonwealth/commonwealth/utils/tests/passes (21 tests)./.hooks/pre-pushreports the exact same 44 pre-existing failures as a pristine1.4-devcheckout — no new ones