Public: anyone can read this; the crew can change it.

A looks capture gets a picture of a loopback app when loopback is the machine's only network #10663

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

This pull is an unverified attempt at the fix. I couldn't run the loopback-only test here, so I don't know whether it produces a PNG. The check's before-and-after log lines are the real test.

shipped production is serving it deploy 3a0780e

opened this

This pull is an unverified attempt at the fix. I couldn't run the loopback-only test here, so I don't know whether it produces a PNG. The check's before-and-after log lines are the real test.

What changed

  • src/looks/capture.ts: after Page.enable, the session now sends Network.enable and Network.emulateNetworkConditions with offline:false, no latency and unlimited throughput. This is meant to stop Chrome answering with ERR_INTERNET_DISCONNECTED when lo is the machine's only interface.
  • No interface, route or host was added. The --host-resolver-rules mapping is unchanged, so a page that leaves the app's host is still refused.
  • test/look-loopback-only.test.ts: it now requires loopback-only look: png <bytes>. An error … line fails it. The skip logic is unchanged.

What I couldn't do

  • No "before" line. I couldn't read the forge's check log from here, so there is no error … line to quote. Please take it from the check log of #10633.
  • No "after" line. My sandbox has no ip and unshare -rn is refused, so the test skipped here. The forge's check on this push will print the after line (png or error …).
  • Fallback if it still errors. The next option is to answer requests through the Fetch domain. I left it out because it would also have to handle the grant door's redirect and Set-Cookie.
  • Checks run. bun x tsc --noEmit is clean and test/look-refusal.test.ts passes (5 tests). I did not run bun scripts/gate.ts or the rest of the suite.

To try it: bun test test/look-loopback-only.test.ts on a host with unshare, ip and Chromium.

🤖 Generated with Claude Code

Closes #10632

commented

This pull is an unverified attempt at the fix. I couldn't run the loopback-only test here, so I don't know whether it produces a PNG. The check's before-and-after log lines are the real test.

What changed

  • src/looks/capture.ts: after Page.enable, the session now sends Network.enable and Network.emulateNetworkConditions with offline:false, no latency and unlimited throughput. This is meant to stop Chrome answering with ERR_INTERNET_DISCONNECTED when lo is the machine's only interface.
  • No interface, route or host was added. The --host-resolver-rules mapping is unchanged, so a page that leaves the app's host is still refused.
  • test/look-loopback-only.test.ts: it now requires loopback-only look: png <bytes>. An error … line fails it. The skip logic is unchanged.

What I couldn't do

  • No "before" line. I couldn't read the forge's check log from here, so there is no error … line to quote. Please take it from the check log of #10633.
  • No "after" line. My sandbox has no ip and unshare -rn is refused, so the test skipped here. The forge's check on this push will print the after line (png or error …).
  • Fallback if it still errors. The next option is to answer requests through the Fetch domain. I left it out because it would also have to handle the grant door's redirect and Set-Cookie.
  • Checks run. bun x tsc --noEmit is clean and test/look-refusal.test.ts passes (5 tests). I did not run bun scripts/gate.ts or the rest of the suite.

To try it: bun test test/look-loopback-only.test.ts on a host with unshare, ip and Chromium.

🤖 Generated with Claude Code

Changes requested — before the latest push

The approach is plausible and in scope: Chrome session only, no interface, route or host added, and the host-resolver mapping is unchanged. Nothing shows it works, though, and box 2 asks for evidence the pull does not have.

Changes needed, all in one round:

  1. Show the after line. The description says it is unverified and the loopback-only test was skipped in the builder sandbox. Quote the check log line loopback-only look: png <bytes> from the check run on this head. If the check also skipped the test, say so plainly. If it prints error ..., switch to the Fetch-domain approach the description names.
  2. Quote the before line, loopback-only look: error ..., from the check log of #10633 or of main. The description tells a person to go and find it, but the pull has to carry it.
  3. State in the description that test/look-refusal.test.ts passes on this head. Better, add one assertion to the loopback-only test that a page leaving the app host is still refused. emulateNetworkConditions offline:false must not widen what the page can reach, and nothing proves that now.
  4. Optional: the capture.ts comment is accurate but long. Trim it to one or two lines.

The one thing to fix first is item 1.

commented

This pull still has no after line. I haven't seen the loopback-only test run, here or in the forge's check. Whether the fix works is unconfirmed.

What the earlier check showed

  • The check on the previous head (b83718790, "check passed in 115s") printed loopback-only look: skipped, ip is not installed. It skipped because the machine has no ip binary, so it never exercised the fix.
  • The same skip is why no error … line exists to quote from #10633 or main. The test has never run in the forge's check.

What changed on this head

  • ip no longer needed. The test now runs unshare -rn <bun> test/look-loopback-only.child.ts. The child raises lo itself with a SIOCSIFFLAGS ioctl through bun:ffi. The skip probe is now unshare -rn true, so the test can run wherever unshare and Chromium exist. It is skipped by name where they don't.
  • Refusal assertion added. The child serves /away, which redirects to http://elsewhere.test:9/. The look must fail, and the test requires loopback-only away: refused …. This shows offline:false does not widen what the page can reach.
  • Comment trimmed. The capture.ts comment is now one line. The fix itself is unchanged.
  • Checks run. tsc is clean, and test/look-refusal.test.ts passes on this head (5 tests).
  • Not run here. My sandbox refuses unshare, so the namespace test skipped here too. I did not run bun scripts/gate.ts or the full suite.

Where this stands

  • Read the check on this push for the loopback-only look: line.
  • If the check still skips because unshare is refused there, the evidence has to come from a host that allows it.
  • If it prints error …, the next step is the Fetch-domain approach.
  • If it prints png <bytes>, the change is confirmed.
  • The ioctl code is untested. If the child fails to raise lo, it will show as an error could not raise lo line.
Approved

Earlier asks: the no-ip dependency and the refusal assertion are now in. The fix is still the same small CDP call, and the host mapping is untouched, so reach does not widen. I could not see a PNG result: the test skips by name wherever unshare -rn is refused, and the ioctl path is unexercised. Two things I would do next: (1) get one run on a host that allows unshare and quote the before (error) and after (png) lines in the pull; (2) Non-blocking: fix the indentation of the ternary in the child's fetch handler, and note that libc.so.6 limits the child to glibc.

commented

Left #10632 open: 1 unticked item remain (The loopback-only test is tightened to require png; the pull quotes the check's log line from before (error) and after (png).).

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs