HarperFast / HarperFast/harper-pro

remove_node is not honored by the inbound replication auth gate: a removed node re-authorizes on reconnect and keeps receiving data

Open
#793 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
JavaScript
Stars
3
Forks
0
Avg merge
1d 21h
Merged PRs (30d)
80

Description

`remove_node` revokes a peer locally, but the removed node re-authorizes itself on its own
reconnect and resumes receiving replicated data. The inbound connection auth gate cannot tell a
genuine `hdb_nodes` tombstone from a transient decode miss, so it falls back to trusting the
certificate-validated name.

## Mechanism (harper-pro, `origin/main` as of 2026-09-01)

`resolveNodeForAuth` (`replication/knownNodes.ts:301-330`) — reached from `readNodeForAuth` at
`replication/replicator.ts:215` and `:267`, the cert/hostname gate for an inbound replication
connection — does a point lookup for the node row, and when that lookup is invalid it falls back to
`storeRecordRangeVisible(store, name)` and returns `{ name }`, i.e. it trusts the cert-validated
name. There is no distinction between "row genuinely deleted by `remove_node`" and "row present but
transiently undecodable".

The codebase already has the primitive that makes that distinction: `probeNodeRow`
(`replication/knownNodes.ts:504`, added in `decbca38`, 2026-07-21) uses `isGenuineNodeDeletion` /
a clean-null point read to separate a real tombstone from a decode race. It is wired only into the
**ongoing send-authorization** watch (`resolveNodeForSendAuth`, and `replicationConnection.ts:584`),
not into the **initial-connection** auth path that gates a removed peer's reconnect. So this bug
class was closed for one path and left open for its sibling.

This is not an unauthenticated bypass — the peer holds a valid certificate from when it was enrolled.
It is an operator revocation the data plane does not honor: after `remove_node`, replicated data
keeps flowing to a node that was decommissioned.

## Why it isn't already covered

The `'remove_node_back;'` operation-name typo (fixed in `1169e8848`, shipped via #615) masked this
repro: with the reciprocal removal working, the removed node's own `hdb_nodes` record is deleted, so
the common repro stops reproducing. The auth-gate hole is untouched. A fixer who lands only the
membership fix will believe they are done.

#615's own body says as much: "[the self-initiated resubscribe] still succeeds today… That is a
separate, currently-live bug." PR #714 attempted a related `probeNodeRow`/posture-cache rework but
was **closed unmerged** (2026-08-17) and targeted the subscription/outbound path, not
`resolveNodeForAuth`.

## Repro

`qa764-resubscribe-auth.test.mjs` — 3/3 on 4 runs (harper-pro `86f2955e`). The
`removeNodeBlastRadius.test.mjs` suite added by #615 pins local revocation durability but does not
cover the removed peer's self-initiated re-auth.

## Fix shape

Route `resolveNodeForAuth`'s invalid-point-lookup fallback through `probeNodeRow` /
`isGenuineNodeDeletion` the way `resolveNodeForSendAuth` already does: a genuine deletion must fail
the auth, a decode race may still fall back to the cert-validated name.

Contributor guide

Open the contributing guide

Research direction

Start with resolveNodeForAuth in replication/knownNodes.ts and its callers readNodeForAuth in replication/replicator.ts. Compare its invalid-lookup handling with probeNodeRow, isGenuineNodeDeletion, and resolveNodeForSendAuth, then run qa764-resubscribe-auth.test.mjs. Done means a genuine hdb_nodes deletion rejects a reconnect while a transient decode race still permits the certificate-validated name.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, nodejs
Domain
authentication, backend, distributed-systems
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
68/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.