234 lines
7.0 KiB
PHP
234 lines
7.0 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Console\Commands;
|
|
|
|
use Illuminate\Console\Command;
|
|
use Illuminate\Support\Str;
|
|
|
|
class ManageGitProtection extends Command
|
|
{
|
|
protected $signature = 'jabali:git-protection
|
|
{action : enable|disable|status|add-committer|remove-committer|list-committers}
|
|
{--email= : Email address for add/remove committer}';
|
|
|
|
protected $description = 'Manage Git commit protection for Jabali';
|
|
|
|
protected string $authFile;
|
|
protected string $hookFile;
|
|
protected string $deployKeyFile;
|
|
|
|
public function __construct()
|
|
{
|
|
parent::__construct();
|
|
$this->authFile = base_path('.git-authorized-committers');
|
|
$this->hookFile = base_path('.git/hooks/pre-commit');
|
|
$this->deployKeyFile = base_path('.deploy-key');
|
|
}
|
|
|
|
public function handle(): int
|
|
{
|
|
$action = $this->argument('action');
|
|
|
|
return match ($action) {
|
|
'enable' => $this->enableProtection(),
|
|
'disable' => $this->disableProtection(),
|
|
'status' => $this->showStatus(),
|
|
'add-committer' => $this->addCommitter(),
|
|
'remove-committer' => $this->removeCommitter(),
|
|
'list-committers' => $this->listCommitters(),
|
|
default => $this->showHelp(),
|
|
};
|
|
}
|
|
|
|
protected function enableProtection(): int
|
|
{
|
|
// Ensure hook exists and is executable
|
|
if (!file_exists($this->hookFile)) {
|
|
$this->error('Pre-commit hook not found. Please reinstall Jabali.');
|
|
return 1;
|
|
}
|
|
|
|
chmod($this->hookFile, 0755);
|
|
|
|
// Create authorized committers file if not exists
|
|
if (!file_exists($this->authFile)) {
|
|
// Add current git user as first authorized committer
|
|
$email = trim(shell_exec('git config user.email') ?? '');
|
|
if ($email) {
|
|
file_put_contents($this->authFile, $email . "\n");
|
|
} else {
|
|
touch($this->authFile);
|
|
}
|
|
chmod($this->authFile, 0600);
|
|
}
|
|
|
|
// Generate deploy key for automated deployments
|
|
if (!file_exists($this->deployKeyFile)) {
|
|
$key = Str::random(64);
|
|
file_put_contents($this->deployKeyFile, $key);
|
|
chmod($this->deployKeyFile, 0600);
|
|
$this->info("Deploy key generated. Use JABALI_DEPLOY_KEY=$key for automated deployments.");
|
|
}
|
|
|
|
$this->info('Git commit protection ENABLED.');
|
|
$this->line('Only authorized committers can now make commits.');
|
|
$this->line('');
|
|
$this->line('Authorized committers file: ' . $this->authFile);
|
|
|
|
return 0;
|
|
}
|
|
|
|
protected function disableProtection(): int
|
|
{
|
|
if (file_exists($this->authFile)) {
|
|
unlink($this->authFile);
|
|
}
|
|
|
|
$this->info('Git commit protection DISABLED.');
|
|
$this->line('Anyone can now make commits to this repository.');
|
|
|
|
return 0;
|
|
}
|
|
|
|
protected function showStatus(): int
|
|
{
|
|
$isEnabled = file_exists($this->authFile);
|
|
|
|
$this->line('Git Protection Status');
|
|
$this->line('=====================');
|
|
$this->line('');
|
|
|
|
if ($isEnabled) {
|
|
$this->info('Status: ENABLED');
|
|
$this->line('');
|
|
|
|
$committers = $this->getCommitters();
|
|
if (count($committers) > 0) {
|
|
$this->line('Authorized committers:');
|
|
foreach ($committers as $email) {
|
|
$this->line(" - $email");
|
|
}
|
|
} else {
|
|
$this->warn('No authorized committers configured!');
|
|
$this->line('No one will be able to commit.');
|
|
}
|
|
|
|
if (file_exists($this->deployKeyFile)) {
|
|
$this->line('');
|
|
$this->line('Deploy key: Configured');
|
|
}
|
|
} else {
|
|
$this->warn('Status: DISABLED');
|
|
$this->line('Anyone can make commits.');
|
|
}
|
|
|
|
// Show last integrity check status
|
|
$lastCheck = \App\Models\DnsSetting::get('last_integrity_check');
|
|
$lastStatus = \App\Models\DnsSetting::get('last_integrity_status');
|
|
|
|
if ($lastCheck) {
|
|
$this->line('');
|
|
$this->line('Last integrity check: ' . $lastCheck);
|
|
$this->line('Status: ' . ($lastStatus === 'clean' ? 'Clean' : 'Modified files detected'));
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
protected function addCommitter(): int
|
|
{
|
|
$email = $this->option('email');
|
|
|
|
if (!$email) {
|
|
$email = $this->ask('Enter committer email address');
|
|
}
|
|
|
|
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
|
$this->error('Invalid email address.');
|
|
return 1;
|
|
}
|
|
|
|
$committers = $this->getCommitters();
|
|
|
|
if (in_array($email, $committers)) {
|
|
$this->warn("$email is already an authorized committer.");
|
|
return 0;
|
|
}
|
|
|
|
$committers[] = $email;
|
|
file_put_contents($this->authFile, implode("\n", $committers) . "\n");
|
|
chmod($this->authFile, 0600);
|
|
|
|
$this->info("Added $email to authorized committers.");
|
|
|
|
return 0;
|
|
}
|
|
|
|
protected function removeCommitter(): int
|
|
{
|
|
$email = $this->option('email');
|
|
|
|
if (!$email) {
|
|
$email = $this->ask('Enter committer email to remove');
|
|
}
|
|
|
|
$committers = $this->getCommitters();
|
|
$committers = array_filter($committers, fn($e) => $e !== $email);
|
|
|
|
file_put_contents($this->authFile, implode("\n", $committers) . "\n");
|
|
|
|
$this->info("Removed $email from authorized committers.");
|
|
|
|
return 0;
|
|
}
|
|
|
|
protected function listCommitters(): int
|
|
{
|
|
$committers = $this->getCommitters();
|
|
|
|
if (empty($committers)) {
|
|
$this->warn('No authorized committers configured.');
|
|
return 0;
|
|
}
|
|
|
|
$this->info('Authorized committers:');
|
|
foreach ($committers as $email) {
|
|
$this->line(" - $email");
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
protected function getCommitters(): array
|
|
{
|
|
if (!file_exists($this->authFile)) {
|
|
return [];
|
|
}
|
|
|
|
$content = file_get_contents($this->authFile);
|
|
$lines = array_filter(array_map('trim', explode("\n", $content)));
|
|
|
|
return $lines;
|
|
}
|
|
|
|
protected function showHelp(): int
|
|
{
|
|
$this->line('Usage: php artisan jabali:git-protection <action>');
|
|
$this->line('');
|
|
$this->line('Actions:');
|
|
$this->line(' enable Enable commit protection');
|
|
$this->line(' disable Disable commit protection');
|
|
$this->line(' status Show protection status');
|
|
$this->line(' add-committer Add an authorized committer');
|
|
$this->line(' remove-committer Remove an authorized committer');
|
|
$this->line(' list-committers List all authorized committers');
|
|
$this->line('');
|
|
$this->line('Options:');
|
|
$this->line(' --email=<email> Email address for add/remove actions');
|
|
|
|
return 0;
|
|
}
|
|
}
|