Files
coolify/resources/js/terminal-connection.test.js
T
Andras BacsaiandClaude Opus 5.5 3a4ea3b4d6 fix(terminal): forward the session cookie instead of guessing its name
The terminal server built the Laravel session cookie name from APP_NAME
with its own regex and ignored SESSION_COOKIE. When the name differed
from Laravel's, every connection closed with "Missing required tokens".
Forward the browser Cookie header so Laravel reads its own session.

Also remove the text rejection messages kept for terminal clients from
before close codes; the server and client now ship in the same image.

Closes #10549

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 15:05:35 +01:00

87 lines
3.3 KiB
JavaScript

import test from 'node:test';
import assert from 'node:assert/strict';
import {
TERMINAL_CLOSE_CODES,
TERMINAL_CONNECT_TIMEOUT_MS,
TERMINAL_CONNECTION_ERRORS,
TERMINAL_SESSION_START_TIMEOUT_MS,
isTerminalAuthRejectionCode,
isTerminalStartupRejection,
resolveTerminalCloseOutcome,
} from './terminal-connection.js';
const closeOutcome = (overrides = {}) => resolveTerminalCloseOutcome({
code: 1006,
sessionPending: false,
reconnectAttempts: 0,
maxReconnectAttempts: 10,
...overrides,
});
test('terminal close codes match the codes sent by the terminal server', () => {
assert.equal(TERMINAL_CLOSE_CODES.AUTH_REJECTED, 4401);
assert.equal(TERMINAL_CLOSE_CODES.TOKEN_REJECTED, 4403);
assert.equal(isTerminalAuthRejectionCode(4401), true);
assert.equal(isTerminalAuthRejectionCode(4403), true);
assert.equal(isTerminalAuthRejectionCode(1006), false);
assert.equal(isTerminalAuthRejectionCode(4000), false);
});
test('auth rejection closes stop reconnecting and show the reload message', () => {
for (const code of [4401, 4403]) {
for (const sessionPending of [true, false]) {
assert.deepEqual(closeOutcome({ code, sessionPending }), {
authRejected: true,
reconnect: false,
error: 'Terminal access was rejected. Reload the page and try again.',
});
}
}
});
test('a clean close neither reconnects nor reports an error', () => {
assert.deepEqual(closeOutcome({ code: 1000, sessionPending: true }), {
authRejected: false,
reconnect: false,
error: null,
});
});
test('a close before the session is ready leaves the connecting state with a generic error', () => {
for (const code of [1006, 1011, 1001, 4000]) {
assert.deepEqual(closeOutcome({ code, sessionPending: true }), {
authRejected: false,
reconnect: true,
error: TERMINAL_CONNECTION_ERRORS.connectionFailed,
});
}
});
test('an idle close reconnects silently until the retry limit, then reports an error', () => {
assert.deepEqual(closeOutcome({ reconnectAttempts: 9 }), {
authRejected: false,
reconnect: true,
error: null,
});
assert.deepEqual(closeOutcome({ reconnectAttempts: 10 }), {
authRejected: false,
reconnect: false,
error: TERMINAL_CONNECTION_ERRORS.connectionFailed,
});
});
test('session start rejections from the terminal server are detected', () => {
assert.equal(isTerminalStartupRejection('Unauthorized: Target host 10.0.0.5 not in authorized list'), true);
assert.equal(isTerminalStartupRejection('Invalid SSH command: No target host found'), true);
assert.equal(isTerminalStartupRejection('pty-ready'), false);
assert.equal(isTerminalStartupRejection('root@host:~# '), false);
assert.equal(isTerminalStartupRejection(new Blob([])), false);
});
test('connection timeouts stay within a bounded window', () => {
assert.equal(TERMINAL_CONNECT_TIMEOUT_MS, 15000);
assert.ok(TERMINAL_SESSION_START_TIMEOUT_MS >= TERMINAL_CONNECT_TIMEOUT_MS);
assert.ok(TERMINAL_SESSION_START_TIMEOUT_MS <= 30000);
assert.equal(TERMINAL_CONNECTION_ERRORS.timeout, 'Timed out while connecting to the terminal. Reload the page and try again.');
});