feat(god-mode): add self-redeploy endpoint via Coolify webhook

This commit is contained in:
cawcenter
2025-12-14 21:36:58 -05:00
parent 659a968b2d
commit 47654f51fb

View File

@@ -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' }
});
};