From aa4449667d339a0f5378a9f7020df47d23c43172 Mon Sep 17 00:00:00 2001 From: Javier Blanco Date: Thu, 30 Apr 2026 10:24:14 +0700 Subject: [PATCH] deploy.php --- deploy.php | 132 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 deploy.php diff --git a/deploy.php b/deploy.php new file mode 100644 index 0000000..abae49b --- /dev/null +++ b/deploy.php @@ -0,0 +1,132 @@ + 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'); \ No newline at end of file