fix(auth-recipe): 回灌 telegram/line_notify/kbdb 種子,補 AuthInjectSpec.path(修 source/live 漂移)

issue #13 升級:根因不只 acr parts 殘留,是 auth-recipe-seeds.ts source 漏了 3 個 static_key
auth recipe(telegram/line_notify/kbdb),但 prod KV 手動 seed 過 → 任何全新 self-hosted
`POST /init/seed` 只 seed 23 個、漏 telegram → self-host(leo21c/mira)telegram_send 的
auth_service:'telegram' resolve 不到 → {{auth.bot_token}} 注入空 → telegram 發訊壞掉。

實測 smoking gun(2026-06-29):
- prod cypher.arcrun.dev/auth-recipes = 27 個(含 telegram)
- self-host arcrun-cypher-executor.leo21c.workers.dev = 23 個(無 telegram/line_notify/kbdb)

修法(資料/型別,非業務邏輯,守 mindset §1 不建 component):
- auth-recipe-seeds.ts 補 telegram(inject.path bot_token)/line_notify(header Bearer)/kbdb(header Bearer)
- recipes.ts AuthInjectSpec 補 path?(WASM auth_static_key + SDD §六早有此欄、source 介面漏 → tsc 擋)
- google_user(oauth2)暫不回灌:內嵌 client_secret 不可進 git + 介面無 oauth2 欄 → 留 Phase D

形態取自 prod GET /auth-recipes/{service};設計權威 auth-recipe.md §六(telegram path)/§七(kbdb 共用)。
telegram 自此與 notion(header)/gsheets(service_account) 同一條 recipe+auth-recipe 鏈,一致。
tsc 全綠;local 模擬 token-in-path 注入 PASS。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
uncle6me-web
2026-06-29 12:37:19 +08:00
parent 764f657201
commit 90777e3877
2 changed files with 100 additions and 0 deletions
@@ -11,6 +11,13 @@ import type { AuthRecipeDefinition } from '../routes/recipes';
const now = Date.now(); const now = Date.now();
// ⚠️ 已知 source/live drift2026-06-29 盤點,未在此檔修):
// prod RECIPES KV 另有 `auth_recipe:google_user`primitive: oauth2)。**故意不回灌 source**,原因:
// (1) 它內嵌 client_secretGOCSPX-...= 機密,不可進 gitwiki-secret-scan / 一般安全);
// (2) 本檔的 AuthRecipeDefinition 介面尚無 oauth2 欄位(client_id/secret/token_endpoint/scopes),
// 回灌前需先擴 schema + 把 secret 改成部署期注入(wrangler secret / env),屬獨立工作。
// → google_user 留待 oauth2 seed 機制(含 secret 注入)獨立處理;本次只修無機密的 static_key 漂移。
export const AUTH_RECIPE_SEEDS: AuthRecipeDefinition[] = [ export const AUTH_RECIPE_SEEDS: AuthRecipeDefinition[] = [
// ── Static Key 類 ────────────────────────────────────────────────────────── // ── Static Key 類 ──────────────────────────────────────────────────────────
@@ -556,6 +563,94 @@ export const AUTH_RECIPE_SEEDS: AuthRecipeDefinition[] = [
updated_at: now, updated_at: now,
}, },
// ── 訊息 / URL-path 注入類(static_key)────────────────────────────────────
//
// 2026-06-29 補:以下三個 static_key auth recipe 一直存在於 prod RECIPES KV(手動 seed 過),
// 但**從未進 source seed**auth-recipe-seeds.ts)→ 任何全新 self-hosted `POST /init/seed`
// 只會 seed 23 個、漏掉 telegram/line_notify/kbdb → self-hostmira/leo21c)的 telegram 發訊
// 走不通(telegram_send 的 auth_service:'telegram' 找不到 auth recipe → {{auth.bot_token}} 注入空)。
// 這正是「source vs live drift = 假綠」(總管反覆踩的同一類)。把 prod 現役定義回灌 source
// 讓 official 與 self-host 共用同一份種子。形態取自 prod GET /auth-recipes/{service}2026-06-29)。
// 設計權威:auth-recipe.md §六(line 70-71, telegram path 注入) + §七(line 150-151, kbdb 共用)。
{
kind: 'auth_recipe',
service: 'telegram',
version: 1,
primitive: 'static_key',
base_url: 'https://api.telegram.org',
display_name: 'Telegram Bot',
description: 'Telegram Bot API — sendMessage 等(bot token 注入 URL path /bot{token}/',
required_secrets: [
{
key: 'telegram_bot_token',
label: 'Bot Token(從 @BotFather 取得)',
help: '在 Telegram 對 @BotFather 送 /newbot 建立 bot,取得格式為 123456:ABC... 的 token',
help_url: 'https://core.telegram.org/bots/features#botfather',
},
],
// path 注入:recipe:telegram_send 的 endpoint 用 {{auth.bot_token}} 從 _auth_path 取值
// auth_static_key WASM 解密後輸出 auth_path → auth-dispatcher 帶進 _auth_path
// → makeRecipeRunner interpolate)。token 不落 header/query/body,符合 Telegram 的 URL-path 慣例。
inject: {
path: {
bot_token: '{{secret.telegram_bot_token}}',
},
},
created_at: now,
updated_at: now,
},
{
kind: 'auth_recipe',
service: 'line_notify',
version: 1,
primitive: 'static_key',
base_url: 'https://notify-api.line.me',
display_name: 'LINE Notify',
description: 'LINE Notify — 推播訊息(static_key Bearer',
required_secrets: [
{
key: 'line_token',
label: 'LINE Notify Token',
help: '至 https://notify-bot.line.me/my/ 發行個人存取權杖',
help_url: 'https://notify-bot.line.me/my/',
},
],
inject: {
header: {
Authorization: 'Bearer {{secret.line_token}}',
},
},
created_at: now,
updated_at: now,
},
{
kind: 'auth_recipe',
service: 'kbdb',
version: 1,
primitive: 'static_key',
base_url: 'https://kbdb.finally.click',
display_name: 'KBDB',
description: 'KBDB partner API — block 讀寫(static_key Bearer)。kbdb_* recipe 共用此把 auth。',
required_secrets: [
{
key: 'kbdb_api_key',
label: 'KBDB API Key(至 arcrun 取統一 API Key 當 credential',
help: 'KBDB 採 Supabase 模式:要用 → 去 arcrun 取統一 API Key 當此 credential',
help_url: 'https://arcrun.dev',
},
],
inject: {
header: {
Authorization: 'Bearer {{secret.kbdb_api_key}}',
},
},
created_at: now,
updated_at: now,
},
// ── Service Account 類(Google 家族,共用同一份 service_account_json)──────── // ── Service Account 類(Google 家族,共用同一份 service_account_json)────────
{ {
+5
View File
@@ -460,6 +460,11 @@ export interface AuthInjectSpec {
header?: Record<string, string>; // e.g. { Authorization: "Bearer {{secret.token}}" } header?: Record<string, string>; // e.g. { Authorization: "Bearer {{secret.token}}" }
query?: Record<string, string>; query?: Record<string, string>;
body?: Record<string, string>; body?: Record<string, string>;
// path:注入 endpoint URL path 的 secretauth-recipe.md §六,2026-05-29 加)。
// 解 telegram 類「token 在 URL path」(/bot{token}/)—— header/query/body 都不適用。
// key = 模板變數名(recipe endpoint 用 {{auth.K}} 引用),value = {{secret.X}} 模板。
// auth_static_key WASM 解密後輸出為 auth_path → auth-dispatcher 帶進 _auth_path → makeRecipeRunner interpolate。
path?: Record<string, string>;
} }
export interface AuthRecipeDefinition { export interface AuthRecipeDefinition {