Repository navigation
Conversation
util.isDeepStrictEqual, assert.deepStrictEqual, assert.deepEqual and Bun.deepEquals walked the own enumerable properties of a KeyObject or a CryptoKey. Both keep their state in C++ and have no own properties, so any two keys compared equal. Follow node's comparisons.js. A KeyObject compares by type and key material. A CryptoKey compares by type, extractable, algorithm, usages and key material. Both then compare own enumerable properties as before. assert.partialDeepStrictEqual now covers CryptoKey through the same helpers.
|
Warning Review limit reached
On-demand reviews are free for the next 14 days. After that, they cost $0.25 per reviewed file. Or wait 5 minutes for your next included review. View limit detailsLimit details: You’ve used all 10 included reviews currently available. Review configuration: ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Essentials Run ID: 📒 Files selected for processing (6)
Comment |
|
Updated 2:23 AM PT - Sep 6th, 2026
❌ @robobun, your commit 74187b6 has 3 failures in
🧪 To try this PR locally: bunx bun-pr 41500That installs a local version of the PR into your bun-41500 --bun |
|
On the usages comparison: node v26.3.0 compares the usages mask for exact equality in every mode, including partial. Checked against node v26.3.0: const k = createSecretKey(Buffer.from("secret-A"));
const a = k.toCryptoKey({ name: "HMAC", hash: "SHA-256" }, true, ["sign", "verify"]);
const b = k.toCryptoKey({ name: "HMAC", hash: "SHA-256" }, true, ["sign"]);
assert.partialDeepStrictEqual(a, b); // node: ERR_ASSERTIONNo change needed. |
Jarred-Sumner
left a comment
There was a problem hiding this comment.
Is there some symbol property for deep equality we can use instead?
|
There is no such symbol today. Node's I can add one. Two shapes:
One detail for either shape: the Which shape do you want? I will rework the PR to match. |
|
This PR is covered by #47567 (89fbb78), which is on main. It landed the comparison of I checked that on main (3f3a9ff). I added the test blocks of this PR to main's versions of the two test files and ran them on a debug build, with no source change from this PR.
Main answers no row of this PR differently. The source differs in two points that no row observes:
#47567 uses type checks in the same place as this PR. The symbol-based hook discussed above is not implemented anywhere. |
Problem
util.isDeepStrictEqual,assert.deepStrictEqual,assert.deepEqualandBun.deepEqualsreport any twoKeyObjects orCryptoKeys as equal.assert.deepStrictEqual(createSecretKey(a), createSecretKey(b))passes for anyaandb. Node throwsERR_ASSERTION. A test that asserts two keys are equal can never fail.Bun__deepEquals(src/jsc/bindings/bindings.cpp). Both classes keep their state in C++ and have no own enumerable properties, so the walk compares nothing.Fix
ObjectTypetail ofspecialObjectsDequal, next to the Temporal arm. It follows node'scomparisons.js: aKeyObjectcompares by type and key material. ACryptoKeycompares by type, extractable,algorithm(deep, with the caller's mode), usages and key material. Both then compare own enumerable properties as before.ERR_CRYPTO_UNSUPPORTED_OPERATIONwhen OpenSSL cannot compare the keys, the same asKeyObject.prototype.equalsand node's handleequals.assert.partialDeepStrictEqualport (src/jsc/modules/NodeUtilTypesModule.cpp) shares the helpers. It already handledKeyObjectthrough a JS call toequals. It now also handlesCryptoKey.test/js/node/assert/deep-equal.test.ts(22 matrix cases, 20 fail on 1.4.2) andtest/js/bun/bun-object/deep-equals.test.ts(fails on 1.4.2). Alsotest/js/node/assert/, node'stest-assert*.js,crypto.key-objects.test.ts,test/js/bun/test/expect*.Background
specialObjectsDequalis the per-type dispatch inside the deep equality walk. It returnsfalseto reject a pair,trueto accept it, andstd::nulloptto continue with the generic own-property compare. All four entry points (node strict, node loose,Bun.deepEquals,expect().toEqual) share this template, soexpect(keyA).toEqual(keyB)now compares key material too. The new bun-object test pins that.JSKeyObjectandJSCryptoKeyboth use theObjectTypecell type, so the arm lives in thec1Type == ObjectTypetail, not in theswitch.KeyObject::create(CryptoKey&)already converts WebCrypto key material to a nodeKeyObjecthandle. TheCryptoKeyarm uses it for the material compare.bindings.cpphunk 2. This PR supersedes that hunk with two deliberate differences: it throws on an unsupported compare instead of falling through, and it deep-compares thealgorithmdictionary instead of the identifier only.Notes
Node v26.3.0 reference:
lib/internal/util/comparisons.js, theisKeyObjectandisCryptoKeyarms ofobjectComparisonStart. Both run in every mode (strict, loose, partial) and fall through tokeyCheckafterwards.Repro on 1.4.2 (node v26.3.0 in the comment):
algorithmis read through the JS getter.JSCryptoKeycaches the dictionary object inm_algorithm, so the read is cheap and the compared objects are plain objects withObject.prototype.The
ObjectTypetail ofspecialObjectsDequalSlowis not reachable forObjectTypecells (the dispatch only sends the listed cell types there), so the arm is added to the templated function only.Suites run with the debug build:
test/js/node/assert/(7 files),test/js/node/test/parallel/test-assert{,-checktag,-class,-deep-with-error,-typedarray-deepequal}.js,test/js/node/crypto/crypto.key-objects.test.ts,test/js/node/util/test-util-types.test.js,test/js/bun/test/expect.test.ts,test/js/bun/test/expect/,test/js/bun/bun-object/.Self-reviewed: 3 concerns raised, 3 addressed (reference #35374 and state the semantic differences, add a
Bun.deepEquals/toEqualtest, fold the duplicatedCryptoKeyarm into one helper).no test proof · iteration 1 · platform-specific test(s) that do not run on this machine, deferring to CI, which covers all platforms: test/js/bun/bun-object/deep-equals.test.ts