fix(deploy): SHA normalization + kua-vault wrap in verifyStatelessRecreated; retire webhook mandatory check; add /api/v1/apps/registry endpoint
- verifyStatelessRecreated(): strip sha256: prefix before comparing image SHAs (same fix already applied to runtime-status in2551af4, completeSelfRecreate in 06852c2; now consistent across all three verify paths) - verifyStatelessRecreated(): add kua-vault wrap on compose images/ps calls (mirrors2551af4runtime-status fix; env interpolation was causing empty output for vault-injected apps, making the verify always fail with 'no running container') - start(): downgrade missing WEBHOOK_SECRET from fatal error to warning; the Forgejo webhook path is retired in favour of the admin API — handler stays but the startup guard no longer blocks kua-deploy from booting - Add GET /api/v1/apps/registry so kua-mcp-core can fetch the full app list over HTTP without depending on a filesystem path inside its container Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
58733939e2
commit
6a583a8572
19
server.js
19
server.js
|
|
@ -636,8 +636,8 @@ ${detail}`);
|
||||||
if (verifyMode === 'off') return { ok: true, results: [], skipped: true };
|
if (verifyMode === 'off') return { ok: true, results: [], skipped: true };
|
||||||
const results = [];
|
const results = [];
|
||||||
for (const svc of services) {
|
for (const svc of services) {
|
||||||
const exp = await runOnServer(server, `cd ${deployDir} && docker compose images --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} && docker compose ps --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 expectedSha = (exp.stdout || '').trim();
|
||||||
const containerId = (cid.stdout || '').trim();
|
const containerId = (cid.stdout || '').trim();
|
||||||
if (!containerId) {
|
if (!containerId) {
|
||||||
|
|
@ -647,7 +647,8 @@ ${detail}`);
|
||||||
const insp = await runOnServer(server, `docker inspect --format '{{.Image}}|{{.State.StartedAt}}' ${containerId}`);
|
const insp = await runOnServer(server, `docker inspect --format '{{.Image}}|{{.State.StartedAt}}' ${containerId}`);
|
||||||
const [actualSha, startedAtStr] = (insp.stdout || '').trim().split('|');
|
const [actualSha, startedAtStr] = (insp.stdout || '').trim().split('|');
|
||||||
const startedAt = new Date(startedAtStr || 0);
|
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;
|
const freshlyStarted = !isNaN(startedAt) && startedAt >= deployStartTs;
|
||||||
results.push({
|
results.push({
|
||||||
service: svc, ok: imageMatch && freshlyStarted,
|
service: svc, ok: imageMatch && freshlyStarted,
|
||||||
|
|
@ -1162,6 +1163,12 @@ fastify.post('/webhook/forgejo', async (request, reply) => {
|
||||||
|
|
||||||
// --- Apps ---
|
// --- 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
|
// List all apps
|
||||||
fastify.get('/api/v1/apps', async () => {
|
fastify.get('/api/v1/apps', async () => {
|
||||||
const results = [];
|
const results = [];
|
||||||
|
|
@ -1502,9 +1509,11 @@ async function completeSelfRecreate() {
|
||||||
|
|
||||||
const start = async () => {
|
const start = async () => {
|
||||||
try {
|
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) {
|
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 loadRegistry();
|
||||||
await loadHistory();
|
await loadHistory();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue