feat(settings): add option to restrict PR deployments to repository members and contributors

This commit is contained in:
Andras Bacsai
2025-09-05 14:30:51 +02:00
parent f38217e717
commit 339118558c
5 changed files with 68 additions and 0 deletions

View File

@@ -78,6 +78,7 @@ class Github extends Controller
$pull_request_html_url = data_get($payload, 'pull_request.html_url'); $pull_request_html_url = data_get($payload, 'pull_request.html_url');
$branch = data_get($payload, 'pull_request.head.ref'); $branch = data_get($payload, 'pull_request.head.ref');
$base_branch = data_get($payload, 'pull_request.base.ref'); $base_branch = data_get($payload, 'pull_request.base.ref');
$author_association = data_get($payload, 'pull_request.author_association');
} }
if (! $branch) { if (! $branch) {
return response('Nothing to do. No branch found in the request.'); return response('Nothing to do. No branch found in the request.');
@@ -170,6 +171,19 @@ class Github extends Controller
if ($x_github_event === 'pull_request') { if ($x_github_event === 'pull_request') {
if ($action === 'opened' || $action === 'synchronize' || $action === 'reopened') { if ($action === 'opened' || $action === 'synchronize' || $action === 'reopened') {
if ($application->isPRDeployable()) { if ($application->isPRDeployable()) {
// Check if PR deployments from public contributors are restricted
if (! $application->settings->is_pr_deployments_public_enabled) {
$trustedAssociations = ['OWNER', 'MEMBER', 'COLLABORATOR', 'CONTRIBUTOR'];
if (! in_array($author_association, $trustedAssociations)) {
$return_payloads->push([
'application' => $application->name,
'status' => 'failed',
'message' => 'PR deployments are restricted to repository members and contributors. Author association: '.$author_association,
]);
continue;
}
}
$deployment_uuid = new Cuid2; $deployment_uuid = new Cuid2;
$found = ApplicationPreview::where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first(); $found = ApplicationPreview::where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first();
if (! $found) { if (! $found) {
@@ -327,6 +341,7 @@ class Github extends Controller
$pull_request_html_url = data_get($payload, 'pull_request.html_url'); $pull_request_html_url = data_get($payload, 'pull_request.html_url');
$branch = data_get($payload, 'pull_request.head.ref'); $branch = data_get($payload, 'pull_request.head.ref');
$base_branch = data_get($payload, 'pull_request.base.ref'); $base_branch = data_get($payload, 'pull_request.base.ref');
$author_association = data_get($payload, 'pull_request.author_association');
} }
if (! $id || ! $branch) { if (! $id || ! $branch) {
return response('Nothing to do. No id or branch found.'); return response('Nothing to do. No id or branch found.');
@@ -400,6 +415,19 @@ class Github extends Controller
if ($x_github_event === 'pull_request') { if ($x_github_event === 'pull_request') {
if ($action === 'opened' || $action === 'synchronize' || $action === 'reopened') { if ($action === 'opened' || $action === 'synchronize' || $action === 'reopened') {
if ($application->isPRDeployable()) { if ($application->isPRDeployable()) {
// Check if PR deployments from public contributors are restricted
if (! $application->settings->is_pr_deployments_public_enabled) {
$trustedAssociations = ['OWNER', 'MEMBER', 'COLLABORATOR', 'CONTRIBUTOR'];
if (! in_array($author_association, $trustedAssociations)) {
$return_payloads->push([
'application' => $application->name,
'status' => 'failed',
'message' => 'PR deployments are restricted to repository members and contributors. Author association: '.$author_association,
]);
continue;
}
}
$deployment_uuid = new Cuid2; $deployment_uuid = new Cuid2;
$found = ApplicationPreview::where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first(); $found = ApplicationPreview::where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first();
if (! $found) { if (! $found) {

View File

@@ -28,6 +28,9 @@ class Advanced extends Component
#[Validate(['boolean'])] #[Validate(['boolean'])]
public bool $isPreviewDeploymentsEnabled = false; public bool $isPreviewDeploymentsEnabled = false;
#[Validate(['boolean'])]
public bool $isPrDeploymentsPublicEnabled = false;
#[Validate(['boolean'])] #[Validate(['boolean'])]
public bool $isAutoDeployEnabled = true; public bool $isAutoDeployEnabled = true;
@@ -91,6 +94,7 @@ class Advanced extends Component
$this->application->settings->is_git_lfs_enabled = $this->isGitLfsEnabled; $this->application->settings->is_git_lfs_enabled = $this->isGitLfsEnabled;
$this->application->settings->is_git_shallow_clone_enabled = $this->isGitShallowCloneEnabled; $this->application->settings->is_git_shallow_clone_enabled = $this->isGitShallowCloneEnabled;
$this->application->settings->is_preview_deployments_enabled = $this->isPreviewDeploymentsEnabled; $this->application->settings->is_preview_deployments_enabled = $this->isPreviewDeploymentsEnabled;
$this->application->settings->is_pr_deployments_public_enabled = $this->isPrDeploymentsPublicEnabled;
$this->application->settings->is_auto_deploy_enabled = $this->isAutoDeployEnabled; $this->application->settings->is_auto_deploy_enabled = $this->isAutoDeployEnabled;
$this->application->settings->is_log_drain_enabled = $this->isLogDrainEnabled; $this->application->settings->is_log_drain_enabled = $this->isLogDrainEnabled;
$this->application->settings->is_gpu_enabled = $this->isGpuEnabled; $this->application->settings->is_gpu_enabled = $this->isGpuEnabled;
@@ -117,6 +121,7 @@ class Advanced extends Component
$this->isGitLfsEnabled = $this->application->settings->is_git_lfs_enabled; $this->isGitLfsEnabled = $this->application->settings->is_git_lfs_enabled;
$this->isGitShallowCloneEnabled = $this->application->settings->is_git_shallow_clone_enabled ?? false; $this->isGitShallowCloneEnabled = $this->application->settings->is_git_shallow_clone_enabled ?? false;
$this->isPreviewDeploymentsEnabled = $this->application->settings->is_preview_deployments_enabled; $this->isPreviewDeploymentsEnabled = $this->application->settings->is_preview_deployments_enabled;
$this->isPrDeploymentsPublicEnabled = $this->application->settings->is_pr_deployments_public_enabled ?? false;
$this->isAutoDeployEnabled = $this->application->settings->is_auto_deploy_enabled; $this->isAutoDeployEnabled = $this->application->settings->is_auto_deploy_enabled;
$this->isGpuEnabled = $this->application->settings->is_gpu_enabled; $this->isGpuEnabled = $this->application->settings->is_gpu_enabled;
$this->gpuDriver = $this->application->settings->gpu_driver; $this->gpuDriver = $this->application->settings->gpu_driver;

View File

@@ -13,6 +13,7 @@ class ApplicationSetting extends Model
'is_force_https_enabled' => 'boolean', 'is_force_https_enabled' => 'boolean',
'is_debug_enabled' => 'boolean', 'is_debug_enabled' => 'boolean',
'is_preview_deployments_enabled' => 'boolean', 'is_preview_deployments_enabled' => 'boolean',
'is_pr_deployments_public_enabled' => 'boolean',
'is_git_submodules_enabled' => 'boolean', 'is_git_submodules_enabled' => 'boolean',
'is_git_lfs_enabled' => 'boolean', 'is_git_lfs_enabled' => 'boolean',
'is_git_shallow_clone_enabled' => 'boolean', 'is_git_shallow_clone_enabled' => 'boolean',

View File

@@ -0,0 +1,28 @@
<?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::table('application_settings', function (Blueprint $table) {
$table->boolean('is_pr_deployments_public_enabled')->default(false)->after('is_preview_deployments_enabled');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('application_settings', function (Blueprint $table) {
$table->dropColumn('is_pr_deployments_public_enabled');
});
}
};

View File

@@ -13,6 +13,12 @@
helper="Allow to automatically deploy Preview Deployments for all opened PR's.<br><br>Closing a PR will delete Preview Deployments." helper="Allow to automatically deploy Preview Deployments for all opened PR's.<br><br>Closing a PR will delete Preview Deployments."
instantSave id="isPreviewDeploymentsEnabled" label="Preview Deployments" canGate="update" instantSave id="isPreviewDeploymentsEnabled" label="Preview Deployments" canGate="update"
:canResource="$application" /> :canResource="$application" />
@if ($isPreviewDeploymentsEnabled)
<x-forms.checkbox
helper="When enabled, anyone can trigger PR deployments. When disabled, only repository members, collaborators, and contributors can trigger PR deployments."
instantSave id="isPrDeploymentsPublicEnabled" label="Allow Public PR Deployments" canGate="update"
:canResource="$application" />
@endif
@endif @endif
<x-forms.checkbox helper="Disable Docker build cache on every deployment." instantSave <x-forms.checkbox helper="Disable Docker build cache on every deployment." instantSave
id="disableBuildCache" label="Disable Build Cache" canGate="update" :canResource="$application" /> id="disableBuildCache" label="Disable Build Cache" canGate="update" :canResource="$application" />