ISEP#47: source Gitea token from env/.env, not remote URL (9 scripts + credential helper)
- 6 hooks + gitea-labels-sync/wiki-panorama/gitea-bootstrap 全改用 gitea_token() - wiki-panorama clone/fetch 改乾淨 URL + credential helper - gitea-bootstrap 冪等清 remote URL + 設 credential.helper - 驗證:bootstrap/labels-sync API 認證通過、clone/push 經 helper 無 token 洩漏 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Kxf68FcYGqiuLAPiKKU2U3
This commit is contained in:
@@ -16,14 +16,29 @@ set -eu
|
||||
REPO=""
|
||||
[ "${1:-}" = "-r" ] && { REPO="${2:?-r 後面要接 owner/repo}"; }
|
||||
|
||||
REMOTE=$(git remote get-url gitea 2>/dev/null) || {
|
||||
echo "✗ 當前目錄沒有名為 gitea 的 remote。請 cd 到目標 repo,或先加 remote。" >&2; exit 1; }
|
||||
# 取當前 repo 的 remote(雲端叫 origin、本機慣例叫 gitea)
|
||||
REMOTE_NAME=$(git remote get-url gitea >/dev/null 2>&1 && echo gitea || (git remote get-url origin >/dev/null 2>&1 && echo origin))
|
||||
[ -n "$REMOTE_NAME" ] || { echo "✗ 當前目錄沒有 gitea/origin remote。請 cd 到目標 repo,或先加 remote。" >&2; exit 1; }
|
||||
REMOTE=$(git remote get-url "$REMOTE_NAME" 2>/dev/null)
|
||||
# 去掉網址裡可能嵌著的憑證 → 乾淨 URL(inkstone/ISEP#47:token 不進 remote URL)
|
||||
REMOTE=$(printf '%s' "$REMOTE" | sed -E 's#//[^/@]*@#//#')
|
||||
|
||||
TOKEN=$(printf '%s' "$REMOTE" | sed -E 's|.*//[^:]+:([^@]+)@.*|\1|')
|
||||
[ "$TOKEN" = "$REMOTE" ] && { echo "✗ gitea remote URL 裡沒有 token,無法取得認證。" >&2; exit 1; }
|
||||
HOST=$(printf '%s' "$REMOTE" | sed -E 's|.*@([^/]+)/.*|\1|')
|
||||
# token 來源=env/.env(不從 remote URL 抽——那會逼 token 明文嵌在 URL 裡 → 洩進 log)
|
||||
_GT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
|
||||
[ -f "$_GT_DIR/lib/gitea-token.sh" ] && . "$_GT_DIR/lib/gitea-token.sh"
|
||||
TOKEN=""; command -v gitea_token >/dev/null 2>&1 && TOKEN=$(gitea_token || true)
|
||||
[ -n "$TOKEN" ] || { echo "✗ 取不到 Gitea token(設 GITEA_TOKEN_CLAUDE_CODE,或在 .env 放 GITEA_TOKEN_CLAUDE_CODE=)。" >&2; exit 1; }
|
||||
HOST=$(printf '%s' "$REMOTE" | sed -E 's|.*://([^/]+)/.*|\1|')
|
||||
[ -n "$REPO" ] || REPO=$(printf '%s' "$REMOTE" | sed -E 's|.*://[^/]+/(.+)\.git$|\1|')
|
||||
|
||||
# 設定乾淨 remote URL + credential helper(冪等):URL 不含 token,認證改由 helper 從 env/.env 供
|
||||
# ⇒ git 把 remote URL 印出來(git-lfs 的 locksverify 那行)也不會洩 token(inkstone/ISEP#47)。
|
||||
if [ -f "$_GT_DIR/git-credential-gitea.sh" ]; then
|
||||
CUR=$(git remote get-url "$REMOTE_NAME" 2>/dev/null || true)
|
||||
case "$CUR" in *@*) git remote set-url "$REMOTE_NAME" "$REMOTE" && echo " ✓ remote $REMOTE_NAME 已清乾淨(移除嵌入的 token)" ;; esac
|
||||
git config credential.helper "$_GT_DIR/git-credential-gitea.sh"
|
||||
fi
|
||||
|
||||
echo "→ repo: $REPO host: $HOST"
|
||||
|
||||
# 狀態機(互斥 scope label)。順序=出貨流程:
|
||||
|
||||
@@ -30,16 +30,15 @@ if [[ ! -f "$LABELS_YAML" ]]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# --- token:跟 InkStoneCo 頂層 gitea remote 拿同一把(不落地檔案、不印出來) ---
|
||||
# --- token:來源=env/.env(inkstone/ISEP#47),不再從 remote URL 抽(那會逼 token 明文嵌在 URL 裡) ---
|
||||
TOKEN="${GITEA_TOKEN:-}"
|
||||
if [[ -z "$TOKEN" ]]; then
|
||||
INKSTONE_TOP="${INKSTONE_TOP:-$HOME/Documents/tech_projects/InkStoneCo}"
|
||||
if [[ -d "$INKSTONE_TOP/.git" ]]; then
|
||||
TOKEN="$(git -C "$INKSTONE_TOP" remote get-url gitea 2>/dev/null | sed -E 's|.*//[^:]+:([^@]+)@.*|\1|')"
|
||||
fi
|
||||
_GT_LIB="$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")" && pwd)/lib/gitea-token.sh"
|
||||
[[ -f "$_GT_LIB" ]] && . "$_GT_LIB"
|
||||
command -v gitea_token >/dev/null 2>&1 && TOKEN="$(gitea_token || true)"
|
||||
fi
|
||||
if [[ -z "$TOKEN" ]]; then
|
||||
echo "拿不到 Gitea token——設 GITEA_TOKEN 環境變數,或確認 $INKSTONE_TOP 的 gitea remote 存在" >&2
|
||||
echo "拿不到 Gitea token——設 GITEA_TOKEN_CLAUDE_CODE 環境變數,或在 .env/頂層 .env 放 GITEA_TOKEN_CLAUDE_CODE=" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
@@ -61,15 +61,21 @@ done
|
||||
|
||||
[ -f "$ROSTER" ] || { echo "找不到 roster:$ROSTER" >&2; exit 1; }
|
||||
|
||||
# ── Gitea base(含憑證,**絕不可印出來**)────────────────────────────────
|
||||
REMOTE=$(git -C "$ROOT" remote get-url gitea 2>/dev/null || true)
|
||||
[ -n "$REMOTE" ] || { echo "本 repo 沒有 gitea remote,無法取 repo。" >&2; exit 1; }
|
||||
# ── Gitea base(乾淨網址;token 來源=env/.env,不從 URL 抽——inkstone/ISEP#47)──────────
|
||||
_GT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
|
||||
[ -f "$_GT_DIR/lib/gitea-token.sh" ] && . "$_GT_DIR/lib/gitea-token.sh"
|
||||
REMOTE=$(git -C "$ROOT" remote get-url gitea 2>/dev/null || git -C "$ROOT" remote get-url origin 2>/dev/null || true)
|
||||
[ -n "$REMOTE" ] || { echo "本 repo 沒有 gitea/origin remote,無法取 repo。" >&2; exit 1; }
|
||||
# 去掉網址裡可能還嵌著的舊憑證(遷移期相容)→ 乾淨 base,clone/fetch 靠 credential helper 認證
|
||||
REMOTE=$(printf '%s' "$REMOTE" | sed -E 's#//[^/@]*@#//#')
|
||||
BASE=${REMOTE%/InkStoneCo.git}
|
||||
BASE=${BASE%/InkStoneCo}
|
||||
SELF=$(basename "$REMOTE" .git)
|
||||
SECRET=$(printf '%s' "$REMOTE" | sed -nE 's|.*//[^:]+:([^@]+)@.*|\1|p')
|
||||
# 任何要外流的字串都先過這關(錯誤訊息可能夾帶 clone URL)
|
||||
# scrub 用的 SECRET:token 從 env/.env 取(不從 URL 抽),用來遮掉萬一夾帶在錯誤訊息裡的 token
|
||||
SECRET=""; command -v gitea_token >/dev/null 2>&1 && SECRET=$(gitea_token || true)
|
||||
scrub() { if [ -n "$SECRET" ]; then sed "s|$SECRET|***|g"; else cat; fi; }
|
||||
# clone/fetch 的認證:乾淨 URL + credential helper(token 不進 URL、不洩進 log)
|
||||
GIT_CRED=""; [ -f "$_GT_DIR/git-credential-gitea.sh" ] && GIT_CRED="-c credential.helper=$_GT_DIR/git-credential-gitea.sh"
|
||||
|
||||
mkdir -p "$CACHE"
|
||||
# 自己這個 repo 一律讀工作副本 ⇒ 快取裡若留著一份舊的自己,是誤導來源(會被人拿去讀)
|
||||
@@ -95,7 +101,7 @@ for repo in $REPOS; do
|
||||
if [ -d "$dst/.git" ]; then
|
||||
if [ "$DO_FETCH" = 1 ]; then
|
||||
br=$(git -C "$dst" symbolic-ref --short HEAD 2>/dev/null || echo main)
|
||||
git -C "$dst" fetch --quiet origin "$br" 2>&1 | scrub >&2 || true
|
||||
git $GIT_CRED -C "$dst" fetch --quiet origin "$br" 2>&1 | scrub >&2 || true
|
||||
git -C "$dst" reset --quiet --hard FETCH_HEAD 2>/dev/null || true
|
||||
fi
|
||||
else
|
||||
@@ -104,7 +110,7 @@ for repo in $REPOS; do
|
||||
fi
|
||||
# blobless + sparse:只下載 wiki 目錄的內容,但保留完整 commit 歷史
|
||||
#(要歷史才算得出「每個檔最後更新是哪天」——淺 clone 會讓所有檔同一天)
|
||||
if ! err=$(git clone --quiet --filter=blob:none --sparse "$BASE/$repo.git" "$dst" 2>&1 | scrub); then
|
||||
if ! err=$(git $GIT_CRED clone --quiet --filter=blob:none --sparse "$BASE/$repo.git" "$dst" 2>&1 | scrub); then
|
||||
printf '%s\tclone-failed\t%s\n' "$repo" "$(printf '%s' "$err" | tr '\n' ' ')" >> "$STATUS_TSV"
|
||||
rm -rf "$dst"; continue
|
||||
fi
|
||||
@@ -312,7 +318,7 @@ if gap > 0:
|
||||
f"Gitea `Leo/*` 在 {ASOF} 實查是 **{TOTAL} 個**,名單 {len(repos)} 個 ⇒ **還有 {gap} 個沒被點名**。")
|
||||
w(" 補法(人發起,一次呼叫,不排程)——拿到完整清單、把缺的名字加進名單再重跑:")
|
||||
w(" ```")
|
||||
w(" TOKEN=$(git remote get-url gitea | sed -E 's|.*//[^:]+:([^@]+)@.*|\\1|')")
|
||||
w(" TOKEN=$GITEA_TOKEN_CLAUDE_CODE # 來源=env/.env,不從 remote URL 抽(inkstone/ISEP#47)")
|
||||
w(" curl -s -H \"Authorization: token $TOKEN\" \\")
|
||||
w(" 'https://git.uncle6.me/api/v1/orgs/Leo/repos?limit=100' | python3 -c \\")
|
||||
w(" 'import sys,json;[print(r[\"name\"]) for r in json.load(sys.stdin)]'")
|
||||
|
||||
Reference in New Issue
Block a user