From eca9f60d7d2a00c586a982995c4e197d37669119 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Tue, 13 Jun 2023 15:37:55 +0200 Subject: [PATCH] test hmac --- app/Jobs/ApplicationDeploymentJob.php | 21 ++++++++++----------- database/seeders/GithubAppSeeder.php | 2 +- routes/webhooks.php | 18 ++++++++++-------- thunder-tests/thunderclient.json | 8 ++++---- 4 files changed, 25 insertions(+), 24 deletions(-) diff --git a/app/Jobs/ApplicationDeploymentJob.php b/app/Jobs/ApplicationDeploymentJob.php index 44388e6cc..74b1a6c2c 100644 --- a/app/Jobs/ApplicationDeploymentJob.php +++ b/app/Jobs/ApplicationDeploymentJob.php @@ -92,7 +92,6 @@ class ApplicationDeploymentJob implements ShouldQueue public function handle(): void { try { - ray()->clearScreen(); if ($this->application->deploymentType() === 'source') { $this->source = $this->application->source->getMorphClass()::where('id', $this->application->source->id)->first(); } @@ -100,7 +99,7 @@ class ApplicationDeploymentJob implements ShouldQueue $this->workdir = "/artifacts/{$this->deployment_uuid}"; if ($this->pull_request_id !== 0) { - ray('Deploying pull/' . $this->pull_request_id . '/head for application: ' . $this->application->name); + ray('Deploying pull/' . $this->pull_request_id . '/head for application: ' . $this->application->name)->green(); if ($this->application->fqdn) { $preview_fqdn = data_get($this->preview, 'fqdn'); $template = $this->application->preview_url_template; @@ -253,13 +252,13 @@ COPY --from=$this->build_image_name /app/{$this->application->publish_directory} "echo 'Starting deployment of {$this->application->git_repository}:{$this->application->git_branch}...'", ]); $this->start_builder_image(); - ray('Rollback Commit: ' . $this->rollback_commit); + ray('Rollback Commit: ' . $this->rollback_commit)->green(); if ($this->rollback_commit === 'HEAD') { $this->clone_repository(); } $this->build_image_name = "{$this->application->uuid}:{$this->git_commit}-build"; $this->production_image_name = "{$this->application->uuid}:{$this->git_commit}"; - ray('Build Image Name: ' . $this->build_image_name . ' & Production Image Name:' . $this->production_image_name); + ray('Build Image Name: ' . $this->build_image_name . ' & Production Image Name:' . $this->production_image_name)->green(); if (!$this->force_rebuild) { $this->execute_now([ "docker images -q {$this->application->uuid}:{$this->git_commit} 2>/dev/null", @@ -295,7 +294,7 @@ COPY --from=$this->build_image_name /app/{$this->application->publish_directory} private function next(string $status) { if (!Str::of($this->application_deployment_queue->status)->startsWith('cancelled')) { - ray('Next Status: ' . $status); + ray('Next Status: ' . $status)->green(); $this->application_deployment_queue->update([ 'status' => $status, ]); @@ -319,14 +318,14 @@ COPY --from=$this->build_image_name /app/{$this->application->publish_directory} private function generate_environment_variables($ports) { $environment_variables = collect(); - ray('Generate Environment Variables'); + ray('Generate Environment Variables')->green(); if ($this->pull_request_id === 0) { - ray($this->application->runtime_environment_variables); + ray($this->application->runtime_environment_variables)->green(); foreach ($this->application->runtime_environment_variables as $env) { $environment_variables->push("$env->key=$env->value"); } } else { - ray($this->application->runtime_environment_variables_preview); + ray($this->application->runtime_environment_variables_preview)->green(); foreach ($this->application->runtime_environment_variables_preview as $env) { $environment_variables->push("$env->key=$env->value"); } @@ -451,7 +450,7 @@ COPY --from=$this->build_image_name /app/{$this->application->publish_directory} } $local_persistent_volumes[] = $volume_name . ':' . $persistentStorage->mount_path; } - ray('local_persistent_volumes', $local_persistent_volumes); + ray('local_persistent_volumes', $local_persistent_volumes)->green(); return $local_persistent_volumes; } @@ -581,13 +580,13 @@ COPY --from=$this->build_image_name /app/{$this->application->publish_directory} } else { $commandText = collect($command)->implode("\n"); } - ray('Executing command: ' . $commandText); + ray('Executing command: ' . $commandText)->green(); $this->activity->properties = $this->activity->properties->merge([ 'command' => $commandText, ]); $this->activity->save(); if ($isDebuggable && !$this->application->settings->is_debug_enabled) { - ray('Debugging is disabled for this application. Skipping command.'); + ray('Debugging is disabled for this application. Skipping command.')->green(); $hideFromOutput = true; } $remote_process = resolve(RunRemoteProcess::class, [ diff --git a/database/seeders/GithubAppSeeder.php b/database/seeders/GithubAppSeeder.php index a9b8dbbc4..50ae63a2e 100644 --- a/database/seeders/GithubAppSeeder.php +++ b/database/seeders/GithubAppSeeder.php @@ -34,7 +34,7 @@ class GithubAppSeeder extends Seeder 'app_id' => 292941, 'installation_id' => 37267016, 'client_id' => 'Iv1.220e564d2b0abd8c', - 'client_secret' => '96b1b31f36ce0a34386d11798ff35b9b6d8aba3a', + 'client_secret' => '116d1d80289f378410dd70ab4e4b81dd8d2c52b6', 'webhook_secret' => '326a47b49054f03288f800d81247ec9414d0abf3', 'private_key_id' => $private_key_2->id, 'team_id' => $root_team->id, diff --git a/routes/webhooks.php b/routes/webhooks.php index 751e2faf7..55ec5ec27 100644 --- a/routes/webhooks.php +++ b/routes/webhooks.php @@ -61,7 +61,7 @@ Route::post('/source/github/events', function () { $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'); + $x_hub_signature_256 = Str::after(request()->header('X-Hub-Signature-256'), 'sha256='); $payload = request()->collect(); if ($x_github_event === 'ping') { // Just pong @@ -72,13 +72,15 @@ Route::post('/source/github/events', function () { 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'); - // } + + $webhook_secret = data_get($github_app, 'webhook_secret'); + $hmac = hash_hmac('sha256', request()->getContent(), $webhook_secret); + ray($hmac, $x_hub_signature_256)->blue(); + if (config('app.env') !== 'local') { + if (!hash_equals($x_hub_signature_256, $hmac)) { + return response('not cool'); + } + } if ($x_github_event === 'push') { $id = data_get($payload, 'repository.id'); diff --git a/thunder-tests/thunderclient.json b/thunder-tests/thunderclient.json index 517c5d4f8..278b40c7c 100644 --- a/thunder-tests/thunderclient.json +++ b/thunder-tests/thunderclient.json @@ -56,11 +56,11 @@ "method": "POST", "sortNum": 20000, "created": "2023-05-31T08:23:28.904Z", - "modified": "2023-06-13T10:01:31.875Z", + "modified": "2023-06-13T13:10:18.357Z", "headers": [ { "name": "X-GitHub-Delivery", - "value": "9b4bc300-ee63-11ed-9133-5f71dd83487d" + "value": "e4c43c10-09cf-11ee-8879-0a481c473173" }, { "name": "X-GitHub-Event", @@ -80,7 +80,7 @@ }, { "name": "X-Hub-Signature-256", - "value": "sha256=d5c8d05cc6de14422ab3661d37ec4b98e71f4fdd63d1116f5dedfcb0213ee03d" + "value": "sha256=d02e35ae379a528076710322fcf9386b23bc14d61fd671259ae1d9d20488b36f" }, { "name": "Content-Type", @@ -90,7 +90,7 @@ "params": [], "body": { "type": "json", - "raw": "{\n \"action\": \"opened\",\n \"number\": 1,\n \"pull_request\": {\n \"html_url\": \"https://github.com/{{repository_name}}/pull/1\",\n \"head\": {\n \"ref\":\"{{repository_ref_pr}}\"\n },\n \"base\": {\n \"ref\":\"{{repository_ref}}\"\n }\n },\n \"repository\": {\n \"id\": \"{{repository_id}}\",\n \"full_name\": \"{{repository_name}}\"\n }\n}", + "raw": "{\r\n \"action\": \"reopened\",\r\n \"number\": 1,\r\n \"pull_request\": {\r\n \"url\": \"https://api.github.com/repos/coollabsio/coolify-examples/pulls/1\",\r\n \"id\": 1352319418,\r\n \"node_id\": \"PR_kwDOI_GW1M5QmsG6\",\r\n \"html_url\": \"https://github.com/coollabsio/coolify-examples/pull/1\",\r\n \"diff_url\": \"https://github.com/coollabsio/coolify-examples/pull/1.diff\",\r\n \"patch_url\": \"https://github.com/coollabsio/coolify-examples/pull/1.patch\",\r\n \"issue_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/issues/1\",\r\n \"number\": 1,\r\n \"state\": \"open\",\r\n \"locked\": false,\r\n \"title\": \"Test\",\r\n \"user\": {\r\n \"login\": \"andrasbacsai\",\r\n \"id\": 5845193,\r\n \"node_id\": \"MDQ6VXNlcjU4NDUxOTM=\",\r\n \"avatar_url\": \"https://avatars.githubusercontent.com/u/5845193?v=4\",\r\n \"gravatar_id\": \"\",\r\n \"url\": \"https://api.github.com/users/andrasbacsai\",\r\n \"html_url\": \"https://github.com/andrasbacsai\",\r\n \"followers_url\": \"https://api.github.com/users/andrasbacsai/followers\",\r\n \"following_url\": \"https://api.github.com/users/andrasbacsai/following{/other_user}\",\r\n \"gists_url\": \"https://api.github.com/users/andrasbacsai/gists{/gist_id}\",\r\n \"starred_url\": \"https://api.github.com/users/andrasbacsai/starred{/owner}{/repo}\",\r\n \"subscriptions_url\": \"https://api.github.com/users/andrasbacsai/subscriptions\",\r\n \"organizations_url\": \"https://api.github.com/users/andrasbacsai/orgs\",\r\n \"repos_url\": \"https://api.github.com/users/andrasbacsai/repos\",\r\n \"events_url\": \"https://api.github.com/users/andrasbacsai/events{/privacy}\",\r\n \"received_events_url\": \"https://api.github.com/users/andrasbacsai/received_events\",\r\n \"type\": \"User\",\r\n \"site_admin\": false\r\n },\r\n \"body\": null,\r\n \"created_at\": \"2023-05-16T11:18:34Z\",\r\n \"updated_at\": \"2023-06-13T13:09:47Z\",\r\n \"closed_at\": null,\r\n \"merged_at\": null,\r\n \"merge_commit_sha\": null,\r\n \"assignee\": null,\r\n \"assignees\": [\r\n\r\n ],\r\n \"requested_reviewers\": [\r\n\r\n ],\r\n \"requested_teams\": [\r\n\r\n ],\r\n \"labels\": [\r\n\r\n ],\r\n \"milestone\": null,\r\n \"draft\": false,\r\n \"commits_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/pulls/1/commits\",\r\n \"review_comments_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/pulls/1/comments\",\r\n \"review_comment_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/pulls/comments{/number}\",\r\n \"comments_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/issues/1/comments\",\r\n \"statuses_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/statuses/7bf7f99f08108661bee8ead3c3854b491030b4d7\",\r\n \"head\": {\r\n \"label\": \"coollabsio:nodejs-fastify\",\r\n \"ref\": \"nodejs-fastify\",\r\n \"sha\": \"7bf7f99f08108661bee8ead3c3854b491030b4d7\",\r\n \"user\": {\r\n \"login\": \"coollabsio\",\r\n \"id\": 60715044,\r\n \"node_id\": \"MDEyOk9yZ2FuaXphdGlvbjYwNzE1MDQ0\",\r\n \"avatar_url\": \"https://avatars.githubusercontent.com/u/60715044?v=4\",\r\n \"gravatar_id\": \"\",\r\n \"url\": \"https://api.github.com/users/coollabsio\",\r\n \"html_url\": \"https://github.com/coollabsio\",\r\n \"followers_url\": \"https://api.github.com/users/coollabsio/followers\",\r\n \"following_url\": \"https://api.github.com/users/coollabsio/following{/other_user}\",\r\n \"gists_url\": \"https://api.github.com/users/coollabsio/gists{/gist_id}\",\r\n \"starred_url\": \"https://api.github.com/users/coollabsio/starred{/owner}{/repo}\",\r\n \"subscriptions_url\": \"https://api.github.com/users/coollabsio/subscriptions\",\r\n \"organizations_url\": \"https://api.github.com/users/coollabsio/orgs\",\r\n \"repos_url\": \"https://api.github.com/users/coollabsio/repos\",\r\n \"events_url\": \"https://api.github.com/users/coollabsio/events{/privacy}\",\r\n \"received_events_url\": \"https://api.github.com/users/coollabsio/received_events\",\r\n \"type\": \"Organization\",\r\n \"site_admin\": false\r\n },\r\n \"repo\": {\r\n \"id\": 603035348,\r\n \"node_id\": \"R_kgDOI_GW1A\",\r\n \"name\": \"coolify-examples\",\r\n \"full_name\": \"coollabsio/coolify-examples\",\r\n \"private\": false,\r\n \"owner\": {\r\n \"login\": \"coollabsio\",\r\n \"id\": 60715044,\r\n \"node_id\": \"MDEyOk9yZ2FuaXphdGlvbjYwNzE1MDQ0\",\r\n \"avatar_url\": \"https://avatars.githubusercontent.com/u/60715044?v=4\",\r\n \"gravatar_id\": \"\",\r\n \"url\": \"https://api.github.com/users/coollabsio\",\r\n \"html_url\": \"https://github.com/coollabsio\",\r\n \"followers_url\": \"https://api.github.com/users/coollabsio/followers\",\r\n \"following_url\": \"https://api.github.com/users/coollabsio/following{/other_user}\",\r\n \"gists_url\": \"https://api.github.com/users/coollabsio/gists{/gist_id}\",\r\n \"starred_url\": \"https://api.github.com/users/coollabsio/starred{/owner}{/repo}\",\r\n \"subscriptions_url\": \"https://api.github.com/users/coollabsio/subscriptions\",\r\n \"organizations_url\": \"https://api.github.com/users/coollabsio/orgs\",\r\n \"repos_url\": \"https://api.github.com/users/coollabsio/repos\",\r\n \"events_url\": \"https://api.github.com/users/coollabsio/events{/privacy}\",\r\n \"received_events_url\": \"https://api.github.com/users/coollabsio/received_events\",\r\n \"type\": \"Organization\",\r\n \"site_admin\": false\r\n },\r\n \"html_url\": \"https://github.com/coollabsio/coolify-examples\",\r\n \"description\": null,\r\n \"fork\": false,\r\n \"url\": \"https://api.github.com/repos/coollabsio/coolify-examples\",\r\n \"forks_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/forks\",\r\n \"keys_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/keys{/key_id}\",\r\n \"collaborators_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/collaborators{/collaborator}\",\r\n \"teams_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/teams\",\r\n \"hooks_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/hooks\",\r\n \"issue_events_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/issues/events{/number}\",\r\n \"events_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/events\",\r\n \"assignees_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/assignees{/user}\",\r\n \"branches_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/branches{/branch}\",\r\n \"tags_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/tags\",\r\n \"blobs_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/git/blobs{/sha}\",\r\n \"git_tags_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/git/tags{/sha}\",\r\n \"git_refs_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/git/refs{/sha}\",\r\n \"trees_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/git/trees{/sha}\",\r\n \"statuses_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/statuses/{sha}\",\r\n \"languages_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/languages\",\r\n \"stargazers_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/stargazers\",\r\n \"contributors_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/contributors\",\r\n \"subscribers_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/subscribers\",\r\n \"subscription_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/subscription\",\r\n \"commits_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/commits{/sha}\",\r\n \"git_commits_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/git/commits{/sha}\",\r\n \"comments_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/comments{/number}\",\r\n \"issue_comment_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/issues/comments{/number}\",\r\n \"contents_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/contents/{+path}\",\r\n \"compare_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/compare/{base}...{head}\",\r\n \"merges_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/merges\",\r\n \"archive_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/{archive_format}{/ref}\",\r\n \"downloads_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/downloads\",\r\n \"issues_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/issues{/number}\",\r\n \"pulls_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/pulls{/number}\",\r\n \"milestones_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/milestones{/number}\",\r\n \"notifications_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/notifications{?since,all,participating}\",\r\n \"labels_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/labels{/name}\",\r\n \"releases_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/releases{/id}\",\r\n \"deployments_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/deployments\",\r\n \"created_at\": \"2023-02-17T13:39:18Z\",\r\n \"updated_at\": \"2023-03-02T12:38:23Z\",\r\n \"pushed_at\": \"2023-06-13T09:12:21Z\",\r\n \"git_url\": \"git://github.com/coollabsio/coolify-examples.git\",\r\n \"ssh_url\": \"git@github.com:coollabsio/coolify-examples.git\",\r\n \"clone_url\": \"https://github.com/coollabsio/coolify-examples.git\",\r\n \"svn_url\": \"https://github.com/coollabsio/coolify-examples\",\r\n \"homepage\": null,\r\n \"size\": 37,\r\n \"stargazers_count\": 0,\r\n \"watchers_count\": 0,\r\n \"language\": null,\r\n \"has_issues\": true,\r\n \"has_projects\": true,\r\n \"has_downloads\": true,\r\n \"has_wiki\": true,\r\n \"has_pages\": false,\r\n \"has_discussions\": false,\r\n \"forks_count\": 0,\r\n \"mirror_url\": null,\r\n \"archived\": false,\r\n \"disabled\": false,\r\n \"open_issues_count\": 3,\r\n \"license\": null,\r\n \"allow_forking\": true,\r\n \"is_template\": false,\r\n \"web_commit_signoff_required\": false,\r\n \"topics\": [\r\n\r\n ],\r\n \"visibility\": \"public\",\r\n \"forks\": 0,\r\n \"open_issues\": 3,\r\n \"watchers\": 0,\r\n \"default_branch\": \"main\",\r\n \"allow_squash_merge\": true,\r\n \"allow_merge_commit\": true,\r\n \"allow_rebase_merge\": true,\r\n \"allow_auto_merge\": false,\r\n \"delete_branch_on_merge\": false,\r\n \"allow_update_branch\": false,\r\n \"use_squash_pr_title_as_default\": false,\r\n \"squash_merge_commit_message\": \"COMMIT_MESSAGES\",\r\n \"squash_merge_commit_title\": \"COMMIT_OR_PR_TITLE\",\r\n \"merge_commit_message\": \"PR_TITLE\",\r\n \"merge_commit_title\": \"MERGE_MESSAGE\"\r\n }\r\n },\r\n \"base\": {\r\n \"label\": \"coollabsio:main\",\r\n \"ref\": \"main\",\r\n \"sha\": \"fe2b09858ef03d8825b5139ed2823eed215cc855\",\r\n \"user\": {\r\n \"login\": \"coollabsio\",\r\n \"id\": 60715044,\r\n \"node_id\": \"MDEyOk9yZ2FuaXphdGlvbjYwNzE1MDQ0\",\r\n \"avatar_url\": \"https://avatars.githubusercontent.com/u/60715044?v=4\",\r\n \"gravatar_id\": \"\",\r\n \"url\": \"https://api.github.com/users/coollabsio\",\r\n \"html_url\": \"https://github.com/coollabsio\",\r\n \"followers_url\": \"https://api.github.com/users/coollabsio/followers\",\r\n \"following_url\": \"https://api.github.com/users/coollabsio/following{/other_user}\",\r\n \"gists_url\": \"https://api.github.com/users/coollabsio/gists{/gist_id}\",\r\n \"starred_url\": \"https://api.github.com/users/coollabsio/starred{/owner}{/repo}\",\r\n \"subscriptions_url\": \"https://api.github.com/users/coollabsio/subscriptions\",\r\n \"organizations_url\": \"https://api.github.com/users/coollabsio/orgs\",\r\n \"repos_url\": \"https://api.github.com/users/coollabsio/repos\",\r\n \"events_url\": \"https://api.github.com/users/coollabsio/events{/privacy}\",\r\n \"received_events_url\": \"https://api.github.com/users/coollabsio/received_events\",\r\n \"type\": \"Organization\",\r\n \"site_admin\": false\r\n },\r\n \"repo\": {\r\n \"id\": 603035348,\r\n \"node_id\": \"R_kgDOI_GW1A\",\r\n \"name\": \"coolify-examples\",\r\n \"full_name\": \"coollabsio/coolify-examples\",\r\n \"private\": false,\r\n \"owner\": {\r\n \"login\": \"coollabsio\",\r\n \"id\": 60715044,\r\n \"node_id\": \"MDEyOk9yZ2FuaXphdGlvbjYwNzE1MDQ0\",\r\n \"avatar_url\": \"https://avatars.githubusercontent.com/u/60715044?v=4\",\r\n \"gravatar_id\": \"\",\r\n \"url\": \"https://api.github.com/users/coollabsio\",\r\n \"html_url\": \"https://github.com/coollabsio\",\r\n \"followers_url\": \"https://api.github.com/users/coollabsio/followers\",\r\n \"following_url\": \"https://api.github.com/users/coollabsio/following{/other_user}\",\r\n \"gists_url\": \"https://api.github.com/users/coollabsio/gists{/gist_id}\",\r\n \"starred_url\": \"https://api.github.com/users/coollabsio/starred{/owner}{/repo}\",\r\n \"subscriptions_url\": \"https://api.github.com/users/coollabsio/subscriptions\",\r\n \"organizations_url\": \"https://api.github.com/users/coollabsio/orgs\",\r\n \"repos_url\": \"https://api.github.com/users/coollabsio/repos\",\r\n \"events_url\": \"https://api.github.com/users/coollabsio/events{/privacy}\",\r\n \"received_events_url\": \"https://api.github.com/users/coollabsio/received_events\",\r\n \"type\": \"Organization\",\r\n \"site_admin\": false\r\n },\r\n \"html_url\": \"https://github.com/coollabsio/coolify-examples\",\r\n \"description\": null,\r\n \"fork\": false,\r\n \"url\": \"https://api.github.com/repos/coollabsio/coolify-examples\",\r\n \"forks_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/forks\",\r\n \"keys_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/keys{/key_id}\",\r\n \"collaborators_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/collaborators{/collaborator}\",\r\n \"teams_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/teams\",\r\n \"hooks_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/hooks\",\r\n \"issue_events_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/issues/events{/number}\",\r\n \"events_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/events\",\r\n \"assignees_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/assignees{/user}\",\r\n \"branches_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/branches{/branch}\",\r\n \"tags_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/tags\",\r\n \"blobs_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/git/blobs{/sha}\",\r\n \"git_tags_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/git/tags{/sha}\",\r\n \"git_refs_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/git/refs{/sha}\",\r\n \"trees_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/git/trees{/sha}\",\r\n \"statuses_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/statuses/{sha}\",\r\n \"languages_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/languages\",\r\n \"stargazers_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/stargazers\",\r\n \"contributors_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/contributors\",\r\n \"subscribers_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/subscribers\",\r\n \"subscription_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/subscription\",\r\n \"commits_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/commits{/sha}\",\r\n \"git_commits_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/git/commits{/sha}\",\r\n \"comments_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/comments{/number}\",\r\n \"issue_comment_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/issues/comments{/number}\",\r\n \"contents_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/contents/{+path}\",\r\n \"compare_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/compare/{base}...{head}\",\r\n \"merges_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/merges\",\r\n \"archive_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/{archive_format}{/ref}\",\r\n \"downloads_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/downloads\",\r\n \"issues_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/issues{/number}\",\r\n \"pulls_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/pulls{/number}\",\r\n \"milestones_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/milestones{/number}\",\r\n \"notifications_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/notifications{?since,all,participating}\",\r\n \"labels_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/labels{/name}\",\r\n \"releases_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/releases{/id}\",\r\n \"deployments_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/deployments\",\r\n \"created_at\": \"2023-02-17T13:39:18Z\",\r\n \"updated_at\": \"2023-03-02T12:38:23Z\",\r\n \"pushed_at\": \"2023-06-13T09:12:21Z\",\r\n \"git_url\": \"git://github.com/coollabsio/coolify-examples.git\",\r\n \"ssh_url\": \"git@github.com:coollabsio/coolify-examples.git\",\r\n \"clone_url\": \"https://github.com/coollabsio/coolify-examples.git\",\r\n \"svn_url\": \"https://github.com/coollabsio/coolify-examples\",\r\n \"homepage\": null,\r\n \"size\": 37,\r\n \"stargazers_count\": 0,\r\n \"watchers_count\": 0,\r\n \"language\": null,\r\n \"has_issues\": true,\r\n \"has_projects\": true,\r\n \"has_downloads\": true,\r\n \"has_wiki\": true,\r\n \"has_pages\": false,\r\n \"has_discussions\": false,\r\n \"forks_count\": 0,\r\n \"mirror_url\": null,\r\n \"archived\": false,\r\n \"disabled\": false,\r\n \"open_issues_count\": 3,\r\n \"license\": null,\r\n \"allow_forking\": true,\r\n \"is_template\": false,\r\n \"web_commit_signoff_required\": false,\r\n \"topics\": [\r\n\r\n ],\r\n \"visibility\": \"public\",\r\n \"forks\": 0,\r\n \"open_issues\": 3,\r\n \"watchers\": 0,\r\n \"default_branch\": \"main\",\r\n \"allow_squash_merge\": true,\r\n \"allow_merge_commit\": true,\r\n \"allow_rebase_merge\": true,\r\n \"allow_auto_merge\": false,\r\n \"delete_branch_on_merge\": false,\r\n \"allow_update_branch\": false,\r\n \"use_squash_pr_title_as_default\": false,\r\n \"squash_merge_commit_message\": \"COMMIT_MESSAGES\",\r\n \"squash_merge_commit_title\": \"COMMIT_OR_PR_TITLE\",\r\n \"merge_commit_message\": \"PR_TITLE\",\r\n \"merge_commit_title\": \"MERGE_MESSAGE\"\r\n }\r\n },\r\n \"_links\": {\r\n \"self\": {\r\n \"href\": \"https://api.github.com/repos/coollabsio/coolify-examples/pulls/1\"\r\n },\r\n \"html\": {\r\n \"href\": \"https://github.com/coollabsio/coolify-examples/pull/1\"\r\n },\r\n \"issue\": {\r\n \"href\": \"https://api.github.com/repos/coollabsio/coolify-examples/issues/1\"\r\n },\r\n \"comments\": {\r\n \"href\": \"https://api.github.com/repos/coollabsio/coolify-examples/issues/1/comments\"\r\n },\r\n \"review_comments\": {\r\n \"href\": \"https://api.github.com/repos/coollabsio/coolify-examples/pulls/1/comments\"\r\n },\r\n \"review_comment\": {\r\n \"href\": \"https://api.github.com/repos/coollabsio/coolify-examples/pulls/comments{/number}\"\r\n },\r\n \"commits\": {\r\n \"href\": \"https://api.github.com/repos/coollabsio/coolify-examples/pulls/1/commits\"\r\n },\r\n \"statuses\": {\r\n \"href\": \"https://api.github.com/repos/coollabsio/coolify-examples/statuses/7bf7f99f08108661bee8ead3c3854b491030b4d7\"\r\n }\r\n },\r\n \"author_association\": \"MEMBER\",\r\n \"auto_merge\": null,\r\n \"active_lock_reason\": null,\r\n \"merged\": false,\r\n \"mergeable\": null,\r\n \"rebaseable\": null,\r\n \"mergeable_state\": \"unknown\",\r\n \"merged_by\": null,\r\n \"comments\": 1,\r\n \"review_comments\": 0,\r\n \"maintainer_can_modify\": false,\r\n \"commits\": 3,\r\n \"additions\": 39,\r\n \"deletions\": 1,\r\n \"changed_files\": 3\r\n },\r\n \"repository\": {\r\n \"id\": 603035348,\r\n \"node_id\": \"R_kgDOI_GW1A\",\r\n \"name\": \"coolify-examples\",\r\n \"full_name\": \"coollabsio/coolify-examples\",\r\n \"private\": false,\r\n \"owner\": {\r\n \"login\": \"coollabsio\",\r\n \"id\": 60715044,\r\n \"node_id\": \"MDEyOk9yZ2FuaXphdGlvbjYwNzE1MDQ0\",\r\n \"avatar_url\": \"https://avatars.githubusercontent.com/u/60715044?v=4\",\r\n \"gravatar_id\": \"\",\r\n \"url\": \"https://api.github.com/users/coollabsio\",\r\n \"html_url\": \"https://github.com/coollabsio\",\r\n \"followers_url\": \"https://api.github.com/users/coollabsio/followers\",\r\n \"following_url\": \"https://api.github.com/users/coollabsio/following{/other_user}\",\r\n \"gists_url\": \"https://api.github.com/users/coollabsio/gists{/gist_id}\",\r\n \"starred_url\": \"https://api.github.com/users/coollabsio/starred{/owner}{/repo}\",\r\n \"subscriptions_url\": \"https://api.github.com/users/coollabsio/subscriptions\",\r\n \"organizations_url\": \"https://api.github.com/users/coollabsio/orgs\",\r\n \"repos_url\": \"https://api.github.com/users/coollabsio/repos\",\r\n \"events_url\": \"https://api.github.com/users/coollabsio/events{/privacy}\",\r\n \"received_events_url\": \"https://api.github.com/users/coollabsio/received_events\",\r\n \"type\": \"Organization\",\r\n \"site_admin\": false\r\n },\r\n \"html_url\": \"https://github.com/coollabsio/coolify-examples\",\r\n \"description\": null,\r\n \"fork\": false,\r\n \"url\": \"https://api.github.com/repos/coollabsio/coolify-examples\",\r\n \"forks_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/forks\",\r\n \"keys_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/keys{/key_id}\",\r\n \"collaborators_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/collaborators{/collaborator}\",\r\n \"teams_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/teams\",\r\n \"hooks_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/hooks\",\r\n \"issue_events_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/issues/events{/number}\",\r\n \"events_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/events\",\r\n \"assignees_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/assignees{/user}\",\r\n \"branches_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/branches{/branch}\",\r\n \"tags_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/tags\",\r\n \"blobs_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/git/blobs{/sha}\",\r\n \"git_tags_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/git/tags{/sha}\",\r\n \"git_refs_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/git/refs{/sha}\",\r\n \"trees_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/git/trees{/sha}\",\r\n \"statuses_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/statuses/{sha}\",\r\n \"languages_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/languages\",\r\n \"stargazers_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/stargazers\",\r\n \"contributors_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/contributors\",\r\n \"subscribers_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/subscribers\",\r\n \"subscription_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/subscription\",\r\n \"commits_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/commits{/sha}\",\r\n \"git_commits_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/git/commits{/sha}\",\r\n \"comments_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/comments{/number}\",\r\n \"issue_comment_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/issues/comments{/number}\",\r\n \"contents_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/contents/{+path}\",\r\n \"compare_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/compare/{base}...{head}\",\r\n \"merges_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/merges\",\r\n \"archive_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/{archive_format}{/ref}\",\r\n \"downloads_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/downloads\",\r\n \"issues_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/issues{/number}\",\r\n \"pulls_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/pulls{/number}\",\r\n \"milestones_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/milestones{/number}\",\r\n \"notifications_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/notifications{?since,all,participating}\",\r\n \"labels_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/labels{/name}\",\r\n \"releases_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/releases{/id}\",\r\n \"deployments_url\": \"https://api.github.com/repos/coollabsio/coolify-examples/deployments\",\r\n \"created_at\": \"2023-02-17T13:39:18Z\",\r\n \"updated_at\": \"2023-03-02T12:38:23Z\",\r\n \"pushed_at\": \"2023-06-13T09:12:21Z\",\r\n \"git_url\": \"git://github.com/coollabsio/coolify-examples.git\",\r\n \"ssh_url\": \"git@github.com:coollabsio/coolify-examples.git\",\r\n \"clone_url\": \"https://github.com/coollabsio/coolify-examples.git\",\r\n \"svn_url\": \"https://github.com/coollabsio/coolify-examples\",\r\n \"homepage\": null,\r\n \"size\": 37,\r\n \"stargazers_count\": 0,\r\n \"watchers_count\": 0,\r\n \"language\": null,\r\n \"has_issues\": true,\r\n \"has_projects\": true,\r\n \"has_downloads\": true,\r\n \"has_wiki\": true,\r\n \"has_pages\": false,\r\n \"has_discussions\": false,\r\n \"forks_count\": 0,\r\n \"mirror_url\": null,\r\n \"archived\": false,\r\n \"disabled\": false,\r\n \"open_issues_count\": 3,\r\n \"license\": null,\r\n \"allow_forking\": true,\r\n \"is_template\": false,\r\n \"web_commit_signoff_required\": false,\r\n \"topics\": [\r\n\r\n ],\r\n \"visibility\": \"public\",\r\n \"forks\": 0,\r\n \"open_issues\": 3,\r\n \"watchers\": 0,\r\n \"default_branch\": \"main\"\r\n },\r\n \"organization\": {\r\n \"login\": \"coollabsio\",\r\n \"id\": 60715044,\r\n \"node_id\": \"MDEyOk9yZ2FuaXphdGlvbjYwNzE1MDQ0\",\r\n \"url\": \"https://api.github.com/orgs/coollabsio\",\r\n \"repos_url\": \"https://api.github.com/orgs/coollabsio/repos\",\r\n \"events_url\": \"https://api.github.com/orgs/coollabsio/events\",\r\n \"hooks_url\": \"https://api.github.com/orgs/coollabsio/hooks\",\r\n \"issues_url\": \"https://api.github.com/orgs/coollabsio/issues\",\r\n \"members_url\": \"https://api.github.com/orgs/coollabsio/members{/member}\",\r\n \"public_members_url\": \"https://api.github.com/orgs/coollabsio/public_members{/member}\",\r\n \"avatar_url\": \"https://avatars.githubusercontent.com/u/60715044?v=4\",\r\n \"description\": \"Control your digital footprint | Open-source & self-hostable applications and services built for your online safety.\"\r\n },\r\n \"sender\": {\r\n \"login\": \"andrasbacsai\",\r\n \"id\": 5845193,\r\n \"node_id\": \"MDQ6VXNlcjU4NDUxOTM=\",\r\n \"avatar_url\": \"https://avatars.githubusercontent.com/u/5845193?v=4\",\r\n \"gravatar_id\": \"\",\r\n \"url\": \"https://api.github.com/users/andrasbacsai\",\r\n \"html_url\": \"https://github.com/andrasbacsai\",\r\n \"followers_url\": \"https://api.github.com/users/andrasbacsai/followers\",\r\n \"following_url\": \"https://api.github.com/users/andrasbacsai/following{/other_user}\",\r\n \"gists_url\": \"https://api.github.com/users/andrasbacsai/gists{/gist_id}\",\r\n \"starred_url\": \"https://api.github.com/users/andrasbacsai/starred{/owner}{/repo}\",\r\n \"subscriptions_url\": \"https://api.github.com/users/andrasbacsai/subscriptions\",\r\n \"organizations_url\": \"https://api.github.com/users/andrasbacsai/orgs\",\r\n \"repos_url\": \"https://api.github.com/users/andrasbacsai/repos\",\r\n \"events_url\": \"https://api.github.com/users/andrasbacsai/events{/privacy}\",\r\n \"received_events_url\": \"https://api.github.com/users/andrasbacsai/received_events\",\r\n \"type\": \"User\",\r\n \"site_admin\": false\r\n },\r\n \"installation\": {\r\n \"id\": 37267016,\r\n \"node_id\": \"MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMzcyNjcwMTY=\"\r\n }\r\n}", "form": [] }, "tests": []