From bd5fbf4c092a0e0366c87abed25471d7cec7269e Mon Sep 17 00:00:00 2001 From: Tomas Kislan Date: Thu, 6 Nov 2025 08:28:19 +0000 Subject: [PATCH 1/4] fix(deepnote-server): Handle disabled IPv6 support Signed-off-by: Tomas Kislan --- src/kernels/deepnote/deepnoteServerStarter.node.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/kernels/deepnote/deepnoteServerStarter.node.ts b/src/kernels/deepnote/deepnoteServerStarter.node.ts index 04b03485e..149d9a7db 100644 --- a/src/kernels/deepnote/deepnoteServerStarter.node.ts +++ b/src/kernels/deepnote/deepnoteServerStarter.node.ts @@ -621,8 +621,17 @@ export class DeepnoteServerStarter implements IDeepnoteServerStarter, IExtension } // Also check IPv6 loopback to be safe + try { const inUseIpv6 = await tcpPortUsed.check(port, '::1'); return !inUseIpv6; + } catch (error) { + if (error instanceof Error && error.message.includes('EAFNOSUPPORT')) { + logger.debug('IPv6 is not supported on this system'); + return true; + } + logger.warn(`Failed to check IPv6 port availability for ${port}:`, error); + return false; + } } catch (error) { logger.warn(`Failed to check port availability for ${port}:`, error); return false; From de2a31ecb9bf6b9f6ed7bff132a85acf4b905322 Mon Sep 17 00:00:00 2001 From: Tomas Kislan Date: Thu, 6 Nov 2025 08:34:55 +0000 Subject: [PATCH 2/4] test: Add tests for disabled IPv6 network Signed-off-by: Tomas Kislan --- .../deepnoteServerStarter.unit.test.ts | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/src/kernels/deepnote/deepnoteServerStarter.unit.test.ts b/src/kernels/deepnote/deepnoteServerStarter.unit.test.ts index dda362b52..9d480af90 100644 --- a/src/kernels/deepnote/deepnoteServerStarter.unit.test.ts +++ b/src/kernels/deepnote/deepnoteServerStarter.unit.test.ts @@ -116,6 +116,66 @@ suite('DeepnoteServerStarter - Port Allocation Integration Tests', () => { warnStub.restore(); } }); + + test('should return true when IPv6 is disabled (EAFNOSUPPORT error)', async () => { + const port = 54324; + const ipv6Error = new Error('connect EAFNOSUPPORT ::1:54324'); + + // IPv4 check succeeds (port is available) + checkStub.onFirstCall().resolves(false); + + // IPv6 check throws EAFNOSUPPORT (IPv6 not supported) + checkStub.onSecondCall().rejects(ipv6Error); + + const debugStub = sinon.stub(logger, 'debug'); + + try { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const isPortAvailable = getPrivateMethod(serverStarter as any, 'isPortAvailable'); + const result = await isPortAvailable(port); + + assert.isTrue(result, 'Expected port to be available when IPv4 is free and IPv6 is not supported'); + assert.strictEqual(checkStub.callCount, 2, 'Should check both IPv4 and IPv6'); + assert.deepEqual(checkStub.getCall(0).args, [port, '127.0.0.1']); + assert.deepEqual(checkStub.getCall(1).args, [port, '::1']); + assert.isTrue( + debugStub.calledWith('IPv6 is not supported on this system'), + 'Should log debug message about IPv6 not being supported' + ); + } finally { + debugStub.restore(); + } + }); + + test('should return false when IPv6 check throws non-EAFNOSUPPORT error', async () => { + const port = 54325; + const ipv6Error = new Error('Some other IPv6 error'); + + // IPv4 check succeeds (port is available) + checkStub.onFirstCall().resolves(false); + + // IPv6 check throws a different error + checkStub.onSecondCall().rejects(ipv6Error); + + const warnStub = sinon.stub(logger, 'warn'); + + try { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const isPortAvailable = getPrivateMethod(serverStarter as any, 'isPortAvailable'); + const result = await isPortAvailable(port); + + assert.isFalse( + result, + 'Expected port check to fail closed when IPv6 check fails with non-EAFNOSUPPORT error' + ); + assert.strictEqual(checkStub.callCount, 2, 'Should check both IPv4 and IPv6'); + assert.isTrue(warnStub.called, 'Should log warning when IPv6 check fails'); + const warnCall = warnStub.getCall(0); + assert.include(warnCall.args[0], 'Failed to check IPv6 port availability'); + } finally { + warnStub.restore(); + } + }); }); suite('findAvailablePort', () => { From 254d178161fb5a94a43b07e87bc02a18c6ff458c Mon Sep 17 00:00:00 2001 From: Tomas Kislan Date: Thu, 6 Nov 2025 08:50:18 +0000 Subject: [PATCH 3/4] feat(deepnote-server): Improve error handling for IPv6 checks Signed-off-by: Tomas Kislan --- src/kernels/deepnote/deepnoteServerStarter.node.ts | 4 ++-- src/kernels/deepnote/deepnoteServerStarter.unit.test.ts | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/kernels/deepnote/deepnoteServerStarter.node.ts b/src/kernels/deepnote/deepnoteServerStarter.node.ts index 149d9a7db..f4463b455 100644 --- a/src/kernels/deepnote/deepnoteServerStarter.node.ts +++ b/src/kernels/deepnote/deepnoteServerStarter.node.ts @@ -624,8 +624,8 @@ export class DeepnoteServerStarter implements IDeepnoteServerStarter, IExtension try { const inUseIpv6 = await tcpPortUsed.check(port, '::1'); return !inUseIpv6; - } catch (error) { - if (error instanceof Error && error.message.includes('EAFNOSUPPORT')) { + } catch (error: unknown) { + if (error instanceof Error && 'code' in error && error.code === 'EAFNOSUPPORT') { logger.debug('IPv6 is not supported on this system'); return true; } diff --git a/src/kernels/deepnote/deepnoteServerStarter.unit.test.ts b/src/kernels/deepnote/deepnoteServerStarter.unit.test.ts index 9d480af90..3f9426ac6 100644 --- a/src/kernels/deepnote/deepnoteServerStarter.unit.test.ts +++ b/src/kernels/deepnote/deepnoteServerStarter.unit.test.ts @@ -120,6 +120,7 @@ suite('DeepnoteServerStarter - Port Allocation Integration Tests', () => { test('should return true when IPv6 is disabled (EAFNOSUPPORT error)', async () => { const port = 54324; const ipv6Error = new Error('connect EAFNOSUPPORT ::1:54324'); + (ipv6Error as any).code = 'EAFNOSUPPORT'; // IPv4 check succeeds (port is available) checkStub.onFirstCall().resolves(false); From fd0ee38bce01693f6c9c54fd18a80217d5e85084 Mon Sep 17 00:00:00 2001 From: Lukas Saltenas Date: Thu, 6 Nov 2025 11:05:50 +0200 Subject: [PATCH 4/4] chore: format --- src/kernels/deepnote/deepnoteServerStarter.node.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/kernels/deepnote/deepnoteServerStarter.node.ts b/src/kernels/deepnote/deepnoteServerStarter.node.ts index f4463b455..38af327da 100644 --- a/src/kernels/deepnote/deepnoteServerStarter.node.ts +++ b/src/kernels/deepnote/deepnoteServerStarter.node.ts @@ -622,8 +622,8 @@ export class DeepnoteServerStarter implements IDeepnoteServerStarter, IExtension // Also check IPv6 loopback to be safe try { - const inUseIpv6 = await tcpPortUsed.check(port, '::1'); - return !inUseIpv6; + const inUseIpv6 = await tcpPortUsed.check(port, '::1'); + return !inUseIpv6; } catch (error: unknown) { if (error instanceof Error && 'code' in error && error.code === 'EAFNOSUPPORT') { logger.debug('IPv6 is not supported on this system');