fix(github): allow custom webhook endpoint input
This commit is contained in:
parent
9b996b4dc9
commit
499a8666db
3 changed files with 68 additions and 11 deletions
|
|
@ -97,6 +97,7 @@ protected function rules(): array
|
||||||
'metadata' => 'nullable|string',
|
'metadata' => 'nullable|string',
|
||||||
'pullRequests' => 'nullable|string',
|
'pullRequests' => 'nullable|string',
|
||||||
'privateKeyId' => 'nullable|int',
|
'privateKeyId' => 'nullable|int',
|
||||||
|
'webhook_endpoint' => ['required', 'string', 'url'],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -259,8 +259,13 @@ class="px-2 py-1 text-xs font-bold uppercase tracking-wide bg-coollabs/10 dark:b
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col gap-3 pt-4 border-t border-neutral-200 dark:border-coolgray-400">
|
<div class="flex flex-col gap-3 pt-4 border-t border-neutral-200 dark:border-coolgray-400">
|
||||||
@if (!isCloud() || isDev())
|
@if (!isCloud() || isDev())
|
||||||
<x-forms.select canGate="create" :canResource="$github_app" wire:model.live='webhook_endpoint' x-model="webhookEndpoint" label="Webhook Endpoint"
|
<x-forms.input canGate="create" :canResource="$github_app" x-model="webhookEndpoint"
|
||||||
helper="All Git webhooks will be sent to this endpoint. <br><br>If you would like to use domain instead of IP address, set your Coolify instance's FQDN in the Settings menu.">
|
:value="$webhook_endpoint" id="webhook_endpoint" type="url"
|
||||||
|
list="webhook-endpoint-suggestions" label="Webhook Endpoint"
|
||||||
|
placeholder="https://coolify.example.com"
|
||||||
|
helper="Type or select the public URL GitHub should use for webhooks. Useful when a tunnel or proxy terminates HTTPS while Coolify itself is configured with HTTP. Do not include /webhooks.">
|
||||||
|
</x-forms.input>
|
||||||
|
<datalist id="webhook-endpoint-suggestions">
|
||||||
@if ($fqdn)
|
@if ($fqdn)
|
||||||
<option value="{{ $fqdn }}">Use {{ $fqdn }}</option>
|
<option value="{{ $fqdn }}">Use {{ $fqdn }}</option>
|
||||||
@endif
|
@endif
|
||||||
|
|
@ -273,7 +278,7 @@ class="px-2 py-1 text-xs font-bold uppercase tracking-wide bg-coollabs/10 dark:b
|
||||||
@if (config('app.url'))
|
@if (config('app.url'))
|
||||||
<option value="{{ config('app.url') }}">Use {{ config('app.url') }}</option>
|
<option value="{{ config('app.url') }}">Use {{ config('app.url') }}</option>
|
||||||
@endif
|
@endif
|
||||||
</x-forms.select>
|
</datalist>
|
||||||
@else
|
@else
|
||||||
<div class="text-sm dark:text-neutral-400">You need to register a GitHub App before using this source.</div>
|
<div class="text-sm dark:text-neutral-400">You need to register a GitHub App before using this source.</div>
|
||||||
@endif
|
@endif
|
||||||
|
|
@ -337,10 +342,10 @@ function createGithubApp(webhook_endpoint, preview_deployment_permissions, admin
|
||||||
uuid
|
uuid
|
||||||
} = @js($github_app->only(['organization', 'html_url', 'uuid']));
|
} = @js($github_app->only(['organization', 'html_url', 'uuid']));
|
||||||
if (!webhook_endpoint) {
|
if (!webhook_endpoint) {
|
||||||
alert('Please select a webhook endpoint.');
|
alert('Please enter a webhook endpoint.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let baseUrl = webhook_endpoint;
|
let baseUrl = webhook_endpoint.trim().replace(/\/+$/, '');
|
||||||
const name = @js($name);
|
const name = @js($name);
|
||||||
const manifestState = @js($manifestState);
|
const manifestState = @js($manifestState);
|
||||||
const isDev = @js(config('app.env')) ===
|
const isDev = @js(config('app.env')) ===
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,27 @@
|
||||||
// Set current team
|
// Set current team
|
||||||
$this->actingAs($this->user);
|
$this->actingAs($this->user);
|
||||||
session(['currentTeam' => $this->team]);
|
session(['currentTeam' => $this->team]);
|
||||||
|
|
||||||
|
InstanceSettings::forceCreate([
|
||||||
|
'id' => 0,
|
||||||
|
'fqdn' => null,
|
||||||
|
'public_ipv4' => null,
|
||||||
|
'public_ipv6' => null,
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function validPrivateKey(): string
|
||||||
|
{
|
||||||
|
$key = openssl_pkey_new([
|
||||||
|
'private_key_bits' => 2048,
|
||||||
|
'private_key_type' => OPENSSL_KEYTYPE_RSA,
|
||||||
|
]);
|
||||||
|
|
||||||
|
openssl_pkey_export($key, $privateKey);
|
||||||
|
|
||||||
|
return $privateKey;
|
||||||
|
}
|
||||||
|
|
||||||
describe('GitHub Source Change Component', function () {
|
describe('GitHub Source Change Component', function () {
|
||||||
test('all github app form controls declare explicit authorization', function () {
|
test('all github app form controls declare explicit authorization', function () {
|
||||||
$view = file_get_contents(resource_path('views/livewire/source/github/change.blade.php'));
|
$view = file_get_contents(resource_path('views/livewire/source/github/change.blade.php'));
|
||||||
|
|
@ -68,8 +87,7 @@
|
||||||
test('defaults webhook endpoint to app url when it is the first available endpoint', function () {
|
test('defaults webhook endpoint to app url when it is the first available endpoint', function () {
|
||||||
config(['app.url' => 'http://localhost:8000']);
|
config(['app.url' => 'http://localhost:8000']);
|
||||||
|
|
||||||
InstanceSettings::forceCreate([
|
InstanceSettings::findOrFail(0)->update([
|
||||||
'id' => 0,
|
|
||||||
'fqdn' => null,
|
'fqdn' => null,
|
||||||
'public_ipv4' => null,
|
'public_ipv4' => null,
|
||||||
'public_ipv6' => null,
|
'public_ipv6' => null,
|
||||||
|
|
@ -91,10 +109,39 @@
|
||||||
->assertSet('webhook_endpoint', 'http://localhost:8000');
|
->assertSet('webhook_endpoint', 'http://localhost:8000');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('webhook endpoint can be typed manually when creating github app', function () {
|
||||||
|
config(['app.url' => 'http://localhost:8000']);
|
||||||
|
|
||||||
|
InstanceSettings::findOrFail(0)->update([
|
||||||
|
'fqdn' => 'http://staging.example.com',
|
||||||
|
'public_ipv4' => '84.1.202.183',
|
||||||
|
'public_ipv6' => null,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$githubApp = GithubApp::create([
|
||||||
|
'name' => 'Test GitHub App',
|
||||||
|
'api_url' => 'https://api.github.com',
|
||||||
|
'html_url' => 'https://github.com',
|
||||||
|
'custom_user' => 'git',
|
||||||
|
'custom_port' => 22,
|
||||||
|
'team_id' => $this->team->id,
|
||||||
|
'is_system_wide' => false,
|
||||||
|
]);
|
||||||
|
|
||||||
|
Livewire::withQueryParams(['github_app_uuid' => $githubApp->uuid])
|
||||||
|
->test(Change::class)
|
||||||
|
->assertSuccessful()
|
||||||
|
->set('webhook_endpoint', 'https://staging.example.com')
|
||||||
|
->assertSet('webhook_endpoint', 'https://staging.example.com')
|
||||||
|
->assertSee('Type or select the public URL GitHub should use for webhooks', false)
|
||||||
|
->assertSee('https://staging.example.com')
|
||||||
|
->assertSee('webhook-endpoint-suggestions');
|
||||||
|
});
|
||||||
|
|
||||||
test('can mount with fully configured github app', function () {
|
test('can mount with fully configured github app', function () {
|
||||||
$privateKey = PrivateKey::create([
|
$privateKey = PrivateKey::create([
|
||||||
'name' => 'Test Key',
|
'name' => 'Test Key',
|
||||||
'private_key' => 'test-private-key-content',
|
'private_key' => validPrivateKey(),
|
||||||
'team_id' => $this->team->id,
|
'team_id' => $this->team->id,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
@ -128,7 +175,7 @@
|
||||||
test('can update github app from null to valid values', function () {
|
test('can update github app from null to valid values', function () {
|
||||||
$privateKey = PrivateKey::create([
|
$privateKey = PrivateKey::create([
|
||||||
'name' => 'Test Key',
|
'name' => 'Test Key',
|
||||||
'private_key' => 'test-private-key-content',
|
'private_key' => validPrivateKey(),
|
||||||
'team_id' => $this->team->id,
|
'team_id' => $this->team->id,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
@ -201,8 +248,8 @@
|
||||||
|
|
||||||
// Verify the database was updated
|
// Verify the database was updated
|
||||||
$githubApp->refresh();
|
$githubApp->refresh();
|
||||||
expect($githubApp->app_id)->toBe('1234567890');
|
expect($githubApp->app_id)->toBe(1234567890);
|
||||||
expect($githubApp->installation_id)->toBe('1234567890');
|
expect($githubApp->installation_id)->toBe(1234567890);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('checkPermissions validates required fields', function () {
|
test('checkPermissions validates required fields', function () {
|
||||||
|
|
@ -223,6 +270,8 @@
|
||||||
->assertSuccessful()
|
->assertSuccessful()
|
||||||
->call('checkPermissions')
|
->call('checkPermissions')
|
||||||
->assertDispatched('error', function ($event, $message) {
|
->assertDispatched('error', function ($event, $message) {
|
||||||
|
$message = is_array($message) ? implode(' ', $message) : $message;
|
||||||
|
|
||||||
return str_contains($message, 'App ID') && str_contains($message, 'Private Key');
|
return str_contains($message, 'App ID') && str_contains($message, 'Private Key');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
@ -246,6 +295,8 @@
|
||||||
->assertSuccessful()
|
->assertSuccessful()
|
||||||
->call('checkPermissions')
|
->call('checkPermissions')
|
||||||
->assertDispatched('error', function ($event, $message) {
|
->assertDispatched('error', function ($event, $message) {
|
||||||
|
$message = is_array($message) ? implode(' ', $message) : $message;
|
||||||
|
|
||||||
return str_contains($message, 'Private Key not found');
|
return str_contains($message, 'Private Key not found');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue