arcrun — AI workflow execution engine (clean history)
Self-hosted 開源:WASM 零件 + recipe + cypher-executor,跑在你自己的 Cloudflare。 此為重建的乾淨歷史起點(移除曾誤 commit 的 GCP SA 金鑰,舊歷史保留在 richblack/arcrun 與本地 backup 分支)。含: - acr init --self-hosted installer(建 KV/R2 + codeload 拉預編譯 wasm + wrangler deploy + seed recipe) - recipe push 把關(資料外流提醒 + 打通檢查) - 19 個正當零件預編譯 wasm(claude_api/km_writer/kbdb_upsert_block 排除:違反 DECISIONS §1) - CLI / cypher-executor / registry / 完整 SDD Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,107 @@
|
||||
/**
|
||||
* Auth Dispatcher
|
||||
*
|
||||
* 對需要認證的零件,在執行前 HTTP POST 到對應的 auth primitive Worker,
|
||||
* 取回 auth_headers / auth_query / auth_body 合併進節點 context。
|
||||
*
|
||||
* 嚴格邊界(rule 02 §2.2):
|
||||
* - 本檔**不做**任何 credential 解密 / template 展開 / JWT 簽章
|
||||
* - 那些全部在 auth primitive WASM 零件內執行(透過 host function `crypto_decrypt` 等)
|
||||
* - 本檔只做「查 recipe 決定走哪個 primitive Worker」+「HTTP fetch 取回注入結果」
|
||||
*
|
||||
* 目前階段接上 `auth_static_key` + `auth_service_account` + `auth_oauth2`,
|
||||
* Phase 4 剩 `auth_mtls`(mTLS handshake 在 Worker runtime 層)。
|
||||
*
|
||||
* 執行時機:graph-executor 在節點 runner 執行前呼叫,取回的 ctx 會:
|
||||
* 1. 先試本 dispatcher(命中才 return enriched ctx)
|
||||
* 2. 沒命中 fallback 到 `injectCredentials`(Phase 1.9 才刪除)
|
||||
*/
|
||||
|
||||
import type { Bindings } from '../types';
|
||||
import { resolveAuthRecipe, resolveRecipe } from '../routes/recipes';
|
||||
import { wasmWorkerUrl } from '../lib/component-loader';
|
||||
|
||||
/** 對應 Phase 1-4 會部署的 auth primitive Worker */
|
||||
const SUPPORTED_PRIMITIVES = new Set(['static_key', 'service_account', 'oauth2']);
|
||||
|
||||
/** auth primitive 本身的 componentId(避免自引用) */
|
||||
const AUTH_PRIMITIVE_IDS = new Set([
|
||||
'auth_static_key',
|
||||
'auth_service_account',
|
||||
'auth_oauth2',
|
||||
'auth_mtls',
|
||||
]);
|
||||
|
||||
/**
|
||||
* 試著對零件做 auth 注入。
|
||||
* - 命中(有對應 auth recipe 且 primitive 已支援)→ 回傳注入後的 ctx
|
||||
* - 未命中 → 回傳 null(呼叫端繼續跑舊路徑)
|
||||
*/
|
||||
export async function tryAuthDispatch(
|
||||
componentId: string,
|
||||
input: Record<string, unknown>,
|
||||
env: Bindings,
|
||||
apiKey: string,
|
||||
): Promise<Record<string, unknown> | null> {
|
||||
if (AUTH_PRIMITIVE_IDS.has(componentId)) {
|
||||
// auth primitive 本身不需要再做 auth
|
||||
return null;
|
||||
}
|
||||
|
||||
// 決定 auth service name:
|
||||
// 1. 若 API recipe 宣告了 auth_service(例 recipe:kbdb_get → "kbdb")→ 用它,
|
||||
// 讓多個 recipe 共用同一把 auth_recipe(不必每個 action 複製 auth recipe)。
|
||||
// 2. 否則 fallback 到把 componentId 當 service name(向後相容舊行為)。
|
||||
let service = componentId;
|
||||
const apiRecipe = await resolveRecipe(componentId, env.RECIPES);
|
||||
if (apiRecipe?.auth_service) {
|
||||
service = apiRecipe.auth_service;
|
||||
}
|
||||
|
||||
const recipe = await resolveAuthRecipe(service, env.RECIPES);
|
||||
if (!recipe) return null;
|
||||
if (!SUPPORTED_PRIMITIVES.has(recipe.primitive)) return null;
|
||||
|
||||
// 走新路徑:HTTP POST 到對應 auth primitive Worker
|
||||
// 走 workers.dev 避開同 zone 死鎖(P0 #9)
|
||||
const primitiveUrl = wasmWorkerUrl(`auth_${recipe.primitive}`, env.WORKER_SUBDOMAIN);
|
||||
const res = await fetch(primitiveUrl, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
action: 'authenticate',
|
||||
api_key: apiKey,
|
||||
service,
|
||||
}),
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
const text = await res.text().catch(() => '');
|
||||
throw new Error(
|
||||
`auth primitive "${recipe.primitive}" 回傳 ${res.status}: ${text.slice(0, 200)}`,
|
||||
);
|
||||
}
|
||||
|
||||
const result = await res.json().catch(() => null) as {
|
||||
success?: boolean;
|
||||
error?: string;
|
||||
auth_headers?: Record<string, string>;
|
||||
auth_query?: Record<string, string>;
|
||||
auth_body?: Record<string, string>;
|
||||
auth_path?: Record<string, string>;
|
||||
} | null;
|
||||
|
||||
if (!result || result.success === false) {
|
||||
throw new Error(
|
||||
`auth primitive 失敗: ${result?.error ?? '未知錯誤'}`,
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
...input,
|
||||
_auth_headers: result.auth_headers ?? {},
|
||||
_auth_query: result.auth_query ?? {},
|
||||
_auth_body: result.auth_body ?? {},
|
||||
_auth_path: result.auth_path ?? {},
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user