diff --git a/deploy/deploy.sh b/deploy/deploy.sh index 73dfd8b..5954b87 100755 --- a/deploy/deploy.sh +++ b/deploy/deploy.sh @@ -26,11 +26,31 @@ warn() { printf '\033[1;33m !! %s\033[0m\n' "$*"; } cd "$REPO_DIR" # ---- 1. code --------------------------------------------------------------- -say "Fetching $BRANCH from $(git remote get-url origin)" -git fetch --prune origin -git checkout -q "$BRANCH" -git reset --hard "origin/$BRANCH" -echo "now at $(git log --oneline -1)" +# This script lives in the repo it updates, so `git reset --hard` rewrites the +# file bash is in the middle of reading. Bash reads a script incrementally and +# keeps a byte offset, so after the reset it resumes at that offset in the *new* +# file — silently skipping or garbling whatever the diff shifted. (That is not +# hypothetical: it is how the certbot renewal hook came to be committed, present +# on disk, and never executed.) +# +# So: stage one updates the checkout and re-execs a *copy* outside the repo, +# which nothing can rewrite underneath it. Stage two does the actual work. +if [[ ${KADENCE_DEPLOY_STAGE:-} != run ]]; then + say "Fetching $BRANCH from $(git remote get-url origin)" + git fetch --prune origin + git checkout -q "$BRANCH" + git reset --hard "origin/$BRANCH" + echo "now at $(git log --oneline -1)" + + staged=$(mktemp /tmp/kadence-deploy.XXXXXX.sh) + cat "$REPO_DIR/deploy/deploy.sh" > "$staged" + chmod +x "$staged" + export KADENCE_DEPLOY_STAGE=run KADENCE_DEPLOY_STAGED="$staged" + exec "$staged" "$@" +fi + +# Stage two: started from the copy, so clean it up on the way out. +trap '[[ -n ${KADENCE_DEPLOY_STAGED:-} ]] && rm -f "$KADENCE_DEPLOY_STAGED"' EXIT # ---- 2. secrets ------------------------------------------------------------ setkv() {