Skip to content

E2e tests - #229

Merged
pappz merged 11 commits into
ux/ios-style-redesignfrom
test/e2e-tests-new-design
Aug 10, 2026
Merged

E2e tests#229
pappz merged 11 commits into
ux/ios-style-redesignfrom
test/e2e-tests-new-design

Conversation

@pappz

@pappz pappz commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator

Summary by CodeRabbit

  • Tests

    • Added comprehensive Android end-to-end coverage for setup-key login, peer connectivity, DNS resolution, exit-node routing, port access controls, and VPN behavior.
    • Added clearer failure handling, diagnostic screenshots, retries, cleanup, and shared test automation.
    • Updated debug test runs to exclude private-account and long-running stress scenarios.
  • Chores

    • Improved Android build caching and environment setup for faster, more reliable builds.
    • Updated the bundled networking component reference.

pappz added 7 commits August 4, 2026 23:02
The iOS-style redesign folded the old add-profile / switch / change-server
flow into a single profile editor dialog, so LoginFlow now drives that:
name + setup key in one submit, with the key field revealed via its
row-owned switch. Enrolment success is verified positively — the profile
must appear in the list — since the dialog also dismisses on paths that
never registered the peer. Creating a profile does not activate it, so the
flow switches to it explicitly before connecting.

All navigation now goes through taps (bottom nav and settings rows) rather
than NavController, keeping the app in the state a user would produce.

The force-relay setup step was flaky because scrollForward() flings and a
tap injected while the list is still settling is consumed as a scroll-stop.
Scroll, settle, click and verify now retry as one unit.

Also: EditText writes are read back (soft-keyboard layout shifts silently
swallowed setText), autofilled setup-key fields are cleared first,
screenshots moved to the app's external files dir (scoped storage made
/sdcard/Pictures fail with EACCES), and the first-run screen is dismissed
before the suite starts since it shares view ids with the profile editor.

VpnTestHarness listens through StateListenerAdapter so the interface can
grow without breaking the suite.
Brings in #7022, which stops NewAuth from rebuilding the config from
scratch on setup-key enrolment — previously that dropped every stored
field, blanking the profile's display name and regenerating the WireGuard
identity. The e2e suite's positive login check depends on it.
connectAndAwait started the engine through MainActivity.switchConnection()
and waited on a StateListener — a code path no user takes. Tap the Home
screen's connect toggle instead and wait for the on-screen status text to
read Connected, so both the trigger and the feedback are the exact UI a
user sees. The suite runs on an English locale, so the literal status text
is matched.
A reachability failure only reported that the peer never answered; the
evidence — did the name resolve, to what address, or did the reply just
not come back — was discarded. Log the complete ping output (and the
resolve probe's) so the CI logcat artifact shows exactly which of those
it was.
The CI artifact showed every failing ping with empty stdout — resolution
errors go to stderr, which executeShellCommand does not capture — and the
tunnel's DNS trail shows only search-domain expansions being queried, never
the bare peer name. What is still missing is the resolver's actual error
and whether the app's own resolver (guaranteed to route through the VPN,
unlike the shell-uid ping) agrees. Log InetAddress.getByName() for the
target on every failed attempt so the next run's artifact answers both.
Three CI runs put the evidence together: the tunnel comes up fast, but its
data plane does not. The relay-backed peer resolves and answers 8-12s after
Connected (attempt 1 fails, attempt 3 pings), and the exit-node profile
SERVFAILs upstream DNS until the exit-node path is ready — every failure
was one of these still settling when the 20s window closed, with a
different test tripping first each run. The Robot suite allows ~3 minutes
for the same sequence; 90s on the ping/resolve/port/egress windows keeps
failures reasonably fast while clearing the observed settling time with
margin. Connect stays at 20s — the UI reports Connected within seconds.
The android/gui-integration work is squash-merged into main — the only code
difference left was main's relay reconnect backoff randomization (#7067),
which the branch did not have.
@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 53d442e4-4dad-41e8-8ce6-6232290b711e

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The pull request adds Android end-to-end test infrastructure and coverage for authentication, peer connectivity, DNS, exit-node routing, and ACL behavior. It also updates Android build caching, excludes e2e tests from the debug workflow, and advances the netbird submodule.

Changes

Android end-to-end testing

Layer / File(s) Summary
Test runtime foundation
app/src/androidTest/java/io/netbird/client/e2e/E2eAppRule.java, app/src/androidTest/java/io/netbird/client/e2e/FailFast.java
Adds shared activity startup and reuse. Subsequent tests are skipped after the first failure.
Shared profile and VPN flows
app/src/androidTest/java/io/netbird/client/e2e/LoginFlow.java, app/src/androidTest/java/io/netbird/client/e2e/VpnTestHarness.java
Adds UI-driven profile enrollment, cleanup, force-relay configuration, VPN control, network checks, retries, and screenshots.
Suite registration and connectivity scenarios
app/src/androidTest/java/io/netbird/client/e2e/E2eSuite.java, app/src/androidTest/java/io/netbird/client/e2e/SetupKeyAuthTest.java, app/src/androidTest/java/io/netbird/client/e2e/PeerConnectivityTest.java, app/src/androidTest/java/io/netbird/client/e2e/DnsResolutionTest.java
Registers the e2e suite and adds setup-key, relay, non-relay, and DNS tests.
Route and ACL scenarios
app/src/androidTest/java/io/netbird/client/e2e/ExitNodeRouteTest.java, app/src/androidTest/java/io/netbird/client/e2e/PortAclTest.java
Adds exit-node public-egress validation and TCP/ICMP ACL validation.

Build and test pipeline

Layer / File(s) Summary
Android toolchain caching
.github/actions/build-android/action.yml
Uses Temurin and caches Go modules, the Android NDK, and the pinned gomobile binary.
Workflow and source revision updates
.github/workflows/build-debug.yml, netbird
Excludes the e2e package from the debug instrumentation command and updates the netbird submodule reference.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant E2ETest
  participant LoginFlow
  participant VpnTestHarness
  participant AndroidApp
  participant NetworkTarget
  E2ETest->>LoginFlow: create profile with setup key
  LoginFlow->>AndroidApp: enroll and select profile
  E2ETest->>VpnTestHarness: request VPN connection
  VpnTestHarness->>AndroidApp: grant consent and connect
  AndroidApp-->>VpnTestHarness: report Connected state
  VpnTestHarness->>NetworkTarget: run DNS, ping, TCP, or HTTPS check
  NetworkTarget-->>E2ETest: return validation result
Loading

Possibly related PRs

Poem

A rabbit hops through tunnels bright,
With setup keys tucked out of sight.
DNS and routes now pass the test,
Cached builds make the pipeline rest.
“Squeak!” says the hare—“The suite is right!”

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 63.64% 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 identifies the primary change: adding Android end-to-end tests and supporting test infrastructure.
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 💡 2
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
⚔️ Resolve merge conflicts 💡
  • Resolve merge conflict in branch test/e2e-tests-new-design
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch test/e2e-tests-new-design

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.

pappz added 2 commits August 5, 2026 18:02
The CI script passes both keys as -P instrumentation arguments, so reading
them from the environment never took effect.
setup-java fails to resolve the 'adopt' distribution — AdoptOpenJDK was
renamed to Eclipse Temurin and the old endpoints are going away — so the
build died before installing a JDK. Same JDK, current name.
The e2e tests need a setup key for a live account, held only by the private
mobile-e2e repo, so every one of them failed here with "setupKey
instrumentation argument is required". They are meant to run from that
repo's workflow, not on every push.

@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: 9

🧹 Nitpick comments (3)
app/src/androidTest/java/io/netbird/client/e2e/VpnTestHarness.java (1)

282-298: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Capture stderr in shell so ping failures log diagnostics.

UiAutomation.executeShellCommand(command) returns only stdout. pingOnce and resolve log shell() output for failures, but host-resolution errors can be emitted to stderr, leaving the artifact empty. Redirect stderr into stdout in the command, or use the stderr-returning command variant if available.

♻️ Proposed change to capture stderr
     String shell(String command) {
         try {
-            ParcelFileDescriptor pfd = uiAutomation.executeShellCommand(command);
+            ParcelFileDescriptor pfd = uiAutomation.executeShellCommand(command + " 2>&1");
🤖 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/androidTest/java/io/netbird/client/e2e/VpnTestHarness.java` around
lines 282 - 298, Update VpnTestHarness.shell to capture stderr along with stdout
when executing commands, such as by redirecting stderr into stdout before
calling uiAutomation.executeShellCommand. Preserve the existing output-reading,
failure logging, and empty-string fallback behavior.
app/src/androidTest/java/io/netbird/client/e2e/FailFast.java (1)

3-17: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use the public RunListener base class.

FailFast does not use any AndroidX Test instrumentation-specific feature, but it lives in androidx.test.internal.runner.listener.InstrumentationRunListener, which is non-public API. Use org.junit.runner.notification.RunListener instead so the listener remains compatible with standard AndroidJUnitRunner listener registration and is not tied to an internal API.

🤖 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/androidTest/java/io/netbird/client/e2e/FailFast.java` around lines 3
- 17, Update FailFast to extend the public
org.junit.runner.notification.RunListener instead of the internal
InstrumentationRunListener, and replace the internal import accordingly.
Preserve the existing failure tracking and skipIfAborted behavior.
.github/actions/build-android/action.yml (1)

47-47: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Move the toolchain actions to Node 24-based majors.

This composite action still pins actions/setup-java@v4, actions/setup-go@v5, and both actions/cache@v4 steps to Node 20. Migrate to actions/setup-java@v5, actions/setup-go@v6, and actions/cache@v5, and check any self-hosted runners are at runner version 2.327.1 or later.

Suggested version changes
-      uses: actions/setup-java@v4
+      uses: actions/setup-java@v5

-      uses: actions/setup-go@v5
+      uses: actions/setup-go@v6

-      uses: actions/cache@v4
+      uses: actions/cache@v5

Also applies to: .github/workflows/build-debug.yml, lines 14, 55, 63, and 90.

🤖 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 @.github/actions/build-android/action.yml at line 47, Update the toolchain
action references in the build-android composite action and the corresponding
build-debug workflow to actions/setup-java@v5, actions/setup-go@v6, and every
actions/cache@v5 usage. Verify any self-hosted runner configuration uses runner
version 2.327.1 or newer.
🤖 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 @.github/actions/build-android/action.yml:
- Around line 45-46: Update the comment near the Java distribution configuration
to remove the incorrect claim that the legacy “adopt” alias fails outright. Keep
“temurin” unchanged and explain that AdoptOpenJDK moved to Eclipse Temurin and
no longer receives updates.

In `@app/src/androidTest/java/io/netbird/client/e2e/DnsResolutionTest.java`:
- Around line 25-35: Update the class Javadoc in DnsResolutionTest to describe
resolution through VpnTestHarness.resolve using the device’s ping command, not
nslookup. Replace the nslookup-specific wording and examples while preserving
the documented FQDN and search-domain resolution assertions.

In `@app/src/androidTest/java/io/netbird/client/e2e/E2eSuite.java`:
- Around line 23-41: Remove the suite-level force-relay setup from E2eSuite,
including its disableForceRelay() method and any now-unused imports. Ensure each
e2e test class retains its own shared, idempotent `@BeforeClass` setup so direct
execution disables force relay before tests run.

In `@app/src/androidTest/java/io/netbird/client/e2e/ExitNodeRouteTest.java`:
- Around line 38-39: Update ExitNodeRouteTest setup and the related lines around
the exitNodeSetupKey validation to use a test assumption that skips when the
optional key is missing, rather than assertNotNull or FailFast.testFailure.
Preserve the documented behavior so only this test is skipped and other E2eSuite
scenarios continue running.

In `@app/src/androidTest/java/io/netbird/client/e2e/FailFast.java`:
- Around line 19-31: Update the instrumentation test runner configuration to
register io.netbird.client.e2e.FailFast as the listener runner argument,
ensuring its testFailure method is invoked and skipIfAborted() can stop
subsequent tests after the first failure.

In `@app/src/androidTest/java/io/netbird/client/e2e/LoginFlow.java`:
- Around line 231-248: Update the retry path in openProfileEditor to use a
tolerant boolean-returning navigation helper instead of openProfiles, whose
tapTab/tapSettingsRow calls fail immediately. Add tryOpenProfiles (and any
needed tolerant tab/row navigation) to return false when navigation elements are
unavailable, allowing subsequent attempts; retain the final dumpScreenshot and
fail only after all three attempts fail.

In `@app/src/androidTest/java/io/netbird/client/e2e/PeerConnectivityTest.java`:
- Around line 84-90: Add a shared VpnTestHarness.disconnectAndAwait method that
turns off the connect toggle when needed and waits until text_connection_status
is no longer "Connected". Call it in tearDown before profile removal in
PeerConnectivityTest.java (84-90), DnsResolutionTest.java (80-86),
ExitNodeRouteTest.java (72-78), and PortAclTest.java (86-92), preserving the
existing visualization cleanup and profile removal.

In `@app/src/androidTest/java/io/netbird/client/e2e/SetupKeyAuthTest.java`:
- Around line 45-68: Update LoginFlow.createProfileAndLogin and its callers so
the generated profile name is published to the owning test immediately after
creation, before enrolment or profile-switching steps can fail. In
app/src/androidTest/java/io/netbird/client/e2e/SetupKeyAuthTest.java:45-68, pass
a result holder and retain the early name for tearDown; apply the same mechanism
in connectAndPing at
app/src/androidTest/java/io/netbird/client/e2e/PeerConnectivityTest.java:108-125,
app/src/androidTest/java/io/netbird/client/e2e/DnsResolutionTest.java:103-104,
app/src/androidTest/java/io/netbird/client/e2e/ExitNodeRouteTest.java:96-97, and
app/src/androidTest/java/io/netbird/client/e2e/PortAclTest.java:110-111 so each
cleanup path can remove partially created profiles.

In `@netbird`:
- Line 1: Update the netbird submodule reference to a commit that exists in the
submodule repository, or add the intended missing revision to its remote
history, so update-server.sh can fetch it and the Android AAR build succeeds.

---

Nitpick comments:
In @.github/actions/build-android/action.yml:
- Line 47: Update the toolchain action references in the build-android composite
action and the corresponding build-debug workflow to actions/setup-java@v5,
actions/setup-go@v6, and every actions/cache@v5 usage. Verify any self-hosted
runner configuration uses runner version 2.327.1 or newer.

In `@app/src/androidTest/java/io/netbird/client/e2e/FailFast.java`:
- Around line 3-17: Update FailFast to extend the public
org.junit.runner.notification.RunListener instead of the internal
InstrumentationRunListener, and replace the internal import accordingly.
Preserve the existing failure tracking and skipIfAborted behavior.

In `@app/src/androidTest/java/io/netbird/client/e2e/VpnTestHarness.java`:
- Around line 282-298: Update VpnTestHarness.shell to capture stderr along with
stdout when executing commands, such as by redirecting stderr into stdout before
calling uiAutomation.executeShellCommand. Preserve the existing output-reading,
failure logging, and empty-string fallback behavior.
🪄 Autofix

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 Plus

Run ID: 6447164e-d382-4987-b328-511d5767e45f

📥 Commits

Reviewing files that changed from the base of the PR and between 35cbf37 and 815862b.

📒 Files selected for processing (13)
  • .github/actions/build-android/action.yml
  • .github/workflows/build-debug.yml
  • app/src/androidTest/java/io/netbird/client/e2e/DnsResolutionTest.java
  • app/src/androidTest/java/io/netbird/client/e2e/E2eAppRule.java
  • app/src/androidTest/java/io/netbird/client/e2e/E2eSuite.java
  • app/src/androidTest/java/io/netbird/client/e2e/ExitNodeRouteTest.java
  • app/src/androidTest/java/io/netbird/client/e2e/FailFast.java
  • app/src/androidTest/java/io/netbird/client/e2e/LoginFlow.java
  • app/src/androidTest/java/io/netbird/client/e2e/PeerConnectivityTest.java
  • app/src/androidTest/java/io/netbird/client/e2e/PortAclTest.java
  • app/src/androidTest/java/io/netbird/client/e2e/SetupKeyAuthTest.java
  • app/src/androidTest/java/io/netbird/client/e2e/VpnTestHarness.java
  • netbird

Comment on lines +45 to +46
# AdoptOpenJDK became Eclipse Temurin; resolving "adopt" now fails
# outright, so the build never gets as far as installing a JDK.

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.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== locate action file =="
fd -a 'action\.yml' .github/actions/build-android 2>/dev/null || true

echo "== relevant action.yml lines =="
if [ -f .github/actions/build-android/action.yml ]; then
  nl -ba .github/actions/build-android/action.yml | sed -n '1,90p'
fi

echo "== check local commit/action references to setup-java and distributions if present =="
rg -n "setup-java|distribution:\s*['\"]adopt|java-version|setup-go|actions/cache" .github/workflows .github/actions 2>/dev/null || true

Repository: netbirdio/android-client

Length of output: 319


🌐 Web query:

actions/setup-java v4 distribution adopt alias deprecation removed v6

💡 Result:

In the actions/setup-java GitHub Action, support for legacy AdoptOpenJDK distributions (specifically the adopt and adopt-openj9 aliases) has been deprecated in favor of Eclipse Temurin and Semeru [1]. Key points regarding this deprecation: 1. Removal: Legacy AdoptOpenJDK distributions (referred to as adopt or adopt-openj9) have been removed as primary options [1]. Users are instructed to use temurin instead of adopt or adopt-hotspot, and semeru instead of adopt-openj9 [1]. 2. Deprecation Status: While these legacy aliases were maintained for backward compatibility, they emit warnings and are considered deprecated [1]. 3. Versioning: As of August 2026, actions/setup-java versions v1 through v4 are officially deprecated [1]. The action has moved toward newer major versions, with v5 being a stable release and v6 under development [1]. 4. Action Required: If you are currently using distribution: 'adopt' or 'adopt-hotspot', you should update your workflow files to use distribution: 'temurin' [1][2]. If you are using 'adopt-openj9', you should switch to 'semeru' [1]. Continuing to use the deprecated aliases may lead to workflow failures in future releases as they are phased out [2].

Citations:


🌐 Web query:

GitHub actions/setup-java v4 action.yml distribution include adopt adopt-openj9

💡 Result:

In the GitHub actions/setup-java v4 action, the adopt and adopt-openj9 distribution keywords were historically supported for backward compatibility with the legacy AdoptOpenJDK project [1][2]. However, the AdoptOpenJDK project was discontinued and moved to the Eclipse Foundation as Eclipse Temurin [1][2]. Because AdoptOpenJDK no longer receives security updates or maintenance, it is strongly recommended—and in many configurations, effectively deprecated—to migrate away from these legacy keywords [1][2][3]. The recommended replacements are: * Replace adopt or adopt-hotspot with temurin (Eclipse Temurin) [1][2][3]. * Replace adopt-openj9 with semeru (IBM Semeru Runtime Open Edition) [1][2][3]. While some versions of the v4 action may still technically accept the adopt and adopt-openj9 keywords due to legacy support, they are no longer recommended for use [1][2]. Furthermore, please note that all versions of actions/setup-java from v1 through v4 are now deprecated; it is advised to upgrade your workflows to actions/setup-java@v5 [4][5][3].

Citations:


🌐 Web query:

``

💡 Result:

No web search query provided.


🌐 Web query:

``

💡 Result:

No web search query provided.


🌐 Web query:

actions/setup-java v4 distribution adopt alias deprecation removed v6

💡 Result:

In actions/setup-java, the legacy AdoptOpenJDK distributions (commonly referenced by the adopt or adopt-hotspot distribution aliases) were removed in favor of temurin and semeru [1][2][3]. While these legacy aliases were deprecated and subsequently removed, they were not associated specifically with the release of v6; rather, the action's move to v6 primarily involved an internal migration to ECMAScript Modules (ESM) to support updated dependencies [4][5]. For workflows still using adopt or adopt-hotspot, you must migrate to the following recommended distributions to continue receiving software and security updates [1][6][7]: - Use temurin instead of adopt or adopt-hotspot [1][2][3]. - Use semeru (IBM Semeru Runtime Open Edition) instead of adopt-openj9 [1][2][3]. Note that versions v1 through v4 of the action itself are deprecated, and users are encouraged to upgrade to the latest stable release (v5 or higher) [1][2][3]. Existing workflows using deprecated aliases may continue to function if they have not been fully purged, but relying on removed distributions will cause failures; therefore, updating the distribution parameter in your workflow YAML is necessary [1][7].

Citations:


🌐 Web query:

github actions/setup-java v4 distribution adopt includes adopt-openj9

💡 Result:

Yes, in actions/setup-java version v4, the adopt distribution option historically included support for adopt-openj9 [1][2][3]. Specifically: - The setup-java action provided adopt (or adopt-hotspot) for AdoptOpenJDK Hotspot builds and adopt-openj9 for AdoptOpenJDK OpenJ9 builds [1][4][2]. - These were legacy distributions [5][6]. The AdoptOpenJDK project was discontinued and succeeded by the Eclipse Temurin project [7][3]. - Because AdoptOpenJDK is no longer maintained, it is strongly recommended to migrate away from these legacy options to continue receiving security and software updates [7][1][3]. - The recommended migration path is to use temurin instead of adopt (or adopt-hotspot), and semeru instead of adopt-openj9 (IBM Semeru Runtime Open Edition) [5][6][3]. Note: The actions/setup-java@v4 action (and earlier versions) is deprecated, and users are encouraged to upgrade to the latest stable release [5][6].

Citations:


🏁 Script executed:

#!/bin/sh
set -euo pipefail

echo "== action.yml lines 35-55 =="
awk 'NR>=35 && NR<=55' .github/actions/build-android/action.yml

echo "== exact setup-java action.yml distribution include lines in repo =="
if command -v grep >/dev/null 2>&1; then
  grep -RInE "setup-java|distribution:\s*[\"']?adopt|temurin|adopt-openj9" .github/actions .github/workflows 2>/dev/null || true
fi

Repository: netbirdio/android-client

Length of output: 1270


Correct the adopt failure claim.

actions/setup-java@v4 still supports the legacy adopt alias; it does not fail outright. Keep temurin, but update the comment to explain that AdoptOpenJDK moved to Eclipse Temurin and no longer receives updates.

🤖 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 @.github/actions/build-android/action.yml around lines 45 - 46, Update the
comment near the Java distribution configuration to remove the incorrect claim
that the legacy “adopt” alias fails outright. Keep “temurin” unchanged and
explain that AdoptOpenJDK moved to Eclipse Temurin and no longer receives
updates.

Comment on lines +25 to +35
* original runs {@code dig <name>}; here we run a real {@code nslookup} on the
* device (via the shell, like the ping tests), so it exercises the device
* resolver / VpnService DNS exactly as a user's traffic would.
*
* <p>Mirrors the two original assertions:
* <ul>
* <li>FQDN resolves: {@code nslookup
* ip-172-20-3-158.eu-central-1.compute.internal} → 172.20.3.158;</li>
* <li>search-domain (unqualified) resolves: {@code nslookup ip-172-20-3-158}
* → 172.20.3.158.</li>
* </ul>

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.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

The javadoc describes nslookup, but the test resolves with ping.

VpnTestHarness.resolve runs ping -c 1 -W 2 <host> and parses the resolved address from the first line. Its own javadoc states that nslookup is not present on these devices. Update this class javadoc so the documented mechanism matches the implementation.

🤖 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/androidTest/java/io/netbird/client/e2e/DnsResolutionTest.java` around
lines 25 - 35, Update the class Javadoc in DnsResolutionTest to describe
resolution through VpnTestHarness.resolve using the device’s ping command, not
nslookup. Replace the nslookup-specific wording and examples while preserving
the documented FQDN and search-domain resolution assertions.

Comment on lines +23 to +41
@RunWith(Suite.class)
@Suite.SuiteClasses({
SetupKeyAuthTest.class,
PeerConnectivityTest.class,
PortAclTest.class,
DnsResolutionTest.class,
ExitNodeRouteTest.class,
})
public class E2eSuite {

/**
* Force relay is a global setting that defaults ON and would stop the
* relay-less peer connecting. Turn it off ONCE, before any test runs.
*/
@BeforeClass
public static void disableForceRelay() throws Exception {
UiDevice device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
LoginFlow.setForceRelay(E2eAppRule.activity(), device, false);
}

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.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Check how the e2e instrumentation tests are invoked and filtered.
set -euo pipefail

rg -n -C5 'connectedDebugAndroidTest|connectedAndroidTest|E2eSuite|notPackage|androidTestInstrumentationRunnerArguments|testInstrumentationRunnerArguments' --glob '*.yml' --glob '*.yaml' --glob '*.gradle' --glob '*.gradle.kts' || true

Repository: netbirdio/android-client

Length of output: 162


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== candidate files =="
git ls-files | rg '(^|/)(AndroidManifest\.xml|.*Test\.java|.*Test\.kt|.*Spec\.java|.*Spec\.kt|.*Suite.*\.java|.*Suite.*\.kt|build\.gradle(\.kts)?|gradle\.properties|.*\.yml|.*\.yaml)$' || true

echo
echo "== locate E2e-related files =="
fd -i 'E2e|BuildConfig|Manifest|Test|Suite|CI|Workflow|Gradle' . || true

echo
echo "== Instrumentation references =="
rg -n -C4 'Instrument|notPackage|AndroidJUnit4|PackageLifecycle|android.test|androidTest|E2eSuite|PeerConnectivityTest|SetupKeyAuthTest|PortAclTest|DnsResolutionTest|ExitNodeRouteTest|forceRelay|ForceRelay' . || true

Repository: netbirdio/android-client

Length of output: 50380


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== AndroidManifest =="
cat -n app/src/main/AndroidManifest.xml

echo
echo "== app/build.gradle.kts relevant lines =="
sed -n '1,120p' app/build.gradle.kts | cat -n

echo
echo "== workflows/actions =="
for f in .github/workflows/*.yml .github/workflows/*.yaml .github/actions/*/action.yml; do
  echo "--- $f"
  sed -n '1,220p' "$f" | cat -n
done

echo
echo "== androidTest README =="
cat -n app/src/androidTest/README.md

echo
echo "== PeerConnectivityTest outline/snippet =="
wc -l app/src/androidTest/java/io/netbird/client/e2e/PeerConnectivityTest.java
sed -n '1,180p' app/src/androidTest/java/io/netbird/client/e2e/PeerConnectivityTest.java | cat -n

echo
echo "== shared e2e classes annotations =="
for f in app/src/androidTest/java/io/netbird/client/e2e/*.java; do
  echo "--- $f"
  sed -n '1,55p' "$f" | cat -n
done

echo
echo "== AndroidJUnitFilter references in manifest/build/workflows =="
rg -n 'androidJUnitFilter|filter|runOptions|tools:filter|packageLifecycle|PackageLifecycle|class=|io\.netbird\.client\.e2e' app/src/main/AndroidManifest.xml app/build.gradle.kts .github || true

Repository: netbirdio/android-client

Length of output: 17324


Remove the suite dependency from force-relay setup.

E2eSuite is no longer the CI entry point; public connectedDebugAndroidTest excludes io.netbird.client.e2e. The e2e classes still carry their own local @BeforeClass disableForceRelay() setup, so force relay stays enabled for relay-less peers when these tests are run directly unless E2eSuite is passed. Keep only one shared, idempotent setup in each e2e test class.

🤖 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/androidTest/java/io/netbird/client/e2e/E2eSuite.java` around lines 23
- 41, Remove the suite-level force-relay setup from E2eSuite, including its
disableForceRelay() method and any now-unused imports. Ensure each e2e test
class retains its own shared, idempotent `@BeforeClass` setup so direct execution
disables force relay before tests run.

Comment on lines +38 to +39
* <p>If {@code exitNodeSetupKey} is not provided the test fails fast on its own
* assertion, so the rest of the suite is unaffected.

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.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

A missing exitNodeSetupKey aborts the rest of the suite, contrary to the javadoc.

The javadoc on Line 38 states the rest of the suite is unaffected. assertNotNull produces a test failure, FailFast.testFailure sets aborted, and every other scenario's @Before then throws AssumptionViolatedException. Today the damage is bounded because this class is last in E2eSuite, but any reordering makes one optional argument skip the whole suite.

If the argument is optional, skip the test instead of failing it.

🐛 Proposed fix using an assumption
+import static org.junit.Assume.assumeTrue;
@@
-        assertNotNull("exitNodeSetupKey instrumentation argument is required", setupKey);
-        assertTrue("exitNodeSetupKey must not be blank", !setupKey.trim().isEmpty());
+        assumeTrue("exitNodeSetupKey instrumentation argument is not set — skipping",
+                setupKey != null && !setupKey.trim().isEmpty());

Also applies to: 82-87

🤖 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/androidTest/java/io/netbird/client/e2e/ExitNodeRouteTest.java` around
lines 38 - 39, Update ExitNodeRouteTest setup and the related lines around the
exitNodeSetupKey validation to use a test assumption that skips when the
optional key is missing, rather than assertNotNull or FailFast.testFailure.
Preserve the documented behavior so only this test is skipped and other E2eSuite
scenarios continue running.

Comment on lines +19 to +31
private static volatile boolean aborted = false;

@Override
public void testFailure(Failure failure) {
aborted = true;
}

/** Skip (not fail) the current test if an earlier test already failed. */
static void skipIfAborted() {
if (aborted) {
throw new AssumptionViolatedException("Skipped: a previous test already failed (fail-fast)");
}
}

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.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Find the runner `listener` argument registration for FailFast.
set -euo pipefail

# Search Gradle, manifests and CI workflows for the listener argument.
rg -n -C3 'testInstrumentationRunnerArgument|listener' --glob '*.gradle' --glob '*.gradle.kts' --glob '*.yml' --glob '*.yaml' --glob 'AndroidManifest.xml' || true

# Confirm any direct reference to the FailFast class outside its own source file.
rg -n 'io\.netbird\.client\.e2e\.FailFast' || true

Repository: netbirdio/android-client

Length of output: 162


🏁 Script executed:

#!/bin/bash
# Description: Inspect the FailFast source and any nearby test runner annotations without modifying or running repository code.
set -euo pipefail

echo "== Locate FailFast =="
fd -a 'FailFast' . | sed 's#^\./##'

echo
echo "== FailFast contents =="
fd 'FailFast' . -x sh -c 'echo "--- $1"; cat -n "$1"' sh {}

echo
echo "== Instrumentation e2e runner annotations in source =="
rg -n -C4 '`@AndroidJUnitRunner`|androidTest|androidTestInstrumentationRunner|AndroidManifest|package io\.netbird\.client\.e2e|class .*Test' . --glob '*.java' --glob '*.xml' || true

Repository: netbirdio/android-client

Length of output: 20749


🏁 Script executed:

#!/bin/bash
# Description: Inspect all tracked Gradle/workflow/manifest files for FailFast or instrumentation listener arguments.
set -euo pipefail

echo "== Track and inspect relevant files =="
git ls-files | rg '(^|/)(build\.gradle(\.kts)?|gradle\.properties|AndroidManifest\.xml|.*\.yml|.*\.yaml)$' || true

echo
echo "== FailFast/listener/testInstrumentationRunnerArgument matches in tracked files =="
python3 - <<'PY'
from pathlib import Path
import subprocess
files=subprocess.check_output(['git','ls-files'],text=True).splitlines()
target=Path('app/src/androidTest/java/io/netbird/client/e2e/FailFast.java')
if target.exists():
    lines=target.read_text().splitlines()
    print(f'FAILFAST_LINES={len(lines)}')
    for i,l in enumerate(lines,1):
        if 'skipIfAborted' in l or '`@Before`' in l:
            print(f'FAILFAST_{i:04d}:{l}')
matches=['io.netbird.client.e2e.FailFast','listener','testInstrumentationRunnerArgument']
for f in files:
    if Path(f).is_file() and f.endswith(('.gradle','.gradle.kts','.properties','.xml','.yml','.yaml','.md')):
        try:
            txt=Path(f).read_text(errors='ignore')
        except Exception:
            continue
        if any(s in txt for s in matches):
            print(f'--- {f}')
            for j,line in enumerate(txt.splitlines(),1):
                if any(s in line for s in matches):
                    print(f'{j}: {line}')
print('Done')
PY

Repository: netbirdio/android-client

Length of output: 1299


Register FailFast with the test runner. skipIfAborted() depends on testFailure setting aborted, but only a listener runner argument can invoke FailFast.testFailure. If this argument is missing or does not name io.netbird.client.e2e.FailFast, fail-fast becomes silent and every instrumentation test continues after the first failure.

🤖 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/androidTest/java/io/netbird/client/e2e/FailFast.java` around lines 19
- 31, Update the instrumentation test runner configuration to register
io.netbird.client.e2e.FailFast as the listener runner argument, ensuring its
testFailure method is invoked and skipIfAborted() can stop subsequent tests
after the first failure.

Comment on lines +231 to +248
for (int attempt = 1; attempt <= 3; attempt++) {
Log.i(TAG, "open profile editor attempt " + attempt);
openProfiles(device);

UiObject2 addBtn = device.wait(
Until.findObject(By.res(PACKAGE, "btn_add_profile")), UI_TIMEOUT_MS);
if (addBtn == null) {
continue;
}
addBtn.click();

if (device.wait(Until.findObject(By.res(PACKAGE, "edit_text_profile_name")),
UI_TIMEOUT_MS) != null) {
return;
}
}
dumpScreenshot(device, "profile-editor-not-open");
fail("profile editor (edit_text_profile_name) did not open after 3 attempts");

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

The retry loop cannot retry: openProfiles fails the test on the first attempt.

openProfiles calls tapTab and tapSettingsRow, and both call fail() when the expected view does not appear. fail() throws an AssertionError, so attempt 1 aborts openProfileEditor before the loop can try again. The comment on Line 228 states the loop exists to absorb the asynchronous teardown of the first-install fragment, but that transient state is exactly what triggers the inner fail().

Add tolerant, boolean-returning navigation helpers for the retry path, and keep the hard fail() only after the last attempt.

♻️ Sketch of a tolerant navigation path
     for (int attempt = 1; attempt <= 3; attempt++) {
         Log.i(TAG, "open profile editor attempt " + attempt);
-        openProfiles(device);
+        if (!tryOpenProfiles(device)) {
+            continue;
+        }
/** Navigate Settings → Profiles without failing the test. */
private static boolean tryOpenProfiles(UiDevice device) throws InterruptedException {
    UiObject2 tab = device.wait(Until.findObject(By.res(PACKAGE, "nav_settings")), UI_TIMEOUT_MS);
    if (tab == null) {
        return false;
    }
    tab.click();
    scrollToRes(device, "row_profiles");
    UiObject2 row = device.wait(Until.findObject(By.res(PACKAGE, "row_profiles")), UI_TIMEOUT_MS);
    if (row == null) {
        return false;
    }
    row.click();
    boolean shown = device.wait(Until.findObject(By.res(PACKAGE, "btn_add_profile")), UI_TIMEOUT_MS) != null;
    device.waitForIdle();
    return shown;
}
📝 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
for (int attempt = 1; attempt <= 3; attempt++) {
Log.i(TAG, "open profile editor attempt " + attempt);
openProfiles(device);
UiObject2 addBtn = device.wait(
Until.findObject(By.res(PACKAGE, "btn_add_profile")), UI_TIMEOUT_MS);
if (addBtn == null) {
continue;
}
addBtn.click();
if (device.wait(Until.findObject(By.res(PACKAGE, "edit_text_profile_name")),
UI_TIMEOUT_MS) != null) {
return;
}
}
dumpScreenshot(device, "profile-editor-not-open");
fail("profile editor (edit_text_profile_name) did not open after 3 attempts");
for (int attempt = 1; attempt <= 3; attempt++) {
Log.i(TAG, "open profile editor attempt " + attempt);
if (!tryOpenProfiles(device)) {
continue;
}
UiObject2 addBtn = device.wait(
Until.findObject(By.res(PACKAGE, "btn_add_profile")), UI_TIMEOUT_MS);
if (addBtn == null) {
continue;
}
addBtn.click();
if (device.wait(Until.findObject(By.res(PACKAGE, "edit_text_profile_name")),
UI_TIMEOUT_MS) != null) {
return;
}
}
dumpScreenshot(device, "profile-editor-not-open");
fail("profile editor (edit_text_profile_name) did not open after 3 attempts");
🤖 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/androidTest/java/io/netbird/client/e2e/LoginFlow.java` around lines
231 - 248, Update the retry path in openProfileEditor to use a tolerant
boolean-returning navigation helper instead of openProfiles, whose
tapTab/tapSettingsRow calls fail immediately. Add tryOpenProfiles (and any
needed tolerant tab/row navigation) to return false when navigation elements are
unavailable, allowing subsequent attempts; retain the final dumpScreenshot and
fail only after all three attempts fail.

Comment on lines +84 to +90
@After
public void tearDown() throws Exception {
if (profileName != null && harness != null) {
harness.disableTouchVisualization();
LoginFlow.removeProfile(E2eAppRule.activity(), harness.device(), profileName);
}
}

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.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Teardown never disconnects the VPN, so a later test can pass on the previous session's Connected state. VpnTestHarness.connectAndAwait skips the toggle tap when btn_connect already reports checked, and then matches text_connection_status against "Connected". Each teardown removes the profile and disables touch visualization only, so the tunnel state carries into the next class.

  • app/src/androidTest/java/io/netbird/client/e2e/PeerConnectivityTest.java#L84-L90: turn the connect toggle off before LoginFlow.removeProfile, and wait for the status to leave "Connected".
  • app/src/androidTest/java/io/netbird/client/e2e/DnsResolutionTest.java#L80-L86: apply the same disconnect step in tearDown.
  • app/src/androidTest/java/io/netbird/client/e2e/ExitNodeRouteTest.java#L72-L78: apply the same disconnect step in tearDown; the exit-node route must not stay active for later classes.
  • app/src/androidTest/java/io/netbird/client/e2e/PortAclTest.java#L86-L92: apply the same disconnect step in tearDown.

Add the shared step as a disconnectAndAwait method on VpnTestHarness so all four teardowns call one implementation.

📍 Affects 4 files
  • app/src/androidTest/java/io/netbird/client/e2e/PeerConnectivityTest.java#L84-L90 (this comment)
  • app/src/androidTest/java/io/netbird/client/e2e/DnsResolutionTest.java#L80-L86
  • app/src/androidTest/java/io/netbird/client/e2e/ExitNodeRouteTest.java#L72-L78
  • app/src/androidTest/java/io/netbird/client/e2e/PortAclTest.java#L86-L92
🤖 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/androidTest/java/io/netbird/client/e2e/PeerConnectivityTest.java`
around lines 84 - 90, Add a shared VpnTestHarness.disconnectAndAwait method that
turns off the connect toggle when needed and waits until text_connection_status
is no longer "Connected". Call it in tearDown before profile removal in
PeerConnectivityTest.java (84-90), DnsResolutionTest.java (80-86),
ExitNodeRouteTest.java (72-78), and PortAclTest.java (86-92), preserving the
existing visualization cleanup and profile removal.

Comment on lines +45 to +68
@Test
public void loginWithSetupKeyViaUi() throws Exception {
Bundle args = InstrumentationRegistry.getArguments();
String setupKey = args.getString("setupKey");

assertNotNull("setupKey instrumentation argument is required", setupKey);
assertTrue("setupKey must not be blank", !setupKey.trim().isEmpty());

device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
profileName = LoginFlow.createProfileAndLogin(
E2eAppRule.activity(), device, "login", setupKey);
}

/**
* Enrolling now creates a profile, so this test leaves one behind — remove
* it like the connectivity tests do, to keep the account's peer list and the
* device's profile list from growing with every run.
*/
@After
public void tearDown() throws Exception {
if (profileName != null && device != null) {
LoginFlow.removeProfile(E2eAppRule.activity(), device, profileName);
}
}

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.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

A failure inside LoginFlow.createProfileAndLogin leaks the created profile in every scenario. The helper creates the profile in the UI, then verifies enrolment and switches profiles. It returns the generated name only on success, so each caller leaves profileName null after a mid-flow failure and its tearDown skips LoginFlow.removeProfile.

  • app/src/androidTest/java/io/netbird/client/e2e/SetupKeyAuthTest.java#L45-L68: publish the generated profile name to the test before the risky steps run, for example by passing a result holder into LoginFlow.createProfileAndLogin.
  • app/src/androidTest/java/io/netbird/client/e2e/PeerConnectivityTest.java#L108-L125: consume the same early-publish mechanism in connectAndPing.
  • app/src/androidTest/java/io/netbird/client/e2e/DnsResolutionTest.java#L103-L104: consume the same early-publish mechanism.
  • app/src/androidTest/java/io/netbird/client/e2e/ExitNodeRouteTest.java#L96-L97: consume the same early-publish mechanism.
  • app/src/androidTest/java/io/netbird/client/e2e/PortAclTest.java#L110-L111: consume the same early-publish mechanism.
📍 Affects 5 files
  • app/src/androidTest/java/io/netbird/client/e2e/SetupKeyAuthTest.java#L45-L68 (this comment)
  • app/src/androidTest/java/io/netbird/client/e2e/PeerConnectivityTest.java#L108-L125
  • app/src/androidTest/java/io/netbird/client/e2e/DnsResolutionTest.java#L103-L104
  • app/src/androidTest/java/io/netbird/client/e2e/ExitNodeRouteTest.java#L96-L97
  • app/src/androidTest/java/io/netbird/client/e2e/PortAclTest.java#L110-L111
🤖 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/androidTest/java/io/netbird/client/e2e/SetupKeyAuthTest.java` around
lines 45 - 68, Update LoginFlow.createProfileAndLogin and its callers so the
generated profile name is published to the owning test immediately after
creation, before enrolment or profile-switching steps can fail. In
app/src/androidTest/java/io/netbird/client/e2e/SetupKeyAuthTest.java:45-68, pass
a result holder and retain the early name for tearDown; apply the same mechanism
in connectAndPing at
app/src/androidTest/java/io/netbird/client/e2e/PeerConnectivityTest.java:108-125,
app/src/androidTest/java/io/netbird/client/e2e/DnsResolutionTest.java:103-104,
app/src/androidTest/java/io/netbird/client/e2e/ExitNodeRouteTest.java:96-97, and
app/src/androidTest/java/io/netbird/client/e2e/PortAclTest.java:110-111 so each
cleanup path can remove partially created profiles.

Comment thread netbird Outdated
@@ -1 +1 @@
Subproject commit 426331552740c69f40a820314ca2833a4cd20ed9
Subproject commit 19a6cedfffd85c938fb1272170e7dd93dcd9c7ab

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.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

new_commit=19a6cedfffd85c938fb1272170e7dd93dcd9c7ab
old_commit=426331552740c69f40a820314ca2833a4cd20ed9

git -C netbird cat-file -e "${new_commit}^{commit}"
git -C netbird cat-file -e "${old_commit}^{commit}"
git -C netbird ls-tree -d --name-only "$new_commit" client/android | grep -Fxq client/android
test "$(git -C netbird rev-parse HEAD)" = "$new_commit"
rg -n -C 3 'gomobile bind|client/android' build-android-lib.sh
git -C netbird diff --stat "$old_commit" "$new_commit" -- client/android

Repository: netbirdio/android-client

Length of output: 338


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== submodule config =="
git config --file .gitmodules --list 2>/dev/null | grep -E '\.url|netbird|submodule' || true

echo "== netbird files =="
git ls-files netbird netbird/.gitmodules netbird/.git 2>/dev/null | sed -n '1,80p' || true

echo "== netbird directory =="
if [ -d netbird ]; then
  ls -la netbird | sed -n '1,40p'
  if [ -f netbird/.git ]; then cat netbird/.git; fi
  if [ -f netbird/.gitmodules ]; then cat netbird/.gitmodules; fi
else
  echo "netbird not as directory"
fi

echo "== gitlink candidates =="
git ls-files -s . | awk '$4 == "160000" {print}' || true

echo "== changed files in HEAD =="
git diff --name-only HEAD | sed -n '1,120p' || true

echo "== references for netbird commits =="
git rev-parse --verify HEAD 2>/dev/null || true
for ref in netbird HEAD; do
  echo "--- $ref"
  git rev-parse --verify --short=12 "${ref}^{commit}" 2>/dev/null || true
done

Repository: netbirdio/android-client

Length of output: 607


🌐 Web query:

netbirdio android-client commit 19a6cedfffd85c938fb1272170e7dd93dcd9c7ab client/android

💡 Result:

The commit hash 19a6cedfffd85c938fb1272170e7dd93dcd9c7ab does not appear in the public commit history of the netbirdio/android-client repository as of August 10, 2026 [1][2][3][4]. The repository makes extensive use of the netbird submodule [5][6][7], which is managed as a git submodule within the android-client project [1][6][7]. It is possible that this specific commit belongs to the main netbird repository rather than the android-client wrapper, or it may refer to a local or private branch not indexed in public history [1][8][9]. To verify a specific commit, you can navigate to the repository on GitHub and view the commit history directly [1].

Citations:


Resolve the missing submodule revision before merging.

Commit 19a6cedfffd85c938fb1272170e7dd93dcd9c7ab is not present in the netbird submodule reference namespace, so update-server.sh cannot fetch the submodule and the Android AAR build will fail. Pin a valid netbird commit or update the repository with the intended revision.

🤖 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 `@netbird` at line 1, Update the netbird submodule reference to a commit that
exists in the submodule repository, or add the intended missing revision to its
remote history, so update-server.sh can fetch it and the Android AAR build
succeeds.

…/e2e-tests-new-design

# Conflicts:
#	netbird
@pappz
pappz merged commit 18a1b6e into ux/ios-style-redesign Aug 10, 2026
2 checks passed
@pappz
pappz deleted the test/e2e-tests-new-design branch August 10, 2026 08:37
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.

3 participants