From 507a8afa20016512ba5f7e24f4abc4c36ee5f476 Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Mon, 15 Jun 2026 12:55:29 +0200 Subject: [PATCH] fix(github): sync app slug before generating installation path --- app/Livewire/Source/Github/Change.php | 2 ++ bootstrap/helpers/github.php | 2 -- tests/Feature/GithubSourceChangeTest.php | 43 +++++++++++++++++++++--- 3 files changed, 40 insertions(+), 7 deletions(-) diff --git a/app/Livewire/Source/Github/Change.php b/app/Livewire/Source/Github/Change.php index 17835258b..682333aa6 100644 --- a/app/Livewire/Source/Github/Change.php +++ b/app/Livewire/Source/Github/Change.php @@ -204,6 +204,8 @@ public function checkPermissions() return; } + syncGithubAppName($this->github_app); + GithubAppPermissionJob::dispatchSync($this->github_app); $this->github_app->refresh()->makeVisible('client_secret')->makeVisible('webhook_secret'); $this->syncData(false); diff --git a/bootstrap/helpers/github.php b/bootstrap/helpers/github.php index a2feb3360..978e9ddae 100644 --- a/bootstrap/helpers/github.php +++ b/bootstrap/helpers/github.php @@ -192,8 +192,6 @@ function syncGithubAppName(GithubApp $source, bool $throw = false): ?string function getInstallationPath(GithubApp $source): string { - syncGithubAppName($source); - $name = str(Str::kebab($source->name)); $baseUrl = rtrim($source->html_url, '/'); $host = parse_url($source->html_url, PHP_URL_HOST); diff --git a/tests/Feature/GithubSourceChangeTest.php b/tests/Feature/GithubSourceChangeTest.php index 0b8030050..70d4e101d 100644 --- a/tests/Feature/GithubSourceChangeTest.php +++ b/tests/Feature/GithubSourceChangeTest.php @@ -171,10 +171,8 @@ function validPrivateKey(): string ]); }); - test('installation path synchronizes github app slug before generating the url', function () { - Http::fake([ - 'https://api.github.com/app' => Http::response(['slug' => 'actual-github-slug']), - ]); + test('installation path is pure and never calls github or mutates the app', function () { + Http::fake(); $privateKey = PrivateKey::create([ 'name' => 'github-app-local-name', @@ -198,7 +196,42 @@ function validPrivateKey(): string $installationUrl = getInstallationPath($githubApp); - expect($installationUrl)->toStartWith('https://octocorp.ghe.com/apps/acme-enterprise/actual-github-slug/installations/new?') + Http::assertNothingSent(); + + expect($installationUrl)->toStartWith('https://octocorp.ghe.com/apps/acme-enterprise/local-display-name/installations/new?') + ->and($githubApp->refresh()->name)->toBe('Local Display Name') + ->and($privateKey->refresh()->name)->toBe('github-app-local-name'); + }); + + test('syncGithubAppName persists the github slug and renames the private key', function () { + Http::fake([ + '*/app' => Http::response(['slug' => 'actual-github-slug']), + '*/zen' => Http::response('Keep it logically awesome.'), + ]); + + $privateKey = PrivateKey::create([ + 'name' => 'github-app-local-name', + 'private_key' => validPrivateKey(), + 'team_id' => $this->team->id, + 'is_git_related' => true, + ]); + + $githubApp = GithubApp::create([ + 'name' => 'Local Display Name', + 'organization' => 'acme-enterprise', + 'api_url' => 'https://api.github.com', + 'html_url' => 'https://octocorp.ghe.com', + 'custom_user' => 'git', + 'custom_port' => 22, + 'app_id' => 12345, + 'private_key_id' => $privateKey->id, + 'team_id' => $this->team->id, + 'is_system_wide' => false, + ]); + + $appSlug = syncGithubAppName($githubApp, true); + + expect($appSlug)->toBe('actual-github-slug') ->and($githubApp->refresh()->name)->toBe('actual-github-slug') ->and($privateKey->refresh()->name)->toBe('github-app-actual-github-slug'); });