Skip to content

Commit a59ce4d

Browse files
Web3NLclaude
andcommitted
fix(dapp-cli): bypass Chromium DNS for *.localhost via Playwright route interception
--host-resolver-rules is not reliably propagated to Chrome's sandboxed network service subprocess (chrome-headless-shell), so *.localhost DNS fails non-deterministically on Ubuntu CI runners. Instead, intercept all *.localhost requests in Node.js with context.route() and proxy them to localhost, preserving the Host header so PocketIC's HTTP gateway routes to the correct canister. This bypasses Chrome DNS entirely. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent b912365 commit a59ce4d

1 file changed

Lines changed: 26 additions & 8 deletions

File tree

packages-rs/my-canister-dapp-cli/playwright-js/derive-principal.mjs

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -51,16 +51,34 @@ async function handleIIPopupAlwaysNew(popup) {
5151
}
5252

5353
async function main() {
54-
const browser = await chromium.launch({
55-
headless: true,
56-
// On Ubuntu, Chromium's built-in DNS resolver does not resolve *.localhost
57-
// subdomains. Explicitly map them to 127.0.0.1 so the local PocketIC
58-
// HTTP gateway (e.g. rdmx6-...-cai.localhost:8080) is reachable.
59-
// macOS resolves *.localhost natively; this rule is a no-op there.
60-
args: ['--host-resolver-rules=MAP *.localhost 127.0.0.1'],
61-
});
54+
const browser = await chromium.launch({ headless: true });
6255
// Fresh context = no stored passkey identity
6356
const context = await browser.newContext();
57+
58+
// On Linux, Chromium's built-in DNS resolver does not reliably resolve
59+
// *.localhost subdomains (the --host-resolver-rules flag is not propagated
60+
// to Chrome's sandboxed network service). Intercept all *.localhost requests
61+
// in Node.js and proxy them via localhost, preserving the Host header so
62+
// PocketIC's HTTP gateway can route to the correct canister.
63+
// macOS resolves *.localhost natively — this adds negligible overhead there.
64+
await context.route(
65+
(url) => url.hostname !== 'localhost' && url.hostname.endsWith('.localhost'),
66+
async (route) => {
67+
const url = new URL(route.request().url());
68+
const proxied = `http://localhost:${url.port}${url.pathname}${url.search}`;
69+
try {
70+
const response = await route.fetch({
71+
url: proxied,
72+
headers: { ...route.request().headers(), host: url.host },
73+
});
74+
await route.fulfill({ response });
75+
} catch (e) {
76+
process.stderr.write(`[proxy] ${url.href}: ${e.message}\n`);
77+
await route.abort();
78+
}
79+
}
80+
);
81+
6482
const page = await context.newPage();
6583

6684
// Intercept canister origin — canister does not need to be running

0 commit comments

Comments
 (0)