fix(e2e): reject invalid client gateway ports

This commit is contained in:
Vincent Koc
2026-06-18 20:46:11 +02:00
parent 0b14724c87
commit cebe5cb94a
6 changed files with 41 additions and 21 deletions
+4 -3
View File
@@ -6,9 +6,9 @@ import { renderBitmapTextPngBase64 } from "../../../../test/helpers/live-image-p
import { createGatewayWsClient } from "../../../lib/gateway-ws-client.ts";
import { resolveGatewaySuccessPayload } from "../gateway-frame-payload.mjs";
import { createJsonlRequestTailer } from "./jsonl-request-tail.mjs";
import { readPositiveIntEnv } from "./limits.mjs";
import { readPositiveIntEnv, readTcpPortEnv } from "./limits.mjs";
const port = process.env.PORT;
const portText = process.env.PORT;
const token = process.env.OPENCLAW_GATEWAY_TOKEN;
const appServerLog =
process.env.OPENCLAW_CODEX_MEDIA_PATH_APP_SERVER_LOG ??
@@ -19,9 +19,10 @@ const logTailMaxBytes = readPositiveIntEnv(
2 * 1024 * 1024,
);
if (!port || !token) {
if (!portText || !token) {
throw new Error("missing PORT/OPENCLAW_GATEWAY_TOKEN");
}
const port = readTcpPortEnv("PORT", portText);
function assert(condition, message) {
if (!condition) {
+5 -14
View File
@@ -1,26 +1,17 @@
// Gateway client for OpenAI chat tools E2E scenarios.
const port = process.env.PORT;
import { readPositiveIntEnv, readTcpPortEnv } from "../env-limits.mjs";
const portText = process.env.PORT;
const token = process.env.OPENCLAW_GATEWAY_TOKEN;
const backendModel = process.env.MODEL_REF || "openai/gpt-5.4-mini";
function readPositiveIntEnv(name, fallback) {
const text = String(process.env[name] ?? fallback).trim();
if (!/^\d+$/u.test(text)) {
throw new Error(`invalid ${name}: ${text}`);
}
const value = Number(text);
if (!Number.isSafeInteger(value) || value <= 0) {
throw new Error(`invalid ${name}: ${text}`);
}
return value;
}
const timeoutSeconds = readPositiveIntEnv("OPENCLAW_OPENAI_CHAT_TOOLS_TIMEOUT_SECONDS", 180);
const maxBodyBytes = readPositiveIntEnv("OPENCLAW_OPENAI_CHAT_TOOLS_MAX_BODY_BYTES", 1048576);
if (!port || !token) {
if (!portText || !token) {
throw new Error("missing PORT/OPENCLAW_GATEWAY_TOKEN");
}
const port = readTcpPortEnv("PORT", portText);
if (!Number.isFinite(timeoutSeconds) || timeoutSeconds <= 0) {
throw new Error(`invalid OPENCLAW_OPENAI_CHAT_TOOLS_TIMEOUT_SECONDS: ${timeoutSeconds}`);
}
@@ -1,6 +1,7 @@
// Client script for minimal OpenAI web-search E2E scenarios.
import { readdirSync } from "node:fs";
import { pathToFileURL } from "node:url";
import { readTcpPortEnv } from "../env-limits.mjs";
async function loadCallGateway() {
const candidates = readdirSync("/app/dist")
@@ -24,12 +25,20 @@ function readExpectedRawSchemaError() {
return process.env.RAW_SCHEMA_ERROR?.trim() || DEFAULT_RAW_SCHEMA_ERROR;
}
function resolveGatewayPort(env = process.env) {
const portText = env.PORT;
if (!portText) {
throw new Error("missing PORT");
}
return readTcpPortEnv("PORT", portText, env);
}
async function gatewayAgent(params) {
const port = process.env.PORT;
const token = process.env.OPENCLAW_GATEWAY_TOKEN;
if (!port || !token) {
if (!token) {
throw new Error("missing PORT/OPENCLAW_GATEWAY_TOKEN");
}
const port = resolveGatewayPort();
try {
const callGateway = await loadCallGateway();
@@ -186,6 +195,7 @@ export const testing = {
DEFAULT_RAW_SCHEMA_ERROR,
SUCCESS_MARKER,
extractSuccessReplyTexts,
resolveGatewayPort,
validateSuccessResult,
validateRejectResult,
};
+8 -1
View File
@@ -5,7 +5,10 @@ import { tmpdir } from "node:os";
import path from "node:path";
import { afterEach, describe, expect, it } from "vitest";
import { createJsonlRequestTailer } from "../../scripts/e2e/lib/codex-media-path/jsonl-request-tail.mjs";
import { readPositiveIntEnv } from "../../scripts/e2e/lib/codex-media-path/limits.mjs";
import {
readPositiveIntEnv,
readTcpPortEnv,
} from "../../scripts/e2e/lib/codex-media-path/limits.mjs";
import { createBoundedChildOutput } from "../helpers/bounded-child-output.js";
const tempRoots: string[] = [];
@@ -106,6 +109,10 @@ describe("codex media path limits", () => {
).toThrow("invalid OPENCLAW_CODEX_MEDIA_PATH_LOG_TAIL_MAX_BYTES: 64bytes");
});
it("rejects out-of-range TCP ports", () => {
expect(() => readTcpPortEnv("PORT", 18790, { PORT: "65536" })).toThrow("invalid PORT: 65536");
});
it("writes strict positive timeout and port values into generated config", () => {
const root = makeTempRoot();
const result = runWriteConfig(root, {
@@ -35,7 +35,7 @@ async function listen(server: Server): Promise<number> {
}
function runClient(
port: number,
port: number | string,
env: Record<string, string> = {},
timeout = 5_000,
): Promise<ClientResult> {
@@ -222,6 +222,13 @@ describe("scripts/e2e/lib/openai-chat-tools/client.mjs", () => {
expect(result.stderr).toContain("invalid OPENCLAW_OPENAI_CHAT_TOOLS_MAX_BODY_BYTES: 64bytes");
});
it("rejects out-of-range client gateway ports", async () => {
const result = await runClient("65536");
expect(result.status).not.toBe(0);
expect(result.stderr).toContain("invalid PORT: 65536");
});
it("rejects loose write-config timeout env values", () => {
const root = mkdtempSync(path.join(tmpdir(), "openclaw-openai-chat-tools-"));
try {
@@ -41,6 +41,10 @@ describe("scripts/e2e/lib/openai-web-search-minimal/client.mjs", () => {
).toThrow(/reject mode failed for an unexpected reason/u);
});
it("rejects out-of-range gateway ports before connecting", () => {
expect(() => testing.resolveGatewayPort({ PORT: "65536" })).toThrow("invalid PORT: 65536");
});
it("accepts success mode only when the final assistant reply contains the marker", () => {
expect(() =>
testing.validateSuccessResult({