diff --git a/content-editor.js b/content-editor.js index 723017c..6ffb1aa 100644 --- a/content-editor.js +++ b/content-editor.js @@ -305,18 +305,20 @@ const server = http.createServer(async (req, res) => { // trigger a rebuild. Deploy only the explicitly configured environment; // never default to production. Overridable for tests. if (outcome.hadChanges) { - // WHY setsid+nohup+stdin-null: under systemd the naive `cmd &` child died - // together with the spawning shell (observed: the deploy never ran after a - // CMS publish, leaving the site on stale content). Full detachment makes it - // survive; the audit entries make the spawn observable instead of silent. + // WHY direct child instead of a detached `cmd &`: under the systemd unit's + // hardening (NoNewPrivileges/PrivateTmp) the backgrounded grandchild died + // silently (observed twice: stale site after a publish). A direct child is + // not detached, runs to completion, and the callback turns the audit entry + // into a real "deploy finished/failed" signal. The HTTP response is already + // sent; deploy output goes to deploy.log so the pipes stay quiet. const deployCmd = process.env.CONTENT_EDITOR_DEPLOY_CMD - || `cd ../../../ && setsid nohup ./deploy.sh ${CMS_DEPLOY_ENV} > deploy.log 2>&1 < /dev/null &`; + || `cd ../../../ && ./deploy.sh ${CMS_DEPLOY_ENV} > deploy.log 2>&1`; writeAudit('deploy_spawned', { clientAddress, user: CMS_USER, env: CMS_DEPLOY_ENV }); - exec(deployCmd, deployError => { + exec(deployCmd, { maxBuffer: 8 * 1024 * 1024 }, deployError => { writeAudit('deploy_exec_exit', { clientAddress, user: CMS_USER, - result: deployError ? 'error' : 'shell_exited', + result: deployError ? 'error' : 'ok', error: deployError ? String(deployError.message).slice(0, 300) : undefined, }); });