fix(docker): reap orphaned helper containers regardless of registry (#11540)

This commit is contained in:
🏔️ Peak 2026-09-04 16:30:57 +02:00 committed by GitHub
commit faea1d5436
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 80 additions and 1 deletions

View file

@ -19,6 +19,11 @@ class CleanupHelperContainersJob implements ShouldBeEncrypted, ShouldBeUnique, S
public function __construct(public Server $server) {}
private static function helperContainersCommand(): string
{
return 'docker container ps --format \'{{json .}}\' | jq -s \'map(select(.Image|test("(^|/)coollabsio/coolify-helper(:|@)")))\'';
}
public function handle(): void
{
try {
@ -36,7 +41,7 @@ public function handle(): void
'active_deployment_uuids' => $activeDeployments,
]);
$containers = instant_remote_process_with_timeout(['docker container ps --format \'{{json .}}\' | jq -s \'map(select(.Image | contains("'.coolifyRegistryUrl().'/coollabsio/coolify-helper")))\''], $this->server, false);
$containers = instant_remote_process_with_timeout([self::helperContainersCommand()], $this->server, false);
$helperContainers = collect(json_decode($containers));
if ($helperContainers->count() > 0) {

View file

@ -0,0 +1,74 @@
<?php
use App\Jobs\CleanupHelperContainersJob;
use App\Models\Server;
use Symfony\Component\Process\Process;
it('matches helper image references without matching similarly named images', function () {
$command = (new ReflectionMethod(CleanupHelperContainersJob::class, 'helperContainersCommand'))->invoke(null);
$directory = sys_get_temp_dir().'/coolify-helper-filter-'.bin2hex(random_bytes(4));
$docker = $directory.'/docker';
$images = [
'coollabsio/coolify-helper:1.0.15',
'docker.io/coollabsio/coolify-helper:1.0.16',
'ghcr.io/coollabsio/coolify-helper@sha256:abc',
'registry.example/team/coollabsio/coolify-helper:latest',
'coollabsio/coolify:latest',
'coollabsio/coolify:4.3.12',
'coollabsio/coolify-realtime:1.0.10',
'coolify-helper:latest',
'someone/coolify-helper:1.0.16',
'evil/coollabsio/coolify-helper-copy:latest',
'coollabsio/not-coolify-helper:latest',
];
mkdir($directory);
file_put_contents($docker, "#!/bin/sh\n".implode("\n", array_map(
fn (string $image): string => 'echo '.escapeshellarg(json_encode(['Image' => $image], JSON_THROW_ON_ERROR)),
$images
))."\n");
chmod($docker, 0755);
try {
$process = new Process(['/bin/sh', '-c', $command], env: [
'PATH' => $directory.':'.getenv('PATH'),
]);
$process->mustRun();
expect(array_column(json_decode($process->getOutput(), true, flags: JSON_THROW_ON_ERROR), 'Image'))
->toBe(array_slice($images, 0, 4));
} finally {
unlink($docker);
rmdir($directory);
}
});
it('preserves the helper image filter for non-root servers', function () {
$command = (new ReflectionMethod(CleanupHelperContainersJob::class, 'helperContainersCommand'))->invoke(null);
$server = Mockery::mock(Server::class)->makePartial();
$server->user = 'ubuntu';
$command = parseCommandsByLineForSudo(collect([$command]), $server)[0];
$directory = sys_get_temp_dir().'/coolify-helper-sudo-filter-'.bin2hex(random_bytes(4));
$docker = $directory.'/docker';
$sudo = $directory.'/sudo';
mkdir($directory);
file_put_contents($docker, "#!/bin/sh\necho '{\"Image\":\"coollabsio/coolify-helper:1.0.15\"}'\n");
file_put_contents($sudo, "#!/bin/sh\nexec \"\$@\"\n");
chmod($docker, 0755);
chmod($sudo, 0755);
try {
$process = new Process(['/bin/sh', '-c', $command], env: [
'PATH' => $directory.':'.getenv('PATH'),
]);
$process->mustRun();
expect(array_column(json_decode($process->getOutput(), true, flags: JSON_THROW_ON_ERROR), 'Image'))
->toBe(['coollabsio/coolify-helper:1.0.15']);
} finally {
unlink($docker);
unlink($sudo);
rmdir($directory);
}
});