Skip to content

fix(tesla): make PEM key handling non-blocking and configurable - #106

Merged
Bre77 merged 2 commits into
mainfrom
fm/tfa-pem-optional-skip-async
Aug 2, 2026
Merged

fix(tesla): make PEM key handling non-blocking and configurable#106
Bre77 merged 2 commits into
mainfrom
fm/tfa-pem-optional-skip-async

Conversation

@Bre77

@Bre77 Bre77 commented Aug 2, 2026

Copy link
Copy Markdown
Member

Intent

Make PEM key handling non-blocking and optional in tesla_fleet_api/tesla/tesla.py. Today, reading an existing on-disk RSA/EC PEM key deserializes it inline (serialization.load_pem_private_key called synchronously) inside _load_pem_private_key, which stalls the asyncio event loop by ~200ms for a 4096-bit RSA key. Fixed by wrapping that deserialization in asyncio.to_thread, matching the non-blocking pattern already used for RSA key generation (added in PR #105/fm/tfa-rsa-keygen-blocking). Added two new optional constructor params to get_rsa_private_key: (1) skip_rsa_key_validation (default False, preserves current full-validation behavior) which forwards cryptography's unsafe_skip_rsa_key_validation flag when loading an EXISTING externally-supplied RSA PEM from disk, letting a caller who trusts the key skip the expensive RSA consistency check; (2) async_rsa_key_creation (default True, preserves current behavior of using the isolated-subprocess keygen from PR #105) which, when set False, opts back into the older simpler blocking in-process RSA key generator instead of the subprocess-based one - useful for tests or environments where subprocess spawning is undesired. Also: a PEM this library just generated internally (via _deserialize_rsa_pem, right after generation) now always skips RSA validation unconditionally regardless of the new param, since a freshly-generated key by this library cannot be mathematically malformed (only structurally invalid, which still raises ValueError on PEM parse failure) - so revalidating it was pure wasted stall. Deliberately no redesign of key handling: pure parameter plumbing and scoped application of an existing cryptography library flag. Added 12 new tests in tests/test_tesla_private_key.py covering: default full validation on existing-key read, skip_rsa_key_validation forwarding, internal-PEM scoped skip, async_rsa_key_creation True/False behavior (subprocess called vs not), non-blocking existing-key read via heartbeat test, and default-behavior parity. Also added one bullet to AGENTS.md documenting this. Full test suite (524 tests), ruff check/format, and pyright strict all pass.

What Changed

  • Move existing RSA and EC PEM deserialization to a worker thread so key loading does not block the asyncio event loop.
  • Add options to skip trusted RSA consistency validation and to use blocking in-process RSA key generation, while preserving existing defaults.
  • Skip redundant validation for internally generated RSA keys and document and test the new behavior.

Risk Assessment

✅ Low: The change is narrowly scoped and consistently moves existing PEM deserialization off the event loop while preserving validation and asynchronous-creation defaults and correctly limiting validation skipping to authorized RSA paths.

Testing

All 30 targeted private-key tests passed, including the new optional-validation and non-blocking cases; a public-API transcript additionally demonstrated round-trip key integrity, 39 heartbeat ticks during two delayed PEM loads, default/opt-out validation forwarding, and subprocess-free creation. No UI evidence was applicable because this is a Python library API change.

Evidence: Public API PEM behavior evidence

existing_key_round_trip=True validation_flags_default_then_opt_out=[False, True] heartbeat_ticks_during_two_200ms_deserializations=39 event_loop_remained_responsive=True blocking_creation_subprocess_calls=0 generated_key_type=RSAPrivateKey generated_pem_exists=True

existing_key_round_trip=True
validation_flags_default_then_opt_out=[False, True]
heartbeat_ticks_during_two_200ms_deserializations=39
event_loop_remained_responsive=True
blocking_creation_subprocess_calls=0
generated_key_type=RSAPrivateKey
generated_pem_exists=True

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 pytest -q tests/test_tesla_private_key.py::GetRsaPrivateKeyOptionalValidationTests
  • uv run pytest -q tests/test_tesla_private_key.py
  • Public API demonstration using a real on-disk 2048-bit RSA PEM, two deliberately delayed deserializations with an asyncio heartbeat, default and skipped validation modes, and async_rsa_key_creation=False while monitoring subprocess calls
  • git status --short confirmed testing left no transient worktree changes
✅ **Document** - passed

✅ No issues found.

✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

firstmate crewmate added 2 commits August 2, 2026 15:05
… optional

Reading an existing RSA/EC PEM deserialized it inline in
_load_pem_private_key, stalling the event loop by ~200ms for a 4096-bit
RSA key. Wrap it in asyncio.to_thread like the generation path already
does, add get_rsa_private_key(skip_rsa_key_validation=..., defaults
False) to let a caller skip cryptography's RSA consistency check for a
trusted externally-supplied key, and always skip it for a PEM the
library just generated (it can't be mathematically malformed).
async_rsa_key_creation (default True) exposes an opt-out back to the
older blocking in-process generator.
@Bre77 Bre77 added the fm Opened by a Firstmate crewmate label Aug 2, 2026
@Bre77
Bre77 merged commit 95daa12 into main Aug 2, 2026
5 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