Treat an empty password as valid, distinct from unset - #17
Merged
Conversation
Some Vector boards have no password configured, which the firmware authenticates by signing with an empty-string HMAC key. The client conflated an empty password with "no password set": the Machine.password property coerced "" to the $VECTOR_PASSWORD fallback, and both the auth preflight and the HTTP transport rejected a falsy password outright, so an empty password could never be used. Distinguish None (unset — still falls back to the environment and raises AuthenticationRequiredError when nothing is configured) from "" (a valid empty password that is signed as such): - Machine.password returns an explicitly-set empty string instead of the env fallback; only None falls back. - Machine._preflight_auth and HttpTransport._send guard on `is None` rather than falsiness. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014Y49XvgGpmTHrYLDeTvmbA
Coverage report✅ Total coverage: 100.00% (0.00% vs base |
mullinmax
marked this pull request as ready for review
July 18, 2026 20:19
mullinmax
added a commit
that referenced
this pull request
Jul 18, 2026
* Treat an empty password as valid, distinct from unset Some Vector boards have no password configured, which the firmware authenticates by signing with an empty-string HMAC key. The client conflated an empty password with "no password set": the Machine.password property coerced "" to the $VECTOR_PASSWORD fallback, and both the auth preflight and the HTTP transport rejected a falsy password outright, so an empty password could never be used. Distinguish None (unset — still falls back to the environment and raises AuthenticationRequiredError when nothing is configured) from "" (a valid empty password that is signed as such): - Machine.password returns an explicitly-set empty string instead of the env fallback; only None falls back. - Machine._preflight_auth and HttpTransport._send guard on `is None` rather than falsiness. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014Y49XvgGpmTHrYLDeTvmbA * Require a version bump on every PR; bump to 0.2.2 The empty-password fix (#17) merged without a version bump, so main could ship a behavior change under the already-released 0.2.1. Add a CI gate that fails a pull request unless it raises __version__ above the base branch, and bump to 0.2.2 to cover the merged fix. - scripts/check_version_bump.py compares the head __version__ against the base branch's (read from git) and requires head > base; a missing base file (new package) passes. PEP 440 ordering via packaging when available, with a numeric-plus-suffix fallback. - ci.yml gains a version-bump job (pull_request only) that runs it against the PR base sha. - Unit tests cover the comparison logic. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014Y49XvgGpmTHrYLDeTvmbA --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
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
Some Vector boards have no password configured, which the firmware authenticates by signing with an empty-string HMAC key. The client currently conflates an empty password (
"") with "no password set" (None), so an empty password can never authenticate:Machine.passworddidreturn self._password or os.environ.get(...), so an explicit""was coerced into the$VECTOR_PASSWORDfallback.Machine._preflight_authandHttpTransport._sendboth rejected a falsy password (if not self.password: raise), so even if""reached them it raisedAuthenticationRequiredError— yetauth.sign("", ...)produces a perfectly valid signature the firmware accepts.This distinguishes
None(unset) from""(a valid empty password):Machine.passwordreturns an explicitly-set empty string as-is; onlyNonefalls back to$VECTOR_PASSWORD.Machine._preflight_authandHttpTransport._sendguard onis Noneinstead of falsiness.Unset behavior is unchanged: with no password configured (and no env var), authenticated routes still raise
AuthenticationRequiredErrorbefore any traffic.Testing
Added tests:
test_http.py::test_empty_password_is_valid_and_signs— an empty password fetches a challenge and signs with an empty HMAC key.test_machine.py::test_empty_password_passes_preflight— authenticated routes work withpassword="".test_machine.py::test_empty_password_not_overridden_by_env— an explicit""wins over$VECTOR_PASSWORD.python -m pytest tests/test_machine.py tests/test_http.py tests/test_auth.py tests/test_connect.pypasses. (The twotest_usb.pyfailures in this environment are pre-existing and unrelated — they require the optionalpyserialdependency, which isn't installed here.)Context
Found while wiring up empty-password support in the Memory Mapper tool (warped-pinball/memory-mapper#34), which currently has to sign empty-password requests itself to work around this. With this fix that workaround can be dropped and the high-level
Machinemethods used directly.🤖 Generated with Claude Code
https://claude.ai/code/session_014Y49XvgGpmTHrYLDeTvmbA
Generated by Claude Code