From 47654f51fb57080c532503cf43ca2f9af1ee5ec5 Mon Sep 17 00:00:00 2001 From: cawcenter Date: Sun, 14 Dec 2025 21:36:58 -0500 Subject: [PATCH] feat(god-mode): add self-redeploy endpoint via Coolify webhook --- src/pages/api/god/redeploy.ts | 111 ++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 src/pages/api/god/redeploy.ts diff --git a/src/pages/api/god/redeploy.ts b/src/pages/api/god/redeploy.ts new file mode 100644 index 0000000..b9b4649 --- /dev/null +++ b/src/pages/api/god/redeploy.ts @@ -0,0 +1,111 @@ +import type { APIRoute } from 'astro'; + +/** + * 🔱 GOD MODE - Self-Redeploy Endpoint + * + * Triggers a Coolify redeploy via webhook + * Allows God Mode to update itself with latest code from GitHub + */ + +// God Mode Token validation +function validateGodToken(request: Request): boolean { + const token = request.headers.get('X-God-Token') || + request.headers.get('Authorization')?.replace('Bearer ', '') || + new URL(request.url).searchParams.get('token'); + + const godToken = process.env.GOD_MODE_TOKEN || import.meta.env.GOD_MODE_TOKEN; + + if (!godToken) { + console.warn('⚠️ GOD_MODE_TOKEN not set - backdoor is open!'); + return true; + } + + return token === godToken; +} + +export const POST: APIRoute = async ({ request }) => { + if (!validateGodToken(request)) { + return new Response(JSON.stringify({ error: 'Unauthorized - Invalid God Mode Token' }), { + status: 401, + headers: { 'Content-Type': 'application/json' } + }); + } + + try { + const webhookUrl = process.env.COOLIFY_WEBHOOK_URL; + + if (!webhookUrl) { + return new Response(JSON.stringify({ + error: 'COOLIFY_WEBHOOK_URL not configured', + help: 'Add COOLIFY_WEBHOOK_URL to environment variables in Coolify settings' + }), { + status: 400, + headers: { 'Content-Type': 'application/json' } + }); + } + + // Trigger Coolify webhook + const response = await fetch(webhookUrl, { + method: 'GET', // Coolify webhooks use GET + headers: { + 'User-Agent': 'God-Mode-Self-Deploy' + } + }); + + if (response.ok) { + return new Response(JSON.stringify({ + success: true, + message: 'Redeploy triggered successfully', + status: response.status, + timestamp: new Date().toISOString(), + note: 'God Mode will restart in ~3-5 minutes with latest code from GitHub' + }), { + status: 200, + headers: { 'Content-Type': 'application/json' } + }); + } else { + const errorText = await response.text(); + return new Response(JSON.stringify({ + success: false, + error: 'Webhook request failed', + status: response.status, + details: errorText + }), { + status: 500, + headers: { 'Content-Type': 'application/json' } + }); + } + + } catch (error: any) { + return new Response(JSON.stringify({ + error: error.message, + stack: error.stack + }), { + status: 500, + headers: { 'Content-Type': 'application/json' } + }); + } +}; + +export const GET: APIRoute = async ({ request }) => { + if (!validateGodToken(request)) { + return new Response(JSON.stringify({ error: 'Unauthorized' }), { + status: 401, + headers: { 'Content-Type': 'application/json' } + }); + } + + const webhookConfigured = !!process.env.COOLIFY_WEBHOOK_URL; + + return new Response(JSON.stringify({ + endpoint: 'POST /api/god/redeploy', + description: 'Trigger self-redeploy via Coolify webhook', + webhook_configured: webhookConfigured, + webhook_url: webhookConfigured ? 'Configured ✅' : 'Not set ❌', + usage: 'POST request with X-God-Token header', + example: 'curl -X POST -H "X-God-Token: YOUR_TOKEN" https://spark.jumpstartscaling.com/api/god/redeploy' + }), { + status: 200, + headers: { 'Content-Type': 'application/json' } + }); +};