fix(e2e): reject invalid client gateway ports · openclaw/openclaw@cebe5cb
vincentkoc
·
2026-06-19
·
via Recent Commits to openclaw:main
File tree
openai-web-search-minimal
| Original file line number | Diff line number | Diff line change |
|---|
@@ -6,9 +6,9 @@ import { renderBitmapTextPngBase64 } from "../../../../test/helpers/live-image-p
|
6 | 6 | import { createGatewayWsClient } from "../../../lib/gateway-ws-client.ts"; |
7 | 7 | import { resolveGatewaySuccessPayload } from "../gateway-frame-payload.mjs"; |
8 | 8 | import { createJsonlRequestTailer } from "./jsonl-request-tail.mjs"; |
9 | | -import { readPositiveIntEnv } from "./limits.mjs"; |
| 9 | +import { readPositiveIntEnv, readTcpPortEnv } from "./limits.mjs"; |
10 | 10 | |
11 | | -const port = process.env.PORT; |
| 11 | +const portText = process.env.PORT; |
12 | 12 | const token = process.env.OPENCLAW_GATEWAY_TOKEN; |
13 | 13 | const appServerLog = |
14 | 14 | process.env.OPENCLAW_CODEX_MEDIA_PATH_APP_SERVER_LOG ?? |
@@ -19,9 +19,10 @@ const logTailMaxBytes = readPositiveIntEnv(
|
19 | 19 | 2 * 1024 * 1024, |
20 | 20 | ); |
21 | 21 | |
22 | | -if (!port || !token) { |
| 22 | +if (!portText || !token) { |
23 | 23 | throw new Error("missing PORT/OPENCLAW_GATEWAY_TOKEN"); |
24 | 24 | } |
| 25 | +const port = readTcpPortEnv("PORT", portText); |
25 | 26 | |
26 | 27 | function assert(condition, message) { |
27 | 28 | if (!condition) { |
|
| Original file line number | Diff line number | Diff line change |
|---|
|
1 | 1 | // Gateway client for OpenAI chat tools E2E scenarios. |
2 | | -const port = process.env.PORT; |
| 2 | +import { readPositiveIntEnv, readTcpPortEnv } from "../env-limits.mjs"; |
| 3 | + |
| 4 | +const portText = process.env.PORT; |
3 | 5 | const token = process.env.OPENCLAW_GATEWAY_TOKEN; |
4 | 6 | const backendModel = process.env.MODEL_REF || "openai/gpt-5.4-mini"; |
5 | 7 | |
6 | | -function readPositiveIntEnv(name, fallback) { |
7 | | -const text = String(process.env[name] ?? fallback).trim(); |
8 | | -if (!/^\d+$/u.test(text)) { |
9 | | -throw new Error(`invalid ${name}: ${text}`); |
10 | | -} |
11 | | -const value = Number(text); |
12 | | -if (!Number.isSafeInteger(value) || value <= 0) { |
13 | | -throw new Error(`invalid ${name}: ${text}`); |
14 | | -} |
15 | | -return value; |
16 | | -} |
17 | | - |
18 | 8 | const timeoutSeconds = readPositiveIntEnv("OPENCLAW_OPENAI_CHAT_TOOLS_TIMEOUT_SECONDS", 180); |
19 | 9 | const maxBodyBytes = readPositiveIntEnv("OPENCLAW_OPENAI_CHAT_TOOLS_MAX_BODY_BYTES", 1048576); |
20 | 10 | |
21 | | -if (!port || !token) { |
| 11 | +if (!portText || !token) { |
22 | 12 | throw new Error("missing PORT/OPENCLAW_GATEWAY_TOKEN"); |
23 | 13 | } |
| 14 | +const port = readTcpPortEnv("PORT", portText); |
24 | 15 | if (!Number.isFinite(timeoutSeconds) || timeoutSeconds <= 0) { |
25 | 16 | throw new Error(`invalid OPENCLAW_OPENAI_CHAT_TOOLS_TIMEOUT_SECONDS: ${timeoutSeconds}`); |
26 | 17 | } |
|
| Original file line number | Diff line number | Diff line change |
|---|
|
1 | 1 | // Client script for minimal OpenAI web-search E2E scenarios. |
2 | 2 | import { readdirSync } from "node:fs"; |
3 | 3 | import { pathToFileURL } from "node:url"; |
| 4 | +import { readTcpPortEnv } from "../env-limits.mjs"; |
4 | 5 | |
5 | 6 | async function loadCallGateway() { |
6 | 7 | const candidates = readdirSync("/app/dist") |
@@ -24,12 +25,20 @@ function readExpectedRawSchemaError() {
|
24 | 25 | return process.env.RAW_SCHEMA_ERROR?.trim() || DEFAULT_RAW_SCHEMA_ERROR; |
25 | 26 | } |
26 | 27 | |
| 28 | +function resolveGatewayPort(env = process.env) { |
| 29 | +const portText = env.PORT; |
| 30 | +if (!portText) { |
| 31 | +throw new Error("missing PORT"); |
| 32 | +} |
| 33 | +return readTcpPortEnv("PORT", portText, env); |
| 34 | +} |
| 35 | + |
27 | 36 | async function gatewayAgent(params) { |
28 | | -const port = process.env.PORT; |
29 | 37 | const token = process.env.OPENCLAW_GATEWAY_TOKEN; |
30 | | -if (!port || !token) { |
| 38 | +if (!token) { |
31 | 39 | throw new Error("missing PORT/OPENCLAW_GATEWAY_TOKEN"); |
32 | 40 | } |
| 41 | +const port = resolveGatewayPort(); |
33 | 42 | |
34 | 43 | try { |
35 | 44 | const callGateway = await loadCallGateway(); |
@@ -186,6 +195,7 @@ export const testing = {
|
186 | 195 | DEFAULT_RAW_SCHEMA_ERROR, |
187 | 196 | SUCCESS_MARKER, |
188 | 197 | extractSuccessReplyTexts, |
| 198 | + resolveGatewayPort, |
189 | 199 | validateSuccessResult, |
190 | 200 | validateRejectResult, |
191 | 201 | }; |
| Original file line number | Diff line number | Diff line change |
|---|
@@ -5,7 +5,10 @@ import { tmpdir } from "node:os";
|
5 | 5 | import path from "node:path"; |
6 | 6 | import { afterEach, describe, expect, it } from "vitest"; |
7 | 7 | import { createJsonlRequestTailer } from "../../scripts/e2e/lib/codex-media-path/jsonl-request-tail.mjs"; |
8 | | -import { readPositiveIntEnv } from "../../scripts/e2e/lib/codex-media-path/limits.mjs"; |
| 8 | +import { |
| 9 | +readPositiveIntEnv, |
| 10 | +readTcpPortEnv, |
| 11 | +} from "../../scripts/e2e/lib/codex-media-path/limits.mjs"; |
9 | 12 | import { createBoundedChildOutput } from "../helpers/bounded-child-output.js"; |
10 | 13 | |
11 | 14 | const tempRoots: string[] = []; |
@@ -106,6 +109,10 @@ describe("codex media path limits", () => {
|
106 | 109 | ).toThrow("invalid OPENCLAW_CODEX_MEDIA_PATH_LOG_TAIL_MAX_BYTES: 64bytes"); |
107 | 110 | }); |
108 | 111 | |
| 112 | +it("rejects out-of-range TCP ports", () => { |
| 113 | +expect(() => readTcpPortEnv("PORT", 18790, { PORT: "65536" })).toThrow("invalid PORT: 65536"); |
| 114 | +}); |
| 115 | + |
109 | 116 | it("writes strict positive timeout and port values into generated config", () => { |
110 | 117 | const root = makeTempRoot(); |
111 | 118 | const result = runWriteConfig(root, { |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -35,7 +35,7 @@ async function listen(server: Server): Promise<number> {
|
35 | 35 | } |
36 | 36 | |
37 | 37 | function runClient( |
38 | | -port: number, |
| 38 | +port: number | string, |
39 | 39 | env: Record<string, string> = {}, |
40 | 40 | timeout = 5_000, |
41 | 41 | ): Promise<ClientResult> { |
@@ -222,6 +222,13 @@ describe("scripts/e2e/lib/openai-chat-tools/client.mjs", () => {
|
222 | 222 | expect(result.stderr).toContain("invalid OPENCLAW_OPENAI_CHAT_TOOLS_MAX_BODY_BYTES: 64bytes"); |
223 | 223 | }); |
224 | 224 | |
| 225 | +it("rejects out-of-range client gateway ports", async () => { |
| 226 | +const result = await runClient("65536"); |
| 227 | + |
| 228 | +expect(result.status).not.toBe(0); |
| 229 | +expect(result.stderr).toContain("invalid PORT: 65536"); |
| 230 | +}); |
| 231 | + |
225 | 232 | it("rejects loose write-config timeout env values", () => { |
226 | 233 | const root = mkdtempSync(path.join(tmpdir(), "openclaw-openai-chat-tools-")); |
227 | 234 | try { |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -41,6 +41,10 @@ describe("scripts/e2e/lib/openai-web-search-minimal/client.mjs", () => {
|
41 | 41 | ).toThrow(/reject mode failed for an unexpected reason/u); |
42 | 42 | }); |
43 | 43 | |
| 44 | +it("rejects out-of-range gateway ports before connecting", () => { |
| 45 | +expect(() => testing.resolveGatewayPort({ PORT: "65536" })).toThrow("invalid PORT: 65536"); |
| 46 | +}); |
| 47 | + |
44 | 48 | it("accepts success mode only when the final assistant reply contains the marker", () => { |
45 | 49 | expect(() => |
46 | 50 | testing.validateSuccessResult({ |
|
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。