Skip to content

Commit 13dcded

Browse files
committed
fix(release): bound cross-os fetch bodies
1 parent 4c3a029 commit 13dcded

2 files changed

Lines changed: 56 additions & 3 deletions

File tree

scripts/openclaw-cross-os-release-checks.ts

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ const OMITTED_QA_EXTENSION_PREFIXES = [
120120
];
121121
export const CROSS_OS_DASHBOARD_SMOKE_TIMEOUT_MS = 120_000;
122122
export const CROSS_OS_DASHBOARD_FETCH_TIMEOUT_MS = 10_000;
123+
export const CROSS_OS_FETCH_BODY_MAX_CHARS = 1024 * 1024;
123124
export const CROSS_OS_GATEWAY_STATUS_RPC_TIMEOUT_MS = 30_000;
124125
export const CROSS_OS_GATEWAY_STATUS_COMMAND_TIMEOUT_MS =
125126
CROSS_OS_GATEWAY_STATUS_RPC_TIMEOUT_MS + 45_000;
@@ -2462,6 +2463,45 @@ async function configureDiscordSmoke(params) {
24622463
});
24632464
}
24642465

2466+
export async function readBoundedCrossOsResponseText(
2467+
response: Response,
2468+
maxChars = CROSS_OS_FETCH_BODY_MAX_CHARS,
2469+
): Promise<string> {
2470+
if (!response.body) {
2471+
return "";
2472+
}
2473+
2474+
const reader = response.body.getReader();
2475+
const decoder = new TextDecoder();
2476+
let text = "";
2477+
let truncated = false;
2478+
2479+
try {
2480+
while (text.length <= maxChars) {
2481+
const { done, value } = await reader.read();
2482+
if (done) {
2483+
text += decoder.decode();
2484+
break;
2485+
}
2486+
2487+
text += decoder.decode(value, { stream: true });
2488+
if (text.length > maxChars) {
2489+
text = text.slice(0, maxChars);
2490+
truncated = true;
2491+
break;
2492+
}
2493+
}
2494+
} finally {
2495+
if (truncated) {
2496+
await reader.cancel().catch(() => undefined);
2497+
} else {
2498+
reader.releaseLock();
2499+
}
2500+
}
2501+
2502+
return truncated ? `${text}\n[truncated]` : text;
2503+
}
2504+
24652505
async function waitForDiscordMessage(params) {
24662506
const deadline = Date.now() + 3 * 60 * 1000;
24672507
while (Date.now() < deadline) {
@@ -2473,7 +2513,7 @@ async function waitForDiscordMessage(params) {
24732513
},
24742514
},
24752515
);
2476-
const text = await response.text();
2516+
const text = await readBoundedCrossOsResponseText(response);
24772517
if (!response.ok) {
24782518
await sleep(2_000);
24792519
continue;
@@ -2501,7 +2541,7 @@ async function postDiscordMessage(params) {
25012541
}),
25022542
},
25032543
);
2504-
const text = await response.text();
2544+
const text = await readBoundedCrossOsResponseText(response);
25052545
if (!response.ok) {
25062546
throw new Error(`Failed to post Discord smoke message: ${text}`);
25072547
}
@@ -3292,7 +3332,7 @@ async function runDashboardSmoke(params) {
32923332
const response = await fetch(dashboardUrl, {
32933333
signal: AbortSignal.timeout(CROSS_OS_DASHBOARD_FETCH_TIMEOUT_MS),
32943334
});
3295-
const html = await response.text();
3335+
const html = await readBoundedCrossOsResponseText(response);
32963336
if (
32973337
response.ok &&
32983338
html.includes("<title>OpenClaw Control</title>") &&

test/scripts/openclaw-cross-os-release-checks.test.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import {
2828
canConnectToLoopbackPort,
2929
buildDiscordSmokeGuildsConfig,
3030
buildRealUpdateEnv,
31+
CROSS_OS_FETCH_BODY_MAX_CHARS,
3132
CROSS_OS_GATEWAY_READY_TIMEOUT_MS,
3233
CROSS_OS_GATEWAY_STATUS_COMMAND_TIMEOUT_MS,
3334
CROSS_OS_GATEWAY_STATUS_RPC_TIMEOUT_MS,
@@ -51,6 +52,7 @@ import {
5152
parseArgs,
5253
packageHasScript,
5354
readInstalledVersion,
55+
readBoundedCrossOsResponseText,
5456
readRunnerOverrideEnv,
5557
resolveCrossOsAgentTurnOptional,
5658
runCommand,
@@ -87,6 +89,17 @@ describe("scripts/openclaw-cross-os-release-checks", () => {
8789
expect(CROSS_OS_DASHBOARD_FETCH_TIMEOUT_MS).toBeGreaterThanOrEqual(10_000);
8890
});
8991

92+
it("bounds cross-OS fetched response bodies", async () => {
93+
const tail = "tail-sentinel-should-not-appear";
94+
const response = new Response(`${"x".repeat(5000)}${tail}`);
95+
96+
const text = await readBoundedCrossOsResponseText(response, 128);
97+
98+
expect(text).toContain("[truncated]");
99+
expect(text).not.toContain(tail);
100+
expect(CROSS_OS_FETCH_BODY_MAX_CHARS).toBeGreaterThan(1024);
101+
});
102+
90103
it("keeps gateway RPC status probes patient enough for live release startup", () => {
91104
expect(CROSS_OS_GATEWAY_STATUS_RPC_TIMEOUT_MS).toBeGreaterThanOrEqual(30_000);
92105
expect(CROSS_OS_GATEWAY_STATUS_COMMAND_TIMEOUT_MS).toBeGreaterThan(

0 commit comments

Comments
 (0)