Add unit tests for osism.utils.ssh#2350
Merged
Merged
Conversation
6b7deaa to
1de3e94
Compare
ideaship
requested changes
Jul 3, 2026
Add tests/unit/utils/test_ssh.py covering every function in osism/utils/ssh.py: - ensure_known_hosts_file: existing dir/file, directory and file creation, PermissionError/OSError/catch-all branches, and a custom path argument - get_host_identifiers: DNS resolution, gaierror, NetBox fallback with primary_ip4 prefix stripping, missing and raising NetBox lookups, and de-duplication of DNS/NetBox IPs - remove_known_hosts_entries: empty hostname, missing file, empty and raising identifier lookups, ssh-keygen success/no-op/non-zero exit, TimeoutExpired, CalledProcessError and generic errors, mixed multi-host results, and empty-identifier skipping - backup_known_hosts: empty/missing/unreadable path, missing and unwritable backup directory, happy path, post-copy verification, and PermissionError/OSError/catch-all copy failures - cleanup_ssh_known_hosts_for_node: backup success and None, the create_backup toggle, and failure/exception propagation Tests use pytest-mock and the shared loguru_logs fixture, mirroring the conventions in tests/unit/utils. Because socket, shutil and datetime are imported inside the functions under test, socket.gethostbyname and shutil.copy2 are patched on their real modules and the timestamped backup path is asserted via a regular expression. Part of #2199. Implements #2231. Assisted-by: Claude:anthropic-opus-4-8 Signed-off-by: Christian Berendt <berendt@osism.tech>
ssh-keygen -R returns 0 even when the host is absent from the file, and the non-existent-file case is short-circuited before ssh-keygen runs. A non-zero exit therefore signals a genuine failure such as a corrupt or unreadable known_hosts, in which case a stale host key may survive and must not be reported as a successful cleanup. Assisted-by: Claude:claude-opus-4-8 Signed-off-by: Christian Berendt <berendt@osism.tech>
1de3e94 to
f38f9be
Compare
ideaship
approved these changes
Jul 3, 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.
Summary
Implements #2231. Adds
tests/unit/utils/test_ssh.py, a single cohesivetest module covering every function in
osism/utils/ssh.py(SSHknown_hostsmaintenance for reset/undeploy flows). No production code ischanged.
Part of the Tier 4 testing effort (#2199); follow-up to #2192 / #2193.
Change set (single commit)
Add unit tests for osism.utils.ssh— adds 44 test functions groupedby the function under test:
ssh.py)ensure_known_hosts_fileos.makedirs(..., mode=0o755, exist_ok=True), missing file →open(path,"a")+os.chmod(path,0o644),PermissionError/OSError/catch-all branches, custom path propagationget_host_identifierssocket.gaierror,utils.nb is None, NetBoxprimary_ip4with prefix stripped, deviceNone, NetBox lookup raises (no propagation), same IP from DNS+NetBox de-duplicated, list always starts with hostnameremove_known_hosts_entriesTrue, empty identifiers →False, lookup raises,ssh-keygensuccess (updated/ identifier-in-stderr / neither), non-zero exit continues,TimeoutExpired/CalledProcessError/generic →success=False, multi-host one-timeout, empty-identifier skip, success/empty final logsbackup_known_hostsshutil.copy2+ path regex), post-copyexists/getsizeverification,PermissionError/OSError/catch-all copy failurescleanup_ssh_known_hosts_for_nodeNone(cleanup still runs),create_backup=False, remove returnsFalse, remove raises (caught) — always usesKNOWN_HOSTS_PATHNotes for the reviewer
pytest-mock(mocker) and the sharedloguru_logsfixturefrom
tests/conftest.py, matching the existingtests/unit/utilsstyle.socket,shutilanddatetimeare imported inside the functionsunder test. The issue's hint to patch
osism.utils.ssh.datetime.datetimecannot resolve (no module-level
datetimeattribute), so the timestampedbackup path is asserted with a regular expression instead — the
alternative the issue explicitly allows. For the same reason
socket.gethostbynameandshutil.copy2are patched on their realmodules;
utils.nbis patched viaosism.utils.ssh.utils.nb(
create=True), mirroringtests/unit/tasks/conductor/test_netbox.py.Verification
black --check,flake8(repo config): clean on the new file.mypy: no type errors in the test logic (local run reports onlythird-party
import-not-foundnotes, which resolve inside the CI venv).ssh.pyshows every executable line is exercised,comfortably above the ≥95 % target.
pytest/coverage left to the Zuulpython-osism-unit-testsjob.Closes #2231.
Assisted-by: Claude:anthropic-opus-4-8