From 7a1f09a0f7e3253fe41b96802f629a0fc07027b9 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 12 Aug 2026 12:47:31 +0000 Subject: [PATCH] Rename reinstall-mode prompt; make security-dashboard's "Full reinstall" a real teardown MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two-part change discussed and scoped in this session before touching anything: 1. Rename "Reinstall in place" (r) -> "Update" (u) and "Full install" (f) -> "Full reinstall" everywhere the prompt appears: lib/common.sh's shared prompt_reinstall_mode(), plus the three services that carry their own duplicated standalone-stub copy of it for standalone execution (asterisk.sh, coturn.sh, wordpress.sh — per this repo's documented standalone-bootstrap pattern). Internal state values (update/fresh/cancel) are unchanged, so no other service's case statement needed touching. docs/anveo-direct-setup-guide.md's `r` reference updated to `u` to match. attic/asterisk-digital-ocean.sh deliberately left alone — this repo's own policy is to not backport fixes into attic/. 2. security-dashboard.sh's "Full reinstall" now does a real teardown before reinstalling — stops and removes the systemd unit, sudoers grant, Caddy site block, and secdash system user, then proceeds through the normal fresh-install flow — instead of just overwriting files in place while leaving the old service running underneath. Prototype for a pattern discussed for other services later: split the destructive question out explicitly ("also delete dashboard-admins.conf — per-admin extension scoping?", default n) so full reinstall doesn't silently discard state a plain "start over" request wouldn't expect to lose. Verified the backup/restore mechanics (mktemp, copy out before teardown, copy back after) against a mock under `set -u` for both the preserve and wipe paths before shipping. Update mode was already the strongest existing example of surfacing newer optional prompts (its "Reconfigure Caddy protection?" / "Reconfigure per-admin scoping?" sub-prompts already cover every setting fresh-install offers) — no changes needed there for this service. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01H4k6J1qXXyYxhGEgnJaMvn --- docs/anveo-direct-setup-guide.md | 2 +- lib/common.sh | 8 ++--- services/asterisk.sh | 8 ++--- services/coturn.sh | 8 ++--- services/security-dashboard.sh | 53 +++++++++++++++++++++++++++++++- services/wordpress.sh | 8 ++--- 6 files changed, 69 insertions(+), 18 deletions(-) diff --git a/docs/anveo-direct-setup-guide.md b/docs/anveo-direct-setup-guide.md index f219370..45657e4 100644 --- a/docs/anveo-direct-setup-guide.md +++ b/docs/anveo-direct-setup-guide.md @@ -143,7 +143,7 @@ account default in step 6 and skip even that: sudo ./setup.sh pstn-trunk ``` -- Existing install → choose **update** (`r`) if you're just changing the +- Existing install → choose **update** (`u`) if you're just changing the DID/server, or the CLI will walk fresh prompts if none exists yet. - Provider quick-pick: **1) Anveo Direct** — pre-fills `sbc.anveo.com` and Anveo's 4 published signaling IPs (only one of which the hostname diff --git a/lib/common.sh b/lib/common.sh index fb4024b..016aaf5 100644 --- a/lib/common.sh +++ b/lib/common.sh @@ -718,12 +718,12 @@ prompt_reinstall_mode() { return fi echo " Existing install detected. Choose:" - echo " r) Reinstall in place — refresh vendor files/config, keep existing settings" - echo " f) Full install — re-run every prompt from scratch" + echo " u) Update — refresh vendor files/config, keep existing settings" + echo " f) Full reinstall — re-run every prompt from scratch" echo " c) Cancel — leave everything as-is [default]" - read -p " Choice [r/f/c, Enter=cancel]: " response + read -p " Choice [u/f/c, Enter=cancel]: " response case "${response,,}" in - r) eval "$varname='update'" ;; + u) eval "$varname='update'" ;; f) eval "$varname='fresh'" ;; *) eval "$varname='cancel'" ;; esac diff --git a/services/asterisk.sh b/services/asterisk.sh index 865da5a..4ff649f 100644 --- a/services/asterisk.sh +++ b/services/asterisk.sh @@ -82,12 +82,12 @@ if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then return fi echo " Existing install detected. Choose:" - echo " r) Reinstall in place — refresh vendor files/config, keep existing settings" - echo " f) Full install — re-run every prompt from scratch" + echo " u) Update — refresh vendor files/config, keep existing settings" + echo " f) Full reinstall — re-run every prompt from scratch" echo " c) Cancel — leave everything as-is [default]" - read -r -p " Choice [r/f/c, Enter=cancel]: " _r + read -r -p " Choice [u/f/c, Enter=cancel]: " _r case "${_r,,}" in - r) eval "$_var='update'" ;; + u) eval "$_var='update'" ;; f) eval "$_var='fresh'" ;; *) eval "$_var='cancel'" ;; esac diff --git a/services/coturn.sh b/services/coturn.sh index 19b3fdc..a0ce841 100644 --- a/services/coturn.sh +++ b/services/coturn.sh @@ -87,12 +87,12 @@ if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then local _var="$1" _r if [[ "${UNATTENDED:-false}" == "true" ]]; then eval "$_var='cancel'"; return; fi echo " Existing install detected. Choose:" - echo " r) Reinstall in place — refresh vendor files, keep existing settings" - echo " f) Full install — re-run every prompt from scratch" + echo " u) Update — refresh vendor files, keep existing settings" + echo " f) Full reinstall — re-run every prompt from scratch" echo " c) Cancel — leave everything as-is [default]" - read -r -p " Choice [r/f/c, Enter=cancel]: " _r + read -r -p " Choice [u/f/c, Enter=cancel]: " _r case "${_r,,}" in - r) eval "$_var='update'" ;; + u) eval "$_var='update'" ;; f) eval "$_var='fresh'" ;; *) eval "$_var='cancel'" ;; esac diff --git a/services/security-dashboard.sh b/services/security-dashboard.sh index 789f3ca..40bd0ff 100644 --- a/services/security-dashboard.sh +++ b/services/security-dashboard.sh @@ -184,7 +184,24 @@ install_security-dashboard() { log_info "Leaving the existing install as-is." return 0 ;; - fresh) ;; + fresh) + echo "" + log_warning "Full reinstall stops the dashboard and removes its systemd unit," + log_warning "sudoers grant, Caddy block, service user, and app files, then sets" + log_warning "it up again from scratch — every prompt below runs as if this were" + log_warning "a brand new install." + local _WIPE_ADMINS="" + prompt_yn " Also delete dashboard-admins.conf (per-admin Calls/Texts/Voicemail scoping)? (y/n):" "n" _WIPE_ADMINS + + local _ADMINS_BACKUP="" + if [[ ! "$_WIPE_ADMINS" =~ ^[Yy]$ ]] && [ -f "$APP_DIR/dashboard-admins.conf" ]; then + _ADMINS_BACKUP="$(mktemp)" + cp "$APP_DIR/dashboard-admins.conf" "$_ADMINS_BACKUP" + log_info "Preserving dashboard-admins.conf across the reinstall." + fi + + _secdash_teardown "$APP_DIR" "$SVC_USER" "$DASHBOARD_PORT" + ;; esac fi @@ -197,6 +214,11 @@ install_security-dashboard() { _secdash_grant_asterisk_access "$SVC_USER" "$ASTERISK_LOG_DIR" "$ASTERISK_CONFIG_DIR" "$ASTERISK_EA_CONFIG_DIR" "$ASTERISK_SPOOL_DIR" mkdir -p "$APP_DIR" + if [ -n "${_ADMINS_BACKUP:-}" ]; then + cp "$_ADMINS_BACKUP" "$APP_DIR/dashboard-admins.conf" + rm -f "$_ADMINS_BACKUP" + log_success "Restored dashboard-admins.conf" + fi _secdash_write_app "$APP_DIR" chown -R "$SVC_USER:$SVC_USER" "$APP_DIR" _secdash_write_asn_helper "$APP_DIR" @@ -974,6 +996,35 @@ _secdash_remove_caddy_block() { log_info "Removed the existing dashboard Caddy block (regenerating it fresh)." } +# Full teardown for "Full reinstall" — stops the service and removes +# everything a fresh install recreates: systemd unit, sudoers grant, Caddy +# site block, the secdash system user, and the app directory. Non-Docker +# service (systemd + /opt, not a container), so lib/common.sh's +# remove_service() (Docker-only, $DOCKER_DIR/) doesn't apply here — +# this is the equivalent for this one service. Callers are responsible for +# backing up/restoring anything under $_app_dir they want to survive (see +# the dashboard-admins.conf handling around the "fresh" case in +# install_security-dashboard() — this function does not know which files, +# if any, the caller wants to keep). +_secdash_teardown() { + local _app_dir="$1" _svc_user="$2" _port="$3" + + systemctl stop security-dashboard 2>/dev/null || true + systemctl disable security-dashboard 2>/dev/null || true + rm -f /etc/systemd/system/security-dashboard.service + systemctl daemon-reload + + rm -f /etc/sudoers.d/security-dashboard + + _secdash_remove_caddy_block "$_port" + + id "$_svc_user" &>/dev/null && userdel "$_svc_user" 2>/dev/null + + rm -rf "$_app_dir" + + log_success "Removed security-dashboard's systemd unit, sudoers grant, Caddy block, user, and app files." +} + # Root-owned helper for editing CrowdSec's Asterisk-scenario YAMLs — the # secdash service user (--shell /usr/sbin/nologin, no special file grants) # cannot write /etc/crowdsec/scenarios/*.yaml directly (root:root, mode diff --git a/services/wordpress.sh b/services/wordpress.sh index 85b092b..7438e0f 100644 --- a/services/wordpress.sh +++ b/services/wordpress.sh @@ -95,12 +95,12 @@ if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then local _var="$1" _r if [[ "${UNATTENDED:-false}" == "true" ]]; then eval "$_var='cancel'"; return; fi echo " Existing install detected. Choose:" - echo " r) Reinstall in place — refresh image/compose, keep database and settings" - echo " f) Full install — re-run every prompt from scratch" + echo " u) Update — refresh image/compose, keep database and settings" + echo " f) Full reinstall — re-run every prompt from scratch" echo " c) Cancel — leave everything as-is [default]" - read -r -p " Choice [r/f/c, Enter=cancel]: " _r + read -r -p " Choice [u/f/c, Enter=cancel]: " _r case "${_r,,}" in - r) eval "$_var='update'" ;; + u) eval "$_var='update'" ;; f) eval "$_var='fresh'" ;; *) eval "$_var='cancel'" ;; esac