diff --git a/app/Models/Application.php b/app/Models/Application.php index 809b5336a..b2f852f15 100644 --- a/app/Models/Application.php +++ b/app/Models/Application.php @@ -1801,7 +1801,7 @@ class Application extends BaseModel $git_clone_command = $this->applyGitConfigOptionsToCloneCommand($git_clone_command, $gitConfigOptions); } $git_clone_command = $this->setGitImportSettings($deployment_uuid, $git_clone_command, public: true, commit: $commit, gitConfigOptions: $gitConfigOptions); - $otherSshCommand = "ssh -o ConnectTimeout=30 -p {$customPort} -o Port={$customPort} -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i {$customSshKeyLocation} -o IdentitiesOnly=yes"; + $otherSshCommand = "ssh -o ConnectTimeout=30 -p {$customPort} -o Port={$customPort} -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /root/.ssh/id_rsa"; if ($pull_request_id !== 0) { $gitCommand = isset($gitConfigOptions) ? "git {$gitConfigOptions}" : 'git'; diff --git a/tests/Unit/DeployKeyDedicatedPathTest.php b/tests/Unit/DeployKeyDedicatedPathTest.php index 9fb4e1b1d..a3373f42a 100644 --- a/tests/Unit/DeployKeyDedicatedPathTest.php +++ b/tests/Unit/DeployKeyDedicatedPathTest.php @@ -110,3 +110,80 @@ it('writes a deploy key to a per-deployment path and cleans it up when cloning o ->toContain("trap 'rm -f {$keyPath}' EXIT") ->not->toContain('tee /root/.ssh/id_rsa >'); }); + +it('writes a GitLab source private key to a per-deployment path and cleans it up when cloning on the host', function () use ($keyPath) { + $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(GitlabApp::class); + $gitlabSource->shouldReceive('getAttribute')->with('html_url')->andReturn('https://gitlab.com'); + $gitlabSource->shouldReceive('getAttribute')->with('privateKey')->andReturn($privateKey); + $gitlabSource->shouldReceive('getAttribute')->with('custom_port')->andReturn(22); + + $settings = Mockery::mock(ApplicationSetting::class)->makePartial(); + $settings->shouldReceive('getAttribute')->with('is_git_shallow_clone_enabled')->andReturn(false); + $settings->shouldReceive('getAttribute')->with('is_git_submodules_enabled')->andReturn(false); + $settings->shouldReceive('getAttribute')->with('is_git_lfs_enabled')->andReturn(false); + + $application = Mockery::mock(Application::class)->makePartial(); + $application->git_branch = 'main'; + $application->source = $gitlabSource; + $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->shouldReceive('getAttribute')->with('settings')->andReturn($settings); + $application->shouldReceive('getAttribute')->with('git_commit_sha')->andReturn('HEAD'); + + $result = $application->generateGitImportCommands('test-deployment-uuid', 0, null, false); + + expect($result['commands']) + ->toContain("tee {$keyPath}") + ->toContain("-i {$keyPath} -o IdentitiesOnly=yes") + ->toContain("trap 'rm -f {$keyPath}' EXIT") + ->not->toContain('tee /root/.ssh/id_rsa >'); +}); + +it('uses the per-deployment deploy key for pull request fetches', function () use ($keyPath) { + $privateKey = Mockery::mock(PrivateKey::class)->makePartial(); + $privateKey->shouldReceive('getAttribute')->with('private_key')->andReturn('fake-private-key'); + + $settings = Mockery::mock(ApplicationSetting::class)->makePartial(); + $settings->shouldReceive('getAttribute')->with('is_git_shallow_clone_enabled')->andReturn(false); + $settings->shouldReceive('getAttribute')->with('is_git_submodules_enabled')->andReturn(false); + $settings->shouldReceive('getAttribute')->with('is_git_lfs_enabled')->andReturn(false); + + $application = Mockery::mock(Application::class)->makePartial(); + $application->git_branch = 'main'; + $application->shouldReceive('deploymentType')->andReturn('deploy_key'); + $application->shouldReceive('customRepository')->andReturn(['repository' => 'git@github.com:user/repo.git', 'port' => 22]); + $application->shouldReceive('getAttribute')->with('private_key')->andReturn($privateKey); + $application->shouldReceive('getAttribute')->with('settings')->andReturn($settings); + $application->shouldReceive('getAttribute')->with('git_commit_sha')->andReturn('HEAD'); + + $result = $application->generateGitImportCommands('test-deployment-uuid', 123, 'github', false); + + expect($result['commands']) + ->toContain("GIT_SSH_COMMAND=\"ssh -o ConnectTimeout=30 -p 22 -o Port=22 -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i {$keyPath} -o IdentitiesOnly=yes\" git fetch origin pull/123/head:pr-123-coolify") + ->not->toContain('GIT_SSH_COMMAND="ssh -o ConnectTimeout=30 -p 22 -o Port=22 -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /root/.ssh/id_rsa" git fetch origin pull/123/head:pr-123-coolify'); +}); + +it('does not force a missing per-deployment key for other repository pull request fetches', function () use ($keyPath) { + $settings = Mockery::mock(ApplicationSetting::class)->makePartial(); + $settings->shouldReceive('getAttribute')->with('is_git_shallow_clone_enabled')->andReturn(false); + $settings->shouldReceive('getAttribute')->with('is_git_submodules_enabled')->andReturn(false); + $settings->shouldReceive('getAttribute')->with('is_git_lfs_enabled')->andReturn(false); + + $application = Mockery::mock(Application::class)->makePartial(); + $application->git_branch = 'main'; + $application->shouldReceive('deploymentType')->andReturn('other'); + $application->shouldReceive('customRepository')->andReturn(['repository' => 'git@github.com:user/repo.git', 'port' => 22]); + $application->shouldReceive('getAttribute')->with('settings')->andReturn($settings); + $application->shouldReceive('getAttribute')->with('git_commit_sha')->andReturn('HEAD'); + + $result = $application->generateGitImportCommands('test-deployment-uuid', 123, 'github', false); + + expect($result['commands']) + ->toContain('GIT_SSH_COMMAND="ssh -o ConnectTimeout=30 -p 22 -o Port=22 -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /root/.ssh/id_rsa" git fetch origin pull/123/head:pr-123-coolify') + ->not->toContain($keyPath); +}); diff --git a/tests/Unit/GitSubmoduleCredentialTest.php b/tests/Unit/GitSubmoduleCredentialTest.php index 5ac5c501a..d22e1ad4c 100644 --- a/tests/Unit/GitSubmoduleCredentialTest.php +++ b/tests/Unit/GitSubmoduleCredentialTest.php @@ -156,7 +156,7 @@ describe('Git submodule credential propagation', function () { exec_in_docker: false, ); - $sshCommand = 'ssh -o ConnectTimeout=30 -p 22 -o Port=22 -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /root/.ssh/id_rsa'; + $sshCommand = 'ssh -o ConnectTimeout=30 -p 22 -o Port=22 -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /root/.ssh/id_rsa_coolify_test-uuid -o IdentitiesOnly=yes'; expect($result['commands']) ->toContain('GIT_SSH_COMMAND="'.$sshCommand.'" git fetch origin merge-requests/123/head:pr-123-coolify')