diff --git a/server.js b/server.js index 52e4c24..74dd67d 100644 --- a/server.js +++ b/server.js @@ -708,7 +708,11 @@ ${detail}`); const selfRecreate = appName === SELF_APP_NAME && isLocal(server) && stateless.includes(SELF_APP_NAME); if (selfRecreate) { // Capture the freshly-built image SHA for post-restart verification. - const builtSha = (await run(`docker compose -p ${composeProject} -f ${deployDir}/docker-compose.yml images --quiet ${SELF_APP_NAME} 2>/dev/null | head -1`)).stdout.trim() || null; + // `docker compose images` returns the image used by the EXISTING container + // (still the OLD one before recreate). For the just-built image, query the + // image tag that compose builds into: ${project}-${service}:latest. + const builtImageTag = `${composeProject}-${SELF_APP_NAME}:latest`; + const builtSha = (await run(`docker images ${builtImageTag} --quiet --no-trunc | head -1`)).stdout.trim() || null; steps[steps.length - 1] = { step: 'deploy', status: 'running', @@ -1443,7 +1447,9 @@ async function completeSelfRecreate() { } } catch { /* docker unreachable — leave progress in pending; next startup retries */ } - const imageMatches = expectedSha && runningSha && expectedSha.endsWith(runningSha.replace(/^sha256:/, '')); + // Normalize: strip sha256: prefix from both sides for tolerant comparison. + const normSha = s => (s || '').replace(/^sha256:/, '').trim(); + const imageMatches = expectedSha && runningSha && normSha(expectedSha) === normSha(runningSha); const freshlyStarted = startedAtStr && recreateStartedAt && new Date(startedAtStr) >= recreateStartedAt; const ok = !!(imageMatches && freshlyStarted && state === 'running');