feat(credential-store-migration): T5 寫入路徑改走 Workers Secrets + D1 ref
POST/PUT /credentials 改寫:密文值 PUT 進 CF Workers per-script Secrets (唯寫,D19 不持有內容物),D1 credentials 表只存目錄(不含密文)。 secret_ref = CRED_<NAME>_<sha256(api_key)[:8]>,避免跨租戶撞名。 DELETE/GET /credentials 本次不動(仍走舊 KV,T9 範圍),已誠實標注。 新增 CREDENTIALS_DB D1 binding(與 KBDB base 共用同一顆 arcrun-kbdb, 沿用既有 database_id 注入機制)+ CF_SECRETS_API_TOKEN/CF_ACCOUNT_ID env vars(CF_ACCOUNT_ID 由 deploy.ts 自動注入,同 WORKER_SUBDOMAIN 模式)。 §2.4 選項甲落地:client 不再加密,明文值經 TLS 傳輸,cypher 短暫經手 明文不落地不持金鑰——與舊版 01-tech-stack.md 傳輸格式不同,是本 SDD 對舊格式的刻意取代(§6 Q-b 仍需 leo 明確接受)。 驗證:tsc --noEmit exit 0;vitest 26/27(1 pre-existing 無關失敗)。 端到端:真實部署 leo21c arcrun-cypher-executor,POST/PUT /credentials 成功寫入 Workers Secrets + D1 row(CF API + D1 query 雙重確認), 清理測試資料後 restore wrangler.toml(無帳號專屬 id 殘留 git)。 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018D6QoC5waFkcjc2N7csJBB
This commit is contained in:
+29
-1
@@ -197,7 +197,35 @@ CLI 薄殼(rule 07):`acr creds list`(讀 D1 顯示)、`acr creds repla
|
||||
`fn(...)` 呼叫——用 probe 測試證實 `kv_get` 的 import 同樣不可直接呼叫,確認是既有架構的
|
||||
環境限制非 secret_get 缺陷,已移除該 2 案例並在測試檔內註記;pointer 機制的真實驗證改由
|
||||
T5 wrangler 部署端到端涵蓋。
|
||||
- [ ] T5 寫入路徑:`POST/PUT /credentials` 改寫 Workers Secrets(API `PUT`)+ D1 ref(§2.4)。
|
||||
- [x] T5 寫入路徑:`POST/PUT /credentials` 改寫 Workers Secrets(API `PUT`)+ D1 ref(§2.4)。2026-07-03 完成:
|
||||
`cypher-executor/src/routes/credentials.ts` 整檔改寫 POST(建立)+ 新增 PUT `/credentials/:name`
|
||||
(覆寫):兩者共用 `writeCredential()` → 1) `putWorkerSecret()` PUT 進 CF Workers Scripts secrets
|
||||
管理 API(唯寫)2) `upsertCredentialRow()` D1 upsert(不含密文,覆寫時保留原 `created_at`)。
|
||||
`secret_ref` 命名=`CRED_<NAME 大寫>_<sha256(api_key) 前 8 碼大寫>`(`cypher-executor/src/lib/hash.ts`
|
||||
匯出既有 `sha256Prefix`,避免跨租戶同名 credential 撞名覆蓋彼此的 secret;純函式衍生非解密/簽章邏輯,
|
||||
不違 rule 02 §2.2)。DELETE/GET `/credentials` 本次刻意不動(仍讀寫舊 KV,T9 治理端點範圍),
|
||||
已在檔頭與 §3 comment 誠實標注此缺口。`types.ts` Bindings 加 `CREDENTIALS_DB: D1Database`
|
||||
(與 KBDB base 共用同一顆 `arcrun-kbdb` D1)+ `CF_SECRETS_API_TOKEN?` / `CF_ACCOUNT_ID?`。
|
||||
`wrangler.toml` 加 `[[d1_databases]] binding="CREDENTIALS_DB"`(沿用 kbdb 同款 database_id
|
||||
注入機制,deploy.ts 不用改)+ `[vars] CF_ACCOUNT_ID=""` 佔位(T3 由 deploy.ts 自動注入非機密
|
||||
帳號 id,同 WORKER_SUBDOMAIN 模式)。**§2.4 選項甲落地**(client 不再 AES-GCM 加密,明文值經
|
||||
TLS 傳輸,cypher 短暫在記憶體經手明文不落地不持金鑰)——與舊版 `01-tech-stack.md` 記載的
|
||||
`{name,encrypted,iv}` 傳輸格式不同,此為本 SDD 對舊格式的刻意取代,§6 Q-b 仍列需 leo 明確
|
||||
接受的誠實 trade-off(先落地,若不接受選項甲需回頭改,見任務完成報告「撞牆」段)。
|
||||
驗證:`tsc --noEmit` exit 0(cli + cypher-executor 皆是);`vitest run` 26/27 通過(1 個
|
||||
pre-existing 無關失敗,見 T4 記錄,non-regression 已用 git stash 驗證)。**端到端證據**(真實
|
||||
leo21c `arcrun-cypher-executor` worker,非測試替身——寫入端點本身就是要驗的東西,無替代):
|
||||
比照 mistakes #23 手法本地 patch `wrangler.toml`(KV/D1 id、CF_ACCOUNT_ID、WORKER_SUBDOMAIN、
|
||||
KBDB_BASE_URL 換 leo21c 真實值,strip `[ai]`/`[[routes]]`)→ `wrangler deploy --dry-run` 核對
|
||||
binding 表(`env.CREDENTIALS_DB (arcrun-kbdb) D1 Database` 等全對)→ 真部署 → `wrangler secret put
|
||||
CF_SECRETS_API_TOKEN`(沿用 `CLOUDFLARE_API_TOKEN`)→ `curl POST /credentials` 回
|
||||
`{"success":true,"secret_ref":"CRED_TELEGRAM_BOT_TOKEN_9BB9FB82",...}` → CF API `GET
|
||||
.../workers/scripts/arcrun-cypher-executor/secrets` 確認該 secret 真的存在 → D1 query 確認
|
||||
對應 row(api_key/name/service/sensitivity/secret_ref/created_at 全對)→ `curl PUT
|
||||
/credentials/telegram_bot_token` 覆寫值,確認 `secret_ref` 不變、`created_at` 不變(覆寫語意
|
||||
正確)→ 清理:CF API `DELETE .../secrets/{ref}` + D1 `DELETE FROM credentials`,二次查詢確認
|
||||
皆已清空。部署完成後**立刻 restore `wrangler.toml` 備份**,git 追蹤版本無 leo21c 帳號專屬 id
|
||||
殘留(已 grep 確認)。
|
||||
- [ ] T6 讀取/注入路徑:auth-dispatcher 改 D1 ref → `env[ref]` 取值(§2.5)+ 更新 last_used。
|
||||
- [ ] T7 雙讀 fallback(§4.1)。
|
||||
- [ ] T8 回填端點 `POST /credentials/migrate-to-workers-secrets`(§4.2,冪等可審)。
|
||||
|
||||
Reference in New Issue
Block a user