From e27f203f39393aa011dee8f2e2c3f743421f3eae Mon Sep 17 00:00:00 2001 From: git-bridge Date: Fri, 17 Jul 2026 02:17:37 +0000 Subject: [PATCH] add FF-only Gitea to GitHub sync job --- docker-compose.yaml | 28 ++++++++++++ git-bridge/README.md | 13 ++++++ git-bridge/bin/git-askpass.sh | 8 ++++ git-bridge/bin/sync-main-forward.sh | 68 +++++++++++++++++++++++++++++ git-bridge/config/repositories.conf | 3 ++ 5 files changed, 120 insertions(+) create mode 100644 git-bridge/README.md create mode 100755 git-bridge/bin/git-askpass.sh create mode 100755 git-bridge/bin/sync-main-forward.sh create mode 100644 git-bridge/config/repositories.conf diff --git a/docker-compose.yaml b/docker-compose.yaml index cd0a9ff..cfb3e34 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -117,6 +117,34 @@ services: networks: - n8n_default + git-bridge: + container_name: git-bridge + profiles: ["git-bridge"] + image: ${GITEA_IMAGE:-gitea/gitea:1.23} + restart: "no" + user: "0:0" + environment: + HOME: /state/home + HTTP_PROXY: http://192.168.0.4:7890 + HTTPS_PROXY: http://192.168.0.4:7890 + ALL_PROXY: http://192.168.0.4:7890 + NO_PROXY: localhost,127.0.0.1,::1,gitea,postgres,litellm + entrypoint: ["/bin/sh", "/app/bin/sync-main-forward.sh"] + volumes: + - ./git-bridge/bin:/app/bin:ro + - ./git-bridge/config:/app/config:ro + - ./git-bridge/state:/state + - ./git-bridge/secrets/gitea_token:/run/secrets/gitea_token:ro + - ./git-bridge/secrets/github_token:/run/secrets/github_token:ro + read_only: true + tmpfs: + - /tmp + cap_drop: ["ALL"] + security_opt: + - no-new-privileges:true + networks: + - git_forge + networks: git_forge: name: git_forge diff --git a/git-bridge/README.md b/git-bridge/README.md new file mode 100644 index 0000000..298b149 --- /dev/null +++ b/git-bridge/README.md @@ -0,0 +1,13 @@ +# Git Bridge + +Phase 1 provides a deterministic, one-shot forward sync from Gitea Main to +GitHub Main. The job refuses divergence and never force-pushes. + +Run after this change is merged and deployed: + +```bash +docker compose --profile git-bridge run --rm --no-deps git-bridge +``` + +GitHub remains a development workspace. Production deployment continues to +use only Gitea Main. diff --git a/git-bridge/bin/git-askpass.sh b/git-bridge/bin/git-askpass.sh new file mode 100755 index 0000000..a1bb67b --- /dev/null +++ b/git-bridge/bin/git-askpass.sh @@ -0,0 +1,8 @@ +#!/bin/sh +case "$1" in + *Username*github.com*|*github.com*Username*) printf '%s\n' 'RX-Penguin' ;; + *github.com*) cat /run/secrets/github_token ;; + *Username*gitea*|*gitea*Username*) printf '%s\n' 'git-bridge' ;; + *gitea*) cat /run/secrets/gitea_token ;; + *) exit 1 ;; +esac diff --git a/git-bridge/bin/sync-main-forward.sh b/git-bridge/bin/sync-main-forward.sh new file mode 100755 index 0000000..bc44036 --- /dev/null +++ b/git-bridge/bin/sync-main-forward.sh @@ -0,0 +1,68 @@ +#!/bin/sh +set -eu + +. /app/config/repositories.conf + +state_repo=/state/infra.git +lock_dir=/state/forward-sync.lock + +mkdir -p /state +mkdir -p "$HOME" +if ! mkdir "$lock_dir" 2>/dev/null; then + echo "forward sync is already running" >&2 + exit 75 +fi +trap 'rmdir "$lock_dir" 2>/dev/null || true' EXIT INT TERM + +export GIT_TERMINAL_PROMPT=0 +export GIT_ASKPASS=/app/bin/git-askpass.sh + +if [ ! -d "$state_repo" ]; then + git init --bare "$state_repo" >/dev/null +fi + +if git -C "$state_repo" remote get-url gitea >/dev/null 2>&1; then + [ "$(git -C "$state_repo" remote get-url gitea)" = "$GITEA_REMOTE" ] || { + echo "gitea remote mismatch" >&2 + exit 2 + } +else + git -C "$state_repo" remote add gitea "$GITEA_REMOTE" +fi +if git -C "$state_repo" remote get-url github >/dev/null 2>&1; then + [ "$(git -C "$state_repo" remote get-url github)" = "$GITHUB_REMOTE" ] || { + echo "github remote mismatch" >&2 + exit 2 + } +else + git -C "$state_repo" remote add github "$GITHUB_REMOTE" +fi + +git -C "$state_repo" fetch --no-tags gitea \ + "+refs/heads/$MAIN_BRANCH:refs/remotes/gitea/$MAIN_BRANCH" +gitea_sha=$(git -C "$state_repo" rev-parse "refs/remotes/gitea/$MAIN_BRANCH") + +if git -C "$state_repo" ls-remote --exit-code --heads github \ + "refs/heads/$MAIN_BRANCH" >/dev/null 2>&1; then + git -C "$state_repo" fetch --no-tags github \ + "+refs/heads/$MAIN_BRANCH:refs/remotes/github/$MAIN_BRANCH" + github_sha=$(git -C "$state_repo" rev-parse "refs/remotes/github/$MAIN_BRANCH") + if ! git -C "$state_repo" merge-base --is-ancestor "$github_sha" "$gitea_sha"; then + echo "sync refused: GitHub Main is not an ancestor of Gitea Main" >&2 + exit 42 + fi +fi + +git -C "$state_repo" push github \ + "refs/remotes/gitea/$MAIN_BRANCH:refs/heads/$MAIN_BRANCH" +verified_sha=$(git -C "$state_repo" ls-remote github \ + "refs/heads/$MAIN_BRANCH" | awk 'NR == 1 { print $1 }') +[ "$verified_sha" = "$gitea_sha" ] || { + echo "sync verification failed" >&2 + exit 1 +} + +echo "forward sync completed" +echo "branch=$MAIN_BRANCH" +echo "commit=$gitea_sha" +echo "force_push=false" diff --git a/git-bridge/config/repositories.conf b/git-bridge/config/repositories.conf new file mode 100644 index 0000000..7b736f2 --- /dev/null +++ b/git-bridge/config/repositories.conf @@ -0,0 +1,3 @@ +GITEA_REMOTE=http://gitea:3000/slh/infra.git +GITHUB_REMOTE=https://github.com/RX-Penguin/infra.git +MAIN_BRANCH=main -- 2.47.2