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 '); $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 address for add/remove actions'); return 0; } }