Repository navigation
Conversation
…ke Node
prepareAsymmetricKey passed a null object name to parseKeyEncoding, so a
bad format/type/passphrase inside a { key, format, ... } argument was
reported as options.format etc. Node v26.1.0 (nodejs/node#62527) reports
these as key.format, key.type and key.passphrase, and keeps options.*
for KeyObject#export and options.<public|private>KeyEncoding.* for
generateKeyPair.
makeOptionString now takes the full prefix like Node's option() helper:
prepareAsymmetricKey passes "key", generateKeyPair passes
"options.publicKeyEncoding" / "options.privateKeyEncoding", and export
keeps passing null for the bare options.* form.
|
Warning Review limit reached
Next review available in: 39 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (5)
Comment |
|
Status: fix pushed, self-review in progress. Reproduced on the released binary ( Same for The new block in Out of scope, tracked separately: |
There was a problem hiding this comment.
LGTM — error-message-only Node compat fix with all call sites accounted for.
What was reviewed
makeOptionStringsemantics change: verified the only three call-site families (prepareAsymmetricKey,generateKeyPair'sparseKeyEncodingConfig,KeyObject#export) and confirmed each now passes the right prefix soexportandgenerateKeyPairmessages are unchanged while input-key messages becomekey.<option>.- New test block pins all three prefixes (7 consumers × 3 key-material shapes × 4 options, plus
exportandgenerateKeyPairSync); vendoredtest-crypto-key-objects.jsupdated to the upstreamkey.typewording. - No success-path behavior touched; the passphrase check for
createPublicKeystill gates onisPublic != true, so thekey.passphrasecase in the matrix is reachable for both public and private consumers.
Extended reasoning...
Overview
This PR changes the property-path prefix in ERR_INVALID_ARG_VALUE messages produced by node:crypto's key-encoding validation to match Node v26.1+ (nodejs/node#62527). The native change is five lines: makeOptionString now treats its first argument as a full prefix (<prefix>.<option>) instead of a sub-name under options., the three parseKeyEncoding calls in prepareAsymmetricKey pass "key" instead of null, and the two generateKeyPair callers pass the already-prefixed "options.publicKeyEncoding" / "options.privateKeyEncoding" to preserve their existing output. KeyObject#export keeps passing null, which still renders as options.<option>.
Security risks
None. This is a change to the text of validation error messages; no parsing, allocation, key-material handling, or control flow on the success path is affected.
Level of scrutiny
Low. The only functional risk with a helper-semantics change like this is missing a caller. I grepped for every use of makeOptionString, parseKeyEncoding, parsePublicKeyEncoding, and parsePrivateKeyEncoding — there are exactly three call-site families, all touched or verified unchanged in this PR, and the new tests explicitly pin the output of all three (input-key → key.*, export → options.*, keygen → options.<pub|priv>KeyEncoding.*). The vendored Node parallel test is updated to the upstream wording rather than weakened.
Other factors
Test coverage is thorough: a describe.each × test.each matrix over 7 consumers and 3 key-material shapes exercises the string / JSArrayBufferView / JSArrayBuffer branches of prepareAsymmetricKey for format, type, missing type, and passphrase; separate tests pin export and generateKeyPairSync messages so a future refactor of makeOptionString can't silently regress the unchanged paths. The PR description documents the known residual divergence (Sign#sign/privateEncrypt/privateDecrypt say key.* where Node says privateKey.*) as a pre-existing root-name difference tracked separately, which is consistent with Bun's other messages for those APIs. No CODEOWNERS cover these files.
|
Updated 5:05 AM PT - Aug 14th, 2026
❌ @robobun, your commit 98d4e21 has some failures in 🧪 To try this PR locally: bunx bun-pr 38415That installs a local version of the PR into your bun-38415 --bun |
|
Closing: #45335 contains this change. It passes the name of the caller to |
Problem
createPrivateKey({ key, format: "bogus" })throwsERR_INVALID_ARG_VALUE: The property 'options.format' is invalid. Received 'bogus'. Node v26.3.0 (the version Bun reports) says'key.format'. Same forkey.typeandkey.passphrase, and for every API that takes a{ key, ... }object:createPublicKey,crypto.sign/verify,Verify#verify,publicEncrypt/publicDecrypt,Sign#sign,privateEncrypt/privateDecrypt.KeyObject::prepareAsymmetricKey(src/jsc/bindings/node/crypto/KeyObject.cpp:2008,:2023,:2037) callsparseKeyEncodingwith a null object name, andmakeOptionString(src/jsc/bindings/node/crypto/CryptoUtil.cpp:800) renders a null name asoptions.<option>. Both mirror Node'soption()helper as it was before Node v26.1.0; crypto: accept key data in crypto.diffieHellman() and cleanup DH jobs nodejs/node#62527 changed it to take a full prefix and madeprepareAsymmetricKeypasskey.test/js/node/test/parallel/test-crypto-key-objects.jspinned the oldoptions.typewording (upstream changed that line tokey.typein the same Node PR).Fix
makeOptionString(prefix, option)now renders<prefix>.<option>, with a null prefix still meaning the bareoptions.<option>form, exactly like Node's currentoption().prepareAsymmetricKeypasses"key";generateKeyPairpasses"options.publicKeyEncoding"/"options.privateKeyEncoding"(previously the bare names, whichmakeOptionStringprependedoptions.to);KeyObject#exportkeeps passing null. So the only messages that change are the input-key ones, which is also the only thing crypto: accept key data in crypto.diffieHellman() and cleanup DH jobs nodejs/node#62527 changed.key(createPrivateKey,createPublicKey,sign,verify,Verify#verify,publicEncrypt,publicDecrypt); a 93-line matrix of these calls now produces byte-identical output between this build and Node v26.3.0.Sign#sign,privateEncryptandprivateDecryptnow saykey.formatwhere Node 26.1+ saysprivateKey.format; that root-name difference already applies to all of their other messages (key.key,key.asymmetricKeyType, ...) and is tracked separately, so this change only brings them in line with the rest of their own messages.test/js/node/crypto/crypto.key-objects.test.ts(newencoding option namesblock: 7 consumers x string/Buffer/ArrayBuffer key material x format/type/missing type/passphrase, plusKeyObject#exportandgenerateKeyPairSynccases pinning the unchangedoptions.*prefixes; 22 tests fail on the released binary, all pass with this build).test/js/node/test/parallel/test-crypto-key-objects.jsupdated to the upstream wording; it and the 38 other vendoredtest-crypto-key*/keygen*/sign-verify/rsa-dsa/dh-statelesstests pass with this build.test/js/node/crypto/(node-crypto,crypto-rsa,crypto-oneshot,crypto-pqc,sign-jwk-ieee-p1363,crypto-sign-regression) andtest/js/third_party/jsonwebtoken/validateAsymmetricKey.test.jspass with this build.Background
prepareAsymmetricKeyis the shared entry point that turns the key argument ofcreatePublicKey/createPrivateKey/sign/verify/publicEncrypt/... into key material. When the argument is an object ({ key, format, type, passphrase, ... }), its encoding options are validated byparseKeyEncoding, the same functionKeyObject#exportandgenerateKeyPairuse for output encodings.parseKeyEncodingtakes an object-name argument purely for error messages. Node derives the reported property path from it withoption(name, prefix):options.<name>when no prefix is given (the encoding object is theoptionsargument itself, as inexport), otherwise<prefix>.<name>.makeOptionStringis Bun's port of that helper.ERR_INVALID_ARG_VALUErendersThe property 'a.b' is invalidwhen the name contains a dot andThe argument 'a' is invalidotherwise, so the prefix decides the whole shape of the message.