github webhooks
This commit is contained in:
parent
19ad184cd6
commit
76bf601e1b
@ -72,7 +72,7 @@ public function loadRepositories($github_app_id)
|
|||||||
$this->repositories = collect();
|
$this->repositories = collect();
|
||||||
$this->page = 1;
|
$this->page = 1;
|
||||||
$this->github_app = GithubApp::where('id', $github_app_id)->first();
|
$this->github_app = GithubApp::where('id', $github_app_id)->first();
|
||||||
$this->token = generate_github_token($this->github_app);
|
$this->token = generate_github_installation_token($this->github_app);
|
||||||
$this->loadRepositoryByPage();
|
$this->loadRepositoryByPage();
|
||||||
if ($this->repositories->count() < $this->total_repositories_count) {
|
if ($this->repositories->count() < $this->total_repositories_count) {
|
||||||
while ($this->repositories->count() < $this->total_repositories_count) {
|
while ($this->repositories->count() < $this->total_repositories_count) {
|
||||||
@ -123,6 +123,7 @@ public function submit()
|
|||||||
}
|
}
|
||||||
$application = Application::create([
|
$application = Application::create([
|
||||||
'name' => "{$this->selected_repository_owner}/{$this->selected_repository_repo}:{$this->selected_branch_name}",
|
'name' => "{$this->selected_repository_owner}/{$this->selected_repository_repo}:{$this->selected_branch_name}",
|
||||||
|
'project_id' => $this->selected_repository_id,
|
||||||
'git_repository' => "{$this->selected_repository_owner}/{$this->selected_repository_repo}",
|
'git_repository' => "{$this->selected_repository_owner}/{$this->selected_repository_repo}",
|
||||||
'git_branch' => $this->selected_branch_name,
|
'git_branch' => $this->selected_branch_name,
|
||||||
'build_pack' => 'nixpacks',
|
'build_pack' => 'nixpacks',
|
||||||
|
@ -469,7 +469,7 @@ private function gitImport()
|
|||||||
$this->execute_in_builder($git_clone_command)
|
$this->execute_in_builder($git_clone_command)
|
||||||
];
|
];
|
||||||
} else {
|
} else {
|
||||||
$github_access_token = generate_github_token($this->source);
|
$github_access_token = generate_github_installation_token($this->source);
|
||||||
return [
|
return [
|
||||||
$this->execute_in_builder("git clone -q -b {$this->application->git_branch} $source_html_url_scheme://x-access-token:$github_access_token@$source_html_url_host/{$this->application->git_repository}.git {$this->workdir}")
|
$this->execute_in_builder("git clone -q -b {$this->application->git_branch} $source_html_url_scheme://x-access-token:$github_access_token@$source_html_url_host/{$this->application->git_repository}.git {$this->workdir}")
|
||||||
];
|
];
|
||||||
|
@ -24,6 +24,7 @@ protected static function booted()
|
|||||||
|
|
||||||
protected $fillable = [
|
protected $fillable = [
|
||||||
'name',
|
'name',
|
||||||
|
'project_id',
|
||||||
'description',
|
'description',
|
||||||
'git_repository',
|
'git_repository',
|
||||||
'git_branch',
|
'git_branch',
|
||||||
|
@ -12,7 +12,10 @@ protected static function boot()
|
|||||||
parent::boot();
|
parent::boot();
|
||||||
|
|
||||||
static::creating(function (Model $model) {
|
static::creating(function (Model $model) {
|
||||||
|
// Generate a UUID if one isn't set
|
||||||
|
if (!$model->uuid) {
|
||||||
$model->uuid = (string) new Cuid2(7);
|
$model->uuid = (string) new Cuid2(7);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
class GithubApp extends BaseModel
|
class GithubApp extends BaseModel
|
||||||
{
|
{
|
||||||
protected $fillable = ['name', 'organization', 'api_url', 'html_url', 'custom_user', 'custom_port', 'team_id'];
|
protected $fillable = ['name', 'uuid', 'organization', 'api_url', 'html_url', 'custom_user', 'custom_port', 'team_id'];
|
||||||
protected $casts = [
|
protected $casts = [
|
||||||
'is_public' => 'boolean',
|
'is_public' => 'boolean',
|
||||||
];
|
];
|
||||||
|
14
app/Models/GithubEventsApplications.php
Normal file
14
app/Models/GithubEventsApplications.php
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class GithubEventsApplications extends Model
|
||||||
|
{
|
||||||
|
protected $fillable = [
|
||||||
|
'delivery_guid',
|
||||||
|
'application_id',
|
||||||
|
];
|
||||||
|
}
|
@ -189,8 +189,8 @@ function generateRandomName()
|
|||||||
use Lcobucci\JWT\Signer\Rsa\Sha256;
|
use Lcobucci\JWT\Signer\Rsa\Sha256;
|
||||||
use Lcobucci\JWT\Token\Builder;
|
use Lcobucci\JWT\Token\Builder;
|
||||||
|
|
||||||
if (!function_exists('generate_github_token')) {
|
if (!function_exists('generate_github_installation_token')) {
|
||||||
function generate_github_token(GithubApp $source)
|
function generate_github_installation_token(GithubApp $source)
|
||||||
{
|
{
|
||||||
$signingKey = InMemory::plainText($source->privateKey->private_key);
|
$signingKey = InMemory::plainText($source->privateKey->private_key);
|
||||||
$algorithm = new Sha256();
|
$algorithm = new Sha256();
|
||||||
@ -213,6 +213,23 @@ function generate_github_token(GithubApp $source)
|
|||||||
return $token->json()['token'];
|
return $token->json()['token'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!function_exists('generate_github_jwt_token')) {
|
||||||
|
function generate_github_jwt_token(GithubApp $source)
|
||||||
|
{
|
||||||
|
$signingKey = InMemory::plainText($source->privateKey->private_key);
|
||||||
|
$algorithm = new Sha256();
|
||||||
|
$tokenBuilder = (new Builder(new JoseEncoder(), ChainedFormatter::default()));
|
||||||
|
$now = new DateTimeImmutable();
|
||||||
|
$now = $now->setTime($now->format('H'), $now->format('i'));
|
||||||
|
$issuedToken = $tokenBuilder
|
||||||
|
->issuedBy($source->app_id)
|
||||||
|
->issuedAt($now->modify('-1 minute'))
|
||||||
|
->expiresAt($now->modify('+10 minutes'))
|
||||||
|
->getToken($algorithm, $signingKey)
|
||||||
|
->toString();
|
||||||
|
return $issuedToken;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (!function_exists('getParameters')) {
|
if (!function_exists('getParameters')) {
|
||||||
function getParameters()
|
function getParameters()
|
||||||
{
|
{
|
||||||
|
@ -13,6 +13,7 @@ public function up(): void
|
|||||||
{
|
{
|
||||||
Schema::create('applications', function (Blueprint $table) {
|
Schema::create('applications', function (Blueprint $table) {
|
||||||
$table->id();
|
$table->id();
|
||||||
|
$table->integer('project_id')->nullable();
|
||||||
$table->string('uuid')->unique();
|
$table->string('uuid')->unique();
|
||||||
$table->string('name');
|
$table->string('name');
|
||||||
|
|
||||||
|
@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('github_events_applications', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->string('delivery_guid');
|
||||||
|
$table->foreignId('application_id');
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('github_events_applications');
|
||||||
|
}
|
||||||
|
};
|
@ -25,6 +25,7 @@ public function run(): void
|
|||||||
|
|
||||||
Application::create([
|
Application::create([
|
||||||
'name' => 'coollabsio/coolify-examples:nodejs-fastify',
|
'name' => 'coollabsio/coolify-examples:nodejs-fastify',
|
||||||
|
'project_id' => 603035348,
|
||||||
'git_repository' => 'coollabsio/coolify-examples',
|
'git_repository' => 'coollabsio/coolify-examples',
|
||||||
'git_branch' => 'nodejs-fastify',
|
'git_branch' => 'nodejs-fastify',
|
||||||
'build_pack' => 'nixpacks',
|
'build_pack' => 'nixpacks',
|
||||||
|
@ -26,7 +26,8 @@ public function run(): void
|
|||||||
'team_id' => $root_team->id,
|
'team_id' => $root_team->id,
|
||||||
]);
|
]);
|
||||||
GithubApp::create([
|
GithubApp::create([
|
||||||
'name' => 'coolify-laravel-development-private-github',
|
'name' => 'coolify-laravel-development-public',
|
||||||
|
'uuid' => '69420',
|
||||||
'api_url' => 'https://api.github.com',
|
'api_url' => 'https://api.github.com',
|
||||||
'html_url' => 'https://github.com',
|
'html_url' => 'https://github.com',
|
||||||
'is_public' => false,
|
'is_public' => false,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<x-layout>
|
<x-layout>
|
||||||
<div>v{{ config('coolify.version') }}</div>
|
<div>v{{ config('version') }}</div>
|
||||||
<a href="/login">Login</a>
|
<a href="/login">Login</a>
|
||||||
@if ($is_registration_enabled)
|
@if ($is_registration_enabled)
|
||||||
<a href="/register">Register</a>
|
<a href="/register">Register</a>
|
||||||
|
@ -18,13 +18,6 @@
|
|||||||
Route::get('/health', function () {
|
Route::get('/health', function () {
|
||||||
return 'OK';
|
return 'OK';
|
||||||
});
|
});
|
||||||
Route::get('/webhooks/source/github/redirect', function () {
|
|
||||||
$code = request()->get('code');
|
|
||||||
$state = request()->get('state');
|
|
||||||
$github_app = GithubApp::where('uuid', $state)->firstOrFail();
|
|
||||||
return 'OK';
|
|
||||||
});
|
|
||||||
|
|
||||||
// Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
|
// Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
|
||||||
// return $request->user();
|
// return $request->user();
|
||||||
// });
|
// });
|
||||||
|
@ -38,7 +38,6 @@
|
|||||||
})->flatten();
|
})->flatten();
|
||||||
$private_keys = PrivateKey::where('team_id', $id)->get();
|
$private_keys = PrivateKey::where('team_id', $id)->get();
|
||||||
$github_apps = GithubApp::private();
|
$github_apps = GithubApp::private();
|
||||||
|
|
||||||
return view('dashboard', [
|
return view('dashboard', [
|
||||||
'servers' => $servers->sortBy('name'),
|
'servers' => $servers->sortBy('name'),
|
||||||
'projects' => $projects->sortBy('name'),
|
'projects' => $projects->sortBy('name'),
|
||||||
@ -86,7 +85,7 @@
|
|||||||
Route::get('/source/new', fn () => view('source.new'))->name('source.new');
|
Route::get('/source/new', fn () => view('source.new'))->name('source.new');
|
||||||
Route::get('/source/github/{github_app_uuid}', function (Request $request) {
|
Route::get('/source/github/{github_app_uuid}', function (Request $request) {
|
||||||
$github_app = GithubApp::where('uuid', request()->github_app_uuid)->first();
|
$github_app = GithubApp::where('uuid', request()->github_app_uuid)->first();
|
||||||
$name = Str::kebab('coolify' . $github_app->name);
|
$name = Str::of(Str::kebab($github_app->name))->start('coolify-');
|
||||||
$settings = InstanceSettings::first();
|
$settings = InstanceSettings::first();
|
||||||
$host = $request->schemeAndHttpHost();
|
$host = $request->schemeAndHttpHost();
|
||||||
if ($settings->fqdn) {
|
if ($settings->fqdn) {
|
||||||
|
@ -1,9 +1,14 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
use App\Jobs\DeployApplicationJob;
|
||||||
|
use App\Models\Application;
|
||||||
use App\Models\PrivateKey;
|
use App\Models\PrivateKey;
|
||||||
use App\Models\GithubApp;
|
use App\Models\GithubApp;
|
||||||
|
use App\Models\GithubEventsApplications;
|
||||||
use Illuminate\Support\Facades\Http;
|
use Illuminate\Support\Facades\Http;
|
||||||
use Illuminate\Support\Facades\Route;
|
use Illuminate\Support\Facades\Route;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
use Visus\Cuid2\Cuid2;
|
||||||
|
|
||||||
Route::get('/source/github/redirect', function () {
|
Route::get('/source/github/redirect', function () {
|
||||||
try {
|
try {
|
||||||
@ -50,3 +55,58 @@
|
|||||||
return generalErrorHandler($e);
|
return generalErrorHandler($e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
Route::post('/source/github/events', function () {
|
||||||
|
try {
|
||||||
|
$x_github_delivery = request()->header('X-GitHub-Delivery');
|
||||||
|
$x_github_event = Str::lower(request()->header('X-GitHub-Event'));
|
||||||
|
$x_github_hook_installation_target_id = request()->header('X-GitHub-Hook-Installation-Target-Id');
|
||||||
|
$x_hub_signature_256 = request()->header('X-Hub-Signature-256');
|
||||||
|
$payload = request()->collect();
|
||||||
|
if ($x_github_event === 'ping') {
|
||||||
|
// Just pong
|
||||||
|
return response('pong');
|
||||||
|
}
|
||||||
|
if ($x_github_event === 'installation') {
|
||||||
|
// Installation handled by setup redirect url. Repositories queried on-demand.
|
||||||
|
return response('cool');
|
||||||
|
}
|
||||||
|
$github_app = GithubApp::where('app_id', $x_github_hook_installation_target_id)->firstOrFail();
|
||||||
|
// TODO: Verify signature
|
||||||
|
// $webhook_secret = data_get($github_app, 'webhook_secret');
|
||||||
|
// $key = hash('sha256', $webhook_secret, true);
|
||||||
|
// $hmac = hash_hmac('sha256', request()->getContent(), $key);
|
||||||
|
// if (!hash_equals($hmac, $x_hub_signature_256)) {
|
||||||
|
// return response('not cool');
|
||||||
|
// }
|
||||||
|
|
||||||
|
if ($x_github_event === 'push') {
|
||||||
|
$id = data_get($payload, 'repository.id');
|
||||||
|
$branch = data_get($payload, 'ref');
|
||||||
|
if (Str::isMatch('/refs\/heads\/*/', $branch)) {
|
||||||
|
$branch = Str::after($branch, 'refs/heads/');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($x_github_event === 'pull_request') {
|
||||||
|
$id = data_get($payload, 'pull_request.base.repo.id');
|
||||||
|
$branch = data_get($payload, 'pull_request.base.ref');
|
||||||
|
}
|
||||||
|
if (!$id || !$branch) {
|
||||||
|
return response('not cool');
|
||||||
|
}
|
||||||
|
$applications = Application::where('project_id', $id)->where('git_branch', $branch)->get();
|
||||||
|
foreach ($applications as $application) {
|
||||||
|
GithubEventsApplications::create([
|
||||||
|
"delivery_guid" => $x_github_delivery,
|
||||||
|
"application_id" => $application->id
|
||||||
|
]);
|
||||||
|
$deployment_uuid = new Cuid2(7);
|
||||||
|
dispatch(new DeployApplicationJob(
|
||||||
|
deployment_uuid: $deployment_uuid,
|
||||||
|
application_uuid: $application->uuid,
|
||||||
|
force_rebuild: false,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return generalErrorHandler($e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
@ -1 +1,17 @@
|
|||||||
[]
|
[
|
||||||
|
{
|
||||||
|
"_id": "e6458286-eef1-401c-be84-860b111d66f0",
|
||||||
|
"colName": "Webhooks",
|
||||||
|
"created": "2023-05-09T11:45:36.504Z",
|
||||||
|
"sortNum": 10000,
|
||||||
|
"folders": [
|
||||||
|
{
|
||||||
|
"_id": "b8cfd093-5467-44a2-9221-ad0207717310",
|
||||||
|
"name": "GitHub",
|
||||||
|
"containerId": "",
|
||||||
|
"created": "2023-05-09T11:45:40.630Z",
|
||||||
|
"sortNum": 10000
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
@ -1 +1,13 @@
|
|||||||
[]
|
[
|
||||||
|
{
|
||||||
|
"_id": "bd3f3c2e-b161-40c9-9077-efcf40dfe1f4",
|
||||||
|
"name": "(Local Env)",
|
||||||
|
"default": false,
|
||||||
|
"global": true,
|
||||||
|
"local": true,
|
||||||
|
"sortNum": -1,
|
||||||
|
"created": "2023-05-09T11:48:22.144Z",
|
||||||
|
"modified": "2023-05-09T11:48:22.144Z",
|
||||||
|
"data": []
|
||||||
|
}
|
||||||
|
]
|
@ -1 +1,50 @@
|
|||||||
[]
|
[
|
||||||
|
{
|
||||||
|
"_id": "b3d379ab-e5e4-4ba4-991d-b6c8c6bbcb98",
|
||||||
|
"colId": "e6458286-eef1-401c-be84-860b111d66f0",
|
||||||
|
"containerId": "b8cfd093-5467-44a2-9221-ad0207717310",
|
||||||
|
"name": "Push",
|
||||||
|
"url": "http://localhost:8000/webhooks/source/github/events",
|
||||||
|
"method": "POST",
|
||||||
|
"sortNum": 10000,
|
||||||
|
"created": "2023-05-09T11:45:50.227Z",
|
||||||
|
"modified": "2023-05-09T12:22:27.192Z",
|
||||||
|
"headers": [
|
||||||
|
{
|
||||||
|
"name": "X-GitHub-Delivery",
|
||||||
|
"value": "9b4bc300-ee63-11ed-9133-5f71dd83487d"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "X-GitHub-Event",
|
||||||
|
"value": "push"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "X-GitHub-Hook-ID",
|
||||||
|
"value": "400873078"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "X-GitHub-Hook-Installation-Target-ID",
|
||||||
|
"value": "292941"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "X-GitHub-Hook-Installation-Target-Type",
|
||||||
|
"value": "integration"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "X-Hub-Signature-256",
|
||||||
|
"value": "sha256=d5c8d05cc6de14422ab3661d37ec4b98e71f4fdd63d1116f5dedfcb0213ee03d"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Content-Type",
|
||||||
|
"value": "application/json"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"params": [],
|
||||||
|
"body": {
|
||||||
|
"type": "json",
|
||||||
|
"raw": "{\n \"ref\": \"{{repository_ref}}\",\n \"repository\": {\n \"id\": \"{{repository_id}}\",\n \"full_name\": \"{{repository_name}}\"\n }\n}",
|
||||||
|
"form": []
|
||||||
|
},
|
||||||
|
"tests": []
|
||||||
|
}
|
||||||
|
]
|
Loading…
Reference in New Issue
Block a user