fix(config): use Object.hasOwn instead of in operator in unsetConfigValueAtPath#99826
fix(config): use Object.hasOwn instead of in operator in unsetConfigValueAtPath#99826zenglingbiao wants to merge 4 commits into
Conversation
|
Codex review: needs maintainer review before merge. Reviewed July 4, 2026, 1:46 AM ET / 05:46 UTC. Summary PR surface: Source 0, Tests +33. Total +33 across 2 files. Reproducibility: yes. Current main source plus a read-only Node expression show the helper can treat inherited names such as Review metrics: none identified. Root-cause cluster Members:
Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything. Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Next step before merge
Security Review detailsBest possible solution: Land the narrow helper change with regression tests after normal maintainer review and required checks. Do we have a high-confidence way to reproduce the issue? Yes. Current main source plus a read-only Node expression show the helper can treat inherited names such as Is this the best way to solve the issue? Yes. Fixing the shared helper's leaf existence check is narrower than caller-side special cases and matches sibling own-property config path helpers. AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against 1b84316a91dc. Label changesLabel justifications:
Evidence reviewedPR surface: Source 0, Tests +33. Total +33 across 2 files. View PR surface stats
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
|
|
@clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. |
|
Superseded by #99846, landed on The landed repair preserves @zenglingbiao as commit author and completes the shared invariant across Final proof: 106 focused tests passed, Testbox Closing this narrower duplicate in favor of the landed canonical repair. |
Summary
Use
Object.hasOwn()instead of theinoperator inunsetConfigValueAtPath()to prevent prototype chain pollution when checking whether a config key exists before deletion.What Problem This Solves
When calling
unsetConfigValueAtPath(root, ["foo", "toString"])on a config object that does not have atoStringkey, the function returnstrue(claiming success) because"toString" in cursormatchesObject.prototype.toString.The function lies to its caller — it reports "key found and deleted" when the key never existed. This can cause config management tools (CLI
config unset, config merge logic) to silently skip error handling for non-existent keys.Code evidence: In
src/config/config-paths.ts:63,if (!(leafKey in cursor))checks the prototype chain.cursoris a plainPathNodeobject (Record<string, unknown>), andleafKeycomes from user-provided dot-notation paths likefoo.toString.Root Cause
inoperator checks the entire prototype chain, not just own propertiesObject.hasOwn()(ES2022+) correctly checks only the object's own propertiesObject.hasOwnis already used 15+ times across the codebase — this was a missed instanceWhy This Fix
Object.hasOwnusage in the codebaseEvidence
/config unset foo.toStringreports "Config value unset" even thoughtoStringnever existed as a config key — theinoperator findsObject.prototype.toString/config unset foo.toStringcorrectly reports "No config value found"if (!(leafKey in cursor))atconfig-paths.ts:63traverses the prototype chain;"toString" in {}istrueReal Behavior Proof
Before (on main)
After (with fix)
Tests and Validation
src/config/config-paths.test.tscovers 4 prototype keys + own-key deletion + parent pruningnode --import tsxproof script (see above)node scripts/run-vitest.mjs src/config/config-paths.test.ts— 1 file, 6 tests passed