From 4eaa57e8b5f843e03ed0ad71aea730e3f75b47b1 Mon Sep 17 00:00:00 2001 From: riccardom Date: Wed, 21 Oct 2026 08:44:13 +0200 Subject: [PATCH] [client] pqkem: wake status subscribers when a peer turns quantum resistant The PSK usually lands after the connection came up, so the flag flips with no other state change. Without a notification, UI and CLI subscribers kept showing the peer as unprotected until something unrelated changed. --- client/internal/peer/status.go | 5 +++-- client/internal/peer/status_test.go | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/client/internal/peer/status.go b/client/internal/peer/status.go index 96b6d930f..067a9b58b 100644 --- a/client/internal/peer/status.go +++ b/client/internal/peer/status.go @@ -782,17 +782,18 @@ func (d *Status) UpdatePeerFQDN(peerPubKey, fqdn string) error { // to show up in the status. The mark persists until the peer is removed. func (d *Status) MarkPeerQuantumResistant(peerPubKey string) error { d.mux.Lock() - defer d.mux.Unlock() - peerState, ok := d.peers[peerPubKey] if !ok { + d.mux.Unlock() return errors.New("peer doesn't exist") } d.pqMarked[peerPubKey] = struct{}{} peerState.RosenpassEnabled = true d.peers[peerPubKey] = peerState + d.mux.Unlock() + d.notifyStateChange() return nil } diff --git a/client/internal/peer/status_test.go b/client/internal/peer/status_test.go index d0de41fb6..a7458f12c 100644 --- a/client/internal/peer/status_test.go +++ b/client/internal/peer/status_test.go @@ -616,3 +616,22 @@ func TestStatus_PQMarkClearedOnRemove(t *testing.T) { require.NoError(t, err) assert.False(t, st.RosenpassEnabled, "a re-added peer must not inherit the removed peer's PQ mark") } + +// TestStatus_PQMarkWakesSubscribers checks that a PSK landing after the connection came up +// reaches status subscribers, which otherwise keep showing the peer as not protected. +func TestStatus_PQMarkWakesSubscribers(t *testing.T) { + const key = "eDQmZp9jhQGX7XdYpHGaFSpAouldr3Sbf7MZRcGTGGQ=" + status := NewRecorder("https://mgm") + require.NoError(t, status.AddPeer(key, "peer.netbird.cloud", "100.64.0.2", "")) + + id, changes := status.SubscribeToStateChanges() + defer status.UnsubscribeFromStateChanges(id) + + require.NoError(t, status.MarkPeerQuantumResistant(key)) + + select { + case <-changes: + default: + assert.Fail(t, "marking a peer quantum resistant must notify status subscribers") + } +}