cPanel * * Cambia SOLO estos valores: */ const WEBHOOK_SECRET = 'jX25kNTa@K1e4;jX25kNTa@K1e4;jX25kNTa@K1e4;'; const ALLOWED_BRANCH = 'master'; const REPO_PATH = '/home/javi/hello-world.ai1.ovh'; const GIT_BIN = '/usr/bin/git'; const LOG_FILE = __DIR__ . '/deploy.log'; /* * Si tu repo NO está en /home/javi/repositories/hello-world, * pon aquí la ruta exacta del repo gestionado por cPanel. */ function respond(int $code, string $message): void { http_response_code($code); header('Content-Type: text/plain; charset=utf-8'); echo $message; exit; } function log_line(string $message): void { $line = '[' . date('Y-m-d H:i:s') . '] ' . $message . PHP_EOL; file_put_contents(LOG_FILE, $line, FILE_APPEND); } function get_header_value(string $name): ?string { $key = 'HTTP_' . strtoupper(str_replace('-', '_', $name)); return $_SERVER[$key] ?? null; } if ($_SERVER['REQUEST_METHOD'] !== 'POST') { respond(405, 'Method Not Allowed'); } $contentType = $_SERVER['CONTENT_TYPE'] ?? ''; if (stripos($contentType, 'application/json') === false) { log_line('ERROR: Content-Type inválido: ' . $contentType); respond(400, 'Invalid Content-Type'); } $payload = file_get_contents('php://input'); if (!$payload) { log_line('ERROR: Payload vacío'); respond(400, 'Empty payload'); } $signatureHeader = get_header_value('X-Gitea-Signature'); if (!$signatureHeader) { log_line('ERROR: Falta header X-Gitea-Signature'); respond(403, 'Missing signature'); } /* * Compatibilidad: * - algunos ejemplos usan solo el hash * - otros usan "sha256=HASH" */ $expected = hash_hmac('sha256', $payload, WEBHOOK_SECRET); $provided = trim($signatureHeader); if (stripos($provided, 'sha256=') === 0) { $provided = substr($provided, 7); } if (!hash_equals($expected, $provided)) { log_line('ERROR: Firma inválida'); respond(403, 'Invalid signature'); } $data = json_decode($payload, true); if (!is_array($data)) { log_line('ERROR: JSON inválido'); respond(400, 'Invalid JSON'); } $event = get_header_value('X-Gitea-Event') ?? ''; if ($event !== 'push') { log_line('INFO: Evento ignorado: ' . $event); respond(200, 'Ignored event'); } $ref = $data['ref'] ?? ''; $expectedRef = 'refs/heads/' . ALLOWED_BRANCH; if ($ref !== $expectedRef) { log_line('INFO: Rama ignorada: ' . $ref); respond(200, 'Ignored branch'); } if (!is_dir(REPO_PATH)) { log_line('ERROR: REPO_PATH no existe: ' . REPO_PATH); respond(500, 'Repository path not found'); } $commands = [ 'cd ' . escapeshellarg(REPO_PATH), GIT_BIN . ' rev-parse --is-inside-work-tree', GIT_BIN . ' fetch origin', GIT_BIN . ' checkout ' . escapeshellarg(ALLOWED_BRANCH), GIT_BIN . ' pull origin ' . escapeshellarg(ALLOWED_BRANCH) . ' 2>&1', ]; $outputAll = []; $returnCode = 0; foreach ($commands as $cmd) { $output = []; $cmdReturn = 0; exec($cmd, $output, $cmdReturn); $outputAll[] = '$ ' . $cmd; $outputAll[] = implode("\n", $output); $outputAll[] = 'exit_code=' . $cmdReturn; if ($cmdReturn !== 0) { $returnCode = $cmdReturn; break; } } $logBlock = "Webhook OK | event=push | ref={$ref}\n" . implode("\n", $outputAll) . "\n---"; log_line($logBlock); if ($returnCode !== 0) { respond(500, 'Deploy failed. Revisa deploy.log'); } respond(200, 'Deploy OK');