* fix: fall back to enroll token when pilot tunnel JWT is rejected
On HTTP 401/404 upgrade rejection, delete stale pilot.jwt and retry with SENCHO_ENROLL_TOKEN.
* test: import pilot agent module after DATA_DIR is set in fallback test
The auth-fallback test statically imported pilot/agent, which freezes its
pilot.jwt path from DATA_DIR at module load, before setupTestDb redirects
DATA_DIR to a writable temp dir. On the Linux CI runner the path resolved
to a non-writable /app/data, so persistToken silently failed and the
round-trip assertion read null. Import the module dynamically in beforeAll
after setupTestDb, matching the sibling unit test.
* fix: remove unexpected-response listener that blocked pilot reconnect
The ws library skips abortHandshake when an unexpected-response listener
exists, so error and close never fire and the agent hangs in CONNECTING.
Detect auth rejection via the abortHandshake error message instead; the
close handler already performs enroll-token fallback and reconnect.
After the central proxy forwards a request through the pilot tunnel, the
agent receives an http_req or ws_open frame and opens a local loopback
request to its own Sencho server. The forwarder previously copied the
inbound headers verbatim with no Authorization header, so the local
authMiddleware rejected every proxied call with 401 Authentication
required. The central cannot sign the missing token because each Sencho
instance has its own auth_jwt_secret generated at first-run setup.
The agent process runs in the same Node process as the local Sencho
server and shares the local DatabaseService, so it can mint a fresh
pilot_tunnel-scoped JWT signed with the local secret. Token TTL is 5
minutes with a refresh-on-use 4-minute cache to avoid jwt.sign on every
request. The header is built once per request via buildLoopbackHeaders
and applied to both onHttpReq and onWsOpen so the two forwarder paths
stay in lockstep. The local authMiddleware accepts the scope through
its existing pilot_tunnel branch with no special-case bypass.
Together with the proxy-side change in the previous commit, this
completes the central, bridge, agent, local-Sencho HTTP path for
pilot-agent-mode nodes.