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