From 3ecf213cab1b5820f16899373fbc21bb5a22970c Mon Sep 17 00:00:00 2001 From: librelad Date: Sun, 24 May 2026 16:29:22 +0100 Subject: [PATCH] refactor(de-sudo): docker calls via runFileOp/dockerCommandRun, drop sudo Container-plane docker now routes through the mode-aware helpers instead of sudo: simple calls (exec/ps/run/build/images/inspect/port/logs across ~15 app/check scripts) -> runFileOp docker (rootless socket as the install user; rooted via the docker group). The cd && docker compose paths drop the sudo on the rooted branch (the rootless branch already used dockerCommandRunInstallUser -- byte-identical now, manager-ready later); gluetun, which had no rootless branch, now uses dockerCommandRun so force-recreate works in both modes. Co-Authored-By: Claude Opus 4.7 Signed-off-by: librelad --- scripts/app/containers/bookstack/bookstack_auth.sh | 2 +- scripts/app/containers/focalboard/focalboard_auth.sh | 2 +- scripts/app/containers/gitea/gitea_auth.sh | 2 +- scripts/app/containers/gluetun/gluetun_recreate_routed.sh | 8 +++----- scripts/app/containers/invidious/invidious_auth.sh | 2 +- scripts/app/containers/mattermost/mattermost_auth.sh | 2 +- .../containers/nextcloud/nextcloud_add_trusted_domain.sh | 4 ++-- scripts/app/containers/nextcloud/nextcloud_auth.sh | 4 ++-- .../app/containers/nextcloud/nextcloud_rescan_files.sh | 2 +- .../app/containers/nextcloud/nextcloud_system_status.sh | 2 +- scripts/app/containers/nextcloud/nextcloud_tail_logs.sh | 2 +- .../containers/nextcloud/nextcloud_toggle_maintenance.sh | 2 +- scripts/config/password/password_hash.sh | 2 +- scripts/docker/app/compose/down_app.sh | 2 +- scripts/docker/app/compose/up_app.sh | 4 ++-- scripts/docker/app/uninstall/down_remove_app.sh | 2 +- scripts/docker/app/uninstall/remove_images.sh | 2 +- scripts/docker/checks/running_for_user.sh | 2 +- scripts/install/install_crowdsec.sh | 2 +- scripts/webui/webui_install_image.sh | 2 +- 20 files changed, 25 insertions(+), 27 deletions(-) diff --git a/scripts/app/containers/bookstack/bookstack_auth.sh b/scripts/app/containers/bookstack/bookstack_auth.sh index f5ee6a1..a0ac991 100644 --- a/scripts/app/containers/bookstack/bookstack_auth.sh +++ b/scripts/app/containers/bookstack/bookstack_auth.sh @@ -8,7 +8,7 @@ _bookstackArtisan() { local container="bookstack" local php_body="$1" shift - sudo docker exec -i -w /app/www "$@" "$container" php artisan tinker --execute="$php_body" 2>&1 + runFileOp docker exec -i -w /app/www "$@" "$container" php artisan tinker --execute="$php_body" 2>&1 } authAdapter_bookstack_setPassword() { diff --git a/scripts/app/containers/focalboard/focalboard_auth.sh b/scripts/app/containers/focalboard/focalboard_auth.sh index 8742944..ee731f8 100644 --- a/scripts/app/containers/focalboard/focalboard_auth.sh +++ b/scripts/app/containers/focalboard/focalboard_auth.sh @@ -1,7 +1,7 @@ #!/bin/bash _focalboardSqlite() { - sudo docker exec -i focalboard-service sqlite3 /data/focalboard.db "$1" 2>&1 + runFileOp docker exec -i focalboard-service sqlite3 /data/focalboard.db "$1" 2>&1 } _focalboardBcrypt() { diff --git a/scripts/app/containers/gitea/gitea_auth.sh b/scripts/app/containers/gitea/gitea_auth.sh index 91cfd48..eebd76f 100644 --- a/scripts/app/containers/gitea/gitea_auth.sh +++ b/scripts/app/containers/gitea/gitea_auth.sh @@ -1,7 +1,7 @@ #!/bin/bash _giteaCmd() { - sudo docker exec -u git gitea-service gitea admin "$@" 2>&1 + runFileOp docker exec -u git gitea-service gitea admin "$@" 2>&1 } authAdapter_gitea_setPassword() { diff --git a/scripts/app/containers/gluetun/gluetun_recreate_routed.sh b/scripts/app/containers/gluetun/gluetun_recreate_routed.sh index a2493c1..d887d43 100644 --- a/scripts/app/containers/gluetun/gluetun_recreate_routed.sh +++ b/scripts/app/containers/gluetun/gluetun_recreate_routed.sh @@ -27,7 +27,7 @@ appGluetunRecreateRouted() installed_apps=$(runInstallOp sqlite3 "$docker_dir/$db_file" \ "SELECT name FROM apps WHERE status = 1 ORDER BY name;" 2>/dev/null) - if ! sudo docker ps --format '{{.Names}}' 2>/dev/null | grep -q '^gluetun-service$'; then + if ! runFileOp docker ps --format '{{.Names}}' 2>/dev/null | grep -q '^gluetun-service$'; then # Nothing to re-attach against; gluetun isn't running. return 0 fi @@ -48,15 +48,13 @@ appGluetunRecreateRouted() # Skip apps with no running/created container — recreate would # do nothing useful and we'd just emit noise. - if ! sudo docker ps -a --format '{{.Names}}' 2>/dev/null \ + if ! runFileOp docker ps -a --format '{{.Names}}' 2>/dev/null \ | grep -q "^${app}-service$"; then continue fi isNotice "Re-attaching ${app} to gluetun's namespace (force-recreate)..." - (cd "${containers_dir}${app}" \ - && sudo docker compose up -d --force-recreate "${app}-service" \ - >/dev/null 2>&1) || true + dockerCommandRun "cd ${containers_dir}${app} && docker compose up -d --force-recreate ${app}-service" >/dev/null 2>&1 || true ((recreated++)) done <<< "$installed_apps" diff --git a/scripts/app/containers/invidious/invidious_auth.sh b/scripts/app/containers/invidious/invidious_auth.sh index 40bda98..f84ed1a 100644 --- a/scripts/app/containers/invidious/invidious_auth.sh +++ b/scripts/app/containers/invidious/invidious_auth.sh @@ -1,7 +1,7 @@ #!/bin/bash _invidiousPsql() { - sudo docker exec -i invidious-db psql -U kemal -d invidious -At -c "$1" 2>&1 + runFileOp docker exec -i invidious-db psql -U kemal -d invidious -At -c "$1" 2>&1 } _invidiousBcrypt() { diff --git a/scripts/app/containers/mattermost/mattermost_auth.sh b/scripts/app/containers/mattermost/mattermost_auth.sh index 618f2ab..6247126 100644 --- a/scripts/app/containers/mattermost/mattermost_auth.sh +++ b/scripts/app/containers/mattermost/mattermost_auth.sh @@ -1,7 +1,7 @@ #!/bin/bash _mattermostMmctl() { - sudo docker exec -i mattermost mmctl --local "$@" 2>&1 + runFileOp docker exec -i mattermost mmctl --local "$@" 2>&1 } authAdapter_mattermost_setPassword() { diff --git a/scripts/app/containers/nextcloud/nextcloud_add_trusted_domain.sh b/scripts/app/containers/nextcloud/nextcloud_add_trusted_domain.sh index 75f9757..0a7581f 100644 --- a/scripts/app/containers/nextcloud/nextcloud_add_trusted_domain.sh +++ b/scripts/app/containers/nextcloud/nextcloud_add_trusted_domain.sh @@ -11,11 +11,11 @@ appNextcloudAddTrustedDomain() { [[ -z "$domain" ]] && { isError "Domain is required."; return 1; } local current_count - current_count=$(sudo docker exec -u www-data nextcloud-service php occ config:system:get trusted_domains 2>/dev/null | grep -c '^\s*[0-9]') + current_count=$(runFileOp docker exec -u www-data nextcloud-service php occ config:system:get trusted_domains 2>/dev/null | grep -c '^\s*[0-9]') [[ -z "$current_count" || "$current_count" -lt 1 ]] && current_count=1 local out - out=$(sudo docker exec -u www-data nextcloud-service php occ config:system:set trusted_domains "$current_count" --value="$domain" 2>&1) + out=$(runFileOp docker exec -u www-data nextcloud-service php occ config:system:set trusted_domains "$current_count" --value="$domain" 2>&1) if echo "$out" | grep -qi "system config value\|set to string"; then isSuccessful "Nextcloud trusted_domains[$current_count] = $domain" return 0 diff --git a/scripts/app/containers/nextcloud/nextcloud_auth.sh b/scripts/app/containers/nextcloud/nextcloud_auth.sh index 89afd97..aa242a4 100644 --- a/scripts/app/containers/nextcloud/nextcloud_auth.sh +++ b/scripts/app/containers/nextcloud/nextcloud_auth.sh @@ -5,12 +5,12 @@ # pipe passwords via the OC_PASS env var (occ supports --password-from-env). _nextcloudOcc() { - sudo docker exec -u www-data nextcloud-service php occ "$@" 2>&1 + runFileOp docker exec -u www-data nextcloud-service php occ "$@" 2>&1 } _nextcloudOccWithPass() { local pass="$1"; shift - sudo docker exec -e OC_PASS="$pass" -u www-data nextcloud-service php occ "$@" 2>&1 + runFileOp docker exec -e OC_PASS="$pass" -u www-data nextcloud-service php occ "$@" 2>&1 } authAdapter_nextcloud_setPassword() { diff --git a/scripts/app/containers/nextcloud/nextcloud_rescan_files.sh b/scripts/app/containers/nextcloud/nextcloud_rescan_files.sh index 7645be4..125d1d8 100644 --- a/scripts/app/containers/nextcloud/nextcloud_rescan_files.sh +++ b/scripts/app/containers/nextcloud/nextcloud_rescan_files.sh @@ -12,7 +12,7 @@ appNextcloudRescanFiles() { [[ -n "$username" ]] && target="$username" local out - out=$(sudo docker exec -u www-data nextcloud-service php occ files:scan $target 2>&1) + out=$(runFileOp docker exec -u www-data nextcloud-service php occ files:scan $target 2>&1) if echo "$out" | grep -qi "scanned\|files found"; then isSuccessful "Nextcloud file rescan completed${username:+ for $username}." return 0 diff --git a/scripts/app/containers/nextcloud/nextcloud_system_status.sh b/scripts/app/containers/nextcloud/nextcloud_system_status.sh index 8bac1fd..e216208 100644 --- a/scripts/app/containers/nextcloud/nextcloud_system_status.sh +++ b/scripts/app/containers/nextcloud/nextcloud_system_status.sh @@ -5,5 +5,5 @@ # modal results pane. appNextcloudSystemStatus() { - sudo docker exec -u www-data nextcloud-service php occ status 2>&1 + runFileOp docker exec -u www-data nextcloud-service php occ status 2>&1 } diff --git a/scripts/app/containers/nextcloud/nextcloud_tail_logs.sh b/scripts/app/containers/nextcloud/nextcloud_tail_logs.sh index f8eff0d..0c1761d 100644 --- a/scripts/app/containers/nextcloud/nextcloud_tail_logs.sh +++ b/scripts/app/containers/nextcloud/nextcloud_tail_logs.sh @@ -9,5 +9,5 @@ appNextcloudTailLogs() { lines="$(authToolArg "$args" lines)" [[ -z "$lines" || ! "$lines" =~ ^[0-9]+$ ]] && lines=100 - sudo docker exec -u www-data nextcloud-service tail -n "$lines" /var/www/html/data/nextcloud.log 2>&1 + runFileOp docker exec -u www-data nextcloud-service tail -n "$lines" /var/www/html/data/nextcloud.log 2>&1 } diff --git a/scripts/app/containers/nextcloud/nextcloud_toggle_maintenance.sh b/scripts/app/containers/nextcloud/nextcloud_toggle_maintenance.sh index b7e7fb4..8793b92 100644 --- a/scripts/app/containers/nextcloud/nextcloud_toggle_maintenance.sh +++ b/scripts/app/containers/nextcloud/nextcloud_toggle_maintenance.sh @@ -12,7 +12,7 @@ appNextcloudToggleMaintenance() { [[ "$enable" == "true" ]] && target=--on local out - out=$(sudo docker exec -u www-data nextcloud-service php occ maintenance:mode $target 2>&1) + out=$(runFileOp docker exec -u www-data nextcloud-service php occ maintenance:mode $target 2>&1) if echo "$out" | grep -qi "maintenance mode (enabled\|already enabled\|disabled\|already disabled)"; then isSuccessful "Nextcloud maintenance mode $target." return 0 diff --git a/scripts/config/password/password_hash.sh b/scripts/config/password/password_hash.sh index 2ffd054..bd2acb5 100755 --- a/scripts/config/password/password_hash.sh +++ b/scripts/config/password/password_hash.sh @@ -19,7 +19,7 @@ hashPassword() if command -v docker &>/dev/null; then local bcrypt_hash - bcrypt_hash=$(sudo docker run --rm ghcr.io/wg-easy/wg-easy wgpw "$password" 2>/dev/null | tr -d '\n') + bcrypt_hash=$(runFileOp docker run --rm ghcr.io/wg-easy/wg-easy wgpw "$password" 2>/dev/null | tr -d '\n') if [[ -n "$bcrypt_hash" ]]; then bcrypt_hash=$(echo "$bcrypt_hash" | awk -F= '{print $NF}') local escaped_hash diff --git a/scripts/docker/app/compose/down_app.sh b/scripts/docker/app/compose/down_app.sh index 3e198bd..75f0733 100755 --- a/scripts/docker/app/compose/down_app.sh +++ b/scripts/docker/app/compose/down_app.sh @@ -44,7 +44,7 @@ dockerComposeDown() local result=$(dockerCommandRunInstallUser "cd $containers_dir$app_name && docker compose $setup_compose down" >/dev/null 2>&1) checkSuccess "Shutting down container for $app_name" elif [[ $mode == "rooted" ]]; then - local result=$(cd "$containers_dir$app_name" && sudo docker compose $setup_compose down >/dev/null 2>&1) + local result=$(cd "$containers_dir$app_name" && docker compose $setup_compose down >/dev/null 2>&1) checkSuccess "Shutting down container for $app_name" else isNotice "Unknown Docker install type '$mode' — cannot shut down $app_name." diff --git a/scripts/docker/app/compose/up_app.sh b/scripts/docker/app/compose/up_app.sh index 3e3aec6..33d59c1 100755 --- a/scripts/docker/app/compose/up_app.sh +++ b/scripts/docker/app/compose/up_app.sh @@ -119,7 +119,7 @@ dockerComposeUp() checkSuccess "Started container for $app_name" elif [[ $CFG_DOCKER_INSTALL_TYPE == "rooted" ]]; then isNotice "Starting container for $app_name, this may take a while..." - local result=$(cd "$containers_dir$app_name" && sudo COMPOSE_PROGRESS=plain docker compose $setup_compose up $_compose_quiet $_compose_build_flag -d) + local result=$(cd "$containers_dir$app_name" && COMPOSE_PROGRESS=plain docker compose $setup_compose up $_compose_quiet $_compose_build_flag -d) checkSuccess "Started container for $app_name" fi # Used for the CLI dockertype switcher. @@ -128,7 +128,7 @@ dockerComposeUp() local result=$(dockerCommandRunInstallUser "cd $containers_dir$app_name && docker compose $setup_compose down") checkSuccess "Shutting down container for $app_name" elif [[ $type == "rooted" ]]; then - local result=$(cd "$containers_dir$app_name" && sudo docker compose $setup_compose down) + local result=$(cd "$containers_dir$app_name" && docker compose $setup_compose down) checkSuccess "Shutting down container for $app_name" fi fi diff --git a/scripts/docker/app/uninstall/down_remove_app.sh b/scripts/docker/app/uninstall/down_remove_app.sh index 60a4896..e56cdb9 100755 --- a/scripts/docker/app/uninstall/down_remove_app.sh +++ b/scripts/docker/app/uninstall/down_remove_app.sh @@ -18,7 +18,7 @@ dockerComposeDownRemove() fi elif [[ $CFG_DOCKER_INSTALL_TYPE == "rooted" ]]; then if [[ -d "$containers_dir$app_name" ]]; then - local result=$(cd $containers_dir$app_name && sudo docker compose down -v --remove-orphans) + local result=$(cd $containers_dir$app_name && docker compose down -v --remove-orphans) isNotice "Shutting down & Removing all $app_name container data" dockerRemoveApp $app_name; else diff --git a/scripts/docker/app/uninstall/remove_images.sh b/scripts/docker/app/uninstall/remove_images.sh index 82d9ec9..a310078 100644 --- a/scripts/docker/app/uninstall/remove_images.sh +++ b/scripts/docker/app/uninstall/remove_images.sh @@ -19,7 +19,7 @@ dockerRemoveAppImages() if [[ $CFG_DOCKER_INSTALL_TYPE == "rootless" ]]; then compose_images=$(dockerCommandRunInstallUser "cd $compose_dir && docker compose config --images" 2>/dev/null) elif [[ $CFG_DOCKER_INSTALL_TYPE == "rooted" ]]; then - compose_images=$(cd "$compose_dir" && sudo docker compose config --images 2>/dev/null) + compose_images=$(cd "$compose_dir" && docker compose config --images 2>/dev/null) fi fi diff --git a/scripts/docker/checks/running_for_user.sh b/scripts/docker/checks/running_for_user.sh index ad30b0f..09d60dc 100755 --- a/scripts/docker/checks/running_for_user.sh +++ b/scripts/docker/checks/running_for_user.sh @@ -9,7 +9,7 @@ dockerCheckIsRunningForUser() local docker_command='docker ps 2>&1' local result=$(dockerCommandRunInstallUser "$docker_command") elif [[ $type == "rooted" ]]; then - local docker_command='sudo docker ps 2>&1' + local docker_command='docker ps 2>&1' local result=$(eval "$docker_command") else echo "Invalid user type specified." diff --git a/scripts/install/install_crowdsec.sh b/scripts/install/install_crowdsec.sh index c95b1a0..5ab0881 100644 --- a/scripts/install/install_crowdsec.sh +++ b/scripts/install/install_crowdsec.sh @@ -22,7 +22,7 @@ crowdsecToggleLibrePortalLogMounts() { *) isError "crowdsecToggleLibrePortalLogMounts: bad mode '$mode'"; return 1 ;; esac - if sudo docker ps --format '{{.Names}}' 2>/dev/null | grep -q '^libreportal-service$'; then + if runFileOp docker ps --format '{{.Names}}' 2>/dev/null | grep -q '^libreportal-service$'; then isNotice "Recreating libreportal so log mount toggle takes effect..." ( cd /docker/containers/libreportal && sudo -u libreportal docker compose up -d >/dev/null 2>&1 ) || true fi diff --git a/scripts/webui/webui_install_image.sh b/scripts/webui/webui_install_image.sh index 3e092ef..66c7067 100755 --- a/scripts/webui/webui_install_image.sh +++ b/scripts/webui/webui_install_image.sh @@ -12,6 +12,6 @@ installLibrePortalImageWebUI() reconcileWebuiDirOwnership isNotice "Building libreportal-service image, this may take a while..." - local result=$(sudo docker build -t libreportal-service -f $containers_dir/libreportal/Dockerfile $containers_dir/libreportal >/dev/null 2>&1) + local result=$(runFileOp docker build -t libreportal-service -f $containers_dir/libreportal/Dockerfile $containers_dir/libreportal >/dev/null 2>&1) checkSuccess "Built LibrePortal WebUI Docker image" } \ No newline at end of file