Repository navigation
Conversation
The post-restore examiner password check never ran. `vhir restore` called
verify_password(examiner, pw) while the function signature is
verify_password(config_path, analyst, password), so every prompt raised
TypeError: verify_password() missing 1 required positional argument:
'password'. The catch-all `except (ImportError, Exception): pass` swallowed
it, so the operator typed a password, saw nothing, and believed HMAC
verification had been confirmed. A wrong or unmatched password only
surfaced much later during `vhir review --findings --verify`.
Pass the config path as the first argument, matching every other call site
(approval_auth.require_confirmation, reset_password) and the sibling
convention `Path.home() / ".vhir" / "config.yaml"` used in approve.py,
reject.py, review.py and config.py. The except clause is split so only
ImportError is silent (approval_auth genuinely absent); any other failure
is reported in the same " <step>... FAILED: {e}" form the surrounding
restore steps already use, so a regression here can no longer hide, while
the restore still completes.
tests/test_backup_restore_password.py drives the real
approval_auth.verify_password against a real password entry in a temp
passwords dir: one test asserts the matching password prints "Password
correct.", the other asserts a wrong password prints the mismatch warning.
Both fail on the unmodified source, which prints only the header line and
returns silently.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…password-config-path
This branch has not been deployed
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.
BLUF
verify_password(examiner, pw)is a 2-argument call to a 3-argument function (verify_password(config_path, analyst, password)); the resultingTypeErrorwas eaten byexcept (ImportError, Exception): pass.vhir restorethat restored a password hash for the current examiner. The real HMAC verification invhir review --findings --verifyis unaffected, so a wrong password is still caught — just much later.main@b2324ac(2026-10-05): the bug is still present — this PR's new tests, applied tomainwithout the fix, still fail (2 failed). The branch now hasmainmerged in.Priority: MEDIUM
Defect
src/vhir_cli/commands/backup.py:1145calls the password verifier with two arguments:but the function takes three positional parameters (
src/vhir_cli/approval_auth.py:249):So every prompt raises
TypeError: verify_password() missing 1 required positional argument: 'password', andexcept (ImportError, Exception)— which is justexcept Exception— swallows it.Why it is wrong
On a TTY restore where the examiner's password hash was restored, the operator sees:
types a password, and the command moves straight on to the OpenSearch restore with no confirmation, no mismatch warning, and no error. The absence of a warning reads as success. The whole point of the prompt — telling the operator now, while the original password is still fresh, that HMAC verification will work — is lost. A wrong or unmatched password only surfaces much later during
vhir review --findings --verify, by which time the "runvhir config --setup-password" advice the prompt would have given is far less actionable.Consistency with sibling code
Every other call site passes the config path first:
approval_auth.require_confirmation(approval_auth.py:192) andapproval_auth.reset_password(approval_auth.py:336). The command layer resolves it the same way everywhere —config_path = Path.home() / ".vhir" / "config.yaml"inapprove.py:48,reject.py:28,review.py:369andconfig.py:15. This change simply makesbackup.pyfollow that convention.Fix
The catch-all is split rather than removed. Only
ImportErrorstays silent, which is the case the comment actually describes. Anything else is now reported in the same" <step>... FAILED: {e}"form the surrounding restore steps already use (" Password hash ({examiner_name})... FAILED: {e}"," OpenSearch restore... FAILED: {e}"). Letting the exception propagate instead would abort the remaining OpenSearch restore, ledger restore and the case-activation banner, all of which run after this point — so a visible warning is the right trade, and a future regression of this kind can no longer hide.Testing
tests/test_backup_restore_password.pydrives the realapproval_auth.verify_password— not a fake — against a real PBKDF2 password entry written into a temp passwords directory, which is exactly the state a restore leaves behind. Because the real function is the driver, the test checks the arity against the actual signature rather than against an assumption baked into a mock.test_correct_password_is_confirmed— a matching password printsPassword correct.test_wrong_password_reports_mismatch— a non-matching password prints the mismatch warning instead of returning silently.Both fail on the unmodified source, with the function producing nothing but its header line:
Full suite: 430 passed on Python 3.10 and 3.12 (428 baseline + 2 new).
ruff check .andruff format --check .clean.CI status
The checks on this PR will show
action_required: GitHub gates workflow runs on pull requests fromfirst-time fork contributors until a maintainer approves them. They need an Approve and run click.
The CI job was reproduced locally after merging
main@b2324ac(761 tests onmain), using the same steps as.github/workflows/ci.yml:pip install -e ".[dev]" && pytest tests/— Python 3.10pip install -e ".[dev]" && pytest tests/— Python 3.11pip install -e ".[dev]" && pytest tests/— Python 3.12ruff check .+ruff format --check .(latest ruff, unpinned as in CI)🤖 Generated with Claude Code