From 340b461f58ed6a9958850f8871cf05381ce95c9d Mon Sep 17 00:00:00 2001 From: uncle6me-web Date: Fri, 14 Aug 2026 23:25:26 +0800 Subject: [PATCH] =?UTF-8?q?fix(cypher):=20credential=20=E5=85=A8=E9=83=A8?= =?UTF-8?q?=E5=BE=9E=E6=96=B0=E5=AE=B6=E5=8F=96=E5=88=B0=E6=99=82=E4=B8=8D?= =?UTF-8?q?=E5=86=8D=E6=89=93=20auth=5Fstatic=5Fkey=20worker=EF=BC=88Arcru?= =?UTF-8?q?n#124=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 病:cypher 看到 {{credential.X}} 就無條件 fetch arcrun-auth-static-key.{WORKER_SUBDOMAIN}.workers.dev。那顆 worker **不在網頁安裝器的首裝清單裡**(只裝 cypher-executor / kbdb / http_request / code 四顆),也沒有「用到才長」的機制 ⇒ fetch 撞 CF 邊緣 404 `error code: 1042` ⇒ 凡是用到 {{credential.X}} 的節點全部 500。 實測兩台都一字不差地同死(唯讀證據): leo21c GET /q/bfezv28v/rag_chat → 500 Node kw_search failed: ... 1042 youlin GET /q/yuga3bse/rag_chat → 500 Node kw_search failed: ... 1042 geek6688(手工維護、那顆在) → 過得了這關 leo 的 8 支 RAG 工作流每一支都用 {{credential.}}(rag_chat 6 處、 rag_ingest_card 7 處)⇒ 問答與寫入同時死,不只 ingest。 修法:resolveCredentialRefs 在 resolveSecretsFromNewHome 之後,若 nameList 每一個都已取到明文,就直接 replaceCredentialRefs 回傳,不打那顆 worker。 為什麼是零行為變化:回填本來就在本檔做(replaceCredentialRefs);那顆 worker 在這條路徑上唯一多做的事是幫「沒取到」的 name fallback 舊 KV(T7 雙讀)。 全取到時它收到 resolved_secrets 就是原樣回傳。只要有任一 name 沒取到, 仍照舊全量交給 WASM 走 T7——不縮減既有能力,只在等價時省掉那一跳。 證據那把金鑰早就在手上:leo21c 的 credential 目錄 last_used_at=1786715805, 與最後一次失敗執行的時間戳同一秒(touchLastUsed 只在真的從新家取到值時才寫)。 🔴 這個 1042 與 d2048e2/95a1462 那兩輪不是同一個病:那兩輪是 same-zone fetch 被擋(解=global_fetch_strictly_public flag,service binding 的解法已被 revert 不要拿回來);本案是目標 worker 根本不存在。同一個錯誤碼、兩種原因。 邊界:rule 02 §2.2 不變(不解密/不展開模板/不組 JWT);rule 3.1 不變(不加 service binding)。明文來源仍是 secret_get host function,與改動前同一條路。 驗證:tsc 對本檔零錯誤;auth-dispatcher+credentials 測試 5 紅 8 綠, 與改動前基準線逐項相同(零回歸;那 5 紅是 7ba7855 註明的「刻意留紅燈」)。 Co-Authored-By: Claude Opus 5 --- .../src/actions/auth-dispatcher.ts | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/cypher-executor/src/actions/auth-dispatcher.ts b/cypher-executor/src/actions/auth-dispatcher.ts index b642fc3..50fa903 100644 --- a/cypher-executor/src/actions/auth-dispatcher.ts +++ b/cypher-executor/src/actions/auth-dispatcher.ts @@ -245,6 +245,35 @@ export async function resolveCredentialRefs( // 沒取到的 name 缺席 → WASM 的 resolve_credentials 分支 fallback 舊 KV(T7)。 const resolvedSecrets = await resolveSecretsFromNewHome(env, apiKey, nameList); + // ── 全部取到 → 不必打 auth_static_key worker(Arcrun#124,2026-08-14)──────────── + // + // 這條路徑上,那顆 worker 唯一比這裡多做的事,是「幫**沒取到**的 name 回頭翻舊 KV」 + // (T7 雙讀 fallback)。當 nameList 每一個都已經從新家取到明文時,它收到 + // `resolved_secrets` 後就是原樣回傳——回填本來就由下面的 `replaceCredentialRefs` + // 在本檔做。**所以那趟往返在「全取到」時不產生任何結果差異。** + // + // 為什麼這不是效能微調,是修 bug:`wasmWorkerUrl` 推導出的 + // `arcrun-auth-static-key.{WORKER_SUBDOMAIN}.workers.dev` **在網頁安裝器裝出來的實例上不存在** + // (首裝只裝 cypher-executor / kbdb / http_request / code 四顆,auth primitive 不在其中, + // 也沒有「用到才長」的機制)。於是 fetch 撞 CF 邊緣的 404 `error code: 1042` + // ⇒ 下面的 `!res.ok` throw ⇒ **凡是工作流用到 {{credential.X}} 的節點全部 500**。 + // 實測:leo21c 與全新安裝的 youlin 兩台,問答與寫入路徑一字不差地同死。 + // + // 🔴 給下一個人:**這個 1042 跟 d2048e2/95a1462 那兩輪的 1042 不是同一個病。** + // 那兩輪是「same-zone fetch 被 CF 擋」(解法=`global_fetch_strictly_public` flag, + // 且 service binding 的解法**已被 revert、不要再拿回來**)。本案是「**目標 worker 根本不存在**」 + // ——同一個錯誤碼、兩種原因。照舊帳去動 flag 或 binding 對本案完全無效(flag 早就在了)。 + // + // 邊界(rule 02 §2.2)不變:本檔仍然不解密、不展開模板、不組 JWT。 + // 明文的來源是 `secret_get`(host function,實作 = env[ref]),與改動前完全同一條路; + // 這裡只是不再為了「拿一份自己已經拿到的東西」去 fetch 一顆可能不存在的 worker。 + // + // 刻意保留 WASM 路徑:只要有任何一個 name 沒從新家取到(舊租戶、遷移過渡期的 KV 存量), + // 就照舊全量交給 WASM 走 T7 雙讀——**不縮減既有能力,只在等價時省掉那一跳**。 + if (nameList.every((n) => Object.prototype.hasOwnProperty.call(resolvedSecrets, n))) { + return replaceCredentialRefs(data, resolvedSecrets) as Record; + } + const url = wasmWorkerUrl('auth_static_key', env.WORKER_SUBDOMAIN); const res = await fetch(url, { method: 'POST',