feat(git-sources): add GitLab integration and URL encode credentials (#8910)
This commit is contained in:
commit
bd01d3a515
7 changed files with 284 additions and 7 deletions
|
|
@ -1163,14 +1163,15 @@ public function generateGitLsRemoteCommands(string $deployment_uuid, bool $exec_
|
||||||
$base_command = "{$base_command} {$escapedRepoUrl}";
|
$base_command = "{$base_command} {$escapedRepoUrl}";
|
||||||
} else {
|
} else {
|
||||||
$github_access_token = generateGithubInstallationToken($this->source);
|
$github_access_token = generateGithubInstallationToken($this->source);
|
||||||
|
$encodedToken = rawurlencode($github_access_token);
|
||||||
|
|
||||||
if ($exec_in_docker) {
|
if ($exec_in_docker) {
|
||||||
$repoUrl = "$source_html_url_scheme://x-access-token:$github_access_token@$source_html_url_host/{$customRepository}.git";
|
$repoUrl = "$source_html_url_scheme://x-access-token:$encodedToken@$source_html_url_host/{$customRepository}.git";
|
||||||
$escapedRepoUrl = escapeshellarg($repoUrl);
|
$escapedRepoUrl = escapeshellarg($repoUrl);
|
||||||
$base_command = "{$base_command} {$escapedRepoUrl}";
|
$base_command = "{$base_command} {$escapedRepoUrl}";
|
||||||
$fullRepoUrl = $repoUrl;
|
$fullRepoUrl = $repoUrl;
|
||||||
} else {
|
} else {
|
||||||
$repoUrl = "$source_html_url_scheme://x-access-token:$github_access_token@$source_html_url_host/{$customRepository}";
|
$repoUrl = "$source_html_url_scheme://x-access-token:$encodedToken@$source_html_url_host/{$customRepository}";
|
||||||
$escapedRepoUrl = escapeshellarg($repoUrl);
|
$escapedRepoUrl = escapeshellarg($repoUrl);
|
||||||
$base_command = "{$base_command} {$escapedRepoUrl}";
|
$base_command = "{$base_command} {$escapedRepoUrl}";
|
||||||
$fullRepoUrl = $repoUrl;
|
$fullRepoUrl = $repoUrl;
|
||||||
|
|
@ -1189,6 +1190,62 @@ public function generateGitLsRemoteCommands(string $deployment_uuid, bool $exec_
|
||||||
'fullRepoUrl' => $fullRepoUrl,
|
'fullRepoUrl' => $fullRepoUrl,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($this->source->getMorphClass() === \App\Models\GitlabApp::class) {
|
||||||
|
$gitlabSource = $this->source;
|
||||||
|
$private_key = data_get($gitlabSource, 'privateKey.private_key');
|
||||||
|
|
||||||
|
if ($private_key) {
|
||||||
|
$fullRepoUrl = $customRepository;
|
||||||
|
$private_key = base64_encode($private_key);
|
||||||
|
$gitlabPort = $gitlabSource->custom_port ?? 22;
|
||||||
|
$escapedCustomRepository = str_replace("'", "'\\''", $customRepository);
|
||||||
|
$base_command = "GIT_SSH_COMMAND=\"ssh -o ConnectTimeout=30 -p {$gitlabPort} -o Port={$gitlabPort} -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /root/.ssh/id_rsa\" {$base_command} '{$escapedCustomRepository}'";
|
||||||
|
|
||||||
|
if ($exec_in_docker) {
|
||||||
|
$commands = collect([
|
||||||
|
executeInDocker($deployment_uuid, 'mkdir -p /root/.ssh'),
|
||||||
|
executeInDocker($deployment_uuid, "echo '{$private_key}' | base64 -d | tee /root/.ssh/id_rsa > /dev/null"),
|
||||||
|
executeInDocker($deployment_uuid, 'chmod 600 /root/.ssh/id_rsa'),
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
$commands = collect([
|
||||||
|
'mkdir -p /root/.ssh',
|
||||||
|
"echo '{$private_key}' | base64 -d | tee /root/.ssh/id_rsa > /dev/null",
|
||||||
|
'chmod 600 /root/.ssh/id_rsa',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($exec_in_docker) {
|
||||||
|
$commands->push(executeInDocker($deployment_uuid, $base_command));
|
||||||
|
} else {
|
||||||
|
$commands->push($base_command);
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'commands' => $commands->implode(' && '),
|
||||||
|
'branch' => $branch,
|
||||||
|
'fullRepoUrl' => $fullRepoUrl,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// GitLab source without private key — use URL as-is (supports user-embedded basic auth)
|
||||||
|
$fullRepoUrl = $customRepository;
|
||||||
|
$escapedCustomRepository = escapeshellarg($customRepository);
|
||||||
|
$base_command = "{$base_command} {$escapedCustomRepository}";
|
||||||
|
|
||||||
|
if ($exec_in_docker) {
|
||||||
|
$commands->push(executeInDocker($deployment_uuid, $base_command));
|
||||||
|
} else {
|
||||||
|
$commands->push($base_command);
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'commands' => $commands->implode(' && '),
|
||||||
|
'branch' => $branch,
|
||||||
|
'fullRepoUrl' => $fullRepoUrl,
|
||||||
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->deploymentType() === 'deploy_key') {
|
if ($this->deploymentType() === 'deploy_key') {
|
||||||
|
|
@ -1301,13 +1358,14 @@ public function generateGitImportCommands(string $deployment_uuid, int $pull_req
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$github_access_token = generateGithubInstallationToken($this->source);
|
$github_access_token = generateGithubInstallationToken($this->source);
|
||||||
|
$encodedToken = rawurlencode($github_access_token);
|
||||||
if ($exec_in_docker) {
|
if ($exec_in_docker) {
|
||||||
$repoUrl = "$source_html_url_scheme://x-access-token:$github_access_token@$source_html_url_host/{$customRepository}.git";
|
$repoUrl = "$source_html_url_scheme://x-access-token:$encodedToken@$source_html_url_host/{$customRepository}.git";
|
||||||
$escapedRepoUrl = escapeshellarg($repoUrl);
|
$escapedRepoUrl = escapeshellarg($repoUrl);
|
||||||
$git_clone_command = "{$git_clone_command} {$escapedRepoUrl} {$escapedBaseDir}";
|
$git_clone_command = "{$git_clone_command} {$escapedRepoUrl} {$escapedBaseDir}";
|
||||||
$fullRepoUrl = $repoUrl;
|
$fullRepoUrl = $repoUrl;
|
||||||
} else {
|
} else {
|
||||||
$repoUrl = "$source_html_url_scheme://x-access-token:$github_access_token@$source_html_url_host/{$customRepository}";
|
$repoUrl = "$source_html_url_scheme://x-access-token:$encodedToken@$source_html_url_host/{$customRepository}";
|
||||||
$escapedRepoUrl = escapeshellarg($repoUrl);
|
$escapedRepoUrl = escapeshellarg($repoUrl);
|
||||||
$git_clone_command = "{$git_clone_command} {$escapedRepoUrl} {$escapedBaseDir}";
|
$git_clone_command = "{$git_clone_command} {$escapedRepoUrl} {$escapedBaseDir}";
|
||||||
$fullRepoUrl = $repoUrl;
|
$fullRepoUrl = $repoUrl;
|
||||||
|
|
@ -1339,6 +1397,77 @@ public function generateGitImportCommands(string $deployment_uuid, int $pull_req
|
||||||
'fullRepoUrl' => $fullRepoUrl,
|
'fullRepoUrl' => $fullRepoUrl,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($this->source->getMorphClass() === \App\Models\GitlabApp::class) {
|
||||||
|
$gitlabSource = $this->source;
|
||||||
|
$private_key = data_get($gitlabSource, 'privateKey.private_key');
|
||||||
|
|
||||||
|
if ($private_key) {
|
||||||
|
$fullRepoUrl = $customRepository;
|
||||||
|
$private_key = base64_encode($private_key);
|
||||||
|
$gitlabPort = $gitlabSource->custom_port ?? 22;
|
||||||
|
$escapedCustomRepository = escapeshellarg($customRepository);
|
||||||
|
$git_clone_command_base = "GIT_SSH_COMMAND=\"ssh -o ConnectTimeout=30 -p {$gitlabPort} -o Port={$gitlabPort} -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /root/.ssh/id_rsa\" {$git_clone_command} {$escapedCustomRepository} {$escapedBaseDir}";
|
||||||
|
if ($only_checkout) {
|
||||||
|
$git_clone_command = $git_clone_command_base;
|
||||||
|
} else {
|
||||||
|
$git_clone_command = $this->setGitImportSettings($deployment_uuid, $git_clone_command_base, commit: $commit);
|
||||||
|
}
|
||||||
|
if ($exec_in_docker) {
|
||||||
|
$commands = collect([
|
||||||
|
executeInDocker($deployment_uuid, 'mkdir -p /root/.ssh'),
|
||||||
|
executeInDocker($deployment_uuid, "echo '{$private_key}' | base64 -d | tee /root/.ssh/id_rsa > /dev/null"),
|
||||||
|
executeInDocker($deployment_uuid, 'chmod 600 /root/.ssh/id_rsa'),
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
$commands = collect([
|
||||||
|
'mkdir -p /root/.ssh',
|
||||||
|
"echo '{$private_key}' | base64 -d | tee /root/.ssh/id_rsa > /dev/null",
|
||||||
|
'chmod 600 /root/.ssh/id_rsa',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($pull_request_id !== 0) {
|
||||||
|
$branch = "merge-requests/{$pull_request_id}/head:$pr_branch_name";
|
||||||
|
if ($exec_in_docker) {
|
||||||
|
$commands->push(executeInDocker($deployment_uuid, "echo 'Checking out $branch'"));
|
||||||
|
} else {
|
||||||
|
$commands->push("echo 'Checking out $branch'");
|
||||||
|
}
|
||||||
|
$git_clone_command = "{$git_clone_command} && cd {$escapedBaseDir} && GIT_SSH_COMMAND=\"ssh -o ConnectTimeout=30 -p {$gitlabPort} -o Port={$gitlabPort} -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /root/.ssh/id_rsa\" git fetch origin $branch && ".$this->buildGitCheckoutCommand($pr_branch_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($exec_in_docker) {
|
||||||
|
$commands->push(executeInDocker($deployment_uuid, $git_clone_command));
|
||||||
|
} else {
|
||||||
|
$commands->push($git_clone_command);
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'commands' => $commands->implode(' && '),
|
||||||
|
'branch' => $branch,
|
||||||
|
'fullRepoUrl' => $fullRepoUrl,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// GitLab source without private key — use URL as-is (supports user-embedded basic auth)
|
||||||
|
$fullRepoUrl = $customRepository;
|
||||||
|
$escapedCustomRepository = escapeshellarg($customRepository);
|
||||||
|
$git_clone_command = "{$git_clone_command} {$escapedCustomRepository} {$escapedBaseDir}";
|
||||||
|
$git_clone_command = $this->setGitImportSettings($deployment_uuid, $git_clone_command, public: true, commit: $commit);
|
||||||
|
|
||||||
|
if ($exec_in_docker) {
|
||||||
|
$commands->push(executeInDocker($deployment_uuid, $git_clone_command));
|
||||||
|
} else {
|
||||||
|
$commands->push($git_clone_command);
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'commands' => $commands->implode(' && '),
|
||||||
|
'branch' => $branch,
|
||||||
|
'fullRepoUrl' => $fullRepoUrl,
|
||||||
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if ($this->deploymentType() === 'deploy_key') {
|
if ($this->deploymentType() === 'deploy_key') {
|
||||||
$fullRepoUrl = $customRepository;
|
$fullRepoUrl = $customRepository;
|
||||||
|
|
|
||||||
|
|
@ -275,9 +275,9 @@ function remove_iip($text)
|
||||||
// ANSI color codes
|
// ANSI color codes
|
||||||
$text = preg_replace('/\x1b\[[0-9;]*m/', '', $text);
|
$text = preg_replace('/\x1b\[[0-9;]*m/', '', $text);
|
||||||
|
|
||||||
// Generic URLs with passwords (covers database URLs, ftp, amqp, ssh, etc.)
|
// Generic URLs with passwords (covers database URLs, ftp, amqp, ssh, git basic auth, etc.)
|
||||||
// (protocol://user:password@host → protocol://user:<REDACTED>@host)
|
// (protocol://user:password@host → protocol://user:<REDACTED>@host)
|
||||||
$text = preg_replace('/((?:postgres|mysql|mongodb|rediss?|mariadb|ftp|sftp|ssh|amqp|amqps|ldap|ldaps|s3):\/\/[^:]+:)[^@]+(@)/i', '$1'.REDACTED.'$2', $text);
|
$text = preg_replace('/((?:https?|postgres|mysql|mongodb|rediss?|mariadb|ftp|sftp|ssh|amqp|amqps|ldap|ldaps|s3):\/\/[^:]+:)[^@]+(@)/i', '$1'.REDACTED.'$2', $text);
|
||||||
|
|
||||||
// Email addresses
|
// Email addresses
|
||||||
$text = preg_replace('/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/', REDACTED, $text);
|
$text = preg_replace('/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/', REDACTED, $text);
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
use App\Models\ApplicationPreview;
|
use App\Models\ApplicationPreview;
|
||||||
use App\Models\EnvironmentVariable;
|
use App\Models\EnvironmentVariable;
|
||||||
use App\Models\GithubApp;
|
use App\Models\GithubApp;
|
||||||
|
use App\Models\GitlabApp;
|
||||||
use App\Models\InstanceSettings;
|
use App\Models\InstanceSettings;
|
||||||
use App\Models\LocalFileVolume;
|
use App\Models\LocalFileVolume;
|
||||||
use App\Models\LocalPersistentVolume;
|
use App\Models\LocalPersistentVolume;
|
||||||
|
|
@ -3522,7 +3523,7 @@ function defaultNginxConfiguration(string $type = 'static'): string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function convertGitUrl(string $gitRepository, string $deploymentType, ?GithubApp $source = null): array
|
function convertGitUrl(string $gitRepository, string $deploymentType, GithubApp|GitlabApp|null $source = null): array
|
||||||
{
|
{
|
||||||
$repository = $gitRepository;
|
$repository = $gitRepository;
|
||||||
$providerInfo = [
|
$providerInfo = [
|
||||||
|
|
@ -3542,6 +3543,7 @@ function convertGitUrl(string $gitRepository, string $deploymentType, ?GithubApp
|
||||||
// Let's try and fix that for known Git providers
|
// Let's try and fix that for known Git providers
|
||||||
switch ($source->getMorphClass()) {
|
switch ($source->getMorphClass()) {
|
||||||
case \App\Models\GithubApp::class:
|
case \App\Models\GithubApp::class:
|
||||||
|
case \App\Models\GitlabApp::class:
|
||||||
$providerInfo['host'] = Url::fromString($source->html_url)->getHost();
|
$providerInfo['host'] = Url::fromString($source->html_url)->getHost();
|
||||||
$providerInfo['port'] = $source->custom_port;
|
$providerInfo['port'] = $source->custom_port;
|
||||||
$providerInfo['user'] = $source->custom_user;
|
$providerInfo['user'] = $source->custom_user;
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
use App\Models\Application;
|
use App\Models\Application;
|
||||||
use App\Models\GithubApp;
|
use App\Models\GithubApp;
|
||||||
|
use App\Models\GitlabApp;
|
||||||
use App\Models\StandaloneDocker;
|
use App\Models\StandaloneDocker;
|
||||||
use Illuminate\Database\Seeder;
|
use Illuminate\Database\Seeder;
|
||||||
|
|
||||||
|
|
@ -98,5 +99,36 @@ public function run(): void
|
||||||
CMD ["sh", "-c", "echo Crashing in 5 seconds... && sleep 5 && exit 1"]
|
CMD ["sh", "-c", "echo Crashing in 5 seconds... && sleep 5 && exit 1"]
|
||||||
',
|
',
|
||||||
]);
|
]);
|
||||||
|
Application::create([
|
||||||
|
'uuid' => 'gitlab-deploy-key',
|
||||||
|
'name' => 'GitLab Deploy Key Example',
|
||||||
|
'fqdn' => 'http://gitlab-deploy-key.127.0.0.1.sslip.io',
|
||||||
|
'git_repository' => 'git@gitlab.com:coollabsio/php-example.git',
|
||||||
|
'git_branch' => 'main',
|
||||||
|
'build_pack' => 'nixpacks',
|
||||||
|
'ports_exposes' => '80',
|
||||||
|
'environment_id' => 1,
|
||||||
|
'destination_id' => 0,
|
||||||
|
'destination_type' => StandaloneDocker::class,
|
||||||
|
'source_id' => 1,
|
||||||
|
'source_type' => GitlabApp::class,
|
||||||
|
'private_key_id' => 1,
|
||||||
|
]);
|
||||||
|
Application::create([
|
||||||
|
'uuid' => 'gitlab-public-example',
|
||||||
|
'name' => 'GitLab Public Example',
|
||||||
|
'fqdn' => 'http://gitlab-public.127.0.0.1.sslip.io',
|
||||||
|
'git_repository' => 'https://gitlab.com/andrasbacsai/coolify-examples.git',
|
||||||
|
'base_directory' => '/astro/static',
|
||||||
|
'publish_directory' => '/dist',
|
||||||
|
'git_branch' => 'main',
|
||||||
|
'build_pack' => 'nixpacks',
|
||||||
|
'ports_exposes' => '80',
|
||||||
|
'environment_id' => 1,
|
||||||
|
'destination_id' => 0,
|
||||||
|
'destination_type' => StandaloneDocker::class,
|
||||||
|
'source_id' => 1,
|
||||||
|
'source_type' => GitlabApp::class,
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,5 +15,12 @@ public function run(): void
|
||||||
$application_1 = Application::find(1)->load(['settings']);
|
$application_1 = Application::find(1)->load(['settings']);
|
||||||
$application_1->settings->is_debug_enabled = false;
|
$application_1->settings->is_debug_enabled = false;
|
||||||
$application_1->settings->save();
|
$application_1->settings->save();
|
||||||
|
|
||||||
|
$gitlabPublic = Application::where('uuid', 'gitlab-public-example')->first();
|
||||||
|
if ($gitlabPublic) {
|
||||||
|
$gitlabPublic->load(['settings']);
|
||||||
|
$gitlabPublic->settings->is_static = true;
|
||||||
|
$gitlabPublic->settings->save();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
91
tests/Unit/GitlabSourceCommandsTest.php
Normal file
91
tests/Unit/GitlabSourceCommandsTest.php
Normal file
|
|
@ -0,0 +1,91 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use App\Models\Application;
|
||||||
|
use App\Models\GitlabApp;
|
||||||
|
use App\Models\PrivateKey;
|
||||||
|
|
||||||
|
afterEach(function () {
|
||||||
|
Mockery::close();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('generates ls-remote commands for GitLab source with private key', function () {
|
||||||
|
$deploymentUuid = 'test-deployment-uuid';
|
||||||
|
|
||||||
|
$privateKey = Mockery::mock(PrivateKey::class)->makePartial();
|
||||||
|
$privateKey->shouldReceive('getAttribute')->with('private_key')->andReturn('fake-private-key');
|
||||||
|
|
||||||
|
$gitlabSource = Mockery::mock(GitlabApp::class)->makePartial();
|
||||||
|
$gitlabSource->shouldReceive('getMorphClass')->andReturn(\App\Models\GitlabApp::class);
|
||||||
|
$gitlabSource->shouldReceive('getAttribute')->with('privateKey')->andReturn($privateKey);
|
||||||
|
$gitlabSource->shouldReceive('getAttribute')->with('private_key_id')->andReturn(1);
|
||||||
|
$gitlabSource->shouldReceive('getAttribute')->with('custom_port')->andReturn(22);
|
||||||
|
|
||||||
|
$application = Mockery::mock(Application::class)->makePartial();
|
||||||
|
$application->git_branch = 'main';
|
||||||
|
$application->shouldReceive('deploymentType')->andReturn('source');
|
||||||
|
$application->shouldReceive('customRepository')->andReturn([
|
||||||
|
'repository' => 'git@gitlab.com:user/repo.git',
|
||||||
|
'port' => 22,
|
||||||
|
]);
|
||||||
|
$application->shouldReceive('getAttribute')->with('source')->andReturn($gitlabSource);
|
||||||
|
$application->source = $gitlabSource;
|
||||||
|
|
||||||
|
$result = $application->generateGitLsRemoteCommands($deploymentUuid, false);
|
||||||
|
|
||||||
|
expect($result)->toBeArray();
|
||||||
|
expect($result)->toHaveKey('commands');
|
||||||
|
expect($result['commands'])->toContain('git ls-remote');
|
||||||
|
expect($result['commands'])->toContain('id_rsa');
|
||||||
|
expect($result['commands'])->toContain('mkdir -p /root/.ssh');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('generates ls-remote commands for GitLab source without private key', function () {
|
||||||
|
$deploymentUuid = 'test-deployment-uuid';
|
||||||
|
|
||||||
|
$gitlabSource = Mockery::mock(GitlabApp::class)->makePartial();
|
||||||
|
$gitlabSource->shouldReceive('getMorphClass')->andReturn(\App\Models\GitlabApp::class);
|
||||||
|
$gitlabSource->shouldReceive('getAttribute')->with('privateKey')->andReturn(null);
|
||||||
|
$gitlabSource->shouldReceive('getAttribute')->with('private_key_id')->andReturn(null);
|
||||||
|
|
||||||
|
$application = Mockery::mock(Application::class)->makePartial();
|
||||||
|
$application->git_branch = 'main';
|
||||||
|
$application->shouldReceive('deploymentType')->andReturn('source');
|
||||||
|
$application->shouldReceive('customRepository')->andReturn([
|
||||||
|
'repository' => 'https://gitlab.com/user/repo.git',
|
||||||
|
'port' => 22,
|
||||||
|
]);
|
||||||
|
$application->shouldReceive('getAttribute')->with('source')->andReturn($gitlabSource);
|
||||||
|
$application->source = $gitlabSource;
|
||||||
|
|
||||||
|
$result = $application->generateGitLsRemoteCommands($deploymentUuid, false);
|
||||||
|
|
||||||
|
expect($result)->toBeArray();
|
||||||
|
expect($result)->toHaveKey('commands');
|
||||||
|
expect($result['commands'])->toContain('git ls-remote');
|
||||||
|
expect($result['commands'])->toContain('https://gitlab.com/user/repo.git');
|
||||||
|
// Should NOT contain SSH key setup
|
||||||
|
expect($result['commands'])->not->toContain('id_rsa');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not return null for GitLab source type', function () {
|
||||||
|
$deploymentUuid = 'test-deployment-uuid';
|
||||||
|
|
||||||
|
$gitlabSource = Mockery::mock(GitlabApp::class)->makePartial();
|
||||||
|
$gitlabSource->shouldReceive('getMorphClass')->andReturn(\App\Models\GitlabApp::class);
|
||||||
|
$gitlabSource->shouldReceive('getAttribute')->with('privateKey')->andReturn(null);
|
||||||
|
$gitlabSource->shouldReceive('getAttribute')->with('private_key_id')->andReturn(null);
|
||||||
|
|
||||||
|
$application = Mockery::mock(Application::class)->makePartial();
|
||||||
|
$application->git_branch = 'main';
|
||||||
|
$application->shouldReceive('deploymentType')->andReturn('source');
|
||||||
|
$application->shouldReceive('customRepository')->andReturn([
|
||||||
|
'repository' => 'https://gitlab.com/user/repo.git',
|
||||||
|
'port' => 22,
|
||||||
|
]);
|
||||||
|
$application->shouldReceive('getAttribute')->with('source')->andReturn($gitlabSource);
|
||||||
|
$application->source = $gitlabSource;
|
||||||
|
|
||||||
|
$lsRemoteResult = $application->generateGitLsRemoteCommands($deploymentUuid, false);
|
||||||
|
expect($lsRemoteResult)->not->toBeNull();
|
||||||
|
expect($lsRemoteResult)->toHaveKeys(['commands', 'branch', 'fullRepoUrl']);
|
||||||
|
});
|
||||||
|
|
@ -153,6 +153,22 @@
|
||||||
expect($result)->toContain('aws_secret_access_key='.REDACTED);
|
expect($result)->toContain('aws_secret_access_key='.REDACTED);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('removes HTTPS basic auth passwords from git URLs', function () {
|
||||||
|
$testCases = [
|
||||||
|
'https://oauth2:glpat-xxxxxxxxxxxx@gitlab.com/user/repo.git' => 'https://oauth2:'.REDACTED.'@'.REDACTED,
|
||||||
|
'https://user:my-secret-token@gitlab.example.com/group/repo.git' => 'https://user:'.REDACTED.'@'.REDACTED,
|
||||||
|
'http://deploy:token123@git.internal.com/repo.git' => 'http://deploy:'.REDACTED.'@'.REDACTED,
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($testCases as $input => $notExpected) {
|
||||||
|
$result = sanitizeLogsForExport($input);
|
||||||
|
// The password should be redacted
|
||||||
|
expect($result)->not->toContain('glpat-xxxxxxxxxxxx');
|
||||||
|
expect($result)->not->toContain('my-secret-token');
|
||||||
|
expect($result)->not->toContain('token123');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
it('removes generic URL passwords', function () {
|
it('removes generic URL passwords', function () {
|
||||||
$testCases = [
|
$testCases = [
|
||||||
'ftp://user:ftppass@ftp.example.com/path' => 'ftp://user:'.REDACTED.'@ftp.example.com/path',
|
'ftp://user:ftppass@ftp.example.com/path' => 'ftp://user:'.REDACTED.'@ftp.example.com/path',
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue