Files
coolify/tests/Feature/Livewire/Project/Application/ConfigurationChangeRefreshEventsTest.php
Andras Bacsai f39c884cc7 fix(servers): support IPv6 server addresses everywhere
Store server IPs in one form (no brackets, short lower-case IPv6) and
write each address in the form its context needs:

- URLs and host:port (Sentinel, database URLs, SFTP backup download,
  DNS servers, SMTP, webhook base URLs, links, health checks) get
  brackets through formatHostForUrl().
- Traefik Host() rules use the address without brackets, so IPv6
  domains no longer return 404; saved labels are fixed at deploy.
  Caddy keeps the brackets.
- SSH keeps the plain address.
- Hetzner gives an IPv6 /64 network; IPv6-only servers now get the
  server address (prefix::1) instead of the unusable prefix::64.
- sslip labels, registry image names with an IPv6 host, the API domain
  list, allowlist matching and duplicate checks handle IPv6.

A migration normalizes stored IPv6 server addresses, repairs Hetzner
servers saved as ::64 that are not reachable, and adds brackets to
saved Sentinel URLs.
2026-10-09 13:50:28 +02:00

79 lines
3.0 KiB
PHP

<?php
use App\Livewire\Project\Shared\EnvironmentVariable\All as EnvironmentVariableAll;
use App\Livewire\Project\Shared\HealthChecks;
use App\Models\Application;
use App\Models\Environment;
use App\Models\InstanceSettings;
use App\Models\Project;
use App\Models\Team;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Livewire\Livewire;
uses(RefreshDatabase::class);
beforeEach(function () {
InstanceSettings::unguarded(function () {
InstanceSettings::updateOrCreate(['id' => 0], []);
});
$this->team = Team::factory()->create();
$this->user = User::factory()->create();
$this->team->members()->attach($this->user->id, ['role' => 'owner']);
$this->actingAs($this->user);
session(['currentTeam' => $this->team]);
$project = Project::factory()->create(['team_id' => $this->team->id]);
$environment = Environment::factory()->create(['project_id' => $project->id]);
$this->application = Application::factory()->create(['environment_id' => $environment->id])->refresh();
});
it('refreshes configuration changes after health check saves', function (string $method) {
Livewire::test(HealthChecks::class, ['resource' => $this->application])
->call($method)
->assertHasNoErrors()
->assertDispatched('configurationChanged');
})->with(['instantSave', 'submit', 'toggleHealthcheck']);
it('refreshes configuration changes after environment variable settings are saved', function () {
Livewire::test(EnvironmentVariableAll::class, ['resource' => $this->application])
->call('loadEnvironmentVariables')
->set('use_build_secrets', true)
->call('instantSave')
->assertHasNoErrors()
->assertDispatched('configurationChanged');
});
it('persists environment variable order as an application setting', function () {
expect($this->application->settings->is_env_sorting_enabled)->toBeFalse();
Livewire::test(EnvironmentVariableAll::class, ['resource' => $this->application])
->assertSee('Environment variable order')
->assertSee('Build secrets')
->assertDontSeeHtml('>Sort</button>')
->call('loadEnvironmentVariables')
->set('is_env_sorting_enabled', true)
->call('instantSave')
->assertHasNoErrors()
->assertDispatched('configurationChanged')
->assertSet('is_env_sorting_enabled', true);
expect($this->application->settings->fresh()->is_env_sorting_enabled)->toBeTrue();
});
it('saves an IPv6 health check host and rejects an invalid one', function () {
Livewire::test(HealthChecks::class, ['resource' => $this->application])
->set('healthCheckHost', '[::1]')
->call('submit')
->assertHasNoErrors();
expect($this->application->fresh()->health_check_host)->toBe('[::1]');
Livewire::test(HealthChecks::class, ['resource' => $this->application->fresh()])
->set('healthCheckHost', '[::1];id')
->call('submit')
->assertNotDispatched('configurationChanged');
expect($this->application->fresh()->health_check_host)->toBe('[::1]');
});