mirror of
https://github.com/coollabsio/coolify.git
synced 2026-11-06 21:18:11 -04:00
Merge remote-tracking branch 'origin/next' into automation/sync-main-to-next
This commit is contained in:
@@ -23,6 +23,7 @@ use App\Traits\HasNoindexDomains;
|
||||
use App\Traits\HasSafeStringAttribute;
|
||||
use App\Traits\HasSecretManager;
|
||||
use App\Traits\ReleasesManagedDnsRecords;
|
||||
use App\Traits\ScopedByAccessGrants;
|
||||
use Database\Factories\ApplicationFactory;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
@@ -139,7 +140,7 @@ use Symfony\Component\Yaml\Yaml;
|
||||
class Application extends BaseModel
|
||||
{
|
||||
/** @use HasFactory<ApplicationFactory> */
|
||||
use Auditable, ClearsGlobalSearchCache, HasComposeVolumeWarnings, HasConfiguration, HasFactory, HasMaintenancePage, HasMetrics, HasNoindexDomains, HasSafeStringAttribute, HasSecretManager, ReleasesManagedDnsRecords, SoftDeletes;
|
||||
use Auditable, ClearsGlobalSearchCache, HasComposeVolumeWarnings, HasConfiguration, HasFactory, HasMaintenancePage, HasMetrics, HasNoindexDomains, HasSafeStringAttribute, HasSecretManager, ReleasesManagedDnsRecords, ScopedByAccessGrants, SoftDeletes;
|
||||
|
||||
public const MAX_DOCKER_COMPOSE_SIZE_BYTES = 5 * 1024 * 1024;
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace App\Models;
|
||||
|
||||
use App\Casts\EncryptedArrayCast;
|
||||
use App\Enums\ApplicationDeploymentStatus;
|
||||
use App\Services\Access\AccessResolver;
|
||||
use App\Services\Security\SensitiveDataRedactor;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
@@ -49,6 +50,20 @@ use OpenApi\Attributes as OA;
|
||||
)]
|
||||
class ApplicationDeploymentQueue extends Model
|
||||
{
|
||||
/**
|
||||
* Only deployments of applications the authenticated member or API token can see.
|
||||
*/
|
||||
public function scopeVisibleToCurrentActor(Builder $query): Builder
|
||||
{
|
||||
foreach (app(AccessResolver::class)->currentLayers() as $layer) {
|
||||
if (! $layer->coversWholeTeam()) {
|
||||
return $query->whereIn('application_id', Application::query()->pluck('id')->map(fn ($id) => (string) $id));
|
||||
}
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Log redaction variants of remote secrets. Kept in memory only, never saved.
|
||||
*
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Services\Access\AccessResolver;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use OpenApi\Attributes as OA;
|
||||
@@ -150,10 +151,11 @@ class ApplicationSetting extends Model
|
||||
*/
|
||||
public static function isContainerNamePrefixInUse(string $prefix, Server $server, ?int $ignoreApplicationId = null): bool
|
||||
{
|
||||
return $server->applications()->contains(function (Application $application) use ($prefix, $ignoreApplicationId) {
|
||||
// Hidden applications of a scoped member still count, or two names on one server could collide.
|
||||
return app(AccessResolver::class)->withoutVisibilityScope(fn () => $server->applications()->contains(function (Application $application) use ($prefix, $ignoreApplicationId) {
|
||||
return $application->id !== $ignoreApplicationId
|
||||
&& in_array($prefix, [$application->uuid, $application->settings->custom_container_name_prefix, $application->settings->custom_internal_name], true);
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
public function stopGracePeriodSeconds(): int
|
||||
|
||||
@@ -5,6 +5,7 @@ namespace App\Models;
|
||||
use App\Traits\Auditable;
|
||||
use App\Traits\ClearsGlobalSearchCache;
|
||||
use App\Traits\HasSafeStringAttribute;
|
||||
use App\Traits\ScopedByAccessGrants;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use OpenApi\Attributes as OA;
|
||||
@@ -24,7 +25,7 @@ use OpenApi\Attributes as OA;
|
||||
class Environment extends BaseModel
|
||||
{
|
||||
use Auditable, HasFactory;
|
||||
use ClearsGlobalSearchCache;
|
||||
use ClearsGlobalSearchCache, ScopedByAccessGrants;
|
||||
use HasSafeStringAttribute;
|
||||
|
||||
protected $fillable = [
|
||||
|
||||
@@ -13,12 +13,14 @@ class PersonalAccessToken extends SanctumPersonalAccessToken
|
||||
'expires_at',
|
||||
'api_token_expiration_warning_sent_at',
|
||||
'team_id',
|
||||
'scopes',
|
||||
];
|
||||
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
'api_token_expiration_warning_sent_at' => 'datetime',
|
||||
'scopes' => 'array',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ namespace App\Models;
|
||||
use App\Traits\Auditable;
|
||||
use App\Traits\ClearsGlobalSearchCache;
|
||||
use App\Traits\HasSafeStringAttribute;
|
||||
use App\Traits\ScopedByAccessGrants;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Support\Collection;
|
||||
use OpenApi\Attributes as OA;
|
||||
@@ -22,7 +23,7 @@ use OpenApi\Attributes as OA;
|
||||
class Project extends BaseModel
|
||||
{
|
||||
use Auditable, HasFactory;
|
||||
use ClearsGlobalSearchCache;
|
||||
use ClearsGlobalSearchCache, ScopedByAccessGrants;
|
||||
use HasSafeStringAttribute;
|
||||
|
||||
protected $fillable = [
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Scopes;
|
||||
|
||||
use App\Models\Environment;
|
||||
use App\Models\Project;
|
||||
use App\Services\Access\AccessResolver;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Scope;
|
||||
|
||||
/**
|
||||
* Hides projects, environments, and resources that the authenticated member or API token has no grant for.
|
||||
*
|
||||
* It filters only when the actor has no team-wide grant, so owners, admins, team-wide members and tokens,
|
||||
* queue workers, and console commands see the same rows as before.
|
||||
*/
|
||||
class VisibleThroughAccessGrants implements Scope
|
||||
{
|
||||
public function apply(Builder $builder, Model $model): void
|
||||
{
|
||||
$resolver = app(AccessResolver::class);
|
||||
if ($resolver->isResolving()) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($resolver->currentLayers() as $layer) {
|
||||
if ($layer->coversWholeTeam()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($model instanceof Project) {
|
||||
$builder->whereIn($model->qualifyColumn('id'), $layer->visibleProjectIds());
|
||||
} elseif ($model instanceof Environment) {
|
||||
$builder->whereIn($model->qualifyColumn('id'), $layer->visibleEnvironmentIds());
|
||||
} else {
|
||||
$builder->where(fn (Builder $query) => $query
|
||||
->whereIn($model->qualifyColumn('environment_id'), $layer->fullEnvironmentIds())
|
||||
->orWhereIn($model->qualifyColumn('uuid'), $layer->resourceUuids()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@ use App\Traits\HasComposeVolumeWarnings;
|
||||
use App\Traits\HasMaintenancePage;
|
||||
use App\Traits\HasSafeStringAttribute;
|
||||
use App\Traits\HasSecretManager;
|
||||
use App\Traits\ScopedByAccessGrants;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
@@ -46,7 +47,7 @@ use OpenApi\Attributes as OA;
|
||||
)]
|
||||
class Service extends BaseModel
|
||||
{
|
||||
use Auditable, ClearsGlobalSearchCache, HasComposeVolumeWarnings, HasFactory, HasMaintenancePage, HasSafeStringAttribute, HasSecretManager, SoftDeletes;
|
||||
use Auditable, ClearsGlobalSearchCache, HasComposeVolumeWarnings, HasFactory, HasMaintenancePage, HasSafeStringAttribute, HasSecretManager, ScopedByAccessGrants, SoftDeletes;
|
||||
|
||||
private static $parserVersion = '5';
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ use App\Traits\HasLogRedactionSetting;
|
||||
use App\Traits\HasMetrics;
|
||||
use App\Traits\HasSafeStringAttribute;
|
||||
use App\Traits\HasSecretManager;
|
||||
use App\Traits\ScopedByAccessGrants;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
@@ -16,7 +17,7 @@ use Throwable;
|
||||
|
||||
class StandaloneClickhouse extends BaseModel
|
||||
{
|
||||
use Auditable, ClearsGlobalSearchCache, HasDatabaseHealthCheck, HasFactory, HasLogRedactionSetting, HasMetrics, HasSafeStringAttribute, HasSecretManager, SoftDeletes;
|
||||
use Auditable, ClearsGlobalSearchCache, HasDatabaseHealthCheck, HasFactory, HasLogRedactionSetting, HasMetrics, HasSafeStringAttribute, HasSecretManager, ScopedByAccessGrants, SoftDeletes;
|
||||
|
||||
protected array $auditExclude = ['last_online_at'];
|
||||
|
||||
|
||||
@@ -9,13 +9,14 @@ use App\Traits\HasLogRedactionSetting;
|
||||
use App\Traits\HasMetrics;
|
||||
use App\Traits\HasSafeStringAttribute;
|
||||
use App\Traits\HasSecretManager;
|
||||
use App\Traits\ScopedByAccessGrants;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class StandaloneDragonfly extends BaseModel
|
||||
{
|
||||
use Auditable, ClearsGlobalSearchCache, HasDatabaseHealthCheck, HasFactory, HasLogRedactionSetting, HasMetrics, HasSafeStringAttribute, HasSecretManager, SoftDeletes;
|
||||
use Auditable, ClearsGlobalSearchCache, HasDatabaseHealthCheck, HasFactory, HasLogRedactionSetting, HasMetrics, HasSafeStringAttribute, HasSecretManager, ScopedByAccessGrants, SoftDeletes;
|
||||
|
||||
protected $fillable = [
|
||||
'uuid',
|
||||
|
||||
@@ -9,13 +9,14 @@ use App\Traits\HasLogRedactionSetting;
|
||||
use App\Traits\HasMetrics;
|
||||
use App\Traits\HasSafeStringAttribute;
|
||||
use App\Traits\HasSecretManager;
|
||||
use App\Traits\ScopedByAccessGrants;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class StandaloneKeydb extends BaseModel
|
||||
{
|
||||
use Auditable, ClearsGlobalSearchCache, HasDatabaseHealthCheck, HasFactory, HasLogRedactionSetting, HasMetrics, HasSafeStringAttribute, HasSecretManager, SoftDeletes;
|
||||
use Auditable, ClearsGlobalSearchCache, HasDatabaseHealthCheck, HasFactory, HasLogRedactionSetting, HasMetrics, HasSafeStringAttribute, HasSecretManager, ScopedByAccessGrants, SoftDeletes;
|
||||
|
||||
protected $fillable = [
|
||||
'uuid',
|
||||
|
||||
@@ -9,6 +9,7 @@ use App\Traits\HasLogRedactionSetting;
|
||||
use App\Traits\HasMetrics;
|
||||
use App\Traits\HasSafeStringAttribute;
|
||||
use App\Traits\HasSecretManager;
|
||||
use App\Traits\ScopedByAccessGrants;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphTo;
|
||||
@@ -16,7 +17,7 @@ use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class StandaloneMariadb extends BaseModel
|
||||
{
|
||||
use Auditable, ClearsGlobalSearchCache, HasDatabaseHealthCheck, HasFactory, HasLogRedactionSetting, HasMetrics, HasSafeStringAttribute, HasSecretManager, SoftDeletes;
|
||||
use Auditable, ClearsGlobalSearchCache, HasDatabaseHealthCheck, HasFactory, HasLogRedactionSetting, HasMetrics, HasSafeStringAttribute, HasSecretManager, ScopedByAccessGrants, SoftDeletes;
|
||||
|
||||
protected $fillable = [
|
||||
'uuid',
|
||||
|
||||
@@ -9,13 +9,14 @@ use App\Traits\HasLogRedactionSetting;
|
||||
use App\Traits\HasMetrics;
|
||||
use App\Traits\HasSafeStringAttribute;
|
||||
use App\Traits\HasSecretManager;
|
||||
use App\Traits\ScopedByAccessGrants;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class StandaloneMongodb extends BaseModel
|
||||
{
|
||||
use Auditable, ClearsGlobalSearchCache, HasDatabaseHealthCheck, HasFactory, HasLogRedactionSetting, HasMetrics, HasSafeStringAttribute, HasSecretManager, SoftDeletes;
|
||||
use Auditable, ClearsGlobalSearchCache, HasDatabaseHealthCheck, HasFactory, HasLogRedactionSetting, HasMetrics, HasSafeStringAttribute, HasSecretManager, ScopedByAccessGrants, SoftDeletes;
|
||||
|
||||
protected $fillable = [
|
||||
'uuid',
|
||||
|
||||
@@ -9,13 +9,14 @@ use App\Traits\HasLogRedactionSetting;
|
||||
use App\Traits\HasMetrics;
|
||||
use App\Traits\HasSafeStringAttribute;
|
||||
use App\Traits\HasSecretManager;
|
||||
use App\Traits\ScopedByAccessGrants;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class StandaloneMysql extends BaseModel
|
||||
{
|
||||
use Auditable, ClearsGlobalSearchCache, HasDatabaseHealthCheck, HasFactory, HasLogRedactionSetting, HasMetrics, HasSafeStringAttribute, HasSecretManager, SoftDeletes;
|
||||
use Auditable, ClearsGlobalSearchCache, HasDatabaseHealthCheck, HasFactory, HasLogRedactionSetting, HasMetrics, HasSafeStringAttribute, HasSecretManager, ScopedByAccessGrants, SoftDeletes;
|
||||
|
||||
protected $fillable = [
|
||||
'uuid',
|
||||
|
||||
@@ -9,13 +9,14 @@ use App\Traits\HasLogRedactionSetting;
|
||||
use App\Traits\HasMetrics;
|
||||
use App\Traits\HasSafeStringAttribute;
|
||||
use App\Traits\HasSecretManager;
|
||||
use App\Traits\ScopedByAccessGrants;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class StandalonePostgresql extends BaseModel
|
||||
{
|
||||
use Auditable, ClearsGlobalSearchCache, HasDatabaseHealthCheck, HasFactory, HasLogRedactionSetting, HasMetrics, HasSafeStringAttribute, HasSecretManager, SoftDeletes;
|
||||
use Auditable, ClearsGlobalSearchCache, HasDatabaseHealthCheck, HasFactory, HasLogRedactionSetting, HasMetrics, HasSafeStringAttribute, HasSecretManager, ScopedByAccessGrants, SoftDeletes;
|
||||
|
||||
protected $fillable = [
|
||||
'uuid',
|
||||
|
||||
@@ -9,13 +9,14 @@ use App\Traits\HasLogRedactionSetting;
|
||||
use App\Traits\HasMetrics;
|
||||
use App\Traits\HasSafeStringAttribute;
|
||||
use App\Traits\HasSecretManager;
|
||||
use App\Traits\ScopedByAccessGrants;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class StandaloneRedis extends BaseModel
|
||||
{
|
||||
use Auditable, ClearsGlobalSearchCache, HasDatabaseHealthCheck, HasFactory, HasLogRedactionSetting, HasMetrics, HasSafeStringAttribute, HasSecretManager, SoftDeletes;
|
||||
use Auditable, ClearsGlobalSearchCache, HasDatabaseHealthCheck, HasFactory, HasLogRedactionSetting, HasMetrics, HasSafeStringAttribute, HasSecretManager, ScopedByAccessGrants, SoftDeletes;
|
||||
|
||||
protected array $auditExclude = ['last_online_at'];
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ use App\Traits\HasLogRedactionSetting;
|
||||
use App\Traits\HasMetrics;
|
||||
use App\Traits\HasSafeStringAttribute;
|
||||
use App\Traits\HasSecretManager;
|
||||
use App\Traits\ScopedByAccessGrants;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
@@ -17,7 +18,7 @@ use InvalidArgumentException;
|
||||
|
||||
class StandaloneSqlite extends BaseModel
|
||||
{
|
||||
use Auditable, ClearsGlobalSearchCache, HasDatabaseHealthCheck, HasFactory, HasLogRedactionSetting, HasMetrics, HasSafeStringAttribute, HasSecretManager, SoftDeletes;
|
||||
use Auditable, ClearsGlobalSearchCache, HasDatabaseHealthCheck, HasFactory, HasLogRedactionSetting, HasMetrics, HasSafeStringAttribute, HasSecretManager, ScopedByAccessGrants, SoftDeletes;
|
||||
|
||||
public const DATA_DIRECTORY = '/var/lib/sqlite';
|
||||
|
||||
|
||||
+1
-1
@@ -337,7 +337,7 @@ class Team extends Model implements SendsDiscord, SendsEmail, SendsPushover, Sen
|
||||
|
||||
public function members()
|
||||
{
|
||||
return $this->belongsToMany(User::class, 'team_user', 'team_id', 'user_id')->withPivot('role');
|
||||
return $this->belongsToMany(User::class, 'team_user', 'team_id', 'user_id')->withPivot('role', 'access');
|
||||
}
|
||||
|
||||
public function subscription()
|
||||
|
||||
+12
-1
@@ -3,14 +3,17 @@
|
||||
namespace App\Models;
|
||||
|
||||
use App\Actions\User\RevokeUserTeamTokens;
|
||||
use App\Enums\AccessLevel;
|
||||
use App\Jobs\UpdateStripeCustomerEmailJob;
|
||||
use App\Notifications\Channels\SendsEmail;
|
||||
use App\Notifications\TransactionalEmails\EmailChangeVerification;
|
||||
use App\Notifications\TransactionalEmails\ResetPassword as TransactionalEmailsResetPassword;
|
||||
use App\Services\Access\AccessResolver;
|
||||
use App\Services\ChangelogService;
|
||||
use App\Traits\DeletesUserSessions;
|
||||
use DateTimeInterface;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
@@ -285,7 +288,7 @@ class User extends Authenticatable implements PasskeyUser, SendsEmail
|
||||
|
||||
public function teams()
|
||||
{
|
||||
return $this->belongsToMany(Team::class)->withPivot('role');
|
||||
return $this->belongsToMany(Team::class)->withPivot('role', 'access');
|
||||
}
|
||||
|
||||
public function changelogReads()
|
||||
@@ -484,6 +487,14 @@ class User extends Authenticatable implements PasskeyUser, SendsEmail
|
||||
return data_get($team, 'pivot.role');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the access grants of the user (and the API token of the request) on a project, environment, or resource.
|
||||
*/
|
||||
public function canAccess(AccessLevel $level, Model $target): bool
|
||||
{
|
||||
return app(AccessResolver::class)->allows($this, $level, $target);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the user is an admin or owner of a specific team
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user