Skip to content

[management] apply login filter only for setup key peers#4943

Merged
pascal-fischer merged 5 commits intomainfrom
feature/limit-login-filter-to-setup-key-peers
Dec 30, 2025
Merged

[management] apply login filter only for setup key peers#4943
pascal-fischer merged 5 commits intomainfrom
feature/limit-login-filter-to-setup-key-peers

Conversation

@pascal-fischer
Copy link
Copy Markdown
Collaborator

@pascal-fischer pascal-fischer commented Dec 12, 2025

Describe your changes

Issue ticket number and link

Stack

Checklist

  • Is it a bug fix
  • Is a typo/documentation fix
  • Is a feature enhancement
  • It is a refactor
  • Created tests that fail without the change (if possible)

By submitting this pull request, you confirm that you have read and agree to the terms of the Contributor License Agreement.

Documentation

Select exactly one:

  • I added/updated documentation for this change
  • Documentation is not needed for this change (explain why)

Docs PR URL (required if "docs added" is checked)

Paste the PR link from https://github.com/netbirdio/docs here:

https://github.com/netbirdio/docs/pull/__

Summary by CodeRabbit

  • New Features

    • Added user lookup by peer key across account management to map peer keys to user IDs.
  • Bug Fixes

    • Updated sync gating so operations block when no user ID is found and ensure semaphores are released on the new error path.
  • Tests

    • Added tests for peer-key-to-user-ID lookup: success, not-found, and empty-user-ID cases.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Dec 12, 2025

Warning

Rate limit exceeded

@pascal-fischer has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 9 minutes and 23 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 9c0a526 and 2a8c845.

📒 Files selected for processing (2)
  • management/server/mock_server/account_mock.go (2 hunks)
  • management/server/store/sql_store_test.go (1 hunks)

Walkthrough

Adds Store and Manager APIs to map a peer key to a user ID, implements the lookup in the SQL store, exposes it via DefaultAccountManager, integrates the lookup into the gRPC Sync path (adjusting login gating and semaphore handling), and adds unit tests for the SQL lookup.

Changes

Cohort / File(s) Summary
Store interface & SQL implementation
management/server/store/store.go, management/server/store/sql_store.go
New GetUserIDByPeerKey(ctx, lockStrength, peerKey) (string, error) on the Store interface and SqlStore; queries nbpeer.Peer for user_id with optional locking and returns query errors (does not special-case not-found vs other errors).
Account manager
management/server/account/manager.go, management/server/account.go
Added GetUserIDByPeerKey(ctx, peerKey) (string, error) to the Manager interface and implemented DefaultAccountManager.GetUserIDByPeerKey delegating to the Store with LockingStrengthNone.
gRPC server Sync integration
management/internals/shared/grpc/server.go
Sync now calls GetUserIDByPeerKey; on lookup error it decrements the sync semaphore and returns a mapped error. Login gating changed to block only when userID is empty AND loginFilter denies; otherwise proceed.
Tests
management/server/store/sql_store_test.go
Added tests for successful lookup, not-found case, and peer with empty userID. The same test set appears duplicated within the test file.

Sequence Diagram

sequenceDiagram
    participant Client
    participant GRPC as gRPC Server (Sync)
    participant Acct as Account Manager
    participant Store as SQL Store
    participant DB as Database

    Client->>GRPC: Sync Request (includes peerKey)
    activate GRPC

    GRPC->>Acct: GetUserIDByPeerKey(ctx, peerKey)
    activate Acct

    Acct->>Store: GetUserIDByPeerKey(ctx, LockingStrengthNone, peerKey)
    activate Store

    Store->>DB: SELECT user_id FROM nbpeer.Peer WHERE key = ?
    activate DB
    DB-->>Store: row (user_id) / no row / error
    deactivate DB

    alt query success (row)
        Store-->>Acct: userID (may be empty)
    else query error / no row
        Store-->>Acct: error
    end
    deactivate Store

    Acct-->>GRPC: userID or error
    deactivate Acct

    alt error returned
        GRPC->>GRPC: decrement sync semaphore
        GRPC-->>Client: mapped error
    else userID non-empty OR loginFilter allows
        GRPC->>GRPC: continue Sync processing
        GRPC-->>Client: Sync response
    else userID empty AND loginFilter denies
        GRPC->>GRPC: decrement sync semaphore
        GRPC-->>Client: mapped error
    end
    deactivate GRPC
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • attention areas:
    • gRPC Sync gating: correctness of the new conditional (userID empty vs loginFilter) and semaphore decrement on all error paths
    • SQL lookup: behavior for not-found vs error and use of locking
    • Tests: duplication within sql_store_test.go and whether assertions match intended store behavior

Poem

🐇 I hopped through rows and keys so bright,
I fetched a user by moonlit byte,
If empty eyes should block the way,
I nudged the semaphore and let it stay —
A tiny hop to make Sync right. 🥕

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description is largely a template with minimal substantive content filled in, lacks specific details about changes, unchecked all checklist items despite visible implementation, and provides no explanation for 'documentation not needed' claim. Fill in the 'Describe your changes' section with a clear summary of the implementation, check appropriate checklist items (likely 'feature enhancement' or 'refactor'), and explain why documentation is not needed.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title 'apply login filter only for setup key peers' directly aligns with the main change in the changeset, which modifies the gating logic to bypass the login filter only when a non-empty userID is present for setup key peers.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

# Conflicts:
#	management/server/store/sql_store_test.go
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
management/internals/shared/grpc/server.go (1)

187-205: Potential behavior change: unregistered peers may now return NotFound instead of PermissionDenied.
Because GetUserIDByPeerKey is called before GetAccountIDForPeerKey, a missing peer key can short-circuit the old “peer is not registered” handling. Consider treating “not found” from GetUserIDByPeerKey as userID == "" and continue.

- userID, err := s.accountManager.GetUserIDByPeerKey(ctx, peerKey.String())
- if err != nil {
-     s.syncSem.Add(-1)
-     return mapError(ctx, err)
- }
+ userID, err := s.accountManager.GetUserIDByPeerKey(ctx, peerKey.String())
+ if err != nil {
+     if st, ok := internalStatus.FromError(err); ok && st.Type() == internalStatus.NotFound {
+         userID = ""
+     } else {
+         s.syncSem.Add(-1)
+         return mapError(ctx, err)
+     }
+ }
management/server/account/manager.go (1)

26-127: MockAccountManager is missing multiple interface method implementations, including GetUserIDByPeerKey.

The MockAccountManager in management/server/mock_server/account_mock.go is missing 9 interface methods required by account.Manager:

  • GetUserIDByPeerKey
  • CreateGroup
  • CreateGroups
  • UpdateGroup
  • UpdateGroups
  • GetAccountIDByUserID
  • GetValidatedPeers
  • OnPeerDisconnected
  • SyncUserJWTGroups

Add the corresponding Func fields to the mock struct and implement the necessary method receivers to restore compilation.

🧹 Nitpick comments (2)
management/server/account.go (1)

2149-2151: Consider guarding against empty peerKey to avoid ambiguous NotFound behavior.
Right now this blindly forwards to the store; an early InvalidArgument (or at least a fast-path "") can make upstream error handling more deterministic.

management/internals/shared/grpc/server.go (1)

194-246: If the goal is “login filter only for setup-key peers”, also gate loginFilter.addLogin(...) behind userID == "".
Right now you bypass allowLogin for user peers, but you still record them in the filter, which is inconsistent with the stated intent and may grow the in-memory filter unnecessarily.

- metahash := metaHash(peerMeta, realIP.String())
- s.loginFilter.addLogin(peerKey.String(), metahash)
+ if userID == "" {
+     metahash := metaHash(peerMeta, realIP.String())
+     s.loginFilter.addLogin(peerKey.String(), metahash)
+ }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 932c02e and cc2917d.

📒 Files selected for processing (6)
  • management/internals/shared/grpc/server.go (1 hunks)
  • management/server/account.go (1 hunks)
  • management/server/account/manager.go (1 hunks)
  • management/server/store/sql_store.go (1 hunks)
  • management/server/store/sql_store_test.go (1 hunks)
  • management/server/store/store.go (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
management/server/store/sql_store.go (3)
management/server/store/store.go (2)
  • LockingStrength (40-40)
  • LockingStrengthNone (47-47)
management/server/peer/peer.go (1)
  • Peer (16-58)
shared/management/status/error.go (3)
  • Error (54-57)
  • Errorf (70-75)
  • NewPeerNotFoundError (90-92)
🔇 Additional comments (1)
management/server/store/store.go (1)

50-207: Store interface change correctly implements GetUserIDByPeerKey in SqlStore.

FileStore is not a Store implementation—it's legacy migration code used only in MigrateFileStoreToSqlite(). The only active Store implementation is SqlStore, which already includes the GetUserIDByPeerKey method (line 4079). No compilation errors or breaking changes to other store backends will occur.

Comment thread management/server/store/sql_store_test.go
Comment thread management/server/store/sql_store.go
@sonarqubecloud
Copy link
Copy Markdown

@pascal-fischer pascal-fischer merged commit 1d2c777 into main Dec 30, 2025
39 checks passed
@pascal-fischer pascal-fischer deleted the feature/limit-login-filter-to-setup-key-peers branch December 30, 2025 09:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants