#!/usr/bin/env bash # # D004 — conflict-free deployment update wrapper. # # Updates a deployed instance with `git pull` WITHOUT ever hitting a merge # conflict from files a scan wrote since the last pull. Guarantees: # # 1. Refuses to update over uncommitted tracked changes (clean-tree guard). # 2. Fast-forwards only (--ff-only): never creates merge commits and never # silently conflicts. # 3. Runtime data (data/, reports/, *.db) is gitignored, so a running scan # leaves no dirty tracked paths and never blocks the pull. # 4. Reinstalls dependencies only if requirements.txt changed. # 5. Applies DB migrations idempotently. # 6. Restarts the app under its supervisor. # # Usage: # sudo deploy/deploy.sh # update + restart (default env: production) # ENV=production deploy/deploy.sh # use deploy/ids@production.service # deploy/deploy.sh --no-restart # update deps+migrate but don't restart set -euo pipefail cd "$(dirname "$0")/.." ENV="${ENV:-production}" RESTART="${1:-restart}" ROOT="$(pwd)" PY="${PY:-python}" echo "== Intrusion Detection deploy (env=$ENV) ==" # 1) Clean-tree guard. Runtime data is gitignored, so this only fails if a # human edited tracked source without committing. if ! git diff --quiet HEAD || ! git diff --cached --quiet; then echo "REFUSING: working tree is not clean." >&2 echo "Commit or stash tracked changes, then re-run." >&2 echo " git status --short" >&2 exit 1 fi # 2) Pre-flight: prove runtime isolation holds (fail fast before touching repo). if "$ROOT/deploy/check_runtime_git.sh"; then echo "== runtime isolation ok ==" else echo "ABORT: runtime isolation check failed." >&2 exit 1 fi # 3) Fast-forward only. echo "== fetching upstream ==" git fetch origin echo "== fast-forward pull ==" git pull --ff-only # 4) Dependencies (only if the requirement set changed since the last pull). if git diff --quiet HEAD@{1} HEAD -- requirements.txt; then echo "== requirements.txt unchanged; skipping pip ==" else echo "== requirements.txt changed; installing deps ==" command -v "$PY" >/dev/null && "$PY" -m pip install -r requirements.txt \ || pip install -r requirements.txt fi # 5) Apply DB migrations (idempotent). echo "== applying DB migrations ==" "$PY" -m app.db --migrate # 6) Restart under the supervisor. if [[ "$RESTART" == "--no-restart" ]]; then echo "== --no-restart: update complete; restart manually ==" else echo "== restarting service ==" "$ROOT/deploy/restart-service.sh" "$ENV" fi echo "== deploy complete =="