fix(e2e): time out npm registry upstream requests (#108718)

This commit is contained in:
Alix-007
2026-07-16 02:06:25 -07:00
committed by GitHub
parent 5ad0d4d6c0
commit f0720a856d
2 changed files with 92 additions and 1 deletions
@@ -25,6 +25,9 @@ function normalizeUpstreamRegistry(raw) {
}
const upstreamRegistry = normalizeUpstreamRegistry(process.env.OPENCLAW_NPM_REGISTRY_UPSTREAM);
// Match other E2E package-download budgets while keeping a stalled public-registry hop
// from consuming the much larger install phase deadline.
const UPSTREAM_REQUEST_TIMEOUT_MS = 120_000;
if (!portFile || packageArgs.length === 0 || packageArgs.length % 3 !== 0) {
console.error(
@@ -139,7 +142,10 @@ async function proxyUpstream(rawRequestUrl, response) {
}
try {
const upstreamUrl = resolveUpstreamRequestUrl(rawRequestUrl);
const upstreamResponse = await fetch(upstreamUrl, { redirect: "manual" });
const upstreamResponse = await fetch(upstreamUrl, {
redirect: "manual",
signal: AbortSignal.timeout(UPSTREAM_REQUEST_TIMEOUT_MS),
});
const body = Buffer.from(await upstreamResponse.arrayBuffer());
// Fetch decodes compressed bodies but preserves upstream length metadata.
// Emit the decoded size so npm clients do not truncate proxied responses.
+85
View File
@@ -12,6 +12,7 @@ import {
import { createServer, request as httpRequest } from "node:http";
import { tmpdir } from "node:os";
import path from "node:path";
import { pathToFileURL } from "node:url";
import { gzipSync } from "node:zlib";
import { describe, expect, it } from "vitest";
import { createBoundedChildOutput } from "../helpers/bounded-child-output.js";
@@ -740,6 +741,90 @@ test -d "$OPENCLAW_PLUGINS_TMP_DIR"
}
});
it("times out stalled upstream response bodies without stopping the fixture registry", async () => {
const tempDirs: string[] = [];
const root = makeTempDir(tempDirs, "openclaw-plugin-npm-fixture-proxy-timeout-");
const portFile = path.join(root, "port");
const preloadPath = path.join(root, "shorten-abort-timeout.mjs");
const tarballPath = path.join(root, "demo-plugin.tgz");
let upstreamHits = 0;
writeFileSync(
preloadPath,
[
"const nativeTimeout = AbortSignal.timeout.bind(AbortSignal);",
"AbortSignal.timeout = () => nativeTimeout(50);",
"",
].join("\n"),
"utf8",
);
writeFileSync(tarballPath, "fixture package archive", "utf8");
const upstream = createServer((_request, response) => {
upstreamHits += 1;
response.writeHead(200, { "content-type": "application/json" });
response.write('{"partial":');
});
await new Promise<void>((resolve) => {
upstream.listen(0, "127.0.0.1", resolve);
});
const upstreamAddress = upstream.address();
if (!upstreamAddress || typeof upstreamAddress === "string") {
throw new Error("expected upstream registry address");
}
const child = spawn(
process.execPath,
[
"--import",
pathToFileURL(preloadPath).href,
"scripts/e2e/lib/plugins/npm-registry-server.mjs",
portFile,
"@openclaw/demo-plugin-npm",
"1.0.0",
tarballPath,
],
{
cwd: process.cwd(),
env: {
...process.env,
OPENCLAW_NPM_REGISTRY_UPSTREAM: `http://127.0.0.1:${upstreamAddress.port}`,
},
stdio: ["ignore", "pipe", "pipe"],
},
);
const stderr = createBoundedChildOutput();
child.stderr.setEncoding("utf8");
child.stderr.on("data", (chunk) => {
stderr.append(chunk);
});
try {
const port = await waitForPortFile(portFile);
const stalled = await requestFixtureRegistry(port, "/stalled-package");
expect(stalled.statusCode, stderr.text()).toBe(502);
expect(stalled.body).toContain("upstream registry request failed");
expect(upstreamHits).toBe(1);
const local = await requestFixtureRegistry(port, "/@openclaw%2Fdemo-plugin-npm");
expect(local.statusCode, stderr.text()).toBe(200);
expect(child.exitCode, stderr.text()).toBeNull();
} finally {
if (child.exitCode === null) {
child.kill();
await new Promise((resolve) => {
child.once("close", resolve);
});
}
upstream.closeAllConnections();
await new Promise<void>((resolve) => {
upstream.close(() => resolve());
});
cleanupTempDirs(tempDirs);
}
});
it("does not let absolute-form request targets escape the configured upstream", async () => {
const tempDirs: string[] = [];
const root = makeTempDir(tempDirs, "openclaw-plugin-npm-fixture-proxy-origin-");