feat(credential-store-migration): T2 D1 migration 0002_credentials.sql

新增 credentials 目錄表(api_key/name/service/sensitivity/secret_ref/
created_at/last_used_at,PRIMARY KEY(api_key,name) + idx_cred_apikey),
D19:只存目錄不存密文,密文本體改住 CF Workers per-script Secrets(T5)。

deploy.ts 重用既有 applyD1Migration,緊接 0001_base.sql 之後套用同一顆 D1,
機制完全一致(同一支 CF D1 query API)。

驗證:cli tsc --noEmit exit 0;leo21c arcrun-kbdb D1
(1099d0f3-d062-4202-984c-5a57b0a8c031)實際套用,
sqlite_master 確認 table+index 存在,重跑驗證冪等。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018D6QoC5waFkcjc2N7csJBB
This commit is contained in:
Claude
2026-07-03 22:52:09 +00:00
parent abf232327c
commit f9dad311ff
3 changed files with 45 additions and 1 deletions
+16
View File
@@ -264,6 +264,22 @@ export async function downloadAndDeploy(
} else {
failures.push(`D1 migration: 部署物缺 kbdb/migrations/0001_base.sql${migPath}`);
}
// 3.6 credential-primitives-wasm T2credential-store-migration.md §2.2):
// credentials 目錄表(api_key/name/service/sensitivity/secret_ref/created_at/last_used_at)。
// 同一顆 D1(與 KBDB base 共用),冪等 IF NOT EXISTS,套用機制與 0001_base.sql 完全相同
// (同一個 applyD1Migration helper,同一支 CF D1 query API)。D19:這張表不含密文,
// 密文本體住在 Workers per-script Secrets(見 cypher-executor/src/routes/credentials.ts)。
const credMigPath = join(root, 'kbdb', 'migrations', '0002_credentials.sql');
if (existsSync(credMigPath)) {
try {
await applyD1Migration(ctx, readFileSync(credMigPath, 'utf8'));
} catch (e) {
failures.push(`D1 migration 0002_credentials (${ctx.d1DatabaseId}): ${e instanceof Error ? e.message : String(e)}`);
}
} else {
failures.push(`D1 migration: 部署物缺 kbdb/migrations/0002_credentials.sql${credMigPath}`);
}
}
const cypherExecutorUrl = ctx.workerSubdomain
+20
View File
@@ -0,0 +1,20 @@
-- credential-primitives-wasm — credential-store-migration T2D19D1 只存目錄,不存密文)
-- SDD: system-dev/docs/3-specs/arcrun/credential-primitives-wasm/credential-store-migration.md §2.2
--
-- 密文本體不在這裡:值住在 CF Workers per-script Secrets(掛在 cypher worker 上,管理 API 唯寫)。
-- 這張表只存「目錄」:租戶(api_key) / 名字 / 服務 / 敏感度 / 指向 Workers Secrets 的 env var 名(secret_ref)。
-- 冪等(IF NOT EXISTS),與 0001_base.sql 同模式,套用機制走 cli/src/lib/deploy.ts applyD1Migration。
-- 同一顆 D1(與 KBDB base 共用 arcrun-kbdb),不新建第二顆。
CREATE TABLE IF NOT EXISTS credentials (
api_key TEXT NOT NULL, -- 租戶
name TEXT NOT NULL, -- credential 名(= auth-recipe required_secrets[].key,如 telegram_bot_token
service TEXT, -- 對應 servicetelegram / notion …),可空
sensitivity TEXT NOT NULL DEFAULT 'standard', -- 'standard' | 'high'high = SA JSON/private key
secret_ref TEXT NOT NULL, -- 指向 Workers Secrets 的 env var 名(如 CRED_TELEGRAM_BOT_TOKEN_XXXXXXXX;不是密文本體)
created_at INTEGER NOT NULL,
last_used_at INTEGER, -- 執行注入時更新(治理面 last_used 顯示用)
PRIMARY KEY (api_key, name)
);
CREATE INDEX IF NOT EXISTS idx_cred_apikey ON credentials(api_key);
@@ -169,7 +169,15 @@ CLI 薄殼(rule 07):`acr creds list`(讀 D1 顯示)、`acr creds repla
## 7. 任務分解(T1.5 全過,T2-T9 解凍施工——2026-07-03,依總管 Arcrun#2 裁決)
- [x] T1 spikeleo21c CF 帳號 Secrets Store create store + worker by-ref 取值驗證(解 Q-a)。**結果:負結果,路徑不成立**(binding 靜態宣告、`.get(ref)` 參數被忽略、REST 唯寫;2026-07-02,證據 Arcrun#2)→ 轉向 T1.5。
- [x] T1.5 spike**Workers per-script Secrets 四驗證全過**(① API 動態加免重部署即讀 ② `env[ref]` 動態索引可行 ③ 14 把未觸上限(D21:記錄即可)④ 重部署後存活;2026-07-03,證據 Arcrun#2)。**方向定案,硬前置解除。**
- [ ] T2 D1 migration `0002_credentials.sql`(§2.2+ deploy.ts 注入。
- [x] T2 D1 migration `0002_credentials.sql`(§2.2+ deploy.ts 注入。2026-07-03 完成:
`kbdb/migrations/0002_credentials.sql` 新增(IF NOT EXISTS 冪等,schema 對齊 §2.2);
`cli/src/lib/deploy.ts` §3.6 新增區塊,重用既有 `applyD1Migration` helper,緊接在 0001_base.sql
套用之後、同一顆 D1`ctx.d1DatabaseId`)、同一支 CF D1 query API,機制與 0001 完全一致。
`cli` package `tsc --noEmit` exit 0(無輸出)。**端到端證據**leo21c `arcrun-kbdb` D1
uuid `1099d0f3-d062-4202-984c-5a57b0a8c031`):`POST .../d1/database/{id}/query` 送整份
0002_credentials.sql → `{"success":true,...}``SELECT name FROM sqlite_master WHERE
type='table' AND name='credentials'` → 回 `{"name":"credentials"}`schema dump 確認欄位與
`idx_cred_apikey` index 完全對齊 §2.2;重跑同一份 migration 第二次 → `success:true`(冪等驗證)。
- [ ] T3 `acr init/update` 確保 secrets 寫入設定就緒:cypher worker 持有「能打 Workers Scripts secrets API 的 CF API token」+ account id(§2.3 寫入路徑;per-script secrets **無 store 資源需 ensure**,原「ensure store + 注入 store_id」整步取消)+ 於非關鍵 worker 跑一次 `acr update` 全流程驗證 secrets 存活(補 spike ④ 的誠實缺口)。〔依 T1.5 spike 2026-07-03 改寫,證據 Arcrun#2
- [ ] T4 wasi-shim 新增 `secret_get(ref)` host function(守 rule 02 邊界;host 端實作=`env[ref]` 動態索引,spike ② 已證可行,零網路呼叫)。〔依 T1.5 spike 2026-07-03 改寫,證據 Arcrun#2
- [ ] T5 寫入路徑:`POST/PUT /credentials` 改寫 Workers SecretsAPI `PUT`+ D1 ref(§2.4)。