Repository navigation
auth: improve from_pem error message for OpenSSH-format keys - #359
Conversation
ssh-keygen's default output since OpenSSH 7.8 is the -----BEGIN OPENSSH PRIVATE KEY----- format, which cryptography's load_pem_private_key cannot parse. Users who generated their Kalshi key with 'ssh-keygen -t rsa' previously saw the generic 'Invalid PEM private key ... Ensure the key is ... PKCS8 PEM format' message and went hunting in the wrong direction. Detect the OpenSSH magic header before calling load_pem_private_key and raise a targeted KalshiAuthError naming the format and giving the exact conversion commands (ssh-keygen -p -m PKCS8 -f <path> -N '', or openssl genpkey). The existing PKCS8/PKCS1 path and passphrase handling are unchanged; genuinely malformed PEM still surfaces the original message. Closes #335
Code ReviewSummary: This PR adds a targeted pre-flight check in Code QualityPlacement is correct. The new check sits after
Potential Issue:
|
… passphrase strip The round-1 hint suggested 'ssh-keygen -p -m PKCS8 -f <path> -N \'\'', where -N '' sets an empty new passphrase. For users whose source key is passphrase-protected, this silently strips the passphrase — a security surprise. Drop -N '' so ssh-keygen prompts interactively for both the current and the new passphrase, which is safe for encrypted and unencrypted source keys alike. Annotate the prompt behaviour in the hint so the interactive step is not unexpected. Test updated to assert the new hint substring and that -N '' is absent.
|
Round-2 review addressed in af06a0f:
Deferred:
|
Code ReviewOverviewTargeted, well-scoped fix for #335. Adds early OpenSSH-format detection in CorrectnessLogic is sound. After the One ordering issue worth fixing. The OpenSSH check sits after the password handling block: pw_bytes: bytes | None = None
if password is not None:
raw = password() if callable(password) else password # ← callable is invoked here
pw_bytes = raw.encode("utf-8") if isinstance(raw, str) else raw
if pem_data.lstrip().startswith(b"-----BEGIN OPENSSH PRIVATE KEY-----"): # ← raises here
raise KalshiAuthError(...)If if pem_data.lstrip().startswith(b"-----BEGIN OPENSSH PRIVATE KEY-----"):
raise KalshiAuthError(...)
pw_bytes: bytes | None = None
if password is not None:
...This is a minor ergonomics issue, not a correctness bug—the error is still raised correctly—but worth fixing given the overall quality bar of the file. Error MessageClear and actionable. Two concrete remediation paths are provided (in-place conversion and fresh key generation), which is the right balance. The Test CoverageSolid. The test covers:
One small nit: The assert "-N ''" not in msg # dropped from earlier draft; empty-passphrase hint confused usersCoverage gap (non-blocking): Summary
The callable-password ordering issue is the only thing worth addressing before merge. Everything else is minor polish. |
…test negative assertion
|
Round-3 review addressed in 07ef490:
|
Code ReviewOverviewThis is a small, well-scoped UX fix: when Code Quality
The check is correctly placed — after The error message is thorough and actionable. Two commands are offered (convert-in-place and generate-fresh), which covers the two realistic user situations. No issues with the implementation itself. Test Coverage
@pytest.mark.parametrize("pem", [openssh_pem, openssh_pem.decode()])
def test_issue_335_from_pem_openssh_format_error_message(self, pem):
...Not a blocker, but worth considering. Minor IssuesInline comment references PR-internal history # regression: dropped from earlier draft (would silently strip passphrase
# on encrypted OpenSSH keys)Per CLAUDE.md: "Don't reference the current task, fix, or callers... since those belong in the PR description and rot as the codebase evolves." The assert itself is self-documenting. If you want to keep a hint for future readers, something like Summary
Solid fix. The two items above are polish-level — neither is a blocker. The implementation is correct and minimal. Good to merge once the comment is cleaned up (or left as a known deviation). Reviewed by Claude (claude-sonnet-4-6) — kalshi-python-sdk PR #359 |
|
Round-4 review addressed in 0b93cca:
|
Code ReviewOverviewThis PR adds a targeted early-exit check in Code Quality & Style
Minor nit — lstrip specificity: Tests
One style note: The test name encodes the issue number ( Behavioral CoverageThe fix propagates naturally to Existing PKCS8/PKCS1 key handling, passphrase paths, and the RSA-type check are all untouched — confirmed by the diff. SecurityNo concerns. The suggested SummaryClean, minimal, well-tested fix. The only actionable suggestion is renaming the test method to drop the issue number from its name. Everything else is solid. Verdict: Approve with minor nit on the test name. |
Summary
KalshiAuth.from_pemnow detects OpenSSH-format private keys (-----BEGIN OPENSSH PRIVATE KEY-----, the defaultssh-keygenoutput since OpenSSH 7.8) and raises a targeted error pointing at the exact conversion command, instead of the generic "Invalid PEM" message that sent users hunting for PKCS8 issues in a non-PKCS8 file.Issues closed
from_pemerror for an OpenSSH-format key mentions only PKCS8 — wrong remediationBehavioral changes
KalshiAuth.from_pem/from_key_path/from_envnow raisesKalshiAuthErrorwith an OpenSSH-specific message and conversion command, before the genericload_pem_private_keypath. PKCS8/PKCS1 handling and the existing passphrase paths are unchanged.Tests
tests/test_auth.py::TestFromPem::test_issue_335_from_pem_openssh_format_error_message— feeds an OpenSSH-format key and asserts the targeted message andssh-keygen -p -m PKCS8hint.Source
Round-3 independent audit closure plan, wave W0.