Skip to content

Commit 766e90e

Browse files
tkislansaltenasl
andauthored
fix(deepnote-server): Handle disabled IPv6 support (#192)
* fix(deepnote-server): Handle disabled IPv6 support Signed-off-by: Tomas Kislan <tomas@kislan.sk> * test: Add tests for disabled IPv6 network Signed-off-by: Tomas Kislan <tomas@kislan.sk> * feat(deepnote-server): Improve error handling for IPv6 checks Signed-off-by: Tomas Kislan <tomas@kislan.sk> * chore: format --------- Signed-off-by: Tomas Kislan <tomas@kislan.sk> Co-authored-by: Lukas Saltenas <lukas.saltenas@gmail.com>
1 parent 985cd44 commit 766e90e

File tree

2 files changed

+72
-2
lines changed

2 files changed

+72
-2
lines changed

src/kernels/deepnote/deepnoteServerStarter.node.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -621,8 +621,17 @@ export class DeepnoteServerStarter implements IDeepnoteServerStarter, IExtension
621621
}
622622

623623
// Also check IPv6 loopback to be safe
624-
const inUseIpv6 = await tcpPortUsed.check(port, '::1');
625-
return !inUseIpv6;
624+
try {
625+
const inUseIpv6 = await tcpPortUsed.check(port, '::1');
626+
return !inUseIpv6;
627+
} catch (error: unknown) {
628+
if (error instanceof Error && 'code' in error && error.code === 'EAFNOSUPPORT') {
629+
logger.debug('IPv6 is not supported on this system');
630+
return true;
631+
}
632+
logger.warn(`Failed to check IPv6 port availability for ${port}:`, error);
633+
return false;
634+
}
626635
} catch (error) {
627636
logger.warn(`Failed to check port availability for ${port}:`, error);
628637
return false;

src/kernels/deepnote/deepnoteServerStarter.unit.test.ts

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,67 @@ suite('DeepnoteServerStarter - Port Allocation Integration Tests', () => {
116116
warnStub.restore();
117117
}
118118
});
119+
120+
test('should return true when IPv6 is disabled (EAFNOSUPPORT error)', async () => {
121+
const port = 54324;
122+
const ipv6Error = new Error('connect EAFNOSUPPORT ::1:54324');
123+
(ipv6Error as any).code = 'EAFNOSUPPORT';
124+
125+
// IPv4 check succeeds (port is available)
126+
checkStub.onFirstCall().resolves(false);
127+
128+
// IPv6 check throws EAFNOSUPPORT (IPv6 not supported)
129+
checkStub.onSecondCall().rejects(ipv6Error);
130+
131+
const debugStub = sinon.stub(logger, 'debug');
132+
133+
try {
134+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
135+
const isPortAvailable = getPrivateMethod(serverStarter as any, 'isPortAvailable');
136+
const result = await isPortAvailable(port);
137+
138+
assert.isTrue(result, 'Expected port to be available when IPv4 is free and IPv6 is not supported');
139+
assert.strictEqual(checkStub.callCount, 2, 'Should check both IPv4 and IPv6');
140+
assert.deepEqual(checkStub.getCall(0).args, [port, '127.0.0.1']);
141+
assert.deepEqual(checkStub.getCall(1).args, [port, '::1']);
142+
assert.isTrue(
143+
debugStub.calledWith('IPv6 is not supported on this system'),
144+
'Should log debug message about IPv6 not being supported'
145+
);
146+
} finally {
147+
debugStub.restore();
148+
}
149+
});
150+
151+
test('should return false when IPv6 check throws non-EAFNOSUPPORT error', async () => {
152+
const port = 54325;
153+
const ipv6Error = new Error('Some other IPv6 error');
154+
155+
// IPv4 check succeeds (port is available)
156+
checkStub.onFirstCall().resolves(false);
157+
158+
// IPv6 check throws a different error
159+
checkStub.onSecondCall().rejects(ipv6Error);
160+
161+
const warnStub = sinon.stub(logger, 'warn');
162+
163+
try {
164+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
165+
const isPortAvailable = getPrivateMethod(serverStarter as any, 'isPortAvailable');
166+
const result = await isPortAvailable(port);
167+
168+
assert.isFalse(
169+
result,
170+
'Expected port check to fail closed when IPv6 check fails with non-EAFNOSUPPORT error'
171+
);
172+
assert.strictEqual(checkStub.callCount, 2, 'Should check both IPv4 and IPv6');
173+
assert.isTrue(warnStub.called, 'Should log warning when IPv6 check fails');
174+
const warnCall = warnStub.getCall(0);
175+
assert.include(warnCall.args[0], 'Failed to check IPv6 port availability');
176+
} finally {
177+
warnStub.restore();
178+
}
179+
});
119180
});
120181

121182
suite('findAvailablePort', () => {

0 commit comments

Comments
 (0)