fix(github): allow system-wide private apps across teams

Use the shared GitHub app scope when listing and loading private apps so system-wide apps owned by another team remain available. Update coverage for mounting and loading repositories through those apps.
This commit is contained in:
Andras Bacsai 2026-05-26 17:36:02 +02:00
parent 9f29df4cc3
commit d443758b03
2 changed files with 38 additions and 8 deletions

View file

@ -71,7 +71,7 @@ public function mount()
$this->parameters = get_route_parameters(); $this->parameters = get_route_parameters();
$this->query = request()->query(); $this->query = request()->query();
$this->repositories = $this->branches = collect(); $this->repositories = $this->branches = collect();
$this->github_apps = GithubApp::where('team_id', currentTeam()->id) $this->github_apps = GithubApp::ownedByCurrentTeam()
->where('is_public', false) ->where('is_public', false)
->whereNotNull('app_id') ->whereNotNull('app_id')
->get(); ->get();
@ -106,7 +106,7 @@ public function loadRepositories(int $github_app_id): void
$this->total_branches_count = 0; $this->total_branches_count = 0;
$this->page = 1; $this->page = 1;
$this->selected_github_app_id = $github_app_id; $this->selected_github_app_id = $github_app_id;
$this->github_app = GithubApp::where('team_id', currentTeam()->id) $this->github_app = GithubApp::ownedByCurrentTeam()
->where('is_public', false) ->where('is_public', false)
->whereNotNull('app_id') ->whereNotNull('app_id')
->findOrFail($github_app_id); ->findOrFail($github_app_id);

View file

@ -127,7 +127,7 @@ function githubPrivateRepositoryTestPrivateKeyForTeam(Team $team): PrivateKey
Http::assertNothingSent(); Http::assertNothingSent();
}); });
test('loadRepositories does not mint tokens for another teams system wide github app', function () { test('mount lists another teams system wide github app', function () {
$victimTeam = Team::factory()->create(); $victimTeam = Team::factory()->create();
$victimPrivateKey = githubPrivateRepositoryTestPrivateKeyForTeam($victimTeam); $victimPrivateKey = githubPrivateRepositoryTestPrivateKeyForTeam($victimTeam);
$systemWideGithubApp = GithubApp::create([ $systemWideGithubApp = GithubApp::create([
@ -147,13 +147,43 @@ function githubPrivateRepositoryTestPrivateKeyForTeam(Team $team): PrivateKey
'is_system_wide' => true, 'is_system_wide' => true,
]); ]);
Http::fake(); $component = Livewire::test(GithubPrivateRepository::class, ['type' => 'private-gh-app']);
expect(fn () => Livewire::test(GithubPrivateRepository::class, ['type' => 'private-gh-app']) expect($component->get('github_apps')->pluck('id')->all())
->toContain($this->githubApp->id)
->toContain($systemWideGithubApp->id);
});
test('loadRepositories can use another teams system wide github app', function () {
$victimTeam = Team::factory()->create();
$victimPrivateKey = githubPrivateRepositoryTestPrivateKeyForTeam($victimTeam);
$systemWideGithubApp = GithubApp::create([
'name' => 'System Wide GitHub App',
'api_url' => 'https://api.github.com',
'html_url' => 'https://github.com',
'custom_user' => 'git',
'custom_port' => 22,
'app_id' => 54321,
'installation_id' => 67890,
'client_id' => 'system-client-id',
'client_secret' => 'system-client-secret',
'webhook_secret' => 'system-webhook-secret',
'private_key_id' => $victimPrivateKey->id,
'team_id' => $victimTeam->id,
'is_public' => false,
'is_system_wide' => true,
]);
$repos = [
['id' => 1, 'name' => 'system-repo', 'owner' => ['login' => 'testuser']],
];
fakeGithubHttp($repos);
Livewire::test(GithubPrivateRepository::class, ['type' => 'private-gh-app'])
->call('loadRepositories', $systemWideGithubApp->id) ->call('loadRepositories', $systemWideGithubApp->id)
)->toThrow(ModelNotFoundException::class); ->assertSet('current_step', 'repository')
->assertSet('total_repositories_count', 1)
Http::assertNothingSent(); ->assertSet('selected_repository_id', 1);
}); });
test('github installation token is not stored as public component state', function () { test('github installation token is not stored as public component state', function () {