mirror of
https://github.com/tiennm99/coolify.git
synced 2026-10-14 02:15:51 +00:00
feat(api): add GitLab Apps CRUD endpoints
There was no API for creating GitLab sources. Add /api/v1/gitlab-apps list/create/update/delete with OpenAPI docs, sensitive-field redaction, and feature coverage mirroring the GitHub Apps API.
This commit is contained in:
1 parent
bce4f8d7b2
commit
b2fed043c5
3 files changed
+729
-1
No files matched your search
@@ -0,0 +1,182 @@
|
||||
<?php
|
||||
|
||||
use App\Models\GitlabApp;
|
||||
use App\Models\InstanceSettings;
|
||||
use App\Models\Team;
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
|
||||
uses(RefreshDatabase::class);
|
||||
|
||||
beforeEach(function () {
|
||||
config()->set('app.maintenance.driver', 'file');
|
||||
config()->set('cache.default', 'array');
|
||||
|
||||
InstanceSettings::forceCreate(['id' => 0, 'is_api_enabled' => true]);
|
||||
|
||||
$this->team = Team::factory()->create();
|
||||
$this->user = User::factory()->create();
|
||||
$this->team->members()->attach($this->user->id, ['role' => 'owner']);
|
||||
session(['currentTeam' => $this->team]);
|
||||
|
||||
$this->token = $this->user->createToken('test-token', ['*']);
|
||||
$this->bearerToken = $this->token->plainTextToken;
|
||||
});
|
||||
|
||||
describe('GET /api/v1/gitlab-apps', function () {
|
||||
test('returns 401 when not authenticated', function () {
|
||||
$this->getJson('/api/v1/gitlab-apps')->assertStatus(401);
|
||||
});
|
||||
|
||||
test('returns empty array when no gitlab apps exist', function () {
|
||||
$this->withHeaders([
|
||||
'Authorization' => 'Bearer '.$this->bearerToken,
|
||||
])->getJson('/api/v1/gitlab-apps')
|
||||
->assertSuccessful()
|
||||
->assertJson([]);
|
||||
});
|
||||
|
||||
test('returns team gitlab apps without secrets for read tokens', function () {
|
||||
GitlabApp::create([
|
||||
'name' => 'Team GitLab',
|
||||
'api_url' => 'https://gitlab.com/api/v4',
|
||||
'html_url' => 'https://gitlab.com',
|
||||
'custom_user' => 'git',
|
||||
'custom_port' => 22,
|
||||
'client_id' => 'client-id',
|
||||
'client_secret' => 'secret-should-be-hidden',
|
||||
'webhook_token' => 'webhook-should-be-hidden',
|
||||
'team_id' => $this->team->id,
|
||||
'is_system_wide' => false,
|
||||
'is_public' => false,
|
||||
]);
|
||||
|
||||
$readToken = $this->user->createToken('read-token', ['read'])->plainTextToken;
|
||||
|
||||
$response = $this->withHeaders([
|
||||
'Authorization' => 'Bearer '.$readToken,
|
||||
])->getJson('/api/v1/gitlab-apps');
|
||||
|
||||
$response->assertSuccessful()
|
||||
->assertJsonCount(1)
|
||||
->assertJsonFragment(['name' => 'Team GitLab']);
|
||||
|
||||
expect($response->json('0'))->not->toHaveKey('client_secret')
|
||||
->and($response->json('0'))->not->toHaveKey('webhook_token');
|
||||
});
|
||||
});
|
||||
|
||||
describe('POST /api/v1/gitlab-apps', function () {
|
||||
test('creates a gitlab app with derived api url and generated webhook token', function () {
|
||||
$response = $this->withHeaders([
|
||||
'Authorization' => 'Bearer '.$this->bearerToken,
|
||||
])->postJson('/api/v1/gitlab-apps', [
|
||||
'name' => 'Self-hosted GitLab',
|
||||
'html_url' => 'https://gitlab.com/',
|
||||
'group_name' => 'mygroup',
|
||||
]);
|
||||
|
||||
$response->assertCreated()
|
||||
->assertJsonFragment([
|
||||
'name' => 'Self-hosted GitLab',
|
||||
'html_url' => 'https://gitlab.com',
|
||||
'api_url' => 'https://gitlab.com/api/v4',
|
||||
'group_name' => 'mygroup',
|
||||
'custom_user' => 'git',
|
||||
'custom_port' => 22,
|
||||
]);
|
||||
|
||||
$app = GitlabApp::where('name', 'Self-hosted GitLab')->first();
|
||||
expect($app)->not->toBeNull()
|
||||
->and($app->team_id)->toBe($this->team->id)
|
||||
->and($app->webhook_token)->not->toBeEmpty()
|
||||
->and(strlen((string) $app->webhook_token))->toBe(32);
|
||||
});
|
||||
|
||||
test('creates a fully configured gitlab oauth source', function () {
|
||||
$response = $this->withHeaders([
|
||||
'Authorization' => 'Bearer '.$this->bearerToken,
|
||||
])->postJson('/api/v1/gitlab-apps', [
|
||||
'name' => 'Configured GitLab',
|
||||
'html_url' => 'https://gitlab.com',
|
||||
'client_id' => 'oauth-app-id',
|
||||
'client_secret' => 'oauth-app-secret',
|
||||
'webhook_token' => 'custom-webhook-token',
|
||||
'redirect_uri' => 'https://example.com/webhooks/source/gitlab/redirect',
|
||||
]);
|
||||
|
||||
$response->assertCreated()
|
||||
->assertJsonFragment([
|
||||
'name' => 'Configured GitLab',
|
||||
'client_id' => 'oauth-app-id',
|
||||
'redirect_uri' => 'https://example.com/webhooks/source/gitlab/redirect',
|
||||
]);
|
||||
|
||||
$app = GitlabApp::where('name', 'Configured GitLab')->first();
|
||||
$app->makeVisible(['client_secret', 'webhook_token']);
|
||||
expect($app->client_secret)->toBe('oauth-app-secret')
|
||||
->and($app->webhook_token)->toBe('custom-webhook-token');
|
||||
});
|
||||
|
||||
test('rejects members without create permission', function () {
|
||||
$member = User::factory()->create();
|
||||
$this->team->members()->attach($member->id, ['role' => 'member']);
|
||||
session(['currentTeam' => $this->team]);
|
||||
$memberToken = $member->createToken('member-token', ['write'])->plainTextToken;
|
||||
|
||||
$this->withHeaders([
|
||||
'Authorization' => 'Bearer '.$memberToken,
|
||||
])->postJson('/api/v1/gitlab-apps', [
|
||||
'name' => 'Forbidden GitLab',
|
||||
'html_url' => 'https://gitlab.com',
|
||||
])->assertForbidden();
|
||||
});
|
||||
});
|
||||
|
||||
describe('PATCH /api/v1/gitlab-apps/{id}', function () {
|
||||
test('updates gitlab app credentials', function () {
|
||||
$app = GitlabApp::create([
|
||||
'name' => 'Existing',
|
||||
'api_url' => 'https://gitlab.com/api/v4',
|
||||
'html_url' => 'https://gitlab.com',
|
||||
'custom_user' => 'git',
|
||||
'custom_port' => 22,
|
||||
'team_id' => $this->team->id,
|
||||
'is_system_wide' => false,
|
||||
'is_public' => false,
|
||||
]);
|
||||
|
||||
$this->withHeaders([
|
||||
'Authorization' => 'Bearer '.$this->bearerToken,
|
||||
])->patchJson("/api/v1/gitlab-apps/{$app->id}", [
|
||||
'client_id' => 'new-client-id',
|
||||
'group_name' => 'ops',
|
||||
])->assertSuccessful()
|
||||
->assertJsonPath('message', 'GitLab app updated successfully')
|
||||
->assertJsonPath('data.client_id', 'new-client-id')
|
||||
->assertJsonPath('data.group_name', 'ops');
|
||||
});
|
||||
});
|
||||
|
||||
describe('DELETE /api/v1/gitlab-apps/{id}', function () {
|
||||
test('deletes unused gitlab app', function () {
|
||||
$app = GitlabApp::create([
|
||||
'name' => 'Delete me',
|
||||
'api_url' => 'https://gitlab.com/api/v4',
|
||||
'html_url' => 'https://gitlab.com',
|
||||
'custom_user' => 'git',
|
||||
'custom_port' => 22,
|
||||
'team_id' => $this->team->id,
|
||||
'is_system_wide' => false,
|
||||
'is_public' => false,
|
||||
]);
|
||||
|
||||
$this->withHeaders([
|
||||
'Authorization' => 'Bearer '.$this->bearerToken,
|
||||
])->deleteJson("/api/v1/gitlab-apps/{$app->id}")
|
||||
->assertSuccessful()
|
||||
->assertJsonPath('message', 'GitLab app deleted successfully');
|
||||
|
||||
expect(GitlabApp::find($app->id))->toBeNull();
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user