From 59cd5b0d72efbe8b2e64ce0346ef1463e0fc4c45 Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Fri, 21 Aug 2026 23:35:24 +0200 Subject: [PATCH] fix(api): allow system-wide GitHub Apps across teams (#11453) --- .../Api/ApplicationsController.php | 7 ++- .../ApplicationBuildSecretsSettingApiTest.php | 54 +++++++++++++++++++ 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/app/Http/Controllers/Api/ApplicationsController.php b/app/Http/Controllers/Api/ApplicationsController.php index 601c364de..285cf8e2f 100644 --- a/app/Http/Controllers/Api/ApplicationsController.php +++ b/app/Http/Controllers/Api/ApplicationsController.php @@ -1604,7 +1604,12 @@ private function create_application(Request $request, $type) if ($return instanceof JsonResponse) { return $return; } - $githubApp = GithubApp::whereTeamId($teamId)->where('uuid', $githubAppUuid)->first(); + $githubApp = GithubApp::where('uuid', $githubAppUuid) + ->where(function ($query) use ($teamId) { + $query->where('team_id', $teamId) + ->orWhere('is_system_wide', true); + }) + ->first(); if (! $githubApp) { return response()->json(['message' => 'Github App not found.'], 404); } diff --git a/tests/Feature/Api/ApplicationBuildSecretsSettingApiTest.php b/tests/Feature/Api/ApplicationBuildSecretsSettingApiTest.php index 3b3721545..1847c0022 100644 --- a/tests/Feature/Api/ApplicationBuildSecretsSettingApiTest.php +++ b/tests/Feature/Api/ApplicationBuildSecretsSettingApiTest.php @@ -254,4 +254,58 @@ function buildSecretsGithubPrivateKey(): string expect($application->settings->use_build_secrets)->toBeTrue(); }); + + test('creates an application from a system-wide GitHub App owned by another team', function () { + $ownerTeam = Team::factory()->create(); + $privateKey = PrivateKey::create([ + 'name' => 'System-wide GitHub App Key', + 'private_key' => buildSecretsGithubPrivateKey(), + 'team_id' => $ownerTeam->id, + ]); + $githubApp = GithubApp::create([ + 'name' => 'System-wide GitHub App', + 'api_url' => 'https://api.github.com', + 'html_url' => 'https://github.com', + 'app_id' => 54321, + 'installation_id' => 9876, + 'client_id' => 'system-wide-client-id', + 'client_secret' => 'system-wide-client-secret', + 'webhook_secret' => 'system-wide-webhook-secret', + 'private_key_id' => $privateKey->id, + 'team_id' => $ownerTeam->id, + 'is_system_wide' => true, + 'is_public' => false, + ]); + + Http::fake([ + 'https://api.github.com/zen' => Http::response('Keep it logically awesome.', 200, [ + 'Date' => now()->toRfc7231String(), + ]), + 'https://api.github.com/app/installations/9876/access_tokens' => Http::response([ + 'token' => 'github-installation-token', + ], 201), + 'https://api.github.com/repos/coolify/system-wide-test' => Http::response([ + 'id' => 654321, + ]), + ]); + + $response = $this->withHeaders(buildSecretsApiHeaders($this->bearerToken)) + ->postJson('/api/v1/applications/private-github-app', [ + 'project_uuid' => $this->project->uuid, + 'environment_uuid' => $this->environment->uuid, + 'server_uuid' => $this->server->uuid, + 'github_app_uuid' => $githubApp->uuid, + 'git_repository' => 'coolify/system-wide-test', + 'git_branch' => 'main', + 'build_pack' => 'nixpacks', + 'ports_exposes' => '3000', + 'autogenerate_domain' => false, + ]) + ->assertCreated(); + + $application = Application::where('uuid', $response->json('uuid'))->firstOrFail(); + + expect($application->source_id)->toBe($githubApp->id) + ->and($application->environment_id)->toBe($this->environment->id); + }); });