Skip to content

Commit 0eaac1e

Browse files
romtsnmarkushi
andauthored
feat(spotlight): Extract SpotlightIntegration to separate module (#5064)
* feat(spotlight): Extract SpotlightIntegration to separate module * Changelog * Address review * Api dump * Update CHANGELOG.md Co-authored-by: Markus Hintersteiner <[email protected]> * Enable spotlight in the sample app * enabled -> enable --------- Co-authored-by: Markus Hintersteiner <[email protected]>
1 parent 48fbb69 commit 0eaac1e

File tree

18 files changed

+267
-20
lines changed

18 files changed

+267
-20
lines changed

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,17 @@
66

77
- Add `installGroupsOverride` parameter and `installGroups` property to Build Distribution SDK ([#5062](https://github.com/getsentry/sentry-java/pull/5062))
88
- Update Android targetSdk to API 36 (Android 16) ([#5016](https://github.com/getsentry/sentry-java/pull/5016))
9+
- Add AndroidManifest support for Spotlight configuration via `io.sentry.spotlight.enable` and `io.sentry.spotlight.url` ([#5064](https://github.com/getsentry/sentry-java/pull/5064))
10+
11+
### Fixes
12+
13+
- Extract `SpotlightIntegration` to separate `sentry-spotlight` module to prevent insecure HTTP URLs from appearing in release APKs ([#5064](https://github.com/getsentry/sentry-java/pull/5064))
14+
- **Breaking:** Users who enable Spotlight must now add the `io.sentry:sentry-spotlight` dependency:
15+
```kotlin
16+
dependencies {
17+
debugImplementation("io.sentry:sentry-spotlight:<version>")
18+
}
19+
```
920

1021
### Fixes
1122

sentry-android-core/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ dependencies {
102102
testImplementation(libs.mockito.kotlin)
103103
testImplementation(libs.mockito.inline)
104104
testImplementation(projects.sentryTestSupport)
105+
testImplementation(projects.sentrySpotlight)
105106
testImplementation(projects.sentryAndroidFragment)
106107
testImplementation(projects.sentryAndroidTimber)
107108
testImplementation(projects.sentryAndroidReplay)

sentry-android-core/proguard-rules.pro

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,3 +83,8 @@
8383
-dontwarn io.sentry.android.distribution.DistributionIntegration
8484
-keepnames class io.sentry.android.distribution.DistributionIntegration
8585
##---------------End: proguard configuration for sentry-android-distribution ----------
86+
87+
##---------------Begin: proguard configuration for sentry-spotlight ----------
88+
-dontwarn io.sentry.spotlight.SpotlightIntegration
89+
-keepnames class io.sentry.spotlight.SpotlightIntegration
90+
##---------------End: proguard configuration for sentry-spotlight ----------

sentry-android-core/src/main/java/io/sentry/android/core/ManifestMetadataReader.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,10 @@ final class ManifestMetadataReader {
164164

165165
static final String FEEDBACK_SHOW_BRANDING = "io.sentry.feedback.show-branding";
166166

167+
static final String SPOTLIGHT_ENABLE = "io.sentry.spotlight.enable";
168+
169+
static final String SPOTLIGHT_CONNECTION_URL = "io.sentry.spotlight.url";
170+
167171
/** ManifestMetadataReader ctor */
168172
private ManifestMetadataReader() {}
169173

@@ -642,6 +646,15 @@ static void applyMetadata(
642646
metadata, logger, FEEDBACK_USE_SENTRY_USER, feedbackOptions.isUseSentryUser()));
643647
feedbackOptions.setShowBranding(
644648
readBool(metadata, logger, FEEDBACK_SHOW_BRANDING, feedbackOptions.isShowBranding()));
649+
650+
options.setEnableSpotlight(
651+
readBool(metadata, logger, SPOTLIGHT_ENABLE, options.isEnableSpotlight()));
652+
653+
final @Nullable String spotlightUrl =
654+
readString(metadata, logger, SPOTLIGHT_CONNECTION_URL, null);
655+
if (spotlightUrl != null) {
656+
options.setSpotlightConnectionUrl(spotlightUrl);
657+
}
645658
}
646659
options
647660
.getLogger()

sentry-android-core/src/test/java/io/sentry/android/core/ManifestMetadataReaderTest.kt

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2217,4 +2217,76 @@ class ManifestMetadataReaderTest {
22172217
assertTrue(headers.contains("Authorization"))
22182218
assertTrue(headers.contains("X-Custom-Header"))
22192219
}
2220+
2221+
// Spotlight Configuration Tests
2222+
2223+
@Test
2224+
fun `applyMetadata reads spotlight enabled and keeps default value if not found`() {
2225+
// Arrange
2226+
val context = fixture.getContext()
2227+
2228+
// Act
2229+
ManifestMetadataReader.applyMetadata(context, fixture.options, fixture.buildInfoProvider)
2230+
2231+
// Assert
2232+
assertFalse(fixture.options.isEnableSpotlight)
2233+
}
2234+
2235+
@Test
2236+
fun `applyMetadata reads spotlight enabled to options`() {
2237+
// Arrange
2238+
val bundle = bundleOf(ManifestMetadataReader.SPOTLIGHT_ENABLE to true)
2239+
val context = fixture.getContext(metaData = bundle)
2240+
2241+
// Act
2242+
ManifestMetadataReader.applyMetadata(context, fixture.options, fixture.buildInfoProvider)
2243+
2244+
// Assert
2245+
assertTrue(fixture.options.isEnableSpotlight)
2246+
}
2247+
2248+
@Test
2249+
fun `applyMetadata reads spotlight url and keeps null if not found`() {
2250+
// Arrange
2251+
val context = fixture.getContext()
2252+
2253+
// Act
2254+
ManifestMetadataReader.applyMetadata(context, fixture.options, fixture.buildInfoProvider)
2255+
2256+
// Assert
2257+
assertNull(fixture.options.spotlightConnectionUrl)
2258+
}
2259+
2260+
@Test
2261+
fun `applyMetadata reads spotlight url to options`() {
2262+
// Arrange
2263+
val expectedUrl = "http://10.0.2.2:8969/stream"
2264+
val bundle = bundleOf(ManifestMetadataReader.SPOTLIGHT_CONNECTION_URL to expectedUrl)
2265+
val context = fixture.getContext(metaData = bundle)
2266+
2267+
// Act
2268+
ManifestMetadataReader.applyMetadata(context, fixture.options, fixture.buildInfoProvider)
2269+
2270+
// Assert
2271+
assertEquals(expectedUrl, fixture.options.spotlightConnectionUrl)
2272+
}
2273+
2274+
@Test
2275+
fun `applyMetadata reads both spotlight enabled and url to options`() {
2276+
// Arrange
2277+
val expectedUrl = "http://localhost:8969/stream"
2278+
val bundle =
2279+
bundleOf(
2280+
ManifestMetadataReader.SPOTLIGHT_ENABLE to true,
2281+
ManifestMetadataReader.SPOTLIGHT_CONNECTION_URL to expectedUrl,
2282+
)
2283+
val context = fixture.getContext(metaData = bundle)
2284+
2285+
// Act
2286+
ManifestMetadataReader.applyMetadata(context, fixture.options, fixture.buildInfoProvider)
2287+
2288+
// Assert
2289+
assertTrue(fixture.options.isEnableSpotlight)
2290+
assertEquals(expectedUrl, fixture.options.spotlightConnectionUrl)
2291+
}
22202292
}

sentry-android-core/src/test/java/io/sentry/android/core/SentryAndroidTest.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ import io.sentry.SentryOptions
2626
import io.sentry.SentryOptions.BeforeSendCallback
2727
import io.sentry.Session
2828
import io.sentry.ShutdownHookIntegration
29-
import io.sentry.SpotlightIntegration
3029
import io.sentry.SystemOutLogger
3130
import io.sentry.UncaughtExceptionHandlerIntegration
3231
import io.sentry.android.core.cache.AndroidEnvelopeCache
@@ -46,6 +45,7 @@ import io.sentry.cache.PersistingScopeObserver.TRANSACTION_FILENAME
4645
import io.sentry.cache.tape.QueueFile
4746
import io.sentry.protocol.Contexts
4847
import io.sentry.protocol.SentryId
48+
import io.sentry.spotlight.SpotlightIntegration
4949
import io.sentry.test.applyTestOptions
5050
import io.sentry.transport.NoOpEnvelopeCache
5151
import io.sentry.util.StringUtils

sentry-samples/sentry-samples-android/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ dependencies {
127127
implementation(projects.sentryCompose)
128128
implementation(projects.sentryKotlinExtensions)
129129
implementation(projects.sentryOkhttp)
130+
implementation(projects.sentrySpotlight)
130131

131132
// how to exclude androidx if release health feature is disabled
132133
// implementation(projects.sentryAndroid) {

sentry-samples/sentry-samples-android/src/main/AndroidManifest.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,5 +253,8 @@
253253
<meta-data
254254
android:name="io.sentry.session-replay.network-response-headers"
255255
android:value="X-Response-Time,X-Cache-Status,X-Test-Response" />
256+
<meta-data
257+
android:name="io.sentry.spotlight.enable"
258+
android:value="true" />
256259
</application>
257260
</manifest>
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
public final class io/sentry/spotlight/BuildConfig {
2+
public static final field VERSION_NAME Ljava/lang/String;
3+
}
4+
5+
public final class io/sentry/spotlight/SpotlightIntegration : io/sentry/Integration, io/sentry/SentryOptions$BeforeEnvelopeCallback, java/io/Closeable {
6+
public fun <init> ()V
7+
public fun close ()V
8+
public fun execute (Lio/sentry/SentryEnvelope;Lio/sentry/Hint;)V
9+
public fun register (Lio/sentry/IScopes;Lio/sentry/SentryOptions;)V
10+
}
11+

sentry-spotlight/build.gradle.kts

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import net.ltgt.gradle.errorprone.errorprone
2+
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
3+
4+
plugins {
5+
`java-library`
6+
id("io.sentry.javadoc")
7+
alias(libs.plugins.kotlin.jvm)
8+
jacoco
9+
alias(libs.plugins.errorprone)
10+
alias(libs.plugins.gradle.versions)
11+
alias(libs.plugins.animalsniffer)
12+
alias(libs.plugins.buildconfig)
13+
}
14+
15+
tasks.withType<KotlinCompile>().configureEach {
16+
compilerOptions.jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_1_8
17+
}
18+
19+
dependencies {
20+
api(projects.sentry)
21+
22+
errorprone(libs.errorprone.core)
23+
errorprone(libs.nopen.checker)
24+
errorprone(libs.nullaway)
25+
compileOnly(libs.jetbrains.annotations)
26+
compileOnly(libs.nopen.annotations)
27+
28+
// tests
29+
testImplementation(kotlin(Config.kotlinStdLib))
30+
testImplementation(libs.kotlin.test.junit)
31+
testImplementation(libs.mockito.kotlin)
32+
testImplementation(libs.mockito.inline)
33+
testImplementation(projects.sentryTestSupport)
34+
35+
val gummyBearsModule = libs.gummy.bears.api21.get().module
36+
signature("${gummyBearsModule}:${libs.versions.gummyBears.get()}@signature")
37+
}
38+
39+
configure<SourceSetContainer> { test { java.srcDir("src/test/java") } }
40+
41+
jacoco { toolVersion = libs.versions.jacoco.get() }
42+
43+
tasks.jacocoTestReport {
44+
reports {
45+
xml.required.set(true)
46+
html.required.set(false)
47+
}
48+
}
49+
50+
tasks {
51+
jacocoTestCoverageVerification {
52+
violationRules { rule { limit { minimum = Config.QualityPlugins.Jacoco.minimumCoverage } } }
53+
}
54+
check {
55+
dependsOn(jacocoTestCoverageVerification)
56+
dependsOn(jacocoTestReport)
57+
dependsOn(animalsnifferMain)
58+
}
59+
}
60+
61+
buildConfig {
62+
useJavaOutput()
63+
packageName("io.sentry.spotlight")
64+
buildConfigField("String", "VERSION_NAME", "\"${project.version}\"")
65+
}
66+
67+
tasks.withType<JavaCompile>().configureEach {
68+
dependsOn(tasks.generateBuildConfig)
69+
options.errorprone {
70+
check("NullAway", net.ltgt.gradle.errorprone.CheckSeverity.ERROR)
71+
option("NullAway:AnnotatedPackages", "io.sentry")
72+
}
73+
}
74+
75+
tasks.jar {
76+
manifest {
77+
attributes(
78+
"Sentry-Version-Name" to project.version,
79+
"Sentry-SDK-Name" to Config.Sentry.SENTRY_JAVA_SDK_NAME,
80+
"Sentry-SDK-Package-Name" to "maven:io.sentry:sentry-spotlight",
81+
"Implementation-Vendor" to "Sentry",
82+
"Implementation-Title" to project.name,
83+
"Implementation-Version" to project.version,
84+
)
85+
}
86+
}

0 commit comments

Comments
 (0)