Skip to content

[stealth 2/4] neutral identity, icons & manifest minimization#8860

Open
reflog wants to merge 5 commits into
mainfrom
stealth/pr2-identity
Open

[stealth 2/4] neutral identity, icons & manifest minimization#8860
reflog wants to merge 5 commits into
mainfrom
stealth/pr2-identity

Conversation

@reflog

@reflog reflog commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Part of epic getlantern/engineering#3569 — stacked PR 2/4, targets stealth/pr1-foundation.

Per-build neutral Android identity (randomized package name, labels, VPN session name), generated neutral app/notification icons, and Android manifest + permission minimization (incl. the no-VPN manifest). Normal builds unchanged.

Implements getlantern/engineering#3624.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added support for creating stealth Android build variants with customizable branding, icons, and app identity
    • Introduced build-time configuration for app labels, package names, and notification settings per variant
  • Documentation

    • Added guides for stealth Android icon generation and identity profile configuration

@reflog reflog changed the title stealth(identity): neutral identity, icons & manifest minimization [stealth 2/6] neutral identity, icons & manifest minimization Jun 15, 2026
@reflog reflog force-pushed the stealth/pr1-foundation branch from def4ef0 to 82e0867 Compare June 15, 2026 15:45
@reflog reflog force-pushed the stealth/pr2-identity branch from 8e087bf to 73dd0ea Compare June 15, 2026 15:45
@reflog reflog marked this pull request as ready for review June 15, 2026 15:57
Copilot AI review requested due to automatic review settings June 15, 2026 15:57

Copilot AI 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.

Pull request overview

This PR is the second in the Stealth Android stack and introduces build-time–gated mechanisms to neutralize install-time identity (package/app labels/auth scheme), generate neutral icon resources, and minimize the merged Android manifest for stealth modes while keeping normal builds on the existing identity defaults.

Changes:

  • Add generators (with tests) for Android identity profiles (.properties) and deterministic neutral icon resources driven by private seeds.
  • Introduce a post-merge Android manifest filter (with tests) to remove unwanted permissions/components and rewrite component names for stealth vpn/novpn modes.
  • Wire Android runtime strings/icons/labels to build-provided values (via placeholders/BuildConfig), and add stealth-only Kotlin + resource overlays for a neutral bridge surface.

Reviewed changes

Copilot reviewed 27 out of 27 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
android/app/src/main/AndroidManifest.novpn.xml Adds a separate manifest variant intended for a no-VPN mode configuration.
android/app/src/main/AndroidManifest.xml Switches app identity and icon fields to manifest placeholders (label/icons/auth scheme/tile icon).
android/app/src/main/kotlin/org/getlantern/lantern/LanternApp.kt Makes the Application class extensible for generated/debranded variants.
android/app/src/main/kotlin/org/getlantern/lantern/notification/NotificationManager.kt Uses BuildConfig-driven notification channel strings and resolves configurable small-icon resources.
android/app/src/main/kotlin/org/getlantern/lantern/service/LanternVpnService.kt Makes VPN service extensible and moves session naming/exclusion behavior to BuildConfig + stealth helpers.
android/app/src/main/kotlin/org/getlantern/lantern/service/QuickTileService.kt Makes tile service extensible and uses BuildConfig-driven tile labels + configurable service intent target.
android/app/src/main/res/drawable/neutral_app_icon.xml Adds neutral drawable icon resource for identity/profile-based placeholder usage.
android/app/src/main/res/drawable/neutral_notification_icon.xml Adds neutral notification icon drawable resource.
android/app/src/main/res/values/string.xml Removes the checked-in app_name string to rely on build-injected values.
android/app/src/stealth/kotlin/foundation/bridge/AppHost.kt Adds stealth Application host that initializes bridge context.
android/app/src/stealth/kotlin/foundation/bridge/BaseHomeActivity.kt Adds a stealth FlutterActivity base with a bridge control MethodChannel.
android/app/src/stealth/kotlin/foundation/bridge/BridgeCommon.kt Adds shared stealth bridge utilities (state/paths/foreground notification).
android/app/src/stealth/res/drawable/launch_background.xml Adds stealth launch background resource.
android/app/src/stealth/res/drawable/neutral_app_icon.xml Adds stealth overlay neutral app icon resource.
android/app/src/stealth/res/drawable/neutral_notification_icon.xml Adds stealth overlay neutral notification icon resource.
android/app/src/stealth/res/values-night/styles.xml Adds stealth night theme resources.
android/app/src/stealth/res/values/styles.xml Adds stealth default theme resources.
docs/stealth-android-icons.md Documents stealth icon generation and build wiring.
docs/stealth-android-identity.md Documents identity profile generation/usage and schema.
lib/core/common/app_secrets.dart Routes Android package name usage through build-info (stealth-aware) rather than a hard-coded constant.
scripts/stealth/android_manifest_filter.py Implements post-merge manifest minimization + component rewrite for stealth vpn/novpn.
scripts/stealth/android_manifest_filter_test.py Adds coverage for manifest filtering invariants and idempotency.
scripts/stealth/debrand_kotlin.py Implements mechanical debranding copy/transform of Kotlin sources/resources for stealth builds.
scripts/stealth/generate_android_icons.py Generates deterministic neutral icon resource set and metadata from a seed.
scripts/stealth/generate_android_icons_test.py Adds deterministic and file-output tests for icon generation.
scripts/stealth/generate_android_identity.py Generates Android identity profiles (properties) from seed or JSON profile input.
scripts/stealth/generate_android_identity_test.py Adds tests for deterministic identity generation, profile import, and properties output.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread android/app/src/main/kotlin/org/getlantern/lantern/service/LanternVpnService.kt Outdated
Comment thread scripts/stealth/generate_android_icons.py
Comment thread scripts/stealth/generate_android_icons.py
Comment thread docs/stealth-android-icons.md Outdated
Comment thread docs/stealth-android-icons.md Outdated
Comment thread docs/stealth-android-icons.md
Comment thread docs/stealth-android-identity.md Outdated
Comment thread android/app/src/main/AndroidManifest.novpn.xml Outdated
Comment thread android/app/src/main/AndroidManifest.novpn.xml
@reflog reflog force-pushed the stealth/pr1-foundation branch from 82e0867 to bab8b58 Compare June 15, 2026 16:10
@reflog reflog force-pushed the stealth/pr2-identity branch from 73dd0ea to 3a9a501 Compare June 15, 2026 16:10
@reflog reflog force-pushed the stealth/pr1-foundation branch from bab8b58 to fa33939 Compare June 15, 2026 16:27
@reflog reflog force-pushed the stealth/pr2-identity branch from 3a9a501 to a8a0e78 Compare June 15, 2026 16:27
@reflog reflog changed the title [stealth 2/6] neutral identity, icons & manifest minimization [stealth 2/4] neutral identity, icons & manifest minimization Jun 15, 2026
@reflog reflog force-pushed the stealth/pr1-foundation branch from fa33939 to fb322ce Compare June 15, 2026 16:41
@reflog reflog force-pushed the stealth/pr2-identity branch from a8a0e78 to 6b0fb5c Compare June 15, 2026 16:41
@reflog reflog force-pushed the stealth/pr1-foundation branch from fb322ce to ec5db08 Compare June 15, 2026 16:51
@reflog reflog force-pushed the stealth/pr2-identity branch from 6b0fb5c to 4a146d2 Compare June 15, 2026 16:51
reflog and others added 2 commits June 23, 2026 14:20
- Always include core-ktx / lifecycle-livedata-ktx / work-runtime-ktx:
  these are used by the real app code (VPN status, logs, background work)
  in stealth builds too, not just regular builds.
- Drop the dangling proguard-stealth-novpn.pro reference; the existing
  proguard-rules.pro applies to all release variants (incl. stealth-novpn).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@reflog reflog force-pushed the stealth/pr1-foundation branch from ec5db08 to 03e6ede Compare June 23, 2026 12:22
reflog and others added 2 commits June 23, 2026 14:46
- generate_profile.py: enforce non-branded (no "Lantern") app/session names
  for stealth modes, matching the de-branding contract the error messages
  already promised; add regression tests for branded names.
- build.gradle: emit the resolved stealth mode in the STEALTH_MODE
  BuildConfig field so it can't read "normal" while STEALTH_ENABLED=true
  (e.g. when stealth is enabled via -PSTEALTH_MODE without a profile).
- Makefile: gate STEALTH_GO_LDFLAGS and lanternd log level on stealth
  activation (BUILD_TYPE | STEALTH_MODE | STEALTH_PROFILE), not BUILD_TYPE
  alone; use $(PYTHON) instead of hardcoded python3 in stealth recipes.
- release.yml: read stealth_leakage_mode via env indirection with an
  explicit allowlist instead of inlining the template expansion in shell.
- docs: make quick-start commands runnable (include required app/session
  names).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@reflog reflog force-pushed the stealth/pr2-identity branch from 4a146d2 to 0e2c4d1 Compare June 23, 2026 16:08
@coderabbitai

coderabbitai Bot commented Jun 23, 2026

Copy link
Copy Markdown
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 3.36% 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
Title check ✅ Passed The title accurately and concisely describes the main changes: implementing neutral (randomized) identity, generating icons, and minimizing the Android manifest for stealth builds.
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch stealth/pr2-identity

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🤖 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 `@android/app/src/main/AndroidManifest.xml`:
- Around line 69-81: The AndroidManifest.xml intent-filters now advertise the
dynamic ${appAuthScheme} for deep-link handling, but the deep-link routing logic
in lib/lantern_app.dart still hardcodes checks for uri.scheme == 'lantern'.
Update the scheme validation logic in lib/lantern_app.dart where the auth,
report-issue, and private-server hosts are handled to check against the actual
appAuthScheme value that matches what the manifest declares, rather than the
hardcoded 'lantern' string, so that incoming URIs like mobileapp://auth?... are
properly recognized and routed.

In
`@android/app/src/main/kotlin/org/getlantern/lantern/notification/NotificationManager.kt`:
- Around line 237-251: The resolveNotificationSmallIcon function currently falls
back to R.drawable.lantern_notification_icon unconditionally when icon
resolution fails, which leaks the branded identity in stealth builds. Instead of
always returning the branded icon, check whether the application is running in
stealth mode using a stealth-aware check through LanternApp.application, then
return an appropriate stealth-aware fallback icon resource when in stealth mode,
or the branded icon otherwise.

In `@android/app/src/stealth/kotlin/foundation/bridge/BridgeCommon.kt`:
- Line 93: The `.setContentTitle()` call in BridgeCommon.kt is referencing
R.string.app_name which does not exist in the stealth resource tree. Either add
an app_name string resource definition to the stealth flavor's string.xml file,
or replace the R.string.app_name reference with a string resource that actually
exists in the stealth resources (such as the existing disconnect string), or use
a hardcoded string literal instead of a resource reference.

In `@docs/stealth-android-identity.md`:
- Around line 82-87: The documentation in lines 82-87 and 117-119 does not
adequately clarify the difference in APP_AUTH_SCHEME handling between stealth
and non-stealth Android builds. Revise the text to explicitly state that for
stealth builds, ANDROID_IDENTITY_DART_DEFINES remains empty (because
STEALTH_ENABLED is set), which means the appAuthScheme from the .properties file
is passed only to Gradle for manifest substitution but not to Dart. Therefore,
stealth builds must explicitly pass
--dart-define=APP_AUTH_SCHEME=<appAuthScheme> (extracted from the generated
.properties file) when invoking flutter build to ensure Dart's deep-link
handling matches the manifest scheme. Additionally, clarify that lines 117-119
describe behavior specific to non-stealth Android release builds by updating the
section context or heading to distinguish between stealth and non-stealth
configurations.

In `@scripts/stealth/android_manifest_filter.py`:
- Around line 213-229: The ensure_novpn_service() function only checks for
STEALTH_NOVPN_SERVICE_NAME when determining if a no-VPN service already exists,
but it should also recognize pre-existing no-VPN service aliases like
foundation.bridge.SyncService. Modify the condition in the function to check for
all known no-VPN service aliases in addition to STEALTH_NOVPN_SERVICE_NAME, so
that if any variant already exists in the application, the function returns
early instead of appending a duplicate service entry. Additionally, add a
regression test case with a fixture containing foundation.bridge.SyncService to
verify that the function correctly skips appending a new service when this alias
is already present.

In `@scripts/stealth/debrand_kotlin.py`:
- Around line 139-140: Add validation logic before the resource processing
blocks to ensure fail-fast behavior: verify that if --res-source is provided,
--res-output must also be provided (and vice versa), and if --res-overlay is
provided as a path argument, it must be a valid directory before attempting to
process it. If these conditions are not met, the script should exit with an
appropriate error message rather than silently continuing with incomplete
resource operations. This applies to both the main resource processing block at
lines 139-140 and the related section mentioned at lines 177-178.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 47520e99-ed4b-49c5-80ce-5c68c4be832d

📥 Commits

Reviewing files that changed from the base of the PR and between 1e1c52b and 0e2c4d1.

📒 Files selected for processing (27)
  • android/app/src/main/AndroidManifest.novpn.xml
  • android/app/src/main/AndroidManifest.xml
  • android/app/src/main/kotlin/org/getlantern/lantern/LanternApp.kt
  • android/app/src/main/kotlin/org/getlantern/lantern/notification/NotificationManager.kt
  • android/app/src/main/kotlin/org/getlantern/lantern/service/LanternVpnService.kt
  • android/app/src/main/kotlin/org/getlantern/lantern/service/QuickTileService.kt
  • android/app/src/main/res/drawable/neutral_app_icon.xml
  • android/app/src/main/res/drawable/neutral_notification_icon.xml
  • android/app/src/main/res/values/string.xml
  • android/app/src/stealth/kotlin/foundation/bridge/AppHost.kt
  • android/app/src/stealth/kotlin/foundation/bridge/BaseHomeActivity.kt
  • android/app/src/stealth/kotlin/foundation/bridge/BridgeCommon.kt
  • android/app/src/stealth/res/drawable/launch_background.xml
  • android/app/src/stealth/res/drawable/neutral_app_icon.xml
  • android/app/src/stealth/res/drawable/neutral_notification_icon.xml
  • android/app/src/stealth/res/values-night/styles.xml
  • android/app/src/stealth/res/values/styles.xml
  • docs/stealth-android-icons.md
  • docs/stealth-android-identity.md
  • lib/core/common/app_secrets.dart
  • scripts/stealth/android_manifest_filter.py
  • scripts/stealth/android_manifest_filter_test.py
  • scripts/stealth/debrand_kotlin.py
  • scripts/stealth/generate_android_icons.py
  • scripts/stealth/generate_android_icons_test.py
  • scripts/stealth/generate_android_identity.py
  • scripts/stealth/generate_android_identity_test.py
💤 Files with no reviewable changes (1)
  • android/app/src/main/res/values/string.xml

Comment thread android/app/src/main/AndroidManifest.xml
Comment thread android/app/src/stealth/kotlin/foundation/bridge/BridgeCommon.kt Outdated
Comment thread docs/stealth-android-identity.md
Comment thread scripts/stealth/android_manifest_filter.py
Comment thread scripts/stealth/debrand_kotlin.py
- lantern_app.dart: route host-based deep links via AppBuildInfo.isAppAuthUri()
  instead of a hardcoded 'lantern' scheme, matching the ${appAuthScheme} manifest
  intent-filters (default scheme is still 'lantern', so normal builds are
  unchanged).
- NotificationManager: stealth-aware fallback for the small notification icon so
  a failed resource lookup never reintroduces the branded icon.
- BridgeCommon: drop the non-existent R.string.app_name (would fail resource
  linking); use the app's own (neutral) label via PackageManager.
- android_manifest_filter: normalize pre-existing/legacy no-VPN services
  (e.g. foundation.bridge.SyncService) into a single canonical special-use FGS
  instead of appending a duplicate; add regression tests.
- debrand_kotlin: fail fast on partial --res-source/--res-output or an invalid
  --res-overlay before writing any output.
- docs: clarify that APP_AUTH_SCHEME is injected only for non-stealth identity
  release builds; stealth builds must pass --dart-define explicitly.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Base automatically changed from stealth/pr1-foundation to main June 24, 2026 10:02
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