feat(god-mode): add self-redeploy endpoint via Coolify webhook
This commit is contained in:
111
src/pages/api/god/redeploy.ts
Normal file
111
src/pages/api/god/redeploy.ts
Normal 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' }
|
||||
});
|
||||
};
|
||||
Reference in New Issue
Block a user