校驗
執行之前,先自己核對
首頁上有兩條路:把一行字貼給 AI agent,或者自己在終端機跑 curl … | sh。
兩條路最後執行的是同一份腳本,而這種安裝方式的安全性,完全建立在「你信任 yangble5.com 這個網域,而且連線沒有被中間人竄改」之上。這一頁讓你不必只靠信任 —— 你可以自己驗。
先比對那一行。我們發佈給 AI agent 的字串只有一條,長這樣:
Install yangble5 by following https://yangble5.com/AGENTS.md
它沒有旗標、沒有端點網址、沒有金鑰。你手上那一行只要跟它不是逐字相同 —— 多一個字、換一個網域、多一個
--api —— 就不是我們的。這一頁後面所有的雜湊校驗,都擋不住那種情況;
首頁那一節解釋為什麼。
目前公告的 SHA256
即時讀取自 /install.sh.sha256 與 /install.ps1.sha256,沒有任何一個雜湊值寫死在這個頁面裡。
install.sh (macOS / Linux)
讀取中…
install.ps1 (Windows)
讀取中…
顯示「尚未公告」代表什麼?代表這台伺服器上還沒有放校驗檔,不代表腳本是安全的,也不代表可以跳過驗證。這種情況下請直接去 GitHub 上的原始碼比對,或乾脆不要執行。我們寧可你不裝,也不要你在沒有校驗的情況下裝。
逐步核對
macOS / Linux
# 1. 下載,先不要執行 curl -fsSL https://yangble5.com/install.sh -o install.sh # 2. 算出你手上這份的雜湊 shasum -a 256 install.sh # 沒有 shasum 的話: sha256sum install.sh # 3. 跟上面公告的值逐字元比對。不一樣就停在這裡。 # 4. 或者讓機器幫你比(對就印 OK,不對會直接失敗) curl -fsSL https://yangble5.com/install.sh.sha256 -o install.sh.sha256 shasum -a 256 -c install.sh.sha256 # 5. 自己讀過一遍。用編輯器或 cat,不要用 less/more —— # AI agent 的 shell 沒有 tty,分頁器不是把整份倒進對話紀錄就是卡住等按鍵。 cat install.sh # 6. 先空跑:把它打算做的每一件事印出來,一個檔案都不寫 shasum -a 256 -c install.sh.sha256 && sh install.sh --dry-run # 7. 看過計畫、同意了,才真的安裝 sh install.sh
Windows(PowerShell)
# 1. 下載,先不要執行 irm https://yangble5.com/install.ps1 -OutFile install.ps1 # 2. 算出雜湊 Get-FileHash .\install.ps1 -Algorithm SHA256 # 3. 跟公告值比對(PowerShell 輸出是大寫,大小寫不影響) $expected = '<貼上上面公告的值>' $actual = (Get-FileHash .\install.ps1 -Algorithm SHA256).Hash if ($actual -ieq $expected) { 'OK - 相符' } else { 'MISMATCH - 不要執行' } # 3b. 或者讓機器幫你抓公告值來比,不符就 throw,後面都不會跑 irm https://yangble5.com/install.ps1.sha256 -OutFile install.ps1.sha256 $expected = ((Get-Content .\install.ps1.sha256 -Raw) -split '\s+')[0] if ((Get-FileHash .\install.ps1 -Algorithm SHA256).Hash -ine $expected) { throw 'MISMATCH' } # 4. 自己讀過一遍 notepad .\install.ps1 # 5. 先空跑,再真的安裝 powershell -NoProfile -File .\install.ps1 -DryRun powershell -NoProfile -File .\install.ps1
用 certutil(不想開 PowerShell 的話)
certutil -hashfile install.ps1 SHA256
要傳 e-mail/邀請碼的話
管線不會把參數傳進去:curl … | sh 給不了腳本 argv,
irm … | iex 給不了 scriptblock 參數。而且安裝腳本是全自動的,
它不會停下來問你任何事,所以該問的必須事先問完再傳進去:
curl -fsSL https://yangble5.com/install.sh | sh -s -- --email you@example.com
sh install.sh --dry-run --invite YOUR-INVITE-CODE
& ([scriptblock]::Create((irm https://yangble5.com/install.ps1))) -Email you@example.com
powershell -NoProfile -File .\install.ps1 -DryRun -Invite YOUR-INVITE-CODE
# 或用環境變數,兩支腳本都認
YANGBLE5_EMAIL=you@example.com YANGBLE5_INVITE=YOUR-INVITE-CODE sh install.sh
$env:YANGBLE5_EMAIL = 'you@example.com'
對不上怎麼辦
- 不要執行那個檔案。先做這一件事,其他都之後再說。
- 把下載到的檔案刪掉,不要留著「等一下再看」。
- 可能只是我們發佈了新版而校驗檔還沒同步 —— 但你沒辦法從外面分辨這個和真正的攻擊,所以處理方式相同:先當作有問題。
- 到 GitHub issues 回報,附上你算到的雜湊、頁面顯示的雜湊,以及下載時間。
- 如果你是透過公共 Wi-Fi 或不受信任的網路下載的,換一個網路重試一次再下結論。
這個校驗能證明什麼、不能證明什麼
- 能證明:你手上這份檔案,和我們公告雜湊時的那份檔案,位元組完全一致。傳輸過程沒有被改、沒有下載到一半壞掉。
- 不能證明你「怎麼呼叫它」是對的 —— 這是這一頁最大的盲點,請讀完。
雜湊釘住的是腳本,不是命令列。一份雜湊完全相符、逐位元組正版的
install.sh,只要被寫成curl … | sh -s -- --api https://not-us.example(示範,不要執行), 就會把你註冊到那台主機、把它發的金鑰寫進~/.yangble5/credentials、 並把ANTHROPIC_BASE_URL指向它 —— 之後每一個用啟動器開的 session, 你的 prompt、檔案內容與 diff 都會送到它那裡。而這一頁的每一項校驗從頭到尾都會顯示「相符」。
腳本擋得住一半:非預設端點會印出整片警告並拒絕繼續,除非有人在終端機打YES,或明確加上--allow-nondefault-endpoint;curl … | sh沒有終端機,所以那個旗標一定會出現在命令列裡,看得見。 另一半只有你能擋:逐字比對你被交到手上的那一行,尤其當它是從 README、部落格、issue 留言或某個 AI 轉述來的。如果你在用 AI agent 安裝,這件事更重要,因為那一行是它讀到的,不是你打的。 - 不能證明腳本本身是善意的。雜湊只保證「一致」,不保證「安全」。如果我們發佈了一份惡意腳本並公告它的雜湊,校驗一樣會過。這就是為什麼首頁把腳本做的每一件事都逐條列出來,而且原始碼公開 —— 校驗和公開原始碼要一起看,單獨任何一個都不夠。也是為什麼下面把它設的每一個環境變數和寫的每一個檔案逐字列在這裡。
- 不能防護網域本身被攻陷。如果 yangble5.com 被入侵,攻擊者可以同時換掉腳本和校驗檔。要防這種情況,請直接從 GitHub repo 取得腳本並核對 commit 歷史。
- HTTPS 是前提。如果你是用
http://讀這一頁的,上面的雜湊值本身就可能已經被竄改了。請確認網址列是https://yangble5.com。
啟動器到底設了哪些環境變數
首頁寫的是「export 十一個變數,外加一個 unset」。下面是那十一行的逐字原文,
出自 install.sh 的 write_config()——就是產生 ~/.yangble5/env.sh
的那一段。沒有省略任何一項;如果你自己數出來不是十一個,那是我們寫錯了,請開 issue 告訴我們。
(這一頁不寫行號。行號會隨腳本改動而位移,一個過期的行號讀起來卻跟正確的一模一樣;
函式名稱不會這樣騙人。grep -n 'write_config()' install.sh 一秒就能定位。)
# ~/.yangble5/env.sh —— 只被 ~/.yangble5/bin/yangble5-* 這幾支啟動器 source。 # 這些值只存在於啟動器啟動的那個行程裡,不會寫進你的 shell。 # 1-3 先把 ~/.yangble5/credentials「解析」成 KEY=VALUE(不是 source),再 export export YANGBLE5_API YANGBLE5_API_KEY YANGBLE5_MODEL # 4 Claude Code 的設定與登入目錄。你原本的 ~/.claude 不受影響,靠的就是這一行。 export CLAUDE_CONFIG_DIR="${HOME}/.yangble5/claude" # 5-7 把 Claude Code 指向這個端點 export ANTHROPIC_BASE_URL="${YANGBLE5_API}" export ANTHROPIC_AUTH_TOKEN="${YANGBLE5_API_KEY}" export ANTHROPIC_MODEL="${YANGBLE5_MODEL}" # 8-10 三個數值上限。下面是預設值,可以用環境變數覆寫,但一律要先通過數字範圍檢查。 export CLAUDE_CODE_MAX_CONTEXT_TOKENS=1000000 export CLAUDE_CODE_MAX_OUTPUT_TOKENS=65536 export API_TIMEOUT_MS=600000 # +一個 unset。ANTHROPIC_API_KEY 的優先序高於 ANTHROPIC_AUTH_TOKEN, # 留著它會把你真正的 Anthropic 金鑰送到這個代理。移出啟動器環境。 unset ANTHROPIC_API_KEY # 11 Codex 的家目錄,指向下面那份隔離設定 export CODEX_HOME="${HOME}/.yangble5/codex"
兩個容易被略過、但很重要的細節。
env.sh 讀 credentials 的方式是逐行拆成 KEY=VALUE,
而不是 .(source)。憑證檔是資料;source 它就等於把裡面每一個值變成可執行的 shell 程式碼。
解析器讀不動它讀到的東西。讀完之後,其中三個(端點、模型別名、金鑰)還會再被同一組允許字元
檢查一次,不合格就直接退出(離開碼 6)—— 因為安裝腳本的檢查只管得住它自己寫進去的內容,
管不住之後誰去編輯那個檔案。
YANGBLE5_KEY_ID 也會在解析時被賦值,但沒有被 export,
所以它不算在十一個裡面,也不會出現在啟動的行程環境中。
Windows 版是同一組名稱,拆在 yangble5-claude.cmd 與
yangble5-codex.cmd 兩支啟動器裡,用 setlocal 隔離,
ANTHROPIC_API_KEY 則是被設成空值。
它在你的磁碟上寫了哪些東西
完整清單,分成永久留下與暫存兩類。除了下面這些路徑,安裝腳本不寫任何地方 ——
特別是不寫 ~/.claude、~/.codex、.bashrc、.zshrc、
.profile,也不改 PATH。
永久:留在你磁碟上的東西
~/.yangble5/(目錄,權限700)連同底下的claude/、codex/、bin/。~/.yangble5/machine-id(0600)—— 本機產生的 32 bytes 隨機鹽。 只在不存在時建立一次,永遠不會被覆寫,也永遠不會離開這台機器。 機器指紋是它跟 hostname/os/arch 一起做 sha256 的結果。~/.yangble5/credentials(0600)—— 端點、API key、key_id、模型別名。 金鑰在這裡,不在你的畫面上。~/.yangble5/env.sh(0600)—— 上面那十一行。~/.yangble5/INSTALL_INFO(0600)—— 版本、安裝時間、端點、模型、模式、平台。 每次執行都重寫,也是唯一刻意不做備份的檔案。~/.yangble5/uninstall.sh(0700)—— 解除安裝腳本本體。~/.yangble5/claude/README.txt(0600)—— 說明這個目錄是隔離的CLAUDE_CONFIG_DIR。~/.yangble5/codex/config.toml(0600)—— 隔離的 Codex 設定,不是你的~/.codex/config.toml。 你原本那份不會被開啟、讀取或修改。~/.yangble5/bin/底下四支啟動器(都是0700):yangble5-claude、yangble5-codex、yangble5-env(印出上面的環境,金鑰只印前 24 個字元後接...redacted)、yangble5-uninstall。~/.local/bin/底下四個指向上面那四支的 symlink。加--no-bin-link就不會建立;那裡若已經有同名的非 symlink 檔案, 它保留原檔並警告,不覆蓋。<檔名>.bak-<時間戳>—— 只在覆蓋既有檔案時產生,一律建在原檔旁邊, 所以也都在~/.yangble5/裡面。下面那一節是完整規則。
暫存:安裝期間存在,離開時刪除
這一段以前不在這一頁上,而上面那句「除了這些路徑不寫任何地方」因此是錯的。
安裝腳本還會用 mktemp -d 開一個暫存目錄,位置由 $TMPDIR 決定
(沒設的話多數系統是 /tmp),名字是 tmp. 加隨機字元。
建立它的是 install.sh 的 validate_settings(),建完立刻 chmod 700。
它跟你的家目錄無關,所以任何只掃 $HOME 的檢查都看不到它 ——
這正是這句話錯了那麼久還沒被抓到的原因。
安裝過程中會在那裡出現十個檔案。下表的「含金鑰」欄是實測結果:在一次完整安裝中側錄暫存目錄、 再到副本裡搜尋那把金鑰字串。
| 檔名 | 內容 | 含金鑰 | 額外 chmod | 何時刪除 |
|---|---|---|---|---|
curlrc.<pid> | curl 的設定檔,含 x-api-key 與 authorization 兩個標頭 | 是 | 600 | 每次呼叫結束 |
resp.<pid> | HTTP 回應本體,註冊那一次就是金鑰送達的地方 | 是 | — | 每次呼叫結束 |
credentials.<pid> | ~/.yangble5/credentials 的暫存版 | 是 | — | 寫檔後立刻 |
write.<pid> | 寫檔中繼站,每一個產生的檔案都經過它,所以金鑰也經過 | 是 | — | 每寫一個檔就刪 |
curlerr.<pid> | curl 的 stderr | 否 | — | 每次呼叫結束 |
env.<pid> | env.sh 的暫存版(金鑰在這裡是變數引用,不是字面值) | 否 | — | 寫檔後立刻 |
codex.<pid> | codex/config.toml 的暫存版 | 否 | — | 寫檔後立刻 |
install_info.<pid> | INSTALL_INFO 的暫存版 | 否 | — | 寫檔後立刻 |
register.json | 註冊請求本體:機器指紋、標籤,以及你自己傳的 e-mail/邀請碼 | 否 | 600 | 只在離開時 |
probe.json | 驗證用的那一次 /v1/messages 請求本體 | 否 | — | 只在離開時 |
權限:真正的邊界是目錄,不是檔案。十個裡面只有
curlrc 與 register.json 另外做了 chmod 600
(分別在 http_call() 與 obtain_key() 裡),其餘八個沿用你當下的 umask。
擋住同一台機器上其他使用者的是外面那層 700 的目錄。
這在單人機器上沒有差別;在共用主機上,這是你該知道的實際邊界。
刪除:trap cleanup EXIT HUP INT TERM 涵蓋這四種離開方式,
但涵蓋不了 SIGKILL、斷電與當機。
正常結束、或你按 Ctrl-C,整個目錄會被 rm -rf,那裡不會留下任何東西。
被 kill -9 或機器直接斷掉時目錄會留著;我們實測過一次:在 HTTP 呼叫進行中送出
SIGKILL,磁碟上留下 curlrc、register.json、
probe.json、curlerr 四個檔案,
其中 curlrc 裡有完整的金鑰。
遇到這種情況,刪掉 $TMPDIR 底下那個 tmp. 目錄再重跑一次安裝就好。
被覆蓋的檔案,以及怎麼還原
要寫的檔案已經存在、而且內容不同時,安裝腳本先 cp -p 出一份
<檔名>.bak-<時間戳> 再覆蓋;內容一樣就印 unchanged 並跳過。
跑完它會把每一份備份的完整路徑,連同可以直接貼回終端機的還原指令一起印出來。
輸出的格式是這樣(時間戳由 date +%Y%m%d-%H%M%S 產生,路徑是絕對路徑;
下面是版型,不是某一次執行的紀錄):
Files replaced this run — each was copied first
<絕對路徑>/env.sh.bak-<時間戳>
restore with: cp -p "<絕對路徑>/env.sh.bak-<時間戳>" "<絕對路徑>/env.sh"
Exempt on purpose: ~/.yangble5/INSTALL_INFO is rewritten every run
and is owned entirely by the installer, so it is not backed up.
Nothing else is exempt.
一份備份都沒有的時候,它印的是
no existing file was overwritten, so nothing was backed up,而不是沉默。
Windows 版印的是 Copy-Item -LiteralPath … -Destination … -Force,行為一致。
最保險的做法
不用管線,直接從版本控制拿:
git clone https://github.com/shark0120/yangble5
cd yangble5
# 讀原始碼、看 commit 歷史,然後自己決定要不要跑
git log --oneline -20
這一頁跟首頁一樣是單一檔案:HTML 裡沒有任何第三方請求 —— 沒有 CDN、沒有網頁字型、沒有分析追蹤、沒有 cookie。
頁面自己發出的執行期請求只有同源的那兩個 .sha256 檔(首頁另外會讀同源的
/pool/status,讀不到才退回 /health)。整頁存下來離線讀也可以 —— 那兩個雜湊會顯示「尚未公告」,
頁面不會拿一個看起來合理的舊值來充數。
但邊緣會加東西,這點必須講:本站經 Cloudflare 供應,回應帶有 Report-To 與
Nel 標頭,指向 a.nel.cloudflare.com。那是網路錯誤回報(NEL),
不在這個檔案裡,但它確實會讓瀏覽器在連線失敗時把錯誤回報給 Cloudflare。
你開 devtools 就看得到,所以我們自己先說。要完全避開就從 GitHub 拿原始碼,別經過這個網域。