From e36268b556583c2600e1a8f81c897a4b973da309 Mon Sep 17 00:00:00 2001 From: Heidi Date: Mon, 15 Jun 2026 09:12:19 +0100 Subject: [PATCH] ai generated solutions to our ai generated problems --- webhook.cjs | 62 ++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 54 insertions(+), 8 deletions(-) diff --git a/webhook.cjs b/webhook.cjs index 613eb5e..e6be6c0 100644 --- a/webhook.cjs +++ b/webhook.cjs @@ -61,6 +61,7 @@ const ALLOWED_REPOSITORY = (process.env.GITHUB_WEBHOOK_REPOSITORY || '').trim() const RESTART_AFTER_MS = 24 * 60 * 60 * 1000 let deploying = false +let queuedPush = null function json(res, status, body) { res.writeHead(status, { 'content-type': 'application/json; charset=utf-8' }) @@ -347,6 +348,27 @@ function promoteBuiltDist() { } } +function validateBuiltDist() { + const indexPath = path.join(NEXT_DIST_DIR, 'index.html') + if (!fs.existsSync(indexPath)) { + throw new Error('Frontend build did not produce dist-next/index.html') + } + + const html = fs.readFileSync(indexPath, 'utf8') + if (/\sintegrity=(["'])sha(?:256|384|512)-[^"']+\1/i.test(html)) { + throw new Error('Frontend build contains integrity attributes that may not match the obfuscated assets') + } + + const assetPaths = [...html.matchAll(/(?:src|href)=(["'])\/(assets\/[^"']+)\1/g)] + .map((match) => match[2]) + + for (const assetPath of assetPaths) { + if (!fs.existsSync(path.join(NEXT_DIST_DIR, assetPath))) { + throw new Error(`Frontend build references missing asset: /${assetPath}`) + } + } +} + function postDiscordWebhook(payload) { if (!DISCORD_WEBHOOK_URL) return Promise.resolve() @@ -510,6 +532,7 @@ async function deploy(push) { diff = await deployDiff(push) await ensureBuildDependencies() await run('npm', ['run', 'build', '--', '--outDir', '../dist-next']) + validateBuiltDist() await run('cargo', ['build', '--manifest-path', 'backend/Cargo.toml', '--release']) promoteBuiltDist() @@ -524,9 +547,36 @@ async function deploy(push) { } } +async function runDeployQueue(initialPush) { + let push = initialPush + + while (push) { + queuedPush = null + + try { + await deploy(push) + console.log('GitHub push deploy completed') + } catch (error) { + console.error('GitHub push deploy failed:', error) + try { + await notifyDeployFailed(push, error, error.deployDiff) + } catch (notificationError) { + console.error('Failed to send deploy failure notification:', notificationError) + } + } + + push = queuedPush + } +} + const webhookServer = http.createServer((req, res) => { if (req.method === 'GET' && req.url === '/health') { - json(res, 200, { ok: true, deploying, restart_targets: RESTART_TARGETS }) + json(res, 200, { + ok: true, + deploying, + queued: Boolean(queuedPush), + restart_targets: RESTART_TARGETS, + }) return } @@ -583,19 +633,15 @@ const webhookServer = http.createServer((req, res) => { } if (deploying) { - json(res, 202, { queued: false, deploying: true }) + queuedPush = push + json(res, 202, { queued: true, deploying: true }) return } deploying = true json(res, 202, { accepted: true, restart_targets: RESTART_TARGETS }) - deploy(push) - .then(() => console.log('GitHub push deploy completed')) - .catch((error) => { - console.error('GitHub push deploy failed:', error) - notifyDeployFailed(push, error, error.deployDiff) - }) + runDeployQueue(push) .finally(() => { deploying = false })