From 9d08eed7f68033259e1994b6f93761f6a5091798 Mon Sep 17 00:00:00 2001 From: David Buday Date: Sun, 10 Nov 2024 17:00:38 +0100 Subject: [PATCH] chore: small improvement --- app/Jobs/ApplicationDeploymentJob.php | 78 +++++++++++++-------------- app/Traits/ExecuteRemoteCommand.php | 44 +++++++-------- 2 files changed, 61 insertions(+), 61 deletions(-) diff --git a/app/Jobs/ApplicationDeploymentJob.php b/app/Jobs/ApplicationDeploymentJob.php index 66fcb8ee5..ffc0a5051 100644 --- a/app/Jobs/ApplicationDeploymentJob.php +++ b/app/Jobs/ApplicationDeploymentJob.php @@ -196,8 +196,8 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue $this->preserveRepository = $this->application->settings->is_preserve_repository_enabled; $this->basedir = $this->application->generateBaseDir($this->deployment_uuid); - $this->workdir = "{$this->basedir}".rtrim($this->application->base_directory, '/'); - $this->configuration_dir = application_configuration_dir()."/{$this->application->uuid}"; + $this->workdir = "{$this->basedir}" . rtrim($this->application->base_directory, '/'); + $this->configuration_dir = application_configuration_dir() . "/{$this->application->uuid}"; $this->is_debug_enabled = $this->application->settings->is_debug_enabled; $this->container_name = generateApplicationContainerName($this->application, $this->pull_request_id); @@ -397,12 +397,12 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue if ($this->application->docker_use_custom_registry) { $this->handleRegistryAuth(); } - + $this->generate_image_names(); $this->prepare_builder_image(); $this->generate_compose_file(); $this->rolling_update(); - + // Logout if use custom registry if ($this->application->docker_use_custom_registry) { $this->application_deployment_queue->addLogEntry('Logging out from registry...'); @@ -419,7 +419,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue 'hidden' => true ]); } - $this->application_deployment_queue->addLogEntry('Deployment error: ' . $e->getMessage(), 'stderr'); + //$this->application_deployment_queue->addLogEntry('Deployment error: ' . $e->getMessage(), 'stderr'); throw $e; } } @@ -432,13 +432,13 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue if (data_get($this->application, 'docker_compose_custom_start_command')) { $this->docker_compose_custom_start_command = $this->application->docker_compose_custom_start_command; if (! str($this->docker_compose_custom_start_command)->contains('--project-directory')) { - $this->docker_compose_custom_start_command = str($this->docker_compose_custom_start_command)->replaceFirst('compose', 'compose --project-directory '.$this->workdir)->value(); + $this->docker_compose_custom_start_command = str($this->docker_compose_custom_start_command)->replaceFirst('compose', 'compose --project-directory ' . $this->workdir)->value(); } } if (data_get($this->application, 'docker_compose_custom_build_command')) { $this->docker_compose_custom_build_command = $this->application->docker_compose_custom_build_command; if (! str($this->docker_compose_custom_build_command)->contains('--project-directory')) { - $this->docker_compose_custom_build_command = str($this->docker_compose_custom_build_command)->replaceFirst('compose', 'compose --project-directory '.$this->workdir)->value(); + $this->docker_compose_custom_build_command = str($this->docker_compose_custom_build_command)->replaceFirst('compose', 'compose --project-directory ' . $this->workdir)->value(); } } if ($this->pull_request_id === 0) { @@ -452,7 +452,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue if ($this->preserveRepository) { foreach ($this->application->fileStorages as $fileStorage) { $path = $fileStorage->fs_path; - $saveName = 'file_stat_'.$fileStorage->id; + $saveName = 'file_stat_' . $fileStorage->id; $realPathInGit = str($path)->replace($this->application->workdir(), $this->workdir)->value(); // check if the file is a directory or a file inside the repository $this->execute_remote_command( @@ -947,12 +947,12 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue $real_value = $env->real_value; } else { if ($env->is_literal || $env->is_multiline) { - $real_value = '\''.$real_value.'\''; + $real_value = '\'' . $real_value . '\''; } else { $real_value = escapeEnvVariables($env->real_value); } } - $envs->push($env->key.'='.$real_value); + $envs->push($env->key . '=' . $real_value); } // Add PORT if not exists, use the first port as default if ($this->build_pack !== 'dockercompose') { @@ -1006,12 +1006,12 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue $real_value = $env->real_value; } else { if ($env->is_literal || $env->is_multiline) { - $real_value = '\''.$real_value.'\''; + $real_value = '\'' . $real_value . '\''; } else { $real_value = escapeEnvVariables($env->real_value); } } - $envs->push($env->key.'='.$real_value); + $envs->push($env->key . '=' . $real_value); } // Add PORT if not exists, use the first port as default if ($this->build_pack !== 'dockercompose') { @@ -1419,7 +1419,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue destination: $destination, no_questions_asked: true, ); - $this->application_deployment_queue->addLogEntry("Deployment to {$server->name}. Logs: ".route('project.application.deployment.show', [ + $this->application_deployment_queue->addLogEntry("Deployment to {$server->name}. Logs: " . route('project.application.deployment.show', [ 'project_uuid' => data_get($this->application, 'environment.project.uuid'), 'application_uuid' => data_get($this->application, 'uuid'), 'deployment_uuid' => $deployment_uuid, @@ -1759,27 +1759,27 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue 'CMD-SHELL', $this->generate_healthcheck_commands(), ], - 'interval' => $this->application->health_check_interval.'s', - 'timeout' => $this->application->health_check_timeout.'s', + 'interval' => $this->application->health_check_interval . 's', + 'timeout' => $this->application->health_check_timeout . 's', 'retries' => $this->application->health_check_retries, - 'start_period' => $this->application->health_check_start_period.'s', + 'start_period' => $this->application->health_check_start_period . 's', ]; if (! is_null($this->application->limits_cpuset)) { - data_set($docker_compose, 'services.'.$this->container_name.'.cpuset', $this->application->limits_cpuset); + data_set($docker_compose, 'services.' . $this->container_name . '.cpuset', $this->application->limits_cpuset); } if ($this->server->isSwarm()) { - data_forget($docker_compose, 'services.'.$this->container_name.'.container_name'); - data_forget($docker_compose, 'services.'.$this->container_name.'.expose'); - data_forget($docker_compose, 'services.'.$this->container_name.'.restart'); + data_forget($docker_compose, 'services.' . $this->container_name . '.container_name'); + data_forget($docker_compose, 'services.' . $this->container_name . '.expose'); + data_forget($docker_compose, 'services.' . $this->container_name . '.restart'); - data_forget($docker_compose, 'services.'.$this->container_name.'.mem_limit'); - data_forget($docker_compose, 'services.'.$this->container_name.'.memswap_limit'); - data_forget($docker_compose, 'services.'.$this->container_name.'.mem_swappiness'); - data_forget($docker_compose, 'services.'.$this->container_name.'.mem_reservation'); - data_forget($docker_compose, 'services.'.$this->container_name.'.cpus'); - data_forget($docker_compose, 'services.'.$this->container_name.'.cpuset'); - data_forget($docker_compose, 'services.'.$this->container_name.'.cpu_shares'); + data_forget($docker_compose, 'services.' . $this->container_name . '.mem_limit'); + data_forget($docker_compose, 'services.' . $this->container_name . '.memswap_limit'); + data_forget($docker_compose, 'services.' . $this->container_name . '.mem_swappiness'); + data_forget($docker_compose, 'services.' . $this->container_name . '.mem_reservation'); + data_forget($docker_compose, 'services.' . $this->container_name . '.cpus'); + data_forget($docker_compose, 'services.' . $this->container_name . '.cpuset'); + data_forget($docker_compose, 'services.' . $this->container_name . '.cpu_shares'); $docker_compose['services'][$this->container_name]['deploy'] = [ 'mode' => 'replicated', @@ -1841,20 +1841,20 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue } } if ($this->application->isHealthcheckDisabled()) { - data_forget($docker_compose, 'services.'.$this->container_name.'.healthcheck'); + data_forget($docker_compose, 'services.' . $this->container_name . '.healthcheck'); } if (count($this->application->ports_mappings_array) > 0 && $this->pull_request_id === 0) { $docker_compose['services'][$this->container_name]['ports'] = $this->application->ports_mappings_array; } if (count($persistent_storages) > 0) { - if (! data_get($docker_compose, 'services.'.$this->container_name.'.volumes')) { + if (! data_get($docker_compose, 'services.' . $this->container_name . '.volumes')) { $docker_compose['services'][$this->container_name]['volumes'] = []; } $docker_compose['services'][$this->container_name]['volumes'] = array_merge($docker_compose['services'][$this->container_name]['volumes'], $persistent_storages); } if (count($persistent_file_volumes) > 0) { - if (! data_get($docker_compose, 'services.'.$this->container_name.'.volumes')) { + if (! data_get($docker_compose, 'services.' . $this->container_name . '.volumes')) { $docker_compose['services'][$this->container_name]['volumes'] = []; } $docker_compose['services'][$this->container_name]['volumes'] = array_merge($docker_compose['services'][$this->container_name]['volumes'], $persistent_file_volumes->map(function ($item) { @@ -1922,9 +1922,9 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue $volume_name = $persistentStorage->name; } if ($this->pull_request_id !== 0) { - $volume_name = $volume_name.'-pr-'.$this->pull_request_id; + $volume_name = $volume_name . '-pr-' . $this->pull_request_id; } - $local_persistent_volumes[] = $volume_name.':'.$persistentStorage->mount_path; + $local_persistent_volumes[] = $volume_name . ':' . $persistentStorage->mount_path; } return $local_persistent_volumes; @@ -1940,7 +1940,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue $name = $persistentStorage->name; if ($this->pull_request_id !== 0) { - $name = $name.'-pr-'.$this->pull_request_id; + $name = $name . '-pr-' . $this->pull_request_id; } $local_persistent_volumes_names[$name] = [ @@ -2248,7 +2248,7 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf"); ); } } catch (\Exception $error) { - $this->application_deployment_queue->addLogEntry("Error stopping container $containerName: ".$error->getMessage(), 'stderr'); + $this->application_deployment_queue->addLogEntry("Error stopping container $containerName: " . $error->getMessage(), 'stderr'); } $this->remove_container($containerName); @@ -2271,7 +2271,7 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf"); $containers = getCurrentApplicationContainerStatus($this->server, $this->application->id, $this->pull_request_id); if ($this->pull_request_id === 0) { $containers = $containers->filter(function ($container) { - return data_get($container, 'Names') !== $this->container_name && data_get($container, 'Names') !== $this->container_name.'-pr-'.$this->pull_request_id; + return data_get($container, 'Names') !== $this->container_name && data_get($container, 'Names') !== $this->container_name . '-pr-' . $this->pull_request_id; }); } $containers->each(function ($container) { @@ -2375,8 +2375,8 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf"); foreach ($containers as $container) { $containerName = data_get($container, 'Names'); - if ($containers->count() == 1 || str_starts_with($containerName, $this->application->pre_deployment_command_container.'-'.$this->application->uuid)) { - $cmd = "sh -c '".str_replace("'", "'\''", $this->application->pre_deployment_command)."'"; + if ($containers->count() == 1 || str_starts_with($containerName, $this->application->pre_deployment_command_container . '-' . $this->application->uuid)) { + $cmd = "sh -c '" . str_replace("'", "'\''", $this->application->pre_deployment_command) . "'"; $exec = "docker exec {$containerName} {$cmd}"; $this->execute_remote_command( [ @@ -2402,8 +2402,8 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf"); $containers = getCurrentApplicationContainerStatus($this->server, $this->application->id, $this->pull_request_id); foreach ($containers as $container) { $containerName = data_get($container, 'Names'); - if ($containers->count() == 1 || str_starts_with($containerName, $this->application->post_deployment_command_container.'-'.$this->application->uuid)) { - $cmd = "sh -c '".str_replace("'", "'\''", $this->application->post_deployment_command)."'"; + if ($containers->count() == 1 || str_starts_with($containerName, $this->application->post_deployment_command_container . '-' . $this->application->uuid)) { + $cmd = "sh -c '" . str_replace("'", "'\''", $this->application->post_deployment_command) . "'"; $exec = "docker exec {$containerName} {$cmd}"; try { $this->execute_remote_command( diff --git a/app/Traits/ExecuteRemoteCommand.php b/app/Traits/ExecuteRemoteCommand.php index 509a898d1..2bebec587 100644 --- a/app/Traits/ExecuteRemoteCommand.php +++ b/app/Traits/ExecuteRemoteCommand.php @@ -23,7 +23,7 @@ trait ExecuteRemoteCommand } else { $commandsText = collect($commands); } - if ($this->server instanceof Server === false) { + if (! $this->server instanceof Server) { throw new \RuntimeException('Server is not set or is not an instance of Server model'); } $commandsText->each(function ($single_command) { @@ -36,9 +36,9 @@ 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); + $secrets = data_get($single_command, 'secrets', []); + if (!empty($secrets)) { + $command = $this->replaceSecrets($command, $secrets); } if ($this->server->isNonRoot()) { if (str($command)->startsWith('docker exec')) { @@ -50,7 +50,7 @@ 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, $secrets, $hidden, $customType, $append) { $output = str($output)->trim(); - if (count($secrets) > 0) { + if (!empty($secrets)) { $output = $this->maskSecrets($output, $secrets); $command = $this->maskSecrets($command, $secrets); } @@ -68,7 +68,11 @@ trait ExecuteRemoteCommand if (! $this->application_deployment_queue->logs) { $new_log_entry['order'] = 1; } else { - $previous_logs = json_decode($this->application_deployment_queue->logs, associative: true, flags: JSON_THROW_ON_ERROR); + $previous_logs = json_decode( + $this->application_deployment_queue->logs, + associative: true, + flags: JSON_THROW_ON_ERROR + ); $new_log_entry['order'] = count($previous_logs) + 1; } $previous_logs[] = $new_log_entry; @@ -102,27 +106,23 @@ trait ExecuteRemoteCommand }); } - private function interpolateCommand(string $command, array $secrets): string + private function replaceSecrets(string $text, 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; + return preg_replace_callback( + '/\{\{secrets\.(\w+)\}\}/', + fn($match) => $secrets[$match[1]] ?? $match[0], + $text + ); } 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); + // Sort by length to prevent partial matches + $sortedSecrets = collect($secrets)->sortByDesc(fn($value) => strlen($value)); + foreach ($sortedSecrets as $value) { + if (!empty($value)) { + $text = str_replace($value, '******', $text); + } } return $text; }