mirror of
https://github.com/coollabsio/coolify.git
synced 2026-11-14 00:33:44 -04:00
Traffic analytics: - Reject enabling unless the server runs a Coolify-managed Traefik or Caddy proxy, and show the reason in the settings UI - Save the proxy configuration before the setting so a failure leaves both unchanged; allow disabling after the proxy was removed - Skip the proxy restart when the proxy is stopped and report that the config applies on next start - Preserve the user's own Traefik --accesslog* flags and restore them when analytics is disabled - Rotate the Traefik access log in the sidecar with BusyBox tools (copytruncate, 5 gzip rotations) - Create the access log before starting Sentinel, which opens it once Terminal: - Detect and surface WebSocket connection rejections in the browser terminal, with shared helpers in terminal-connection.js and terminal-utils.js Database import: - Restore PostgreSQL backups in a single transaction; SQL replace restores go into a temporary database and swap in only on success, leaving the current database untouched on failure
109 lines
3.7 KiB
PHP
109 lines
3.7 KiB
PHP
<?php
|
|
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Illuminate\Support\Facades\Cache;
|
|
use Symfony\Component\Process\Process;
|
|
|
|
uses(RefreshDatabase::class);
|
|
|
|
beforeEach(function () {
|
|
config()->set('app.maintenance.store', 'array');
|
|
|
|
$stack = seedBrowserResourceStack();
|
|
$stack['server']->settings->update(['is_terminal_enabled' => true]);
|
|
$this->serverUuid = $stack['server']->uuid;
|
|
Cache::flush();
|
|
|
|
$this->terminalServer = null;
|
|
});
|
|
|
|
afterEach(function () {
|
|
$this->terminalServer?->stop(0);
|
|
});
|
|
|
|
/**
|
|
* Start the fake terminal WebSocket server and point the terminal client at it.
|
|
*/
|
|
function startFakeTerminalServer(string $mode): array
|
|
{
|
|
$process = new Process(['node', base_path('tests/Fixtures/terminal-websocket-rejection-server.mjs'), $mode]);
|
|
$process->start();
|
|
$process->waitUntil(fn (string $type, string $output) => str_contains($output, "\n"));
|
|
$port = (int) trim($process->getOutput());
|
|
|
|
config()->set('constants.terminal.protocol', 'ws');
|
|
config()->set('constants.terminal.host', '127.0.0.1');
|
|
config()->set('constants.terminal.port', (string) $port);
|
|
|
|
return [$process, $port];
|
|
}
|
|
|
|
function fakeTerminalServerUpgrades(int $port): int
|
|
{
|
|
return json_decode(file_get_contents("http://127.0.0.1:{$port}/stats"), true)['upgrades'];
|
|
}
|
|
|
|
/**
|
|
* The browser plugin only boots for tests whose closure calls `visit(` as a standalone expression.
|
|
*/
|
|
function openServerTerminal(mixed $loginPage, string $serverUuid): mixed
|
|
{
|
|
return $loginPage
|
|
->fill('email', 'test@example.com')
|
|
->fill('password', 'password')
|
|
->click('Login')
|
|
->assertSee('Dashboard')
|
|
->navigate("/server/{$serverUuid}/terminal");
|
|
}
|
|
|
|
it('shows an auth rejection instead of connecting forever and does not reconnect', function () {
|
|
[$this->terminalServer, $port] = startFakeTerminalServer('close-on-upgrade');
|
|
|
|
$loginPage = visit('/login');
|
|
|
|
$page = openServerTerminal($loginPage, $this->serverUuid)
|
|
->assertSee('Terminal access was rejected. Reload the page and try again.')
|
|
->assertSee('Reload page')
|
|
->assertDontSee('connecting…');
|
|
|
|
// Auth rejections must not start the exponential reconnect loop.
|
|
$page->wait(4);
|
|
expect(fakeTerminalServerUpgrades($port))->toBe(1);
|
|
|
|
$page->assertSee('Terminal access was rejected. Reload the page and try again.')
|
|
->screenshot(filename: 'terminal-auth-rejected');
|
|
});
|
|
|
|
it('shows an auth rejection when the terminal token is rejected', function () {
|
|
[$this->terminalServer, $port] = startFakeTerminalServer('reject-token');
|
|
|
|
$loginPage = visit('/login');
|
|
|
|
$page = openServerTerminal($loginPage, $this->serverUuid)
|
|
->assertSee('Terminal access was rejected. Reload the page and try again.')
|
|
->assertDontSee('connecting…');
|
|
|
|
$page->wait(4);
|
|
expect(fakeTerminalServerUpgrades($port))->toBe(1);
|
|
|
|
$page->screenshot(filename: 'terminal-token-rejected');
|
|
});
|
|
|
|
it('shows a connection error when the terminal server is unreachable', function () {
|
|
// Reserve a free port, then release it so nothing is listening there.
|
|
$socket = stream_socket_server('tcp://127.0.0.1:0');
|
|
$port = (int) substr(strrchr(stream_socket_get_name($socket, false), ':'), 1);
|
|
fclose($socket);
|
|
|
|
config()->set('constants.terminal.protocol', 'ws');
|
|
config()->set('constants.terminal.host', '127.0.0.1');
|
|
config()->set('constants.terminal.port', (string) $port);
|
|
|
|
$loginPage = visit('/login');
|
|
|
|
openServerTerminal($loginPage, $this->serverUuid)
|
|
->assertSee('Could not connect to the terminal server. Reload the page and try again.')
|
|
->assertDontSee('connecting…')
|
|
->screenshot(filename: 'terminal-connection-failed');
|
|
});
|