diff --git a/server.js b/server.js index 436bafa..1a15e49 100644 --- a/server.js +++ b/server.js @@ -636,8 +636,8 @@ ${detail}`); if (verifyMode === 'off') return { ok: true, results: [], skipped: true }; const results = []; for (const svc of services) { - const exp = await runOnServer(server, `cd ${deployDir} && docker compose images --quiet ${svc} 2>/dev/null | head -1`); - const cid = await runOnServer(server, `cd ${deployDir} && docker compose ps --quiet ${svc} 2>/dev/null | head -1`); + const exp = await runOnServer(server, `cd ${deployDir} && ${kvPrefix} docker compose images --quiet ${svc} 2>/dev/null | head -1`); + const cid = await runOnServer(server, `cd ${deployDir} && ${kvPrefix} docker compose ps --quiet ${svc} 2>/dev/null | head -1`); const expectedSha = (exp.stdout || '').trim(); const containerId = (cid.stdout || '').trim(); if (!containerId) { @@ -647,7 +647,8 @@ ${detail}`); const insp = await runOnServer(server, `docker inspect --format '{{.Image}}|{{.State.StartedAt}}' ${containerId}`); const [actualSha, startedAtStr] = (insp.stdout || '').trim().split('|'); const startedAt = new Date(startedAtStr || 0); - const imageMatch = !!expectedSha && actualSha === expectedSha; + const stripSha = (s) => (s || '').replace(/^sha256:/, ''); + const imageMatch = !!expectedSha && stripSha(actualSha) === stripSha(expectedSha); const freshlyStarted = !isNaN(startedAt) && startedAt >= deployStartTs; results.push({ service: svc, ok: imageMatch && freshlyStarted, @@ -1162,6 +1163,12 @@ fastify.post('/webhook/forgejo', async (request, reply) => { // --- Apps --- +// Registry dump — used by kua-mcp-core to discover all apps at startup +// without relying on a filesystem path that may not resolve inside its container. +fastify.get('/api/v1/apps/registry', async () => { + return registry; +}); + // List all apps fastify.get('/api/v1/apps', async () => { const results = []; @@ -1502,9 +1509,11 @@ async function completeSelfRecreate() { const start = async () => { try { - // Fail fast if webhook secret is missing in production + // WEBHOOK_SECRET is optional — the Forgejo webhook path is now retired in + // favour of the admin API (/api/v1/apps/:app/deploy). The handler remains + // but returns 503 when the secret is absent, which is safe. if (!DEV_MODE && !WEBHOOK_SECRET) { - throw new Error('KUA_DEPLOY_WEBHOOK_SECRET must be set in production — refusing to start'); + fastify.log.warn('KUA_DEPLOY_WEBHOOK_SECRET not set — /webhook/forgejo will return 503. Set the secret to re-enable Forgejo push triggers.'); } await loadRegistry(); await loadHistory();