diff --git a/app/Jobs/ApplicationDeploymentJob.php b/app/Jobs/ApplicationDeploymentJob.php index 1088e6a253..961228f949 100644 --- a/app/Jobs/ApplicationDeploymentJob.php +++ b/app/Jobs/ApplicationDeploymentJob.php @@ -237,7 +237,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue $this->deployment_uuid = $this->application_deployment_queue->deployment_uuid; $this->pull_request_id = $this->application_deployment_queue->pull_request_id; - $this->commit = $this->application_deployment_queue->commit; + $this->commit = validateGitRef($this->application_deployment_queue->commit, 'deployment commit'); $this->rollback = $this->application_deployment_queue->rollback; $this->disableBuildCache = $this->application->settings->disable_build_cache; $this->force_rebuild = $this->application_deployment_queue->force_rebuild; diff --git a/bootstrap/helpers/applications.php b/bootstrap/helpers/applications.php index 2fb0bb3f53..7743304c34 100644 --- a/bootstrap/helpers/applications.php +++ b/bootstrap/helpers/applications.php @@ -14,6 +14,7 @@ use Spatie\Url\Url; function queue_application_deployment(Application $application, string $deployment_uuid, ?int $pull_request_id = 0, ?string $commit = null, bool $force_rebuild = false, bool $is_webhook = false, bool $is_api = false, bool $restart_only = false, ?string $git_type = null, bool $no_questions_asked = false, ?Server $server = null, ?StandaloneDocker $destination = null, bool $only_this_server = false, bool $rollback = false, ?string $docker_registry_image_tag = null) { $commit = $commit ?: ($application->git_commit_sha ?: 'HEAD'); + $commit = validateGitRef($commit, 'deployment commit'); $application_id = $application->id; $deployment_link = Url::fromString($application->link()."/deployment/{$deployment_uuid}"); $deployment_url = $deployment_link->getPath(); diff --git a/tests/Feature/QueueApplicationDeploymentCommitTest.php b/tests/Feature/QueueApplicationDeploymentCommitTest.php index 8273a5c61c..f5a8bb110e 100644 --- a/tests/Feature/QueueApplicationDeploymentCommitTest.php +++ b/tests/Feature/QueueApplicationDeploymentCommitTest.php @@ -45,6 +45,53 @@ function makeApplication(int $environmentId, int $destinationId, ?string $gitCom } describe('queue_application_deployment commit resolution', function () { + test('rejects a commit with disallowed characters before creating a deployment', function () { + $application = makeApplication($this->environment->id, $this->destination->id, 'HEAD'); + + expect(fn () => queue_application_deployment( + application: $application, + deployment_uuid: 'invalid-queued-commit', + commit: 'abc;not-a-ref', + is_webhook: true, + ))->toThrow(Exception::class, 'Invalid deployment commit'); + + $this->assertDatabaseMissing('application_deployment_queue', [ + 'deployment_uuid' => 'invalid-queued-commit', + ]); + Bus::assertNotDispatched(ApplicationDeploymentJob::class); + }); + + test('validates the application fallback commit before creating a deployment', function () { + $application = makeApplication( + $this->environment->id, + $this->destination->id, + '$(not-a-ref)', + ); + + expect(fn () => queue_application_deployment( + application: $application, + deployment_uuid: 'invalid-fallback-commit', + ))->toThrow(Exception::class, 'Invalid deployment commit'); + + $this->assertDatabaseMissing('application_deployment_queue', [ + 'deployment_uuid' => 'invalid-fallback-commit', + ]); + Bus::assertNotDispatched(ApplicationDeploymentJob::class); + }); + + test('rejects a stored queue commit with disallowed characters', function () { + $application = makeApplication($this->environment->id, $this->destination->id, 'HEAD'); + queue_application_deployment($application, 'stored-invalid-commit'); + + $deployment = ApplicationDeploymentQueue::query() + ->where('deployment_uuid', 'stored-invalid-commit') + ->sole(); + $deployment->update(['commit' => "abc\nnot-a-ref"]); + + expect(fn () => new ApplicationDeploymentJob($deployment->id)) + ->toThrow(Exception::class, 'Invalid deployment commit'); + }); + test('records a team audit event when a user queues a deployment', function () { $user = User::factory()->create(); $this->team->members()->attach($user, ['role' => 'owner']);