mirror of
https://github.com/coollabsio/coolify.git
synced 2026-06-19 07:35:25 +00:00
fix(security): hide notification secrets from non-admins
Prevent users without update permission from reading notification credentials and manual webhook secrets in Livewire state or rendered forms.
This commit is contained in:
@@ -110,7 +110,9 @@ class Discord extends Component
|
||||
refreshSession();
|
||||
} else {
|
||||
$this->discordEnabled = $this->settings->discord_enabled;
|
||||
$this->discordWebhookUrl = $this->settings->discord_webhook_url;
|
||||
$this->discordWebhookUrl = auth()->user()->can('update', $this->settings)
|
||||
? $this->settings->discord_webhook_url
|
||||
: null;
|
||||
|
||||
$this->deploymentSuccessDiscordNotifications = $this->settings->deployment_success_discord_notifications;
|
||||
$this->deploymentFailureDiscordNotifications = $this->settings->deployment_failure_discord_notifications;
|
||||
|
||||
@@ -113,8 +113,13 @@ class Pushover extends Component
|
||||
refreshSession();
|
||||
} else {
|
||||
$this->pushoverEnabled = $this->settings->pushover_enabled;
|
||||
$this->pushoverUserKey = $this->settings->pushover_user_key;
|
||||
$this->pushoverApiToken = $this->settings->pushover_api_token;
|
||||
if (auth()->user()->can('update', $this->settings)) {
|
||||
$this->pushoverUserKey = $this->settings->pushover_user_key;
|
||||
$this->pushoverApiToken = $this->settings->pushover_api_token;
|
||||
} else {
|
||||
$this->pushoverUserKey = null;
|
||||
$this->pushoverApiToken = null;
|
||||
}
|
||||
|
||||
$this->deploymentSuccessPushoverNotifications = $this->settings->deployment_success_pushover_notifications;
|
||||
$this->deploymentFailurePushoverNotifications = $this->settings->deployment_failure_pushover_notifications;
|
||||
|
||||
@@ -110,7 +110,9 @@ class Slack extends Component
|
||||
refreshSession();
|
||||
} else {
|
||||
$this->slackEnabled = $this->settings->slack_enabled;
|
||||
$this->slackWebhookUrl = $this->settings->slack_webhook_url;
|
||||
$this->slackWebhookUrl = auth()->user()->can('update', $this->settings)
|
||||
? $this->settings->slack_webhook_url
|
||||
: null;
|
||||
|
||||
$this->deploymentSuccessSlackNotifications = $this->settings->deployment_success_slack_notifications;
|
||||
$this->deploymentFailureSlackNotifications = $this->settings->deployment_failure_slack_notifications;
|
||||
|
||||
@@ -169,8 +169,13 @@ class Telegram extends Component
|
||||
$this->settings->save();
|
||||
} else {
|
||||
$this->telegramEnabled = $this->settings->telegram_enabled;
|
||||
$this->telegramToken = $this->settings->telegram_token;
|
||||
$this->telegramChatId = $this->settings->telegram_chat_id;
|
||||
if (auth()->user()->can('update', $this->settings)) {
|
||||
$this->telegramToken = $this->settings->telegram_token;
|
||||
$this->telegramChatId = $this->settings->telegram_chat_id;
|
||||
} else {
|
||||
$this->telegramToken = null;
|
||||
$this->telegramChatId = null;
|
||||
}
|
||||
|
||||
$this->deploymentSuccessTelegramNotifications = $this->settings->deployment_success_telegram_notifications;
|
||||
$this->deploymentFailureTelegramNotifications = $this->settings->deployment_failure_telegram_notifications;
|
||||
|
||||
@@ -105,7 +105,9 @@ class Webhook extends Component
|
||||
refreshSession();
|
||||
} else {
|
||||
$this->webhookEnabled = $this->settings->webhook_enabled;
|
||||
$this->webhookUrl = $this->settings->webhook_url;
|
||||
$this->webhookUrl = auth()->user()->can('update', $this->settings)
|
||||
? $this->settings->webhook_url
|
||||
: null;
|
||||
|
||||
$this->deploymentSuccessWebhookNotifications = $this->settings->deployment_success_webhook_notifications;
|
||||
$this->deploymentFailureWebhookNotifications = $this->settings->deployment_failure_webhook_notifications;
|
||||
|
||||
@@ -34,19 +34,24 @@ class Webhooks extends Component
|
||||
{
|
||||
$this->deploywebhook = generateDeployWebhook($this->resource);
|
||||
|
||||
$this->githubManualWebhookSecret = data_get($this->resource, 'manual_webhook_secret_github');
|
||||
if ($this->canViewSecrets()) {
|
||||
$this->githubManualWebhookSecret = data_get($this->resource, 'manual_webhook_secret_github');
|
||||
$this->gitlabManualWebhookSecret = data_get($this->resource, 'manual_webhook_secret_gitlab');
|
||||
$this->bitbucketManualWebhookSecret = data_get($this->resource, 'manual_webhook_secret_bitbucket');
|
||||
$this->giteaManualWebhookSecret = data_get($this->resource, 'manual_webhook_secret_gitea');
|
||||
}
|
||||
|
||||
$this->githubManualWebhook = generateGitManualWebhook($this->resource, 'github');
|
||||
|
||||
$this->gitlabManualWebhookSecret = data_get($this->resource, 'manual_webhook_secret_gitlab');
|
||||
$this->gitlabManualWebhook = generateGitManualWebhook($this->resource, 'gitlab');
|
||||
|
||||
$this->bitbucketManualWebhookSecret = data_get($this->resource, 'manual_webhook_secret_bitbucket');
|
||||
$this->bitbucketManualWebhook = generateGitManualWebhook($this->resource, 'bitbucket');
|
||||
|
||||
$this->giteaManualWebhookSecret = data_get($this->resource, 'manual_webhook_secret_gitea');
|
||||
$this->giteaManualWebhook = generateGitManualWebhook($this->resource, 'gitea');
|
||||
}
|
||||
|
||||
public function canViewSecrets(): bool
|
||||
{
|
||||
return auth()->user()->can('update', $this->resource);
|
||||
}
|
||||
|
||||
public function submit()
|
||||
{
|
||||
try {
|
||||
|
||||
@@ -26,9 +26,15 @@
|
||||
helper="If enabled, a ping (@here) will be sent to the notification when a critical event happens."
|
||||
label="Ping Enabled" />
|
||||
</div>
|
||||
<x-forms.input canGate="update" :canResource="$settings" type="password"
|
||||
helper="Create a Discord Server and generate a Webhook URL. <br><a class='inline-block underline dark:text-white' href='https://support.discord.com/hc/en-us/articles/228383668-Intro-to-Webhooks' target='_blank'>Webhook Documentation</a>"
|
||||
required id="discordWebhookUrl" label="Webhook" />
|
||||
@can('update', $settings)
|
||||
<x-forms.input type="password"
|
||||
helper="Create a Discord Server and generate a Webhook URL. <br><a class='inline-block underline dark:text-white' href='https://support.discord.com/hc/en-us/articles/228383668-Intro-to-Webhooks' target='_blank'>Webhook Documentation</a>"
|
||||
required id="discordWebhookUrl" label="Webhook" />
|
||||
@else
|
||||
<x-forms.input disabled
|
||||
helper="Create a Discord Server and generate a Webhook URL. <br><a class='inline-block underline dark:text-white' href='https://support.discord.com/hc/en-us/articles/228383668-Intro-to-Webhooks' target='_blank'>Webhook Documentation</a>"
|
||||
required label="Webhook" value="Hidden (only admins can view)" />
|
||||
@endcan
|
||||
</form>
|
||||
<h2 class="mt-4">Notification Settings</h2>
|
||||
<p class="mb-4">
|
||||
|
||||
@@ -24,12 +24,21 @@
|
||||
<x-forms.checkbox canGate="update" :canResource="$settings" instantSave="instantSavePushoverEnabled" id="pushoverEnabled" label="Enabled" />
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input canGate="update" :canResource="$settings" type="password"
|
||||
helper="Get your User Key in Pushover. You need to be logged in to Pushover to see your user key in the top right corner. <br><a class='inline-block underline dark:text-white' href='https://pushover.net/' target='_blank'>Pushover Dashboard</a>"
|
||||
required id="pushoverUserKey" label="User Key" />
|
||||
<x-forms.input canGate="update" :canResource="$settings" type="password"
|
||||
helper="Generate an API Token/Key in Pushover by creating a new application. <br><a class='inline-block underline dark:text-white' href='https://pushover.net/apps/build' target='_blank'>Create Pushover Application</a>"
|
||||
required id="pushoverApiToken" label="API Token" />
|
||||
@can('update', $settings)
|
||||
<x-forms.input type="password"
|
||||
helper="Get your User Key in Pushover. You need to be logged in to Pushover to see your user key in the top right corner. <br><a class='inline-block underline dark:text-white' href='https://pushover.net/' target='_blank'>Pushover Dashboard</a>"
|
||||
required id="pushoverUserKey" label="User Key" />
|
||||
<x-forms.input type="password"
|
||||
helper="Generate an API Token/Key in Pushover by creating a new application. <br><a class='inline-block underline dark:text-white' href='https://pushover.net/apps/build' target='_blank'>Create Pushover Application</a>"
|
||||
required id="pushoverApiToken" label="API Token" />
|
||||
@else
|
||||
<x-forms.input disabled
|
||||
helper="Get your User Key in Pushover. You need to be logged in to Pushover to see your user key in the top right corner. <br><a class='inline-block underline dark:text-white' href='https://pushover.net/' target='_blank'>Pushover Dashboard</a>"
|
||||
required label="User Key" value="Hidden (only admins can view)" />
|
||||
<x-forms.input disabled
|
||||
helper="Generate an API Token/Key in Pushover by creating a new application. <br><a class='inline-block underline dark:text-white' href='https://pushover.net/apps/build' target='_blank'>Create Pushover Application</a>"
|
||||
required label="API Token" value="Hidden (only admins can view)" />
|
||||
@endcan
|
||||
</div>
|
||||
</form>
|
||||
<h2 class="mt-4">Notification Settings</h2>
|
||||
|
||||
@@ -23,9 +23,15 @@
|
||||
<div class="w-32">
|
||||
<x-forms.checkbox canGate="update" :canResource="$settings" instantSave="instantSaveSlackEnabled" id="slackEnabled" label="Enabled" />
|
||||
</div>
|
||||
<x-forms.input canGate="update" :canResource="$settings" type="password"
|
||||
helper="Create a Slack APP and generate a Incoming Webhook URL. <br><a class='inline-block underline dark:text-white' href='https://api.slack.com/apps' target='_blank'>Create Slack APP</a>"
|
||||
required id="slackWebhookUrl" label="Webhook" />
|
||||
@can('update', $settings)
|
||||
<x-forms.input type="password"
|
||||
helper="Create a Slack APP and generate a Incoming Webhook URL. <br><a class='inline-block underline dark:text-white' href='https://api.slack.com/apps' target='_blank'>Create Slack APP</a>"
|
||||
required id="slackWebhookUrl" label="Webhook" />
|
||||
@else
|
||||
<x-forms.input disabled
|
||||
helper="Create a Slack APP and generate a Incoming Webhook URL. <br><a class='inline-block underline dark:text-white' href='https://api.slack.com/apps' target='_blank'>Create Slack APP</a>"
|
||||
required label="Webhook" value="Hidden (only admins can view)" />
|
||||
@endcan
|
||||
</form>
|
||||
<h2 class="mt-4">Notification Settings</h2>
|
||||
<p class="mb-4">
|
||||
|
||||
@@ -24,12 +24,21 @@
|
||||
<x-forms.checkbox canGate="update" :canResource="$settings" instantSave="instantSaveTelegramEnabled" id="telegramEnabled" label="Enabled" />
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input canGate="update" :canResource="$settings" type="password" autocomplete="new-password"
|
||||
helper="Get it from the <a class='inline-block underline dark:text-white' href='https://t.me/botfather' target='_blank'>BotFather Bot</a> on Telegram."
|
||||
required id="telegramToken" label="Bot API Token" />
|
||||
<x-forms.input canGate="update" :canResource="$settings" type="password" autocomplete="new-password"
|
||||
helper="Add your bot to a group chat and add its Chat ID here." required id="telegramChatId"
|
||||
label="Chat ID" />
|
||||
@can('update', $settings)
|
||||
<x-forms.input type="password" autocomplete="new-password"
|
||||
helper="Get it from the <a class='inline-block underline dark:text-white' href='https://t.me/botfather' target='_blank'>BotFather Bot</a> on Telegram."
|
||||
required id="telegramToken" label="Bot API Token" />
|
||||
<x-forms.input type="password" autocomplete="new-password"
|
||||
helper="Add your bot to a group chat and add its Chat ID here." required id="telegramChatId"
|
||||
label="Chat ID" />
|
||||
@else
|
||||
<x-forms.input disabled autocomplete="new-password"
|
||||
helper="Get it from the <a class='inline-block underline dark:text-white' href='https://t.me/botfather' target='_blank'>BotFather Bot</a> on Telegram."
|
||||
required label="Bot API Token" value="Hidden (only admins can view)" />
|
||||
<x-forms.input disabled autocomplete="new-password"
|
||||
helper="Add your bot to a group chat and add its Chat ID here." required label="Chat ID"
|
||||
value="Hidden (only admins can view)" />
|
||||
@endcan
|
||||
</div>
|
||||
</form>
|
||||
<h2 class="mt-4">Notification Settings</h2>
|
||||
|
||||
@@ -28,9 +28,15 @@
|
||||
</div>
|
||||
<div class="flex items-end gap-2">
|
||||
|
||||
<x-forms.input canGate="update" :canResource="$settings" type="password"
|
||||
helper="Enter a valid HTTP or HTTPS URL. Coolify will send POST requests to this endpoint when events occur."
|
||||
required id="webhookUrl" label="Webhook URL (POST)" />
|
||||
@can('update', $settings)
|
||||
<x-forms.input type="password"
|
||||
helper="Enter a valid HTTP or HTTPS URL. Coolify will send POST requests to this endpoint when events occur."
|
||||
required id="webhookUrl" label="Webhook URL (POST)" />
|
||||
@else
|
||||
<x-forms.input disabled
|
||||
helper="Enter a valid HTTP or HTTPS URL. Coolify will send POST requests to this endpoint when events occur."
|
||||
required label="Webhook URL (POST)" value="Hidden (only admins can view)" />
|
||||
@endcan
|
||||
</div>
|
||||
</form>
|
||||
<h2 class="mt-4">Notification Settings</h2>
|
||||
|
||||
@@ -22,9 +22,9 @@
|
||||
helper="Need to set a secret to be able to use this webhook. It should match with the secret in GitHub."
|
||||
label="GitHub Webhook Secret" id="githubManualWebhookSecret"></x-forms.input>
|
||||
@else
|
||||
<x-forms.input disabled type="password"
|
||||
<x-forms.input disabled
|
||||
helper="Need to set a secret to be able to use this webhook. It should match with the secret in GitHub."
|
||||
label="GitHub Webhook Secret" id="githubManualWebhookSecret"></x-forms.input>
|
||||
label="GitHub Webhook Secret" value="Hidden (only admins can view)"></x-forms.input>
|
||||
@endcan
|
||||
</div>
|
||||
<a target="_blank" class="flex hover:no-underline" href="{{ $resource?->gitWebhook }}">
|
||||
@@ -39,9 +39,9 @@
|
||||
helper="Need to set a secret to be able to use this webhook. It should match with the secret in GitLab."
|
||||
label="GitLab Webhook Secret" id="gitlabManualWebhookSecret"></x-forms.input>
|
||||
@else
|
||||
<x-forms.input disabled type="password"
|
||||
<x-forms.input disabled
|
||||
helper="Need to set a secret to be able to use this webhook. It should match with the secret in GitLab."
|
||||
label="GitLab Webhook Secret" id="gitlabManualWebhookSecret"></x-forms.input>
|
||||
label="GitLab Webhook Secret" value="Hidden (only admins can view)"></x-forms.input>
|
||||
@endcan
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
@@ -51,9 +51,9 @@
|
||||
helper="Need to set a secret to be able to use this webhook. It should match with the secret in Bitbucket."
|
||||
label="Bitbucket Webhook Secret" id="bitbucketManualWebhookSecret"></x-forms.input>
|
||||
@else
|
||||
<x-forms.input disabled type="password"
|
||||
<x-forms.input disabled
|
||||
helper="Need to set a secret to be able to use this webhook. It should match with the secret in Bitbucket."
|
||||
label="Bitbucket Webhook Secret" id="bitbucketManualWebhookSecret"></x-forms.input>
|
||||
label="Bitbucket Webhook Secret" value="Hidden (only admins can view)"></x-forms.input>
|
||||
@endcan
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
@@ -63,9 +63,9 @@
|
||||
helper="Need to set a secret to be able to use this webhook. It should match with the secret in Gitea."
|
||||
label="Gitea Webhook Secret" id="giteaManualWebhookSecret"></x-forms.input>
|
||||
@else
|
||||
<x-forms.input disabled type="password"
|
||||
<x-forms.input disabled
|
||||
helper="Need to set a secret to be able to use this webhook. It should match with the secret in Gitea."
|
||||
label="Gitea Webhook Secret" id="giteaManualWebhookSecret"></x-forms.input>
|
||||
label="Gitea Webhook Secret" value="Hidden (only admins can view)"></x-forms.input>
|
||||
@endcan
|
||||
</div>
|
||||
@can('update', $resource)
|
||||
|
||||
@@ -15,7 +15,7 @@ use Livewire\Livewire;
|
||||
uses(RefreshDatabase::class);
|
||||
|
||||
beforeEach(function () {
|
||||
InstanceSettings::updateOrCreate(['id' => 0]);
|
||||
InstanceSettings::unguarded(fn () => InstanceSettings::updateOrCreate(['id' => 0], ['id' => 0]));
|
||||
|
||||
$this->team = Team::factory()->create();
|
||||
|
||||
@@ -275,3 +275,75 @@ test('member cannot send test on any notification channel', function () {
|
||||
expect($this->member->can('sendTest', $this->team->pushoverNotificationSettings))->toBeFalse();
|
||||
expect($this->member->can('sendTest', $this->team->webhookNotificationSettings))->toBeFalse();
|
||||
});
|
||||
|
||||
test('member cannot view notification secrets', function (string $component, string $settingsRelation, array $secrets) {
|
||||
$settings = $this->team->{$settingsRelation};
|
||||
$settings->update($secrets);
|
||||
|
||||
$this->actingAs($this->member);
|
||||
session(['currentTeam' => $this->team]);
|
||||
|
||||
$componentTest = Livewire::test($component);
|
||||
|
||||
foreach ($secrets as $column => $value) {
|
||||
$property = str($column)->camel()->toString();
|
||||
|
||||
$componentTest
|
||||
->assertSet($property, null)
|
||||
->assertDontSee($value);
|
||||
}
|
||||
|
||||
$componentTest->assertSee('Hidden (only admins can view)');
|
||||
})->with([
|
||||
'discord webhook' => [DiscordNotification::class, 'discordNotificationSettings', [
|
||||
'discord_webhook_url' => 'https://discord.com/api/webhooks/secret-member',
|
||||
]],
|
||||
'slack webhook' => [SlackNotification::class, 'slackNotificationSettings', [
|
||||
'slack_webhook_url' => 'https://hooks.slack.com/services/secret-member',
|
||||
]],
|
||||
'telegram token and chat id' => [TelegramNotification::class, 'telegramNotificationSettings', [
|
||||
'telegram_token' => 'telegram-secret-token',
|
||||
'telegram_chat_id' => 'telegram-secret-chat',
|
||||
]],
|
||||
'pushover credentials' => [PushoverNotification::class, 'pushoverNotificationSettings', [
|
||||
'pushover_user_key' => 'pushover-secret-user',
|
||||
'pushover_api_token' => 'pushover-secret-token',
|
||||
]],
|
||||
'generic webhook' => [WebhookNotification::class, 'webhookNotificationSettings', [
|
||||
'webhook_url' => 'https://example.com/secret-webhook',
|
||||
]],
|
||||
]);
|
||||
|
||||
test('admin can view notification secrets', function (string $component, string $settingsRelation, array $secrets) {
|
||||
$settings = $this->team->{$settingsRelation};
|
||||
$settings->update($secrets);
|
||||
|
||||
$this->actingAs($this->admin);
|
||||
session(['currentTeam' => $this->team]);
|
||||
|
||||
$componentTest = Livewire::test($component);
|
||||
|
||||
foreach ($secrets as $column => $value) {
|
||||
$property = str($column)->camel()->toString();
|
||||
|
||||
$componentTest->assertSet($property, $value);
|
||||
}
|
||||
})->with([
|
||||
'discord webhook' => [DiscordNotification::class, 'discordNotificationSettings', [
|
||||
'discord_webhook_url' => 'https://discord.com/api/webhooks/secret-admin',
|
||||
]],
|
||||
'slack webhook' => [SlackNotification::class, 'slackNotificationSettings', [
|
||||
'slack_webhook_url' => 'https://hooks.slack.com/services/secret-admin',
|
||||
]],
|
||||
'telegram token and chat id' => [TelegramNotification::class, 'telegramNotificationSettings', [
|
||||
'telegram_token' => 'telegram-admin-token',
|
||||
'telegram_chat_id' => 'telegram-admin-chat',
|
||||
]],
|
||||
'pushover credentials' => [PushoverNotification::class, 'pushoverNotificationSettings', [
|
||||
'pushover_user_key' => 'pushover-admin-user',
|
||||
'pushover_api_token' => 'pushover-admin-token',
|
||||
]],
|
||||
'generic webhook' => [WebhookNotification::class, 'webhookNotificationSettings', [
|
||||
'webhook_url' => 'https://example.com/admin-webhook',
|
||||
]],
|
||||
]);
|
||||
|
||||
@@ -20,7 +20,7 @@ use Livewire\Livewire;
|
||||
uses(RefreshDatabase::class);
|
||||
|
||||
beforeEach(function () {
|
||||
InstanceSettings::updateOrCreate(['id' => 0]);
|
||||
InstanceSettings::unguarded(fn () => InstanceSettings::updateOrCreate(['id' => 0], ['id' => 0]));
|
||||
|
||||
$this->team = Team::factory()->create();
|
||||
|
||||
@@ -167,6 +167,51 @@ test('admin can update application webhooks', function () {
|
||||
expect($this->admin->can('update', $this->application))->toBeTrue();
|
||||
});
|
||||
|
||||
test('member cannot view application webhook secrets', function () {
|
||||
$this->application->update([
|
||||
'git_repository' => 'coollabsio/coolify',
|
||||
'git_branch' => 'main',
|
||||
'manual_webhook_secret_github' => 'github-secret-value',
|
||||
'manual_webhook_secret_gitlab' => 'gitlab-secret-value',
|
||||
'manual_webhook_secret_bitbucket' => 'bitbucket-secret-value',
|
||||
'manual_webhook_secret_gitea' => 'gitea-secret-value',
|
||||
]);
|
||||
|
||||
$this->actingAs($this->member);
|
||||
session(['currentTeam' => $this->team]);
|
||||
|
||||
Livewire::test(Webhooks::class, ['resource' => $this->application->fresh()])
|
||||
->assertSet('githubManualWebhookSecret', null)
|
||||
->assertSet('gitlabManualWebhookSecret', null)
|
||||
->assertSet('bitbucketManualWebhookSecret', null)
|
||||
->assertSet('giteaManualWebhookSecret', null)
|
||||
->assertSee('Hidden (only admins can view)')
|
||||
->assertDontSee('github-secret-value')
|
||||
->assertDontSee('gitlab-secret-value')
|
||||
->assertDontSee('bitbucket-secret-value')
|
||||
->assertDontSee('gitea-secret-value');
|
||||
});
|
||||
|
||||
test('admin can view application webhook secrets', function () {
|
||||
$this->application->update([
|
||||
'git_repository' => 'coollabsio/coolify',
|
||||
'git_branch' => 'main',
|
||||
'manual_webhook_secret_github' => 'github-secret-value',
|
||||
'manual_webhook_secret_gitlab' => 'gitlab-secret-value',
|
||||
'manual_webhook_secret_bitbucket' => 'bitbucket-secret-value',
|
||||
'manual_webhook_secret_gitea' => 'gitea-secret-value',
|
||||
]);
|
||||
|
||||
$this->actingAs($this->admin);
|
||||
session(['currentTeam' => $this->team]);
|
||||
|
||||
Livewire::test(Webhooks::class, ['resource' => $this->application->fresh()])
|
||||
->assertSet('githubManualWebhookSecret', 'github-secret-value')
|
||||
->assertSet('gitlabManualWebhookSecret', 'gitlab-secret-value')
|
||||
->assertSet('bitbucketManualWebhookSecret', 'bitbucket-secret-value')
|
||||
->assertSet('giteaManualWebhookSecret', 'gitea-secret-value');
|
||||
});
|
||||
|
||||
// --- Resource Limits (policy checks, mount requires full resource data) ---
|
||||
|
||||
test('member cannot update application resource limits', function () {
|
||||
|
||||
Reference in New Issue
Block a user