refactor: use forceCreate() for internal model creation

Replace create() with forceCreate() across internal model creation operations to bypass mass assignment protection. This is appropriate for internal code that constructs complete model state without user input.

Add InternalModelCreationMassAssignmentTest to ensure internal model creation behavior is properly tested. Optimize imports by using shortened Livewire attribute references and removing unused imports.
This commit is contained in:
Andras Bacsai committed 2026-03-30 13:04:11 +02:00
1 parent 71cde5a063
commit 1da1f32f0e
41 files changed
+265 -145

No files matched your search

+1 -1
View File
@@ -49,7 +49,7 @@ class InstallDocker
}');
$found = StandaloneDocker::where('server_id', $server->id);
if ($found->count() == 0 && $server->id) {
StandaloneDocker::create([
StandaloneDocker::forceCreate([
'name' => 'coolify',
'network' => 'coolify',
'server_id' => $server->id,
+1 -1
View File
@@ -136,7 +136,7 @@ class Emails extends Command
$application = Application::all()->first();
$preview = ApplicationPreview::all()->first();
if (! $preview) {
$preview = ApplicationPreview::create([
$preview = ApplicationPreview::forceCreate([
'application_id' => $application->id,
'pull_request_id' => 1,
'pull_request_html_url' => 'http://example.com',
@@ -5,6 +5,7 @@ namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\Project;
use App\Support\ValidationPatterns;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use OpenApi\Attributes as OA;
@@ -234,7 +235,7 @@ class ProjectController extends Controller
}
$return = validateIncomingRequest($request);
if ($return instanceof \Illuminate\Http\JsonResponse) {
if ($return instanceof JsonResponse) {
return $return;
}
$validator = Validator::make($request->all(), [
@@ -257,7 +258,7 @@ class ProjectController extends Controller
], 422);
}
$project = Project::create([
$project = Project::forceCreate([
'name' => $request->name,
'description' => $request->description,
'team_id' => $teamId,
@@ -347,7 +348,7 @@ class ProjectController extends Controller
}
$return = validateIncomingRequest($request);
if ($return instanceof \Illuminate\Http\JsonResponse) {
if ($return instanceof JsonResponse) {
return $return;
}
$validator = Validator::make($request->all(), [
@@ -600,7 +601,7 @@ class ProjectController extends Controller
}
$return = validateIncomingRequest($request);
if ($return instanceof \Illuminate\Http\JsonResponse) {
if ($return instanceof JsonResponse) {
return $return;
}
$validator = Validator::make($request->all(), [
@@ -432,7 +432,7 @@ class ServicesController extends Controller
if (in_array($oneClickServiceName, NEEDS_TO_CONNECT_TO_PREDEFINED_NETWORK)) {
data_set($servicePayload, 'connect_to_docker_network', true);
}
$service = Service::create($servicePayload);
$service = Service::forceCreate($servicePayload);
$service->name = $request->name ?? "$oneClickServiceName-".$service->uuid;
$service->description = $request->description;
if ($request->has('is_container_label_escape_enabled')) {
+2 -2
View File
@@ -119,7 +119,7 @@ class Bitbucket extends Controller
$found = ApplicationPreview::where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first();
if (! $found) {
if ($application->build_pack === 'dockercompose') {
$pr_app = ApplicationPreview::create([
$pr_app = ApplicationPreview::forceCreate([
'git_type' => 'bitbucket',
'application_id' => $application->id,
'pull_request_id' => $pull_request_id,
@@ -128,7 +128,7 @@ class Bitbucket extends Controller
]);
$pr_app->generate_preview_fqdn_compose();
} else {
$pr_app = ApplicationPreview::create([
$pr_app = ApplicationPreview::forceCreate([
'git_type' => 'bitbucket',
'application_id' => $application->id,
'pull_request_id' => $pull_request_id,
+2 -2
View File
@@ -144,7 +144,7 @@ class Gitea extends Controller
$found = ApplicationPreview::where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first();
if (! $found) {
if ($application->build_pack === 'dockercompose') {
$pr_app = ApplicationPreview::create([
$pr_app = ApplicationPreview::forceCreate([
'git_type' => 'gitea',
'application_id' => $application->id,
'pull_request_id' => $pull_request_id,
@@ -153,7 +153,7 @@ class Gitea extends Controller
]);
$pr_app->generate_preview_fqdn_compose();
} else {
$pr_app = ApplicationPreview::create([
$pr_app = ApplicationPreview::forceCreate([
'git_type' => 'gitea',
'application_id' => $application->id,
'pull_request_id' => $pull_request_id,
+2 -2
View File
@@ -177,7 +177,7 @@ class Gitlab extends Controller
$found = ApplicationPreview::where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first();
if (! $found) {
if ($application->build_pack === 'dockercompose') {
$pr_app = ApplicationPreview::create([
$pr_app = ApplicationPreview::forceCreate([
'git_type' => 'gitlab',
'application_id' => $application->id,
'pull_request_id' => $pull_request_id,
@@ -186,7 +186,7 @@ class Gitlab extends Controller
]);
$pr_app->generate_preview_fqdn_compose();
} else {
$pr_app = ApplicationPreview::create([
$pr_app = ApplicationPreview::forceCreate([
'git_type' => 'gitlab',
'application_id' => $application->id,
'pull_request_id' => $pull_request_id,
+2 -2
View File
@@ -118,7 +118,7 @@ class ProcessGithubPullRequestWebhook implements ShouldBeEncrypted, ShouldQueue
if (! $found) {
if ($application->build_pack === 'dockercompose') {
$preview = ApplicationPreview::create([
$preview = ApplicationPreview::forceCreate([
'git_type' => 'github',
'application_id' => $application->id,
'pull_request_id' => $this->pullRequestId,
@@ -127,7 +127,7 @@ class ProcessGithubPullRequestWebhook implements ShouldBeEncrypted, ShouldQueue
]);
$preview->generate_preview_fqdn_compose();
} else {
$preview = ApplicationPreview::create([
$preview = ApplicationPreview::forceCreate([
'git_type' => 'github',
'application_id' => $application->id,
'pull_request_id' => $this->pullRequestId,
+8 -7
View File
@@ -9,6 +9,7 @@ use App\Models\Server;
use App\Models\Team;
use App\Services\ConfigurationRepository;
use Illuminate\Support\Collection;
use Livewire\Attributes\Url;
use Livewire\Component;
use Visus\Cuid2\Cuid2;
@@ -19,18 +20,18 @@ class Index extends Component
'prerequisitesInstalled' => 'handlePrerequisitesInstalled',
];
#[\Livewire\Attributes\Url(as: 'step', history: true)]
#[Url(as: 'step', history: true)]
public string $currentState = 'welcome';
#[\Livewire\Attributes\Url(keep: true)]
#[Url(keep: true)]
public ?string $selectedServerType = null;
public ?Collection $privateKeys = null;
#[\Livewire\Attributes\Url(keep: true)]
#[Url(keep: true)]
public ?int $selectedExistingPrivateKey = null;
#[\Livewire\Attributes\Url(keep: true)]
#[Url(keep: true)]
public ?string $privateKeyType = null;
public ?string $privateKey = null;
@@ -45,7 +46,7 @@ class Index extends Component
public ?Collection $servers = null;
#[\Livewire\Attributes\Url(keep: true)]
#[Url(keep: true)]
public ?int $selectedExistingServer = null;
public ?string $remoteServerName = null;
@@ -66,7 +67,7 @@ class Index extends Component
public Collection $projects;
#[\Livewire\Attributes\Url(keep: true)]
#[Url(keep: true)]
public ?int $selectedProject = null;
public ?Project $createdProject = null;
@@ -440,7 +441,7 @@ class Index extends Component
public function createNewProject()
{
$this->createdProject = Project::create([
$this->createdProject = Project::forceCreate([
'name' => 'My first project',
'team_id' => currentTeam()->id,
'uuid' => (string) new Cuid2,
+2 -3
View File
@@ -5,7 +5,6 @@ namespace App\Livewire\Destination\New;
use App\Models\Server;
use App\Models\StandaloneDocker;
use App\Models\SwarmDocker;
use App\Support\ValidationPatterns;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Livewire\Attributes\Locked;
use Livewire\Attributes\Validate;
@@ -78,7 +77,7 @@ class Docker extends Component
if ($found) {
throw new \Exception('Network already added to this server.');
} else {
$docker = SwarmDocker::create([
$docker = SwarmDocker::forceCreate([
'name' => $this->name,
'network' => $this->network,
'server_id' => $this->selectedServer->id,
@@ -89,7 +88,7 @@ class Docker extends Component
if ($found) {
throw new \Exception('Network already added to this server.');
} else {
$docker = StandaloneDocker::create([
$docker = StandaloneDocker::forceCreate([
'name' => $this->name,
'network' => $this->network,
'server_id' => $this->selectedServer->id,
+1 -1
View File
@@ -30,7 +30,7 @@ class AddEmpty extends Component
{
try {
$this->validate();
$project = Project::create([
$project = Project::forceCreate([
'name' => $this->name,
'description' => $this->description,
'team_id' => currentTeam()->id,
@@ -182,7 +182,7 @@ class Previews extends Component
$this->setDeploymentUuid();
$found = ApplicationPreview::where('application_id', $this->application->id)->where('pull_request_id', $pull_request_id)->first();
if (! $found && ! is_null($pull_request_html_url)) {
$found = ApplicationPreview::create([
$found = ApplicationPreview::forceCreate([
'application_id' => $this->application->id,
'pull_request_id' => $pull_request_id,
'pull_request_html_url' => $pull_request_html_url,
@@ -196,7 +196,7 @@ class Previews extends Component
$this->setDeploymentUuid();
$found = ApplicationPreview::where('application_id', $this->application->id)->where('pull_request_id', $pull_request_id)->first();
if (! $found && ! is_null($pull_request_html_url)) {
$found = ApplicationPreview::create([
$found = ApplicationPreview::forceCreate([
'application_id' => $this->application->id,
'pull_request_id' => $pull_request_id,
'pull_request_html_url' => $pull_request_html_url,
@@ -236,7 +236,7 @@ class Previews extends Component
$this->setDeploymentUuid();
$found = ApplicationPreview::where('application_id', $this->application->id)->where('pull_request_id', $pull_request_id)->first();
if (! $found && ! is_null($pull_request_html_url)) {
ApplicationPreview::create([
ApplicationPreview::forceCreate([
'application_id' => $this->application->id,
'pull_request_id' => $pull_request_id,
'pull_request_html_url' => $pull_request_html_url,
+1 -1
View File
@@ -100,7 +100,7 @@ class CloneMe extends Component
if ($foundProject) {
throw new \Exception('Project with the same name already exists.');
}
$project = Project::create([
$project = Project::forceCreate([
'name' => $this->newName,
'team_id' => currentTeam()->id,
'description' => $this->project->description.' (clone)',
+1 -1
View File
@@ -54,7 +54,7 @@ class DockerCompose extends Component
}
$destination_class = $destination->getMorphClass();
$service = Service::create([
$service = Service::forceCreate([
'docker_compose_raw' => $this->dockerComposeRaw,
'environment_id' => $environment->id,
'server_id' => (int) $server_id,
+1 -1
View File
@@ -133,7 +133,7 @@ class DockerImage extends Component
// Determine the image tag based on whether it's a hash or regular tag
$imageTag = $parser->isImageHash() ? 'sha256-'.$parser->getTag() : $parser->getTag();
$application = Application::create([
$application = Application::forceCreate([
'name' => 'docker-image-'.new Cuid2,
'repository_project_id' => 0,
'git_repository' => 'coollabsio/coolify',
+1 -1
View File
@@ -10,7 +10,7 @@ class EmptyProject extends Component
{
public function createEmptyProject()
{
$project = Project::create([
$project = Project::forceCreate([
'name' => generate_random_name(),
'team_id' => currentTeam()->id,
'uuid' => (string) new Cuid2,
@@ -8,6 +8,7 @@ use App\Models\Project;
use App\Models\StandaloneDocker;
use App\Models\SwarmDocker;
use App\Rules\ValidGitBranch;
use App\Support\ValidationPatterns;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Route;
use Livewire\Component;
@@ -168,7 +169,7 @@ class GithubPrivateRepository extends Component
'selected_repository_owner' => 'required|string|regex:/^[a-zA-Z0-9\-_]+$/',
'selected_repository_repo' => 'required|string|regex:/^[a-zA-Z0-9\-_\.]+$/',
'selected_branch_name' => ['required', 'string', new ValidGitBranch],
'docker_compose_location' => \App\Support\ValidationPatterns::filePathRules(),
'docker_compose_location' => ValidationPatterns::filePathRules(),
]);
if ($validator->fails()) {
@@ -188,7 +189,7 @@ class GithubPrivateRepository extends Component
$project = Project::ownedByCurrentTeam()->where('uuid', $this->parameters['project_uuid'])->firstOrFail();
$environment = $project->environments()->where('uuid', $this->parameters['environment_uuid'])->firstOrFail();
$application = Application::create([
$application = Application::forceCreate([
'name' => generate_application_name($this->selected_repository_owner.'/'.$this->selected_repository_repo, $this->selected_branch_name),
'repository_project_id' => $this->selected_repository_id,
'git_repository' => str($this->selected_repository_owner)->trim()->toString().'/'.str($this->selected_repository_repo)->trim()->toString(),
@@ -11,6 +11,7 @@ use App\Models\StandaloneDocker;
use App\Models\SwarmDocker;
use App\Rules\ValidGitBranch;
use App\Rules\ValidGitRepositoryUrl;
use App\Support\ValidationPatterns;
use Illuminate\Support\Str;
use Livewire\Component;
use Spatie\Url\Url;
@@ -66,7 +67,7 @@ class GithubPrivateRepositoryDeployKey extends Component
'is_static' => 'required|boolean',
'publish_directory' => 'nullable|string',
'build_pack' => 'required|string',
'docker_compose_location' => \App\Support\ValidationPatterns::filePathRules(),
'docker_compose_location' => ValidationPatterns::filePathRules(),
];
}
@@ -182,7 +183,7 @@ class GithubPrivateRepositoryDeployKey extends Component
$application_init['docker_compose_location'] = $this->docker_compose_location;
$application_init['base_directory'] = $this->base_directory;
}
$application = Application::create($application_init);
$application = Application::forceCreate($application_init);
$application->settings->is_static = $this->is_static;
$application->settings->save();
@@ -11,6 +11,7 @@ use App\Models\StandaloneDocker;
use App\Models\SwarmDocker;
use App\Rules\ValidGitBranch;
use App\Rules\ValidGitRepositoryUrl;
use App\Support\ValidationPatterns;
use Carbon\Carbon;
use Livewire\Component;
use Spatie\Url\Url;
@@ -72,7 +73,7 @@ class PublicGitRepository extends Component
'publish_directory' => 'nullable|string',
'build_pack' => 'required|string',
'base_directory' => 'nullable|string',
'docker_compose_location' => \App\Support\ValidationPatterns::filePathRules(),
'docker_compose_location' => ValidationPatterns::filePathRules(),
'git_branch' => ['required', 'string', new ValidGitBranch],
];
}
@@ -233,7 +234,7 @@ class PublicGitRepository extends Component
return;
}
if ($this->git_source->getMorphClass() === \App\Models\GithubApp::class) {
if ($this->git_source->getMorphClass() === GithubApp::class) {
['rate_limit_remaining' => $this->rate_limit_remaining, 'rate_limit_reset' => $this->rate_limit_reset] = githubApi(source: $this->git_source, endpoint: "/repos/{$this->git_repository}/branches/{$this->git_branch}");
$this->rate_limit_reset = Carbon::parse((int) $this->rate_limit_reset)->format('Y-M-d H:i:s');
$this->branchFound = true;
@@ -298,7 +299,7 @@ class PublicGitRepository extends Component
$new_service['source_id'] = $this->git_source->id;
$new_service['source_type'] = $this->git_source->getMorphClass();
}
$service = Service::create($new_service);
$service = Service::forceCreate($new_service);
return redirect()->route('project.service.configuration', [
'service_uuid' => $service->uuid,
@@ -345,7 +346,7 @@ class PublicGitRepository extends Component
$application_init['docker_compose_location'] = $this->docker_compose_location;
$application_init['base_directory'] = $this->base_directory;
}
$application = Application::create($application_init);
$application = Application::forceCreate($application_init);
$application->settings->is_static = $this->isStatic;
$application->settings->save();
@@ -52,7 +52,7 @@ CMD ["nginx", "-g", "daemon off;"]
if (! $port) {
$port = 80;
}
$application = Application::create([
$application = Application::forceCreate([
'name' => 'dockerfile-'.new Cuid2,
'repository_project_id' => 0,
'git_repository' => 'coollabsio/coolify',
+1 -1
View File
@@ -91,7 +91,7 @@ class Create extends Component
if (in_array($oneClickServiceName, NEEDS_TO_CONNECT_TO_PREDEFINED_NETWORK)) {
data_set($service_payload, 'connect_to_docker_network', true);
}
$service = Service::create($service_payload);
$service = Service::forceCreate($service_payload);
$service->name = "$oneClickServiceName-".$service->uuid;
$service->save();
if ($oneClickDotEnvs?->count() > 0) {
+1 -1
View File
@@ -42,7 +42,7 @@ class Show extends Component
{
try {
$this->validate();
$environment = Environment::create([
$environment = Environment::forceCreate([
'name' => $this->name,
'project_id' => $this->project->id,
'uuid' => (string) new Cuid2,
+2 -2
View File
@@ -43,7 +43,7 @@ class Destinations extends Component
return;
} else {
SwarmDocker::create([
SwarmDocker::forceCreate([
'name' => $this->server->name.'-'.$name,
'network' => $this->name,
'server_id' => $this->server->id,
@@ -57,7 +57,7 @@ class Destinations extends Component
return;
} else {
StandaloneDocker::create([
StandaloneDocker::forceCreate([
'name' => $this->server->name.'-'.$name,
'network' => $name,
'server_id' => $this->server->id,
+4 -3
View File
@@ -6,6 +6,7 @@ use App\Models\InstanceSettings;
use App\Models\S3Storage;
use App\Models\ScheduledDatabaseBackup;
use App\Models\Server;
use App\Models\StandaloneDocker;
use App\Models\StandalonePostgresql;
use Livewire\Attributes\Locked;
use Livewire\Attributes\Validate;
@@ -82,7 +83,7 @@ class SettingsBackup extends Component
$postgres_password = $envs['POSTGRES_PASSWORD'];
$postgres_user = $envs['POSTGRES_USER'];
$postgres_db = $envs['POSTGRES_DB'];
$this->database = StandalonePostgresql::create([
$this->database = StandalonePostgresql::forceCreate([
'id' => 0,
'name' => 'coolify-db',
'description' => 'Coolify database',
@@ -90,7 +91,7 @@ class SettingsBackup extends Component
'postgres_password' => $postgres_password,
'postgres_db' => $postgres_db,
'status' => 'running',
'destination_type' => \App\Models\StandaloneDocker::class,
'destination_type' => StandaloneDocker::class,
'destination_id' => 0,
]);
$this->backup = ScheduledDatabaseBackup::create([
@@ -99,7 +100,7 @@ class SettingsBackup extends Component
'save_s3' => false,
'frequency' => '0 0 * * *',
'database_id' => $this->database->id,
'database_type' => \App\Models\StandalonePostgresql::class,
'database_type' => StandalonePostgresql::class,
'team_id' => currentTeam()->id,
]);
$this->database->refresh();
+1 -1
View File
@@ -299,7 +299,7 @@ class Application extends BaseModel
}
});
static::created(function ($application) {
ApplicationSetting::create([
ApplicationSetting::forceCreate([
'application_id' => $application->id,
]);
$application->compose_parsing_version = self::$parserVersion;
+2 -2
View File
@@ -51,10 +51,10 @@ class Project extends BaseModel
protected static function booted()
{
static::created(function ($project) {
ProjectSetting::create([
ProjectSetting::forceCreate([
'project_id' => $project->id,
]);
Environment::create([
Environment::forceCreate([
'name' => 'production',
'project_id' => $project->id,
'uuid' => (string) new Cuid2,
+6 -5
View File
@@ -143,19 +143,19 @@ class Server extends BaseModel
}
});
static::created(function ($server) {
ServerSetting::create([
ServerSetting::forceCreate([
'server_id' => $server->id,
]);
if ($server->id === 0) {
if ($server->isSwarm()) {
SwarmDocker::create([
SwarmDocker::forceCreate([
'id' => 0,
'name' => 'coolify',
'network' => 'coolify-overlay',
'server_id' => $server->id,
]);
} else {
StandaloneDocker::create([
StandaloneDocker::forceCreate([
'id' => 0,
'name' => 'coolify',
'network' => 'coolify',
@@ -164,13 +164,14 @@ class Server extends BaseModel
}
} else {
if ($server->isSwarm()) {
SwarmDocker::create([
SwarmDocker::forceCreate([
'name' => 'coolify-overlay',
'network' => 'coolify-overlay',
'server_id' => $server->id,
]);
} else {
$standaloneDocker = new StandaloneDocker([
$standaloneDocker = new StandaloneDocker;
$standaloneDocker->forceFill([
'name' => 'coolify',
'uuid' => (string) new Cuid2,
'network' => 'coolify',