refactor: unify GATEWAY_SECRET + DASHBOARD_API_KEY into WORKFLOW_DASHBOARD_SECRET
This commit is contained in:
+5
-2
@@ -14,7 +14,10 @@ WORKFLOW_CURSOR_MODEL=
|
||||
# Timeout in milliseconds for Cursor agent operations
|
||||
WORKFLOW_CURSOR_TIMEOUT=
|
||||
|
||||
# ── Hermes Agent (used by workflow-template-solve-issue) ──
|
||||
# ── Hermes Agent (used by develop tester/committer + solve-issue) ──
|
||||
|
||||
# CLI command to invoke the Hermes agent (absolute path required)
|
||||
WORKFLOW_HERMES_COMMAND=
|
||||
|
||||
# Model override for Hermes agent
|
||||
WORKFLOW_HERMES_MODEL=
|
||||
@@ -29,7 +32,7 @@ WORKFLOW_HERMES_TIMEOUT=
|
||||
WORKFLOW_STORAGE_ROOT=
|
||||
|
||||
# Gateway secret for the serve command
|
||||
WORKFLOW_GATEWAY_SECRET=
|
||||
WORKFLOW_DASHBOARD_SECRET=
|
||||
|
||||
# ── Display ──
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ function requireNextArg(argv: string[], i: number, flag: string): Result<string,
|
||||
function parseConnectArgv(argv: string[]): Result<ConnectOptions, string> {
|
||||
let name = osHostname().split(".")[0].toLowerCase();
|
||||
let gatewayUrl = DEFAULT_GATEWAY_URL;
|
||||
const gatewaySecret = process.env.WORKFLOW_GATEWAY_SECRET ?? "";
|
||||
const gatewaySecret = process.env.WORKFLOW_DASHBOARD_SECRET ?? "";
|
||||
const stringFlags: Record<string, (v: string) => void> = {
|
||||
"--name": (v) => {
|
||||
name = v;
|
||||
@@ -56,7 +56,7 @@ export async function dispatchConnect(storageRoot: string, argv: string[]): Prom
|
||||
const options = parsed.value;
|
||||
|
||||
if (options.gatewaySecret === "") {
|
||||
printCliLine("error: WORKFLOW_GATEWAY_SECRET is required");
|
||||
printCliLine("error: WORKFLOW_DASHBOARD_SECRET is required");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import { DurableObject } from "cloudflare:workers";
|
||||
import { parseWsRequestJson, parseWsResponseJson, type WsResponse } from "./ws-protocol.js";
|
||||
|
||||
type ClientSocketEnv = {
|
||||
GATEWAY_SECRET: string;
|
||||
WORKFLOW_DASHBOARD_SECRET: string;
|
||||
};
|
||||
|
||||
export const CLIENT_SOCKET_INTERNAL_STATUS_PATH = "/internal/client-socket/status";
|
||||
@@ -37,7 +37,7 @@ export class ClientSocket extends DurableObject<ClientSocketEnv> {
|
||||
|
||||
private requireAuth(request: Request): Response | null {
|
||||
const auth = request.headers.get("Authorization");
|
||||
if (auth !== `Bearer ${this.env.GATEWAY_SECRET}`) {
|
||||
if (auth !== `Bearer ${this.env.WORKFLOW_DASHBOARD_SECRET}`) {
|
||||
return jsonResponse(401, { error: "unauthorized" });
|
||||
}
|
||||
return null;
|
||||
|
||||
@@ -13,8 +13,7 @@ export { ClientSocket };
|
||||
type Env = {
|
||||
Bindings: {
|
||||
ENDPOINTS: KVNamespace;
|
||||
GATEWAY_SECRET: string;
|
||||
DASHBOARD_API_KEY: string;
|
||||
WORKFLOW_DASHBOARD_SECRET: string;
|
||||
CLIENT_SOCKET: DurableObjectNamespace<ClientSocket>;
|
||||
};
|
||||
};
|
||||
@@ -40,7 +39,7 @@ function checkDashboardAuth(c: {
|
||||
const bearer = c.req.header("Authorization")?.replace("Bearer ", "");
|
||||
const query = c.req.query("key");
|
||||
const key = bearer ?? query;
|
||||
return key === c.env.DASHBOARD_API_KEY;
|
||||
return key === c.env.WORKFLOW_DASHBOARD_SECRET;
|
||||
}
|
||||
|
||||
function isLocalClientUrl(url: string): boolean {
|
||||
@@ -153,7 +152,7 @@ async function fetchClientSocketStatus(
|
||||
const resp = await stub.fetch(
|
||||
new Request(`https://do${CLIENT_SOCKET_INTERNAL_STATUS_PATH}`, {
|
||||
method: "GET",
|
||||
headers: { Authorization: `Bearer ${env.GATEWAY_SECRET}` },
|
||||
headers: { Authorization: `Bearer ${env.WORKFLOW_DASHBOARD_SECRET}` },
|
||||
}),
|
||||
);
|
||||
if (!resp.ok) {
|
||||
@@ -184,14 +183,14 @@ function endpointStatusFromKvAndDo(record: EndpointRecord, doConnected: boolean
|
||||
// ── Health ──────────────────────────────────────────────────────────
|
||||
app.get("/healthz", (c) => c.json({ ok: true }));
|
||||
|
||||
// ── Client reverse WebSocket (GATEWAY_SECRET query param) ────────────
|
||||
// ── Client reverse WebSocket (WORKFLOW_DASHBOARD_SECRET query param) ────────────
|
||||
app.get("/ws/connect", async (c) => {
|
||||
const secret = c.req.query("secret");
|
||||
const name = c.req.query("name");
|
||||
if (name === undefined || name === "") {
|
||||
return c.json({ error: "name required" }, 400);
|
||||
}
|
||||
if (secret !== c.env.GATEWAY_SECRET) {
|
||||
if (secret !== c.env.WORKFLOW_DASHBOARD_SECRET) {
|
||||
return c.json({ error: "unauthorized" }, 401);
|
||||
}
|
||||
if (c.req.header("Upgrade") !== "websocket") {
|
||||
@@ -202,7 +201,7 @@ app.get("/ws/connect", async (c) => {
|
||||
return stub.fetch(c.req.raw);
|
||||
});
|
||||
|
||||
// ── Gateway management (GATEWAY_SECRET auth) ────────────────────────
|
||||
// ── Gateway management (WORKFLOW_DASHBOARD_SECRET auth) ────────────────────────
|
||||
const gateway = new Hono<Env>();
|
||||
|
||||
gateway.post("/register", async (c) => {
|
||||
@@ -217,7 +216,7 @@ gateway.post("/register", async (c) => {
|
||||
if (!name || !url) {
|
||||
return c.json({ error: "name and url required" }, 400);
|
||||
}
|
||||
if (secret !== c.env.GATEWAY_SECRET) {
|
||||
if (secret !== c.env.WORKFLOW_DASHBOARD_SECRET) {
|
||||
return c.json({ error: "unauthorized" }, 401);
|
||||
}
|
||||
|
||||
@@ -242,7 +241,7 @@ gateway.post("/register", async (c) => {
|
||||
|
||||
gateway.delete("/register/:name", async (c) => {
|
||||
const auth = c.req.header("Authorization");
|
||||
if (auth !== `Bearer ${c.env.GATEWAY_SECRET}`) {
|
||||
if (auth !== `Bearer ${c.env.WORKFLOW_DASHBOARD_SECRET}`) {
|
||||
return c.json({ error: "unauthorized" }, 401);
|
||||
}
|
||||
|
||||
@@ -308,7 +307,7 @@ app.all("/api/clients/:client/*", async (c) => {
|
||||
const proxyResp = await fetchThroughClientSocket(
|
||||
c.env,
|
||||
client,
|
||||
c.env.GATEWAY_SECRET,
|
||||
c.env.WORKFLOW_DASHBOARD_SECRET,
|
||||
wsRequest,
|
||||
);
|
||||
if (proxyResp.status !== 503) {
|
||||
|
||||
@@ -17,4 +17,4 @@ new_sqlite_classes = ["AgentSocket"]
|
||||
tag = "rename-agent-to-client"
|
||||
renamed_classes = [{ from = "AgentSocket", to = "ClientSocket" }]
|
||||
|
||||
# GATEWAY_SECRET is set via `wrangler secret put`
|
||||
# WORKFLOW_DASHBOARD_SECRET is set via `wrangler secret put`
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
/**
|
||||
* develop bundle entry — 小橘 🍊
|
||||
*
|
||||
* All roles use cursor-agent with workspace auto-extracted from context.
|
||||
* planner/coder/reviewer → cursor-agent (needs code editing)
|
||||
* tester/committer → hermes-agent (lightweight, no editing needed)
|
||||
*/
|
||||
import { createCursorAgent } from "@uncaged/workflow-agent-cursor";
|
||||
import { createHermesAgent } from "@uncaged/workflow-agent-hermes";
|
||||
import { createWorkflow } from "@uncaged/workflow-runtime";
|
||||
import { optionalEnv, requireEnv } from "@uncaged/workflow-util";
|
||||
import { buildDevelopDescriptor, developWorkflowDefinition } from "./src/index.js";
|
||||
|
||||
const adapter = createCursorAgent({
|
||||
const cursorAdapter = createCursorAgent({
|
||||
command: requireEnv("WORKFLOW_CURSOR_COMMAND", "set WORKFLOW_CURSOR_COMMAND (e.g. cursor-agent)"),
|
||||
model: optionalEnv("WORKFLOW_CURSOR_MODEL"),
|
||||
timeout: optionalEnv("WORKFLOW_CURSOR_TIMEOUT")
|
||||
@@ -17,7 +19,21 @@ const adapter = createCursorAgent({
|
||||
workspace: null,
|
||||
});
|
||||
|
||||
const wf = createWorkflow(developWorkflowDefinition, { adapter, overrides: null });
|
||||
const hermesAdapter = createHermesAgent({
|
||||
command: requireEnv("WORKFLOW_HERMES_COMMAND", "set WORKFLOW_HERMES_COMMAND (absolute path to hermes CLI)"),
|
||||
model: optionalEnv("WORKFLOW_HERMES_MODEL"),
|
||||
timeout: optionalEnv("WORKFLOW_HERMES_TIMEOUT")
|
||||
? Number(optionalEnv("WORKFLOW_HERMES_TIMEOUT"))
|
||||
: null,
|
||||
});
|
||||
|
||||
const wf = createWorkflow(developWorkflowDefinition, {
|
||||
adapter: cursorAdapter,
|
||||
overrides: {
|
||||
tester: hermesAdapter,
|
||||
committer: hermesAdapter,
|
||||
},
|
||||
});
|
||||
|
||||
export const descriptor = buildDevelopDescriptor();
|
||||
export const run = wf;
|
||||
|
||||
Reference in New Issue
Block a user