Skip to content

Migrate to profile ids#189

Open
theodorsm wants to merge 3 commits into
mainfrom
profile-id
Open

Migrate to profile ids#189
theodorsm wants to merge 3 commits into
mainfrom
profile-id

Conversation

@theodorsm
Copy link
Copy Markdown

@theodorsm theodorsm commented Jun 2, 2026

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; profile management and engine interactions use IDs for consistency.
    • Active profile displays correctly in the app menu by name.
  • Bug Fixes

    • Prevents removal of the default profile to avoid accidental loss.
    • Profile add/switch/logout/remove flows updated for more reliable identity handling.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jun 2, 2026

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b8478079-cbbc-47ba-a1f0-543315e5e974

📥 Commits

Reviewing files that changed from the base of the PR and between fb47701 and 32150dc.

📒 Files selected for processing (1)
  • netbird

📝 Walkthrough

Walkthrough

Refactors profile identity from using names to using immutable IDs: Profile gains an id field; ProfileManagerWrapper and UI (ProfilesFragment, MainActivity) now use Profile objects and pass profile IDs to gomobile calls; EngineRunner updated accordingly; netbird submodule pointer bumped.

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 gains an id field; constructor signature changes to (id, name, isActive); getID() accessor added; toString(), equals(), and hashCode() use id.
ProfileManagerWrapper service layer
tool/src/main/java/io/netbird/client/tool/ProfileManagerWrapper.java
listProfiles() builds Profile with gomobile IDs; getActiveProfile() returns a Profile; switchProfile(), logoutProfile(), and removeProfile() accept profile id and invoke gomobile calls using IDs; engine stop/logout logic compares IDs.
ProfilesFragment profile operations
app/src/main/java/io/netbird/client/ui/profile/ProfilesFragment.java
Add-profile confirm handler no longer sanitizes/validates before add; switchProfile(), logoutProfile(), and removeProfile() now call wrapper with profile.getID(); default-profile removal guard checks profile.getID().equals("default"); addProfile error handling null-check adjusted for "already exists" detection.
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 imports Profile and updates updateProfileMenuItem() to read activeProfile.getName() from returned Profile; EngineRunner changes local active-profile variable type from String to Profile during engine initialization/logging.
Submodule version update
netbird
netbird git submodule reference updated to a new commit.

Sequence Diagram

sequenceDiagram
  participant UI as ProfilesFragment
  participant Wrapper as ProfileManagerWrapper
  participant Backend as gomobile ProfileManager
  UI->>Wrapper: switchProfile(profile.getID())
  Wrapper->>Wrapper: stop VPN engine (if active)
  Wrapper->>Backend: switchProfile(id)
  Backend-->>Wrapper: success/failure
  Wrapper-->>UI: callback/result
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • pappz
  • doromaraujo

"I hopped from name to id with glee,
Profiles now carry identity.
Wrapper, UI, engine in line,
Submodule bumped — all looks fine. 🥕🐇"

🚥 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 'Migrate to profile ids' accurately describes the main objective of the pull request, which is to update the Android client to use profile IDs instead of profile names throughout the codebase.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 and usage tips.

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 (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
Comment on lines +52 to 59
public Profile getActiveProfile() {
try {
return profileManager.getActiveProfile();
io.netbird.gomobile.android.Profile p = profileManager.getActiveProfile();
return new Profile(p.getID(), p.getName(), true);
} catch (Exception e) {
Log.e(TAG, "Failed to get active profile", e);
return "default";
return new Profile("default", "default", true);
}
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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Don’t fabricate "default" when active-profile lookup fails.

This turns a real lookup failure into a false active profile. logoutProfile() then compares against the wrong ID and can skip stopEngine() for the actual active profile.

Suggested fix
     public Profile getActiveProfile() {
         try {
             io.netbird.gomobile.android.Profile p = profileManager.getActiveProfile();
-            return new Profile(p.getID(), p.getName(), true);
+            if (p == null) {
+                throw new IllegalStateException("Active profile is unavailable");
+            }
+            return new Profile(p.getID(), p.getName(), p.getIsActive());
         } catch (Exception e) {
             Log.e(TAG, "Failed to get active profile", e);
-            return new Profile("default", "default", true);
+            throw new IllegalStateException("Failed to get active profile", e);
         }
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public Profile getActiveProfile() {
try {
return profileManager.getActiveProfile();
io.netbird.gomobile.android.Profile p = profileManager.getActiveProfile();
return new Profile(p.getID(), p.getName(), true);
} catch (Exception e) {
Log.e(TAG, "Failed to get active profile", e);
return "default";
return new Profile("default", "default", true);
}
public Profile getActiveProfile() {
try {
io.netbird.gomobile.android.Profile p = profileManager.getActiveProfile();
if (p == null) {
throw new IllegalStateException("Active profile is unavailable");
}
return new Profile(p.getID(), p.getName(), p.getIsActive());
} catch (Exception e) {
Log.e(TAG, "Failed to get active profile", e);
throw new IllegalStateException("Failed to get active profile", e);
}
}
🤖 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 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.

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.

1 participant