@@ -45,6 +45,7 @@ class ApplicationsController extends Controller
|
||||
'private_key_id',
|
||||
'value',
|
||||
'real_value',
|
||||
'http_basic_auth_password',
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -183,6 +184,9 @@ class ApplicationsController extends Controller
|
||||
'docker_compose_domains' => ['type' => 'array', 'description' => 'The Docker Compose domains.'],
|
||||
'watch_paths' => ['type' => 'string', 'description' => 'The watch paths.'],
|
||||
'use_build_server' => ['type' => 'boolean', 'nullable' => true, 'description' => 'Use build server.'],
|
||||
'is_http_basic_auth_enabled' => ['type' => 'boolean', 'description' => 'HTTP Basic Authentication enabled.'],
|
||||
'http_basic_auth_username' => ['type' => 'string', 'nullable' => true, 'description' => 'Username for HTTP Basic Authentication'],
|
||||
'http_basic_auth_password' => ['type' => 'string', 'nullable' => true, 'description' => 'Password for HTTP Basic Authentication'],
|
||||
],
|
||||
)
|
||||
),
|
||||
@@ -299,6 +303,9 @@ class ApplicationsController extends Controller
|
||||
'docker_compose_domains' => ['type' => 'array', 'description' => 'The Docker Compose domains.'],
|
||||
'watch_paths' => ['type' => 'string', 'description' => 'The watch paths.'],
|
||||
'use_build_server' => ['type' => 'boolean', 'nullable' => true, 'description' => 'Use build server.'],
|
||||
'is_http_basic_auth_enabled' => ['type' => 'boolean', 'description' => 'HTTP Basic Authentication enabled.'],
|
||||
'http_basic_auth_username' => ['type' => 'string', 'nullable' => true, 'description' => 'Username for HTTP Basic Authentication'],
|
||||
'http_basic_auth_password' => ['type' => 'string', 'nullable' => true, 'description' => 'Password for HTTP Basic Authentication'],
|
||||
],
|
||||
)
|
||||
),
|
||||
@@ -415,6 +422,9 @@ class ApplicationsController extends Controller
|
||||
'docker_compose_domains' => ['type' => 'array', 'description' => 'The Docker Compose domains.'],
|
||||
'watch_paths' => ['type' => 'string', 'description' => 'The watch paths.'],
|
||||
'use_build_server' => ['type' => 'boolean', 'nullable' => true, 'description' => 'Use build server.'],
|
||||
'is_http_basic_auth_enabled' => ['type' => 'boolean', 'description' => 'HTTP Basic Authentication enabled.'],
|
||||
'http_basic_auth_username' => ['type' => 'string', 'nullable' => true, 'description' => 'Username for HTTP Basic Authentication'],
|
||||
'http_basic_auth_password' => ['type' => 'string', 'nullable' => true, 'description' => 'Password for HTTP Basic Authentication'],
|
||||
],
|
||||
)
|
||||
),
|
||||
@@ -515,6 +525,9 @@ class ApplicationsController extends Controller
|
||||
'redirect' => ['type' => 'string', 'nullable' => true, 'description' => 'How to set redirect with Traefik / Caddy. www<->non-www.', 'enum' => ['www', 'non-www', 'both']],
|
||||
'instant_deploy' => ['type' => 'boolean', 'description' => 'The flag to indicate if the application should be deployed instantly.'],
|
||||
'use_build_server' => ['type' => 'boolean', 'nullable' => true, 'description' => 'Use build server.'],
|
||||
'is_http_basic_auth_enabled' => ['type' => 'boolean', 'description' => 'HTTP Basic Authentication enabled.'],
|
||||
'http_basic_auth_username' => ['type' => 'string', 'nullable' => true, 'description' => 'Username for HTTP Basic Authentication'],
|
||||
'http_basic_auth_password' => ['type' => 'string', 'nullable' => true, 'description' => 'Password for HTTP Basic Authentication'],
|
||||
],
|
||||
)
|
||||
),
|
||||
@@ -612,6 +625,9 @@ class ApplicationsController extends Controller
|
||||
'redirect' => ['type' => 'string', 'nullable' => true, 'description' => 'How to set redirect with Traefik / Caddy. www<->non-www.', 'enum' => ['www', 'non-www', 'both']],
|
||||
'instant_deploy' => ['type' => 'boolean', 'description' => 'The flag to indicate if the application should be deployed instantly.'],
|
||||
'use_build_server' => ['type' => 'boolean', 'nullable' => true, 'description' => 'Use build server.'],
|
||||
'is_http_basic_auth_enabled' => ['type' => 'boolean', 'description' => 'HTTP Basic Authentication enabled.'],
|
||||
'http_basic_auth_username' => ['type' => 'string', 'nullable' => true, 'description' => 'Username for HTTP Basic Authentication'],
|
||||
'http_basic_auth_password' => ['type' => 'string', 'nullable' => true, 'description' => 'Password for HTTP Basic Authentication'],
|
||||
],
|
||||
)
|
||||
),
|
||||
@@ -711,7 +727,6 @@ class ApplicationsController extends Controller
|
||||
|
||||
private function create_application(Request $request, $type)
|
||||
{
|
||||
$allowedFields = ['project_uuid', 'environment_name', 'environment_uuid', 'server_uuid', 'destination_uuid', 'type', 'name', 'description', 'is_static', 'domains', 'git_repository', 'git_branch', 'git_commit_sha', 'private_key_uuid', 'docker_registry_image_name', 'docker_registry_image_tag', 'build_pack', 'install_command', 'build_command', 'start_command', 'ports_exposes', 'ports_mappings', 'base_directory', 'publish_directory', 'health_check_enabled', 'health_check_path', 'health_check_port', 'health_check_host', 'health_check_method', 'health_check_return_code', 'health_check_scheme', 'health_check_response_text', 'health_check_interval', 'health_check_timeout', 'health_check_retries', 'health_check_start_period', 'limits_memory', 'limits_memory_swap', 'limits_memory_swappiness', 'limits_memory_reservation', 'limits_cpus', 'limits_cpuset', 'limits_cpu_shares', 'custom_labels', 'custom_docker_run_options', 'post_deployment_command', 'post_deployment_command_container', 'pre_deployment_command', 'pre_deployment_command_container', 'manual_webhook_secret_github', 'manual_webhook_secret_gitlab', 'manual_webhook_secret_bitbucket', 'manual_webhook_secret_gitea', 'redirect', 'github_app_uuid', 'instant_deploy', 'dockerfile', 'docker_compose_location', 'docker_compose_raw', 'docker_compose_custom_start_command', 'docker_compose_custom_build_command', 'docker_compose_domains', 'watch_paths', 'use_build_server', 'static_image', 'custom_nginx_configuration'];
|
||||
$teamId = getTeamIdFromToken();
|
||||
if (is_null($teamId)) {
|
||||
return invalidTokenResponse();
|
||||
@@ -721,6 +736,8 @@ class ApplicationsController extends Controller
|
||||
if ($return instanceof \Illuminate\Http\JsonResponse) {
|
||||
return $return;
|
||||
}
|
||||
$allowedFields = ['project_uuid', 'environment_name', 'environment_uuid', 'server_uuid', 'destination_uuid', 'type', 'name', 'description', 'is_static', 'domains', 'git_repository', 'git_branch', 'git_commit_sha', 'private_key_uuid', 'docker_registry_image_name', 'docker_registry_image_tag', 'build_pack', 'install_command', 'build_command', 'start_command', 'ports_exposes', 'ports_mappings', 'base_directory', 'publish_directory', 'health_check_enabled', 'health_check_path', 'health_check_port', 'health_check_host', 'health_check_method', 'health_check_return_code', 'health_check_scheme', 'health_check_response_text', 'health_check_interval', 'health_check_timeout', 'health_check_retries', 'health_check_start_period', 'limits_memory', 'limits_memory_swap', 'limits_memory_swappiness', 'limits_memory_reservation', 'limits_cpus', 'limits_cpuset', 'limits_cpu_shares', 'custom_labels', 'custom_docker_run_options', 'post_deployment_command', 'post_deployment_command_container', 'pre_deployment_command', 'pre_deployment_command_container', 'manual_webhook_secret_github', 'manual_webhook_secret_gitlab', 'manual_webhook_secret_bitbucket', 'manual_webhook_secret_gitea', 'redirect', 'github_app_uuid', 'instant_deploy', 'dockerfile', 'docker_compose_location', 'docker_compose_raw', 'docker_compose_custom_start_command', 'docker_compose_custom_build_command', 'docker_compose_domains', 'watch_paths', 'use_build_server', 'static_image', 'custom_nginx_configuration', 'is_http_basic_auth_enabled', 'http_basic_auth_username', 'http_basic_auth_password'];
|
||||
|
||||
$validator = customApiValidator($request->all(), [
|
||||
'name' => 'string|max:255',
|
||||
'description' => 'string|nullable',
|
||||
@@ -729,6 +746,9 @@ class ApplicationsController extends Controller
|
||||
'environment_uuid' => 'string|nullable',
|
||||
'server_uuid' => 'string|required',
|
||||
'destination_uuid' => 'string',
|
||||
'is_http_basic_auth_enabled' => 'boolean',
|
||||
'http_basic_auth_username' => 'string|nullable',
|
||||
'http_basic_auth_password' => 'string|nullable',
|
||||
]);
|
||||
|
||||
$extraFields = array_diff(array_keys($request->all()), $allowedFields);
|
||||
@@ -1758,25 +1778,19 @@ class ApplicationsController extends Controller
|
||||
if (is_null($teamId)) {
|
||||
return invalidTokenResponse();
|
||||
}
|
||||
|
||||
if ($request->collect()->count() == 0) {
|
||||
return response()->json([
|
||||
'message' => 'Invalid request.',
|
||||
], 400);
|
||||
}
|
||||
$return = validateIncomingRequest($request);
|
||||
if ($return instanceof \Illuminate\Http\JsonResponse) {
|
||||
return $return;
|
||||
}
|
||||
$application = Application::ownedByCurrentTeamAPI($teamId)->where('uuid', $request->uuid)->first();
|
||||
|
||||
$application = Application::ownedByCurrentTeamAPI($teamId)->where('uuid', $request->uuid)->first();
|
||||
if (! $application) {
|
||||
return response()->json([
|
||||
'message' => 'Application not found',
|
||||
], 404);
|
||||
}
|
||||
$server = $application->destination->server;
|
||||
$allowedFields = ['name', 'description', 'is_static', 'domains', 'git_repository', 'git_branch', 'git_commit_sha', 'docker_registry_image_name', 'docker_registry_image_tag', 'build_pack', 'static_image', 'install_command', 'build_command', 'start_command', 'ports_exposes', 'ports_mappings', 'base_directory', 'publish_directory', 'health_check_enabled', 'health_check_path', 'health_check_port', 'health_check_host', 'health_check_method', 'health_check_return_code', 'health_check_scheme', 'health_check_response_text', 'health_check_interval', 'health_check_timeout', 'health_check_retries', 'health_check_start_period', 'limits_memory', 'limits_memory_swap', 'limits_memory_swappiness', 'limits_memory_reservation', 'limits_cpus', 'limits_cpuset', 'limits_cpu_shares', 'custom_labels', 'custom_docker_run_options', 'post_deployment_command', 'post_deployment_command_container', 'pre_deployment_command', 'pre_deployment_command_container', 'watch_paths', 'manual_webhook_secret_github', 'manual_webhook_secret_gitlab', 'manual_webhook_secret_bitbucket', 'manual_webhook_secret_gitea', 'docker_compose_location', 'docker_compose_raw', 'docker_compose_custom_start_command', 'docker_compose_custom_build_command', 'docker_compose_domains', 'redirect', 'instant_deploy', 'use_build_server', 'custom_nginx_configuration'];
|
||||
$allowedFields = ['name', 'description', 'is_static', 'domains', 'git_repository', 'git_branch', 'git_commit_sha', 'docker_registry_image_name', 'docker_registry_image_tag', 'build_pack', 'static_image', 'install_command', 'build_command', 'start_command', 'ports_exposes', 'ports_mappings', 'base_directory', 'publish_directory', 'health_check_enabled', 'health_check_path', 'health_check_port', 'health_check_host', 'health_check_method', 'health_check_return_code', 'health_check_scheme', 'health_check_response_text', 'health_check_interval', 'health_check_timeout', 'health_check_retries', 'health_check_start_period', 'limits_memory', 'limits_memory_swap', 'limits_memory_swappiness', 'limits_memory_reservation', 'limits_cpus', 'limits_cpuset', 'limits_cpu_shares', 'custom_labels', 'custom_docker_run_options', 'post_deployment_command', 'post_deployment_command_container', 'pre_deployment_command', 'pre_deployment_command_container', 'watch_paths', 'manual_webhook_secret_github', 'manual_webhook_secret_gitlab', 'manual_webhook_secret_bitbucket', 'manual_webhook_secret_gitea', 'docker_compose_location', 'docker_compose_raw', 'docker_compose_custom_start_command', 'docker_compose_custom_build_command', 'docker_compose_domains', 'redirect', 'instant_deploy', 'use_build_server', 'custom_nginx_configuration', 'is_http_basic_auth_enabled', 'http_basic_auth_username', 'http_basic_auth_password'];
|
||||
|
||||
$validationRules = [
|
||||
'name' => 'string|max:255',
|
||||
@@ -1789,6 +1803,9 @@ class ApplicationsController extends Controller
|
||||
'docker_compose_custom_start_command' => 'string|nullable',
|
||||
'docker_compose_custom_build_command' => 'string|nullable',
|
||||
'custom_nginx_configuration' => 'string|nullable',
|
||||
'is_http_basic_auth_enabled' => 'boolean|nullable',
|
||||
'http_basic_auth_username' => 'string',
|
||||
'http_basic_auth_password' => 'string',
|
||||
];
|
||||
$validationRules = array_merge(sharedDataApplications(), $validationRules);
|
||||
$validator = customApiValidator($request->all(), $validationRules);
|
||||
@@ -1844,6 +1861,29 @@ class ApplicationsController extends Controller
|
||||
'errors' => $errors,
|
||||
], 422);
|
||||
}
|
||||
|
||||
if ($request->has('is_http_basic_auth_enabled') && $request->is_http_basic_auth_enabled === true) {
|
||||
if (blank($application->http_basic_auth_username) || blank($application->http_basic_auth_password)) {
|
||||
$validationErrors = [];
|
||||
if (blank($request->http_basic_auth_username)) {
|
||||
$validationErrors['http_basic_auth_username'] = 'The http_basic_auth_username is required.';
|
||||
}
|
||||
if (blank($request->http_basic_auth_password)) {
|
||||
$validationErrors['http_basic_auth_password'] = 'The http_basic_auth_password is required.';
|
||||
}
|
||||
if (count($validationErrors) > 0) {
|
||||
return response()->json([
|
||||
'message' => 'Validation failed.',
|
||||
'errors' => $validationErrors,
|
||||
], 422);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($request->has('is_http_basic_auth_enabled') && $application->is_container_label_readonly_enabled === false) {
|
||||
$application->custom_labels = str(implode('|coolify|', generateLabelsApplication($application)))->replace('|coolify|', "\n");
|
||||
$application->save();
|
||||
}
|
||||
|
||||
$domains = $request->domains;
|
||||
$requestHasDomains = $request->has('domains');
|
||||
if ($requestHasDomains && $server->isProxyShouldRun()) {
|
||||
@@ -2562,10 +2602,6 @@ class ApplicationsController extends Controller
|
||||
])->setStatusCode(201);
|
||||
}
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'message' => 'Something went wrong.',
|
||||
], 500);
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
|
||||
@@ -809,6 +809,6 @@ class ServersController extends Controller
|
||||
}
|
||||
ValidateServer::dispatch($server);
|
||||
|
||||
return response()->json(['message' => 'Validation started.']);
|
||||
return response()->json(['message' => 'Validation started.'], 201);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -380,6 +380,9 @@ class ServicesController extends Controller
|
||||
|
||||
$service = new Service;
|
||||
$result = $this->upsert_service($request, $service, $teamId);
|
||||
if ($result instanceof \Illuminate\Http\JsonResponse) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
return response()->json(serializeApiResponse($result))->setStatusCode(201);
|
||||
} else {
|
||||
@@ -608,12 +611,14 @@ class ServicesController extends Controller
|
||||
}
|
||||
|
||||
$service = Service::whereRelation('environment.project.team', 'id', $teamId)->whereUuid($request->uuid)->first();
|
||||
|
||||
if (! $service) {
|
||||
return response()->json(['message' => 'Service not found.'], 404);
|
||||
}
|
||||
|
||||
$result = $this->upsert_service($request, $service, $teamId);
|
||||
if ($result instanceof \Illuminate\Http\JsonResponse) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
return response()->json(serializeApiResponse($result))->setStatusCode(200);
|
||||
}
|
||||
|
||||
@@ -1377,6 +1377,17 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
|
||||
private function check_git_if_build_needed()
|
||||
{
|
||||
if ($this->source->getMorphClass() === \App\Models\GithubApp::class && $this->source->is_public === false) {
|
||||
$repository = githubApi($this->source, "repos/{$this->customRepository}");
|
||||
$data = data_get($repository, 'data');
|
||||
if (isset($data->id)) {
|
||||
$repository_project_id = $data->id;
|
||||
if (blank($this->application->repository_project_id) || $this->application->repository_project_id !== $repository_project_id) {
|
||||
$this->application->repository_project_id = $repository_project_id;
|
||||
$this->application->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->generate_git_import_commands();
|
||||
$local_branch = $this->branch;
|
||||
if ($this->pull_request_id !== 0) {
|
||||
@@ -1712,25 +1723,6 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
$labels = $labels->filter(function ($value, $key) {
|
||||
return ! Str::startsWith($value, 'coolify.');
|
||||
});
|
||||
$found_caddy_labels = $labels->filter(function ($value, $key) {
|
||||
return Str::startsWith($value, 'caddy_');
|
||||
});
|
||||
if ($found_caddy_labels->count() === 0) {
|
||||
if ($this->pull_request_id !== 0) {
|
||||
$domains = str(data_get($this->preview, 'fqdn'))->explode(',');
|
||||
} else {
|
||||
$domains = str(data_get($this->application, 'fqdn'))->explode(',');
|
||||
}
|
||||
$labels = $labels->merge(fqdnLabelsForCaddy(
|
||||
network: $this->application->destination->network,
|
||||
uuid: $this->application->uuid,
|
||||
domains: $domains,
|
||||
onlyPort: $onlyPort,
|
||||
is_force_https_enabled: $this->application->isForceHttpsEnabled(),
|
||||
is_gzip_enabled: $this->application->isGzipEnabled(),
|
||||
is_stripprefix_enabled: $this->application->isStripprefixEnabled()
|
||||
));
|
||||
}
|
||||
$this->application->custom_labels = base64_encode($labels->implode("\n"));
|
||||
$this->application->save();
|
||||
} else {
|
||||
|
||||
@@ -92,6 +92,9 @@ class General extends Component
|
||||
'application.settings.is_container_label_escape_enabled' => 'boolean|required',
|
||||
'application.settings.is_container_label_readonly_enabled' => 'boolean|required',
|
||||
'application.settings.is_preserve_repository_enabled' => 'boolean|required',
|
||||
'application.is_http_basic_auth_enabled' => 'boolean|required',
|
||||
'application.http_basic_auth_username' => 'string|nullable',
|
||||
'application.http_basic_auth_password' => 'string|nullable',
|
||||
'application.watch_paths' => 'nullable',
|
||||
'application.redirect' => 'string|required',
|
||||
];
|
||||
@@ -178,6 +181,9 @@ class General extends Component
|
||||
if ($this->application->settings->isDirty('is_spa')) {
|
||||
$this->generateNginxConfiguration($this->application->settings->is_spa ? 'spa' : 'static');
|
||||
}
|
||||
if ($this->application->isDirty('is_http_basic_auth_enabled')) {
|
||||
$this->application->save();
|
||||
}
|
||||
$this->application->settings->save();
|
||||
$this->dispatch('success', 'Settings saved.');
|
||||
$this->application->refresh();
|
||||
|
||||
@@ -111,6 +111,7 @@ class Source extends Component
|
||||
$this->application->update([
|
||||
'source_id' => $sourceId,
|
||||
'source_type' => $sourceType,
|
||||
'repository_project_id' => null,
|
||||
]);
|
||||
$this->application->refresh();
|
||||
$this->getSources();
|
||||
|
||||
@@ -236,15 +236,6 @@ class All extends Component
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Check for system variables that shouldn't be deleted
|
||||
foreach ($variablesToDelete as $envVar) {
|
||||
if ($this->isProtectedEnvironmentVariable($envVar->key)) {
|
||||
$this->dispatch('error', "Cannot delete system environment variable '{$envVar->key}'.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if any of these variables are used in Docker Compose
|
||||
if ($this->resource->type() === 'service' || $this->resource->build_pack === 'dockercompose') {
|
||||
foreach ($variablesToDelete as $envVar) {
|
||||
|
||||
@@ -178,13 +178,6 @@ class Show extends Component
|
||||
public function delete()
|
||||
{
|
||||
try {
|
||||
// Check if the variable is protected
|
||||
if ($this->isProtectedEnvironmentVariable($this->env->key)) {
|
||||
$this->dispatch('error', "Cannot delete system environment variable '{$this->env->key}'.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the variable is used in Docker Compose
|
||||
if ($this->type === 'service' || $this->type === 'application' && $this->env->resource()?->docker_compose) {
|
||||
[$isUsed, $reason] = $this->isEnvironmentVariableUsedInDockerCompose($this->env->key, $this->env->resource()?->docker_compose);
|
||||
|
||||
@@ -103,6 +103,9 @@ use Visus\Cuid2\Cuid2;
|
||||
'deleted_at' => ['type' => 'string', 'format' => 'date-time', 'nullable' => true, 'description' => 'The date and time when the application was deleted.'],
|
||||
'compose_parsing_version' => ['type' => 'string', 'description' => 'How Coolify parse the compose file.'],
|
||||
'custom_nginx_configuration' => ['type' => 'string', 'nullable' => true, 'description' => 'Custom Nginx configuration base64 encoded.'],
|
||||
'is_http_basic_auth_enabled' => ['type' => 'boolean', 'description' => 'HTTP Basic Authentication enabled.'],
|
||||
'http_basic_auth_username' => ['type' => 'string', 'nullable' => true, 'description' => 'Username for HTTP Basic Authentication'],
|
||||
'http_basic_auth_password' => ['type' => 'string', 'nullable' => true, 'description' => 'Password for HTTP Basic Authentication'],
|
||||
]
|
||||
)]
|
||||
|
||||
@@ -116,7 +119,10 @@ class Application extends BaseModel
|
||||
|
||||
protected $appends = ['server_status'];
|
||||
|
||||
protected $casts = ['custom_network_aliases' => 'array'];
|
||||
protected $casts = [
|
||||
'custom_network_aliases' => 'array',
|
||||
'http_basic_auth_password' => 'encrypted',
|
||||
];
|
||||
|
||||
public function customNetworkAliases(): Attribute
|
||||
{
|
||||
|
||||
@@ -17,8 +17,8 @@ use phpseclib3\Crypt\PublicKeyLoader;
|
||||
'name' => ['type' => 'string'],
|
||||
'description' => ['type' => 'string'],
|
||||
'private_key' => ['type' => 'string', 'format' => 'private-key'],
|
||||
'public_key' => ['type' => 'string'],
|
||||
'fingerprint' => ['type' => 'string'],
|
||||
'public_key' => ['type' => 'string', 'description' => 'The public key of the private key.'],
|
||||
'fingerprint' => ['type' => 'string', 'description' => 'The fingerprint of the private key.'],
|
||||
'is_git_related' => ['type' => 'boolean'],
|
||||
'team_id' => ['type' => 'integer'],
|
||||
'created_at' => ['type' => 'string'],
|
||||
|
||||
@@ -486,23 +486,13 @@ $schema://$host {
|
||||
$base_path = config('constants.coolify.base_config_path');
|
||||
$proxyType = $this->proxyType();
|
||||
$proxy_path = "$base_path/proxy";
|
||||
// TODO: should use /traefik for already existing configurations?
|
||||
// Should move everything except /caddy and /nginx to /traefik
|
||||
// The code needs to be modified as well, so maybe it does not worth it
|
||||
|
||||
if ($proxyType === ProxyTypes::TRAEFIK->value) {
|
||||
// Do nothing
|
||||
$proxy_path = '/';
|
||||
} elseif ($proxyType === ProxyTypes::CADDY->value) {
|
||||
if (isDev()) {
|
||||
$proxy_path = '/var/lib/docker/volumes/coolify_dev_coolify_data/_data/proxy/caddy';
|
||||
} else {
|
||||
$proxy_path = $proxy_path.'/caddy';
|
||||
}
|
||||
$proxy_path = $proxy_path.'/caddy';
|
||||
} elseif ($proxyType === ProxyTypes::NGINX->value) {
|
||||
if (isDev()) {
|
||||
$proxy_path = '/var/lib/docker/volumes/coolify_dev_coolify_data/_data/proxy/nginx';
|
||||
} else {
|
||||
$proxy_path = $proxy_path.'/nginx';
|
||||
}
|
||||
$proxy_path = $proxy_path.'/nginx';
|
||||
}
|
||||
|
||||
return $proxy_path;
|
||||
|
||||
@@ -141,6 +141,6 @@ class ServiceDatabase extends BaseModel
|
||||
str($this->databaseType())->contains('postgres') ||
|
||||
str($this->databaseType())->contains('postgis') ||
|
||||
str($this->databaseType())->contains('mariadb') ||
|
||||
str($this->databaseType())->contains('mongodb');
|
||||
str($this->databaseType())->contains('mongo');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -296,7 +296,8 @@ function generateServiceSpecificFqdns(ServiceApplication|Application $resource)
|
||||
|
||||
return $payload;
|
||||
}
|
||||
function fqdnLabelsForCaddy(string $network, string $uuid, Collection $domains, bool $is_force_https_enabled = false, $onlyPort = null, ?Collection $serviceLabels = null, ?bool $is_gzip_enabled = true, ?bool $is_stripprefix_enabled = true, ?string $service_name = null, ?string $image = null, string $redirect_direction = 'both', ?string $predefinedPort = null)
|
||||
|
||||
function fqdnLabelsForCaddy(string $network, string $uuid, Collection $domains, bool $is_force_https_enabled = false, $onlyPort = null, ?Collection $serviceLabels = null, ?bool $is_gzip_enabled = true, ?bool $is_stripprefix_enabled = true, ?string $service_name = null, ?string $image = null, string $redirect_direction = 'both', ?string $predefinedPort = null, bool $is_http_basic_auth_enabled = false, ?string $http_basic_auth_username = null, ?string $http_basic_auth_password = null)
|
||||
{
|
||||
$labels = collect([]);
|
||||
if ($serviceLabels) {
|
||||
@@ -304,6 +305,12 @@ function fqdnLabelsForCaddy(string $network, string $uuid, Collection $domains,
|
||||
} else {
|
||||
$labels->push("caddy_ingress_network={$network}");
|
||||
}
|
||||
|
||||
$is_http_basic_auth_enabled = $is_http_basic_auth_enabled && $http_basic_auth_username !== null && $http_basic_auth_password !== null;
|
||||
if ($is_http_basic_auth_enabled) {
|
||||
$hashedPassword = password_hash($http_basic_auth_password, PASSWORD_BCRYPT, ['cost' => 10]);
|
||||
}
|
||||
|
||||
foreach ($domains as $loop => $domain) {
|
||||
$url = Url::fromString($domain);
|
||||
$host = $url->getHost();
|
||||
@@ -340,20 +347,31 @@ function fqdnLabelsForCaddy(string $network, string $uuid, Collection $domains,
|
||||
if ($redirect_direction === 'non-www' && str($host)->startsWith('www.')) {
|
||||
$labels->push("caddy_{$loop}.redir={$schema}://{$host_without_www}{uri}");
|
||||
}
|
||||
if (isDev()) {
|
||||
// $labels->push("caddy_{$loop}.tls=internal");
|
||||
if ($is_http_basic_auth_enabled) {
|
||||
$labels->push("caddy_{$loop}.basicauth.{$http_basic_auth_username}=\"{$hashedPassword}\"");
|
||||
}
|
||||
}
|
||||
|
||||
return $labels->sort();
|
||||
}
|
||||
function fqdnLabelsForTraefik(string $uuid, Collection $domains, bool $is_force_https_enabled = false, $onlyPort = null, ?Collection $serviceLabels = null, ?bool $is_gzip_enabled = true, ?bool $is_stripprefix_enabled = true, ?string $service_name = null, bool $generate_unique_uuid = false, ?string $image = null, string $redirect_direction = 'both')
|
||||
|
||||
function fqdnLabelsForTraefik(string $uuid, Collection $domains, bool $is_force_https_enabled = false, $onlyPort = null, ?Collection $serviceLabels = null, ?bool $is_gzip_enabled = true, ?bool $is_stripprefix_enabled = true, ?string $service_name = null, bool $generate_unique_uuid = false, ?string $image = null, string $redirect_direction = 'both', bool $is_http_basic_auth_enabled = false, ?string $http_basic_auth_username = null, ?string $http_basic_auth_password = null)
|
||||
{
|
||||
$labels = collect([]);
|
||||
$labels->push('traefik.enable=true');
|
||||
$labels->push('traefik.http.middlewares.gzip.compress=true');
|
||||
$labels->push('traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https');
|
||||
|
||||
$is_http_basic_auth_enabled = $is_http_basic_auth_enabled && $http_basic_auth_username !== null && $http_basic_auth_password !== null;
|
||||
$http_basic_auth_label = "http-basic-auth-{$uuid}";
|
||||
if ($is_http_basic_auth_enabled) {
|
||||
$hashedPassword = password_hash($http_basic_auth_password, PASSWORD_BCRYPT, ['cost' => 10]);
|
||||
}
|
||||
|
||||
if ($is_http_basic_auth_enabled) {
|
||||
$labels->push("traefik.http.middlewares.{$http_basic_auth_label}.basicauth.users={$http_basic_auth_username}:{$hashedPassword}");
|
||||
}
|
||||
|
||||
$middlewares_from_labels = collect([]);
|
||||
|
||||
if ($serviceLabels) {
|
||||
@@ -439,6 +457,9 @@ function fqdnLabelsForTraefik(string $uuid, Collection $domains, bool $is_force_
|
||||
$labels = $labels->merge($redirect_to_www);
|
||||
$middlewares->push($to_www_name);
|
||||
}
|
||||
if ($is_http_basic_auth_enabled) {
|
||||
$middlewares->push($http_basic_auth_label);
|
||||
}
|
||||
$middlewares_from_labels->each(function ($middleware_name) use ($middlewares) {
|
||||
$middlewares->push($middleware_name);
|
||||
});
|
||||
@@ -462,6 +483,9 @@ function fqdnLabelsForTraefik(string $uuid, Collection $domains, bool $is_force_
|
||||
$labels = $labels->merge($redirect_to_www);
|
||||
$middlewares->push($to_www_name);
|
||||
}
|
||||
if ($is_http_basic_auth_enabled) {
|
||||
$middlewares->push($http_basic_auth_label);
|
||||
}
|
||||
$middlewares_from_labels->each(function ($middleware_name) use ($middlewares) {
|
||||
$middlewares->push($middleware_name);
|
||||
});
|
||||
@@ -511,6 +535,9 @@ function fqdnLabelsForTraefik(string $uuid, Collection $domains, bool $is_force_
|
||||
$labels = $labels->merge($redirect_to_www);
|
||||
$middlewares->push($to_www_name);
|
||||
}
|
||||
if ($is_http_basic_auth_enabled) {
|
||||
$middlewares->push($http_basic_auth_label);
|
||||
}
|
||||
$middlewares_from_labels->each(function ($middleware_name) use ($middlewares) {
|
||||
$middlewares->push($middleware_name);
|
||||
});
|
||||
@@ -534,6 +561,9 @@ function fqdnLabelsForTraefik(string $uuid, Collection $domains, bool $is_force_
|
||||
$labels = $labels->merge($redirect_to_www);
|
||||
$middlewares->push($to_www_name);
|
||||
}
|
||||
if ($is_http_basic_auth_enabled) {
|
||||
$middlewares->push($http_basic_auth_label);
|
||||
}
|
||||
$middlewares_from_labels->each(function ($middleware_name) use ($middlewares) {
|
||||
$middlewares->push($middleware_name);
|
||||
});
|
||||
@@ -577,7 +607,10 @@ function generateLabelsApplication(Application $application, ?ApplicationPreview
|
||||
is_force_https_enabled: $application->isForceHttpsEnabled(),
|
||||
is_gzip_enabled: $application->isGzipEnabled(),
|
||||
is_stripprefix_enabled: $application->isStripprefixEnabled(),
|
||||
redirect_direction: $application->redirect
|
||||
redirect_direction: $application->redirect,
|
||||
is_http_basic_auth_enabled: $application->is_http_basic_auth_enabled,
|
||||
http_basic_auth_username: $application->http_basic_auth_username,
|
||||
http_basic_auth_password: $application->http_basic_auth_password,
|
||||
));
|
||||
break;
|
||||
case ProxyTypes::CADDY->value:
|
||||
@@ -589,7 +622,10 @@ function generateLabelsApplication(Application $application, ?ApplicationPreview
|
||||
is_force_https_enabled: $application->isForceHttpsEnabled(),
|
||||
is_gzip_enabled: $application->isGzipEnabled(),
|
||||
is_stripprefix_enabled: $application->isStripprefixEnabled(),
|
||||
redirect_direction: $application->redirect
|
||||
redirect_direction: $application->redirect,
|
||||
is_http_basic_auth_enabled: $application->is_http_basic_auth_enabled,
|
||||
http_basic_auth_username: $application->http_basic_auth_username,
|
||||
http_basic_auth_password: $application->http_basic_auth_password,
|
||||
));
|
||||
break;
|
||||
}
|
||||
@@ -601,7 +637,10 @@ function generateLabelsApplication(Application $application, ?ApplicationPreview
|
||||
is_force_https_enabled: $application->isForceHttpsEnabled(),
|
||||
is_gzip_enabled: $application->isGzipEnabled(),
|
||||
is_stripprefix_enabled: $application->isStripprefixEnabled(),
|
||||
redirect_direction: $application->redirect
|
||||
redirect_direction: $application->redirect,
|
||||
is_http_basic_auth_enabled: $application->is_http_basic_auth_enabled,
|
||||
http_basic_auth_username: $application->http_basic_auth_username,
|
||||
http_basic_auth_password: $application->http_basic_auth_password,
|
||||
));
|
||||
$labels = $labels->merge(fqdnLabelsForCaddy(
|
||||
network: $application->destination->network,
|
||||
@@ -611,7 +650,10 @@ function generateLabelsApplication(Application $application, ?ApplicationPreview
|
||||
is_force_https_enabled: $application->isForceHttpsEnabled(),
|
||||
is_gzip_enabled: $application->isGzipEnabled(),
|
||||
is_stripprefix_enabled: $application->isStripprefixEnabled(),
|
||||
redirect_direction: $application->redirect
|
||||
redirect_direction: $application->redirect,
|
||||
is_http_basic_auth_enabled: $application->is_http_basic_auth_enabled,
|
||||
http_basic_auth_username: $application->http_basic_auth_username,
|
||||
http_basic_auth_password: $application->http_basic_auth_password,
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -631,7 +673,10 @@ function generateLabelsApplication(Application $application, ?ApplicationPreview
|
||||
onlyPort: $onlyPort,
|
||||
is_force_https_enabled: $application->isForceHttpsEnabled(),
|
||||
is_gzip_enabled: $application->isGzipEnabled(),
|
||||
is_stripprefix_enabled: $application->isStripprefixEnabled()
|
||||
is_stripprefix_enabled: $application->isStripprefixEnabled(),
|
||||
is_http_basic_auth_enabled: $application->is_http_basic_auth_enabled,
|
||||
http_basic_auth_username: $application->http_basic_auth_username,
|
||||
http_basic_auth_password: $application->http_basic_auth_password,
|
||||
));
|
||||
break;
|
||||
case ProxyTypes::CADDY->value:
|
||||
@@ -642,7 +687,10 @@ function generateLabelsApplication(Application $application, ?ApplicationPreview
|
||||
onlyPort: $onlyPort,
|
||||
is_force_https_enabled: $application->isForceHttpsEnabled(),
|
||||
is_gzip_enabled: $application->isGzipEnabled(),
|
||||
is_stripprefix_enabled: $application->isStripprefixEnabled()
|
||||
is_stripprefix_enabled: $application->isStripprefixEnabled(),
|
||||
is_http_basic_auth_enabled: $application->is_http_basic_auth_enabled,
|
||||
http_basic_auth_username: $application->http_basic_auth_username,
|
||||
http_basic_auth_password: $application->http_basic_auth_password,
|
||||
));
|
||||
break;
|
||||
}
|
||||
@@ -653,7 +701,10 @@ function generateLabelsApplication(Application $application, ?ApplicationPreview
|
||||
onlyPort: $onlyPort,
|
||||
is_force_https_enabled: $application->isForceHttpsEnabled(),
|
||||
is_gzip_enabled: $application->isGzipEnabled(),
|
||||
is_stripprefix_enabled: $application->isStripprefixEnabled()
|
||||
is_stripprefix_enabled: $application->isStripprefixEnabled(),
|
||||
is_http_basic_auth_enabled: $application->is_http_basic_auth_enabled,
|
||||
http_basic_auth_username: $application->http_basic_auth_username,
|
||||
http_basic_auth_password: $application->http_basic_auth_password,
|
||||
));
|
||||
$labels = $labels->merge(fqdnLabelsForCaddy(
|
||||
network: $application->destination->network,
|
||||
@@ -662,7 +713,10 @@ function generateLabelsApplication(Application $application, ?ApplicationPreview
|
||||
onlyPort: $onlyPort,
|
||||
is_force_https_enabled: $application->isForceHttpsEnabled(),
|
||||
is_gzip_enabled: $application->isGzipEnabled(),
|
||||
is_stripprefix_enabled: $application->isStripprefixEnabled()
|
||||
is_stripprefix_enabled: $application->isStripprefixEnabled(),
|
||||
is_http_basic_auth_enabled: $application->is_http_basic_auth_enabled,
|
||||
http_basic_auth_username: $application->http_basic_auth_username,
|
||||
http_basic_auth_password: $application->http_basic_auth_password,
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -682,8 +736,10 @@ function isDatabaseImage(?string $image = null)
|
||||
$image = str($image)->append(':latest');
|
||||
}
|
||||
$imageName = $image->before(':');
|
||||
if (collect(DATABASE_DOCKER_IMAGES)->contains($imageName)) {
|
||||
return true;
|
||||
foreach (DATABASE_DOCKER_IMAGES as $database_docker_image) {
|
||||
if (str($imageName)->contains($database_docker_image)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -715,6 +771,7 @@ function convertDockerRunToCompose(?string $custom_docker_run_options = null)
|
||||
'--ip' => 'ip',
|
||||
'--shm-size' => 'shm_size',
|
||||
'--gpus' => 'gpus',
|
||||
'--hostname' => 'hostname',
|
||||
]);
|
||||
foreach ($matches as $match) {
|
||||
$option = $match[1];
|
||||
@@ -725,6 +782,16 @@ function convertDockerRunToCompose(?string $custom_docker_run_options = null)
|
||||
$options[$option][] = $value;
|
||||
$options[$option] = array_unique($options[$option]);
|
||||
}
|
||||
if ($option === '--hostname') {
|
||||
// Match --hostname=value or --hostname value
|
||||
$regexForParsingHostname = '/--hostname(?:=|\s+)([^\s]+)/';
|
||||
preg_match($regexForParsingHostname, $custom_docker_run_options, $hostname_matches);
|
||||
$value = $hostname_matches[1] ?? null;
|
||||
if ($value && ! empty(trim($value))) {
|
||||
$options[$option][] = $value;
|
||||
$options[$option] = array_unique($options[$option]);
|
||||
}
|
||||
}
|
||||
if (isset($match[2]) && $match[2] !== '') {
|
||||
$value = $match[2];
|
||||
$options[$option][] = $value;
|
||||
@@ -761,8 +828,8 @@ function convertDockerRunToCompose(?string $custom_docker_run_options = null)
|
||||
}
|
||||
});
|
||||
$compose_options->put($mapping[$option], $ulimits);
|
||||
} elseif ($option === '--shm-size') {
|
||||
if (! is_null($value) && is_array($value) && count($value) > 0) {
|
||||
} elseif ($option === '--shm-size' || $option === '--hostname') {
|
||||
if (! is_null($value) && is_array($value) && count($value) > 0 && ! empty(trim($value[0]))) {
|
||||
$compose_options->put($mapping[$option], $value[0]);
|
||||
}
|
||||
} elseif ($option === '--gpus') {
|
||||
@@ -770,7 +837,7 @@ function convertDockerRunToCompose(?string $custom_docker_run_options = null)
|
||||
'driver' => 'nvidia',
|
||||
'capabilities' => ['gpu'],
|
||||
];
|
||||
if (! is_null($value) && is_array($value) && count($value) > 0) {
|
||||
if (! is_null($value) && is_array($value) && count($value) > 0 && ! empty(trim($value[0]))) {
|
||||
if (str($value[0]) != 'all') {
|
||||
if (str($value[0])->contains(',')) {
|
||||
$payload['device_ids'] = str($value[0])->explode(',')->toArray();
|
||||
@@ -800,7 +867,6 @@ function convertDockerRunToCompose(?string $custom_docker_run_options = null)
|
||||
|
||||
continue;
|
||||
}
|
||||
$compose_options->forget($option);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3819,7 +3819,6 @@ function newParser(Application|Service $resource, int $pull_request_id = 0, ?int
|
||||
return $volume;
|
||||
});
|
||||
|
||||
ray($serviceLabels);
|
||||
$payload = collect($service)->merge([
|
||||
'container_name' => $containerName,
|
||||
'restart' => $restart->value(),
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
<?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('applications', function (Blueprint $table) {
|
||||
$table->boolean('is_http_basic_auth_enabled')->default(false);
|
||||
$table->string('http_basic_auth_username')->nullable(true)->default(null);
|
||||
$table->string('http_basic_auth_password')->nullable(true)->default(null);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('applications', function (Blueprint $table) {
|
||||
$table->dropColumn('is_http_basic_auth_enabled');
|
||||
$table->dropColumn('http_basic_auth_username');
|
||||
$table->dropColumn('http_basic_auth_password');
|
||||
});
|
||||
}
|
||||
};
|
||||
92
openapi.json
92
openapi.json
@@ -339,6 +339,20 @@
|
||||
"type": "boolean",
|
||||
"nullable": true,
|
||||
"description": "Use build server."
|
||||
},
|
||||
"is_http_basic_auth_enabled": {
|
||||
"type": "boolean",
|
||||
"description": "HTTP Basic Authentication enabled."
|
||||
},
|
||||
"http_basic_auth_username": {
|
||||
"type": "string",
|
||||
"nullable": true,
|
||||
"description": "Username for HTTP Basic Authentication"
|
||||
},
|
||||
"http_basic_auth_password": {
|
||||
"type": "string",
|
||||
"nullable": true,
|
||||
"description": "Password for HTTP Basic Authentication"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
@@ -673,6 +687,20 @@
|
||||
"type": "boolean",
|
||||
"nullable": true,
|
||||
"description": "Use build server."
|
||||
},
|
||||
"is_http_basic_auth_enabled": {
|
||||
"type": "boolean",
|
||||
"description": "HTTP Basic Authentication enabled."
|
||||
},
|
||||
"http_basic_auth_username": {
|
||||
"type": "string",
|
||||
"nullable": true,
|
||||
"description": "Username for HTTP Basic Authentication"
|
||||
},
|
||||
"http_basic_auth_password": {
|
||||
"type": "string",
|
||||
"nullable": true,
|
||||
"description": "Password for HTTP Basic Authentication"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
@@ -1007,6 +1035,20 @@
|
||||
"type": "boolean",
|
||||
"nullable": true,
|
||||
"description": "Use build server."
|
||||
},
|
||||
"is_http_basic_auth_enabled": {
|
||||
"type": "boolean",
|
||||
"description": "HTTP Basic Authentication enabled."
|
||||
},
|
||||
"http_basic_auth_username": {
|
||||
"type": "string",
|
||||
"nullable": true,
|
||||
"description": "Username for HTTP Basic Authentication"
|
||||
},
|
||||
"http_basic_auth_password": {
|
||||
"type": "string",
|
||||
"nullable": true,
|
||||
"description": "Password for HTTP Basic Authentication"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
@@ -1270,6 +1312,20 @@
|
||||
"type": "boolean",
|
||||
"nullable": true,
|
||||
"description": "Use build server."
|
||||
},
|
||||
"is_http_basic_auth_enabled": {
|
||||
"type": "boolean",
|
||||
"description": "HTTP Basic Authentication enabled."
|
||||
},
|
||||
"http_basic_auth_username": {
|
||||
"type": "string",
|
||||
"nullable": true,
|
||||
"description": "Username for HTTP Basic Authentication"
|
||||
},
|
||||
"http_basic_auth_password": {
|
||||
"type": "string",
|
||||
"nullable": true,
|
||||
"description": "Password for HTTP Basic Authentication"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
@@ -1516,6 +1572,20 @@
|
||||
"type": "boolean",
|
||||
"nullable": true,
|
||||
"description": "Use build server."
|
||||
},
|
||||
"is_http_basic_auth_enabled": {
|
||||
"type": "boolean",
|
||||
"description": "HTTP Basic Authentication enabled."
|
||||
},
|
||||
"http_basic_auth_username": {
|
||||
"type": "string",
|
||||
"nullable": true,
|
||||
"description": "Username for HTTP Basic Authentication"
|
||||
},
|
||||
"http_basic_auth_password": {
|
||||
"type": "string",
|
||||
"nullable": true,
|
||||
"description": "Password for HTTP Basic Authentication"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
@@ -7553,6 +7623,20 @@
|
||||
"type": "string",
|
||||
"nullable": true,
|
||||
"description": "Custom Nginx configuration base64 encoded."
|
||||
},
|
||||
"is_http_basic_auth_enabled": {
|
||||
"type": "boolean",
|
||||
"description": "HTTP Basic Authentication enabled."
|
||||
},
|
||||
"http_basic_auth_username": {
|
||||
"type": "string",
|
||||
"nullable": true,
|
||||
"description": "Username for HTTP Basic Authentication"
|
||||
},
|
||||
"http_basic_auth_password": {
|
||||
"type": "string",
|
||||
"nullable": true,
|
||||
"description": "Password for HTTP Basic Authentication"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
@@ -7729,6 +7813,14 @@
|
||||
"type": "string",
|
||||
"format": "private-key"
|
||||
},
|
||||
"public_key": {
|
||||
"type": "string",
|
||||
"description": "The public key of the private key."
|
||||
},
|
||||
"fingerprint": {
|
||||
"type": "string",
|
||||
"description": "The fingerprint of the private key."
|
||||
},
|
||||
"is_git_related": {
|
||||
"type": "boolean"
|
||||
},
|
||||
|
||||
72
openapi.yaml
72
openapi.yaml
@@ -248,6 +248,17 @@ paths:
|
||||
type: boolean
|
||||
nullable: true
|
||||
description: 'Use build server.'
|
||||
is_http_basic_auth_enabled:
|
||||
type: boolean
|
||||
description: 'HTTP Basic Authentication enabled.'
|
||||
http_basic_auth_username:
|
||||
type: string
|
||||
nullable: true
|
||||
description: 'Username for HTTP Basic Authentication'
|
||||
http_basic_auth_password:
|
||||
type: string
|
||||
nullable: true
|
||||
description: 'Password for HTTP Basic Authentication'
|
||||
type: object
|
||||
responses:
|
||||
'201':
|
||||
@@ -487,6 +498,17 @@ paths:
|
||||
type: boolean
|
||||
nullable: true
|
||||
description: 'Use build server.'
|
||||
is_http_basic_auth_enabled:
|
||||
type: boolean
|
||||
description: 'HTTP Basic Authentication enabled.'
|
||||
http_basic_auth_username:
|
||||
type: string
|
||||
nullable: true
|
||||
description: 'Username for HTTP Basic Authentication'
|
||||
http_basic_auth_password:
|
||||
type: string
|
||||
nullable: true
|
||||
description: 'Password for HTTP Basic Authentication'
|
||||
type: object
|
||||
responses:
|
||||
'201':
|
||||
@@ -726,6 +748,17 @@ paths:
|
||||
type: boolean
|
||||
nullable: true
|
||||
description: 'Use build server.'
|
||||
is_http_basic_auth_enabled:
|
||||
type: boolean
|
||||
description: 'HTTP Basic Authentication enabled.'
|
||||
http_basic_auth_username:
|
||||
type: string
|
||||
nullable: true
|
||||
description: 'Username for HTTP Basic Authentication'
|
||||
http_basic_auth_password:
|
||||
type: string
|
||||
nullable: true
|
||||
description: 'Password for HTTP Basic Authentication'
|
||||
type: object
|
||||
responses:
|
||||
'201':
|
||||
@@ -912,6 +945,17 @@ paths:
|
||||
type: boolean
|
||||
nullable: true
|
||||
description: 'Use build server.'
|
||||
is_http_basic_auth_enabled:
|
||||
type: boolean
|
||||
description: 'HTTP Basic Authentication enabled.'
|
||||
http_basic_auth_username:
|
||||
type: string
|
||||
nullable: true
|
||||
description: 'Username for HTTP Basic Authentication'
|
||||
http_basic_auth_password:
|
||||
type: string
|
||||
nullable: true
|
||||
description: 'Password for HTTP Basic Authentication'
|
||||
type: object
|
||||
responses:
|
||||
'201':
|
||||
@@ -1089,6 +1133,17 @@ paths:
|
||||
type: boolean
|
||||
nullable: true
|
||||
description: 'Use build server.'
|
||||
is_http_basic_auth_enabled:
|
||||
type: boolean
|
||||
description: 'HTTP Basic Authentication enabled.'
|
||||
http_basic_auth_username:
|
||||
type: string
|
||||
nullable: true
|
||||
description: 'Username for HTTP Basic Authentication'
|
||||
http_basic_auth_password:
|
||||
type: string
|
||||
nullable: true
|
||||
description: 'Password for HTTP Basic Authentication'
|
||||
type: object
|
||||
responses:
|
||||
'201':
|
||||
@@ -5042,6 +5097,17 @@ components:
|
||||
type: string
|
||||
nullable: true
|
||||
description: 'Custom Nginx configuration base64 encoded.'
|
||||
is_http_basic_auth_enabled:
|
||||
type: boolean
|
||||
description: 'HTTP Basic Authentication enabled.'
|
||||
http_basic_auth_username:
|
||||
type: string
|
||||
nullable: true
|
||||
description: 'Username for HTTP Basic Authentication'
|
||||
http_basic_auth_password:
|
||||
type: string
|
||||
nullable: true
|
||||
description: 'Password for HTTP Basic Authentication'
|
||||
type: object
|
||||
ApplicationDeploymentQueue:
|
||||
description: 'Project model'
|
||||
@@ -5159,6 +5225,12 @@ components:
|
||||
private_key:
|
||||
type: string
|
||||
format: private-key
|
||||
public_key:
|
||||
type: string
|
||||
description: 'The public key of the private key.'
|
||||
fingerprint:
|
||||
type: string
|
||||
description: 'The fingerprint of the private key.'
|
||||
is_git_related:
|
||||
type: boolean
|
||||
team_id:
|
||||
|
||||
@@ -181,7 +181,7 @@
|
||||
@if ($application->build_pack === 'dockerimage')
|
||||
<x-forms.input
|
||||
helper="You can add custom docker run options that will be used when your container is started.<br>Note: Not all options are supported, as they could mess up Coolify's automation and could cause bad experience for users.<br><br>Check the <a class='underline dark:text-white' href='https://coolify.io/docs/knowledge-base/docker/custom-commands'>docs.</a>"
|
||||
placeholder="--cap-add SYS_ADMIN --device=/dev/fuse --security-opt apparmor:unconfined --ulimit nofile=1024:1024 --tmpfs /run:rw,noexec,nosuid,size=65536k"
|
||||
placeholder="--cap-add SYS_ADMIN --device=/dev/fuse --security-opt apparmor:unconfined --ulimit nofile=1024:1024 --tmpfs /run:rw,noexec,nosuid,size=65536k --hostname=myapp"
|
||||
id="application.custom_docker_run_options" label="Custom Docker Options" />
|
||||
@else
|
||||
@if ($application->could_set_build_commands())
|
||||
@@ -274,7 +274,7 @@
|
||||
@endif
|
||||
<x-forms.input
|
||||
helper="You can add custom docker run options that will be used when your container is started.<br>Note: Not all options are supported, as they could mess up Coolify's automation and could cause bad experience for users.<br><br>Check the <a class='underline dark:text-white' href='https://coolify.io/docs/knowledge-base/docker/custom-commands'>docs.</a>"
|
||||
placeholder="--cap-add SYS_ADMIN --device=/dev/fuse --security-opt apparmor:unconfined --ulimit nofile=1024:1024 --tmpfs /run:rw,noexec,nosuid,size=65536k"
|
||||
placeholder="--cap-add SYS_ADMIN --device=/dev/fuse --security-opt apparmor:unconfined --ulimit nofile=1024:1024 --tmpfs /run:rw,noexec,nosuid,size=65536k --hostname=myapp"
|
||||
id="application.custom_docker_run_options" label="Custom Docker Options" />
|
||||
|
||||
@if ($application->build_pack !== 'dockercompose')
|
||||
@@ -349,6 +349,21 @@
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<h3 class="pt-8">HTTP Basic Authentication</h3>
|
||||
<div>
|
||||
<div class="w-96">
|
||||
<x-forms.checkbox helper="This will add the proper proxy labels to the container." instantSave
|
||||
label="Enable" id="application.is_http_basic_auth_enabled" />
|
||||
</div>
|
||||
@if ($application->is_http_basic_auth_enabled)
|
||||
<div class="flex gap-2 py-2">
|
||||
<x-forms.input id="application.http_basic_auth_username" label="Username" required />
|
||||
<x-forms.input id="application.http_basic_auth_password" type="password" label="Password"
|
||||
required />
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
@if ($application->settings->is_container_label_readonly_enabled)
|
||||
<x-forms.textarea readonly disabled label="Container Labels" rows="15" id="customLabels"
|
||||
monacoEditorLanguage="ini" useMonacoEditor></x-forms.textarea>
|
||||
|
||||
@@ -81,7 +81,7 @@
|
||||
</x-modal-confirmation>
|
||||
</div>
|
||||
@empty
|
||||
<div class="text-center">No sources found</div>
|
||||
<div>No other sources found</div>
|
||||
@endforelse
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -20,7 +20,12 @@
|
||||
</div>
|
||||
<div class="w-48 pb-2">
|
||||
<x-forms.checkbox instantSave label="Backup Enabled" id="backupEnabled" />
|
||||
<x-forms.checkbox instantSave label="S3 Enabled" id="saveS3" />
|
||||
@if ($s3s->count() > 0)
|
||||
<x-forms.checkbox instantSave label="S3 Enabled" id="saveS3" />
|
||||
@else
|
||||
<x-forms.checkbox instantSave helper="No validated S3 storage available." label="S3 Enabled" id="saveS3"
|
||||
disabled />
|
||||
@endif
|
||||
</div>
|
||||
@if ($backup->save_s3)
|
||||
<div class="pb-6">
|
||||
|
||||
@@ -16,8 +16,13 @@ use App\Models\Server;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
Route::get('/health', [OtherController::class, 'healthcheck']);
|
||||
Route::post('/feedback', [OtherController::class, 'feedback']);
|
||||
Route::group([
|
||||
'prefix' => 'v1',
|
||||
], function () {
|
||||
Route::get('/health', [OtherController::class, 'healthcheck']);
|
||||
});
|
||||
|
||||
Route::post('/feedback', [OtherController::class, 'feedback']);
|
||||
Route::group([
|
||||
'middleware' => ['auth:sanctum', 'api.ability:write'],
|
||||
'prefix' => 'v1',
|
||||
@@ -88,7 +93,6 @@ Route::group([
|
||||
Route::patch('/applications/{uuid}/envs/bulk', [ApplicationsController::class, 'create_bulk_envs'])->middleware(['api.ability:write']);
|
||||
Route::patch('/applications/{uuid}/envs', [ApplicationsController::class, 'update_env_by_uuid'])->middleware(['api.ability:write']);
|
||||
Route::delete('/applications/{uuid}/envs/{env_uuid}', [ApplicationsController::class, 'delete_env_by_uuid'])->middleware(['api.ability:write']);
|
||||
// Route::post('/applications/{uuid}/execute', [ApplicationsController::class, 'execute_command_by_uuid'])->middleware(['ability:write']);
|
||||
Route::get('/applications/{uuid}/logs', [ApplicationsController::class, 'logs_by_uuid'])->middleware(['api.ability:read']);
|
||||
|
||||
Route::match(['get', 'post'], '/applications/{uuid}/start', [ApplicationsController::class, 'action_deploy'])->middleware(['api.ability:write']);
|
||||
@@ -117,7 +121,7 @@ Route::group([
|
||||
Route::post('/services', [ServicesController::class, 'create_service'])->middleware(['api.ability:write']);
|
||||
|
||||
Route::get('/services/{uuid}', [ServicesController::class, 'service_by_uuid'])->middleware(['api.ability:read']);
|
||||
Route::patch('/services/{uuid}', [ServicesController::class, 'update_by_uuid'])->middleware(['ability:write']);
|
||||
Route::patch('/services/{uuid}', [ServicesController::class, 'update_by_uuid'])->middleware(['api.ability:write']);
|
||||
Route::delete('/services/{uuid}', [ServicesController::class, 'delete_by_uuid'])->middleware(['api.ability:write']);
|
||||
|
||||
Route::get('/services/{uuid}/envs', [ServicesController::class, 'envs'])->middleware(['api.ability:read']);
|
||||
|
||||
@@ -1,5 +1,34 @@
|
||||
<?php
|
||||
|
||||
test('Hostname', function () {
|
||||
$input = '--hostname=test';
|
||||
$output = convertDockerRunToCompose($input);
|
||||
expect($output)->toBe([
|
||||
'hostname' => 'test',
|
||||
]);
|
||||
});
|
||||
test('HostnameWithoutEqualSign', function () {
|
||||
$input = '--hostname test';
|
||||
$output = convertDockerRunToCompose($input);
|
||||
expect($output)->toBe([
|
||||
'hostname' => 'test',
|
||||
]);
|
||||
});
|
||||
test('HostnameWithoutEqualSignAndHyphens', function () {
|
||||
$input = '--hostname my-super-host';
|
||||
$output = convertDockerRunToCompose($input);
|
||||
expect($output)->toBe([
|
||||
'hostname' => 'my-super-host',
|
||||
]);
|
||||
});
|
||||
|
||||
test('HostnameWithHyphens', function () {
|
||||
$input = '--hostname=my-super-host';
|
||||
$output = convertDockerRunToCompose($input);
|
||||
expect($output)->toBe([
|
||||
'hostname' => 'my-super-host',
|
||||
]);
|
||||
});
|
||||
test('ConvertCapAdd', function () {
|
||||
$input = '--cap-add=NET_ADMIN --cap-add=NET_RAW --cap-add SYS_ADMIN';
|
||||
$output = convertDockerRunToCompose($input);
|
||||
|
||||
Reference in New Issue
Block a user