A listener on all interfaces silently receives a test node's connections on macOS; the conflict canary cannot see it
@dawsontoth đang làm issue này rồi.
Từ ngày 28/9/2026.
Đánh giá
Issue này chưa được đánh giá.
Mô tả
On macOS, a process listening on Harper's fixed ports on all interfaces, most commonly a local Harper instance running with its default config, receives a test node's connections whenever the node has no listener of its own on its loopback address. That happens before the node binds, during an HTTP-worker restart (non-overlapping on macOS), and after teardown. Clients with keep-alive, such as fetch, then stay connected to that process, so a suite fails, or passes, against the wrong server. The loopback pool's conflict canary does not detect this.
Reproduction
Machine: macOS with a Harper instance listening on *:9925, *:9926, *:1883, *:8883 (IPv6 dual-stack, started with harper run).
A suite starts a node through startHarper (it got 127.0.0.8), runs restart_service with service: 'http_workers', then sends GET /nonexistent with the harness admin credentials:
fetch(keep-alive):404 Not foundbefore the restart, then401 {"error":"Login failed"}on every later probe (20 over 10 s).- One fresh connection per probe:
404→ about 350 ms of401→404for the remaining 5 s.
lsof -nP [email protected] after the restart shows the probe connection's server end owned by the other Harper's PID, while the node is listening on 127.0.0.8:9926 again. The other instance has no admin / Abc1234! user, so it rejects the credentials. This was first investigated as a credential-store regression in Harper, because only restarts handed from a worker or job thread showed it. Those operations return before the replacement worker binds; a main-thread deploy_component with restart: true waits for it.
Why the canary misses it
findConflictingPort (src/loopbackAddressPool.ts) probes the canary ports with an exclusive bind. On macOS, Node/libuv sets SO_REUSEADDR, and BSD semantics let a bind to 127.0.0.x:P succeed next to another socket's wildcard listener on P. The bind probe therefore reports the address free. Measured with plain Node, Node 24.21.0:
| OS | wildcard listener | bind 127.0.0.1:P |
connect 127.0.0.1:P |
|---|---|---|---|
| macOS 26 (Darwin 25.6.0) | 0.0.0.0:P or [::]:P |
succeeds | accepted by the wildcard |
| Linux (node:24-slim container) | 0.0.0.0:P or [::]:P |
EADDRINUSE |
accepted by the wildcard |
When nothing else listens, a connection opened during the node's gap gets ECONNREFUSED. With a wildcard listener present, the kernel falls back to it instead.
On Linux the canary does fire, but it reports each address as still in use by another Harper node and keeps retrying with no deadline. That is a separate, lower-impact problem, tracked in #39.
Proposed fix
After the canary's bind succeeds, getNextAvailableLoopbackAddress also connect-probes the canary ports on the new address. No Harper node runs there yet, so an accepted connection means another process's listener covers the address. It then releases the slot and throws a ForeignListenerError that names the address and port, the likely cause, how to find the holder, and an opt-out: HARPER_INTEGRATION_TEST_ALLOW_FOREIGN_LISTENERS=1 turns the error into a warning. A refused loopback connect costs p50 0.03 ms / p99 0.6 ms (Linux) and 0.04 / 0.9 ms (macOS), and on Linux the bind canary catches this case first.
Out of scope, possible follow-ups:
- MQTT (1883/8883) and HTTPS (9927) are not probed. Probing them would fail every suite, MQTT or not, on a host with a resident broker; the host in #28 has one on the pool address. MQTT suites that connect across a restart (for example harper's
integrationTests/mqtt/qa649-mqtt-restart-wedge.test.ts) stay exposed to a broker listening on all interfaces. - A pre-set
ctx.harper.hostnameskips allocation, so it skips the check. - A foreign listener that starts after allocation is not detected.
Measured on
| Component | Version |
|---|---|
| @harperfast/integration-testing | 1.0.0 (origin/main 74ea958) |
| harper (system under test) | origin/main 360c60a72 |
| Node | v24.21.0 |
| OS | macOS 26, Darwin 25.6.0 (arm64); Linux via node:24-slim for the bind table |
- Ngôn ngữ chính
- TypeScript
- Star
- 1
- Fork
- 0
- Chỉ số merge pull request
- Không có pull request nào được merge trong 30 ngày
Chuẩn bị môi trường
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của HarperFast/integration-testing
-
setupHarperWithFixture overwrites ctx.harper, dropping pre-set hostname (breaks multi-node add_node)Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 68/100
-
enhancement good first issue
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 85/100
-
Độ khó 3/5 1-2 ngày Mức phù hợp với người mới 74/100
-
Độ khó 4/5 3-5 ngày Mức phù hợp với người mới 58/100
-
Detached Harper children are orphaned permanently when the runner dies by SIGKILL/SIGHUP — reap guard only covers exit/SIGINT/SIGTERMCó thể làm lại được @kriszyp đã nhận 38 ngày trước và không có pull request nào đang mở. Đang mở
HarperFast/integration-testing#29 · 1 bình luận · 1 người được giao ·
Tất cả issue của HarperFast/integration-testing
Issue tương tự
-
triage
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 90/100
Maintainer thường phản hồi trong vòng 1 ngày
-
bug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 68/100
mermaid-js/mermaid-live-editor#2053 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
factory
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 82/100
jessepollak/home#1455 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
community first-timers-only good first issue hacktoberfest help wanted low hanging fruit up-for-grabs
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 95/100
lingdojo/kana-dojo#31227 · 1 bình luận · 5 reaction ·
Maintainer thường phản hồi trong vòng 1 ngày
-
mobile: device viewer shows dark status bar icons on its dark backdrop in light mode (Android)Đang mở
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 92/100
appandflow/stim#1838 ·
Maintainer thường phản hồi trong vòng 1 ngày