[stealth 1/4] build profile + flag plumbing - #8859
Conversation
There was a problem hiding this comment.
Pull request overview
This PR introduces the first slice of “Stealth Lantern” build-time gating by adding a build-profile generator and plumbing profile-derived flags through Make/Flutter/Android Gradle plus CI workflow inputs, with accompanying documentation.
Changes:
- Adds
scripts/stealth/generate_profile.py(+ unit tests) to generate/normalize stealth profile JSON and emit dart-defines, artifact metadata, and Go tag suffixes. - Extends the Makefile and Android Gradle build to consume stealth profiles, generate auxiliary build outputs (identity profile, icons, manifests), and optionally build Go code via
garble. - Adds documentation and CI workflow inputs to support stealth leakage scanning and new build options.
Reviewed changes
Copilot reviewed 10 out of 12 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
scripts/stealth/generate_profile.py |
New profile generator/validator producing normalized profile + derived outputs. |
scripts/stealth/generate_profile_test.py |
Unit tests covering profile validation and output generation. |
Makefile |
Adds stealth profile generation, Go tag plumbing, optional obfuscation, and Android build wiring. |
android/app/build.gradle |
Loads stealth/identity profiles, switches source sets/manifest/icons for stealth builds, and exports BuildConfig fields/placeholders. |
lib/core/common/app_build_info.dart |
Adds Dart environment flag accessors and feature gates for stealth builds. |
docs/stealth-build-profile.md |
Documents stealth profile generation and consumption via Make/Gradle. |
docs/stealth-feature-gates.md |
Documents Dart define-based feature gates for stealth artifacts. |
.github/workflows/build-android.yml |
Adds inputs/steps for leakage scanning and optional Go obfuscation build path. |
.github/workflows/release.yml |
Propagates optional stealth leakage scan mode from manual release dispatch to Android build workflow. |
pubspec.yaml |
Adds a new Flutter asset directory entry for stealth assets. |
pubspec.lock |
Dependency lockfile updates. |
.gitignore |
Ignores built APKs and .so artifacts. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
def4ef0 to
82e0867
Compare
bab8b58 to
fa33939
Compare
fb322ce to
ec5db08
Compare
- 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>
ec5db08 to
03e6ede
Compare
|
Caution Review failedAn error occurred during the review process. Please try again later. 📝 WalkthroughWalkthroughThis PR introduces a complete "stealth build" pipeline: a Python script generates and validates stealth build profiles (with Android identity, obfuscation seeds, and dart defines), new Makefile variables and targets propagate stealth configuration across all platforms (Android, iOS, macOS, Linux, Windows) using optional ChangesStealth Build Pipeline
Sequence Diagram(s)sequenceDiagram
rect rgba(100, 100, 200, 0.5)
note over ReleaseCIWorkflow,BuildAndroidWorkflow: CI dispatch with stealth_leakage_mode
end
participant ReleaseCIWorkflow as release.yml
participant SetMetadata as set-metadata job
participant BuildAndroidWorkflow as build-android.yml
ReleaseCIWorkflow->>SetMetadata: workflow_dispatch(stealth_leakage_mode)
SetMetadata->>SetMetadata: derive STEALTH_LEAKAGE_MODE (skip if "none")
SetMetadata-->>BuildAndroidWorkflow: with.stealth_leakage_mode, obfuscate_go, android_identity_seed
alt obfuscate_go == true
BuildAndroidWorkflow->>BuildAndroidWorkflow: install garble
BuildAndroidWorkflow->>BuildAndroidWorkflow: run android-release-ci-obfuscated (ANDROID_IDENTITY_SEED, STEALTH_GARBLE_SEED)
else
BuildAndroidWorkflow->>BuildAndroidWorkflow: run android-release-ci (ANDROID_IDENTITY_SEED)
end
opt stealth_leakage_mode != ""
BuildAndroidWorkflow->>BuildAndroidWorkflow: stealth-leakage-check → stealth-leakage-report.txt
BuildAndroidWorkflow->>BuildAndroidWorkflow: upload artifact stealth-leakage-report.txt
end
Estimated code review effort🎯 5 (Critical) | ⏱️ ~120 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 8
🤖 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/workflows/build-android.yml:
- Around line 196-199: Replace all floating GitHub Actions version references
with pinned commit SHAs to eliminate supply-chain security risks. For each
instance of actions/upload-artifact@v4 (and any other floating action references
in the workflow), replace the floating tag with the full 40-character commit SHA
followed by the version tag as an inline comment (e.g., uses:
actions/upload-artifact@<full-sha> # v4). Apply this pattern consistently across
all action uses declarations in the file, including the multiple occurrences of
upload-artifact references.
In @.github/workflows/release.yml:
- Around line 270-276: The workflow directly injects the GitHub Actions template
expansion of stealth_leakage_mode into the shell script on line 272, which
creates a template injection risk. Move the template expansion outside of the
shell code by adding REQUESTED_STEALTH_LEAKAGE_MODE environment variable in the
step's env section with the value of github.event.inputs.stealth_leakage_mode,
then reference this environment variable within the shell conditional instead of
directly using the template syntax. This separates template processing from
shell interpretation and improves security.
In `@android/app/build.gradle`:
- Around line 195-203: The code resolves the stealth mode in lines 195-203 by
processing the stealthProfile.mode and falling back to the STEALTH_MODE project
property, resulting in the processed stealthMode variable. However, at line 408
where the stealth mode is emitted, the original stealthProfile.mode is still
being used instead of the resolved stealthMode variable. Replace the usage of
stealthProfile.mode at line 408 (and line 409 if applicable) with the resolved
stealthMode variable to ensure the emitted value matches the actual resolved
stealth mode.
In `@docs/stealth-build-profile.md`:
- Around line 15-16: The quick-start command examples in the
stealth-build-profile.md documentation are incomplete and will fail during
execution because they lack required stealth identity name parameters. Update
the example commands (around line 15-16 with the make stealth-profile
STEALTH_MODE=stealth-vpn command, and also at lines 55-57) to include the
required app/session name parameters that are now mandatory for stealth mode
profile generation. Ensure each command example shows the complete set of
parameters needed for successful execution.
In `@Makefile`:
- Around line 336-340: Replace all hardcoded python3 invocations with the
$(PYTHON) variable in the stealth-related Makefile recipes to use the configured
interpreter consistently. This includes the python3 calls in the
STEALTH_PROFILE_SCRIPT section around lines 336-340 and all other stealth recipe
sections at lines 350, 420, and 787-794. Update each occurrence where python3
appears in these stealth recipes to use $(PYTHON) instead, ensuring the Makefile
respects the configured Python interpreter across all environments.
- Around line 76-79: The STEALTH_GO_LDFLAGS variable currently only applies
stealth build flags when BUILD_TYPE matches "stealth stealth-%", but stealth can
be activated through STEALTH_MODE or STEALTH_PROFILE without changing
BUILD_TYPE. Update the conditional check in the STEALTH_GO_LDFLAGS assignment to
gate the ldflags on stealth activation by also checking if STEALTH_MODE or
STEALTH_PROFILE are defined, in addition to the existing BUILD_TYPE filter. This
ensures the StealthBuild and StealthLogLevel flags are applied regardless of
which method activates stealth mode.
In `@scripts/stealth/generate_profile_test.py`:
- Around line 221-254: Add two new test methods following the pattern of
test_stealth_build_requires_app_name and
test_stealth_build_requires_session_name to explicitly verify that branded
stealth names are rejected. Create a test that passes appName="Lantern" with
stealth-vpn mode and asserts the exit code is non-zero, and another test that
passes sessionName="LanternVpn" with stealth-vpn mode and asserts the exit code
is non-zero. These tests will lock in the de-branding privacy rule through
regression testing.
In `@scripts/stealth/generate_profile.py`:
- Around line 206-214: The validation block in the stealth mode section only
verifies that app_name and session_name are not empty, but the error messages
and the comment indicate these values must also not be Lantern-branded. Add
additional checks after the non-empty validation to detect and reject
Lantern-branded values (such as "Lantern", "LanternVpn", or other branded
keywords) in both app_name and session_name parameters. Raise ProfileError with
an appropriate message if a branded value is detected, ensuring stealth
artifacts do not leak branding information.
🪄 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: d305df14-ff96-47c8-8ee4-5885601ba616
⛔ Files ignored due to path filters (1)
pubspec.lockis excluded by!**/*.lock
📒 Files selected for processing (10)
.github/workflows/build-android.yml.github/workflows/release.yml.gitignoreMakefileandroid/app/build.gradledocs/stealth-build-profile.mddocs/stealth-feature-gates.mdlib/core/common/app_build_info.dartscripts/stealth/generate_profile.pyscripts/stealth/generate_profile_test.py
- 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>
|
|
||
| defaultConfig { | ||
| applicationId = "org.getlantern.lantern" | ||
| applicationId = androidIdentity.applicationId |
There was a problem hiding this comment.
I think this needs to be like this
applicationId = stealthMode ? androidIdentity.applicationId : "org.getlantern.lantern"
There was a problem hiding this comment.
androidIdentity.applicationId already defaults to org.getlantern.lantern for normal builds (defaultStealthProfile.packageName → androidIdentityDefaults.applicationId), and line 285 validates it. It is only overridden when an identity profile is explicitly passed — which is intentional: identity randomization is a separate axis from stealth mode (e.g. the ./gradlew assembleRelease -PandroidIdentityProfile=… side-by-side install path). Gating on stealthMode here would ignore a provided profile's applicationId whenever full stealth is not enabled, so I'd keep it as-is.
| // BOTH stealth and regular builds (stealth now compiles the real handlers, | ||
| // not the legacy stub). Only STEALTH_ENABLED differs by build. | ||
| buildConfigField "boolean", "STEALTH_ENABLED", stealthMode ? "true" : "false" | ||
| buildConfigField "String", "STEALTH_MODE", buildConfigString(resolvedStealthMode) |
There was a problem hiding this comment.
Quick question: why do we need the STEALTH_MODE? As a separate key, shouldn't we consider if this stealth enable is true? It is by default in stealth mode, and if not, then normal. Am I missing something here?
There was a problem hiding this comment.
Seems like I got my answers. I think we have two modes: VPN on and no VPN, correct?
There was a problem hiding this comment.
@jigar-f yeah, regular Stealth is just 'white label lantern', the NOVPN stealth removes tunnels, etc, and just leaves a SOCKs proxy mode
Part of epic getlantern/engineering#3569 — stacked PR 1/4, targets
main.Build-profile generation + flag plumbing: a per-build stealth profile (mode, package/app/session name, obfuscation seed, denylist version) fed into Android Gradle, Flutter dart-defines, Go build tags, and CI metadata, plus the central
AppBuildInfoflag surface. All stealth behavior is build-time gated — normal builds are unchanged.Implements getlantern/engineering#3623.
🤖 Generated with Claude Code
Summary by CodeRabbit
Release Notes
New Features
Documentation