From 29ee546b95c1d4368198032339bb05911d3c00b9 Mon Sep 17 00:00:00 2001 From: Sohan Kshirsagar Date: Tue, 17 Mar 2026 11:06:38 -0700 Subject: [PATCH 1/2] fix: filter IPC and Unix domain socket false positives from TCP instrumentation --- .../libraries/tcp/Instrumentation.ts | 26 ++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/instrumentation/libraries/tcp/Instrumentation.ts b/src/instrumentation/libraries/tcp/Instrumentation.ts index 7f7e0adc..b54d9ed7 100644 --- a/src/instrumentation/libraries/tcp/Instrumentation.ts +++ b/src/instrumentation/libraries/tcp/Instrumentation.ts @@ -161,8 +161,7 @@ export class TcpInstrumentation extends TdInstrumentationBase { args: any[], socketContext: any, ): any { - // Don't want to log any HTTP response socket calls - if (this._isHttpResponseSocket(socketContext)) { + if (this._isNonNetworkSocket(socketContext)) { return originalMethod.apply(socketContext, args); } @@ -177,7 +176,6 @@ export class TcpInstrumentation extends TdInstrumentationBase { // Don't want to log any TCP calls made to the CLI if (spanKind === SpanKind.SERVER && callingLibrary !== "ProtobufCommunicator") { - // Log unpatched dependency without expensive stack trace this._logUnpatchedDependency(methodName, currentSpanInfo, socketContext); } @@ -186,8 +184,24 @@ export class TcpInstrumentation extends TdInstrumentationBase { return originalMethod.apply(socketContext, args); } - private _isHttpResponseSocket(socketContext: any): boolean { - // Check if this socket is associated with HTTP response handling - return socketContext && socketContext._httpMessage; + private _isNonNetworkSocket(socketContext: any): boolean { + if (!socketContext) return false; + + // HTTP response sockets (outbound response writing) + if (socketContext._httpMessage) return true; + + // Node.js IPC channels (e.g. process.send() used by tsx, jest workers, etc.) + // and Unix domain sockets use Pipe handles internally, while real network + // sockets use TCP handles. These are local-only and never external dependencies. + // + // In lib/net.js (https://github.com/nodejs/node/blob/main/lib/net.js#L1328-L1331), + // socket._handle is assigned as either `new Pipe(...)` or `new TCP(...)`: + // this._handle = pipe ? new Pipe(PipeConstants.SOCKET) : new TCP(TCPConstants.SOCKET); + // where Pipe = internalBinding('pipe_wrap') and TCP = internalBinding('tcp_wrap'). + // So _handle.constructor.name is "Pipe" for IPC/Unix sockets, "TCP" for network sockets. + const handleType = socketContext._handle?.constructor?.name; + if (handleType === "Pipe") return true; + + return false; } } From cd4cd7b40d0eb153b923e4bc845e843e7bfd285d Mon Sep 17 00:00:00 2001 From: Sohan Kshirsagar Date: Tue, 17 Mar 2026 11:38:43 -0700 Subject: [PATCH 2/2] address pr comment --- .../libraries/tcp/Instrumentation.ts | 29 ++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/src/instrumentation/libraries/tcp/Instrumentation.ts b/src/instrumentation/libraries/tcp/Instrumentation.ts index b54d9ed7..f30c388b 100644 --- a/src/instrumentation/libraries/tcp/Instrumentation.ts +++ b/src/instrumentation/libraries/tcp/Instrumentation.ts @@ -24,7 +24,11 @@ export interface TcpInstrumentationConfig extends TdInstrumentationConfig { */ export class TcpInstrumentation extends TdInstrumentationBase { private mode: TuskDriftMode; - private loggedSpans = new Set(); // Track spans that have been logged + private loggedSpans = new Set(); + // Tracks sockets that went through our patched connect(). Used to distinguish + // inherited IPC pipes (which never call connect) from Unix domain socket + // connections (which do). See _isNonNetworkSocket for details. + private explicitlyConnectedSockets = new WeakSet(); constructor(config: TcpInstrumentationConfig = {}) { super("tcp", config); @@ -99,6 +103,7 @@ export class TcpInstrumentation extends TdInstrumentationBase { // Socket.prototype has other methods we can patch (read, _write, end, etc) // But connect should be sufficient since we are only patching TCP to get insights into what modules we haven't patched netModule.Socket.prototype.connect = function (...args: any[]) { + self.explicitlyConnectedSockets.add(this); return self._handleTcpCall("connect", originalConnect, args, this); }; @@ -187,20 +192,24 @@ export class TcpInstrumentation extends TdInstrumentationBase { private _isNonNetworkSocket(socketContext: any): boolean { if (!socketContext) return false; - // HTTP response sockets (outbound response writing) if (socketContext._httpMessage) return true; - // Node.js IPC channels (e.g. process.send() used by tsx, jest workers, etc.) - // and Unix domain sockets use Pipe handles internally, while real network - // sockets use TCP handles. These are local-only and never external dependencies. + // Filter out inherited IPC pipes while still flagging Unix domain socket connections. // - // In lib/net.js (https://github.com/nodejs/node/blob/main/lib/net.js#L1328-L1331), - // socket._handle is assigned as either `new Pipe(...)` or `new TCP(...)`: + // Both IPC pipes and Unix domain sockets use Pipe handles (vs TCP handles for network + // sockets) — see lib/net.js: https://github.com/nodejs/node/blob/main/lib/net.js#L1328-L1331 // this._handle = pipe ? new Pipe(PipeConstants.SOCKET) : new TCP(TCPConstants.SOCKET); - // where Pipe = internalBinding('pipe_wrap') and TCP = internalBinding('tcp_wrap'). - // So _handle.constructor.name is "Pipe" for IPC/Unix sockets, "TCP" for network sockets. + // + // The key distinction: IPC pipes (e.g. process.send() used by tsx, jest workers, etc.) + // are inherited from the parent process and never go through net.Socket.prototype.connect(). + // Unix domain socket connections (e.g. PostgreSQL via /var/run/postgresql/.s.PGSQL.5432) + // DO call connect(). We track which sockets went through our patched connect() in + // explicitlyConnectedSockets, so we can filter Pipe sockets that were never connected + // (IPC) while still alerting on ones that were (potential unpatched dependencies). const handleType = socketContext._handle?.constructor?.name; - if (handleType === "Pipe") return true; + if (handleType === "Pipe" && !this.explicitlyConnectedSockets.has(socketContext)) { + return true; + } return false; }