From 48ed9c23818a29cafd19aae641bc0e03907070e8 Mon Sep 17 00:00:00 2001 From: ogt Date: Thu, 9 Jul 2026 18:38:53 +0800 Subject: [PATCH] fix(backup): support ssh gitea bundle remotes --- ...t_gitea_repo_bundle_backup_readback_api.py | 4 +++ scripts/backup/gitea-repo-bundle-backup.sh | 26 ++++++++++++++++--- .../test_reboot_p0_operational_contract.py | 3 +++ 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/apps/api/tests/test_gitea_repo_bundle_backup_readback_api.py b/apps/api/tests/test_gitea_repo_bundle_backup_readback_api.py index f2147eddd..5c3a3b557 100644 --- a/apps/api/tests/test_gitea_repo_bundle_backup_readback_api.py +++ b/apps/api/tests/test_gitea_repo_bundle_backup_readback_api.py @@ -1,5 +1,9 @@ from __future__ import annotations +import os + +os.environ.setdefault("DATABASE_URL", "postgresql+asyncpg://test:test@localhost/test") + from fastapi import FastAPI from fastapi.testclient import TestClient diff --git a/scripts/backup/gitea-repo-bundle-backup.sh b/scripts/backup/gitea-repo-bundle-backup.sh index 7e16a2fac..b27f0fbfd 100755 --- a/scripts/backup/gitea-repo-bundle-backup.sh +++ b/scripts/backup/gitea-repo-bundle-backup.sh @@ -1,11 +1,12 @@ #!/usr/bin/env bash -# Create emergency Git bundle backups from Gitea over Git HTTP. +# Create emergency Git bundle backups from Gitea over a non-interactive Git remote. # This is a repository-history fallback only. It does not replace `gitea dump`, # does not back up Gitea DB rows, settings, issues, packages, secrets, or LFS. set -euo pipefail GITEA_BASE_URL="${GITEA_BASE_URL:-http://192.168.0.110:3001}" +GIT_REMOTE_BASE="${GIT_REMOTE_BASE:-}" OUTPUT_ROOT="${OUTPUT_ROOT:-/home/ollama/backup/110/gitea/git-bundles}" TIMEOUT_LS_REMOTE_SECONDS="${TIMEOUT_LS_REMOTE_SECONDS:-60}" TIMEOUT_CLONE_SECONDS="${TIMEOUT_CLONE_SECONDS:-180}" @@ -23,12 +24,16 @@ Options: --repo OWNER/NAME Repository to bundle. May be passed more than once. --output-root PATH Bundle root. Default: /home/ollama/backup/110/gitea/git-bundles --gitea-base URL Gitea base URL. Default: http://192.168.0.110:3001 + --git-remote-base URL + Git remote base, such as ssh://git@192.168.0.110:2222. + When set, it is used instead of --gitea-base. --stamp STAMP Output directory stamp. Default: current local timestamp. --dry-run Print target URLs without cloning or writing bundles. -h, --help Show this help. This script uses GIT_TERMINAL_PROMPT=0 and never asks for, reads, or prints -tokens or passwords. Private repositories without an existing credential fail +tokens or passwords. Private repositories without an existing non-interactive +credential or SSH key fail closed in the manifest. USAGE } @@ -47,6 +52,10 @@ while [ "$#" -gt 0 ]; do shift GITEA_BASE_URL="${1:?--gitea-base requires URL}" ;; + --git-remote-base) + shift + GIT_REMOTE_BASE="${1:?--git-remote-base requires URL}" + ;; --stamp) shift STAMP="${1:?--stamp requires value}" @@ -84,9 +93,18 @@ if [ "${#REPOS[@]}" -eq 0 ]; then ) fi +repo_remote_url() { + repo="$1" + if [ -n "$GIT_REMOTE_BASE" ]; then + printf '%s/%s.git\n' "${GIT_REMOTE_BASE%/}" "$repo" + return + fi + printf '%s/%s.git\n' "${GITEA_BASE_URL%/}" "$repo" +} + if [ "$DRY_RUN" -eq 1 ]; then for repo in "${REPOS[@]}"; do - printf 'DRY_RUN repo=%s url=%s/%s.git\n' "$repo" "$GITEA_BASE_URL" "$repo" + printf 'DRY_RUN repo=%s url=%s\n' "$repo" "$(repo_remote_url "$repo")" done exit 0 fi @@ -101,7 +119,7 @@ printf 'repo\tstatus\thead_count\tbundle\tchecksum\n' > "$manifest" for repo in "${REPOS[@]}"; do slug="${repo//\//__}" - url="${GITEA_BASE_URL%/}/${repo}.git" + url="$(repo_remote_url "$repo")" refs_file="${backup_root}/${slug}.refs" err_file="${backup_root}/${slug}.err" bundle_file="${backup_root}/${slug}.bundle" diff --git a/scripts/reboot-recovery/tests/test_reboot_p0_operational_contract.py b/scripts/reboot-recovery/tests/test_reboot_p0_operational_contract.py index 3f3a301d8..35b31b19b 100644 --- a/scripts/reboot-recovery/tests/test_reboot_p0_operational_contract.py +++ b/scripts/reboot-recovery/tests/test_reboot_p0_operational_contract.py @@ -470,6 +470,9 @@ def test_gitea_repo_bundle_backup_is_non_interactive_and_manifested() -> None: restore_script = read("scripts/backup/gitea-bundle-sample-restore-dry-run.sh") assert "GIT_TERMINAL_PROMPT=0" in script + assert "GIT_REMOTE_BASE" in script + assert "--git-remote-base" in script + assert "repo_remote_url" in script assert "bundle create" in script assert "bundle verify" in script assert ".sha256" in script