From 3727eb6951ec7ebd499d8204352b2b50b841cd38 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 24 Jul 2026 17:54:08 +0000 Subject: [PATCH 1/3] security-dashboard: add a Commit Changes button to the PSTN Trunk tab Confirmed live this session: writes to pstn-permissions.conf, pstn-groups.conf, and pstn-personal-dids.conf land on disk immediately, but AST_CONFIG() in the dialplan sometimes kept returning a stale value (e.g. a personal DID's old owner after reassigning it to a group) until the Asterisk container was fully restarted - not just dialplan/module reload. This contradicts the "live, no restart needed" premise the rest of this tab's copy relies on, so surfacing it explicitly beats letting admins discover it by trial and error. Adds a "Commit Changes (Restart Asterisk)" button and banner to the PSTN Trunk tab, shown after any save on that tab (permissions, limits, groups, personal DIDs) and warning via beforeunload if left uncommitted. Backend restart_asterisk_container() runs `docker restart` on the Easy Asterisk container through the same scoped-sudoers/run_sudo mechanism the native Easy Asterisk Admin tab already uses for its own docker exec calls, so this needed one new sudoers line, not a new privilege model. --- services/security-dashboard.sh | 89 +++++++++++++++++++++++++++++++--- 1 file changed, 83 insertions(+), 6 deletions(-) diff --git a/services/security-dashboard.sh b/services/security-dashboard.sh index 186219d..0438726 100644 --- a/services/security-dashboard.sh +++ b/services/security-dashboard.sh @@ -458,15 +458,20 @@ _secdash_write_sudoers() { # `docker exec -i tee ` instead of a direct # host-side file write (see _secdash_grant_asterisk_access's comment on # why), plus the two Asterisk CLI calls needed after a change and the - # live registration-status check. All six are exact commands, no + # live registration-status check. All seven are exact commands, no # wildcards, scoped to the one container actually installed on this box. + # The last line (docker restart) backs the PSTN Trunk tab's "Commit + # Changes" button — see restart_asterisk_container()'s comment for why + # that exists (AST_CONFIG() live-reads not always picking up dashboard + # edits without a full container restart). if [ -n "$_ea_container" ]; then _ea_lines="$_svc_user ALL=(root) NOPASSWD: /usr/bin/docker exec -i $_ea_container tee /etc/asterisk/pjsip.conf $_svc_user ALL=(root) NOPASSWD: /usr/bin/docker exec -i $_ea_container tee /etc/easy-asterisk/categories.conf $_svc_user ALL=(root) NOPASSWD: /usr/bin/docker exec -i $_ea_container tee /etc/easy-asterisk/rooms.conf $_svc_user ALL=(root) NOPASSWD: /usr/bin/docker exec $_ea_container asterisk -rx module\ reload\ res_pjsip.so $_svc_user ALL=(root) NOPASSWD: /usr/bin/docker exec $_ea_container asterisk -rx pjsip\ show\ endpoints -$_svc_user ALL=(root) NOPASSWD: /usr/bin/docker exec $_ea_container /usr/local/bin/easy-asterisk --rebuild-dialplan" +$_svc_user ALL=(root) NOPASSWD: /usr/bin/docker exec $_ea_container /usr/local/bin/easy-asterisk --rebuild-dialplan +$_svc_user ALL=(root) NOPASSWD: /usr/bin/docker restart $_ea_container" fi cat > /etc/sudoers.d/security-dashboard << SUDOERS $_svc_user ALL=(root) NOPASSWD: /usr/bin/cscli decisions delete --id [0-9]* @@ -1644,6 +1649,27 @@ def ea_rebuild_dialplan(): run_sudo(["docker", "exec", ASTERISK_EA_CONTAINER, "/usr/local/bin/easy-asterisk", "--rebuild-dialplan"]) +def restart_asterisk_container(): + """Restarts the Easy Asterisk container - the "Commit Changes" button on + the PSTN Trunk tab. Confirmed live: dashboard writes to + pstn-permissions.conf/pstn-groups.conf/pstn-personal-dids.conf land on + disk immediately (readable via a plain `cat` right after saving), but + AST_CONFIG() in the dialplan sometimes kept returning a stale value + until the container was fully restarted - not just a `dialplan reload` + or `module reload`, an actual container restart. Root cause not fully + understood (contradicts AST_CONFIG's whole "reads fresh every call, no + restart needed" design premise, which this codebase otherwise relies on + throughout), but the restart reliably clears it, so this button exists + instead of requiring every admin to rediscover "just restart it" the + hard way. Uses the same ASTERISK_EA_CONTAINER/run_sudo mechanism as the + Easy Asterisk Admin tab's own docker exec calls - no new sudoers scope + needed beyond the one line added for this.""" + if not ASTERISK_EA_CONTAINER: + return False, "No Asterisk container detected on this box" + ok, _out, err = run_sudo(["docker", "restart", ASTERISK_EA_CONTAINER], timeout=30) + return ok, ("" if ok else (err or "Restart failed")) + + def ea_get_status(): """Registered/unregistered per extension — same 'pjsip show endpoints' parsing as the vendored get_registered_endpoints().""" @@ -2311,9 +2337,17 @@ INDEX_HTML = """