bundle check/bundle outdated、濃縮 Gemfile.lock 差異,再以通用 HTTP Webhook把摘要與狀態回傳你的 Jenkins、GitHub Actions、自建 API 或告警系統。延伸可讀 GitHub Checks × lockfile、Jenkins Webhook 預檢、Discord 摘要推送;Ruby 拉取決策見 Bundler/Git 源 CI 矩陣。對齊 docs.openclaw.ai。
步驟一:安裝、閘道守護程序、令牌與健康檢查
1)Node 與 openclaw CLI:建議 Node 22.16+ 或 24 LTS;擇一以官方腳本或 npm i -g openclaw 安裝。執行 openclaw onboard、openclaw doctor,確認憑證、代理與埠占用。排錯流程可對照 OpenClaw 安裝與排錯指南。
2)閘道 daemon 與令牌:HTTP 服務綁 127.0.0.1,對外僅經 TLS 終止或隧道暴露。閘道 Bearer、觸發來源驗簽密鑰(若上游為 GitHub/Jenkins 等)、出站 CI Webhook 令牌分桶存放(環境變數或 chmod 600 檔),避免一處外洩整條管線失守。
3)launchd 與 PATH:守護程序帳號需能 git clone、寫日誌、呼叫 ruby/bundle;勿給 sudo。launchd plist 明寫 PATH(含 Homebrew、rbenv 路徑),與互動 SSH 一致;跨境請設 NODE_EXTRA_CA_CERTS。LaunchAgent 與健康探針細節見 閘道健康檢查與 LaunchAgent。
- 每輪預檢使用獨立
mktemp -d工作目錄,結束可刪除,避免並行執行互相覆寫Gemfile.lock工作樹。 - 週期性
curl本機/health(間隔如 60s),閘道掛掉時先告警,別讓 CI 靜默收不到摘要。
# 閘道健康(替換 PORT、GATEWAY_TOKEN;路徑以官方文件為準)
curl -sS -o /dev/null -w '%{http_code}\n' \
-H 'Authorization: Bearer YOUR_GATEWAY_TOKEN' \
--connect-timeout 3 --max-time 10 \
http://127.0.0.1:PORT/health
版本凍結:記錄 node -v、OpenClaw、Ruby、Bundler 版號;升級前在複本機跑通同一腳本。
非同步重活:若上游 Webhook 要求極短 ACK,先回 2xx 再將 bundle 預檢丟背景佇列,避免逾時重送風暴。
祕鑰注入:用 launchd EnvironmentVariables 或鑰匙圈讀取,勿把 token 寫進版本庫或 world-readable 腳本。
步驟二:工作目錄沙箱(WORKDIR)
每一輪預檢建立唯一目錄,例如 WORKDIR=$(mktemp -d /tmp/bundle-preflight.XXXXXX),可選 umask 027。於其下 git clone --depth 1 目標倉庫後 git fetch/checkout 指定 SHA。將 BUNDLE_PATH 指到 $WORKDIR/vendor/bundle(或專案子目錄),避免多專案共用 ~/.bundle 造成 gem 來源混淆。
- 磁碟配額足夠容納
bundle install(若預檢會裝依賴)與日誌。 - 並行 runner 時以
RUN_ID或 UUID 區隔目錄名,防止兩個 job 寫入同一路徑。 - 需讀私有 gem 源時,在沙箱內注入只讀權杖(環境變數),勿寫入全域 git config。
WORKDIR=$(mktemp -d /tmp/oc-bundle.XXXXXX) export BUNDLE_PATH="$WORKDIR/vendor/bundle" cd "$WORKDIR" git clone --depth 1 "https://github.com/org/app.git" repo cd repo git fetch origin "$SHA" --depth=1 && git checkout -q "$SHA"
步驟三:腳本模板——觸發 bundle check/outdated 與 lock diff
在沙箱內依門檻選擇是否設 BUNDLE_FROZEN=1:嚴格門檻下 bundle check 會在 lock 與實際不一致時非零退出,適合阻擋合併;諮詢型 job 可暫不凍結,僅收集 bundle outdated --parseable。將 Gemfile.lock 與基準分支比對可濃縮成短字串供 Webhook 使用。
cd "$WORKDIR/repo"
BASE_REF="${BASE_REF:-main}"
git fetch origin "$BASE_REF" --depth=1 2>/dev/null || true
LOG="$WORKDIR/bundler.log"
{
echo "=== bundle check ==="
bundle check
echo "=== outdated (head) ==="
bundle outdated --parseable 2>&1 | head -n 50
echo "=== Gemfile.lock diff (truncated) ==="
git diff "origin/${BASE_REF}"...HEAD -- Gemfile.lock 2>/dev/null | head -c 4000
} 2>&1 | tee "$LOG"
BUNDLE_OK=$?
# 之後以 BUNDLE_OK、LOG 末段組 JSON 摘要
若由 OpenClaw 技能包裝,建議輸出 { bundler_ok, outdated_excerpt, lock_diff_excerpt, duration_ms },供後續條件路由到 Slack/HTTP。矩陣 pipeline 宜由單一彙總觸發,避免重複告警。
- 對
bundle子程序加總逾時(如timeout 300或程式內計時),防止佔滿閘道 worker。 - Git 源 gem 與鏡像參數請與正式 CI 對齊,決策表見站內 Bundler CI 矩陣。
步驟四:失敗重試與日誌歸檔
網路類錯誤(git、rubygems、自建 gem server)建議有界重試:2/4/8 秒退避,最多三至四輪。每次將 stdout/stderr tee 到帶時間戳檔案;定期把 LOG_ROOT 下檔案 gzip 或交由 logrotate,保留與 run_id 對應的稽核軌跡。
# 包一層重試(示例:最多 4 輪;run_preflight 請替換為上一節 tee 至 LOG 的指令區塊或函式)
attempt=0
delay=2
until run_preflight; do
attempt=$((attempt+1))
[ "$attempt" -ge 4 ] && break
sleep "$delay"
delay=$((delay*2))
done
ARCHIVE_DIR="${LOG_ROOT:-/var/log/openclaw-bundler}"
mkdir -p "$ARCHIVE_DIR"
ts=$(date +%Y%m%d-%H%M%S)
gzip -c "$LOG" > "$ARCHIVE_DIR/run-${RUN_ID:-$ts}.log.gz" || true
與 OpenClaw 失敗恢復策略一致時,可把非致命步驟標記為 warning,僅在連續失敗時升級為 critical 告警。延伸閱讀 失敗恢復與重試。
步驟五:對接通用 HTTP Webhook 回傳摘要
預檢結束後以 curl 對任意 HTTPS 端點送出 JSON:建議欄位 status(success/failure)、bundler_ok(布林)、run_id、repo、sha、summary(截斷約 1~2KB,取自日誌末段)、lock_diff_hint(可選)。設定 --connect-timeout、--max-time;非 2xx 時採指數退避重送。若目標為 Discord/Slack,可並行參考 Discord 摘要步驟 調整 payload 形狀。
# 通用 CI Webhook(替換 URL、TOKEN;summary 請先 escape JSON)
STATUS="failure"
[ "$BUNDLE_OK" -eq 0 ] && STATUS="success"
SUMMARY="$(tail -n 35 "$LOG" | sed 's/"/\\"/g' | tr '\n' ' ')"
curl -sS -X POST "${CI_WEBHOOK_URL}" \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer ${CI_WEBHOOK_TOKEN}" \
--data "{\"status\":\"$STATUS\",\"bundler_ok\":$([ "$BUNDLE_OK" -eq 0 ] && echo true || echo false),\"run_id\":\"${RUN_ID}\",\"summary\":\"$SUMMARY\"}" \
--connect-timeout 5 --max-time 25 \
--retry 3 --retry-delay 2 --retry-all-errors
排錯 FAQ(閘道、Bundler、Webhook)
openclaw doctor 顯示閘道未監聽?
檢查 LaunchAgent 是否載入、WorkingDirectory 與 PATH 是否含 node 與 openclaw;以 launchctl kickstart 重啟後再 curl 本機 /health。詳見 閘道健康檢查教學。
bundle check 在 frozen 模式下立刻失敗?
BUNDLE_FROZEN=1 或 --deployment 會把 lock 漂移視為錯誤,屬預期。若只要 outdated 清單,拆出 advisory job 或暫不設 frozen。
Webhook 回 401/403?
確認 Authorization 標頭、接收端密鑰是否輪替;檢查遠端 Mac 出站是否被防火牆擋下;勿在日誌打印含 token 的完整 URL。
bundle/git 在 launchd 下找不到?
在 plist 寫死 PATH(含 Homebrew、rbenv/asdf shim);以 which bundle、openclaw doctor 驗證;Git 源 gem 逾時可調 BUNDLE_RETRY 等變數(見 Bundler 矩陣文)。
能和現有 GitHub/Jenkins/CircleCI 觸發鏈並用嗎?
可以:各平台先依官方方式驗簽,再呼叫本文同一組 Bundler 沙箱與 HTTP 回傳即可。站內 GitHub Checks、Jenkins 等文負責入站校驗,本文負責 Ruby 預檢與出站摘要。
與既有 OpenClaw 觸發鏈銜接
上游若已是 GitHub Checks、Jenkins Generic Webhook 或 CircleCI Outbound,可在各自 handler 驗簽通過後呼叫本文同一組 Bundler 區塊與 HTTP 回傳,無須重寫預檢邏輯。令牌與事件去重仍依各平台文件;閘道側專注沙箱隔離、日誌與出站摘要即可。
實際編譯與完整 bundle install 建議留在 CI 主流程或專用 Runner;遠端 Mac 閘道負責輕量預檢與告警,可降低主 pipeline 噪音並提早暴露 lock 漂移。