Release v1.0.0
Some checks failed
CI / Migrations, tests, build, and audit (push) Failing after 10m7s
CI / Production gate and container images (push) Successful in 20m35s

This commit is contained in:
2026-07-31 14:21:43 +08:00
commit 36f466ba11
187 changed files with 98907 additions and 0 deletions

View File

@@ -0,0 +1,76 @@
#!/usr/bin/env bash
set -Eeuo pipefail
usage() {
cat >&2 <<'EOF'
Usage: scheduled-maintenance.sh <backup|restore-latest>
Requires FRAMEFLOW_BACKUP_MOUNTPOINT and FRAMEFLOW_BACKUP_DESTINATION.
The destination must be a writable directory inside the active mount point.
EOF
exit "${1:-2}"
}
fail() {
echo "Scheduled maintenance failed: $1" >&2
exit 1
}
[[ $# -eq 1 ]] || usage
case "$1" in
backup|restore-latest) mode="$1" ;;
--help|-h) usage 0 ;;
*) usage ;;
esac
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
mount_point="${FRAMEFLOW_BACKUP_MOUNTPOINT:-}"
backup_destination="${FRAMEFLOW_BACKUP_DESTINATION:-}"
[[ -n "${mount_point}" ]] || fail "FRAMEFLOW_BACKUP_MOUNTPOINT is required"
[[ -n "${backup_destination}" ]] || fail "FRAMEFLOW_BACKUP_DESTINATION is required"
for path in "${mount_point}" "${backup_destination}"; do
[[ "${path}" == /* ]] || fail "backup paths must be absolute: ${path}"
[[ "${path}" != "/" ]] || fail "the filesystem root cannot be used for backups"
[[ ! "${path}" =~ [[:space:]] ]] || fail "backup paths must not contain whitespace: ${path}"
[[ -d "${path}" ]] || fail "backup directory does not exist: ${path}"
[[ ! -L "${path}" ]] || fail "backup paths must not be symbolic links: ${path}"
done
mount_point="$(cd "${mount_point}" && pwd -P)"
backup_destination="$(cd "${backup_destination}" && pwd -P)"
if [[ "${backup_destination}" != "${mount_point}" && "${backup_destination}" != "${mount_point}/"* ]]; then
fail "backup destination must be inside FRAMEFLOW_BACKUP_MOUNTPOINT"
fi
[[ -w "${backup_destination}" ]] || fail "backup destination is not writable: ${backup_destination}"
command -v findmnt >/dev/null 2>&1 || fail "findmnt is required to verify the backup mount"
mounted_target="$(findmnt -rn -M "${mount_point}" -o TARGET 2>/dev/null)" \
|| fail "backup mount is not active: ${mount_point}"
[[ "${mounted_target}" == "${mount_point}" ]] \
|| fail "backup mount resolved to an unexpected target: ${mounted_target}"
case "${mode}" in
backup)
exec "${script_dir}/backup.sh" "${backup_destination}"
;;
restore-latest)
latest_name=""
latest_path=""
while IFS= read -r -d '' candidate; do
[[ ! -L "${candidate}" ]] || continue
candidate_name="${candidate##*/}"
[[ "${candidate_name}" =~ ^frameflow-[0-9]{8}T[0-9]{6}Z$ ]] || continue
if [[ -z "${latest_name}" || "${candidate_name}" > "${latest_name}" ]]; then
latest_name="${candidate_name}"
latest_path="${candidate}"
fi
done < <(find "${backup_destination}" -mindepth 1 -maxdepth 1 -type d -name 'frameflow-*' -print0)
[[ -n "${latest_path}" ]] || fail "no timestamped FrameFlow backup was found"
echo "Selected latest backup for restore rehearsal: ${latest_path}"
"${script_dir}/verify-backup.sh" "${latest_path}"
exec "${script_dir}/rehearse-restore.sh" "${latest_path}"
;;
esac