fix(scripts): keep the first proxy error in the package-update verifier (#6362)

The registry fixture sent response headers before reading the upstream body,
then always wrote a 500 on error. A body failure hit ERR_HTTP_HEADERS_SENT,
which hid the real error and crashed the verifier with its helper still running.
The fixture now reads the body first, destroys a response that already started,
and the verifier rethrows the first fixture error.

Refs #6038.

🤖 Generated with Claude Code (Sonnet 5.5) 🦊

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Cassie_FoxandClaude Sonnet 5.5 authored and GitHub committed 2026-10-23 06:10:39 +08:00
1 parent 371f3d91ae
commit 0f09630645
2 files changed
+109 -1

No files matched your search

+11 -1
View File
@@ -24,8 +24,14 @@ export async function verifyPackageUpdate({
'[mcp_servers.rea]\ncommand = "npx"\nargs = ["-y", "rea-agents@0.0.0", "mcp"]\n';
await mkdir(dirname(codexPath), { recursive: true });
await writeFile(codexPath, originalConfig);
let fixtureFailure;
const server = createServer((request, response) => {
void serveRegistry(request, response).catch((error) => {
fixtureFailure ??= error;
if (response.headersSent) {
response.destroy();
return;
}
response.writeHead(500);
response.end(String(error));
});
@@ -57,11 +63,12 @@ export async function verifyPackageUpdate({
response.end("{}");
} else {
const upstream = await fetch(`https://registry.npmjs.org${request.url}`);
const body = Buffer.from(await upstream.arrayBuffer());
response.writeHead(upstream.status, {
"Content-Type":
upstream.headers.get("content-type") ?? "application/octet-stream",
});
response.end(Buffer.from(await upstream.arrayBuffer()));
response.end(body);
}
}
await new Promise((resolveListen, reject) => {
@@ -171,11 +178,14 @@ if (result.status === "failed") process.exitCode = 1;
throw new Error(
"Updated CLI did not expose update as its sole maintenance command",
);
if (fixtureFailure !== undefined) throw fixtureFailure;
return {
installed_version: result.installedVersion,
exact_release: true,
maintenance_read_only: true,
};
} catch (error) {
throw fixtureFailure ?? error;
} finally {
server.closeAllConnections();
await new Promise((resolveClose, reject) =>
@@ -0,0 +1,98 @@
import { execFile } from "node:child_process";
import { mkdir, writeFile } from "node:fs/promises";
import { join, resolve } from "node:path";
import { promisify } from "node:util";
import { pathToFileURL } from "node:url";
import { expect, it } from "vitest";
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
const execFileAsync = promisify(execFile);
const injectedFailure = "injected upstream body failure";
it("reports the upstream body failure instead of a second header write", async () => {
const testRoot = await createTestTempDirectory("rea-update-registry-");
const packageRoot = join(testRoot, "package");
const workspace = join(testRoot, "workspace");
const prefix = join(testRoot, "prefix");
const tarball = join(testRoot, "release.tgz");
const application = join(packageRoot, "dist", "application");
await Promise.all([
mkdir(application, { recursive: true }),
mkdir(join(packageRoot, "scripts"), { recursive: true }),
mkdir(workspace, { recursive: true }),
mkdir(prefix, { recursive: true }),
]);
await Promise.all([
writeFile(tarball, "archive"),
writeFile(
join(packageRoot, "package.json"),
JSON.stringify({ name: "rea-agents", version: "6.0.0" }),
),
writeFile(
join(packageRoot, "dist", "generatedPackageMetadata.js"),
'export const generated = { version: "6.0.0" };\n',
),
writeFile(
join(packageRoot, "scripts", "rea.mjs"),
[
'import { readFileSync } from "node:fs";',
'const metadata = new URL("../package.json", import.meta.url);',
"console.log(JSON.parse(readFileSync(metadata, 'utf8')).version);",
"",
].join("\n"),
),
writeFile(
join(application, "Update.js"),
[
"export async function runUpdate() {",
" const registry = process.env.npm_config_registry;",
" const response = await fetch(`${registry}/unlisted`, {",
" signal: AbortSignal.timeout(5000),",
" });",
" const body = await response.text();",
" throw new Error(`registry fixture answered ${response.status}: ${body}`);",
"}",
"",
].join("\n"),
),
writeFile(
join(application, "UpdateRuntime.js"),
"export const systemUpdateHost = () => ({});\n",
),
]);
const verifierUrl = pathToFileURL(
resolve("scripts/verify-package-update.mjs"),
).href;
const harness = `
globalThis.fetch = async () => ({
status: 200,
headers: new Headers({ "content-type": "application/json" }),
arrayBuffer: async () => {
throw new Error(${JSON.stringify(injectedFailure)});
},
});
const { verifyPackageUpdate } = await import(${JSON.stringify(verifierUrl)});
let failure;
try {
await verifyPackageUpdate({
prefix: ${JSON.stringify(prefix)},
packageRoot: ${JSON.stringify(packageRoot)},
tarball: ${JSON.stringify(tarball)},
workspace: ${JSON.stringify(workspace)},
environment: { PATH: process.env.PATH },
});
} catch (cause) {
failure = cause instanceof Error ? cause.message : String(cause);
}
process.stdout.write(JSON.stringify({ failure }));
`;
const { stdout } = await execFileAsync(
process.execPath,
["--input-type=module", "--eval", harness],
{ env: { ...process.env }, maxBuffer: 1_024 * 1_024, timeout: 30_000 },
);
expect(JSON.parse(stdout)).toEqual({ failure: injectedFailure });
}, 45_000);