Skip to content

feat(tesla): raise PrivateKeyError for unusable existing key files - #146

Merged
Bre77 merged 3 commits into
mainfrom
fm/tfa-private-key-error
Sep 5, 2026
Merged

feat(tesla): raise PrivateKeyError for unusable existing key files#146
Bre77 merged 3 commits into
mainfrom
fm/tfa-private-key-error

Conversation

@Bre77

@Bre77 Bre77 commented Sep 5, 2026

Copy link
Copy Markdown
Member

Intent

Review-comment fix on PR 146: PrivateKeyError must subclass LibraryError, not TeslaFleetError, since a key-file failure is local to this library, not an upstream Fleet API error. Moved the class next to SigningDisabled under LibraryError in exceptions.py, kept the reason/message attributes and docstring, updated the docstring's rationale and the README line that described it as a TeslaFleetError subclass. LibraryError subclasses Exception (not BaseException); PrivateKeyError(...) from err raise sites in tesla.py are unaffected by this base-class change. Tests still assert PrivateKeyError itself and needed no changes.

What Changed

  • Added PrivateKeyError (a LibraryError subclass, not TeslaFleetError, since a key-file failure is local to this library rather than an upstream Fleet API error) with a reason of "unreadable", "malformed", "encrypted", or "wrong_type", plus a message attribute.
  • Tesla.get_private_key/get_rsa_private_key now route a known-existing key file's read/parse failure through a shared _load_existing_private_key helper that raises PrivateKeyError for I/O errors, invalid PEM, password-encrypted PEM, and a loaded key of the wrong type, replacing the previous ad-hoc FileNotFoundError/PermissionError/AssertionError handling; key generation and the O_EXCL create-race fallback are unaffected.
  • Updated the README and docs/bluetooth_vehicles.md/docs/fleet_api_energy_sites.md to document the new PrivateKeyError reasons and its LibraryError base, consolidating the create/load semantics description in the README with cross-references from the docs.
  • Added PrivateKeyErrorTests covering unreadable, malformed, encrypted, and wrong-type key files for both the EC and RSA loaders.

Risk Assessment

✅ Low: Small, well-scoped change: moves PrivateKeyError from TeslaFleetError to LibraryError, correctly threads the message through Exception.init (required since LibraryError has no custom init unlike TeslaFleetError), updates docs consistently, and has no internal call sites that catch TeslaFleetError/BaseException expecting to intercept PrivateKeyError, so no behavior regression.

Testing

Ran the existing targeted unit tests in tests/test_tesla_private_key.py (all 38 pass unchanged, confirming the intent's claim that no test changes were needed) and additionally wrote a manual end-to-end script exercising the actual exception-hierarchy behavior change: it proves a caller's generic except TeslaFleetError handler no longer swallows PrivateKeyError post-fix, while except LibraryError does, and that reason/message/str() remain intact. No issues found; working tree left clean.

Evidence: End-to-end demonstration: PrivateKeyError escapes `except TeslaFleetError` but is caught by `except LibraryError`
OK: propagated past except TeslaFleetError -> reason='malformed' message='Private key file at /tmp/.../key.pem is not a valid PEM private key'
OK: caught by except LibraryError -> reason='malformed'
OK: str(e)='Private key file at /tmp/.../key.pem is not a valid PEM private key'

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

✅ **Review** - passed

✅ No issues found.

✅ **Test** - passed

✅ No issues found.

  • uv run python -m pytest tests/test_tesla_private_key.py -v (38 passed, including the 8 PrivateKeyErrorTests asserting reason/message/cause unchanged)
  • Manual script: constructed a malformed PEM file, called Tesla().get_private_key(path), and confirmed except TeslaFleetError no longer catches the raised error while except LibraryError does, with reason, message, and str(e) all intact
  • issubclass(PrivateKeyError, LibraryError) is True, issubclass(PrivateKeyError, TeslaFleetError) is False, issubclass(LibraryError, Exception) is True
✅ **Document** - passed

✅ No issues found.

✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

Home Assistant has to catch OSError/ValueError/TypeError/AssertionError at
multiple sites to handle an unreadable, malformed, encrypted, or wrong-type
key file. Give get_private_key/get_rsa_private_key one typed exception with
a reason instead.

Claude-Session: https://claude.ai/code/session_01D7girHWFLWBu78by9NL3qE
@Bre77 Bre77 added the fm Opened by a Firstmate crewmate label Sep 5, 2026
Comment thread tesla_fleet_api/exceptions.py Outdated
status = 540


class PrivateKeyError(TeslaFleetError):

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be a LibraryError since its not actually a Tesla Fleet API upstream error?

A key-file failure is local to this library, not an upstream Fleet API
error, so it belongs with SigningDisabled under LibraryError.

Claude-Session: https://claude.ai/code/session_01D7girHWFLWBu78by9NL3qE
@Bre77
Bre77 merged commit d6b5fe9 into main Sep 5, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

fm Opened by a Firstmate crewmate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant