Skip to content

Commit af19bd0

Browse files
andrasbacsaiclaude
andcommitted
fix(sources): validate the selected private key on source settings
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 1f7a011 commit af19bd0

4 files changed

Lines changed: 97 additions & 2 deletions

File tree

‎app/Livewire/Source/Github/Change.php‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use Illuminate\Support\Facades\Cache;
1111
use Illuminate\Support\Facades\Http;
1212
use Illuminate\Support\Str;
13+
use Illuminate\Validation\Rule;
1314
use Illuminate\Validation\ValidationException;
1415
use Livewire\Component;
1516

@@ -102,7 +103,7 @@ protected function rules(): array
102103
'contents' => 'nullable|string',
103104
'metadata' => 'nullable|string',
104105
'pullRequests' => 'nullable|string',
105-
'privateKeyId' => 'nullable|int',
106+
'privateKeyId' => ['nullable', 'integer', Rule::exists('private_keys', 'id')->where('team_id', $this->github_app->team_id)],
106107
'webhook_endpoint' => ['required', 'string', 'url'],
107108
'custom_webhook_endpoint' => ['nullable', 'string', 'url'],
108109
'use_custom_webhook_endpoint' => ['required', 'bool'],
@@ -449,6 +450,8 @@ public function instantSave()
449450
try {
450451
$this->authorize('update', $this->github_app);
451452

453+
$this->validateOnly('privateKeyId');
454+
452455
$this->syncData(true);
453456
$this->github_app->save();
454457
$this->isConnected = $this->github_app->isConnected();

‎app/Livewire/Source/Gitlab/Change.php‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use Illuminate\Support\Facades\Gate;
1111
use Illuminate\Support\Facades\Http;
1212
use Illuminate\Support\Str;
13+
use Illuminate\Validation\Rule;
1314
use Livewire\Component;
1415

1516
class Change extends Component
@@ -79,7 +80,7 @@ protected function rules(): array
7980
'webhookToken' => 'nullable|string',
8081
'groupName' => 'nullable|string',
8182
'isSystemWide' => 'required|bool',
82-
'privateKeyId' => 'nullable|int',
83+
'privateKeyId' => ['nullable', 'integer', Rule::exists('private_keys', 'id')->where('team_id', $this->gitlab_app->team_id)],
8384
'webhook_endpoint' => ['required', 'string', 'url'],
8485
'custom_webhook_endpoint' => ['nullable', 'string', 'url'],
8586
'use_custom_webhook_endpoint' => ['required', 'bool'],

‎tests/Feature/Application/GithubSourceChangeTest.php‎

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,48 @@ function validPrivateKey(): string
236236
->and($privateKey->refresh()->name)->toBe('github-app-actual-github-slug');
237237
});
238238

239+
test('saving settings keeps key selection within the source team', function (string $action) {
240+
$otherTeam = Team::factory()->create();
241+
$foreignKey = PrivateKey::create([
242+
'name' => 'other-team-key',
243+
'private_key' => validPrivateKey(),
244+
'team_id' => $otherTeam->id,
245+
]);
246+
$ownKey = PrivateKey::create([
247+
'name' => 'own-team-key',
248+
'private_key' => validPrivateKey(),
249+
'team_id' => $this->team->id,
250+
]);
251+
252+
$githubApp = GithubApp::create([
253+
'name' => 'Test GitHub App',
254+
'api_url' => 'https://api.github.com',
255+
'html_url' => 'https://github.com',
256+
'custom_user' => 'git',
257+
'custom_port' => 22,
258+
'app_id' => 12345,
259+
'installation_id' => 67890,
260+
'private_key_id' => $ownKey->id,
261+
'team_id' => $this->team->id,
262+
'is_system_wide' => false,
263+
]);
264+
265+
Livewire::withQueryParams(['github_app_uuid' => $githubApp->uuid])
266+
->test(Change::class)
267+
->set('privateKeyId', $foreignKey->id)
268+
->call($action);
269+
270+
expect($githubApp->refresh()->private_key_id)->toBe($ownKey->id);
271+
272+
Livewire::withQueryParams(['github_app_uuid' => $githubApp->uuid])
273+
->test(Change::class)
274+
->set('privateKeyId', $ownKey->id)
275+
->call($action)
276+
->assertHasNoErrors();
277+
278+
expect($githubApp->refresh()->private_key_id)->toBe($ownKey->id);
279+
})->with(['submit', 'instantSave']);
280+
239281
test('ghe.com installation path encodes the organization segment', function () {
240282
$githubApp = new GithubApp;
241283
$githubApp->forceFill([

‎tests/Feature/GitlabAppAuthorizationTest.php‎

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,26 @@
55
use App\Models\Application;
66
use App\Models\GitlabApp;
77
use App\Models\InstanceSettings;
8+
use App\Models\PrivateKey;
89
use App\Models\Team;
910
use App\Models\User;
1011
use Illuminate\Foundation\Testing\RefreshDatabase;
1112
use Livewire\Livewire;
1213

1314
uses(RefreshDatabase::class);
1415

16+
function gitlabTestPrivateKey(): string
17+
{
18+
$key = openssl_pkey_new([
19+
'private_key_bits' => 2048,
20+
'private_key_type' => OPENSSL_KEYTYPE_RSA,
21+
]);
22+
23+
openssl_pkey_export($key, $privateKey);
24+
25+
return $privateKey;
26+
}
27+
1528
beforeEach(function () {
1629
$this->team = Team::factory()->create();
1730
$this->owner = User::factory()->create();
@@ -104,6 +117,42 @@
104117
expect($this->gitlabApp->refresh()->is_system_wide)->toBeTrue();
105118
});
106119

120+
test('saving settings keeps key selection within the source team', function () {
121+
$otherTeam = Team::factory()->create();
122+
$foreignKey = PrivateKey::create([
123+
'name' => 'other-team-key',
124+
'private_key' => gitlabTestPrivateKey(),
125+
'team_id' => $otherTeam->id,
126+
]);
127+
$ownKey = PrivateKey::create([
128+
'name' => 'own-team-key',
129+
'private_key' => gitlabTestPrivateKey(),
130+
'team_id' => $this->team->id,
131+
]);
132+
$this->gitlabApp->update([
133+
'api_url' => 'https://gitlab.com/api/v4',
134+
'html_url' => 'https://gitlab.com',
135+
]);
136+
137+
$this->actingAs($this->owner);
138+
session(['currentTeam' => $this->team]);
139+
140+
Livewire::withQueryParams(['gitlab_app_uuid' => $this->gitlabApp->uuid])
141+
->test(Change::class)
142+
->set('privateKeyId', $foreignKey->id)
143+
->call('submit');
144+
145+
expect($this->gitlabApp->refresh()->private_key_id)->toBeNull();
146+
147+
Livewire::withQueryParams(['gitlab_app_uuid' => $this->gitlabApp->uuid])
148+
->test(Change::class)
149+
->set('privateKeyId', $ownKey->id)
150+
->call('submit')
151+
->assertHasNoErrors();
152+
153+
expect($this->gitlabApp->refresh()->private_key_id)->toBe($ownKey->id);
154+
});
155+
107156
test('instantSave rejects unsafe GitLab URLs', function (string $url) {
108157
$this->actingAs($this->owner);
109158
session(['currentTeam' => $this->team]);

0 commit comments

Comments
 (0)