This commit is contained in:
Reinier Criel 2026-05-22 16:55:17 +08:00 committed by GitHub
commit 68d71b2e31
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 93 additions and 25 deletions

View file

@ -68,6 +68,7 @@ function createHttpsServer(hostname, port, interceptor) {
return; return;
} }
try {
const pathAndQuery = getRequestPathAndQuery(req.url); const pathAndQuery = getRequestPathAndQuery(req.url);
const targetUrl = `https://${hostname}${pathAndQuery}`; const targetUrl = `https://${hostname}${pathAndQuery}`;
@ -83,6 +84,13 @@ function createHttpsServer(hostname, port, interceptor) {
// Collect request body // Collect request body
forwardRequest(req, hostname, port, res, requestInterceptor); forwardRequest(req, hostname, port, res, requestInterceptor);
} catch (/** @type {any} */ error) {
ui.writeError(
`Safe-chain: Error handling request for ${req.url}: ${error.message}`
);
res.writeHead(502, "Bad Gateway");
res.end("Bad Gateway: Error handling request");
}
} }
const server = https.createServer( const server = https.createServer(

View file

@ -14,6 +14,7 @@ let timedoutImdsEndpoints = [];
* @returns {void} * @returns {void}
*/ */
export function tunnelRequest(req, clientSocket, head) { export function tunnelRequest(req, clientSocket, head) {
try {
const httpsProxy = process.env.HTTPS_PROXY || process.env.https_proxy; const httpsProxy = process.env.HTTPS_PROXY || process.env.https_proxy;
if (httpsProxy) { if (httpsProxy) {
@ -31,6 +32,11 @@ export function tunnelRequest(req, clientSocket, head) {
} else { } else {
tunnelRequestToDestination(req, clientSocket, head); tunnelRequestToDestination(req, clientSocket, head);
} }
} catch (/** @type {any} */ err) {
ui.writeError(
`Safe-chain: tunnel request failed for ${req.url} : ${err.message}`
);
}
} }
/** /**

View file

@ -0,0 +1,54 @@
import { describe, it, before, beforeEach, afterEach } from "node:test";
import { DockerTestContainer } from "./DockerTestContainer.js";
import assert from "node:assert";
describe("E2E: DNS failure resilience", () => {
let container;
before(async () => {
DockerTestContainer.buildImage();
});
beforeEach(async () => {
container = new DockerTestContainer();
await container.start();
const installationShell = await container.openShell("zsh");
await installationShell.runCommand("safe-chain setup");
});
afterEach(async () => {
if (container) {
await container.stop();
container = null;
}
});
it("should not crash when the npm registry is unreachable", async () => {
const shell = await container.openShell("zsh");
// Make the npm registry domain unreachable.
// `npm install lodash` talks to https://registry.npmjs.org/ for both metadata and tarballs.
await shell.runCommand(
'echo "127.0.0.1 registry.npmjs.org" >> /etc/hosts'
);
const result = await shell.runCommand(
// Fail fast so the shell runner doesn't time out.
// Also disable extra network calls that could introduce noise.
"npm install lodash --no-audit --no-fund --fetch-retries=0 --fetch-timeout=2000 --safe-chain-logging=verbose"
);
assert.ok(
result.output.includes("registry.npmjs.org"),
`Output did not reference the npm registry host; /etc/hosts override may not have applied. Output was:\n${result.output}`
);
// Ensure it did NOT crash with Unhandled Promise Rejection
assert.strictEqual(
result.output.includes("Unhandled promise rejection"),
false,
`Output indicates process crash (Unhandled promise rejection). Output was:\n${result.output}`
);
});
});