mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IJPL-236763 Ensure TRACE data collection requires AI Assistant plugin
- Updated handling in GDPR consent UI to enforce TRACE data collection dependency on the availability of the AI Assistant plugin - Adjusted tests to verify forced disabling of TRACE consent when the AI Assistant plugin is unavailable or forcibly disabled - Added Mockito dependency for mocking plugin states in unit tests IJ-CR-194089 (cherry picked from commit 7284d71a054448d67c63e7d32ea59a65a612e8bd) GitOrigin-RevId: bae064b033e5ae8a0559dd0b6a483315fec69573
This commit is contained in:
committed by
intellij-monorepo-bot
parent
859db02320
commit
2ec242a01d
@@ -2738,6 +2738,7 @@ gdpr.ai.data.collection.consent.additional.notice.2=\
|
||||
Even if this setting is disabled, the AI Assistant plugin will send the data essential for this feature to large language model providers \
|
||||
and models hosted on JetBrains servers. If you work on a project where you don't want to share your data, you can disable the plugin.
|
||||
gdpr.consent.externally.disabled.warning=This option is disabled externally
|
||||
gdpr.consent.trace.requires.ai.assistant=This option requires the AI Assistant plugin
|
||||
gdpr.data.sharing.title.comment.text=Help shape the future of {0} products. By sharing your data and usage statistics, you allow us to better understand how you use our tools and how we can improve them. Learn more <a href="https://www.jetbrains.com/legal/docs/terms/product_data_collection/">here</a>.
|
||||
gdpr.data.collection.consent.setting.enabled.warning.text=Data collection has been enabled by your organization administrator.
|
||||
gdpr.data.collection.consent.setting.disabled.warning.text=Data collection has been disabled by your organization administrator.
|
||||
|
||||
@@ -63,8 +63,11 @@ final class ConsentOptionsProviderImpl implements ConsentOptionsProvider {
|
||||
return false;
|
||||
}
|
||||
AiDataCollectionExternalSettings settings = AiDataCollectionExternalSettings.findSettingsImplementedByAiAssistant();
|
||||
if (settings == null) {
|
||||
return false; // AIA plugin is required for TRACE data collection
|
||||
}
|
||||
boolean isAllowed = isTraceDataCollectionAllowedByMetadata(metadata);
|
||||
boolean isDisabled = settings != null && settings.isForciblyDisabled();
|
||||
boolean isDisabled = settings.isForciblyDisabled();
|
||||
return isAllowed && !isDisabled;
|
||||
}
|
||||
|
||||
|
||||
+13
@@ -2,8 +2,11 @@
|
||||
package com.intellij.ide.gdpr.ui.consents
|
||||
|
||||
import com.intellij.internal.statistic.utils.getPluginInfo
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.extensions.ExtensionPointName
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
|
||||
@ApiStatus.Internal
|
||||
interface AiDataCollectionExternalSettings {
|
||||
@@ -13,8 +16,18 @@ interface AiDataCollectionExternalSettings {
|
||||
|
||||
private const val AI_ASSISTANT_PLUGIN_ID = "com.intellij.ml.llm"
|
||||
|
||||
private var testOverride: AiDataCollectionExternalSettings? = null
|
||||
|
||||
@TestOnly
|
||||
@JvmStatic
|
||||
fun overrideForTest(settings: AiDataCollectionExternalSettings, parentDisposable: Disposable) {
|
||||
testOverride = settings
|
||||
Disposer.register(parentDisposable) { testOverride = null }
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun findSettingsImplementedByAiAssistant(): AiDataCollectionExternalSettings? {
|
||||
testOverride?.let { return it }
|
||||
return EP_NAME.findFirstSafe {
|
||||
val pluginInfo = getPluginInfo(it.javaClass)
|
||||
pluginInfo.isDevelopedByJetBrains() && pluginInfo.id == AI_ASSISTANT_PLUGIN_ID
|
||||
|
||||
+11
-9
@@ -22,15 +22,17 @@ internal class TraceDataCollectionConsentUI(
|
||||
if (LOG.isDebugEnabled) {
|
||||
LOG.debug("AiDataCollectionExternalSettings: $externalSettings")
|
||||
}
|
||||
if (externalSettings != null) {
|
||||
val isForciblyDisabled = externalSettings.isForciblyDisabled()
|
||||
if (LOG.isDebugEnabled) {
|
||||
LOG.debug("AiDataCollectionExternalSettings: isForciblyDisabled: ${isForciblyDisabled}")
|
||||
}
|
||||
if (isForciblyDisabled) {
|
||||
return ConsentForcedState.ExternallyDisabled(externalSettings.getForciblyDisabledDescription()
|
||||
?: IdeBundle.message("gdpr.consent.externally.disabled.warning"))
|
||||
}
|
||||
if (externalSettings == null) {
|
||||
// AIA plugin is required for TRACE data collection
|
||||
return ConsentForcedState.ExternallyDisabled(IdeBundle.message("gdpr.consent.trace.requires.ai.assistant"))
|
||||
}
|
||||
val isForciblyDisabled = externalSettings.isForciblyDisabled()
|
||||
if (LOG.isDebugEnabled) {
|
||||
LOG.debug("AiDataCollectionExternalSettings: isForciblyDisabled: $isForciblyDisabled")
|
||||
}
|
||||
if (isForciblyDisabled) {
|
||||
return ConsentForcedState.ExternallyDisabled(externalSettings.getForciblyDisabledDescription()
|
||||
?: IdeBundle.message("gdpr.consent.externally.disabled.warning"))
|
||||
}
|
||||
val dataCollectionAgreement = DataCollectionAgreement.getInstance()
|
||||
return when (dataCollectionAgreement) {
|
||||
|
||||
@@ -189,6 +189,7 @@ jvm_library(
|
||||
"//platform/platform-tests/eel-helper",
|
||||
"//platform/platform-impl/ui",
|
||||
"//platform/eel-provider",
|
||||
"//libraries/mockito",
|
||||
"@lib//:io-mockk",
|
||||
"@lib//:io-mockk-jvm",
|
||||
"//platform/bookmarks",
|
||||
|
||||
@@ -138,6 +138,7 @@
|
||||
<orderEntry type="module" module-name="intellij.platform.eelHelper" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.platform.ide.ui" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.platform.eel.provider" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.libraries.mockito" scope="TEST" />
|
||||
<orderEntry type="library" scope="TEST" name="io.mockk" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="io.mockk.jvm" level="project" />
|
||||
<orderEntry type="module" module-name="intellij.platform.bookmarks" scope="TEST" />
|
||||
|
||||
+39
-1
@@ -1,10 +1,13 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.ide.gdpr;
|
||||
|
||||
import com.intellij.ide.IdeBundle;
|
||||
import com.intellij.ide.gdpr.ui.consents.AiDataCollectionExternalSettings;
|
||||
import com.intellij.ide.gdpr.ui.consents.ConsentForcedState;
|
||||
import com.intellij.ide.gdpr.ui.consents.ConsentUi;
|
||||
import com.intellij.testFramework.fixtures.BasePlatformTestCase;
|
||||
import com.intellij.ui.LicensingFacade;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
public class DataCollectionConsentUiTest extends BasePlatformTestCase {
|
||||
private static final String CONSENT_ID_USAGE_STATS = "rsch.send.usage.stat";
|
||||
@@ -66,6 +69,10 @@ public class DataCollectionConsentUiTest extends BasePlatformTestCase {
|
||||
false, "en");
|
||||
ConsentUi ui = ConsentSettingsUi.getConsentUi(trace);
|
||||
|
||||
AiDataCollectionExternalSettings mockSettings = Mockito.mock(AiDataCollectionExternalSettings.class);
|
||||
Mockito.doReturn(false).when(mockSettings).isForciblyDisabled();
|
||||
AiDataCollectionExternalSettings.overrideForTest(mockSettings, getTestRootDisposable());
|
||||
|
||||
setupLicensingFacade('X');
|
||||
assertNull(ui.getForcedState());
|
||||
|
||||
@@ -81,4 +88,35 @@ public class DataCollectionConsentUiTest extends BasePlatformTestCase {
|
||||
assertInstanceOf(state, ConsentForcedState.AlwaysEnabled.class);
|
||||
assertEquals("Data collection has been enabled by your organization administrator.", state.getDescription());
|
||||
}
|
||||
}
|
||||
|
||||
public void testTraceConsentForcedDisabledWhenAiaPluginAbsent() {
|
||||
Consent trace = new Consent(CONSENT_ID_TRACE_DATA_COM_COLLECTION, Version.fromString("1.0"), "Send detailed code-related data", "text", false,
|
||||
false, "en");
|
||||
ConsentUi ui = ConsentSettingsUi.getConsentUi(trace);
|
||||
|
||||
for (char agreementChar : new char[]{'X', 'N', 'Y'}) {
|
||||
setupLicensingFacade(agreementChar);
|
||||
var state = ui.getForcedState();
|
||||
assertNotNull("TRACE consent must be force-disabled when AIA plugin is absent (agreement='" + agreementChar + "')", state);
|
||||
assertInstanceOf(state, ConsentForcedState.ExternallyDisabled.class);
|
||||
assertEquals(IdeBundle.message("gdpr.consent.trace.requires.ai.assistant"), state.getDescription());
|
||||
}
|
||||
}
|
||||
|
||||
public void testTraceConsentForcedDisabledWhenAiaForciblyDisabled() {
|
||||
Consent trace = new Consent(CONSENT_ID_TRACE_DATA_COM_COLLECTION, Version.fromString("1.0"), "Send detailed code-related data", "text", false,
|
||||
false, "en");
|
||||
ConsentUi ui = ConsentSettingsUi.getConsentUi(trace);
|
||||
|
||||
AiDataCollectionExternalSettings mockSettings = Mockito.mock(AiDataCollectionExternalSettings.class);
|
||||
Mockito.doReturn(true).when(mockSettings).isForciblyDisabled();
|
||||
Mockito.doReturn("Disabled by organization").when(mockSettings).getForciblyDisabledDescription();
|
||||
AiDataCollectionExternalSettings.overrideForTest(mockSettings, getTestRootDisposable());
|
||||
|
||||
setupLicensingFacade('X');
|
||||
var state = ui.getForcedState();
|
||||
assertNotNull(state);
|
||||
assertInstanceOf(state, ConsentForcedState.ExternallyDisabled.class);
|
||||
assertEquals("Disabled by organization", state.getDescription());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user