VPS and dedicated server ordering, managed panels, SSO, billing, and launcher integration — forked from hosting infrastructure with server-focused routes and dashboard. Co-authored-by: Cursor <cursoragent@cursor.com>
53 lines
1.7 KiB
PHP
53 lines
1.7 KiB
PHP
<?php
|
|
|
|
namespace App\Console\Commands;
|
|
|
|
use App\Models\HostingAccount;
|
|
use App\Services\Hosting\Providers\SharedNodeProvider;
|
|
use Illuminate\Console\Command;
|
|
|
|
class HardenHostingAccountIsolationCommand extends Command
|
|
{
|
|
protected $signature = 'hosting:harden-account-isolation {--account= : Limit to one hosting account id} {--dry-run : Show affected accounts without applying changes}';
|
|
|
|
protected $description = 'Apply filesystem isolation permissions to shared hosting accounts.';
|
|
|
|
public function handle(SharedNodeProvider $provider): int
|
|
{
|
|
$accounts = HostingAccount::query()
|
|
->with(['node', 'sites'])
|
|
->where('type', HostingAccount::TYPE_SHARED)
|
|
->when($this->option('account'), fn ($query, $accountId) => $query->whereKey($accountId))
|
|
->orderBy('id')
|
|
->get();
|
|
|
|
if ($accounts->isEmpty()) {
|
|
$this->info('No hosting accounts matched.');
|
|
return self::SUCCESS;
|
|
}
|
|
|
|
foreach ($accounts as $account) {
|
|
$this->line(sprintf('[%d] %s (%s)', $account->id, $account->username, $account->primary_domain ?: 'no-domain'));
|
|
}
|
|
|
|
if ($this->option('dry-run')) {
|
|
$this->warn('Dry run mode: no changes applied.');
|
|
return self::SUCCESS;
|
|
}
|
|
|
|
$failures = 0;
|
|
|
|
foreach ($accounts as $account) {
|
|
try {
|
|
$provider->hardenAccountFilesystem($account);
|
|
$this->info("Hardened {$account->username}");
|
|
} catch (\Throwable $e) {
|
|
$failures++;
|
|
$this->error("Failed {$account->username}: {$e->getMessage()}");
|
|
}
|
|
}
|
|
|
|
return $failures === 0 ? self::SUCCESS : self::FAILURE;
|
|
}
|
|
}
|