mirror of
https://github.com/vitodeploy/vito.git
synced 2025-04-19 09:51:37 +00:00
Isolate Users (#431)
* WIP to isolate users * Resolved issue with SSH AsUser Updated Isolated User Script to use Server User for Team Access Updated Path creation script to simplify for running as the isolated user * Included the server user * PHPMyAdmin script updated Wordpress Script Updated Updated Execute Script to support executing as isolated users * Issue Resolution & Resolved Failing Unit Tests * Fix for isolated_username vs user * Run the deploy as the isolated user * queue updates for isolated user * Support isolated users in cronjobs * script tests for isolated users * Queue tests for isolated users * Cronjob tests for isolated user * Removed default queue command for laravel apps * add default user to factory * laravel pint fixes * ensure echos are consistent * removed unneeded parameter * update * fix queues for isolated users * revert addslashes --------- Co-authored-by: Saeed Vaziry <mr.saeedvaziry@gmail.com>
This commit is contained in:
parent
5947ae80bb
commit
c1ae58772c
@ -6,6 +6,7 @@
|
||||
use App\Models\CronJob;
|
||||
use App\Models\Server;
|
||||
use App\ValidationRules\CronRule;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class CreateCronJob
|
||||
{
|
||||
@ -27,7 +28,7 @@ public function create(Server $server, array $input): CronJob
|
||||
return $cronJob;
|
||||
}
|
||||
|
||||
public static function rules(array $input): array
|
||||
public static function rules(array $input, Server $server): array
|
||||
{
|
||||
$rules = [
|
||||
'command' => [
|
||||
@ -35,7 +36,7 @@ public static function rules(array $input): array
|
||||
],
|
||||
'user' => [
|
||||
'required',
|
||||
'in:root,'.config('core.ssh_user'),
|
||||
Rule::in($server->getSshUsers()),
|
||||
],
|
||||
'frequency' => [
|
||||
'required',
|
||||
|
@ -46,7 +46,7 @@ public function create(mixed $queueable, array $input): void
|
||||
})->onConnection('ssh');
|
||||
}
|
||||
|
||||
public static function rules(Server $server): array
|
||||
public static function rules(Site $site): array
|
||||
{
|
||||
return [
|
||||
'command' => [
|
||||
@ -56,7 +56,7 @@ public static function rules(Server $server): array
|
||||
'required',
|
||||
Rule::in([
|
||||
'root',
|
||||
$server->ssh_user,
|
||||
$site->user,
|
||||
]),
|
||||
],
|
||||
'numprocs' => [
|
||||
|
@ -41,9 +41,11 @@ public function execute(Script $script, array $input): ScriptExecution
|
||||
|
||||
public static function rules(array $input): array
|
||||
{
|
||||
$users = ['root'];
|
||||
if (isset($input['server'])) {
|
||||
/** @var ?Server $server */
|
||||
$server = Server::query()->find($input['server']);
|
||||
$users = $server->getSshUsers();
|
||||
}
|
||||
|
||||
return [
|
||||
@ -53,10 +55,7 @@ public static function rules(array $input): array
|
||||
],
|
||||
'user' => [
|
||||
'required',
|
||||
Rule::in([
|
||||
'root',
|
||||
isset($server) ? $server?->ssh_user : null,
|
||||
]),
|
||||
Rule::in($users),
|
||||
],
|
||||
'variables' => 'array',
|
||||
'variables.*' => [
|
||||
|
@ -23,12 +23,14 @@ public function create(Server $server, array $input): Site
|
||||
{
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
$user = $input['user'] ?? $server->getSshUser();
|
||||
$site = new Site([
|
||||
'server_id' => $server->id,
|
||||
'type' => $input['type'],
|
||||
'domain' => $input['domain'],
|
||||
'aliases' => $input['aliases'] ?? [],
|
||||
'path' => '/home/'.$server->getSshUser().'/'.$input['domain'],
|
||||
'user' => $user,
|
||||
'path' => '/home/'.$user.'/'.$input['domain'],
|
||||
'status' => SiteStatus::INSTALLING,
|
||||
]);
|
||||
|
||||
@ -108,6 +110,13 @@ public static function rules(Server $server, array $input): array
|
||||
'aliases.*' => [
|
||||
new DomainRule,
|
||||
],
|
||||
'user' => [
|
||||
'regex:/^[a-z_][a-z0-9_-]*[a-z0-9]$/',
|
||||
'min:3',
|
||||
'max:32',
|
||||
'unique:sites,user',
|
||||
Rule::notIn($server->getSshUsers()),
|
||||
],
|
||||
];
|
||||
|
||||
return array_merge($rules, self::typeRules($server, $input));
|
||||
|
@ -3,6 +3,7 @@
|
||||
namespace App\Actions\Site;
|
||||
|
||||
use App\Models\Site;
|
||||
use App\SSH\Services\PHP\PHP;
|
||||
use App\SSH\Services\Webserver\Webserver;
|
||||
|
||||
class DeleteSite
|
||||
@ -12,6 +13,16 @@ public function delete(Site $site): void
|
||||
/** @var Webserver $webserverHandler */
|
||||
$webserverHandler = $site->server->webserver()->handler();
|
||||
$webserverHandler->deleteSite($site);
|
||||
|
||||
if ($site->isIsolated()) {
|
||||
/** @var PHP $php */
|
||||
$php = $site->server->php()->handler();
|
||||
$php->removeFpmPool($site->user, $site->php_version, $site->id);
|
||||
|
||||
$os = $site->server->os();
|
||||
$os->deleteIsolatedUser($site->user);
|
||||
}
|
||||
|
||||
$site->delete();
|
||||
}
|
||||
}
|
||||
|
@ -48,7 +48,8 @@ public function run(Site $site): Deployment
|
||||
path: $site->path,
|
||||
script: $site->deploymentScript->content,
|
||||
serverLog: $log,
|
||||
variables: $site->environmentVariables($deployment)
|
||||
user: $site->user,
|
||||
variables: $site->environmentVariables($deployment),
|
||||
);
|
||||
$deployment->status = DeploymentStatus::FINISHED;
|
||||
$deployment->save();
|
||||
|
@ -43,7 +43,6 @@ public function init(Server $server, ?string $asUser = null): self
|
||||
$this->server = $server->refresh();
|
||||
$this->user = $server->getSshUser();
|
||||
if ($asUser && $asUser != $server->getSshUser()) {
|
||||
$this->user = $asUser;
|
||||
$this->asUser = $asUser;
|
||||
}
|
||||
$this->privateKey = PublicKeyLoader::loadPrivateKey(
|
||||
@ -146,6 +145,10 @@ public function exec(string $command, string $log = '', ?int $siteId = null, ?bo
|
||||
return $output;
|
||||
}
|
||||
} catch (Throwable $e) {
|
||||
Log::error('Error executing command', [
|
||||
'msg' => $e->getMessage(),
|
||||
'log' => $this->log,
|
||||
]);
|
||||
throw new SSHCommandError(
|
||||
message: $e->getMessage(),
|
||||
log: $this->log
|
||||
|
@ -51,7 +51,7 @@ public function create(Request $request, Project $project, Server $server): Cron
|
||||
|
||||
$this->validateRoute($project, $server);
|
||||
|
||||
$this->validate($request, CreateCronJob::rules($request->all()));
|
||||
$this->validate($request, CreateCronJob::rules($request->all(), $server));
|
||||
|
||||
$cronJob = app(CreateCronJob::class)->create($server, $request->all());
|
||||
|
||||
|
@ -26,6 +26,7 @@ public function toArray(Request $request): array
|
||||
'branch' => $this->branch,
|
||||
'status' => $this->status,
|
||||
'port' => $this->port,
|
||||
'user' => $this->user,
|
||||
'progress' => $this->progress,
|
||||
'created_at' => $this->created_at,
|
||||
'updated_at' => $this->updated_at,
|
||||
|
@ -267,6 +267,15 @@ public function getSshUser(): string
|
||||
return config('core.ssh_user');
|
||||
}
|
||||
|
||||
public function getSshUsers(): array
|
||||
{
|
||||
$users = ['root', $this->getSshUser()];
|
||||
$isolatedSites = $this->sites()->pluck('user')->toArray();
|
||||
$users = array_merge($users, $isolatedSites);
|
||||
|
||||
return array_unique($users);
|
||||
}
|
||||
|
||||
public function service($type, $version = null): ?Service
|
||||
{
|
||||
/* @var Service $service */
|
||||
|
@ -7,6 +7,7 @@
|
||||
use App\Exceptions\SourceControlIsNotConnected;
|
||||
use App\Exceptions\SSHError;
|
||||
use App\SiteTypes\SiteType;
|
||||
use App\SSH\Services\PHP\PHP;
|
||||
use App\SSH\Services\Webserver\Webserver;
|
||||
use App\Traits\HasProjectThroughServer;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
@ -33,6 +34,7 @@
|
||||
* @property string $status
|
||||
* @property int $port
|
||||
* @property int $progress
|
||||
* @property string $user
|
||||
* @property Server $server
|
||||
* @property ServerLog[] $logs
|
||||
* @property Deployment[] $deployments
|
||||
@ -68,6 +70,7 @@ class Site extends AbstractModel
|
||||
'status',
|
||||
'port',
|
||||
'progress',
|
||||
'user',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
@ -200,6 +203,14 @@ public function changePHPVersion($version): void
|
||||
/** @var Webserver $handler */
|
||||
$handler = $this->server->webserver()->handler();
|
||||
$handler->changePHPVersion($this, $version);
|
||||
|
||||
if ($this->isIsolated()) {
|
||||
/** @var PHP $php */
|
||||
$php = $this->server->php()->handler();
|
||||
$php->removeFpmPool($this->user, $this->php_version, $this->id);
|
||||
$php->createFpmPool($this->user, $version, $this->id);
|
||||
}
|
||||
|
||||
$this->php_version = $version;
|
||||
$this->save();
|
||||
}
|
||||
@ -307,4 +318,31 @@ public function environmentVariables(?Deployment $deployment = null): array
|
||||
'PHP_PATH' => '/usr/bin/php'.$this->php_version,
|
||||
];
|
||||
}
|
||||
|
||||
public function isolate(): void
|
||||
{
|
||||
if (! $this->isIsolated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->server->os()->createIsolatedUser(
|
||||
$this->user,
|
||||
Str::random(15),
|
||||
$this->id
|
||||
);
|
||||
|
||||
// Generate the FPM pool
|
||||
/** @var PHP $php */
|
||||
$php = $this->php()->handler();
|
||||
$php->createFpmPool(
|
||||
$this->user,
|
||||
$this->php_version,
|
||||
$this->id
|
||||
);
|
||||
}
|
||||
|
||||
public function isIsolated(): bool
|
||||
{
|
||||
return $this->user != $this->server->getSshUser();
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ class Composer
|
||||
|
||||
public function installDependencies(Site $site): void
|
||||
{
|
||||
$site->server->ssh()->exec(
|
||||
$site->server->ssh($site->user)->exec(
|
||||
$this->getScript('composer-install.sh', [
|
||||
'path' => $site->path,
|
||||
'php_version' => $site->php_version,
|
||||
|
@ -11,7 +11,7 @@ class Git
|
||||
|
||||
public function clone(Site $site): void
|
||||
{
|
||||
$site->server->ssh()->exec(
|
||||
$site->server->ssh($site->user)->exec(
|
||||
$this->getScript('clone.sh', [
|
||||
'host' => str($site->getFullRepositoryUrl())->after('@')->before('-'),
|
||||
'repo' => $site->getFullRepositoryUrl(),
|
||||
@ -26,7 +26,7 @@ public function clone(Site $site): void
|
||||
|
||||
public function checkout(Site $site): void
|
||||
{
|
||||
$site->server->ssh()->exec(
|
||||
$site->server->ssh($site->user)->exec(
|
||||
$this->getScript('checkout.sh', [
|
||||
'path' => $site->path,
|
||||
'branch' => $site->branch,
|
||||
|
@ -2,6 +2,8 @@ echo "Host __host__-__key__
|
||||
Hostname __host__
|
||||
IdentityFile=~/.ssh/__key__" >> ~/.ssh/config
|
||||
|
||||
chmod 600 ~/.ssh/config
|
||||
|
||||
ssh-keyscan -H __host__ >> ~/.ssh/known_hosts
|
||||
|
||||
rm -rf __path__
|
||||
|
@ -5,6 +5,7 @@
|
||||
use App\Exceptions\SSHUploadFailed;
|
||||
use App\Models\Server;
|
||||
use App\Models\ServerLog;
|
||||
use App\Models\Site;
|
||||
use App\SSH\HasScripts;
|
||||
use Illuminate\Filesystem\FilesystemAdapter;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
@ -58,6 +59,30 @@ public function createUser(string $user, string $password, string $key): void
|
||||
);
|
||||
}
|
||||
|
||||
public function createIsolatedUser(string $user, string $password, int $site_id): void
|
||||
{
|
||||
$this->server->ssh()->exec(
|
||||
$this->getScript('create-isolated-user.sh', [
|
||||
'user' => $user,
|
||||
'server_user' => $this->server->getSshUser(),
|
||||
'password' => $password,
|
||||
]),
|
||||
'create-isolated-user',
|
||||
$site_id
|
||||
);
|
||||
}
|
||||
|
||||
public function deleteIsolatedUser(string $user): void
|
||||
{
|
||||
$this->server->ssh()->exec(
|
||||
$this->getScript('delete-isolated-user.sh', [
|
||||
'user' => $user,
|
||||
'server_user' => $this->server->getSshUser(),
|
||||
]),
|
||||
'delete-isolated-user'
|
||||
);
|
||||
}
|
||||
|
||||
public function getPublicKey(string $user): string
|
||||
{
|
||||
return $this->server->ssh()->exec(
|
||||
@ -88,19 +113,20 @@ public function deleteSSHKey(string $key): void
|
||||
);
|
||||
}
|
||||
|
||||
public function generateSSHKey(string $name): void
|
||||
public function generateSSHKey(string $name, ?Site $site = null): void
|
||||
{
|
||||
$this->server->ssh()->exec(
|
||||
$site->server->ssh($site->user)->exec(
|
||||
$this->getScript('generate-ssh-key.sh', [
|
||||
'name' => $name,
|
||||
]),
|
||||
'generate-ssh-key'
|
||||
'generate-ssh-key',
|
||||
$site?->id
|
||||
);
|
||||
}
|
||||
|
||||
public function readSSHKey(string $name): string
|
||||
public function readSSHKey(string $name, ?Site $site = null): string
|
||||
{
|
||||
return $this->server->ssh()->exec(
|
||||
return $site->server->ssh($site->user)->exec(
|
||||
$this->getScript('read-ssh-key.sh', [
|
||||
'name' => $name,
|
||||
]),
|
||||
|
17
app/SSH/OS/scripts/create-isolated-user.sh
Normal file
17
app/SSH/OS/scripts/create-isolated-user.sh
Normal file
@ -0,0 +1,17 @@
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
if ! sudo useradd -p $(openssl passwd -1 __password__) __user__; then
|
||||
echo 'VITO_SSH_ERROR' && exit 1
|
||||
fi
|
||||
|
||||
sudo mkdir /home/__user__
|
||||
sudo mkdir /home/__user__/.logs
|
||||
sudo mkdir /home/__user__/tmp
|
||||
sudo mkdir /home/__user__/bin
|
||||
sudo mkdir /home/__user__/.ssh
|
||||
echo 'export PATH="/home/__user__/bin:$PATH"' | sudo tee -a /home/__user__/.bashrc
|
||||
sudo usermod -a -G __user__ __server_user__
|
||||
sudo chown -R __user__:__user__ /home/__user__
|
||||
sudo chmod -R 755 /home/__user__
|
||||
sudo chmod -R 700 /home/__user__/.ssh
|
||||
sudo chsh -s /bin/bash __user__
|
||||
echo "Created user __user__."
|
3
app/SSH/OS/scripts/delete-isolated-user.sh
Normal file
3
app/SSH/OS/scripts/delete-isolated-user.sh
Normal file
@ -0,0 +1,3 @@
|
||||
sudo gpasswd -d __server_user__ __user__
|
||||
sudo userdel -r "__user__"
|
||||
echo "User __user__ has been deleted."
|
@ -11,7 +11,7 @@ class PHPMyAdmin
|
||||
|
||||
public function install(Site $site): void
|
||||
{
|
||||
$site->server->ssh()->exec(
|
||||
$site->server->ssh($site->user)->exec(
|
||||
$this->getScript('install.sh', [
|
||||
'version' => $site->type_data['version'],
|
||||
'path' => $site->path,
|
||||
|
@ -1,6 +1,10 @@
|
||||
sudo rm -rf phpmyadmin
|
||||
if ! rm -rf phpmyadmin; then
|
||||
echo 'VITO_SSH_ERROR' && exit 1
|
||||
fi
|
||||
|
||||
sudo rm -rf __path__
|
||||
if ! rm -rf __path__; then
|
||||
echo 'VITO_SSH_ERROR' && exit 1
|
||||
fi
|
||||
|
||||
if ! wget https://files.phpmyadmin.net/phpMyAdmin/__version__/phpMyAdmin-__version__-all-languages.zip; then
|
||||
echo 'VITO_SSH_ERROR' && exit 1
|
||||
|
@ -110,4 +110,32 @@ public function getPHPIni(string $type): string
|
||||
sprintf('/etc/php/%s/%s/php.ini', $this->service->version, $type)
|
||||
);
|
||||
}
|
||||
|
||||
public function createFpmPool(string $user, string $version, $site_id): void
|
||||
{
|
||||
$this->service->server->ssh()->exec(
|
||||
$this->getScript('create-fpm-pool.sh', [
|
||||
'user' => $user,
|
||||
'version' => $version,
|
||||
'config' => $this->getScript('fpm-pool.conf', [
|
||||
'user' => $user,
|
||||
'version' => $version,
|
||||
]),
|
||||
]),
|
||||
"create-{$version}fpm-pool-{$user}",
|
||||
$site_id
|
||||
);
|
||||
}
|
||||
|
||||
public function removeFpmPool(string $user, string $version, $site_id): void
|
||||
{
|
||||
$this->service->server->ssh()->exec(
|
||||
$this->getScript('remove-fpm-pool.sh', [
|
||||
'user' => $user,
|
||||
'version' => $version,
|
||||
]),
|
||||
"remove-{$version}fpm-pool-{$user}",
|
||||
$site_id
|
||||
);
|
||||
}
|
||||
}
|
||||
|
2
app/SSH/Services/PHP/scripts/create-fpm-pool.sh
Normal file
2
app/SSH/Services/PHP/scripts/create-fpm-pool.sh
Normal file
@ -0,0 +1,2 @@
|
||||
echo '__config__' | sudo tee /etc/php/__version__/fpm/pool.d/__user__.conf
|
||||
sudo service php__version__-fpm restart
|
22
app/SSH/Services/PHP/scripts/fpm-pool.conf
Normal file
22
app/SSH/Services/PHP/scripts/fpm-pool.conf
Normal file
@ -0,0 +1,22 @@
|
||||
[__user__]
|
||||
user = __user__
|
||||
group = __user__
|
||||
|
||||
listen = /run/php/php__version__-fpm-__user__.sock
|
||||
listen.owner = vito
|
||||
listen.group = vito
|
||||
listen.mode = 0660
|
||||
|
||||
pm = dynamic
|
||||
pm.max_children = 5
|
||||
pm.start_servers = 2
|
||||
pm.min_spare_servers = 1
|
||||
pm.max_spare_servers = 3
|
||||
pm.max_requests = 500
|
||||
|
||||
php_admin_value[open_basedir] = /home/__user__/:/tmp/
|
||||
php_admin_value[upload_tmp_dir] = /home/__user__/tmp
|
||||
php_admin_value[session.save_path] = /home/__user__/tmp
|
||||
php_admin_value[display_errors] = off
|
||||
php_admin_value[log_errors] = on
|
||||
php_admin_value[error_log] = /home/__user__/.logs/php_errors.log
|
2
app/SSH/Services/PHP/scripts/remove-fpm-pool.sh
Normal file
2
app/SSH/Services/PHP/scripts/remove-fpm-pool.sh
Normal file
@ -0,0 +1,2 @@
|
||||
sudo rm -f /etc/php/__version__/fpm/pool.d/__user__.conf
|
||||
sudo service php__version__-fpm restart
|
@ -53,9 +53,11 @@ public function create(
|
||||
),
|
||||
true
|
||||
);
|
||||
$this->service->server->ssh($user)->exec(
|
||||
$this->service->server->ssh()->exec(
|
||||
$this->getScript('supervisor/create-worker.sh', [
|
||||
'id' => $id,
|
||||
'log_file' => $logFile,
|
||||
'user' => $user,
|
||||
]),
|
||||
'create-worker',
|
||||
$siteId
|
||||
|
@ -1,8 +1,14 @@
|
||||
mkdir -p ~/.logs
|
||||
if ! sudo mkdir -p "$(dirname __log_file__)"; then
|
||||
echo 'VITO_SSH_ERROR' && exit 1
|
||||
fi
|
||||
|
||||
mkdir -p ~/.logs/workers
|
||||
if ! sudo touch __log_file__; then
|
||||
echo 'VITO_SSH_ERROR' && exit 1
|
||||
fi
|
||||
|
||||
touch ~/.logs/workers/__id__.log
|
||||
if ! sudo chown __user__:__user__ __log_file__; then
|
||||
echo 'VITO_SSH_ERROR' && exit 1
|
||||
fi
|
||||
|
||||
if ! sudo supervisorctl reread; then
|
||||
echo 'VITO_SSH_ERROR' && exit 1
|
||||
|
@ -52,8 +52,23 @@ public function uninstall(): void
|
||||
$this->service->server->os()->cleanup();
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws SSHError
|
||||
*/
|
||||
public function createVHost(Site $site): void
|
||||
{
|
||||
// We need to get the isolated user first, if the site is isolated
|
||||
// otherwise, use the default ssh user
|
||||
$ssh = $this->service->server->ssh($site->user);
|
||||
|
||||
$ssh->exec(
|
||||
$this->getScript('nginx/create-path.sh', [
|
||||
'path' => $site->path,
|
||||
]),
|
||||
'create-path',
|
||||
$site->id
|
||||
);
|
||||
|
||||
$this->service->server->ssh()->exec(
|
||||
$this->getScript('nginx/create-vhost.sh', [
|
||||
'domain' => $site->domain,
|
||||
@ -189,10 +204,16 @@ protected function generateVhost(Site $site, bool $noSSL = false): string
|
||||
$vhost = Str::replace('__port__', (string) $site->port, $vhost);
|
||||
}
|
||||
|
||||
$php_socket = 'unix:/var/run/php/php-fpm.sock';
|
||||
if ($site->isIsolated()) {
|
||||
$php_socket = "unix:/run/php/php{$site->php_version}-fpm-{$site->user}.sock";
|
||||
}
|
||||
|
||||
$vhost = Str::replace('__domain__', $site->domain, $vhost);
|
||||
$vhost = Str::replace('__aliases__', $site->getAliasesString(), $vhost);
|
||||
$vhost = Str::replace('__path__', $site->path, $vhost);
|
||||
$vhost = Str::replace('__web_directory__', $site->web_directory, $vhost);
|
||||
$vhost = Str::replace('__php_socket__', $php_socket, $vhost);
|
||||
|
||||
if ($ssl) {
|
||||
$vhost = Str::replace('__certificate__', $ssl->getCertificatePath(), $vhost);
|
||||
|
16
app/SSH/Services/Webserver/scripts/nginx/create-path.sh
Normal file
16
app/SSH/Services/Webserver/scripts/nginx/create-path.sh
Normal file
@ -0,0 +1,16 @@
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
if ! rm -rf __path__; then
|
||||
echo 'VITO_SSH_ERROR'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! mkdir __path__; then
|
||||
echo 'VITO_SSH_ERROR'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! chmod -R 755 __path__; then
|
||||
echo 'VITO_SSH_ERROR'
|
||||
exit 1
|
||||
fi
|
@ -1,15 +1,3 @@
|
||||
if ! rm -rf __path__; then
|
||||
echo 'VITO_SSH_ERROR' && exit 1
|
||||
fi
|
||||
|
||||
if ! mkdir __path__; then
|
||||
echo 'VITO_SSH_ERROR' && exit 1
|
||||
fi
|
||||
|
||||
if ! sudo chown -R 755 __path__; then
|
||||
echo 'VITO_SSH_ERROR' && exit 1
|
||||
fi
|
||||
|
||||
if ! echo '' | sudo tee /etc/nginx/conf.d/__domain___redirects; then
|
||||
echo 'VITO_SSH_ERROR' && exit 1
|
||||
fi
|
||||
|
@ -24,7 +24,7 @@ server {
|
||||
error_page 404 /index.php;
|
||||
|
||||
location ~ \.php$ {
|
||||
fastcgi_pass unix:/var/run/php/php__php_version__-fpm.sock;
|
||||
fastcgi_pass __php_socket__;
|
||||
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
|
||||
include fastcgi_params;
|
||||
fastcgi_hide_header X-Powered-By;
|
||||
|
@ -20,7 +20,7 @@ server {
|
||||
error_page 404 /index.php;
|
||||
|
||||
location ~ \.php$ {
|
||||
fastcgi_pass unix:/var/run/php/php__php_version__-fpm.sock;
|
||||
fastcgi_pass __php_socket__;
|
||||
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
|
||||
include fastcgi_params;
|
||||
fastcgi_hide_header X-Powered-By;
|
||||
|
@ -11,10 +11,12 @@ class Wordpress
|
||||
|
||||
public function install(Site $site): void
|
||||
{
|
||||
$site->server->ssh()->exec(
|
||||
$site->server->ssh($site->user)->exec(
|
||||
$this->getScript('install.sh', [
|
||||
'path' => $site->path,
|
||||
'domain' => $site->domain,
|
||||
'is_isolated' => $site->isIsolated(),
|
||||
'isolated_username' => $site->user,
|
||||
'db_name' => $site->type_data['database'],
|
||||
'db_user' => $site->type_data['database_user'],
|
||||
'db_pass' => $site->type_data['database_password'],
|
||||
@ -25,7 +27,8 @@ public function install(Site $site): void
|
||||
'email' => $site->type_data['email'],
|
||||
'title' => $site->type_data['title'],
|
||||
]),
|
||||
'install-wordpress'
|
||||
'install-wordpress',
|
||||
$site->id
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -6,9 +6,15 @@ if ! chmod +x wp-cli.phar; then
|
||||
echo 'VITO_SSH_ERROR' && exit 1
|
||||
fi
|
||||
|
||||
if ! sudo mv wp-cli.phar /usr/local/bin/wp; then
|
||||
if [ "__is_isolated__" == "true" ]; then
|
||||
if ! mv wp-cli.phar /home/__isolated_username__/bin/wp; then
|
||||
echo 'VITO_SSH_ERROR' && exit 1
|
||||
fi
|
||||
else
|
||||
if ! mv wp-cli.phar /usr/local/bin/wp; then
|
||||
echo 'VITO_SSH_ERROR' && exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
rm -rf __path__
|
||||
|
||||
@ -16,12 +22,20 @@ if ! wp --path=__path__ core download; then
|
||||
echo 'VITO_SSH_ERROR' && exit 1
|
||||
fi
|
||||
|
||||
if ! wp --path=__path__ core config --dbname='__db_name__' --dbuser='__db_user__' --dbpass='__db_pass__' --dbhost='__db_host__' --dbprefix='__db_prefix__'; then
|
||||
if ! wp --path=__path__ core config \
|
||||
--dbname="__db_name__" \
|
||||
--dbuser="__db_user__" \
|
||||
--dbpass="__db_pass__" \
|
||||
--dbhost="__db_host__" \
|
||||
--dbprefix="__db_prefix__"; then
|
||||
echo 'VITO_SSH_ERROR' && exit 1
|
||||
fi
|
||||
|
||||
if ! wp --path=__path__ core install --url='http://__domain__' --title="__title__" --admin_user='__username__' --admin_password="__password__" --admin_email='__email__'; then
|
||||
if ! wp --path=__path__ core install \
|
||||
--url="http://__domain__" \
|
||||
--title="__title__" \
|
||||
--admin_user="__username__" \
|
||||
--admin_password="__password__" \
|
||||
--admin_email="__email__"; then
|
||||
echo 'VITO_SSH_ERROR' && exit 1
|
||||
fi
|
||||
|
||||
echo "Wordpress installed!"
|
||||
|
@ -26,8 +26,8 @@ protected function progress(int $percentage): void
|
||||
protected function deployKey(): void
|
||||
{
|
||||
$os = $this->site->server->os();
|
||||
$os->generateSSHKey($this->site->getSshKeyName());
|
||||
$this->site->ssh_key = $os->readSSHKey($this->site->getSshKeyName());
|
||||
$os->generateSSHKey($this->site->getSshKeyName(), $this->site);
|
||||
$this->site->ssh_key = $os->readSSHKey($this->site->getSshKeyName(), $this->site);
|
||||
$this->site->save();
|
||||
$this->site->sourceControl?->provider()?->deployKey(
|
||||
$this->site->domain.'-key-'.$this->site->id,
|
||||
|
@ -43,6 +43,8 @@ public function data(array $input): array
|
||||
|
||||
public function install(): void
|
||||
{
|
||||
$this->site->isolate();
|
||||
|
||||
/** @var Webserver $webserver */
|
||||
$webserver = $this->site->server->webserver()->handler();
|
||||
$webserver->createVHost($this->site);
|
||||
|
@ -43,6 +43,8 @@ public function data(array $input): array
|
||||
|
||||
public function install(): void
|
||||
{
|
||||
$this->site->isolate();
|
||||
|
||||
/** @var Webserver $webserver */
|
||||
$webserver = $this->site->server->webserver()->handler();
|
||||
$webserver->createVHost($this->site);
|
||||
|
@ -76,6 +76,8 @@ public function data(array $input): array
|
||||
*/
|
||||
public function install(): void
|
||||
{
|
||||
$this->site->isolate();
|
||||
|
||||
/** @var Webserver $webserver */
|
||||
$webserver = $this->site->server->webserver()->handler();
|
||||
$webserver->createVHost($this->site);
|
||||
|
@ -84,6 +84,8 @@ public function data(array $input): array
|
||||
|
||||
public function install(): void
|
||||
{
|
||||
$this->site->isolate();
|
||||
|
||||
/** @var Webserver $webserver */
|
||||
$webserver = $this->site->server->webserver()->handler();
|
||||
$webserver->createVHost($this->site);
|
||||
|
@ -37,7 +37,6 @@ public function init(Server $server, ?string $asUser = null): self
|
||||
$this->server = $server->refresh();
|
||||
$this->user = $server->getSshUser();
|
||||
if ($asUser && $asUser != $server->getSshUser()) {
|
||||
$this->user = $asUser;
|
||||
$this->asUser = $asUser;
|
||||
}
|
||||
|
||||
|
@ -52,16 +52,14 @@ protected function getHeaderActions(): array
|
||||
->rules(fn (Get $get) => ExecuteScript::rules($get())['user'])
|
||||
->native(false)
|
||||
->options(function (Get $get) {
|
||||
$options = [
|
||||
'root' => 'root',
|
||||
];
|
||||
$users = ['root'];
|
||||
|
||||
$server = Server::query()->find($get('server'));
|
||||
if ($server) {
|
||||
$options[$server->ssh_user] = $server->ssh_user;
|
||||
$users = $server->getSshUsers();
|
||||
}
|
||||
|
||||
return $options;
|
||||
return array_combine($users, $users);
|
||||
}),
|
||||
];
|
||||
|
||||
|
@ -33,6 +33,8 @@ public function getWidgets(): array
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
$users = $this->server->getSshUsers();
|
||||
|
||||
return [
|
||||
Action::make('read-the-docs')
|
||||
->label('Read the Docs')
|
||||
@ -46,25 +48,22 @@ protected function getHeaderActions(): array
|
||||
->modalWidth(MaxWidth::ExtraLarge)
|
||||
->form([
|
||||
TextInput::make('command')
|
||||
->rules(fn (callable $get) => CreateCronJob::rules($get())['command'])
|
||||
->rules(fn (callable $get) => CreateCronJob::rules($get(), $this->server)['command'])
|
||||
->helperText(fn () => view('components.link', [
|
||||
'href' => 'https://vitodeploy.com/servers/cronjobs',
|
||||
'external' => true,
|
||||
'text' => 'How the command should look like?',
|
||||
])),
|
||||
Select::make('user')
|
||||
->rules(fn (callable $get) => CreateCronJob::rules($get())['user'])
|
||||
->options([
|
||||
'vito' => $this->server->ssh_user,
|
||||
'root' => 'root',
|
||||
]),
|
||||
->rules(fn (callable $get) => CreateCronJob::rules($get(), $this->server)['user'])
|
||||
->options(array_combine($users, $users)),
|
||||
Select::make('frequency')
|
||||
->options(config('core.cronjob_intervals'))
|
||||
->reactive()
|
||||
->rules(fn (callable $get) => CreateCronJob::rules($get())['frequency']),
|
||||
->rules(fn (callable $get) => CreateCronJob::rules($get(), $this->server)['frequency']),
|
||||
TextInput::make('custom')
|
||||
->label('Custom Frequency (Cron)')
|
||||
->rules(fn (callable $get) => CreateCronJob::rules($get())['custom'])
|
||||
->rules(fn (callable $get) => CreateCronJob::rules($get(), $this->server)['custom'])
|
||||
->visible(fn (callable $get) => $get('frequency') === 'custom')
|
||||
->placeholder('0 * * * *'),
|
||||
])
|
||||
|
@ -133,6 +133,13 @@ protected function getHeaderActions(): array
|
||||
->rules(fn (Get $get) => CreateSite::rules($this->server, $get())['version']),
|
||||
// WordPress
|
||||
$this->wordpressFields(),
|
||||
TextInput::make('user')
|
||||
->label('Username')
|
||||
->hintIcon('heroicon-o-information-circle')
|
||||
->hintIconTooltip(
|
||||
'Optional. If provided, a new user will be created and the site will be owned by this user.'
|
||||
)
|
||||
->rules(fn (Get $get) => CreateSite::rules($this->server, $get())['user']),
|
||||
])
|
||||
->action(function (array $data) {
|
||||
$this->authorize('create', [Site::class, $this->server]);
|
||||
|
@ -47,17 +47,17 @@ protected function getHeaderActions(): array
|
||||
->label('New Queue')
|
||||
->form([
|
||||
TextInput::make('command')
|
||||
->rules(CreateQueue::rules($this->server)['command'])
|
||||
->rules(CreateQueue::rules($this->site)['command'])
|
||||
->helperText('Example: php /home/vito/your-site/artisan queue:work'),
|
||||
Select::make('user')
|
||||
->rules(fn (callable $get) => CreateQueue::rules($this->server)['user'])
|
||||
->rules(fn (callable $get) => CreateQueue::rules($this->site)['user'])
|
||||
->options([
|
||||
'vito' => $this->server->ssh_user,
|
||||
'root' => 'root',
|
||||
$this->site->user => $this->site->user,
|
||||
]),
|
||||
TextInput::make('numprocs')
|
||||
->default(1)
|
||||
->rules(CreateQueue::rules($this->server)['numprocs'])
|
||||
->rules(CreateQueue::rules($this->site)['numprocs'])
|
||||
->helperText('Number of processes'),
|
||||
Grid::make()
|
||||
->schema([
|
||||
|
@ -50,6 +50,9 @@ public function infolist(Infolist $infolist): Infolist
|
||||
->inlineLabel()
|
||||
->hintIcon('heroicon-o-information-circle')
|
||||
->hintIconTooltip('Site unique identifier to use in the API'),
|
||||
TextEntry::make('user')
|
||||
->label('Site User')
|
||||
->inlineLabel(),
|
||||
TextEntry::make('created_at')
|
||||
->label('Created At')
|
||||
->formatStateUsing(fn ($record) => $record->created_at_by_timezone)
|
||||
|
@ -21,6 +21,7 @@ public function definition(): array
|
||||
'progress' => '100',
|
||||
'php_version' => '8.2',
|
||||
'branch' => 'main',
|
||||
'user' => 'vito',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
28
database/migrations/2025_01_12_173141_add_user_to_sites.php
Normal file
28
database/migrations/2025_01_12_173141_add_user_to_sites.php
Normal file
@ -0,0 +1,28 @@
|
||||
<?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('sites', function (Blueprint $table) {
|
||||
$table->string('user')->default(config('core.ssh_user'));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('sites', function (Blueprint $table) {
|
||||
$table->dropColumn('user');
|
||||
});
|
||||
}
|
||||
};
|
@ -43,6 +43,8 @@ public function test_create_site(array $inputs): void
|
||||
->assertJsonFragment([
|
||||
'domain' => $inputs['domain'],
|
||||
'aliases' => $inputs['aliases'] ?? [],
|
||||
'user' => $inputs['user'] ?? $this->server->getSshUser(),
|
||||
'path' => '/home/'.($inputs['user'] ?? $this->server->getSshUser()).'/'.$inputs['domain'],
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,8 @@
|
||||
use App\Enums\CronjobStatus;
|
||||
use App\Facades\SSH;
|
||||
use App\Models\CronJob;
|
||||
use App\Models\Server;
|
||||
use App\Models\Site;
|
||||
use App\Web\Pages\Servers\CronJobs\Index;
|
||||
use App\Web\Pages\Servers\CronJobs\Widgets\CronJobsList;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
@ -83,6 +85,79 @@ public function test_create_cronjob()
|
||||
SSH::assertExecutedContains('sudo -u vito crontab -l');
|
||||
}
|
||||
|
||||
public function test_create_cronjob_for_isolated_user(): void
|
||||
{
|
||||
SSH::fake();
|
||||
$this->actingAs($this->user);
|
||||
|
||||
$this->site->user = 'example';
|
||||
$this->site->save();
|
||||
|
||||
Livewire::test(Index::class, [
|
||||
'server' => $this->server,
|
||||
])
|
||||
->callAction('create', [
|
||||
'command' => 'ls -la',
|
||||
'user' => 'example',
|
||||
'frequency' => '* * * * *',
|
||||
])
|
||||
->assertSuccessful();
|
||||
|
||||
$this->assertDatabaseHas('cron_jobs', [
|
||||
'server_id' => $this->server->id,
|
||||
'user' => 'example',
|
||||
]);
|
||||
|
||||
SSH::assertExecutedContains("echo '* * * * * ls -la' | sudo -u example crontab -");
|
||||
SSH::assertExecutedContains('sudo -u example crontab -l');
|
||||
}
|
||||
|
||||
public function test_cannot_create_cronjob_for_non_existing_user(): void
|
||||
{
|
||||
SSH::fake();
|
||||
$this->actingAs($this->user);
|
||||
|
||||
Livewire::test(Index::class, [
|
||||
'server' => $this->server,
|
||||
])
|
||||
->callAction('create', [
|
||||
'command' => 'ls -la',
|
||||
'user' => 'example',
|
||||
'frequency' => '* * * * *',
|
||||
])
|
||||
->assertHasActionErrors();
|
||||
|
||||
$this->assertDatabaseMissing('cron_jobs', [
|
||||
'server_id' => $this->server->id,
|
||||
'user' => 'example',
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_cannot_create_cronjob_for_user_on_another_server(): void
|
||||
{
|
||||
SSH::fake();
|
||||
$this->actingAs($this->user);
|
||||
|
||||
Site::factory()->create([
|
||||
'server_id' => Server::factory()->create(['user_id' => 1])->id,
|
||||
'user' => 'example',
|
||||
]);
|
||||
|
||||
Livewire::test(Index::class, [
|
||||
'server' => $this->server,
|
||||
])
|
||||
->callAction('create', [
|
||||
'command' => 'ls -la',
|
||||
'user' => 'example',
|
||||
'frequency' => '* * * * *',
|
||||
])
|
||||
->assertHasActionErrors();
|
||||
|
||||
$this->assertDatabaseMissing('cron_jobs', [
|
||||
'user' => 'example',
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_create_custom_cronjob()
|
||||
{
|
||||
SSH::fake();
|
||||
|
@ -5,6 +5,7 @@
|
||||
use App\Enums\QueueStatus;
|
||||
use App\Facades\SSH;
|
||||
use App\Models\Queue;
|
||||
use App\Models\Site;
|
||||
use App\Web\Pages\Servers\Sites\Pages\Queues\Index;
|
||||
use App\Web\Pages\Servers\Sites\Pages\Queues\Widgets\QueuesList;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
@ -88,6 +89,97 @@ public function test_create_queue()
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_create_queue_as_isolated_user(): void
|
||||
{
|
||||
SSH::fake();
|
||||
|
||||
$this->actingAs($this->user);
|
||||
|
||||
$this->site->user = 'example';
|
||||
$this->site->save();
|
||||
|
||||
Livewire::test(Index::class, [
|
||||
'server' => $this->server,
|
||||
'site' => $this->site,
|
||||
])
|
||||
->callAction('create', [
|
||||
'command' => 'php artisan queue:work',
|
||||
'user' => 'example',
|
||||
'auto_start' => 1,
|
||||
'auto_restart' => 1,
|
||||
'numprocs' => 1,
|
||||
])
|
||||
->assertSuccessful();
|
||||
|
||||
$this->assertDatabaseHas('queues', [
|
||||
'server_id' => $this->server->id,
|
||||
'site_id' => $this->site->id,
|
||||
'command' => 'php artisan queue:work',
|
||||
'user' => 'example',
|
||||
'auto_start' => 1,
|
||||
'auto_restart' => 1,
|
||||
'numprocs' => 1,
|
||||
'status' => QueueStatus::RUNNING,
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_cannot_create_queue_as_invalid_user(): void
|
||||
{
|
||||
SSH::fake();
|
||||
|
||||
$this->actingAs($this->user);
|
||||
|
||||
Livewire::test(Index::class, [
|
||||
'server' => $this->server,
|
||||
'site' => $this->site,
|
||||
])
|
||||
->callAction('create', [
|
||||
'command' => 'php artisan queue:work',
|
||||
'user' => 'example',
|
||||
'auto_start' => 1,
|
||||
'auto_restart' => 1,
|
||||
'numprocs' => 1,
|
||||
])
|
||||
->assertHasActionErrors();
|
||||
|
||||
$this->assertDatabaseMissing('queues', [
|
||||
'server_id' => $this->server->id,
|
||||
'site_id' => $this->site->id,
|
||||
'user' => 'example',
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_cannot_create_queue_on_another_sites_user(): void
|
||||
{
|
||||
SSH::fake();
|
||||
|
||||
$this->actingAs($this->user);
|
||||
|
||||
Site::factory()->create([
|
||||
'server_id' => $this->server->id,
|
||||
'user' => 'example',
|
||||
]);
|
||||
|
||||
Livewire::test(Index::class, [
|
||||
'server' => $this->server,
|
||||
'site' => $this->site,
|
||||
])
|
||||
->callAction('create', [
|
||||
'command' => 'php artisan queue:work',
|
||||
'user' => 'example',
|
||||
'auto_start' => 1,
|
||||
'auto_restart' => 1,
|
||||
'numprocs' => 1,
|
||||
])
|
||||
->assertHasActionErrors();
|
||||
|
||||
$this->assertDatabaseMissing('queues', [
|
||||
'server_id' => $this->server->id,
|
||||
'site_id' => $this->site->id,
|
||||
'user' => 'example',
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_start_queue(): void
|
||||
{
|
||||
SSH::fake();
|
||||
|
@ -6,6 +6,8 @@
|
||||
use App\Facades\SSH;
|
||||
use App\Models\Script;
|
||||
use App\Models\ScriptExecution;
|
||||
use App\Models\Server;
|
||||
use App\Models\Site;
|
||||
use App\Web\Pages\Scripts\Executions;
|
||||
use App\Web\Pages\Scripts\Index;
|
||||
use App\Web\Pages\Scripts\Widgets\ScriptExecutionsList;
|
||||
@ -118,6 +120,7 @@ public function test_execute_script_and_view_log(): void
|
||||
$this->assertDatabaseHas('script_executions', [
|
||||
'script_id' => $script->id,
|
||||
'status' => ScriptExecutionStatus::COMPLETED,
|
||||
'user' => 'root',
|
||||
]);
|
||||
|
||||
$this->assertDatabaseHas('server_logs', [
|
||||
@ -133,6 +136,88 @@ public function test_execute_script_and_view_log(): void
|
||||
->assertSuccessful();
|
||||
}
|
||||
|
||||
public function test_execute_script_as_isolated_user(): void
|
||||
{
|
||||
SSH::fake('script output');
|
||||
|
||||
$this->actingAs($this->user);
|
||||
|
||||
$script = Script::factory()->create([
|
||||
'user_id' => $this->user->id,
|
||||
]);
|
||||
|
||||
Site::factory()->create([
|
||||
'server_id' => $this->server->id,
|
||||
'user' => 'example',
|
||||
]);
|
||||
|
||||
Livewire::test(Executions::class, [
|
||||
'script' => $script,
|
||||
])
|
||||
->callAction('execute', [
|
||||
'server' => $this->server->id,
|
||||
'user' => 'example',
|
||||
])
|
||||
->assertSuccessful();
|
||||
|
||||
$this->assertDatabaseHas('script_executions', [
|
||||
'script_id' => $script->id,
|
||||
'status' => ScriptExecutionStatus::COMPLETED,
|
||||
'user' => 'example',
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_cannot_execute_script_as_non_existing_user(): void
|
||||
{
|
||||
$this->actingAs($this->user);
|
||||
|
||||
$script = Script::factory()->create([
|
||||
'user_id' => $this->user->id,
|
||||
]);
|
||||
|
||||
Livewire::test(Executions::class, [
|
||||
'script' => $script,
|
||||
])
|
||||
->callAction('execute', [
|
||||
'server' => $this->server->id,
|
||||
'user' => 'example',
|
||||
])
|
||||
->assertHasActionErrors();
|
||||
|
||||
$this->assertDatabaseMissing('script_executions', [
|
||||
'script_id' => $script->id,
|
||||
'user' => 'example',
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_cannot_execute_script_as_user_not_on_server(): void
|
||||
{
|
||||
$this->actingAs($this->user);
|
||||
|
||||
$script = Script::factory()->create([
|
||||
'user_id' => $this->user->id,
|
||||
]);
|
||||
|
||||
Site::factory()->create([
|
||||
'server_id' => Server::factory()->create(['user_id' => 1])->id,
|
||||
'user' => 'example',
|
||||
]);
|
||||
|
||||
Livewire::test(Executions::class, [
|
||||
'script' => $script,
|
||||
])
|
||||
->callAction('execute', [
|
||||
'server' => $this->server->id,
|
||||
'user' => 'example',
|
||||
])
|
||||
->assertHasActionErrors();
|
||||
|
||||
$this->assertDatabaseMissing('script_executions', [
|
||||
'script_id' => $script->id,
|
||||
'user' => 'example',
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_see_executions(): void
|
||||
{
|
||||
$this->actingAs($this->user);
|
||||
|
@ -48,13 +48,31 @@ public function test_create_site(array $inputs): void
|
||||
->assertHasNoActionErrors()
|
||||
->assertSuccessful();
|
||||
|
||||
$expectedUser = empty($inputs['user']) ? $this->server->getSshUser() : $inputs['user'];
|
||||
$this->assertDatabaseHas('sites', [
|
||||
'domain' => $inputs['domain'],
|
||||
'aliases' => json_encode($inputs['aliases'] ?? []),
|
||||
'status' => SiteStatus::READY,
|
||||
'user' => $expectedUser,
|
||||
'path' => '/home/'.$expectedUser.'/'.$inputs['domain'],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider failure_create_data
|
||||
*/
|
||||
public function test_isolated_user_failure(array $inputs): void
|
||||
{
|
||||
SSH::fake();
|
||||
$this->actingAs($this->user);
|
||||
|
||||
Livewire::test(Index::class, [
|
||||
'server' => $this->server,
|
||||
])
|
||||
->callAction('create', $inputs)
|
||||
->assertHasActionErrors();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider create_failure_data
|
||||
*/
|
||||
@ -247,6 +265,62 @@ public function test_see_logs(): void
|
||||
->assertSee('Logs');
|
||||
}
|
||||
|
||||
public static function failure_create_data(): array
|
||||
{
|
||||
return [
|
||||
[
|
||||
[
|
||||
'type' => SiteType::PHP_BLANK,
|
||||
'domain' => 'example.com',
|
||||
'aliases' => ['www.example.com'],
|
||||
'php_version' => '8.2',
|
||||
'web_directory' => 'public',
|
||||
'user' => 'a',
|
||||
],
|
||||
],
|
||||
[
|
||||
[
|
||||
'type' => SiteType::PHP_BLANK,
|
||||
'domain' => 'example.com',
|
||||
'aliases' => ['www.example.com'],
|
||||
'php_version' => '8.2',
|
||||
'web_directory' => 'public',
|
||||
'user' => 'root',
|
||||
],
|
||||
],
|
||||
[
|
||||
[
|
||||
'type' => SiteType::PHP_BLANK,
|
||||
'domain' => 'example.com',
|
||||
'aliases' => ['www.example.com'],
|
||||
'php_version' => '8.2',
|
||||
'web_directory' => 'public',
|
||||
'user' => 'vito',
|
||||
],
|
||||
],
|
||||
[
|
||||
[
|
||||
'type' => SiteType::PHP_BLANK,
|
||||
'domain' => 'example.com',
|
||||
'aliases' => ['www.example.com'],
|
||||
'php_version' => '8.2',
|
||||
'web_directory' => 'public',
|
||||
'user' => '123',
|
||||
],
|
||||
],
|
||||
[
|
||||
[
|
||||
'type' => SiteType::PHP_BLANK,
|
||||
'domain' => 'example.com',
|
||||
'aliases' => ['www.example.com'],
|
||||
'php_version' => '8.2',
|
||||
'web_directory' => 'public',
|
||||
'user' => 'qwertyuiopasdfghjklzxcvbnmqwertyu',
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
public static function create_data(): array
|
||||
{
|
||||
return [
|
||||
@ -262,6 +336,19 @@ public static function create_data(): array
|
||||
'composer' => true,
|
||||
],
|
||||
],
|
||||
[
|
||||
[
|
||||
'type' => SiteType::LARAVEL,
|
||||
'domain' => 'example.com',
|
||||
'aliases' => ['www.example.com', 'www2.example.com'],
|
||||
'php_version' => '8.2',
|
||||
'web_directory' => 'public',
|
||||
'repository' => 'test/test',
|
||||
'branch' => 'main',
|
||||
'composer' => true,
|
||||
'user' => 'example',
|
||||
],
|
||||
],
|
||||
[
|
||||
[
|
||||
'type' => SiteType::WORDPRESS,
|
||||
@ -277,6 +364,22 @@ public static function create_data(): array
|
||||
'database_password' => 'password',
|
||||
],
|
||||
],
|
||||
[
|
||||
[
|
||||
'type' => SiteType::WORDPRESS,
|
||||
'domain' => 'example.com',
|
||||
'aliases' => ['www.example.com'],
|
||||
'php_version' => '8.2',
|
||||
'title' => 'Example',
|
||||
'username' => 'example',
|
||||
'email' => 'email@example.com',
|
||||
'password' => 'password',
|
||||
'database' => 'example',
|
||||
'database_user' => 'example',
|
||||
'database_password' => 'password',
|
||||
'user' => 'example',
|
||||
],
|
||||
],
|
||||
[
|
||||
[
|
||||
'type' => SiteType::PHP_BLANK,
|
||||
@ -286,6 +389,16 @@ public static function create_data(): array
|
||||
'web_directory' => 'public',
|
||||
],
|
||||
],
|
||||
[
|
||||
[
|
||||
'type' => SiteType::PHP_BLANK,
|
||||
'domain' => 'example.com',
|
||||
'aliases' => ['www.example.com'],
|
||||
'php_version' => '8.2',
|
||||
'web_directory' => 'public',
|
||||
'user' => 'example',
|
||||
],
|
||||
],
|
||||
[
|
||||
[
|
||||
'type' => SiteType::PHPMYADMIN,
|
||||
@ -295,6 +408,16 @@ public static function create_data(): array
|
||||
'version' => '5.1.2',
|
||||
],
|
||||
],
|
||||
[
|
||||
[
|
||||
'type' => SiteType::PHPMYADMIN,
|
||||
'domain' => 'example.com',
|
||||
'aliases' => ['www.example.com'],
|
||||
'php_version' => '8.2',
|
||||
'version' => '5.1.2',
|
||||
'user' => 'example',
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user