diff --git a/app/Jobs/ApplicationDeploymentJob.php b/app/Jobs/ApplicationDeploymentJob.php index ac295e9aa..66fcb8ee5 100644 --- a/app/Jobs/ApplicationDeploymentJob.php +++ b/app/Jobs/ApplicationDeploymentJob.php @@ -2477,18 +2477,20 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf"); private function handleRegistryAuth() { - $username = escapeshellarg($this->application->docker_registry_username); + $username = $this->application->docker_registry_username; + $registry = $this->application->docker_registry_url ?: 'docker.io'; $token = escapeshellarg($this->application->docker_registry_token); - - $registry = escapeshellarg($this->application->docker_registry_url ?: 'docker.io'); // Default to docker.io - $this->application_deployment_queue->addLogEntry('Attempting to log into registry...'); + $command = "echo {{secrets.token}} | docker login {$registry} -u {$username} --password-stdin"; - $command = "echo {$token} | docker login {$registry} -u {$username} --password-stdin"; - - $this->execute_remote_command([ - $command, - 'hidden' => true, - ]); + $this->execute_remote_command( + [ + 'command' => $command, + 'secrets' => [ + 'token' => $token, + ], + 'hidden' => true, + ] + ); } } diff --git a/app/Livewire/Project/Application/General.php b/app/Livewire/Project/Application/General.php index 4ad57d2a7..6d9cd8765 100644 --- a/app/Livewire/Project/Application/General.php +++ b/app/Livewire/Project/Application/General.php @@ -73,8 +73,8 @@ class General extends Component 'application.docker_registry_image_tag' => 'nullable', 'application.docker_use_custom_registry' => 'boolean', 'application.docker_registry_url' => 'nullable', - 'application.docker_registry_username' => 'required_with:application.docker_use_custom_registry', - 'application.docker_registry_token' => 'required_with:application.docker_use_custom_registry', + 'application.docker_registry_username' => 'nullable|required_if:application.docker_use_custom_registry,true', + 'application.docker_registry_token' => 'nullable|required_if:application.docker_use_custom_registry,true', 'application.dockerfile_location' => 'nullable', 'application.docker_compose_location' => 'nullable', 'application.docker_compose' => 'nullable', @@ -154,6 +154,7 @@ class General extends Component $this->application->fqdn = null; $this->application->settings->save(); } + $this->parsedServiceDomains = $this->application->docker_compose_domains ? json_decode($this->application->docker_compose_domains, true) : []; $this->ports_exposes = $this->application->ports_exposes; $this->is_preserve_repository_enabled = $this->application->settings->is_preserve_repository_enabled; diff --git a/app/Livewire/Project/New/DockerImage.php b/app/Livewire/Project/New/DockerImage.php index ae7f38586..4e70a7e4b 100644 --- a/app/Livewire/Project/New/DockerImage.php +++ b/app/Livewire/Project/New/DockerImage.php @@ -21,8 +21,8 @@ class DockerImage extends Component protected $rules = [ 'dockerImage' => 'required|string', - 'registryUsername' => 'required_with:useCustomRegistry|string', - 'registryToken' => 'required_with:useCustomRegistry|string', + 'registryUsername' => 'required_if:useCustomRegistry,true|string|nullable', + 'registryToken' => 'required_if:useCustomRegistry,true|string|nullable', 'registryUrl' => 'nullable|string', 'useCustomRegistry' => 'boolean' ]; @@ -38,8 +38,8 @@ class DockerImage extends Component { $this->validate([ 'dockerImage' => 'required', - 'registryUsername' => 'required_with:useCustomRegistry', - 'registryToken' => 'required_with:useCustomRegistry', + 'registryUsername' => 'required_if:useCustomRegistry,true', + 'registryToken' => 'required_if:useCustomRegistry,true', ]); // Only save registry settings if useCustomRegistry is true diff --git a/app/Models/Application.php b/app/Models/Application.php index 2180b78a3..c377d2951 100644 --- a/app/Models/Application.php +++ b/app/Models/Application.php @@ -113,6 +113,10 @@ class Application extends BaseModel protected $guarded = []; + protected $casts = [ + 'docker_registry_token' => 'encrypted', + ]; + protected $appends = ['server_status']; protected static function booted() diff --git a/app/Traits/ExecuteRemoteCommand.php b/app/Traits/ExecuteRemoteCommand.php index f8ccee9db..509a898d1 100644 --- a/app/Traits/ExecuteRemoteCommand.php +++ b/app/Traits/ExecuteRemoteCommand.php @@ -36,6 +36,10 @@ trait ExecuteRemoteCommand $ignore_errors = data_get($single_command, 'ignore_errors', false); $append = data_get($single_command, 'append', true); $this->save = data_get($single_command, 'save'); + $secrets = data_get($single_command, 'secrets', []); // Secrets for interpolation and masking + if (count($secrets) > 0) { + $command = $this->interpolateCommand($command, $secrets); + } if ($this->server->isNonRoot()) { if (str($command)->startsWith('docker exec')) { $command = str($command)->replace('docker exec', 'sudo docker exec'); @@ -44,10 +48,14 @@ trait ExecuteRemoteCommand } } $remote_command = SshMultiplexingHelper::generateSshCommand($this->server, $command); - $process = Process::timeout(3600)->idleTimeout(3600)->start($remote_command, function (string $type, string $output) use ($command, $hidden, $customType, $append) { + $process = Process::timeout(3600)->idleTimeout(3600)->start($remote_command, function (string $type, string $output) use ($command, $secrets, $hidden, $customType, $append) { $output = str($output)->trim(); - if ($output->startsWith('╔')) { - $output = "\n".$output; + if (count($secrets) > 0) { + $output = $this->maskSecrets($output, $secrets); + $command = $this->maskSecrets($command, $secrets); + } + if (str($output)->startsWith('╔')) { + $output = "\n" . $output; } $new_log_entry = [ 'command' => remove_iip($command), @@ -93,4 +101,29 @@ trait ExecuteRemoteCommand } }); } + + private function interpolateCommand(string $command, array $secrets): string + { + foreach ($secrets as $key => $value) { + // Define the placeholder format + $placeholder = "{{secrets.$key}}"; + // Replace placeholder with actual value + $command = str_replace($placeholder, $value, $command); + } + return $command; + } + + private function maskSecrets(string $text, array $secrets): string + { + // Sort secrets by length descending to prevent partial masking + usort($secrets, function ($a, $b) { + return strlen($b) - strlen($a); + }); + + foreach ($secrets as $value) { + // Replace each secret value with '*****' + $text = str_replace($value, '*****', $text); + } + return $text; + } } diff --git a/resources/views/livewire/project/new/docker-image.blade.php b/resources/views/livewire/project/new/docker-image.blade.php index 96cd84075..7af0ffcfd 100644 --- a/resources/views/livewire/project/new/docker-image.blade.php +++ b/resources/views/livewire/project/new/docker-image.blade.php @@ -21,11 +21,11 @@ helper="Leave empty for Docker Hub" /> @endif