diff --git a/app/Http/Middleware/CanCreateResources.php b/app/Http/Middleware/CanCreateResources.php index ba0ab67c1..874feb347 100644 --- a/app/Http/Middleware/CanCreateResources.php +++ b/app/Http/Middleware/CanCreateResources.php @@ -12,15 +12,14 @@ class CanCreateResources /** * Handle an incoming request. * - * @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next + * @param Closure(Request): (Response) $next */ public function handle(Request $request, Closure $next): Response { - return $next($request); - // if (! Gate::allows('createAnyResource')) { - // abort(403, 'You do not have permission to create resources.'); - // } + if (! Gate::allows('createAnyResource')) { + abort(403, 'You do not have permission to create resources.'); + } - // return $next($request); + return $next($request); } } diff --git a/app/Livewire/Project/New/DockerCompose.php b/app/Livewire/Project/New/DockerCompose.php index 2cf0659bf..55ed8941c 100644 --- a/app/Livewire/Project/New/DockerCompose.php +++ b/app/Livewire/Project/New/DockerCompose.php @@ -5,11 +5,14 @@ use App\Models\EnvironmentVariable; use App\Models\Project; use App\Models\Service; +use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Livewire\Component; use Symfony\Component\Yaml\Yaml; class DockerCompose extends Component { + use AuthorizesRequests; + public string $dockerComposeRaw = ''; public string $envFile = ''; @@ -30,6 +33,8 @@ public function mount() public function submit() { try { + $this->authorize('create', Service::class); + $this->validate([ 'dockerComposeRaw' => 'required', ]); diff --git a/app/Livewire/Project/New/DockerImage.php b/app/Livewire/Project/New/DockerImage.php index de86bea4a..68ee0d055 100644 --- a/app/Livewire/Project/New/DockerImage.php +++ b/app/Livewire/Project/New/DockerImage.php @@ -6,10 +6,13 @@ use App\Models\Project; use App\Services\DockerImageParser; use App\Support\ValidationPatterns; +use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Livewire\Component; class DockerImage extends Component { + use AuthorizesRequests; + public string $imageName = ''; public string $imageTag = ''; @@ -80,6 +83,8 @@ public function updatedImageName(): void public function submit() { + $this->authorize('create', Application::class); + $this->validate([ 'imageName' => ValidationPatterns::dockerImageNameRules(required: true), 'imageTag' => ValidationPatterns::dockerImageTagRules(), diff --git a/app/Livewire/Project/New/EmptyProject.php b/app/Livewire/Project/New/EmptyProject.php index 7c92ce96b..b2187c615 100644 --- a/app/Livewire/Project/New/EmptyProject.php +++ b/app/Livewire/Project/New/EmptyProject.php @@ -3,12 +3,17 @@ namespace App\Livewire\Project\New; use App\Models\Project; +use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Livewire\Component; class EmptyProject extends Component { + use AuthorizesRequests; + public function createEmptyProject() { + $this->authorize('create', Project::class); + $project = Project::create([ 'name' => generate_random_name(), 'team_id' => currentTeam()->id, diff --git a/app/Livewire/Project/New/GithubPrivateRepository.php b/app/Livewire/Project/New/GithubPrivateRepository.php index 1c9c8e896..35e9b186e 100644 --- a/app/Livewire/Project/New/GithubPrivateRepository.php +++ b/app/Livewire/Project/New/GithubPrivateRepository.php @@ -7,6 +7,7 @@ use App\Models\Project; use App\Rules\ValidGitBranch; use App\Support\ValidationPatterns; +use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Illuminate\Support\Facades\Http; use Illuminate\Support\Facades\Route; use Livewire\Attributes\Locked; @@ -14,6 +15,8 @@ class GithubPrivateRepository extends Component { + use AuthorizesRequests; + public $current_step = 'github_apps'; public $github_apps; @@ -169,6 +172,8 @@ protected function loadBranchByPage() public function submit() { try { + $this->authorize('create', Application::class); + // Validate git repository parts and branch $validator = validator([ 'selected_repository_owner' => $this->selected_repository_owner, diff --git a/app/Livewire/Project/New/GithubPrivateRepositoryDeployKey.php b/app/Livewire/Project/New/GithubPrivateRepositoryDeployKey.php index 045ddc6cb..d5b4bbef8 100644 --- a/app/Livewire/Project/New/GithubPrivateRepositoryDeployKey.php +++ b/app/Livewire/Project/New/GithubPrivateRepositoryDeployKey.php @@ -10,12 +10,15 @@ use App\Rules\ValidGitBranch; use App\Rules\ValidGitRepositoryUrl; use App\Support\ValidationPatterns; +use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Illuminate\Support\Str; use Livewire\Component; use Spatie\Url\Url; class GithubPrivateRepositoryDeployKey extends Component { + use AuthorizesRequests; + public $current_step = 'private_keys'; public $parameters; @@ -128,6 +131,8 @@ public function setPrivateKey($private_key_id) public function submit() { + $this->authorize('create', Application::class); + $this->validate(); try { $destination_uuid = $this->query['destination'] ?? null; diff --git a/app/Livewire/Project/New/PublicGitRepository.php b/app/Livewire/Project/New/PublicGitRepository.php index 9fe630d63..4fddd744b 100644 --- a/app/Livewire/Project/New/PublicGitRepository.php +++ b/app/Livewire/Project/New/PublicGitRepository.php @@ -6,16 +6,18 @@ use App\Models\GithubApp; use App\Models\GitlabApp; use App\Models\Project; -use App\Models\Service; use App\Rules\ValidGitBranch; use App\Rules\ValidGitRepositoryUrl; use App\Support\ValidationPatterns; use Carbon\Carbon; +use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Livewire\Component; use Spatie\Url\Url; class PublicGitRepository extends Component { + use AuthorizesRequests; + public string $repository_url; public int $port = 3000; @@ -260,6 +262,8 @@ private function getBranch() public function submit() { try { + $this->authorize('create', Application::class); + $this->validate(); // Additional validation for git repository and branch @@ -295,33 +299,6 @@ public function submit() $project = Project::ownedByCurrentTeam()->where('uuid', $project_uuid)->firstOrFail(); $environment = $project->environments()->where('uuid', $environment_uuid)->firstOrFail(); - if ($this->build_pack === 'dockercompose' && isDev() && $this->new_compose_services) { - $server = $destination->server; - $new_service = [ - 'name' => 'service'.str()->random(10), - 'docker_compose_raw' => 'coolify', - 'environment_id' => $environment->id, - 'server_id' => $server->id, - ]; - if ($this->git_source === 'other') { - $new_service['git_repository'] = $this->git_repository; - $new_service['git_branch'] = $this->git_branch; - } else { - $new_service['git_repository'] = $this->git_repository; - $new_service['git_branch'] = $this->git_branch; - $new_service['source_id'] = $this->git_source->id; - $new_service['source_type'] = $this->git_source->getMorphClass(); - } - $service = Service::create($new_service); - - return redirect()->route('project.service.configuration', [ - 'service_uuid' => $service->uuid, - 'environment_uuid' => $environment->uuid, - 'project_uuid' => $project->uuid, - ]); - - return; - } if ($this->git_source === 'other') { $application_init = [ 'name' => generate_random_name(), diff --git a/app/Livewire/Project/New/SimpleDockerfile.php b/app/Livewire/Project/New/SimpleDockerfile.php index 5a84343fd..3328c5db3 100644 --- a/app/Livewire/Project/New/SimpleDockerfile.php +++ b/app/Livewire/Project/New/SimpleDockerfile.php @@ -5,10 +5,13 @@ use App\Models\Application; use App\Models\GithubApp; use App\Models\Project; +use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Livewire\Component; class SimpleDockerfile extends Component { + use AuthorizesRequests; + public string $dockerfile = ''; public array $parameters; @@ -29,6 +32,8 @@ public function mount() public function submit() { + $this->authorize('create', Application::class); + $this->validate([ 'dockerfile' => 'required', ]); diff --git a/app/Livewire/Project/Resource/Create.php b/app/Livewire/Project/Resource/Create.php index 4619ddf37..e0b45eea0 100644 --- a/app/Livewire/Project/Resource/Create.php +++ b/app/Livewire/Project/Resource/Create.php @@ -4,16 +4,20 @@ use App\Models\EnvironmentVariable; use App\Models\Service; +use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Livewire\Component; class Create extends Component { + use AuthorizesRequests; + public $type; public $project; public function mount() { + $this->authorize('createAnyResource'); $type = str(request()->query('type')); $destination_uuid = request()->query('destination'); diff --git a/tests/Feature/Authorization/ResourceCreationAuthorizationTest.php b/tests/Feature/Authorization/ResourceCreationAuthorizationTest.php new file mode 100644 index 000000000..eb4636d3d --- /dev/null +++ b/tests/Feature/Authorization/ResourceCreationAuthorizationTest.php @@ -0,0 +1,133 @@ + 'array', + 'cache.default' => 'array', + ]); + + InstanceSettings::query()->forceCreate(['id' => 0]); + + $this->team = Team::factory()->create(); + + $this->admin = User::factory()->create(); + $this->admin->teams()->attach($this->team, ['role' => 'admin']); + + $this->member = User::factory()->create(); + $this->member->teams()->attach($this->team, ['role' => 'member']); + + $this->project = Project::create([ + 'uuid' => (string) Str::uuid(), + 'name' => 'Test Project', + 'team_id' => $this->team->id, + ]); + + $this->environment = $this->project->environments()->first(); + + $keyId = DB::table('private_keys')->insertGetId([ + 'uuid' => (string) Str::uuid(), + 'name' => 'Test Key', + 'private_key' => 'test-key', + 'team_id' => $this->team->id, + 'created_at' => now(), + 'updated_at' => now(), + ]); + + $this->server = Server::factory()->create([ + 'team_id' => $this->team->id, + 'private_key_id' => $keyId, + ]); + + StandaloneDocker::withoutEvents(function () { + $this->destination = StandaloneDocker::firstOrCreate( + ['server_id' => $this->server->id, 'network' => 'coolify'], + ['uuid' => (string) Str::uuid(), 'name' => 'test-docker'] + ); + }); +}); + +test('member cannot pass create resources middleware', function () { + $this->actingAs($this->member); + session(['currentTeam' => $this->team]); + + $middleware = new CanCreateResources; + $request = Request::create('/project/new', 'GET'); + + expect(fn () => $middleware->handle($request, fn () => response('ok'))) + ->toThrow(HttpException::class, 'You do not have permission to create resources.'); +}); + +test('admin can pass create resources middleware', function () { + $this->actingAs($this->admin); + session(['currentTeam' => $this->team]); + + $middleware = new CanCreateResources; + $request = Request::create('/project/new', 'GET'); + $response = $middleware->handle($request, fn () => response('ok')); + + expect($response->getStatusCode())->toBe(200); +}); + +test('member cannot create docker compose service through livewire action', function () { + $this->actingAs($this->member); + session(['currentTeam' => $this->team]); + + Livewire::test(DockerCompose::class) + ->set('parameters', [ + 'project_uuid' => $this->project->uuid, + 'environment_uuid' => $this->environment->uuid, + ]) + ->set('query', ['destination' => $this->destination->uuid]) + ->set('dockerComposeRaw', <<<'YAML' +services: + app: + image: alpine +YAML) + ->call('submit') + ->assertDispatched('error'); + + expect(Service::query()->count())->toBe(0); +}); + +test('public git docker compose creates an application in local mode', function () { + config(['app.env' => 'local']); + + $this->actingAs($this->admin); + session(['currentTeam' => $this->team]); + + Livewire::test(PublicGitRepository::class) + ->set('parameters', [ + 'project_uuid' => $this->project->uuid, + 'environment_uuid' => $this->environment->uuid, + ]) + ->set('query', ['destination' => $this->destination->uuid]) + ->set('repository_url', 'https://github.com/coollabsio/coolify') + ->set('git_repository', 'https://github.com/coollabsio/coolify') + ->set('git_branch', 'main') + ->set('build_pack', 'dockercompose') + ->set('new_compose_services', true) + ->call('submit'); + + expect(Application::query()->count())->toBe(1) + ->and(Service::query()->count())->toBe(0); +});