fix(api): hide sensitive fields by default

Add model-level hidden fields for secrets, tokens, keys, notification
credentials, deployment logs, and environment values. Allow explicit
read:sensitive API access to reveal gated private keys and deployment logs,
and cover the behavior with feature and unit tests.
This commit is contained in:
Andras Bacsai committed 2026-05-11 21:18:07 +02:00
1 parent f40bb80f9d
commit 81a3bb0f07
20 files changed
+335 -2

No files matched your search

@@ -68,6 +68,10 @@ class ApplicationDeploymentQueue extends Model
'finished_at',
];
protected $hidden = [
'logs',
];
protected $casts = [
'pull_request_id' => 'integer',
'finished_at' => 'datetime',
+4
View File
@@ -12,6 +12,10 @@ class CloudInitScript extends Model
'script',
];
protected $hidden = [
'script',
];
protected function casts(): array
{
return [
+4
View File
@@ -11,6 +11,10 @@ class CloudProviderToken extends BaseModel
'name',
];
protected $hidden = [
'token',
];
protected $casts = [
'token' => 'encrypted',
];
@@ -34,6 +34,10 @@ class DiscordNotificationSettings extends Model
'discord_ping_enabled',
];
protected $hidden = [
'discord_webhook_url',
];
protected $casts = [
'discord_enabled' => 'boolean',
'discord_webhook_url' => 'encrypted',
+10
View File
@@ -43,6 +43,16 @@ class EmailNotificationSettings extends Model
'traefik_outdated_email_notifications',
];
protected $hidden = [
'smtp_from_address',
'smtp_from_name',
'smtp_recipients',
'smtp_host',
'smtp_username',
'smtp_password',
'resend_api_key',
];
protected $casts = [
'smtp_enabled' => 'boolean',
'smtp_from_address' => 'encrypted',
+11
View File
@@ -48,6 +48,17 @@ class InstanceSettings extends Model
'is_mcp_server_enabled',
];
protected $hidden = [
'smtp_from_address',
'smtp_from_name',
'smtp_recipients',
'smtp_host',
'smtp_username',
'smtp_password',
'resend_api_key',
'sentinel_token',
];
protected $casts = [
'smtp_enabled' => 'boolean',
'smtp_from_address' => 'encrypted',
+4
View File
@@ -13,6 +13,10 @@ class OauthSetting extends Model
protected $fillable = ['provider', 'client_id', 'client_secret', 'redirect_uri', 'tenant', 'base_url', 'enabled'];
protected $hidden = [
'client_secret',
];
protected function clientSecret(): Attribute
{
return Attribute::make(
+4
View File
@@ -41,6 +41,10 @@ class PrivateKey extends BaseModel
'fingerprint',
];
protected $hidden = [
'private_key',
];
protected $casts = [
'private_key' => 'encrypted',
];
@@ -34,6 +34,11 @@ class PushoverNotificationSettings extends Model
'traefik_outdated_pushover_notifications',
];
protected $hidden = [
'pushover_user_key',
'pushover_api_token',
];
protected $casts = [
'pushover_enabled' => 'boolean',
'pushover_user_key' => 'encrypted',
+5
View File
@@ -26,6 +26,11 @@ class S3Storage extends BaseModel
'unusable_email_sent',
];
protected $hidden = [
'key',
'secret',
];
protected $casts = [
'is_usable' => 'boolean',
'key' => 'encrypted',
+4
View File
@@ -30,6 +30,10 @@ class SharedEnvironmentVariable extends Model
'version',
];
protected $hidden = [
'value',
];
protected $casts = [
'key' => 'string',
'value' => 'encrypted',
+4
View File
@@ -33,6 +33,10 @@ class SlackNotificationSettings extends Model
'traefik_outdated_slack_notifications',
];
protected $hidden = [
'slack_webhook_url',
];
protected $casts = [
'slack_enabled' => 'boolean',
'slack_webhook_url' => 'encrypted',
+4
View File
@@ -20,6 +20,10 @@ class SslCertificate extends Model
'is_ca_certificate',
];
protected $hidden = [
'ssl_private_key',
];
protected $casts = [
'ssl_certificate' => 'encrypted',
'ssl_private_key' => 'encrypted',
+21 -1
View File
@@ -49,6 +49,25 @@ class TelegramNotificationSettings extends Model
'telegram_notifications_traefik_outdated_thread_id',
];
protected $hidden = [
'telegram_token',
'telegram_chat_id',
'telegram_notifications_deployment_success_thread_id',
'telegram_notifications_deployment_failure_thread_id',
'telegram_notifications_status_change_thread_id',
'telegram_notifications_backup_success_thread_id',
'telegram_notifications_backup_failure_thread_id',
'telegram_notifications_scheduled_task_success_thread_id',
'telegram_notifications_scheduled_task_failure_thread_id',
'telegram_notifications_docker_cleanup_success_thread_id',
'telegram_notifications_docker_cleanup_failure_thread_id',
'telegram_notifications_server_disk_usage_thread_id',
'telegram_notifications_server_reachable_thread_id',
'telegram_notifications_server_unreachable_thread_id',
'telegram_notifications_server_patch_thread_id',
'telegram_notifications_traefik_outdated_thread_id',
];
protected $casts = [
'telegram_enabled' => 'boolean',
'telegram_token' => 'encrypted',
@@ -75,7 +94,8 @@ class TelegramNotificationSettings extends Model
'telegram_notifications_backup_failure_thread_id' => 'encrypted',
'telegram_notifications_scheduled_task_success_thread_id' => 'encrypted',
'telegram_notifications_scheduled_task_failure_thread_id' => 'encrypted',
'telegram_notifications_docker_cleanup_thread_id' => 'encrypted',
'telegram_notifications_docker_cleanup_success_thread_id' => 'encrypted',
'telegram_notifications_docker_cleanup_failure_thread_id' => 'encrypted',
'telegram_notifications_server_disk_usage_thread_id' => 'encrypted',
'telegram_notifications_server_reachable_thread_id' => 'encrypted',
'telegram_notifications_server_unreachable_thread_id' => 'encrypted',
@@ -33,6 +33,10 @@ class WebhookNotificationSettings extends Model
'traefik_outdated_webhook_notifications',
];
protected $hidden = [
'webhook_url',
];
protected function casts(): array
{
return [