Files
sencho/backend/src/utils
Anso f5a52e44dc refactor(pilot): narrow Mesh handle, prune dead code, add replay-route test (#982)
* refactor(pilot): narrow PilotTunnelManager.getBridge to MeshTunnelHandle

The manager handed out the entire PilotTunnelBridge to its only consumer,
MeshService, which let any current or future caller reach into transport
internals: loopback URL, per-stream maps, the close API, the underscored
_writeTcpData / _closeTcpStream, the diagnostic helpers. None of that
was load-bearing for Mesh.

Introduce a MeshTunnelHandle interface alongside TcpStream in
PilotTunnelBridge.ts that exposes only the two methods Mesh actually
calls (openTcpStream and getBufferedAmount), have PilotTunnelBridge
declare implements MeshTunnelHandle, and change getBridge to return
the interface. MeshService continues to compile unchanged because its
existing call sites only touch the narrowed surface.

A future alternative transport (a stub for tests, a different routing
strategy) now has a one-method-and-a-getter contract to satisfy
instead of the full bridge.

* refactor(pilot): drop unused tunnel manager and bridge surface

Three public methods predating the hardening pass had zero callers
across the entire codebase (verified via grep across backend, frontend,
e2e):

  - PilotTunnelManager.touch(nodeId): never invoked. The pilot_last_seen
    timestamp is updated by the manager itself on registerTunnel and by
    the persistence layer on heartbeat events.
  - PilotTunnelManager.listActive(): never invoked. The metrics endpoint
    added in PR #979 returns its own per-node breakdown via
    getMetricsSnapshot, which is the canonical observability surface.
  - PilotTunnelBridge.listTcpStreams() and the supporting
    TcpStreamSummary interface: never invoked. The Mesh diagnostics
    sheet that would have consumed it is not wired and would use
    getMetricsSnapshot if/when it ships.

Removing them tightens the public surface and prevents accidental new
dependencies on speculative future-proofing.

* test(pilot): cover enrollment replay rejection at the route layer

The DB-level test in pilot-enrollment.test.ts already verifies that
consumePilotEnrollment is one-shot. That guards the persistence layer
but not the route handler: a refactor of handlePilotTunnel that swaps
the order of consume vs upgrade, or that grants the WebSocket
upgrade before checking the consume result, would silently break the
security invariant while DB-layer tests stay green.

Drive handlePilotTunnel directly with a stub IncomingMessage and
Duplex socket. Six cases:
  - Already-consumed enrollment row -> 401.
  - Token whose hash matches no row -> 401.
  - Row whose expires_at has passed -> 401.
  - Missing Authorization header -> 401.
  - JWT signed with a wrong secret -> 401.
  - pilot_tunnel JWT for an unknown node -> 404.

The stub captures HTTP/1.1 status writes so the test asserts the
exact rejection lands on the wire, not just that the function
returned without throwing.

* docs(debug): warn future committers off per-frame isDebugEnabled calls

Code-review feedback on PR #979 noted that isDebugEnabled is fine in
the cadences it has today (per-tunnel, per-request, error paths) but
is fragile against a future commit that drops it into a per-frame
WebSocket loop. The function does a try/catch + Node require cache
lookup + a method call into DatabaseService on every invocation;
acceptable at hundreds of calls per second, expensive at thousands.

Add a comment block above the function spelling out the acceptable
and unacceptable cadences and the snapshot-outside-the-loop
mitigation, so the next person to add a diag log there sees the
constraint.

* fix(pilot): address PR A code-review findings

Code review on this branch surfaced four items:

  - Em-dash directive (CLAUDE.md Directive 18) violations in four
    comment sites; replaced with colons or restructured.
  - debug.ts perf comment claimed try/catch frame setup as the cost
    driver. V8 inlines those; the load-bearing cost is the require
    lookup and singleton dispatch. Reword.
  - Test file header described coverage as 'replay rejection at the
    route layer' but the file now also covers missing-header,
    wrong-secret, expired-row, never-stored, and unknown-node
    rejection paths. Widen the JSDoc and the describe label to match.
  - Stub-cast comment in the replay test now explicitly lists the
    IncomingMessage and Duplex surface the stub satisfies, so a
    future commit that grows handlePilotTunnel's surface (rate
    limiting, socket options) updates both stubs instead of
    silently no-opping against them.

No behavior change.
2026-05-07 23:45:16 -04:00
..