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:
uncle6me-web
2026-06-03 15:52:38 +08:00
commit 922a57fe34
485 changed files with 89356 additions and 0 deletions
@@ -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 ?? {},
};
}