fix(self-hosted): avoid overwriting update.sh (#48690)

This commit is contained in:
Andrey A. authored and GitHub committed 2026-08-04 21:56:44 +02:00
1 parent b9053794a0
commit a8a0a66853
2 files changed
+68 -8

No files matched your search

+34
View File
@@ -339,6 +339,40 @@ assert_file_missing_pattern ".env" "NEW_KEY" "malformed manife
assert_path_absent "backups" "malformed manifest: no backup taken"
assert_file_contains ".supabase-version" "ref=self-hosted/v0.9.0" "malformed manifest: stamp not advanced"
echo ""
echo "=== update.sh: never overwrites the running script; stages the target's copy as .dist ==="
# A dedicated upstream whose docker/ ships an update.sh that DIFFERS from the one
# we run, so the merge must divert it to update.sh.dist rather than rewrite the
# live script mid-run (which would corrupt this process).
SELFSRC="$WORK/selfsrc"
mkdir -p "$SELFSRC/docker"
cd "$SELFSRC"
git init -q
git config user.email t@t.t
git config user.name t
printf 'services:\n db:\n image: x\n' > docker/docker-compose.yml
printf 'KEEP=1\n' > docker/.env.example
cp "$DOCKER_DIR/.gitignore" docker/.gitignore
printf '#!/bin/sh\necho THIS-IS-THE-NEW-UPDATE-SH\n' > docker/update.sh
git add -A && git commit -qm self && git tag self-hosted/v2.0.0
SELFDEP="$WORK/selfdep"
mkdir -p "$SELFDEP"
printf 'services:\n db:\n image: x\n' > "$SELFDEP/docker-compose.yml"
printf 'KEEP=1\n' > "$SELFDEP/.env"
cp "$UPDATE_SH" "$SELFDEP/update.sh" # the running script = the real update.sh
printf 'ref=self-hosted/v2.0.0\n' > "$SELFDEP/.supabase-version"
cd "$SELFDEP"
rc=0
SUPABASE_REPO_URL="$SELFSRC" sh ./update.sh --to self-hosted/v2.0.0 --yes > "$WORK/self.log" 2>&1 || rc=$?
if [ "$rc" = "0" ]; then ok "self-update run exits 0"; else bad "expected exit 0, got $rc"; fi
if cmp -s ./update.sh "$UPDATE_SH"; then ok "running update.sh left byte-identical"; else bad "running update.sh was modified in place"; fi
assert_no_line "./update.sh" '^(<<<<<<<|=======|>>>>>>>)' "no conflict markers written into the running update.sh"
assert_path_exists "$SELFDEP/update.sh.dist" "target's update.sh staged as update.sh.dist"
assert_file_contains "$SELFDEP/update.sh.dist" "THIS-IS-THE-NEW-UPDATE-SH" "update.sh.dist holds the target's version"
assert_file_contains "$WORK/self.log" "update.sh.dist" "summary points the user at update.sh.dist"
# --- summary -----------------------------------------------------------------
echo ""
+34 -8
View File
@@ -70,6 +70,7 @@ cd "$(dirname "$0")"
REPO_URL="${SUPABASE_REPO_URL:-https://github.com/supabase/supabase}"
STAMP_FILE=".supabase-version"
SELF_NAME=$(basename "$0")
DRY_RUN=0
ASSUME_YES=0
TO_REF=""
@@ -177,7 +178,7 @@ fetch_snapshot() {
_dest="$2"
_work=$(mktemp -d "$TMP_ROOT/fetch.XXXXXX")
if _sparse_init "$_work" \
&& git -C "$_work" fetch --depth=1 -q origin "$_ref" 2>/dev/null \
&& git -C "$_work" fetch --depth=1 --filter=blob:none -q origin "$_ref" 2>/dev/null \
&& git -C "$_work" checkout -q FETCH_HEAD 2>/dev/null \
&& [ -d "$_work/docker" ]; then
mkdir -p "$_dest"
@@ -311,9 +312,8 @@ $(grep -E '^[A-Za-z_][A-Za-z0-9_]*=' "$TARGET_DIR/.env.example" | cut -d= -f1)
EOF
fi
echo ""
warn "This is NOT the full update. To see what would actually change (updated files,"
warn "conflicts, breaking-change gate), record a base version - see the guidance above -"
warn "then re-run. Nothing was written."
warn "This is NOT the full update. To see what would actually change, record a base version."
warn "See the guidance above and re-run the script. Nothing was written."
}
# --- breaking-change gate (manifest-driven, before any writes) ---------------
@@ -333,9 +333,9 @@ build_gate_report() {
fi
if [ -z "$BASE_VER" ] || [ -z "$TARGET_VER" ]; then
warn "Base or target is not a self-hosted/vX.Y.Z tag; cannot compute an exact"
warn "update window. Showing all applicable manual-action releases - review"
warn "which ones apply to your deployment."
warn "Base or target is not a self-hosted/vX.Y.Z tag; cannot compute an exact update window."
warn "Showing all applicable manual-action releases."
warn "Review which ones apply to your deployment."
fi
for k in $(jq -r 'keys[]' "$_manifest" 2>/dev/null); do
@@ -469,6 +469,19 @@ merge_one_file() {
fi
}
# The running script is a vendor file too, but overwriting it in place would
# corrupt this process (the shell reads $0 as it runs). Never write it directly:
# if the target ships a different version, stage it as <name>.dist to review.
stage_self_update() {
_t="$TARGET_DIR/$SELF_NAME"
if [ ! -f "$_t" ] || cmp -s "$SELF_NAME" "$_t"; then
record "unchanged" "$SELF_NAME"
return 0
fi
[ "$DRY_RUN" = "1" ] || cp -f "$_t" "$SELF_NAME.dist"
record "self-staged" "$SELF_NAME"
}
merge_vendor_files() {
_empty="$TMP_ROOT/empty"
: > "$_empty"
@@ -477,6 +490,10 @@ merge_vendor_files() {
while IFS= read -r f; do
[ -n "$f" ] || continue
is_excluded "$f" && continue
if [ "$f" = "$SELF_NAME" ]; then
stage_self_update
continue
fi
merge_one_file "$f" "$_empty"
done <<EOF
$( { list_files "$BASE_DIR"; list_files "$TARGET_DIR"; } | sort -u )
@@ -556,6 +573,15 @@ print_summary() {
log "Removed upstream but kept in place (you may no longer need these):"
list_status removed-upstream
fi
if [ "$(count_status self-staged)" != "0" ]; then
echo ""
if [ "$DRY_RUN" = "1" ]; then
log "$SELF_NAME differs from the version in '$TARGET_REF'; a real run would stage that version as $SELF_NAME.dist (the running script is never overwritten in place)."
else
log "$SELF_NAME differs from the version in '$TARGET_REF', staged as $SELF_NAME.dist (the running script was not modified)."
log "Review it, then swap it in if needed: mv $SELF_NAME.dist $SELF_NAME"
fi
fi
if [ -s "$ENV_ADDED" ]; then
echo ""
log ".env keys added (review values):"
@@ -586,7 +612,7 @@ write_stamp() {
print_next_steps() {
echo ""
log "Next steps:"
echo " 1. Review the changes (git diff, or compare against the backup in backups/)."
echo " 1. Review the changes above (compare against the latest backup in backups/ if needed)."
echo " 2. sh run.sh pull"
echo " 3. sh run.sh recreate"
}