Skip to content

v1.1.16 — Upgrade resilience: dirty-worktree preflight + orphan-container cleanup

Choose a tag to compare

@MKippen MKippen released this 14 May 00:55
· 49 commits to main since this release
b97d9e9

Fixed

  • Upgrade aborted with Your local changes to scripts/upgrade.sh would be overwritten by checkout when a tracked file had been hot-patched on the host (via SCP, an editor, or anything that wrote bytes without committing). The bug was visible in the wild during the v1.1.15 rollout: the 2026-05-09 SCP'd COMPOSE_PROJECT_NAME fix left scripts/upgrade.sh dirty, and every subsequent git checkout v1.1.X bailed with git's raw stderr. New preflight in scripts/upgrade.sh:
    • For each locally-modified tracked file, compare the working-tree bytes to what the target tag would install. If equal — the local edit is redundant — silently discard it (git checkout HEAD -- <file>) and continue. This is the SCP-hotfix shape and now auto-resolves.
    • If different — refuse upgrade with each path named, plus the exact git checkout HEAD -- <file> command to discard each one, plus a mention of the new --force-clean flag.
  • Upgrade aborted with Conflict. The container name "/zeroproof-mqtt" is already in use when a stopped container from a different compose project (typically the legacy repo_* project from before COMPOSE_PROJECT_NAME was pinned) held one of our hardcoded container_name: values. The v1.1.14 fix only resolved the parallel-project case; orphans outliving a botched run still wedged every retry. scripts/upgrade.sh now scans docker-compose.yml for declared container_name: values before every compose up and removes any matching container whose com.docker.compose.project label is not ours. Containers with no compose-project label are surfaced as a warning, not auto-removed — those look operator-managed and silently nuking them would be a different class of bug.
  • --check mode now actually validates the worktree. The pre-existing untracked-file preflight (added in v1.1.5) and the new dirty-file preflight were both running after the --check early-exit, so --check would happily report "no changes applied" even when the real upgrade was about to wedge. Both preflights now run before the --check exit, with --check-aware "Would …" output so --check stays strictly read-only.

Added

  • --force-clean flag on scripts/upgrade.sh: discards locally-modified tracked files that differ from the target instead of refusing. Documented in --help. Intended for operators who've reviewed the diff and want to proceed.
  • Two new CI jobs in install-smoke.yml that prevent regression of both fixes above:
    • worktree-drift — unit-style: three scenarios (refuse + named file, --force-clean succeeds, redundant edit auto-discards) executed against the PR's upgrade.sh in --check mode.
    • orphan-cleanup — end-to-end: installs the previous release, seeds a stopped container labelled com.docker.compose.project=ci-foreign-project named zeroproof-mqtt, then runs the PR's upgrade.sh and asserts the orphan was removed transparently and /health still answers.

Upgrade notes

  • No manual action required. Operators already on v1.1.15 pick this up the next time they upgrade — and the new preflight will auto-resolve any redundant local edits to tracked files (which is exactly the residue the v1.1.15 → v1.1.16 upgrade is shaped to hit if you'd hot-patched anything on the host).