Hacktoberfest 2026: los issues que los mantenedores marcaron para octubre, abiertos y aptos para principiantes. Explorar issues de Hacktoberfest

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

Abierto
#38 1 comentario 0 reacciones 1 asignado Ver en GitHub

@dawsontoth ya está trabajando en esto.

Desde el 28/9/2026.

Evaluación

Este issue todavía no se ha evaluado.

Descripción

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
Lenguaje dominante
TypeScript
Estrellas
1
Forks
0
Métricas de merge de PR
Sin PR fusionados en 30 d

Preparar el entorno

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Más de HarperFast/integration-testing

Todos los issues de HarperFast/integration-testing

Issues similares

Más issues de TypeScript

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.