Files
ISEP/docs/cloud-setup-script.sh
Claude 762c28c522 雲端 setup:git 認證改用讀環境變數的 credential helper,並讓驗證有能力變紅
雲端實測(真的雲端 session,不是本機模擬):
- session 是 root/HOME=/root,setup 階段寫進 $HOME 的三個機制一個都沒到
  (沒有 insteadOf、沒有 ~/.git-credentials、沒有 /etc/gitconfig)
- 薄殼 settings.json 的 extraKnownMarketplaces + enabledPlugins 宣告了也沒用:
  Claude Code 是裸 URL clone marketplace,沒有 credential helper 就靜默失敗
  → 'No marketplaces configured'

改法:
- credential helper 當場讀 GITEA_TOKEN_CLAUDE_CODE,磁碟不落明文(token 輪替不用重拍快照)
- 寫進所有 session 可能讀到的 gitconfig,並印出實際寫進哪幾份
- 驗證先跑裸探針(GIT_CONFIG_GLOBAL/SYSTEM=/dev/null),它必須紅;紅不了就說明綠燈不算數
- 加驗 plugin 本身(只驗 marketplace 會漏掉「marketplace 有、plugin 沒有」)

在雲端容器內實跑過:裸環境正確失敗 → 補 helper 後 marketplace 就位、
isep@inkstone 0.3.1 installed/enabled,腳本 exit 0。
2026-08-20 15:46:47 +00:00

129 lines
7.9 KiB
Bash
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
# 貼進 code-on-web「Cloud environments → 你的環境 → Setup script」欄位的內容。
# 不是 ISEP 的一部分(不會被 Claude Code 當 hook/command/skill 掃描),
# 純粹是給 leo 複製貼上的參考檔,見 docs/cloud-session-bootstrap.md。
#
# 前提(要先在同一個 Cloud environment 的 Environment variables 欄位加好):
# GITEA_TOKEN_CLAUDE_CODE ← 既有機器帳號 token,名字沿用 InkStoneCo#14 已建立的那把,
# 不要新造一把。值本身不寫在這支腳本或任何檔案裡。
#
# 這支腳本做兩件事:
# 1. 讓 session 裡任何對 git.uncle6.me 的 clone 都認得出憑證
# —— Claude Code 拉 marketplace 是用**裸 URL clone**,走的就是 git credential helper
# 2026-08-20 雲端實測的原始錯誤訊息:「HTTPS authentication failed. Please ensure
# your git credential helper has valid credentials for git.uncle6.me」)。
# 2. 把 ISEP 裝成 user-scope plugin —— 裝的東西 100% 來自 inkstone/ISEP 本身,沒有第二份內容。
#
# 何時跑:只在「這個 Cloud environment 第一次開 session」時跑一次,
# 跑完 Anthropic 會把整個檔案系統拍成快照,之後的 session 直接沿用快照
# (不重跑,除非改了這支腳本本身、改了 allowed network hosts、或快照滿 7 天過期)。
# ⇒ 這是唯一會讓「ISEP 改了但雲端還是舊的」重新出現的地方,
# 緩解法見 docs/cloud-session-bootstrap.md「已知限制」段。
set -euo pipefail
if [ -z "${GITEA_TOKEN_CLAUDE_CODE:-}" ]; then
echo "❌ 找不到 GITEA_TOKEN_CLAUDE_CODE —— 去 Cloud environment 的 Environment variables 加這個名字" >&2
exit 1
fi
# ── git 認證 ────────────────────────────────────────────────────────────
#
# 🔴 舊版(2026-08-20 之前)在這裡踩了兩個坑,兩個都是「不出聲的」:
#
# ① 把 token 明文寫進 `~/.git-credentials`。
# —— 換 token 那天起這份就是壞的,而且壞法是「認證失敗」不是「檔案不見」,很難聯想。
# 改法:credential helper **當場讀環境變數**,磁碟上不落任何明文。
# token 輪替時只要改 Environment variables,這支腳本不用動、快照也不用重拍。)
#
# ② 只寫 `$HOME`。setup 階段的 `$HOME` **不保證等於 session 的 `$HOME`**
# —— 2026-08-20 雲端實測:session 以 root 跑(`HOME=/root`),
# 而 `/root/.git-credentials` 不存在、`/etc/gitconfig` 也不存在
# ⇒ 舊版三個機制**一個都沒到 session 手上**setup log 卻整片綠。
# 改法:把同一段 helper 寫進所有「session 可能會讀」的 gitconfig,並印出實際寫進哪幾份。
#
# helper 內容不含 token,只含「去讀 $GITEA_TOKEN_CLAUDE_CODE」這個動作。
HELPER='!f() { test "$1" = get && printf "username=claude-code\npassword=%s\n" "$GITEA_TOKEN_CLAUDE_CODE"; }; f'
echo "── 寫 git credential helper(不落地明文 token)──"
wrote=0
seen=""
for cfg in "${HOME:-/root}/.gitconfig" /root/.gitconfig /home/claude/.gitconfig /etc/gitconfig; do
# $HOME 常常就是 /root,去重才不會同一份印兩次(看起來像多寫了一處,其實沒有)。
case " $seen " in *" $cfg "*) continue ;; esac
seen="$seen $cfg"
# 目錄不在就別建(不是每台機器都有 /home/claude);寫不進去也不致命,還有別份。
[ -d "$(dirname "$cfg")" ] || { echo " .跳過 $cfg(目錄不存在)"; continue; }
if git config --file "$cfg" credential."https://git.uncle6.me".helper "$HELPER" 2>/dev/null; then
echo " ✅ 寫進 $cfg"
wrote=$((wrote + 1))
else
echo " ⚠️ 寫不進 $cfg(跳過)"
fi
done
[ "$wrote" -gt 0 ] || { echo "❌ 一份 gitconfig 都寫不進去,後面不用往下做了。" >&2; exit 1; }
# ── 🔴 自我驗證一:這個測試有沒有能力變紅 ────────────────────────────
# 先在「什麼設定都不讀」的條件下跑一次,**它必須失敗**。
# 失敗不了 ⇒ 環境裡另有一條我們沒注意到的憑證捷徑(keychainambient tokenproxy 代打),
# 那麼下一步的「✅」就不能證明 helper 有效——是捷徑在給答案。
# 2026-08-20 同一天在這個形狀上連摔三次,見 InkStoneCo mistakes.md「隔離環境沒有隔離系統層」。)
echo "── 驗證 git 認證 ──"
if GIT_CONFIG_GLOBAL=/dev/null GIT_CONFIG_SYSTEM=/dev/null GIT_TERMINAL_PROMPT=0 \
git ls-remote https://git.uncle6.me/inkstone/ISEP.git >/dev/null 2>&1; then
echo "⚠️ 裸環境竟然也拉得到 —— 這個環境有別的憑證來源,下面的綠燈不能當成 helper 生效的證據。" >&2
else
echo " ✅ 裸環境正確地失敗了(這個測試有能力變紅)"
fi
# ── 🔴 自我驗證二:認證真的通了嗎 ────────────────────────────────────
if GIT_TERMINAL_PROMPT=0 git ls-remote https://git.uncle6.me/inkstone/ISEP.git >/dev/null 2>&1; then
echo " ✅ git 認證通:拉得到 inkstone/ISEP"
else
echo "❌ git 認證不通——marketplace 一定裝不起來,後面不用往下做了。" >&2
echo " 檢查:GITEA_TOKEN_CLAUDE_CODE 的值對不對、那把 token 有沒有被撤銷。" >&2
exit 1
fi
# ── 安裝 ────────────────────────────────────────────────────────────────
# 🔴 官方文件(cloud-environments 的 what-carries-over 表)明文:
# 「Plugins enabled only in your user settings」→ **不會**帶到雲端 session。
# 薄殼 repo 的 .claude/settings.json 裡的 enabledPlugins extraKnownMarketplaces 才是主要路徑。
# 但 2026-08-20 雲端實測證明:**那兩個 key 宣告了也沒用,如果 git 認證不在。**
# Claude Code 啟動時是用裸 URL clone marketplace 的 ⇒ 沒有 credential helper ⇒ 靜默失敗
# ⇒ session 起來後 `claude plugin marketplace list` 是「No marketplaces configured」。
# ⇒ **上面那段 credential helper 才是主要路徑;下面兩行是備援。**
echo "── 安裝 marketplace / plugin ──"
claude plugin marketplace add https://git.uncle6.me/inkstone/ISEP.git --scope user 2>/dev/null || true
claude plugin install isep@inkstone --scope user 2>/dev/null || true
# ── 🔴 自我驗證三:marketplace 與 plugin 都真的就位了嗎 ──────────────
# 只驗 marketplace 不夠:marketplace 列得出來、plugin 沒裝起來,
# session 啟動時 enabledPlugins 一樣是一張跳票的支票。
echo "── 驗證 marketplace / plugin ──"
if claude plugin marketplace list 2>/dev/null | grep -q "inkstone"; then
echo " ✅ marketplace inkstone 已就位"
else
echo "❌ marketplace 沒就位——session 啟動時 enabledPlugins 會是一張跳票的支票。" >&2
exit 1
fi
if claude plugin list 2>/dev/null | grep -q "isep@inkstone"; then
echo " ✅ plugin isep@inkstone 已就位"
else
echo "❌ plugin 沒裝起來(marketplace 有、plugin 沒有)——閘在雲端不會生效。" >&2
exit 1
fi
cat <<'EOF'
✅ setup 完成。
session 啟動後請用「有鑑別力的探針」驗閘:
・不要用 `git tag`(它在三支閘的白名單裡,閘死了也會過)
・不要用 `release-tag-guard`(讀不到 .claude-plugin/plugin.json 就按設計 exit 0
・先確認你挑的那支閘「在這個情境下的設計行為」是擋,不是放行
驗閘之外,也順手確認這兩件(任一為否 ⇒ 這個 session 沒有 plugin,別當成有):
claude plugin marketplace list # 要看到 inkstone
claude plugin list # 要看到 isep@inkstone · enabled
EOF