Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: IDE-24 Disable Tracking via Segment and Amplitude for NON-MT-US … #469

Merged
merged 5 commits into from
Feb 5, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 13 additions & 13 deletions src/main/kotlin/io/snyk/plugin/services/SnykAnalyticsService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import snyk.analytics.QuickFixIsDisplayed
import snyk.analytics.QuickFixIsTriggered
import snyk.analytics.WelcomeIsViewed
import snyk.common.SnykError
import snyk.common.isFedramp
import snyk.common.isAnalyticsPermitted
import snyk.container.ContainerResult
import snyk.iac.IacResult
import snyk.oss.OssResult
Expand Down Expand Up @@ -146,7 +146,7 @@ class SnykAnalyticsService : Disposable {
}

fun obtainUserId(token: String?): String {
if (!settings.usageAnalyticsEnabled || isFedramp()) {
if (!settings.usageAnalyticsEnabled || !isAnalyticsPermitted()) {
log.warn("Token is null or empty, or analytics disabled. User public id will not be obtained.")
return ""
}
Expand All @@ -164,7 +164,7 @@ class SnykAnalyticsService : Disposable {
}

fun identify() {
if (!settings.usageAnalyticsEnabled || isFedramp() || userId.isBlank()) {
if (!settings.usageAnalyticsEnabled || !isAnalyticsPermitted() || userId.isBlank()) {
return
}

Expand All @@ -174,15 +174,15 @@ class SnykAnalyticsService : Disposable {
}

fun logWelcomeIsViewed(event: WelcomeIsViewed) {
if (!settings.usageAnalyticsEnabled || isFedramp()) return
if (!settings.usageAnalyticsEnabled || !isAnalyticsPermitted()) return

catchAll(log, "welcomeIsViewed") {
itly.logWelcomeIsViewed(userId, event)
}
}

fun logAnalysisIsTriggered(event: AnalysisIsTriggered) {
if (!settings.usageAnalyticsEnabled || isFedramp() || userId.isBlank()) {
if (!settings.usageAnalyticsEnabled || !isAnalyticsPermitted() || userId.isBlank()) {
return
}

Expand All @@ -192,7 +192,7 @@ class SnykAnalyticsService : Disposable {
}

private fun logAnalysisIsReady(event: AnalysisIsReady) {
if (!settings.usageAnalyticsEnabled || isFedramp() || userId.isBlank()) {
if (!settings.usageAnalyticsEnabled || !isAnalyticsPermitted() || userId.isBlank()) {
return
}

Expand All @@ -202,7 +202,7 @@ class SnykAnalyticsService : Disposable {
}

fun logIssueInTreeIsClicked(event: IssueInTreeIsClicked) {
if (!settings.usageAnalyticsEnabled || isFedramp() || userId.isBlank()) {
if (!settings.usageAnalyticsEnabled || !isAnalyticsPermitted() || userId.isBlank()) {
return
}

Expand All @@ -212,7 +212,7 @@ class SnykAnalyticsService : Disposable {
}

fun logHealthScoreIsClicked(event: HealthScoreIsClicked) {
if (!settings.usageAnalyticsEnabled || isFedramp() || userId.isBlank()) {
if (!settings.usageAnalyticsEnabled || !isAnalyticsPermitted() || userId.isBlank()) {
return
}

Expand All @@ -222,39 +222,39 @@ class SnykAnalyticsService : Disposable {
}

fun logPluginIsInstalled(event: PluginIsInstalled) {
if (!settings.usageAnalyticsEnabled || isFedramp()) return
if (!settings.usageAnalyticsEnabled || !isAnalyticsPermitted()) return

catchAll(log, "pluginIsInstalled") {
itly.logPluginIsInstalled(userId, event)
}
}

fun logPluginIsUninstalled(event: PluginIsUninstalled) {
if (!settings.usageAnalyticsEnabled || isFedramp()) return
if (!settings.usageAnalyticsEnabled || !isAnalyticsPermitted()) return

catchAll(log, "pluginIsUninstalled") {
itly.logPluginIsUninstalled(userId, event)
}
}

fun logAuthenticateButtonIsClicked(event: AuthenticateButtonIsClicked) {
if (!settings.usageAnalyticsEnabled || isFedramp()) return
if (!settings.usageAnalyticsEnabled || !isAnalyticsPermitted()) return

catchAll(log, "authenticateButtonIsClicked") {
itly.logAuthenticateButtonIsClicked(userId, event)
}
}

fun logQuickFixIsDisplayed(event: QuickFixIsDisplayed) {
if (!settings.usageAnalyticsEnabled || isFedramp()) return
if (!settings.usageAnalyticsEnabled || !isAnalyticsPermitted()) return

catchAll(log, "quickFixIsDisplayed") {
itly.logQuickFixIsDisplayed(userId, event)
}
}

fun logQuickFixIsTriggered(event: QuickFixIsTriggered) {
if (!settings.usageAnalyticsEnabled || isFedramp()) return
if (!settings.usageAnalyticsEnabled || !isAnalyticsPermitted()) return

catchAll(log, "quickFixIsTriggered") {
itly.logQuickFixIsTriggered(userId, event)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import snyk.amplitude.api.AmplitudeExperimentApiClient
import snyk.amplitude.api.AmplitudeExperimentApiClient.Defaults.FALLBACK_VARIANT
import snyk.amplitude.api.ExperimentUser
import snyk.amplitude.api.Variant
import snyk.common.isFedramp
import snyk.common.isAnalyticsPermitted
import java.io.IOException
import java.util.Properties
import java.util.concurrent.ConcurrentHashMap
Expand All @@ -31,7 +31,7 @@ class AmplitudeExperimentService : Disposable {
prop.load(javaClass.classLoader.getResourceAsStream("application.properties"))
val apiKey = prop.getProperty("amplitude.experiment.api-key") ?: ""
val settings = pluginSettings()
if (settings.usageAnalyticsEnabled && !isFedramp()) {
if (settings.usageAnalyticsEnabled && !isAnalyticsPermitted()) {
apiClient = AmplitudeExperimentApiClient.create(apiKey = apiKey)
} else {
LOG.debug("Amplitude experiment disabled.")
Expand Down
7 changes: 4 additions & 3 deletions src/main/kotlin/snyk/common/CustomEndpoints.kt
Original file line number Diff line number Diff line change
Expand Up @@ -126,13 +126,14 @@

fun URI.isDev() = isSnykDomain() && host.lowercase().startsWith("dev.")

fun URI.isFedramp() = isSnykGov()
fun URI.isAnalyticsPermitted() = host != null &&
(host.lowercase() == "app.snyk.io" || host.lowercase() == "app.us.snyk.io" || host.lowercase() == "snyk.io" )
github-advanced-security[bot] marked this conversation as resolved.
Fixed
Show resolved Hide resolved

fun isFedramp(): Boolean {
fun isAnalyticsPermitted(): Boolean {
val settings = pluginSettings()
return settings.customEndpointUrl
?.let { URI(it) }
?.isFedramp() ?: false
?.isAnalyticsPermitted() ?: true
}

fun URI.isLocalCodeEngine() = pluginSettings().localCodeEngineEnabled == true
Expand Down
2 changes: 1 addition & 1 deletion src/main/kotlin/snyk/common/EnvironmentHelper.kt
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ object EnvironmentHelper {

environment["SNYK_API"] = endpoint

if (!pluginSettings().usageAnalyticsEnabled || endpointURI.isFedramp()) {
if (!pluginSettings().usageAnalyticsEnabled || !endpointURI.isAnalyticsPermitted()) {
environment["SNYK_CFG_DISABLE_ANALYTICS"] = "1"
}

Expand Down
4 changes: 2 additions & 2 deletions src/main/kotlin/snyk/errorHandler/SentryErrorReporter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import io.sentry.protocol.SentryId
import io.sentry.protocol.SentryRuntime
import io.snyk.plugin.pluginSettings
import snyk.PropertyLoader
import snyk.common.isFedramp
import snyk.common.isAnalyticsPermitted
import snyk.pluginInfo

object SentryErrorReporter {
Expand Down Expand Up @@ -109,7 +109,7 @@ object SentryErrorReporter {
if (ApplicationManager.getApplication().isUnitTestMode) return SentryId.EMPTY_ID

val settings = pluginSettings()
return if (settings.crashReportingEnabled && !isFedramp()) {
return if (settings.crashReportingEnabled && isAnalyticsPermitted()) {
val sentryId = Sentry.captureException(throwable)
LOG.info("Sentry event reported: $sentryId")
sentryId
Expand Down
41 changes: 29 additions & 12 deletions src/test/kotlin/snyk/common/CustomEndpointsTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -174,12 +174,14 @@ class CustomEndpointsTest {

@Test
fun `api snyk path needs token`() {
var uri = "https://api.snyk.io/v1"
assertTrue(needsSnykToken(uri))
uri = "https://app.eu.snyk.io/api"
assertTrue(needsSnykToken(uri))
uri = "https://app.au.snyk.io/api"
assertTrue(needsSnykToken(uri))
val uris = listOf(
Copy link
Collaborator

Choose a reason for hiding this comment

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

nice refactor!

"https://api.snyk.io/v1",
"https://app.eu.snyk.io/api",
"https://app.au.snyk.io/api"
)
uris.forEach { uri ->
assertTrue(needsSnykToken(uri))
}
}

@Test
Expand All @@ -204,14 +206,29 @@ class CustomEndpointsTest {
}

@Test
fun `isFedramp true for the right URI`() {
val uri = URI("https://app.fedramp.snykgov.io")
assertTrue(uri.isFedramp())
fun `isAnalyticsPermitted false for URIs not allowed`() {
val uris = listOf(
"https://app.fedramp.snykgov.io",
"https://app.eu.snyk.io/api",
"https://app.au.snyk.io/api"
)
uris.forEach { uri ->
assertFalse(URI(uri).isAnalyticsPermitted())
}
}

@Test
fun `isFedramp false for the right URI`() {
val uri = URI("https://app.fedddramp.snykagov.io")
assertFalse(uri.isFedramp())
fun `isAnalyticsPermitted true for the right URIs`() {
val uris = listOf(
"https://snyk.io/api",
"https://app.snyk.io",
acke marked this conversation as resolved.
Show resolved Hide resolved
"https://app.us.snyk.io",
"https://app.snyk.io/api",
"https://app.snyk.io/v1"
)

uris.forEach { uri ->
assertTrue(URI(uri).isAnalyticsPermitted())
}
}
}
29 changes: 26 additions & 3 deletions src/test/kotlin/snyk/errorHandler/SentryErrorReporterTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,14 @@
import io.sentry.protocol.SentryId
import io.snyk.plugin.pluginSettings
import io.snyk.plugin.services.SnykApplicationSettingsStateService
import junit.framework.TestCase
import org.junit.After
import org.junit.Before
import org.junit.Test
import snyk.PluginInformation
import snyk.common.isAnalyticsPermitted
import snyk.pluginInfo
import java.net.URI

class SentryErrorReporterTest {
@Before
Expand Down Expand Up @@ -43,16 +46,36 @@
}

@Test
fun `captureException should not send exceptions to Sentry when crashReportingEnabled is true and fedramp`() {
fun `captureException should only report if permitted env`() {
val settings = mockPluginInformation()
setUnitTesting(false)
settings.crashReportingEnabled = true
settings.customEndpointUrl = "https://api.fedramp.snykgov.io"
acke marked this conversation as resolved.
Show resolved Hide resolved

val uris = listOf(
"https://app.fedramp.snykgov.io",
"https://app.eu.snyk.io/api",
"https://app.au.snyk.io/api"
)

uris.forEach { uri ->
settings.customEndpointUrl = uri

SentryErrorReporter.captureException(RuntimeException("test"))

verify(exactly = 0) { Sentry.captureException(any()) }
}
}
@Test
fun `captureException should send exceptions to Sentry when URL is a permitted environment`() {
val settings = mockPluginInformation()
setUnitTesting(false)
settings.crashReportingEnabled = true
settings.customEndpointUrl = "https://app.snyk.io"

SentryErrorReporter.captureException(RuntimeException("test"))

verify(exactly = 0) { Sentry.captureException(any()) }
verify(exactly = 1) { Sentry.captureException(any()) }
}

Check warning

Code scanning / detekt

Declarations and declarations with annotations should have an empty space between. Warning test

Declarations and declarations with annotations should have an empty space between.

@Test
fun `captureException should not send exceptions to Sentry when crashReportingEnabled is false`() {
Expand Down
Loading