From d84f0c1af8673b0bda5e0e54bd9754af814aee95 Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Tue, 14 Jul 2026 18:05:13 +0530 Subject: [PATCH] fix: restore invoking user's ownership after sudo deploy scripts Co-Authored-By: Claude Fable 5 --- remote_up.sh | 15 +++++++++++++++ scripts/setup_custom_domain.sh | 10 ++++++++++ scripts/setup_remote.sh | 10 ++++++++++ scripts/update_remote.sh | 10 ++++++++++ 4 files changed, 45 insertions(+) diff --git a/remote_up.sh b/remote_up.sh index 01990067..b3274908 100755 --- a/remote_up.sh +++ b/remote_up.sh @@ -12,10 +12,21 @@ if [[ ! -f "$LIB_PATH" ]]; then LIB_PATH="$BOOTSTRAP_LIB" fi +# The preflight rewrites .env (awk + mv in dograh_set_env_key), so running this +# script via sudo leaves .env root-owned and later sudo-less edits fail. Hand +# the deploy dir back to the user who invoked sudo; a no-op for unprivileged +# runs and real root, where SUDO_UID is unset. +restore_ownership() { + if [[ -n "${SUDO_UID:-}" && -n "${SUDO_GID:-}" && -n "${DOGRAH_DEPLOY_PROJECT_DIR:-}" && -d "$DOGRAH_DEPLOY_PROJECT_DIR" ]]; then + chown -R "$SUDO_UID:$SUDO_GID" "$DOGRAH_DEPLOY_PROJECT_DIR" || true + fi +} + cleanup() { if [[ -n "$BOOTSTRAP_LIB" ]]; then rm -f "$BOOTSTRAP_LIB" fi + restore_ownership } trap cleanup EXIT @@ -91,4 +102,8 @@ if (( ${#EXTRA_ARGS[@]} )); then CMD+=("${EXTRA_ARGS[@]}") fi +# exec replaces the shell, so the EXIT trap never fires on the success path — +# restore ownership here; everything this script writes happens before this point. +restore_ownership + exec "${CMD[@]}" diff --git a/scripts/setup_custom_domain.sh b/scripts/setup_custom_domain.sh index 7d5962dd..f30de43a 100755 --- a/scripts/setup_custom_domain.sh +++ b/scripts/setup_custom_domain.sh @@ -22,6 +22,16 @@ cleanup() { if [[ -n "$BOOTSTRAP_LIB" ]]; then rm -f "$BOOTSTRAP_LIB" fi + # The script runs as root, so the files it touches in the install directory + # (.env rewrites, downloaded helper bundle, certs copied from Let's Encrypt) + # become root-owned, breaking later sudo-less git/edit operations. Hand the + # install back to the user who invoked sudo. SUDO_UID is unset when running + # as real root — nothing to restore then. Runs from the EXIT trap so a + # mid-setup failure also leaves ownership fixed. + if [[ -n "${SUDO_UID:-}" && -n "${SUDO_GID:-}" && -n "${DOGRAH_DEPLOY_PROJECT_DIR:-}" && -d "$DOGRAH_DEPLOY_PROJECT_DIR" ]]; then + echo -e "${BLUE}Restoring ownership of $DOGRAH_DEPLOY_PROJECT_DIR to ${SUDO_USER:-uid $SUDO_UID}...${NC}" + chown -R "$SUDO_UID:$SUDO_GID" "$DOGRAH_DEPLOY_PROJECT_DIR" || true + fi } trap cleanup EXIT diff --git a/scripts/setup_remote.sh b/scripts/setup_remote.sh index 0710aec0..13346f18 100755 --- a/scripts/setup_remote.sh +++ b/scripts/setup_remote.sh @@ -22,6 +22,16 @@ cleanup() { if [[ -n "$BOOTSTRAP_LIB" ]]; then rm -f "$BOOTSTRAP_LIB" fi + # The script runs as root, so everything it creates in the deploy directory + # (.env, certs/, a cloned repo in build mode) is root-owned, which breaks + # later sudo-less git/edit operations. Hand it back to the user who invoked + # sudo. SUDO_UID is unset when running as real root (e.g. cloud-init) — + # root already owns its files, nothing to restore. Runs from the EXIT trap + # so a mid-setup failure also leaves ownership fixed. + if [[ -n "${SUDO_UID:-}" && -n "${SUDO_GID:-}" && -n "${DOGRAH_DEPLOY_PROJECT_DIR:-}" && -d "$DOGRAH_DEPLOY_PROJECT_DIR" ]]; then + echo -e "${BLUE}Restoring ownership of $DOGRAH_DEPLOY_PROJECT_DIR to ${SUDO_USER:-uid $SUDO_UID}...${NC}" + chown -R "$SUDO_UID:$SUDO_GID" "$DOGRAH_DEPLOY_PROJECT_DIR" || true + fi } trap cleanup EXIT diff --git a/scripts/update_remote.sh b/scripts/update_remote.sh index eef2dc75..5e793524 100755 --- a/scripts/update_remote.sh +++ b/scripts/update_remote.sh @@ -22,6 +22,16 @@ cleanup() { if [[ -n "$BOOTSTRAP_LIB" ]]; then rm -f "$BOOTSTRAP_LIB" fi + # When run via sudo (the common case: docker access, root-owned installs), + # the refreshed deployment files and the rewritten .env become root-owned, + # breaking later sudo-less edits. Hand the install back to the user who + # invoked sudo; a no-op for unprivileged runs and real root, where SUDO_UID + # is unset. Runs from the EXIT trap so a mid-update failure also leaves + # ownership fixed. + if [[ -n "${SUDO_UID:-}" && -n "${SUDO_GID:-}" && -n "${DOGRAH_DEPLOY_PROJECT_DIR:-}" && -d "$DOGRAH_DEPLOY_PROJECT_DIR" ]]; then + echo -e "${BLUE}Restoring ownership of $DOGRAH_DEPLOY_PROJECT_DIR to ${SUDO_USER:-uid $SUDO_UID}...${NC}" + chown -R "$SUDO_UID:$SUDO_GID" "$DOGRAH_DEPLOY_PROJECT_DIR" || true + fi } trap cleanup EXIT