From 5ce3a234f347d61c12725f5aad9fc9832ba2f18a Mon Sep 17 00:00:00 2001 From: S Date: Sat, 28 Feb 2026 22:09:21 -0500 Subject: [PATCH] fix: harden phase auth and failure handling --- phase5_migrate_pipelines.sh | 37 ++++++++++++++++++++++++++++++++----- phase5_teardown.sh | 34 +++++++++++++++++++++++++++++++--- phase6_github_mirrors.sh | 2 +- phase8_cutover.sh | 6 ++++++ phase9_security.sh | 34 +++++++++++++++++++++++++++++++--- phase9_teardown.sh | 34 +++++++++++++++++++++++++++++++--- 6 files changed, 132 insertions(+), 15 deletions(-) diff --git a/phase5_migrate_pipelines.sh b/phase5_migrate_pipelines.sh index 62d9e34..47e6d28 100755 --- a/phase5_migrate_pipelines.sh +++ b/phase5_migrate_pipelines.sh @@ -26,17 +26,46 @@ phase_header 5 "Migrate Pipelines (GitHub → Gitea Actions)" REPOS=("$REPO_1_NAME" "$REPO_2_NAME" "$REPO_3_NAME") TEMP_BASE="/tmp/gitea-migration" MIGRATION_HEADER="# Migrated from GitHub Actions — review for Gitea compatibility" +GITEA_BASE_URL="${GITEA_INTERNAL_URL%/}" +ASKPASS_SCRIPT="" # Clean up temp directory on exit (even on failure) cleanup() { rm -rf "$TEMP_BASE" + if [[ -n "$ASKPASS_SCRIPT" ]]; then + rm -f "$ASKPASS_SCRIPT" + fi } trap cleanup EXIT +# Use ephemeral askpass auth so tokens are never embedded in git remote URLs. +setup_git_auth() { + ASKPASS_SCRIPT=$(mktemp) + cat > "$ASKPASS_SCRIPT" <<'EOF' +#!/usr/bin/env sh +case "$1" in + *sername*) printf '%s\n' "$GITEA_GIT_USERNAME" ;; + *assword*) printf '%s\n' "$GITEA_GIT_TOKEN" ;; + *) printf '\n' ;; +esac +EOF + chmod 700 "$ASKPASS_SCRIPT" +} + +git_with_auth() { + GIT_TERMINAL_PROMPT=0 \ + GIT_ASKPASS="$ASKPASS_SCRIPT" \ + GITEA_GIT_USERNAME="$GITEA_ADMIN_USER" \ + GITEA_GIT_TOKEN="$GITEA_ADMIN_TOKEN" \ + "$@" +} + SUCCESS=0 SKIPPED=0 FAILED=0 +setup_git_auth + for repo in "${REPOS[@]}"; do log_info "--- Processing repo: ${repo} ---" @@ -58,11 +87,9 @@ for repo in "${REPOS[@]}"; do rm -rf "$CLONE_DIR" mkdir -p "$CLONE_DIR" - # Construct clone URL with embedded token for auth - # Format: http://token:TOKEN@host:port/org/repo.git - CLONE_URL="${GITEA_INTERNAL_URL%%://*}://${GITEA_ADMIN_USER}:${GITEA_ADMIN_TOKEN}@${GITEA_INTERNAL_URL#*://}" + REPO_URL="${GITEA_BASE_URL}/${GITEA_ORG_NAME}/${repo}.git" log_info "Cloning ${repo}..." - git clone -q "${CLONE_URL}/${GITEA_ORG_NAME}/${repo}.git" "$CLONE_DIR" + git_with_auth git clone -q "$REPO_URL" "$CLONE_DIR" # ------------------------------------------------------------------------- # Step 2: Check for GitHub workflows @@ -137,7 +164,7 @@ for repo in "${REPOS[@]}"; do git config user.email "migration@gitea.local" git add .gitea/ git commit -q -m "Migrate workflows to Gitea Actions" - git push -q origin HEAD + git_with_auth git push -q origin HEAD cd "$SCRIPT_DIR" log_success "Workflows migrated for ${repo}" diff --git a/phase5_teardown.sh b/phase5_teardown.sh index c31f19e..1fb7e87 100755 --- a/phase5_teardown.sh +++ b/phase5_teardown.sh @@ -19,12 +19,38 @@ log_warn "=== Phase 5 Teardown: Remove Gitea Workflows ===" REPOS=("$REPO_1_NAME" "$REPO_2_NAME" "$REPO_3_NAME") TEMP_BASE="/tmp/gitea-migration-teardown" +GITEA_BASE_URL="${GITEA_INTERNAL_URL%/}" +ASKPASS_SCRIPT="" cleanup() { rm -rf "$TEMP_BASE" + if [[ -n "$ASKPASS_SCRIPT" ]]; then + rm -f "$ASKPASS_SCRIPT" + fi } trap cleanup EXIT +setup_git_auth() { + ASKPASS_SCRIPT=$(mktemp) + cat > "$ASKPASS_SCRIPT" <<'EOF' +#!/usr/bin/env sh +case "$1" in + *sername*) printf '%s\n' "$GITEA_GIT_USERNAME" ;; + *assword*) printf '%s\n' "$GITEA_GIT_TOKEN" ;; + *) printf '\n' ;; +esac +EOF + chmod 700 "$ASKPASS_SCRIPT" +} + +git_with_auth() { + GIT_TERMINAL_PROMPT=0 \ + GIT_ASKPASS="$ASKPASS_SCRIPT" \ + GITEA_GIT_USERNAME="$GITEA_ADMIN_USER" \ + GITEA_GIT_TOKEN="$GITEA_ADMIN_TOKEN" \ + "$@" +} + printf 'This will remove .gitea/workflows/ from all repos. Continue? [y/N] ' read -r confirm if [[ ! "$confirm" =~ ^[Yy]$ ]]; then @@ -32,6 +58,8 @@ if [[ ! "$confirm" =~ ^[Yy]$ ]]; then exit 0 fi +setup_git_auth + for repo in "${REPOS[@]}"; do log_info "--- Processing: ${repo} ---" @@ -45,8 +73,8 @@ for repo in "${REPOS[@]}"; do CLONE_DIR="${TEMP_BASE}/${repo}" rm -rf "$CLONE_DIR" - CLONE_URL="${GITEA_INTERNAL_URL%%://*}://${GITEA_ADMIN_USER}:${GITEA_ADMIN_TOKEN}@${GITEA_INTERNAL_URL#*://}" - git clone -q "${CLONE_URL}/${GITEA_ORG_NAME}/${repo}.git" "$CLONE_DIR" + REPO_URL="${GITEA_BASE_URL}/${GITEA_ORG_NAME}/${repo}.git" + git_with_auth git clone -q "$REPO_URL" "$CLONE_DIR" if [[ -d "${CLONE_DIR}/.gitea/workflows" ]]; then rm -rf "${CLONE_DIR}/.gitea/workflows" @@ -55,7 +83,7 @@ for repo in "${REPOS[@]}"; do git config user.email "migration@gitea.local" git add -A git commit -q -m "Remove Gitea Actions workflows (teardown)" - git push -q origin HEAD + git_with_auth git push -q origin HEAD cd "$SCRIPT_DIR" log_success "Removed .gitea/workflows/ from ${repo}" else diff --git a/phase6_github_mirrors.sh b/phase6_github_mirrors.sh index 602e7ad..b6bd6a3 100755 --- a/phase6_github_mirrors.sh +++ b/phase6_github_mirrors.sh @@ -18,7 +18,7 @@ source "${SCRIPT_DIR}/lib/common.sh" load_env require_vars GITEA_ADMIN_TOKEN GITEA_INTERNAL_URL GITEA_ORG_NAME \ - GITHUB_USERNAME GITHUB_MIRROR_TOKEN GITHUB_MIRROR_INTERVAL \ + GITHUB_USERNAME GITHUB_TOKEN GITHUB_MIRROR_TOKEN GITHUB_MIRROR_INTERVAL \ REPO_1_NAME REPO_2_NAME REPO_3_NAME phase_header 6 "GitHub Push Mirrors" diff --git a/phase8_cutover.sh b/phase8_cutover.sh index 750b911..4287836 100755 --- a/phase8_cutover.sh +++ b/phase8_cutover.sh @@ -369,6 +369,7 @@ fi log_step 11 "Marking GitHub repos as offsite backup..." init_phase8_state_store +GITHUB_REPO_UPDATE_FAILURES=0 for repo in "${REPOS[@]}"; do # Fetch repo metadata (single API call) REPO_DATA=$(github_api GET "/repos/${GITHUB_USERNAME}/${repo}" 2>/dev/null || echo "{}") @@ -403,6 +404,7 @@ for repo in "${REPOS[@]}"; do log_success "Marked GitHub repo as mirror: ${repo}" else log_error "Failed to update GitHub repo: ${repo}" + GITHUB_REPO_UPDATE_FAILURES=$((GITHUB_REPO_UPDATE_FAILURES + 1)) fi # Disable GitHub Pages if enabled (Pages can incur bandwidth costs) @@ -413,5 +415,9 @@ done # Summary # --------------------------------------------------------------------------- printf '\n' +if [[ "$GITHUB_REPO_UPDATE_FAILURES" -gt 0 ]]; then + log_error "Phase 8 failed: ${GITHUB_REPO_UPDATE_FAILURES} GitHub repo update(s) failed" + exit 1 +fi log_success "Phase 8 complete — Gitea is live at https://${GITEA_DOMAIN}" log_info "GitHub repos marked as offsite backup. Push mirrors remain active." diff --git a/phase9_security.sh b/phase9_security.sh index 8bb338a..cef23c3 100755 --- a/phase9_security.sh +++ b/phase9_security.sh @@ -29,16 +29,44 @@ phase_header 9 "Security Scanning" REPOS=("$REPO_1_NAME" "$REPO_2_NAME" "$REPO_3_NAME") TEMP_BASE="/tmp/gitea-migration-security" +GITEA_BASE_URL="${GITEA_INTERNAL_URL%/}" +ASKPASS_SCRIPT="" cleanup() { rm -rf "$TEMP_BASE" + if [[ -n "$ASKPASS_SCRIPT" ]]; then + rm -f "$ASKPASS_SCRIPT" + fi } trap cleanup EXIT +setup_git_auth() { + ASKPASS_SCRIPT=$(mktemp) + cat > "$ASKPASS_SCRIPT" <<'EOF' +#!/usr/bin/env sh +case "$1" in + *sername*) printf '%s\n' "$GITEA_GIT_USERNAME" ;; + *assword*) printf '%s\n' "$GITEA_GIT_TOKEN" ;; + *) printf '\n' ;; +esac +EOF + chmod 700 "$ASKPASS_SCRIPT" +} + +git_with_auth() { + GIT_TERMINAL_PROMPT=0 \ + GIT_ASKPASS="$ASKPASS_SCRIPT" \ + GITEA_GIT_USERNAME="$GITEA_ADMIN_USER" \ + GITEA_GIT_TOKEN="$GITEA_ADMIN_TOKEN" \ + "$@" +} + SUCCESS=0 SKIPPED=0 FAILED=0 +setup_git_auth + for repo in "${REPOS[@]}"; do log_info "--- Processing repo: ${repo} ---" @@ -58,9 +86,9 @@ for repo in "${REPOS[@]}"; do rm -rf "$CLONE_DIR" mkdir -p "$CLONE_DIR" - CLONE_URL="${GITEA_INTERNAL_URL%%://*}://${GITEA_ADMIN_USER}:${GITEA_ADMIN_TOKEN}@${GITEA_INTERNAL_URL#*://}" + REPO_URL="${GITEA_BASE_URL}/${GITEA_ORG_NAME}/${repo}.git" log_info "Cloning ${repo}..." - git clone -q "${CLONE_URL}/${GITEA_ORG_NAME}/${repo}.git" "$CLONE_DIR" + git_with_auth git clone -q "$REPO_URL" "$CLONE_DIR" # ------------------------------------------------------------------------- # Step 2: Render security workflow template @@ -82,7 +110,7 @@ for repo in "${REPOS[@]}"; do git config user.email "migration@gitea.local" git add .gitea/workflows/security-scan.yml git commit -q -m "Add security scanning workflow (Semgrep + Trivy + Gitleaks)" - git push -q origin HEAD + git_with_auth git push -q origin HEAD cd "$SCRIPT_DIR" log_success "Security workflow deployed to ${repo}" diff --git a/phase9_teardown.sh b/phase9_teardown.sh index 17de01c..2bbe2ac 100755 --- a/phase9_teardown.sh +++ b/phase9_teardown.sh @@ -20,12 +20,38 @@ log_warn "=== Phase 9 Teardown: Security Scanning ===" REPOS=("$REPO_1_NAME" "$REPO_2_NAME" "$REPO_3_NAME") TEMP_BASE="/tmp/gitea-migration-security-teardown" +GITEA_BASE_URL="${GITEA_INTERNAL_URL%/}" +ASKPASS_SCRIPT="" cleanup() { rm -rf "$TEMP_BASE" + if [[ -n "$ASKPASS_SCRIPT" ]]; then + rm -f "$ASKPASS_SCRIPT" + fi } trap cleanup EXIT +setup_git_auth() { + ASKPASS_SCRIPT=$(mktemp) + cat > "$ASKPASS_SCRIPT" <<'EOF' +#!/usr/bin/env sh +case "$1" in + *sername*) printf '%s\n' "$GITEA_GIT_USERNAME" ;; + *assword*) printf '%s\n' "$GITEA_GIT_TOKEN" ;; + *) printf '\n' ;; +esac +EOF + chmod 700 "$ASKPASS_SCRIPT" +} + +git_with_auth() { + GIT_TERMINAL_PROMPT=0 \ + GIT_ASKPASS="$ASKPASS_SCRIPT" \ + GITEA_GIT_USERNAME="$GITEA_ADMIN_USER" \ + GITEA_GIT_TOKEN="$GITEA_ADMIN_TOKEN" \ + "$@" +} + printf 'This will remove security-scan.yml from all repos. Continue? [y/N] ' read -r confirm if [[ ! "$confirm" =~ ^[Yy]$ ]]; then @@ -33,6 +59,8 @@ if [[ ! "$confirm" =~ ^[Yy]$ ]]; then exit 0 fi +setup_git_auth + for repo in "${REPOS[@]}"; do log_info "--- Processing: ${repo} ---" @@ -46,8 +74,8 @@ for repo in "${REPOS[@]}"; do CLONE_DIR="${TEMP_BASE}/${repo}" rm -rf "$CLONE_DIR" - CLONE_URL="${GITEA_INTERNAL_URL%%://*}://${GITEA_ADMIN_USER}:${GITEA_ADMIN_TOKEN}@${GITEA_INTERNAL_URL#*://}" - git clone -q "${CLONE_URL}/${GITEA_ORG_NAME}/${repo}.git" "$CLONE_DIR" + REPO_URL="${GITEA_BASE_URL}/${GITEA_ORG_NAME}/${repo}.git" + git_with_auth git clone -q "$REPO_URL" "$CLONE_DIR" if [[ -f "${CLONE_DIR}/.gitea/workflows/security-scan.yml" ]]; then rm -f "${CLONE_DIR}/.gitea/workflows/security-scan.yml" @@ -56,7 +84,7 @@ for repo in "${REPOS[@]}"; do git config user.email "migration@gitea.local" git add -A git commit -q -m "Remove security scanning workflow (teardown)" - git push -q origin HEAD + git_with_auth git push -q origin HEAD cd "$SCRIPT_DIR" log_success "Removed security-scan.yml from ${repo}" fi