feat(runtime): 即梦本机运行时 - 接入安全生成闭环与桌面本机渠道

Refs #225

Co-authored-by: zkhyww <127009345+zkhyww@users.noreply.github.com>
This commit is contained in:
ddCatandzkhyww committed 2026-08-15 12:45:29 +08:00
1 parent 8f2232feee
commit 57e1820f41
179 files changed
+49746 -1897

No files matched your search

@@ -0,0 +1,154 @@
import assert from "node:assert/strict";
import { EventEmitter } from "node:events";
import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { waitForLocalDreaminaGenerationTask } from "../../../web/src/services/local-dreamina-generation.ts";
import { DreaminaCliRuntime } from "../../src/dreamina-cli-runtime.js";
import { createDreaminaHttpModule } from "../../src/modules/dreamina-http.js";
const configDir = await fs.mkdtemp(path.join(os.tmpdir(), "dreamina-node-web-cross-runtime-"));
const stateFile = path.join(configDir, "dreamina-runtime-state.json");
const id = "dreamina-node-web-cross-runtime-0001";
const ownerId = "owner-node-web-cross-runtime-0001";
const videoBytes = Buffer.from("00000018667479706d703432", "hex");
await fs.writeFile(stateFile, JSON.stringify({
version: 1,
records: [{
ownerId,
idempotencyKey: id,
requestHash: "9".repeat(64),
state: "accepted",
submitId: "receipt-node-web-cross-runtime",
updatedAt: "2026-08-13T00:00:00.000Z",
taskVersion: 1,
operation: "text2video",
mode: "video",
model: "seedance2.0mini",
createdAt: "2026-08-13T00:00:00.000Z",
nextPollAt: "2000-01-01T00:00:00.000Z",
}],
}));
let releaseWinner!: () => void;
let markWinnerEntered!: () => void;
const winnerGate = new Promise<void>((resolve) => { releaseWinner = resolve; });
const winnerEntered = new Promise<void>((resolve) => { markWinnerEntered = resolve; });
let winnerQueries = 0;
let waiterQueries = 0;
const common = {
ownerId,
stateFile,
ensureReady: async () => undefined,
discover: async () => ({ installed: true as const, executable: "dreamina-fixture" }),
};
const winner = new DreaminaCliRuntime({
...common,
runProcess: async (input) => {
winnerQueries += 1;
if (winnerQueries === 1) {
markWinnerEntered();
await winnerGate;
}
const output = input.args.find((arg) => arg.startsWith("--download_dir="))?.slice("--download_dir=".length);
if (output) await fs.writeFile(path.join(output, "result.mp4"), videoBytes);
return { exitCode: 0, stdout: '{"status":"completed"}', stderr: "" };
},
});
const waiter = new DreaminaCliRuntime({
...common,
runProcess: async () => {
waiterQueries += 1;
return { exitCode: 0, stdout: '{"status":"failed"}', stderr: "" };
},
});
const module = createDreaminaHttpModule({ ownerId, configDir, dreaminaRuntime: waiter });
try {
await winner.start();
await winnerEntered;
const parsed = waitForLocalDreaminaGenerationTask(id, "video", {
client: {
async connect() {
return {
state: "connected" as const,
runtimeVersion: 2,
session: {
sessionId: "session-test-000000000001",
keyId: "browser-key-test",
scopes: ["dreamina:generate"],
expiresAt: "2099-01-01T00:00:00.000Z",
},
};
},
async request(route, init) {
const response = await invoke(module, route, Buffer.from(String(init?.body)));
return new Response(JSON.stringify(response.body), {
status: response.status,
headers: { "content-type": "application/json" },
});
},
},
});
await Promise.resolve();
releaseWinner();
const task = await parsed;
assert.equal(task.status, "succeeded");
assert.deepEqual(task.result, {
mode: "video",
video: {
dataUrl: `data:video/mp4;base64,${videoBytes.toString("base64")}`,
mimeType: "video/mp4",
bytes: videoBytes.byteLength,
},
});
assert.equal(waiterQueries, 0);
assert.equal(winnerQueries, 2);
const journalText = await fs.readFile(stateFile, "utf8");
const productText = await fs.readFile(path.join(configDir, "dreamina-generation-task-store.json"), "utf8");
for (const durableText of [journalText, productText]) {
assert.equal(durableText.includes("data:video/"), false);
assert.equal(durableText.includes(videoBytes.toString("base64")), false);
assert.equal(/stdout|stderr|token|cookie/i.test(durableText), false);
}
process.stdout.write("dreamina-cross-runtime-web-ok\n");
} finally {
releaseWinner();
await Promise.allSettled([winner.dispose(), module.dispose?.()]);
await fs.rm(configDir, { recursive: true, force: true, maxRetries: 10, retryDelay: 10 });
}
async function invoke(
runtimeModule: ReturnType<typeof createDreaminaHttpModule>,
routePath: string,
body: Buffer,
): Promise<{ status: number; body: unknown }> {
const route = runtimeModule.routes.find((candidate) => candidate.path === routePath);
assert(route);
const req = new EventEmitter() as EventEmitter & { body?: Buffer };
req.body = body;
const res = new EventEmitter() as EventEmitter & {
destroyed: boolean;
writableEnded: boolean;
statusCode: number;
json(value: unknown): void;
status(code: number): typeof res;
};
res.destroyed = false;
res.writableEnded = false;
res.statusCode = 200;
let resolve!: (value: { status: number; body: unknown }) => void;
const result = new Promise<{ status: number; body: unknown }>((done) => { resolve = done; });
res.json = (value) => {
res.writableEnded = true;
resolve({ status: res.statusCode, body: value });
};
res.status = (code) => {
res.statusCode = code;
return res;
};
route.handler(req as never, res as never, (error?: unknown) => {
if (error) resolve({ status: 500, body: { ok: false, code: "test_route_error" } });
});
return result;
}
@@ -0,0 +1,252 @@
import fs from "node:fs/promises";
import path from "node:path";
import { fileURLToPath } from "node:url";
import type { RequestHandler } from "express";
import type { LocalRuntimeConfig } from "../../src/config.js";
import { startLocalRuntime } from "../../src/local-runtime-host.js";
import type { LocalRuntimeModule } from "../../src/local-runtime.js";
const FORBIDDEN_PORTS = new Set([3000, 8080, 17371]);
const WORKTREE_ROOT = path.resolve(fileURLToPath(new URL("../../..", import.meta.url)));
const DEFAULT_TRUSTED_ORIGIN = "http://127.0.0.1:31300";
export type BrowserRuntimeScenario =
| "missing"
| "installed"
| "login_pending"
| "authenticated"
| "error"
| "origin_denied";
export type BrowserRuntimeFixtureOptions = {
scenario: BrowserRuntimeScenario;
port: number;
configDir: string;
trustedOrigin: string;
log?: (line: string) => void;
};
export async function startBrowserRuntimeFixture(options: BrowserRuntimeFixtureOptions) {
validatePort(options.port);
await requireContainedConfigDirectory(options.configDir);
const trustedOrigin = exactWebOrigin(options.trustedOrigin);
const calls = { count: 0 };
const dreamina = fakeDreaminaModule(options.scenario, calls);
const config: LocalRuntimeConfig = {
url: `http://127.0.0.1:${options.port}`,
token: "browser-harness-master-canary-must-not-leak",
ownerId: "browser-harness-owner-01",
origins: [],
trustedWebOrigins: options.scenario === "origin_denied" ? [] : [trustedOrigin],
browserRegistrations: [],
};
const runtime = startLocalRuntime({
config,
modules: [fakeCanvasModule(), dreamina],
port: options.port,
log: options.log ?? (() => undefined),
persistConfig: () => undefined,
});
await runtime.ready;
return {
pid: process.pid,
endpoint: `http://127.0.0.1:${options.port}`,
cliCalls: () => calls.count,
close: runtime.close,
};
}
function fakeCanvasModule(): LocalRuntimeModule {
return {
descriptor: {
id: "canvas-agent",
displayName: "Canvas Agent",
apiVersion: 1,
scopes: ["canvas:connect"],
},
routes: [],
};
}
function fakeDreaminaModule(
initialScenario: BrowserRuntimeScenario,
calls: { count: number },
): LocalRuntimeModule {
let scenario = initialScenario === "origin_denied" ? "installed" : initialScenario;
const status: RequestHandler = (_req, res) => {
calls.count += 1;
if (scenario === "error") {
res.status(500).json({
ok: false,
code: "dreamina_internal_error",
message: "Dreamina CLI 请求失败",
});
return;
}
res.json({ ok: true, status: dreaminaStatus(scenario) });
};
const login: RequestHandler = (_req, res) => {
calls.count += 1;
if (scenario === "missing") {
res.status(404).json({
ok: false,
code: "dreamina_missing",
message: "未检测到 Dreamina CLI",
});
return;
}
scenario = "login_pending";
res.json({ ok: true, status: dreaminaStatus(scenario) });
};
const logout: RequestHandler = (_req, res) => {
calls.count += 1;
scenario = "installed";
res.json({ ok: true, status: dreaminaStatus(scenario) });
};
return {
descriptor: {
id: "dreamina",
displayName: "Dreamina CLI",
apiVersion: 1,
scopes: ["dreamina:status", "dreamina:login", "dreamina:logout", "dreamina:run"],
},
routes: [
{ method: "GET", path: "/dreamina/status", scope: "dreamina:status", handler: status },
{ method: "POST", path: "/dreamina/login", scope: "dreamina:login", handler: login },
{ method: "POST", path: "/dreamina/logout", scope: "dreamina:logout", handler: logout },
],
};
}
function dreaminaStatus(scenario: Exclude<BrowserRuntimeScenario, "origin_denied" | "error">) {
if (scenario === "missing") {
return {
provider: "dreamina-cli",
state: "missing",
installed: false,
authenticated: false,
code: "dreamina_missing",
message: "未检测到 Dreamina CLI",
};
}
if (scenario === "authenticated") {
return {
provider: "dreamina-cli",
state: "authenticated",
installed: true,
authenticated: true,
version: "fixture-1.0.0",
message: "Dreamina CLI 已登录",
};
}
if (scenario === "login_pending") {
return {
provider: "dreamina-cli",
state: "login_pending",
installed: true,
authenticated: false,
version: "fixture-1.0.0",
code: "dreamina_login_pending",
message: "请在官方页面确认 Dreamina 登录",
verificationUri: "https://jimeng.jianying.com/ai-tool/cli-auth",
userCode: "DREAMINA-FIXTURE",
expiresAt: new Date(Date.now() + 10 * 60_000).toISOString(),
};
}
return {
provider: "dreamina-cli",
state: "installed",
installed: true,
authenticated: false,
version: "fixture-1.0.0",
code: "dreamina_login_required",
message: "Dreamina CLI 已安装,需要登录",
};
}
function validatePort(port: number) {
if (!Number.isInteger(port) || port < 1 || port > 65_535 || FORBIDDEN_PORTS.has(port)) {
throw new Error("Browser Runtime fixture requires an isolated non-production port");
}
}
async function requireContainedConfigDirectory(configDir: string) {
if (!path.isAbsolute(configDir)) {
throw new Error("Browser Runtime fixture config directory must be absolute");
}
const [worktreeRoot, resolvedConfigDir] = await Promise.all([
fs.realpath(WORKTREE_ROOT),
fs.realpath(configDir),
]);
if (resolvedConfigDir === worktreeRoot
|| !resolvedConfigDir.startsWith(`${worktreeRoot}${path.sep}`)) {
throw new Error("Browser Runtime fixture config directory must stay inside the worktree");
}
}
function exactWebOrigin(value: string) {
const url = new URL(value);
if (!['http:', 'https:'].includes(url.protocol)
|| url.username
|| url.password
|| url.pathname !== "/"
|| url.search
|| url.hash
|| url.origin !== value) {
throw new Error("Browser Runtime fixture trusted origin is invalid");
}
return url.origin;
}
function parseCliArguments(argv: readonly string[]): BrowserRuntimeFixtureOptions {
const values = new Map<string, string>();
for (let index = 0; index < argv.length; index += 2) {
const key = argv[index];
const value = argv[index + 1];
if (!key?.startsWith("--") || value === undefined || values.has(key)) {
throw new Error("Browser Runtime fixture arguments are invalid");
}
values.set(key, value);
}
const allowed = new Set(["--scenario", "--port", "--config-dir", "--trusted-origin"]);
if ([...values.keys()].some((key) => !allowed.has(key))) {
throw new Error("Browser Runtime fixture arguments are invalid");
}
const scenario = values.get("--scenario");
if (!isScenario(scenario)) throw new Error("Browser Runtime fixture scenario is invalid");
return {
scenario,
port: Number(values.get("--port")),
configDir: values.get("--config-dir") ?? "",
trustedOrigin: values.get("--trusted-origin") ?? DEFAULT_TRUSTED_ORIGIN,
};
}
function isScenario(value: unknown): value is BrowserRuntimeScenario {
return value === "missing"
|| value === "installed"
|| value === "login_pending"
|| value === "authenticated"
|| value === "error"
|| value === "origin_denied";
}
async function runCli() {
const fixture = await startBrowserRuntimeFixture(parseCliArguments(process.argv.slice(2)));
console.log(`Browser Runtime fixture listening at ${fixture.endpoint}`);
console.log(`Browser Runtime fixture PID: ${fixture.pid}`);
await new Promise<void>((resolve) => {
process.once("SIGINT", resolve);
process.once("SIGTERM", resolve);
});
await fixture.close();
}
if (path.resolve(process.argv[1] ?? "") === path.resolve(fileURLToPath(import.meta.url))) {
runCli().catch(() => {
console.error("Browser Runtime fixture failed to start");
process.exitCode = 1;
});
}