Skip to content

Migrate to profile ids - #189

Merged
pappz merged 7 commits into
mainfrom
profile-id
Jul 2, 2026
Merged

Migrate to profile ids#189
pappz merged 7 commits into
mainfrom
profile-id

Conversation

@theodorsm

@theodorsm theodorsm commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

This PR uses the new profile ids implemented in netbirdio/netbird#6326

The go bindings are updated to use the new profile with the id field. Sanitation is removed, as this is done by the go profilemanager.

image image

Summary by CodeRabbit

  • Improvements
    • Profiles now have unique, immutable IDs, and profile-related actions (add/switch/logout/remove) consistently use those IDs.
    • The active profile displayed in the app menu remains accurate using the profile’s name.
  • Bug Fixes
    • Prevents removal of the default profile.
    • More reliable add/switch/logout/remove flows with safer validation and clearer error handling when the active profile can’t be retrieved.

@coderabbitai

coderabbitai Bot commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • ✅ Review completed - (🔄 Check again to review again)
📝 Walkthrough

Walkthrough

Profile handling now uses immutable profile IDs across the model, wrapper, UI, and engine entry points. The netbird submodule pointer also moved to a new commit.

Changes

Profile Identity Refactoring

Layer / File(s) Summary
Profile model contract with ID field
tool/src/main/java/io/netbird/client/tool/Profile.java
Profile adds id, requires it in the constructor, exposes getID(), and uses id for equality, hashing, and string output.
ProfileManagerWrapper API and behavior
tool/src/main/java/io/netbird/client/tool/ProfileManagerWrapper.java
Wrapper methods now work with profile IDs, return a Profile from getActiveProfile(), and update engine-stop handling around switch/logout/remove flows.
ProfilesFragment profile operations
app/src/main/java/io/netbird/client/ui/profile/ProfilesFragment.java
Profile actions now pass profile.getID() through to the wrapper, the default-profile guard checks the ID, add-profile confirmation no longer sanitizes first, and the existing-profile error path changes.
MainActivity and EngineRunner consume Profile objects
app/src/main/java/io/netbird/client/MainActivity.java, tool/src/main/java/io/netbird/client/tool/EngineRunner.java
MainActivity and EngineRunner now treat the active profile as a Profile object instead of a string.
Submodule pointer update
netbird
The checked-in netbird submodule reference was updated.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ProfilesFragment
  participant ProfileManagerWrapper
  participant GomobileProfileManager
  ProfilesFragment->>ProfileManagerWrapper: switchProfile(profile.getID())
  ProfileManagerWrapper->>ProfileManagerWrapper: stop VPN engine when needed
  ProfileManagerWrapper->>GomobileProfileManager: switchProfile(id)
  GomobileProfileManager-->>ProfileManagerWrapper: result
  ProfileManagerWrapper-->>ProfilesFragment: callback
Loading

Possibly related PRs

Suggested reviewers: pappz, doromaraujo

Poem

A bunny hopped through name and id,
And tucked each profile where it fit.
The wrapper switched, the UI spun,
The engine smiled, the log was done. 🐇

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: switching profile handling to use IDs instead of names.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch profile-id

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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 (1)
app/src/main/java/io/netbird/client/ui/profile/ProfilesFragment.java (1)

183-188: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Always surface add-profile failures to the user.

When e.getMessage() is null, this path only logs. Since the dialog callback still returns true, the dialog closes with no feedback.

Suggested fix
             Log.e(TAG, "Failed to add profile", e);
             String errorMsg = e.getMessage();
-            if (errorMsg != null) {
-                Toast.makeText(requireContext(),
-                        "Failed to add profile: " + e.getMessage(),
-                        Toast.LENGTH_SHORT).show();
-            }
+            Toast.makeText(
+                    requireContext(),
+                    errorMsg == null ? "Failed to add profile" : "Failed to add profile: " + errorMsg,
+                    Toast.LENGTH_SHORT
+            ).show();
         }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/src/main/java/io/netbird/client/ui/profile/ProfilesFragment.java` around
lines 183 - 188, In ProfilesFragment (the add-profile error handler where
errorMsg = e.getMessage()), always show user feedback even when e.getMessage()
is null: replace the conditional that only Toasts when errorMsg != null with
logic that computes a safe message (use e.getMessage() if non-null, otherwise
e.toString() or a generic "Failed to add profile" string) and call
Toast.makeText(requireContext(), safeMessage, Toast.LENGTH_SHORT).show(); keep
the rest of the dialog callback behavior unchanged so the dialog still returns
true.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tool/src/main/java/io/netbird/client/tool/Profile.java`:
- Around line 10-15: Constructor Profile(String id, String name, boolean
isActive) currently allows a null id which breaks equals(), hashCode(), and
callers like ProfilesFragment.removeProfile(); validate the id parameter and
throw an IllegalArgumentException if id is null or empty, similarly to the
existing name check. Update the Profile constructor (Profile(String id, String
name, boolean isActive)) to perform the id null/empty check and document that id
is required so equals() and hashCode() can safely assume a non-null id (this
will prevent issues in ProfilesFragment.removeProfile() and calls like
profile.getID().equals(...)).

In `@tool/src/main/java/io/netbird/client/tool/ProfileManagerWrapper.java`:
- Around line 52-59: Do not return a fabricated Profile when
profileManager.getActiveProfile() fails; in getActiveProfile()
(ProfileManagerWrapper.getActiveProfile) remove the fallback new
Profile("default",...) and either return null or rethrow the exception so
callers can detect a real failure. Update callers such as logoutProfile() to
handle a null/exceptional result (check for null before comparing IDs and ensure
stopEngine() is invoked for the actual active profile) so failures don't
masquerade as a valid "default" profile.

---

Outside diff comments:
In `@app/src/main/java/io/netbird/client/ui/profile/ProfilesFragment.java`:
- Around line 183-188: In ProfilesFragment (the add-profile error handler where
errorMsg = e.getMessage()), always show user feedback even when e.getMessage()
is null: replace the conditional that only Toasts when errorMsg != null with
logic that computes a safe message (use e.getMessage() if non-null, otherwise
e.toString() or a generic "Failed to add profile" string) and call
Toast.makeText(requireContext(), safeMessage, Toast.LENGTH_SHORT).show(); keep
the rest of the dialog callback behavior unchanged so the dialog still returns
true.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5e4c18d5-613b-470a-bbf1-e9e6ae944678

📥 Commits

Reviewing files that changed from the base of the PR and between 0e81e82 and 4b25d2c.

📒 Files selected for processing (6)
  • app/src/main/java/io/netbird/client/MainActivity.java
  • app/src/main/java/io/netbird/client/ui/profile/ProfilesFragment.java
  • netbird
  • tool/src/main/java/io/netbird/client/tool/EngineRunner.java
  • tool/src/main/java/io/netbird/client/tool/Profile.java
  • tool/src/main/java/io/netbird/client/tool/ProfileManagerWrapper.java

Comment thread tool/src/main/java/io/netbird/client/tool/Profile.java

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
tool/src/main/java/io/netbird/client/tool/ProfileManagerWrapper.java (1)

94-107: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

logoutProfile now aborts for unrelated profiles when active-profile lookup fails.

getActiveProfile() (Lines 52-63) was just changed to throw IllegalStateException instead of returning a "default" fallback. logoutProfile() calls it unguarded at Line 100, so any active-profile lookup failure now propagates and blocks logout of any profile id, even ones unrelated to the active profile — a regression from the previous fallback behavior. This is exactly the caller-update the prior review comment called out but wasn't applied here.

Also, validation at Line 95 only checks id == null, unlike switchProfile/removeProfile which also reject blank/whitespace ids.

🔧 Proposed fix
     public void logoutProfile(String id) throws Exception {
-        if (id == null) {
-            throw new IllegalArgumentException("Profile name cannot be empty");
+        if (id == null || id.trim().isEmpty()) {
+            throw new IllegalArgumentException("Profile id cannot be empty");
         }
 
         // Check if logging out from active profile
-        Profile activeProfile = getActiveProfile();
-        if (activeProfile.getID().equals(id)) {
-            // Stop VPN service if logging out from active profile
-            stopEngine();
+        try {
+            Profile activeProfile = getActiveProfile();
+            if (activeProfile.getID().equals(id)) {
+                // Stop VPN service if logging out from active profile
+                stopEngine();
+            }
+        } catch (Exception e) {
+            Log.w(TAG, "Could not determine active profile before logout, proceeding without engine stop check", e);
         }
 
         profileManager.logoutProfile(id);
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tool/src/main/java/io/netbird/client/tool/ProfileManagerWrapper.java` around
lines 94 - 107, `logoutProfile` should not let `getActiveProfile()` failures
block logging out unrelated profiles, and its id validation should also reject
blank or whitespace-only input. Update `ProfileManagerWrapper.logoutProfile` so
it only calls `stopEngine()` when an active profile is successfully available
and matches the target id, while allowing logout to continue otherwise; also
align the `id` check with `switchProfile` and `removeProfile` by treating
empty/blank ids as invalid.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Duplicate comments:
In `@tool/src/main/java/io/netbird/client/tool/ProfileManagerWrapper.java`:
- Around line 94-107: `logoutProfile` should not let `getActiveProfile()`
failures block logging out unrelated profiles, and its id validation should also
reject blank or whitespace-only input. Update
`ProfileManagerWrapper.logoutProfile` so it only calls `stopEngine()` when an
active profile is successfully available and matches the target id, while
allowing logout to continue otherwise; also align the `id` check with
`switchProfile` and `removeProfile` by treating empty/blank ids as invalid.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e1a1eb62-8531-49fa-8f21-5846245313ae

📥 Commits

Reviewing files that changed from the base of the PR and between 6d6062b and 7975ae3.

📒 Files selected for processing (2)
  • netbird
  • tool/src/main/java/io/netbird/client/tool/ProfileManagerWrapper.java

@pappz
pappz merged commit dc40e04 into main Jul 2, 2026
7 checks passed
@pappz
pappz deleted the profile-id branch July 2, 2026 09:20
pappz added a commit that referenced this pull request Jul 3, 2026
Squash-merge the four commits from PR #189 (profile-id branch) onto the
redesign branch, adapting the profile-id migration to the new bottom-nav
UI instead of the old drawer/NavigationView layout:

- getActiveProfile() now returns a Profile (with ID) instead of a String;
  update SettingsFragment and HomeFragment callers to use getName().
- Drop the PR's drawer-specific MainActivity changes (updateProfileMenuItem,
  drawer onKeyDown) — the redesign replaced the drawer with bottom nav.
- Graft the new disable-IPv6 switch listener into AdvancedFragment and add
  the IPv6 settings row to fragment_advanced.xml in the redesign row style.
- Bump netbird submodule to 62afff6 (adds Profile.ID to the gomobile binding).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
pappz added a commit that referenced this pull request Jul 27, 2026
Squash-merge the four commits from PR #189 (profile-id branch) onto the
redesign branch, adapting the profile-id migration to the new bottom-nav
UI instead of the old drawer/NavigationView layout:

- getActiveProfile() now returns a Profile (with ID) instead of a String;
  update SettingsFragment and HomeFragment callers to use getName().
- Drop the PR's drawer-specific MainActivity changes (updateProfileMenuItem,
  drawer onKeyDown) — the redesign replaced the drawer with bottom nav.
- Graft the new disable-IPv6 switch listener into AdvancedFragment and add
  the IPv6 settings row to fragment_advanced.xml in the redesign row style.
- Bump netbird submodule to 62afff6 (adds Profile.ID to the gomobile binding).
pappz pushed a commit that referenced this pull request Jul 27, 2026
* Add profile id migration

* Check if ID is set on Profile

* Bump netbird

* Update profile-id-name branch

* Fix active profile errors, bump netbird

* Bump netbird to v0.74.0
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