#!/usr/bin/env bash set -Eeuo pipefail # Pulls latest code using PAT auth without persisting password credentials. # Required env vars: # GIT_USERNAME # GIT_PAT # # Example: # export GIT_USERNAME="austindebest" # export GIT_PAT="***" # bash infra/deploy/git-pat-sync.sh --repo-dir /opt/proxpanel --branch main REPO_DIR="/opt/proxpanel" BRANCH="main" REMOTE="origin" REPO_URL="" die() { printf '\n[ERROR] %s\n' "$*" >&2 exit 1 } usage() { cat <<'EOF' Usage: bash infra/deploy/git-pat-sync.sh [options] Options: --repo-dir Repository directory (default: /opt/proxpanel) --branch Branch to pull (default: main) --remote Remote to use (default: origin) --repo-url Optional URL to set on remote before sync -h, --help Show this help Required environment variables: GIT_USERNAME Git username GIT_PAT Personal Access Token EOF } parse_args() { while [[ $# -gt 0 ]]; do case "$1" in --repo-dir) REPO_DIR="${2:-}" shift 2 ;; --branch) BRANCH="${2:-}" shift 2 ;; --remote) REMOTE="${2:-}" shift 2 ;; --repo-url) REPO_URL="${2:-}" shift 2 ;; -h|--help) usage exit 0 ;; *) die "Unknown argument: $1" ;; esac done } require_env() { [[ -n "${GIT_USERNAME:-}" ]] || die "GIT_USERNAME is required." [[ -n "${GIT_PAT:-}" ]] || die "GIT_PAT is required." } build_auth_header() { local pair pair="${GIT_USERNAME}:${GIT_PAT}" printf 'Authorization: Basic %s' "$(printf '%s' "${pair}" | base64 | tr -d '\n')" } sync_repo() { [[ -d "${REPO_DIR}/.git" ]] || die "Not a git repo: ${REPO_DIR}" local auth_header auth_header="$(build_auth_header)" if [[ -n "${REPO_URL}" ]]; then git -C "${REPO_DIR}" remote set-url "${REMOTE}" "${REPO_URL}" fi git -c http.extraHeader="${auth_header}" -C "${REPO_DIR}" fetch "${REMOTE}" --prune git -C "${REPO_DIR}" checkout "${BRANCH}" git -c http.extraHeader="${auth_header}" -C "${REPO_DIR}" pull --ff-only "${REMOTE}" "${BRANCH}" } main() { parse_args "$@" require_env sync_repo echo "Repository synced successfully: ${REPO_DIR} (${BRANCH})" } main "$@"