From e178f764e31154ecde65d144598ab7be7783d647 Mon Sep 17 00:00:00 2001 From: lodar Date: Thu, 23 Jul 2026 11:21:28 +0000 Subject: [PATCH] fix(telegram): /restart + /model use _self_restart on standard boxes (DIVE-1813) restartAgent now calls 'sudo -n 5dive agent _self_restart' instead of 'sudo 5dive agent restart '. On a standard-isolation (customer) box the scoped sudoers grants exactly the self-restart primitive and NOT 'agent restart ', so /restart and /model previously failed with 'sudo: a password is required'. _self_restart restarts only the caller's own unit (derived from SUDO_USER, never argv) and defers internally. grok is the generator base; agy/qwen regenerated (generate.ts --check byte-exact, parity 50/50). Paired with 5dive-cli _self_restart (DIVE-1813). HOLD: awaiting Marcus security sign-off before push/land. Co-Authored-By: Claude Opus 4.8 --- plugins/telegram-agy/server.ts | 12 ++++++++---- plugins/telegram-codex/server.ts | 12 ++++++++---- plugins/telegram-grok/server.ts | 12 ++++++++---- 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/plugins/telegram-agy/server.ts b/plugins/telegram-agy/server.ts index f6820fa..5a6fad1 100644 --- a/plugins/telegram-agy/server.ts +++ b/plugins/telegram-agy/server.ts @@ -1036,11 +1036,15 @@ async function restartAgent(name: string, ackUpdateId?: number): Promise { try { await bot.api.getUpdates({ offset: ackUpdateId + 1, limit: 1, timeout: 0 }) } catch {} } await new Promise(resolve => { - // `sudo 5dive agent restart ` is the canonical path — it - // touches the systemd unit, not the tmux session directly, so the - // unit's audit log and restart counter stay consistent. + // DIVE-1813: `sudo 5dive agent _self_restart` is the canonical path — on a + // standard-isolation box the agent's scoped sudoers grants exactly this + // (there is NO `agent restart ` grant), and it restarts ONLY the + // caller's own unit (derived from SUDO_USER, never argv). Deferred + // internally so the ack lands before the respawn. Touches the systemd unit, + // not the tmux session, so the unit's audit log + restart counter stay + // consistent. require('child_process').execFile('sudo', - ['-n', '5dive', 'agent', 'restart', name], + ['-n', '5dive', 'agent', '_self_restart'], { timeout: 10_000 }, () => resolve(), ) diff --git a/plugins/telegram-codex/server.ts b/plugins/telegram-codex/server.ts index fd0e4e5..a0c305c 100644 --- a/plugins/telegram-codex/server.ts +++ b/plugins/telegram-codex/server.ts @@ -1063,11 +1063,15 @@ async function restartAgent(name: string, ackUpdateId?: number): Promise { try { await bot.api.getUpdates({ offset: ackUpdateId + 1, limit: 1, timeout: 0 }) } catch {} } await new Promise(resolve => { - // `sudo 5dive agent restart ` is the canonical path — it - // touches the systemd unit, not the tmux session directly, so the - // unit's audit log and restart counter stay consistent. + // DIVE-1813: `sudo 5dive agent _self_restart` is the canonical path — on a + // standard-isolation box the agent's scoped sudoers grants exactly this + // (there is NO `agent restart ` grant), and it restarts ONLY the + // caller's own unit (derived from SUDO_USER, never argv). Deferred + // internally so the ack lands before the respawn. Touches the systemd unit, + // not the tmux session, so the unit's audit log + restart counter stay + // consistent. require('child_process').execFile('sudo', - ['-n', '5dive', 'agent', 'restart', name], + ['-n', '5dive', 'agent', '_self_restart'], { timeout: 10_000 }, () => resolve(), ) diff --git a/plugins/telegram-grok/server.ts b/plugins/telegram-grok/server.ts index ede940e..b1dddfa 100755 --- a/plugins/telegram-grok/server.ts +++ b/plugins/telegram-grok/server.ts @@ -1048,11 +1048,15 @@ async function restartAgent(name: string, ackUpdateId?: number): Promise { try { await bot.api.getUpdates({ offset: ackUpdateId + 1, limit: 1, timeout: 0 }) } catch {} } await new Promise(resolve => { - // `sudo 5dive agent restart ` is the canonical path — it - // touches the systemd unit, not the tmux session directly, so the - // unit's audit log and restart counter stay consistent. + // DIVE-1813: `sudo 5dive agent _self_restart` is the canonical path — on a + // standard-isolation box the agent's scoped sudoers grants exactly this + // (there is NO `agent restart ` grant), and it restarts ONLY the + // caller's own unit (derived from SUDO_USER, never argv). Deferred + // internally so the ack lands before the respawn. Touches the systemd unit, + // not the tmux session, so the unit's audit log + restart counter stay + // consistent. require('child_process').execFile('sudo', - ['-n', '5dive', 'agent', 'restart', name], + ['-n', '5dive', 'agent', '_self_restart'], { timeout: 10_000 }, () => resolve(), )