8d8b01d240
leo 2026-07-21 明令封存:卷已完成,留主目錄會讓未來 session 誤以為進行中。
最後一項 T10(廢除自管加密金鑰)已於 20c7610 完成(移除約 2500 行)。
- git mv 整卷 → system-dev/docs/3-specs/archive/credential-primitives-wasm/
design.md status: closed;superseded_by 留空(據實:非被另一卷取代,是機制整個換掉)
- 卷首補「封存時仍未完成的項目」——逐條查 code 核實,不當作完成:
真缺口=auth_mtls 從未實作、7.6 self-hosted auth 鏈端到端從未驗;
另有勾選過期(auth_oauth2 其實已完成)與驗收條件已作廢(與現行 rule 07 牴觸)者
- 修好 14 處引用(原盤點 10 處,實際更多):session-start-load-sdd.sh 內容嚴重過期
(把已完成 Phase 寫成進行中)→ 改為以 frontmatter 為判準;四份 rules、CLAUDE.md、
BACKLOG、3-specs/README、deploy.ts、credentials.ts、wrangler.toml 逐一按性質處理
- 額外:system-dev/docs/2-architecture/ 有四個規則檔重複副本(06-08 遷移遺留)
→ 同步修好,否則留一份過期真相(今日第三次撞到「同一資訊兩份副本」的債)
- 02-forbidden.md §2.1 列的三個「待刪違規 TS」其實早已不存在
→ 改標刪除線+禁止重新引入(過期文件同時製造假待辦與假進行中)
驗證:sdd-active-check exit 0(active 仍恰一份=portal-auth);
session-start-load-sdd.sh exit 0;cypher-executor 與 cli typecheck 全綠;
測試 187/188(唯一 fail 為 pre-existing,stash 覆驗相同)。
未動:pre-write-guard.sh 的 KNOWN_SDDS 白名單不含 archive 路徑
(放寬 guardrail 需明確授權,留待決定)。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
215 lines
20 KiB
Markdown
215 lines
20 KiB
Markdown
# Credential Store 重設計提案(A telegram 一致性 + B KV→D1 + C 友善前門)
|
||
|
||
> ⚠️ **歷史記錄**:本檔的儲存決策已被 `credential-store-migration.md` 取代並執行完畢
|
||
> (2026-07-20)。文中提及的舊自管金鑰機制**已不存在**,僅供考古,勿依此操作。
|
||
|
||
> 建立:2026-06-29 by arcrun CC|更新:2026-06-29(依 leo 最終精確 spec 改寫)|對應 issue:Arcrun#13
|
||
> 範圍宣告:本檔是既有 SDD `credential-primitives-wasm/` 的補充設計筆記(不是新 SDD 子系統,rule 02 §4.3 例外)。
|
||
> 詞彙(leo 堅持精確):**零件/component=TinyGo WASM**、**recipe=http_request+固定設定(打最終 API)**、
|
||
> **workflow=多步 YAML(在這層「按名指定要哪個 credential」)**、**auth-recipe=credential 怎麼注入**。
|
||
|
||
---
|
||
|
||
## 0. leo 的最終 spec(一句話):**不是拆除,是把前門做友善 + 把 D1 收尾**
|
||
|
||
**保留全部既有零件,只改「credential 怎麼餵進去」,不改 recipe 本身。**
|
||
|
||
```
|
||
人填 .env / 環境變數 ← 友善前門,任何人都會(本機=.env;雲端=code-on-web 的 Environment 設定,對稱)
|
||
↓ acr creds push 保留,但「值的來源」= .env/env-var(不再強迫手寫 credentials.yaml)
|
||
長久存「我的 D1」 ← 存一次,存進使用者自己的 D1;之後自動,永不重推
|
||
↓ workflow YAML「按名」指定要哪個 credential("我要 google 那把")→ 自動從 D1 取
|
||
recipe 打最終 API ← telegram_send / notion / gsheets,保留,不刪
|
||
```
|
||
|
||
**對稱性**:本機讀 `.env`;雲端讀 code-on-web 的 Environment 設定。**同機制,只是來源位置不同。**
|
||
|
||
### 明確「保留、不可刪」
|
||
1. **`acr creds push` 保留** —— 手動推單一 credential 仍合法(只是不再是唯一/被迫的路徑)。
|
||
2. **最終 API recipe 保留** —— telegram_send / notion / gsheets(http_request + 固定設定)是打 API 的端點,**不刪**。改的是「credential 怎麼餵」,不是 recipe。
|
||
|
||
---
|
||
|
||
## 0.5 Q1 — list 是動態讀 store 還是 hardcoded?(已核實 code,2026-06-29)
|
||
|
||
**結論:recipe/auth-recipe 的「正規清單」是動態的;但 `acr parts` 是 hardcoded 且把 5 個 recipe 混進去 → 那 5 個之外的 pushed recipe 在 `acr parts` 看不到。**
|
||
|
||
| 指令 | 讀哪裡 | 動態? | pushed recipe 會出現? |
|
||
|---|---|---|---|
|
||
| `acr recipe push` | `POST /recipes` → KV store(recipe.ts:87) | — | 寫入 store |
|
||
| `acr recipe list` | `GET /recipes` → `RECIPES.list({prefix:'recipe:'})`(recipe.ts:182 / recipes.ts:260) | ✅ 動態 | ✅ 會 |
|
||
| `acr auth-recipe list` | `GET /auth-recipes` → `RECIPES.list({prefix:'auth_recipe:'})`(auth-recipe.ts:42 / recipes.ts:547) | ✅ 動態 | ✅ 會 |
|
||
| **`acr parts`** | **hardcoded `BUILTIN_COMPONENTS` 陣列(parts.ts:28-262),完全不 fetch store** | **❌ 靜態** | **❌ 不會** |
|
||
|
||
- **component(零件=WASM)hardcoded 是對的**:零件只能 PR merge 新增(mindset §4 人類閘門),固定、慢增,靜態清單反映真實。
|
||
- **但 `acr parts` 把 5 個 recipe 也 hardcode 進去**(parts.ts:197-261:gmail_send / google_sheets_append / telegram_send / line_notify_send / notion)——**這是 component 與 recipe 的 conflation**。recipe 是動態投稿的(任何人 `acr recipe push`),卻被釘進 `acr parts` 的靜態清單。
|
||
- **後果(leo 的擔憂成立,但範圍精確)**:用戶 `acr recipe push my_recipe` → 進 store → `acr recipe list` / `acr recipe search` **看得到**;但 `acr parts` **永遠看不到**(除非改 source 重發 CLI)。「submitted = invisible」**只發生在 `acr parts` 這個面**,不是整個生態壞掉。
|
||
- **與 telegram bug 的關係**:telegram bug 是另一條軸(seed source vs live KV 漂移,A 已修),但與此**同病**=「hardcoded 清單 ≠ live store」。`acr parts` 列退役/釘選 recipe(#13)也是這病的症狀。
|
||
|
||
### Q1 修法 scope(建議,未在本批改 code)
|
||
1. **`acr parts` 移除 5 個 recipe 的 hardcode**(parts.ts:197-261),只留**真零件**(logic/data/ai/http_request/cron…=WASM,PR-only,靜態正確)。
|
||
2. **`acr parts` 末尾改成「指路」**:列完真零件後,動態提示「整合類服務 → `acr auth-recipe list`(即時讀 store);API recipe → `acr recipe list`(即時讀 store)」。讓 AI/人從 `acr parts` 被導到動態清單,不在靜態清單找 recipe。
|
||
- 進階(可選):`acr parts` 末段直接 fetch `GET /recipes` + `GET /auth-recipes` 把 store 的 recipe 也列出來(標明「動態,來自 store」),徹底消除「submitted = invisible」。
|
||
3. **明確分流原則寫進 parts.ts 註解**:零件=靜態(PR-only);recipe/auth-recipe=動態(從 store 讀)。不再把 recipe 釘進零件清單。
|
||
4. 這 scope = #13「acr parts 殘留」的根治版(#13 只把 recipe 描述改對,沒解決「recipe 不該 hardcode 在 parts」的結構問題)。**屬薄殼修正(rule 07)=把「列 recipe」這能力從介面靜態資料改成讀 API store,不違禁令。**
|
||
|
||
---
|
||
|
||
## 1. 現狀(已核實 code + 實測 live,2026-06-29)
|
||
|
||
### 1.1 儲存:**KV,不是 D1**(B 的根因=未完成的遷移,非「設計即如此」)
|
||
- credential 只存 `CREDENTIALS_KV`,key=`{api_key}:cred:{name}`,AES-GCM。
|
||
- 寫:`acr creds push` → `POST /credentials`(`cypher-executor/src/routes/credentials.ts:48`)。
|
||
- 讀+解密:`auth_static_key` WASM `kv_get`(`registry/components/auth_static_key/main.go:146`)。
|
||
- binding:`cypher-executor/wrangler.toml:23`;型別 `src/types.ts:31`。
|
||
- **全 repo 無任何 credential 的 D1**(D1 引用全是 KBDB graph)。
|
||
- leo 確認:採用 KBDB 後使用者已有自己的 D1,當時就要求 credential 也搬進「我的 D1」長久存 → **此遷移從未完成**。
|
||
→ B(KV→D1)**確定要做**,是 leo 明確要的「長久存我的 D1」層。
|
||
|
||
### 1.2 .env → credential:**值不會自動進**(C 的痛點,但前門不友善 ≠ 拆掉)
|
||
- `.env` 目前只供「設定」:`ENCRYPTION_KEY`/`NAMESPACE`/`ARCRUN_*`/`CLOUDFLARE_*`(`cli/src/lib/config.ts:125`)。
|
||
- credential 的**值**只來自手寫 `credentials.yaml` → `acr creds push`(`cli/src/commands/creds.ts`)。
|
||
- leo 記憶「notion/gsheets 只靠 .env 就通」與 code 不符——實際是早先 push 過、值已在 KV。
|
||
- 痛點(北極星「拿 credential ≠ 攻打用戶」):每次要手寫 yaml;不像 n8n Credentials tab 填一次長存。
|
||
→ **C 不是發明「自動偵測魔法」**,而是把 `acr creds push` 的**值來源**從「手寫 yaml」改成「讀 .env/env-var」,存進 D1,之後 workflow 按名取。
|
||
|
||
### 1.3 telegram 漂移(A)——已實測 smoking gun,已修 source
|
||
- recipe `telegram_send`(`api-recipe-seeds.ts:108`)`auth_service:'telegram'`,endpoint `.../bot{{auth.bot_token}}/sendMessage`。
|
||
- 但 `auth-recipe-seeds.ts` source 只有 **23** 個 service,缺 `telegram`/`line_notify`/`kbdb`/`google_user`。
|
||
- 實測:prod = 27(手動 seed 過 telegram);self-host **leo21c = 23,無 telegram** → telegram_send 找不到 auth recipe → `{{auth.bot_token}}` 注入空 → URL 變 `.../bot/sendMessage` → 壞。notion/gsheets 通是因它們在那 23 裡。
|
||
- 這是「source vs live 漂移=假綠」。telegram **不是**走 legacy `BUILTIN_CREDENTIALS_MAP`,正確形態一直是 recipe+auth-recipe,只是 auth-recipe 沒進 source 種子。
|
||
|
||
---
|
||
|
||
## 2. 目標狀態(target,=leo 的 3 層流,全部保留只連得更友善)
|
||
|
||
1. **唯一打外部 API 的方式**= recipe(保留)。telegram 與 notion/gsheets **同一條**「workflow 按名指定 → 從 D1 取 → auth-recipe 注入 → recipe 打 API」鏈,無例外(A,本次已修 source)。
|
||
2. **credential 長久存使用者自己的 D1**(如 n8n Credentials tab):填一次、長存、workflow 按名引用、永不重推(B)。
|
||
3. **友善前門**:使用者把 token 填進 `.env`(本機)/ code-on-web Environment(雲端)**一次**,`acr creds push`(保留)以此為值來源,client 端加密後存進 D1。不再被迫手寫 `credentials.yaml`(C)。
|
||
|
||
---
|
||
|
||
## 3. 遷移步驟(A 已做;B/C 是設計變更,誠實標工作量)
|
||
|
||
### Phase A — telegram/line_notify/kbdb 一致性(本次已做,commit 90777e3,未 push/merge)
|
||
- [x] `auth-recipe-seeds.ts` 補 telegram(inject.path bot_token)/ line_notify(header Bearer)/ kbdb(header Bearer),形態取自 prod。
|
||
- [x] `recipes.ts` `AuthInjectSpec` 補 `path?`(WASM/SDD §六早有、source 介面漏 → tsc 擋)。
|
||
- [ ] google_user(oauth2)暫不回灌:內嵌 client_secret 不可進 git + 介面無 oauth2 欄 → 留 Phase D。
|
||
- 部署後 leo21c 跑 `acr update`(/init/seed) → 23→26,telegram 即與 notion 同鏈可用。
|
||
- **不刪任何 recipe;不碰 `acr creds push`。** 純補種子 + 補型別欄位。
|
||
|
||
### Phase B —(已翻案,見 §4.5)儲存:**KV 維持,不搬 D1**;高敏感可選補 Secrets Store
|
||
> 早先版本寫「KV→D1 遷移」。§4.5 核實史實 + leo 自己 2026-06-07 拍板(credential 留 KV)後**翻案**:
|
||
> credential=Redis-class(按 key 直接點查、密文不可 SQL 查),搬 D1 是淨負債。**B 改為:**
|
||
1. **低敏感 credential 維持 KV**(現狀 CREDENTIALS_KV,AES-GCM)。`acr creds list` 已可用(`GET /credentials` KV.list)。
|
||
2. **(可選、後續)高敏感(service account JSON/private key)→ Cloudflare Secrets Store**(credential_parts.md §8.2,KV 只存 ref)。唯一值得的儲存升級,與拍板不衝突。
|
||
3. **不新增 D1 credentials 表、不新增 `cred_get` host function、不做 KV→D1 migration**——這些原計畫取消(好處 KV 已有)。
|
||
4. 若 leo 仍要 D1:屬新需求(須更新 2026-06-07 拍板)。即便如此,密文本體仍留 KV/Secrets Store,D1 只放非機密 metadata。
|
||
5. 風險:跨 TS Worker / WASM / host function 三層,**必端到端實測**(防再假綠,mindset §7)。**非小工程。**
|
||
|
||
### Phase C — 友善前門:`acr creds push` 值來源=.env/env-var → D1(小~中工程,依附 B)
|
||
> **精確(leo 修正)**:不是「自動 pickup 魔法」,是「`acr creds push` 保留,但值的來源改成 .env/env-var,存進 D1,之後 workflow 按名取」。
|
||
1. `acr creds push`(保留)新增「從 .env/env-var 讀值」模式:掃 .env 中「已知 credential 名」
|
||
(由 auth-recipe 的 `required_secrets[].key` 反推,例 `notion_token`/`telegram_bot_token`)→ client 端加密 → 存進 D1(Phase B 的 store)。
|
||
- 仍保留現有「從 credentials.yaml 讀值」模式(向後相容,不刪)。yaml 變成可選輸入源之一,不再是被迫。
|
||
2. **對稱**:本機讀 `.env`(`config.ts loadDotEnvOnce` 已會載入 .env 進 `process.env`);
|
||
雲端=code-on-web 的 Environment 設定(同樣落到 env-var)。同一套讀法、不同來源位置。
|
||
3. 名稱規約:.env 用大寫(`NOTION_TOKEN`)→ normalize 成 credential 名 `notion_token`(=auth-recipe required_secrets.key)。
|
||
4. **薄殼界線**(rule 07):這是「擴 `acr creds push` 的輸入源」=介面慣例的輸入解析(§2 允許第 1 項),
|
||
**不是**在 CLI 拼裝 API 缺的能力(值來源是 .env/yaml 都只是「轉成 API 期望的加密 payload」)。加密仍 client 端(§2 第 4 項唯一例外)。store 仍是 API(D1)。
|
||
5. 結果:填一次 .env → `acr creds push`(或 deploy 末尾自動觸發一次)→ 長存 D1 → workflow 按名引用、零重複推。
|
||
|
||
### Phase D(後續,非本批)— google_user(oauth2) 回灌 + oauth2 secret 部署期注入
|
||
- AuthRecipeDefinition 介面補 oauth2 欄位;client_secret 走 `wrangler secret`/env 注入(不進 git),再回灌 source。
|
||
|
||
---
|
||
|
||
## 4. 正解:telegram 的 workflow / recipe yaml(給 mira 抄)
|
||
|
||
telegram 發訊=**recipe `telegram_send`**(不是 component、不是自建零件);**credential 在 workflow 層按名指定**:
|
||
|
||
```yaml
|
||
name: notify_done
|
||
flow:
|
||
- "notify >> ON_SUCCESS >> end" # 單節點時 flow 可省
|
||
|
||
config:
|
||
notify:
|
||
component: telegram_send # ← 內建 recipe canonical_id(不是 component:telegram)
|
||
chat_id: "123456789"
|
||
text: "✅ 任務完成"
|
||
# bot_token 不寫這裡。recipe 的 auth_service='telegram' → 按名從 D1 取 telegram_bot_token
|
||
# → auth-recipe:telegram 的 inject.path 注入進 URL path。一致鏈,與 notion/gsheets 同型。
|
||
```
|
||
|
||
**credential 解析(target 設計):**
|
||
1. 使用者把 `TELEGRAM_BOT_TOKEN=123456:ABC...` 填進 `.env`(本機)/ code-on-web Environment(雲端)**一次**。
|
||
2. `acr creds push`(保留;值來源=.env)→ client 加密 → 存進「我的 D1」credential store。**之後永不重推。**
|
||
3. 執行時:cypher-executor 見 `telegram_send.auth_service='telegram'` → `auth_static_key` WASM 用 `cred_get` 從 D1 取
|
||
`telegram_bot_token` 密文 → `crypto_decrypt` → 依 `auth_recipe:telegram` 的 `inject.path.bot_token` 輸出 `auth_path`
|
||
→ `makeRecipeRunner` 把 endpoint `{{auth.bot_token}}` 換成真 token → POST `https://api.telegram.org/bot<token>/sendMessage`,body=`{chat_id,text}`。
|
||
|
||
這條鏈與 notion(header 注入)/gsheets(service_account runtime token 注入)**完全同型**,只注入位置不同(path vs header)。
|
||
|
||
> **過渡期(B/C 未完成前,今天就能用的方式)**:在 `credentials.yaml` 放 `telegram_bot_token` + `acr creds push`(值進 KV)。
|
||
> 上面 yaml 的 workflow 寫法不變——只是 store 暫時是 KV、值來源暫時是手寫 yaml。B/C 完成後 store→D1、來源→.env,**workflow yaml 一字不改**(按名引用穩定)。
|
||
|
||
---
|
||
|
||
## 4.5 Q2 — KV vs D1:史實核實 + 三方調和 + CC 推薦(leo 授權我決定)
|
||
|
||
### 史實(git 核實,2026-06-29):**本 repo 的 credential 從來沒在 D1**
|
||
- 最早 MVP commit `2707fca`:credential 即「AES-GCM decrypt from **CREDENTIALS_KV**」。
|
||
- 更早的 u6u-credentials ancestor worker(`credentials/` 已刪):`CREDENTIALS_KV.put('cred:${id}')`——**也是 KV**。
|
||
(它的 `CredentialRecord` 已有 name/type/created_at 結構欄位,但以 JSON 存進 KV。)
|
||
- 全 history 的 `CREATE TABLE` 只有 KBDB(entries/templates/entry_values),**從無 credentials 表**。
|
||
- → **找不到任何「credential D1→KV 撤退」的 commit**。leo 記憶的「原本 D1 有 credentials 表、後來退 KV」
|
||
**在本 repo 史實裡不存在**(可能是 pre-repo 設計或別處,沒落地過 code)。
|
||
|
||
### 三方說法(全部攤開,none 寫 D1 存 credential)
|
||
| 來源 | 對 credential 儲存的說法 |
|
||
|---|---|
|
||
| leo 口頭(現在) | 存 **D1**(「長久存我的 D1」) |
|
||
| 現行 code | **KV**(CREDENTIALS_KV,MVP 至今未變) |
|
||
| **kbdb-base SDD 拍板 2026-06-07(leo 親簽「Leo:同意」)** | **credential 留 KV**(「session、verdict、credential 留 KV=短期高頻純取用,類比 Redis;workflow/recipe/成功記錄才進 D1=要層級/列舉/排序」)。`kbdb-base/design.md:318`、`tasks.md:11`、`tasks.md:83` 三處一致。 |
|
||
| credential_parts.md §8.2(長期需求源) | **tenant KV + Cloudflare Secrets Store**(低敏感→KV AES-GCM;高敏感如 service account JSON/private key→Secrets Store,KV 只存 ref)。**不是 D1。** |
|
||
|
||
→ **leo 口頭「D1」與他自己 2026-06-07 的書面拍板(credential 留 KV)直接衝突**,且兩份書面需求源都沒說 D1。
|
||
SDD 協議(00-sdd-protocol「規範互相矛盾→引原文、不自行猜」)要求攤開矛盾;但 leo 此次**明確授權「你決定並推薦」**,故下方給推薦(grounded in 上述證據),同時把矛盾標清楚讓 leo 有機會推翻。
|
||
|
||
### 「退 D1→KV 的理由還成立嗎?」(leo 的核心提問)
|
||
- 本 repo 沒發生過該退守,故無「當初理由」可考。但 leo 假設的理由(「self-hosted 少依賴、免 D1」)**今天確實已 moot**——
|
||
self-hosted 用戶現在本來就有一顆 KBDB D1(`kbdb/wrangler.toml:10` `[[d1_databases]]`,deploy.ts 注入用戶自己的 id)。
|
||
- **但「能用 D1」不等於「credential 該用 D1」。** 2026-06-07 拍板把 KV 留給 credential 的理由不是「沒有 D1」,
|
||
而是**「credential =短期高頻純取用(by api_key+name 直接點查),是 Redis-class 工作負載,不需要 D1 的層級/列舉/排序」**。
|
||
這個理由**與有沒有 D1 無關,今天仍成立**。
|
||
|
||
### ✅ CC 推薦(leo 授權我決定):**credential 主存維持 KV;不為「列表/按名引用」而搬 D1**
|
||
理由(誠實 trade-off,mindset §7):
|
||
1. **守 leo 自己的拍板**:2026-06-07「credential 留 KV」是有理由的設計(Redis vs PostgreSQL 分工),非偷懶。推翻它要有新理由,目前沒有。
|
||
2. **D1 宣稱的好處在 KV 上已可達或不需要**:
|
||
- 「`acr creds list`」KV 已能做(`GET /credentials` 用 `KV.list({prefix})` 列名,credentials.ts:68-78 已實作,**今天就有**)。
|
||
- 「按名引用(workflow 指定要哪把 cred)」是 **key 設計**(`{api_key}:cred:{name}`)就給的,與 KV/D1 無關——telegram_send 的 `auth_service`→`required_secrets.key` 已是按名取。**A 修好後就具備,不需 D1。**
|
||
- 「結構化欄位/sensitivity 分級」credential 是不可查詢的密文 blob(查詢明文=洩漏),D1 的 SQL 查詢優勢對 credential **用不上**;分級需求由 credential_parts.md 的 **Secrets Store**(高敏感)解,不是 D1。
|
||
3. **搬 D1 成本高且踩鐵律邊界**:要新 host function `cred_get`(WASM 改)、一次性 migration、跨 TS/WASM/host-function 三層 e2e——換來的好處 KV 已有。**淨負債。**
|
||
4. **真正缺的不是 D1,是「友善前門 C」**:leo 真痛點是「每 cred 手寫 yaml + 重推」,那是 **C(.env 當值來源 + 一次存)** 解的,**與 store 是 KV 還 D1 無關**。
|
||
|
||
**推薦的目標儲存(取代本檔早先「搬 D1」設計):**
|
||
- **低敏感 credential(多數 token/api_key)→ 維持 KV**(現狀,AES-GCM)。
|
||
- **高敏感(service account JSON / private key)→ Cloudflare Secrets Store**(依 credential_parts.md §8.2,KV 只存 ref)——這是**唯一值得做的儲存升級**,且與 leo 拍板不衝突(拍板說 credential 留 KV,未禁高敏感走 Secrets Store;兩者互補)。
|
||
- **C(友善前門)照做**:`acr creds push` 值來源=.env/env-var、存一次、workflow 按名取。**store 仍 KV(+Secrets Store)**。
|
||
- → **B 從「KV→D1 遷移」改為「KV 維持 + 高敏感補 Secrets Store(可選、後續)」**。telegram/notion/gsheets 的一致鏈(A)與一次填(C)**完全不依賴 D1**。
|
||
|
||
> 若 leo 看完仍要 D1(例如想未來在同一顆 DB 做 cred 審計/輪替記錄):那是**新需求**,需更新 2026-06-07 拍板。
|
||
> 屆時 credential **本體**仍建議 KV/Secrets Store(密文不需 SQL),D1 只放**非機密的 metadata**(cred 名稱/服務/建立時間/last_verified),與 workflow/recipe 進 D1 同模式。**不要把密文搬進 D1 當主存。**
|
||
|
||
---
|
||
|
||
## 5. 與既有鐵律/SDD 的對齊
|
||
- **不刪 recipe、不禁 `acr creds push`**(leo spec)。A 純補種子 + 型別欄位;C 是擴 `acr creds push` 輸入源,非拆除。
|
||
- 不新建 component(mindset §1 / rule 02)。
|
||
- credential 解密仍在 WASM(rule 02 §2.2);KV→D1 只是密文來源從 `kv_get` 換成新 host function `cred_get`(屬 wasi-shim,rule 02 §2.3 合法)。
|
||
- 薄殼(rule 07):`acr creds push` 讀 .env 仍只做「輸入解析 + client 加密 + 呼叫 API」,能力(store)在 API/D1,不在介面層。
|
||
- 設計權威:`auth-recipe.md` §六(telegram path 注入 line 70-71)、§七(kbdb 共用 line 150-151);
|
||
需求源 `docs/user_requirements/credential_parts.md`(credential 長期規格)。
|