


















11import { spawn, spawnSync } from "node:child_process";
2-import { mkdtempSync, readFileSync, rmSync } from "node:fs";
2+import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
33import { createServer, type Server } from "node:http";
44import { tmpdir } from "node:os";
55import path from "node:path";
66import { describe, expect, it } from "vitest";
7788const clientPath = path.resolve("scripts/e2e/lib/openai-chat-tools/client.mjs");
9+const dockerRunnerPath = path.resolve("scripts/e2e/openai-chat-tools-docker.sh");
910const writeConfigPath = path.resolve("scripts/e2e/lib/openai-chat-tools/write-config.mjs");
10111112interface ClientResult {
@@ -96,6 +97,20 @@ function runWriteConfig(root: string, env: Record<string, string> = {}) {
9697});
9798}
9899100+function runDockerRunnerAuthPreflight(root: string, env: Record<string, string> = {}) {
101+return spawnSync("bash", [dockerRunnerPath], {
102+encoding: "utf8",
103+env: {
104+ ...process.env,
105+HOME: root,
106+OPENAI_API_KEY: "",
107+OPENAI_BASE_URL: "",
108+OPENCLAW_OPENAI_CHAT_TOOLS_PROFILE_FILE: path.join(root, "missing.profile"),
109+ ...env,
110+},
111+});
112+}
113+99114function toolCallResponse() {
100115return {
101116choices: [
@@ -118,6 +133,53 @@ function toolCallResponse() {
118133}
119134120135describe("scripts/e2e/lib/openai-chat-tools/client.mjs", () => {
136+it("keeps full profile exports out of the Docker build phase", () => {
137+const runner = readFileSync(dockerRunnerPath, "utf8");
138+const preflightSourceIndex = runner.indexOf('source "$profile_file"');
139+const buildIndex = runner.indexOf("docker_e2e_build_or_reuse");
140+const fullProfileSourceIndex = runner.indexOf('source "$PROFILE_FILE"', buildIndex);
141+142+expect(preflightSourceIndex).toBeGreaterThanOrEqual(0);
143+expect(buildIndex).toBeGreaterThan(preflightSourceIndex);
144+expect(fullProfileSourceIndex).toBeGreaterThan(buildIndex);
145+});
146+147+it("fails auth preflight before Docker build work starts", () => {
148+const root = mkdtempSync(path.join(tmpdir(), "openclaw-openai-chat-tools-"));
149+try {
150+const result = runDockerRunnerAuthPreflight(root);
151+const output = `${result.stdout}\n${result.stderr}`;
152+153+expect(result.status).toBe(1);
154+expect(output).toContain("OPENAI_API_KEY was not available");
155+expect(output).not.toContain("Building Docker image:");
156+expect(output).not.toContain("Reusing Docker image:");
157+expect(output).not.toContain("Running OpenAI Chat Completions tools Docker E2E");
158+} finally {
159+rmSync(root, { force: true, recursive: true });
160+}
161+});
162+163+it("treats placeholder profile auth as missing before Docker build work starts", () => {
164+const root = mkdtempSync(path.join(tmpdir(), "openclaw-openai-chat-tools-"));
165+try {
166+const profile = path.join(root, "profile");
167+writeFileSync(profile, "OPENAI_API_KEY=undefined\n");
168+const result = runDockerRunnerAuthPreflight(root, {
169+OPENCLAW_OPENAI_CHAT_TOOLS_PROFILE_FILE: profile,
170+});
171+const output = `${result.stdout}\n${result.stderr}`;
172+173+expect(result.status).toBe(1);
174+expect(output).toContain("OPENAI_API_KEY was not available");
175+expect(output).not.toContain("Building Docker image:");
176+expect(output).not.toContain("Reusing Docker image:");
177+expect(output).not.toContain("Running OpenAI Chat Completions tools Docker E2E");
178+} finally {
179+rmSync(root, { force: true, recursive: true });
180+}
181+});
182+121183it("rejects loose timeout env values instead of parsing numeric prefixes", async () => {
122184const result = await runClient(1, {
123185OPENCLAW_OPENAI_CHAT_TOOLS_TIMEOUT_SECONDS: "1e3",
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。