Skip to content

Fix connectOptions dropped to tls.connect via Object.create#25

Merged
silverbucket merged 1 commit into
masterfrom
fix/connectoptions-prototype-drop
Jul 4, 2026
Merged

Fix connectOptions dropped to tls.connect via Object.create#25
silverbucket merged 1 commit into
masterfrom
fix/connectoptions-prototype-drop

Conversation

@silverbucket

@silverbucket silverbucket commented Jul 4, 2026

Copy link
Copy Markdown
Owner

Summary

Fixes #24.

IrcSocket built its connect options with Object.create(config.connectOptions), which placed all caller-supplied options on the prototype of the new object rather than as own properties. At connect time this object is handed to impl.connect(...); when impl is Node's tls module, tls.connect() internally spreads ...options, copying only own enumerable properties. As a result, TLS options such as rejectUnauthorized, ca, key, and cert were silently dropped and Node's defaults were used instead.

Fix

Replace Object.create with a shallow spread copy ({ ...config.connectOptions }) so caller options become own enumerable properties while the caller's original object stays immutable.

A shallow copy is used deliberately — the repo's copyJsonMaybe helper (JSON.parse(JSON.stringify(...))) would corrupt Buffer options (ca/key/cert) and drop function options like checkServerIdentity. A !== null guard is added since typeof null === "object".

Tests

Adds a connectOptions regression suite:

  • caller options (including a Buffer ca) reach impl.connect() as own enumerable properties and survive a spread — mirroring exactly what tls.connect() does
  • the caller's connectOptions object is not mutated

Verified the first test fails on the pre-fix Object.create code and passes after the fix. Full suite: 51 passing.

Summary by CodeRabbit

  • Bug Fixes

    • Improved handling of connection settings so caller-provided options are copied safely and forwarded correctly.
    • Preserved custom option values while preventing the original settings object from being modified.
  • Tests

    • Added regression coverage for connection option forwarding and immutability.

Object.create(config.connectOptions) placed caller-supplied options on
the prototype chain rather than as own properties. tls.connect() spreads
(`...options`), which copies only own enumerable properties, so TLS
options such as rejectUnauthorized, ca, key, and cert were silently
dropped and Node's defaults were used instead.

Use a shallow spread copy so caller options become own enumerable
properties while keeping the caller's original object immutable. A
shallow copy (not the JSON-based copyJsonMaybe helper) is required so
Buffer options (ca/key/cert) and function options (checkServerIdentity)
survive intact.

Adds regression tests asserting caller options reach impl.connect() as
own enumerable properties (including a Buffer value) and that the
caller's connectOptions object is not mutated.

Fixes #24
@coderabbitai

coderabbitai Bot commented Jul 4, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: db74c1d8-9d63-4534-98ea-65eee5e06d70

📥 Commits

Reviewing files that changed from the base of the PR and between c66f833 and 2d057aa.

📒 Files selected for processing (2)
  • irc-socket.js
  • test/irc-socket.js

📝 Walkthrough

Walkthrough

The constructor of IrcSocket now builds this.connectOptions via a shallow object spread ({ ...config.connectOptions }) instead of Object.create(config.connectOptions), ensuring caller-supplied options become own enumerable properties. New tests verify correct forwarding to impl.connect and that the caller's object is not mutated.

Changes

connectOptions shallow-copy fix

Layer / File(s) Summary
Shallow clone connectOptions and regression tests
irc-socket.js, test/irc-socket.js
Constructor uses { ...config.connectOptions } instead of Object.create, preserving own-property semantics for downstream consumers like tls.connect; tests assert own-property forwarding (including Buffer values) and that the original caller object stays unmutated.

Estimated code review effort: 1 (Trivial) | ~5 minutes

Poem

A prototype chain, sneaky and thin,
Hid options that never got in.
Now spread with a flick,
Own props do the trick—
Hop hop, let the TLS handshake begin! 🐇🔒

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and accurately describes the main fix: preserving connectOptions instead of using Object.create.
Linked Issues check ✅ Passed The PR preserves connectOptions as own properties, keeps the input object immutable, and adds regression tests as requested.
Out of Scope Changes check ✅ Passed The changes stay focused on connectOptions handling and its regression tests, with no unrelated scope added.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/connectoptions-prototype-drop

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@silverbucket silverbucket self-assigned this Jul 4, 2026
@silverbucket silverbucket added the bug Something isn't working label Jul 4, 2026
@silverbucket
silverbucket merged commit 43f1323 into master Jul 4, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

connectOptions passed via Object.create loses caller-supplied TLS options (rejectUnauthorized, ca, etc.) to tls.connect

1 participant