Hacktoberfest 2026: le issue che i maintainer hanno segnato per ottobre, aperte e adatte ai principianti. Sfoglia le issue Hacktoberfest

A listener on all interfaces silently receives a test node's connections on macOS; the conflict canary cannot see it

Aperta
#38 1 commento 0 reazioni 1 assegnatario Vedi su GitHub

@dawsontoth ci sta già lavorando.

Dal 28/9/2026.

Valutazione

Questa issue non è ancora stata valutata.

Descrizione

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 found before the restart, then 401 {"error":"Login failed"} on every later probe (20 over 10 s).
  • One fresh connection per probe: 404 → about 350 ms of 401 → 404 for 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.hostname skips 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
Lingua principale
TypeScript
Stelle
1
Fork
0
Metriche di merge delle PR
Nessuna PR unita negli ultimi 30g

Preparare l'ambiente

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di HarperFast/integration-testing

Tutte le issue di HarperFast/integration-testing

Issue simili

Altre issue su TypeScript

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.