fix(backups): pin S3 endpoint DNS for mc cp uploads

mc --resolve applies per invocation and is not stored in the alias, so
mc cp resolved the S3 host again inside the helper container. On hosts
with split DNS this failed with "no such host", and the upload did not
use the IP validated by SafeWebhookUrl.

Fixes #12129
This commit is contained in:
Andras Bacsai
2026-10-09 08:29:53 +02:00
parent b39a8e647c
commit 065d4825d3
4 changed files with 4 additions and 4 deletions
+1 -1
View File
@@ -889,7 +889,7 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue
$resolveOptions = $resolveOptions === '' ? '' : ' '.$resolveOptions;
$commands[] = "docker exec backup-of-{$this->backup_log_uuid} mc alias set{$resolveOptions} temporary {$escapedEndpoint} {$escapedKey} {$escapedSecret}";
$commands[] = "docker exec backup-of-{$this->backup_log_uuid} mc cp {$escapedBackupLocation} {$escapedS3Destination}";
$commands[] = "docker exec backup-of-{$this->backup_log_uuid} mc cp{$resolveOptions} {$escapedBackupLocation} {$escapedS3Destination}";
instant_remote_process($commands, $this->server, true, false, $this->commandTimeout(), disableMultiplexing: true);
$this->s3_uploaded = true;
+1 -1
View File
@@ -372,7 +372,7 @@ class VolumeBackupJob implements ShouldBeEncrypted, ShouldQueue
.escapeshellarg($backupLocation.':'.$backupLocation.':ro').' '.escapeshellarg($image),
'docker exec '.escapeshellarg($containerName).' mc alias set'.$resolveOptions.' temporary '
.escapeshellarg($s3->endpoint).' '.escapeshellarg($s3->key).' '.escapeshellarg($s3->secret),
'docker exec '.escapeshellarg($containerName).' mc cp '.escapeshellarg($backupLocation).' '
'docker exec '.escapeshellarg($containerName).' mc cp'.$resolveOptions.' '.escapeshellarg($backupLocation).' '
.escapeshellarg('temporary/'.$s3->bucket.$backupDirectory.'/'),
], $server, timeout: $this->timeout, disableMultiplexing: true);
} finally {
+1 -1
View File
@@ -330,7 +330,7 @@ test('database backup job escapes the S3 copy destination argument', function ()
$source = file_get_contents(app_path('Jobs/DatabaseBackupJob.php'));
expect($source)->toContain('$escapedS3Destination = escapeshellarg("temporary/{$bucket}{$this->backup_dir}/");')
->and($source)->toContain('mc cp {$escapedBackupLocation} {$escapedS3Destination}')
->and($source)->toContain('mc cp{$resolveOptions} {$escapedBackupLocation} {$escapedS3Destination}')
->and($source)->not->toContain('mc cp $this->backup_location temporary/$bucket{$this->backup_dir}/');
});
+1 -1
View File
@@ -2122,7 +2122,7 @@ it('keeps local-first archive creation and mc copy when retaining a local volume
Process::assertRan(fn ($process) => str_contains($process->command, 'tar -I')
&& str_contains($process->command, '>')
&& ! str_contains($process->command, 'mc pipe'));
Process::assertRan(fn ($process) => str_contains($process->command, 'mc cp')
Process::assertRan(fn ($process) => str_contains($process->command, 'mc cp --resolve ')
&& ! str_contains($process->command, 'mc pipe'));
});