From 4c9a17c98e484e8545b1c7f2f6b51c840fd4c3b8 Mon Sep 17 00:00:00 2001 From: Angelo Buono Date: Wed, 29 Nov 2023 17:09:10 +0100 Subject: [PATCH] SONARKT-375 - Prepare for release (#389) * SONARKT-375 - Update dependencies, rules metadata, Detekt, AndroidLint and KtLint. * Raise available memory for build to 12G This should be a temporary measure, it seems that the updated Gradle scanner has issues with memory usage/management. --------- Co-authored-by: Johann Beleites --- .cirrus.yml | 2 +- build.gradle.kts | 13 +- gradle.properties | 2 +- its/plugin/build.gradle.kts | 2 +- .../org/sonarsource/slang/SonarLintTest.java | 8 +- .../org/sonarsource/slang/SurefireTest.java | 4 +- .../java/org/sonarsource/slang/TestBase.java | 4 +- .../java/org/sonarsource/slang/Tests.java | 7 +- its/ruling/build.gradle.kts | 2 +- .../sonarsource/slang/SlangRulingTest.java | 7 +- settings.gradle.kts | 49 +- .../l10n/android/rules/androidlint/rules.json | 320 +++++++--- .../sonar/l10n/kotlin/rules/ktlint/rules.json | 216 +++++++ .../AndroidLintRulesDefinitionTest.kt | 2 +- .../ktlint/KtlintRulesDefinitionTest.kt | 2 +- sonar-kotlin-plugin/sonarpedia.json | 2 +- .../sonar/l10n/kotlin/rules/kotlin/S1066.html | 30 +- .../sonar/l10n/kotlin/rules/kotlin/S1066.json | 2 +- .../sonar/l10n/kotlin/rules/kotlin/S1110.html | 18 +- .../sonar/l10n/kotlin/rules/kotlin/S1125.html | 17 +- .../sonar/l10n/kotlin/rules/kotlin/S1128.html | 75 ++- .../sonar/l10n/kotlin/rules/kotlin/S1128.json | 2 +- .../sonar/l10n/kotlin/rules/kotlin/S1135.html | 2 +- .../sonar/l10n/kotlin/rules/kotlin/S1144.html | 30 +- .../sonar/l10n/kotlin/rules/kotlin/S1144.json | 2 +- .../sonar/l10n/kotlin/rules/kotlin/S117.html | 58 +- .../sonar/l10n/kotlin/rules/kotlin/S1172.html | 5 +- .../sonar/l10n/kotlin/rules/kotlin/S1186.html | 33 +- .../sonar/l10n/kotlin/rules/kotlin/S1192.html | 22 +- .../sonar/l10n/kotlin/rules/kotlin/S125.html | 5 +- .../sonar/l10n/kotlin/rules/kotlin/S134.html | 12 +- .../sonar/l10n/kotlin/rules/kotlin/S1481.html | 40 +- .../sonar/l10n/kotlin/rules/kotlin/S1763.html | 1 + .../sonar/l10n/kotlin/rules/kotlin/S1871.html | 85 ++- .../sonar/l10n/kotlin/rules/kotlin/S1874.html | 28 +- .../sonar/l10n/kotlin/rules/kotlin/S2068.html | 1 - .../sonar/l10n/kotlin/rules/kotlin/S3329.html | 8 +- .../sonar/l10n/kotlin/rules/kotlin/S3353.html | 12 +- .../sonar/l10n/kotlin/rules/kotlin/S3776.html | 28 +- .../sonar/l10n/kotlin/rules/kotlin/S3776.json | 2 +- .../sonar/l10n/kotlin/rules/kotlin/S4347.html | 70 ++- .../sonar/l10n/kotlin/rules/kotlin/S4423.html | 5 +- .../sonar/l10n/kotlin/rules/kotlin/S4790.html | 1 - .../sonar/l10n/kotlin/rules/kotlin/S4790.json | 3 +- .../sonar/l10n/kotlin/rules/kotlin/S5322.html | 1 - .../sonar/l10n/kotlin/rules/kotlin/S5324.html | 4 +- .../sonar/l10n/kotlin/rules/kotlin/S5542.html | 1 - .../sonar/l10n/kotlin/rules/kotlin/S5547.html | 1 - .../sonar/l10n/kotlin/rules/kotlin/S6288.html | 6 +- .../sonar/l10n/kotlin/rules/kotlin/S6301.html | 102 +++- .../sonar/l10n/kotlin/rules/kotlin/S6432.html | 89 ++- .../sonar/l10n/kotlin/rules/kotlin/S6511.html | 4 +- utils-kotlin/README.md | 4 +- .../src/main/resources/android-lint-help.txt | 547 +++++++++++++++--- 54 files changed, 1588 insertions(+), 410 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index 75c4bcc82..88eda06b1 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -46,7 +46,7 @@ linux_3_5_cpu_7G_template: &LINUX_3_5_CPU_7G eks_container: <<: *LINUX_IMAGE cpu: 3.5 - memory: 7G + memory: 12G # TODO: decrease back to 7G when we fix the memory issues with the Gradle scanner linux_6_cpu_12G_java_17_template: &LINUX_6_CPU_12G_JAVA_17 eks_container: diff --git a/build.gradle.kts b/build.gradle.kts index 7ece088f6..8b50b1ff4 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,15 +1,14 @@ - import org.jetbrains.kotlin.gradle.tasks.KotlinCompile -import org.sonarsource.kotlin.buildsrc.tasks.CreateKotlinRuleStubsTask import org.sonarsource.kotlin.buildsrc.tasks.CreateKotlinGradleRuleStubsTask +import org.sonarsource.kotlin.buildsrc.tasks.CreateKotlinRuleStubsTask import org.sonarsource.kotlin.buildsrc.tasks.FetchRuleMetadata plugins { java id("jacoco") id("com.jfrog.artifactory") version "4.25.1" - id("io.spring.dependency-management") version "1.0.11.RELEASE" apply false - id("org.sonarqube") version "3.3" + id("io.spring.dependency-management") version "1.1.4" apply false + id("org.sonarqube") version "4.4.1.3373" id("org.jetbrains.kotlin.jvm") apply false id("com.diffplug.spotless") version "6.11.0" `maven-publish` @@ -18,7 +17,7 @@ plugins { val projectTitle: String by project -configure(subprojects.filter { it.name != "kotlin-checks-test-sources"}) { +configure(subprojects.filter { it.name != "kotlin-checks-test-sources" }) { apply(plugin = "com.diffplug.spotless") configure { @@ -168,13 +167,13 @@ subprojects { val sourcesJar by tasks.creating(Jar::class) { dependsOn(JavaPlugin.CLASSES_TASK_NAME) - classifier = "sources" + archiveClassifier.set("sources") from(sourceSets.main.get().allSource) } val javadocJar by tasks.creating(Jar::class) { dependsOn(javadoc) - classifier = "javadoc" + archiveClassifier.set("javadoc") from(tasks["javadoc"]) } diff --git a/gradle.properties b/gradle.properties index 5a40e501c..295e6d343 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,5 +2,5 @@ group=org.sonarsource.kotlin version=2.19-SNAPSHOT description=Code Analyzer for Kotlin projectTitle=Kotlin -kotlinVersion=1.9.0 +kotlinVersion=1.9.21 org.gradle.jvmargs=-Xmx4096M diff --git a/its/plugin/build.gradle.kts b/its/plugin/build.gradle.kts index c4c280aef..2637181c4 100644 --- a/its/plugin/build.gradle.kts +++ b/its/plugin/build.gradle.kts @@ -1,6 +1,6 @@ dependencies { testImplementation(testLibs.sonarlint.core) - testImplementation(testLibs.sonar.orchestrator) + testImplementation(testLibs.sonar.orchestrator.junit4) testImplementation(testLibs.assertj.core) testImplementation(testLibs.sonar.ws) testImplementation(libs.sonar.analyzer.commons) diff --git a/its/plugin/src/test/java/org/sonarsource/slang/SonarLintTest.java b/its/plugin/src/test/java/org/sonarsource/slang/SonarLintTest.java index 8fa91efaa..1b7a1eae5 100644 --- a/its/plugin/src/test/java/org/sonarsource/slang/SonarLintTest.java +++ b/its/plugin/src/test/java/org/sonarsource/slang/SonarLintTest.java @@ -19,8 +19,8 @@ */ package org.sonarsource.slang; -import com.sonar.orchestrator.Orchestrator; -import com.sonar.orchestrator.OrchestratorBuilder; +import com.sonar.orchestrator.junit4.OrchestratorRule; +import com.sonar.orchestrator.junit4.OrchestratorRuleBuilder; import com.sonar.orchestrator.locator.Locators; import java.io.File; import java.io.IOException; @@ -61,9 +61,9 @@ public class SonarLintTest { @BeforeClass public static void prepare() throws Exception { // Orchestrator is used only to retrieve plugin artifacts from filesystem or maven - OrchestratorBuilder orchestratorBuilder = Orchestrator.builderEnv(); + OrchestratorRuleBuilder orchestratorBuilder = OrchestratorRule.builderEnv(); Tests.addLanguagePlugins(orchestratorBuilder); - Orchestrator orchestrator = orchestratorBuilder + OrchestratorRule orchestrator = orchestratorBuilder .useDefaultAdminCredentialsForBuilds(true) .setSonarVersion(System.getProperty(Tests.SQ_VERSION_PROPERTY, Tests.DEFAULT_SQ_VERSION)) .build(); diff --git a/its/plugin/src/test/java/org/sonarsource/slang/SurefireTest.java b/its/plugin/src/test/java/org/sonarsource/slang/SurefireTest.java index 0c69b379c..2c2da2937 100644 --- a/its/plugin/src/test/java/org/sonarsource/slang/SurefireTest.java +++ b/its/plugin/src/test/java/org/sonarsource/slang/SurefireTest.java @@ -19,8 +19,8 @@ */ package org.sonarsource.slang; -import com.sonar.orchestrator.Orchestrator; import com.sonar.orchestrator.build.MavenBuild; +import com.sonar.orchestrator.junit4.OrchestratorRule; import java.io.File; import java.nio.file.Path; import java.nio.file.Paths; @@ -36,7 +36,7 @@ public class SurefireTest extends TestBase { @ClassRule - public static final Orchestrator ORCHESTRATOR = Tests.ORCHESTRATOR; + public static final OrchestratorRule ORCHESTRATOR = Tests.ORCHESTRATOR; private static final Path BASE_DIRECTORY = Paths.get("projects"); diff --git a/its/plugin/src/test/java/org/sonarsource/slang/TestBase.java b/its/plugin/src/test/java/org/sonarsource/slang/TestBase.java index 13dbdc9b2..864946c20 100644 --- a/its/plugin/src/test/java/org/sonarsource/slang/TestBase.java +++ b/its/plugin/src/test/java/org/sonarsource/slang/TestBase.java @@ -19,8 +19,8 @@ */ package org.sonarsource.slang; -import com.sonar.orchestrator.Orchestrator; import com.sonar.orchestrator.build.SonarScanner; +import com.sonar.orchestrator.junit4.OrchestratorRule; import java.io.File; import java.util.Arrays; import java.util.Collections; @@ -44,7 +44,7 @@ public abstract class TestBase { @ClassRule - public static final Orchestrator ORCHESTRATOR = Tests.ORCHESTRATOR; + public static final OrchestratorRule ORCHESTRATOR = Tests.ORCHESTRATOR; protected SonarScanner getSonarScanner(String projectKey, String directoryToScan, String languageKey) { return getSonarScanner(projectKey, directoryToScan, languageKey, null); diff --git a/its/plugin/src/test/java/org/sonarsource/slang/Tests.java b/its/plugin/src/test/java/org/sonarsource/slang/Tests.java index 2e17cb604..323e784da 100644 --- a/its/plugin/src/test/java/org/sonarsource/slang/Tests.java +++ b/its/plugin/src/test/java/org/sonarsource/slang/Tests.java @@ -19,8 +19,9 @@ */ package org.sonarsource.slang; -import com.sonar.orchestrator.Orchestrator; import com.sonar.orchestrator.OrchestratorBuilder; +import com.sonar.orchestrator.junit4.OrchestratorRule; +import com.sonar.orchestrator.junit4.OrchestratorRuleBuilder; import com.sonar.orchestrator.locator.FileLocation; import com.sonar.orchestrator.locator.Location; import com.sonar.orchestrator.locator.MavenLocation; @@ -48,10 +49,10 @@ public class Tests { private static final Set LANGUAGES = new HashSet<>(Collections.singletonList("kotlin")); @ClassRule - public static final Orchestrator ORCHESTRATOR; + public static final OrchestratorRule ORCHESTRATOR; static { - OrchestratorBuilder orchestratorBuilder = Orchestrator.builderEnv(); + OrchestratorRuleBuilder orchestratorBuilder = OrchestratorRule.builderEnv(); addLanguagePlugins(orchestratorBuilder); ORCHESTRATOR = orchestratorBuilder .useDefaultAdminCredentialsForBuilds(true) diff --git a/its/ruling/build.gradle.kts b/its/ruling/build.gradle.kts index 25ce9d6fb..1ad4172ab 100644 --- a/its/ruling/build.gradle.kts +++ b/its/ruling/build.gradle.kts @@ -4,7 +4,7 @@ plugins { } dependencies { - testImplementation(testLibs.sonar.orchestrator) + testImplementation(testLibs.sonar.orchestrator.junit4) testImplementation(testLibs.assertj.core) testImplementation(libs.sonar.analyzer.commons) } diff --git a/its/ruling/src/test/java/org/sonarsource/slang/SlangRulingTest.java b/its/ruling/src/test/java/org/sonarsource/slang/SlangRulingTest.java index 40203f9ee..ca37a2518 100644 --- a/its/ruling/src/test/java/org/sonarsource/slang/SlangRulingTest.java +++ b/its/ruling/src/test/java/org/sonarsource/slang/SlangRulingTest.java @@ -19,11 +19,12 @@ */ package org.sonarsource.slang; -import com.sonar.orchestrator.Orchestrator; import com.sonar.orchestrator.OrchestratorBuilder; import com.sonar.orchestrator.build.Build; import com.sonar.orchestrator.build.GradleBuild; import com.sonar.orchestrator.build.SonarScanner; +import com.sonar.orchestrator.junit4.OrchestratorRule; +import com.sonar.orchestrator.junit4.OrchestratorRuleBuilder; import com.sonar.orchestrator.locator.FileLocation; import com.sonar.orchestrator.locator.Location; import com.sonar.orchestrator.locator.MavenLocation; @@ -56,7 +57,7 @@ public class SlangRulingTest { private static final String SQ_VERSION_PROPERTY = "sonar.runtimeVersion"; private static final String DEFAULT_SQ_VERSION = "LATEST_RELEASE"; - private static Orchestrator orchestrator; + private static OrchestratorRule orchestrator; private static boolean keepSonarqubeRunning = "true".equals(System.getProperty("keepSonarqubeRunning")); private static final boolean IGNORE_EXPECTED_ISSUES_AND_REPORT_ALL = "true".equals(System.getProperty("reportAll")); private static final boolean CLEAN_PROJECT_BINARIES = "true".equals(System.getProperty("cleanProjects")); @@ -64,7 +65,7 @@ public class SlangRulingTest { @BeforeClass public static void setUp() { - OrchestratorBuilder builder = Orchestrator.builderEnv() + OrchestratorRuleBuilder builder = OrchestratorRule.builderEnv() .useDefaultAdminCredentialsForBuilds(true) .setSonarVersion(System.getProperty(SQ_VERSION_PROPERTY, DEFAULT_SQ_VERSION)) .addPlugin(MavenLocation.of("org.sonarsource.sonar-lits-plugin", "sonar-lits-plugin", "0.11.0.2659")); diff --git a/settings.gradle.kts b/settings.gradle.kts index a2befc493..c35974177 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -36,55 +36,56 @@ dependencyResolutionManagement { versionCatalogs { val kotlinVersion: String by extra - val analyzerCommonsVersionStr = "2.7.0.1482" - val sonarPluginApi = "10.1.0.809" + val analyzerCommonsVersionStr = "2.8.0.2593" + val sonarPluginApi = "10.4.0.1999" val slf4jApi = "1.7.30" create("libs") { val analyzerCommons = version("analyzerCommons", analyzerCommonsVersionStr) - val gson = version("gson", "2.9.0") - val staxmate = version("staxmate", "2.4.0") + val gson = version("gson", "2.10.1") + val staxmate = version("staxmate", "2.4.1") val gradleToolingApi = version("gradle-tooling-api", "7.5.1") library("gson", "com.google.code.gson", "gson").versionRef(gson) library("kotlin-compiler-embeddable", "org.jetbrains.kotlin", "kotlin-compiler-embeddable").version(kotlinVersion) library("sonar-analyzer-commons", "org.sonarsource.analyzer-commons", "sonar-analyzer-commons").versionRef(analyzerCommons) - library("sonar-analyzer-commons-recognizers", "org.sonarsource.analyzer-commons", "sonar-analyzer-recognizers").versionRef(analyzerCommons) - library("sonar-performance-measure", "org.sonarsource.analyzer-commons", "sonar-performance-measure").versionRef(analyzerCommons) + library("sonar-analyzer-commons-recognizers", "org.sonarsource.analyzer-commons", "sonar-analyzer-recognizers") + .versionRef(analyzerCommons) + library("sonar-performance-measure", "org.sonarsource.analyzer-commons", "sonar-performance-measure") + .versionRef(analyzerCommons) library("sonar-plugin-api", "org.sonarsource.api.plugin", "sonar-plugin-api").version(sonarPluginApi) library("slf4j-api", "org.slf4j", "slf4j-api").version(slf4jApi) library("sonar-regex-parsing", "org.sonarsource.analyzer-commons", "sonar-regex-parsing").versionRef(analyzerCommons) library("sonar-xml-parsing", "org.sonarsource.analyzer-commons", "sonar-xml-parsing").versionRef(analyzerCommons) library("staxmate", "com.fasterxml.staxmate", "staxmate").versionRef(staxmate) - library("gradle-tooling-api","org.gradle", "gradle-tooling-api").versionRef(gradleToolingApi) + library("gradle-tooling-api", "org.gradle", "gradle-tooling-api").versionRef(gradleToolingApi) } create("utilLibs") { - val detekt = version("detekt", "1.23.0") - val jcommander = version("jcommander", "1.81") - val ktlint = version("ktlint", "0.49.1") + val detekt = version("detekt", "1.23.3") + val jcommander = version("jcommander", "1.82") + val ktlint = version("ktlint", "1.0.1") library("detekt-api", "io.gitlab.arturbosch.detekt", "detekt-api").versionRef(detekt) library("detekt-cli", "io.gitlab.arturbosch.detekt", "detekt-cli").versionRef(detekt) library("detekt-core", "io.gitlab.arturbosch.detekt", "detekt-core").versionRef(detekt) library("jcommander", "com.beust", "jcommander").versionRef(jcommander) - library("ktlint", "com.pinterest", "ktlint").versionRef(ktlint) - library("ktlint-core", "com.pinterest.ktlint", "ktlint-core").versionRef(ktlint) + library("ktlint-core", "com.pinterest.ktlint", "ktlint-rule-engine-core").versionRef(ktlint) library("ktlint-ruleset-standard", "com.pinterest.ktlint", "ktlint-ruleset-standard").versionRef(ktlint) bundle("detekt", listOf("detekt-cli", "detekt-core", "detekt-api")) - bundle("ktlint", listOf("ktlint", "ktlint-core", "ktlint-ruleset-standard")) + bundle("ktlint", listOf("ktlint-core", "ktlint-ruleset-standard")) } create("testLibs") { val analyzerCommons = version("analyzerCommons", analyzerCommonsVersionStr) - val assertj = version("assertj", "3.23.1") - val classgraph = version("classgraph", "4.8.149") - val junit = version("junit", "5.8.2") - val mockito = version("mockito", "4.6.1") - val mockk = version("mockk", "1.12.4") - val orchestrator = version("orchestrator", "3.40.0.183") - val sonarlint = version("sonarlint", "8.16.0.67686") + val assertj = version("assertj", "3.24.2") + val classgraph = version("classgraph", "4.8.165") + val junit = version("junit", "5.10.1") + val mockito = version("mockito", "5.7.0") + val mockk = version("mockk", "1.13.3") + val orchestrator = version("orchestrator", "4.5.0.1682") + val sonarlint = version("sonarlint", "9.5.0.76302") val sonarqube = version("sonarqube", "10.0.0.68432") library("assertj-core", "org.assertj", "assertj-core").versionRef(assertj) @@ -94,10 +95,12 @@ dependencyResolutionManagement { library("junit-params", "org.junit.jupiter", "junit-jupiter-params").versionRef(junit) library("mockito-core", "org.mockito", "mockito-core").versionRef(mockito) library("mockk", "io.mockk", "mockk").versionRef(mockk) - library("sonar-analyzer-test-commons", "org.sonarsource.analyzer-commons", "sonar-analyzer-test-commons").versionRef(analyzerCommons) - library("sonar-orchestrator", "org.sonarsource.orchestrator", "sonar-orchestrator").versionRef(orchestrator) + library("sonar-analyzer-test-commons", "org.sonarsource.analyzer-commons", "sonar-analyzer-test-commons") + .versionRef(analyzerCommons) + library("sonar-orchestrator-junit4", "org.sonarsource.orchestrator", "sonar-orchestrator-junit4").versionRef(orchestrator) library("sonar-plugin-api-impl", "org.sonarsource.sonarqube", "sonar-plugin-api-impl").versionRef(sonarqube) - library("sonar-plugin-api-test-fixtures", "org.sonarsource.api.plugin", "sonar-plugin-api-test-fixtures").version(sonarPluginApi) + library("sonar-plugin-api-test-fixtures", "org.sonarsource.api.plugin", "sonar-plugin-api-test-fixtures") + .version(sonarPluginApi) library("sonar-ws", "org.sonarsource.sonarqube", "sonar-ws").versionRef(sonarqube) library("sonarlint-core", "org.sonarsource.sonarlint.core", "sonarlint-core").versionRef(sonarlint) } diff --git a/sonar-kotlin-external-linters/src/main/resources/org/sonar/l10n/android/rules/androidlint/rules.json b/sonar-kotlin-external-linters/src/main/resources/org/sonar/l10n/android/rules/androidlint/rules.json index 973d36dcb..550216c50 100644 --- a/sonar-kotlin-external-linters/src/main/resources/org/sonar/l10n/android/rules/androidlint/rules.json +++ b/sonar-kotlin-external-linters/src/main/resources/org/sonar/l10n/android/rules/androidlint/rules.json @@ -13,7 +13,7 @@ { "key": "AcceptsUserCertificates", "name": "Allowing User Certificates", - "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nAllowing user certificates could allow eavesdroppers to intercept data sent by\nyour app, 'which could impact the privacy of your users. Consider nesting your\napp's trust-anchors inside a <debug-overrides> element to make sure they are\nonly available when android:debuggable is set to "true".\n

\n

\nMore information:
\nhttps://developer.android.com/training/articles/security-config#TrustingDebugCa
\n

\n", + "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nAllowing user certificates could allow eavesdroppers to intercept data sent by\nyour app, 'which could impact the privacy of your users. Consider nesting your\napp's trust-anchors inside a <debug-overrides> element to make sure they are\nonly available when android:debuggable is set to "true".\n

\n

\nMore information:
\nhttps://goo.gle/AcceptsUserCertificates
\nhttps://developer.android.com/training/articles/security-config#TrustingDebugCa\n

\n", "tags": [ "security", "android" @@ -47,7 +47,7 @@ { "key": "AddJavascriptInterface", "name": "addJavascriptInterface Called", - "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nFor applications built for API levels below 17, WebView#addJavascriptInterface\npresents a security hazard as JavaScript on the target web page has the\nability to use reflection to access the injected object's public fields and\nthus manipulate the host application in unintended ways.\n

\n

\nMore information:
\nhttps://developer.android.com/reference/android/webkit/WebView.html#addJavascriptInterface(java.lang.Object,%20java.lang.String)
\nhttps://support.google.com/faqs/answer/9095419?hl=en\n

\n", + "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nFor applications built for API levels below 17, WebView#addJavascriptInterface\npresents a security hazard as JavaScript on the target web page has the\nability to use reflection to access the injected object's public fields and\nthus manipulate the host application in unintended ways.\n

\n

\nMore information:
\nhttps://developer.android.com/reference/android/webkit/WebView.html#addJavascriptInterface(java.lang.Object,%20java.lang.String)
\nhttps://support.google.com/faqs/answer/9095419?hl=en\nhttps://goo.gle/AddJavascriptInterface\n

\n", "tags": [ "security", "android" @@ -71,7 +71,7 @@ { "key": "AllowAllHostnameVerifier", "name": "Insecure HostnameVerifier", - "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nThis check looks for use of HostnameVerifier implementations whose verify\nmethod always returns true (thus trusting any hostname) which could result in\ninsecure network traffic caused by trusting arbitrary hostnames in TLS/SSL\ncertificates presented by peers.\n

\n

\n

\n", + "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nThis check looks for use of HostnameVerifier implementations whose verify\nmethod always returns true (thus trusting any hostname) which could result in\ninsecure network traffic caused by trusting arbitrary hostnames in TLS/SSL\ncertificates presented by peers.\n

\n

\nMore information:
\nhttps://goo.gle/AllowAllHostnameVerifier
\n

\n", "tags": [ "security", "android" @@ -278,7 +278,7 @@ { "key": "BadHostnameVerifier", "name": "Insecure HostnameVerifier", - "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nThis check looks for implementations of HostnameVerifier whose verify method\nalways returns true (thus trusting any hostname) which could result in\ninsecure network traffic caused by trusting arbitrary hostnames in TLS/SSL\ncertificates presented by peers.\n

\n

\n

\n", + "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nThis check looks for implementations of HostnameVerifier whose verify method\nalways returns true (thus trusting any hostname) which could result in\ninsecure network traffic caused by trusting arbitrary hostnames in TLS/SSL\ncertificates presented by peers.\n

\n

\nMore information:
\nhttps://goo.gle/BadHostnameVerifier
\n

\n", "tags": [ "security", "android" @@ -310,6 +310,18 @@ "severity": "MAJOR", "constantDebtMinutes": 5 }, + { + "key": "BinderGetCallingInMainThread", + "name": "Incorrect usage of getCallingUid() or getCallingPid()", + "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nBinder.getCallingUid() and Binder.getCallingPid() will return information\nabout the current process if called inside a thread that is not handling a\nbinder transaction. This can cause security issues. If you still want to use\nyour own uid/pid, use Process.myUid() or Process.myPid().\n

\n

\n

\n", + "tags": [ + "security", + "android" + ], + "type": "BUG", + "severity": "MAJOR", + "constantDebtMinutes": 5 + }, { "key": "BlockedPrivateApi", "name": "Using Blocked Private API", @@ -321,6 +333,17 @@ "severity": "CRITICAL", "constantDebtMinutes": 5 }, + { + "key": "BomWithoutPlatform", + "name": "Using a BOM without platform call", + "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nWhen including a BOM, the dependency's coordinates must be wrapped in a call\nto platform() for Gradle to interpret it correctly.\n

\n

\nMore information:
\nhttps://developer.android.com/r/tools/gradle-bom-docs
\n

\n", + "tags": [ + "android" + ], + "type": "CODE_SMELL", + "severity": "MINOR", + "constantDebtMinutes": 5 + }, { "key": "BottomAppBar", "name": "BottomAppBar Problems", @@ -405,7 +428,29 @@ { "key": "CheckResult", "name": "Ignoring results", - "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nSome methods have no side effects, and calling them without doing something\nwithout the result is suspicious.\n

\n

\n

\n", + "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nSome methods have no side effects, and calling them without doing something\nwith the result is suspicious.\n

\n

\n

\n", + "tags": [ + "android" + ], + "type": "CODE_SMELL", + "severity": "MINOR", + "constantDebtMinutes": 5 + }, + { + "key": "ChromeOsAbiSupport", + "name": "Missing ABI Support for ChromeOS", + "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nTo properly support ChromeOS, your Android application should have an x86\nand/or x86_64 binary as part of the build configuration. To fix the issue,\nensure your files are properly optimized for ARM; the binary translator will\nthen ensure compatibility with x86. Alternatively, add an abiSplit for x86\nwithin your build.gradle file and create the required x86 dependencies.\n

\n

\nMore information:
\nhttps://developer.android.com/ndk/guides/abis
\n

\n", + "tags": [ + "android" + ], + "type": "CODE_SMELL", + "severity": "MINOR", + "constantDebtMinutes": 5 + }, + { + "key": "ChromeOsOnConfigurationChanged", + "name": "Poor performance with APIs inside onConfigurationChanged()", + "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nWhen users resize the Android emulator in Android 13 and Chrome OS, an\nonConfigurationChanged() API call occurs. If your onConfigurationChanged()\nmethod contains any code that can cause a redraw, your app might take a\nperformance hit on large screens. To fix the issue, ensure your\nonConfigurationChanged() method does not contain any calls to UI redraw logic\nfor specific elements.\n

\n

\n

\n", "tags": [ "android" ], @@ -473,7 +518,7 @@ { "key": "ContentDescription", "name": "Image without contentDescription", - "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nNon-textual widgets like ImageViews and ImageButtons should use the\ncontentDescription attribute to specify a textual description of the widget\nsuch that screen readers and other accessibility tools can adequately describe\nthe user interface.\n

\n

\nNote that elements in application screens that are purely decorative and do\nnot provide any content or enable a user action should not have accessibility\ncontent descriptions. In this case, just suppress the lint warning with a\ntools:ignore="ContentDescription" attribute.\n

\n

\nNote that for text fields, you should not set both the hint and the\ncontentDescription attributes since the hint will never be shown. Just set the\nhint.\n

\n

\nMore information:
\nhttps://developer.android.com/guide/topics/ui/accessibility/apps#special-cases
\n

\n", + "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nNon-textual widgets like ImageViews and ImageButtons should use the\ncontentDescription attribute to specify a textual description of the widget\nsuch that screen readers and other accessibility tools can adequately describe\nthe user interface.\n

\n

\nNote that elements in application screens that are purely decorative and do\nnot provide any content or enable a user action should not have accessibility\ncontent descriptions. In this case, set their descriptions to @null. If your\napp's minSdkVersion is 16 or higher, you can instead set these graphical\nelements' android:importantForAccessibility attributes to no.\n

\n

\nNote that for text fields, you should not set both the hint and the\ncontentDescription attributes since the hint will never be shown. Just set the\nhint.\n

\n

\nMore information:
\nhttps://developer.android.com/guide/topics/ui/accessibility/apps#special-cases
\n

\n", "tags": [ "accessibility", "android" @@ -497,7 +542,7 @@ { "key": "CustomPermissionTypo", "name": "Permission appears to be a custom permission with a typo", - "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nThis check looks for required permissions that look like custom permissions\ndefined in the same manifest, but aren't, and may be typos.\n

\n

\nPlease double check the permission value you have supplied.\n

\n

\n

\n", + "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nThis check looks for required permissions that look like custom permissions\ndefined in the same manifest, but aren't, and may be typos.\n

\n

\nPlease double check the permission value you have supplied.\n

\n

\nMore information:
\nhttps://goo.gle/CustomPermissionTypo
\n

\n", "tags": [ "security", "android" @@ -531,7 +576,7 @@ { "key": "CustomX509TrustManager", "name": "Implements custom TLS trust manager", - "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nThis check looks for custom X509TrustManager implementations.\n

\n

\n

\n", + "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nThis check looks for custom X509TrustManager implementations.\n

\n

\nMore information:
\nhttps://goo.gle/CustomX509TrustManager
\n

\n", "tags": [ "security", "android" @@ -576,7 +621,7 @@ { "key": "DataExtractionRules", "name": "Missing data extraction rules", - "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nBefore Android 12, the attributes android:allowBackup and\nandroid:fullBackupContent were used to configure all forms of backup,\nincluding cloud backups, device-to-device transfers and adb backup.\n

\n

\nIn Android 12 and higher, these attributes have been deprecated and will only\napply to cloud backups. You should instead use the attribute\nandroid:dataExtractionRules, specifying an @xml resource that configures which\nfiles to back up, for cloud backups and for device-to-device transfers,\nseparately. If your minSdkVersion supports older versions, you'll still want\nto specify an android:fullBackupContent resource if the default behavior is\nnot right for your app.\n

\n

\nMore information:
\nhttps://developer.android.com/about/versions/12/backup-restore#xml-changes
\n

\n", + "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nBefore Android 12, the attributes android:allowBackup and\nandroid:fullBackupContent were used to configure all forms of backup,\nincluding cloud backups, device-to-device transfers and adb backup.\n

\n

\nIn Android 12 and higher, these attributes have been deprecated and will only\napply to cloud backups. You should instead use the attribute\nandroid:dataExtractionRules, specifying an @xml resource that configures which\nfiles to back up, for cloud backups and for device-to-device transfers,\nseparately. If your minSdkVersion supports older versions, you'll still want\nto specify an android:fullBackupContent resource if the default behavior is\nnot right for your app.\n

\n

\nMore information:
\nhttps://developer.android.com/about/versions/12/backup-restore#xml-changes
\nhttps://goo.gle/DataExtractionRules\n

\n", "tags": [ "security", "android" @@ -610,7 +655,7 @@ { "key": "DeletedProvider", "name": "Using Deleted Provider", - "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nThe Crypto provider has been completely removed in Android P (and was\ndeprecated in an earlier release). This means that the code will throw a\nNoSuchProviderException and the app will crash. Even if the code catches that\nexception at a higher level, this is not secure and should not be used.\n

\n

\nMore information:
\nhttps://android-developers.googleblog.com/2018/03/cryptography-changes-in-android-p.html
\n

\n", + "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nThe Crypto provider has been completely removed in Android P (and was\ndeprecated in an earlier release). This means that the code will throw a\nNoSuchProviderException and the app will crash. Even if the code catches that\nexception at a higher level, this is not secure and should not be used.\n

\n

\nMore information:
\nhttps://android-developers.googleblog.com/2018/03/cryptography-changes-in-android-p.html
\nhttps://goo.gle/DeletedProvider\n

\n", "tags": [ "security", "android" @@ -633,7 +678,7 @@ { "key": "DeprecatedProvider", "name": "Using BC Provider", - "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nThe BC provider has been deprecated and will not be provided when\ntargetSdkVersion is P or higher.\n

\n

\nMore information:
\nhttps://android-developers.googleblog.com/2018/03/cryptography-changes-in-android-p.html
\n

\n", + "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nThe BC provider has been deprecated and will not be provided when\ntargetSdkVersion is P or higher.\n

\n

\nMore information:
\nhttps://android-developers.googleblog.com/2018/03/cryptography-changes-in-android-p.html
\nhttps://goo.gle/DeprecatedProvider\n

\n", "tags": [ "security", "android" @@ -835,6 +880,17 @@ "severity": "MINOR", "constantDebtMinutes": 5 }, + { + "key": "EditedTargetSdkVersion", + "name": "Manually Edited TargetSdkVersion", + "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nUpdating the targetSdkVersion of an app is seemingly easy: just increment the\ntargetSdkVersion number in the manifest file!\n

\n

\nBut that's not actually safe. The targetSdkVersion controls a wide range of\nbehaviors that change from release to release, and to update, you should\ncarefully consult the documentation to see what has changed, how your app may\nneed to adjust, and then of course, carefully test everything.\n

\n

\nIn new versions of Android Studio, there is a special migration assistant,\navailable from the tools menu (and as a quickfix from this lint warning) which\nanalyzes your specific app and filters the set of applicable migration steps\nto those needed for your app.\n

\n

\nThis lint check does something very simple: it just detects whether it looks\nlike you've manually edited the targetSdkVersion field in a build.gradle file.\nObviously, as part of doing the above careful steps, you may end up editing\nthe value, which would trigger the check -- and it's safe to ignore it; this\nlint check only runs in the IDE, not from the command line; it's sole purpose\nto bring awareness to the (many) developers who haven't been aware of this\nissue and have just bumped the targetSdkVersion, recompiled, and uploaded\ntheir updated app to the Google Play Store, sometimes leading to crashes or\nother problems on newer devices.\n

\n

\n

\n", + "tags": [ + "android" + ], + "type": "CODE_SMELL", + "severity": "MAJOR", + "constantDebtMinutes": 5 + }, { "key": "EllipsizeMaxLines", "name": "Combining Ellipsize and Maxlines", @@ -880,6 +936,17 @@ "severity": "MINOR", "constantDebtMinutes": 5 }, + { + "key": "ExactAlarm", + "name": "Invalid Usage of Exact Alarms", + "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nThe USE_EXACT_ALARM permission is only available when targeting API level 33\nand above. Also, note that this permission is only permitted for apps whose\ncore functionality requires precisely-timed actions for user facing features.\n

\n

\nMore information:
\nhttps://developer.android.com/training/scheduling/alarms
\n

\n", + "tags": [ + "android" + ], + "type": "BUG", + "severity": "MAJOR", + "constantDebtMinutes": 5 + }, { "key": "ExifInterface", "name": "Using android.media.ExifInterface", @@ -930,7 +997,7 @@ { "key": "ExportedContentProvider", "name": "Content provider does not require permission", - "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nContent providers are exported by default and any application on the system\ncan potentially use them to read and write data. If the content provider\nprovides access to sensitive data, it should be protected by specifying\nexport=false in the manifest or by protecting it with a permission that can be\ngranted to other applications.\n

\n

\n

\n", + "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nContent providers are exported by default and any application on the system\ncan potentially use them to read and write data. If the content provider\nprovides access to sensitive data, it should be protected by specifying\nexport=false in the manifest or by protecting it with a permission that can be\ngranted to other applications.\n

\n

\nMore information:
\nhttps://goo.gle/ExportedContentProvider
\n

\n", "tags": [ "security", "android" @@ -942,7 +1009,7 @@ { "key": "ExportedPreferenceActivity", "name": "PreferenceActivity should not be exported", - "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nFragment injection gives anyone who can send your PreferenceActivity an intent\nthe ability to load any fragment, with any arguments, in your process.\n

\n

\nMore information:
\nhttp://securityintelligence.com/new-vulnerability-android-framework-fragment-injection
\n

\n", + "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nFragment injection gives anyone who can send your PreferenceActivity an intent\nthe ability to load any fragment, with any arguments, in your process.\n

\n

\nMore information:
\nhttp://securityintelligence.com/new-vulnerability-android-framework-fragment-injection
\nhttps://goo.gle/ExportedPreferenceActivity\n

\n", "tags": [ "security", "android" @@ -954,7 +1021,7 @@ { "key": "ExportedReceiver", "name": "Receiver does not require permission", - "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nExported receivers (receivers which either set exported=true or contain an\nintent-filter and do not specify exported=false) should define a permission\nthat an entity must have in order to launch the receiver or bind to it.\nWithout this, any application can use this receiver.\n

\n

\n

\n", + "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nExported receivers (receivers which either set exported=true or contain an\nintent-filter and do not specify exported=false) should define a permission\nthat an entity must have in order to launch the receiver or bind to it.\nWithout this, any application can use this receiver.\n

\n

\nMore information:
\nhttps://goo.gle/ExportedReceiver
\n

\n", "tags": [ "security", "android" @@ -966,7 +1033,7 @@ { "key": "ExportedService", "name": "Exported service does not require permission", - "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nExported services (services which either set exported=true or contain an\nintent-filter and do not specify exported=false) should define a permission\nthat an entity must have in order to launch the service or bind to it. Without\nthis, any application can use this service.\n

\n

\n

\n", + "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nExported services (services which either set exported=true or contain an\nintent-filter and do not specify exported=false) should define a permission\nthat an entity must have in order to launch the service or bind to it. Without\nthis, any application can use this service.\n

\n

\nMore information:
\nhttps://goo.gle/ExportedService
\n

\n", "tags": [ "security", "android" @@ -1067,7 +1134,7 @@ { "key": "GetInstance", "name": "Cipher.getInstance with ECB", - "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nCipher#getInstance should not be called with ECB as the cipher mode or without\nsetting the cipher mode because the default mode on android is ECB, which is\ninsecure.\n

\n

\n

\n", + "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nCipher#getInstance should not be called with ECB as the cipher mode or without\nsetting the cipher mode because the default mode on android is ECB, which is\ninsecure.\n

\n

\nMore information:
\nhttps://goo.gle/GetInstance
\n

\n", "tags": [ "security", "android" @@ -1212,7 +1279,7 @@ { "key": "GrantAllUris", "name": "Content provider shares everything", - "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nThe <grant-uri-permission> element allows specific paths to be shared. This\ndetector checks for a path URL of just '/' (everything), which is probably not\nwhat you want; you should limit access to a subset.\n

\n

\n

\n", + "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nThe <grant-uri-permission> element allows specific paths to be shared. This\ndetector checks for a path URL of just '/' (everything), which is probably not\nwhat you want; you should limit access to a subset.\n

\n

\nMore information:
\nhttps://goo.gle/GrantAllUris
\n

\n", "tags": [ "security", "android" @@ -1258,7 +1325,7 @@ { "key": "HardcodedDebugMode", "name": "Hardcoded value of android:debuggable in the manifest", - "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nIt's best to leave out the android:debuggable attribute from the manifest. If\nyou do, then the tools will automatically insert android:debuggable=true when\nbuilding an APK to debug on an emulator or device. And when you perform a\nrelease build, such as Exporting APK, it will automatically set it to false.\n

\n

\nIf on the other hand you specify a specific value in the manifest file, then\nthe tools will always use it. This can lead to accidentally publishing your\napp with debug information.\n

\n

\n

\n", + "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nIt's best to leave out the android:debuggable attribute from the manifest. If\nyou do, then the tools will automatically insert android:debuggable=true when\nbuilding an APK to debug on an emulator or device. And when you perform a\nrelease build, such as Exporting APK, it will automatically set it to false.\n

\n

\nIf on the other hand you specify a specific value in the manifest file, then\nthe tools will always use it. This can lead to accidentally publishing your\napp with debug information.\n

\n

\nMore information:
\nhttps://goo.gle/HardcodedDebugMode
\n

\n", "tags": [ "security", "android" @@ -1628,7 +1695,7 @@ { "key": "InsecureBaseConfiguration", "name": "Insecure Base Configuration", - "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nPermitting cleartext traffic could allow eavesdroppers to intercept data sent\nby your app, which impacts the privacy of your users. Consider only allowing\nencrypted traffic by setting the cleartextTrafficPermitted tag to "false".\n

\n

\nMore information:
\nhttps://developer.android.com/preview/features/security-config.html
\n

\n", + "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nPermitting cleartext traffic could allow eavesdroppers to intercept data sent\nby your app, which impacts the privacy of your users. Consider only allowing\nencrypted traffic by setting the cleartextTrafficPermitted tag to "false".\n

\n

\nMore information:
\nhttps://goo.gle/InsecureBaseConfiguration
\nhttps://developer.android.com/preview/features/security-config.html\n

\n", "tags": [ "security", "android" @@ -1662,7 +1729,7 @@ { "key": "IntentFilterExportedReceiver", "name": "Unspecified android:exported in manifest", - "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nApps targeting Android 12 and higher are required to specify an explicit value\nfor android:exported when the corresponding component has an intent filter\ndefined. Otherwise, installation will fail. Set it to true to make this\nactivity accessible to other apps, and false to limit it to be used only by\nthis app or the OS. For launch activities, this should be set to true;\notherwise, the app will fail to launch.\n

\n

\nPreviously, android:exported for components without any intent filters present\nused to default to false, and when intent filters were present, the default\nwas true. Defaults which change value based on other values are confusing and\nlead to apps accidentally exporting components as a side-effect of adding\nintent filters. This is a security risk, and we have made this change to avoid\nintroducing accidental vulnerabilities.\n

\n

\nWhile the default without intent filters remains unchanged, it is now required\nto explicitly specify a value when intent filters are present. Any app failing\nto meet this requirement will fail to install on any Android version after\nAndroid 11.\n

\n

\nWe recommend setting android:exported to false (even on previous versions of\nAndroid prior to this requirement) unless you have a good reason to export a\nparticular component.\n

\n

\n

\n", + "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nApps targeting Android 12 and higher are required to specify an explicit value\nfor android:exported when the corresponding component has an intent filter\ndefined. Otherwise, installation will fail. Set it to true to make this\nactivity accessible to other apps, and false to limit it to be used only by\nthis app or the OS. For launch activities, this should be set to true;\notherwise, the app will fail to launch.\n

\n

\nPreviously, android:exported for components without any intent filters present\nused to default to false, and when intent filters were present, the default\nwas true. Defaults which change value based on other values are confusing and\nlead to apps accidentally exporting components as a side-effect of adding\nintent filters. This is a security risk, and we have made this change to avoid\nintroducing accidental vulnerabilities.\n

\n

\nWhile the default without intent filters remains unchanged, it is now required\nto explicitly specify a value when intent filters are present. Any app failing\nto meet this requirement will fail to install on any Android version after\nAndroid 11.\n

\n

\nWe recommend setting android:exported to false (even on previous versions of\nAndroid prior to this requirement) unless you have a good reason to export a\nparticular component.\n

\n

\nMore information:
\nhttps://goo.gle/IntentFilterExportedReceiver
\n

\n", "tags": [ "security", "android" @@ -1841,7 +1908,7 @@ { "key": "JavascriptInterface", "name": "Missing @JavascriptInterface on methods", - "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nAs of API 17, you must annotate methods in objects registered with the\naddJavascriptInterface method with a @JavascriptInterface annotation.\n

\n

\nMore information:
\nhttps://developer.android.com/reference/android/webkit/WebView.html#addJavascriptInterface(java.lang.Object, java.lang.String)\n

\n", + "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nAs of API 17, you must annotate methods in objects registered with the\naddJavascriptInterface method with a @JavascriptInterface annotation.\n

\n

\nMore information:
\nhttps://developer.android.com/reference/android/webkit/WebView.html#addJavascriptInterface(java.lang.Object, java.lang.String)\nhttps://goo.gle/JavascriptInterface\n

\n", "tags": [ "security", "android" @@ -1872,6 +1939,18 @@ "severity": "MINOR", "constantDebtMinutes": 5 }, + { + "key": "KaptUsageInsteadOfKsp", + "name": "Kapt usage should be replaced with KSP", + "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nKSP is a more efficient replacement for kapt. For libraries that support both,\nKSP should be used to improve build times.\n

\n

\nMore information:
\nhttps://developer.android.com/studio/build/migrate-to-ksp
\n

\n", + "tags": [ + "performance", + "android" + ], + "type": "CODE_SMELL", + "severity": "MINOR", + "constantDebtMinutes": 5 + }, { "key": "KeyboardInaccessibleWidget", "name": "Keyboard inaccessible widget", @@ -1887,7 +1966,7 @@ { "key": "KnownPermissionError", "name": "Value specified for permission is a known error", - "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nThis check looks for values specified in component permissions that are known\nerrors, such as android:permission="true".\n

\n

\n Please double check the permission value you have supplied. The value is\nexpected to be a permission string from the system, another app, or your own,\nNOT a boolean.\n

\n

\n

\n", + "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nThis check looks for values specified in component permissions that are known\nerrors, such as android:permission="true".\n

\n

\n Please double check the permission value you have supplied. The value is\nexpected to be a permission string from the system, another app, or your own,\nNOT a boolean.\n

\n

\nMore information:
\nhttps://goo.gle/KnownPermissionError
\n

\n", "tags": [ "security", "android" @@ -1919,6 +1998,18 @@ "severity": "MINOR", "constantDebtMinutes": 5 }, + { + "key": "KotlincFE10", + "name": "Avoid using old K1 Kotlin compiler APIs", + "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\nNOTE: This issue is disabled by default!\nYou can enable it by adding --enable KotlincFE10\n

\n

\nK2, the new version of Kotlin compiler, which encompasses the new frontend, is\ncoming. Try to avoid using internal APIs from the old frontend if possible.\n

\n

\n

\n", + "tags": [ + "lint-implementation", + "android" + ], + "type": "CODE_SMELL", + "severity": "MINOR", + "constantDebtMinutes": 5 + }, { "key": "KtxExtensionAvailable", "name": "KTX Extension Available", @@ -2691,6 +2782,17 @@ "severity": "MINOR", "constantDebtMinutes": 5 }, + { + "key": "NoOp", + "name": "NoOp Code", + "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\nNOTE: This issue is disabled by default!\nYou can enable it by adding --enable NoOp\n

\n

\nThis check looks for code which looks like it's a no-op -- usually leftover\nexpressions from interactive debugging, but in some cases bugs where you had\nintended to do something with the expression such as assign it to a field.\n

\n

\nAvailable options:
\n

\n

\npure-getters (default is false):
\nWhether to assume methods with getter-names have no side effects.\n

\n

\nGetter methods (where names start with get or is, and have non-void return types, and no arguments) should not have side effects. With this option turned on, lint will assume that is the case and will list any getter calls whose results are ignored as suspicious code.\n

\n

\nTo configure this option, use a lint.xml file with an <option> like this:
\n

\n

\n<lint>\n <issue id="NoOp">\n <option name="pure-getters" value="false" />\n </issue>\n</lint>\n

\n

\n

\n

\n

\n", + "tags": [ + "android" + ], + "type": "CODE_SMELL", + "severity": "MINOR", + "constantDebtMinutes": 5 + }, { "key": "NonConstantResourceId", "name": "Checks use of resource IDs in places requiring constants", @@ -2906,17 +3008,6 @@ "severity": "MINOR", "constantDebtMinutes": 5 }, - { - "key": "Override", - "name": "Method conflicts with new inherited method", - "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nSuppose you are building against Android API 8, and you've subclassed\nActivity. In your subclass you add a new method called isDestroyed(). At some\nlater point, a method of the same name and signature is added to Android. Your\nmethod will now override the Android method, and possibly break its contract.\nYour method is not calling super.isDestroyed(), since your compilation target\ndoesn't know about the method.\n

\n

\nThe above scenario is what this lint detector looks for. The above example is\nreal, since isDestroyed() was added in API 17, but it will be true for any\nmethod you have added to a subclass of an Android class where your build\ntarget is lower than the version the method was introduced in.\n

\n

\nTo fix this, either rename your method, or if you are really trying to augment\nthe builtin method if available, switch to a higher build target where you can\ndeliberately add @Override on your overriding method, and call super if\nappropriate etc.\n

\n

\n

\n", - "tags": [ - "android" - ], - "type": "BUG", - "severity": "MAJOR", - "constantDebtMinutes": 5 - }, { "key": "OverrideAbstract", "name": "Not overriding abstract methods on older platforms", @@ -2928,22 +3019,10 @@ "severity": "MAJOR", "constantDebtMinutes": 5 }, - { - "key": "PackageManagerGetSignatures", - "name": "Potential Multiple Certificate Exploit", - "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nImproper validation of app signatures could lead to issues where a malicious\napp submits itself to the Play Store with both its real certificate and a fake\ncertificate and gains access to functionality or information it shouldn't have\ndue to another application only checking for the fake certificate and ignoring\nthe rest. Please make sure to validate all signatures returned by this\nmethod.\n

\n

\nMore information:
\nhttps://bluebox.com/technical/android-fake-id-vulnerability/
\n

\n", - "tags": [ - "security", - "android" - ], - "type": "CODE_SMELL", - "severity": "MINOR", - "constantDebtMinutes": 5 - }, { "key": "PackagedPrivateKey", "name": "Packaged private key", - "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nIn general, you should not package private key files inside your app.\n

\n

\n

\n", + "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nIn general, you should not package private key files inside your app.\n

\n

\nMore information:
\nhttps://goo.gle/PackagedPrivateKey
\n

\n", "tags": [ "security", "android" @@ -2988,7 +3067,7 @@ { "key": "PermissionImpliesUnsupportedChromeOsHardware", "name": "Permission Implies Unsupported Chrome OS Hardware", - "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\nNOTE: This issue is disabled by default!\nYou can enable it by adding --enable PermissionImpliesUnsupportedChromeOsHardware\n

\n

\nThe <uses-permission> element should not require a permission that implies an\nunsupported Chrome OS hardware feature. Google Play assumes that certain\nhardware related permissions indicate that the underlying hardware features\nare required by default. To fix the issue, consider declaring the\ncorresponding uses-feature element with required="false" attribute.\n

\n

\nMore information:
\nhttps://developer.android.com/topic/arc/manifest.html#implied-features
\n

\n", + "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nThe <uses-permission> element should not require a permission that implies an\nunsupported large screen hardware feature. Google Play assumes that certain\nhardware related permissions indicate that the underlying hardware features\nare required by default. To fix the issue, consider declaring the\ncorresponding <uses-feature> element with required="false" attribute.\n

\n

\nMore information:
\nhttps://developer.android.com/topic/arc/manifest.html#implied-features
\n

\n", "tags": [ "android" ], @@ -3119,6 +3198,18 @@ "severity": "MAJOR", "constantDebtMinutes": 5 }, + { + "key": "ProviderReadPermissionOnly", + "name": "Provider with readPermission only and implemented write APIs", + "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nThis check looks for Content Providers that only have the readPermission\nattribute but implement write APIs.\n

\n

\nIf android:readPermission is specified and both android:permission and\nandroid:writePermission are omitted, other apps can access any write\noperations that this provider exposes with no permission check. For a quick\nfix, changing the existing android:readPermission to android:permission will\nprotect both read and write access with the same permission. Alternatively,\ndeclaring a separate android:writePermission can protect write access with a\ndifferent permission.\n

\n

\n

\n", + "tags": [ + "security", + "android" + ], + "type": "CODE_SMELL", + "severity": "MINOR", + "constantDebtMinutes": 5 + }, { "key": "ProxyPassword", "name": "Proxy Password in Cleartext", @@ -3267,6 +3358,18 @@ "severity": "MAJOR", "constantDebtMinutes": 5 }, + { + "key": "ReportShortcutUsage", + "name": "Report shortcut usage", + "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nReporting shortcut usage is important to improving the ranking of shortcuts\n

\n

\nMore information:
\nhttps://developer.android.com/develop/ui/views/launch/shortcuts/managing-shortcuts
\n

\n", + "tags": [ + "user-experience", + "android" + ], + "type": "CODE_SMELL", + "severity": "INFO", + "constantDebtMinutes": 5 + }, { "key": "RequiredSize", "name": "Missing layout_width or layout_height attributes", @@ -3381,7 +3484,7 @@ { "key": "RiskyLibrary", "name": "Libraries with Privacy or Security Risks", - "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nYour app is using a version of a library that has been identified by the\nlibrary developer as a potential source of privacy and/or security risks. This\nmay be a violation of Google Play policies (see\nhttps://play.google.com/about/monetization-ads/ads/) and/or affect your app’s\nvisibility on the Play Store.\n

\n

\nWhen available, the individual error messages from lint will include details\nabout the reasons for this advisory.\n

\n

\nPlease try updating your app with an updated version of this library, or\nremove it from your app.\n

\n

\nMore information:
\nhttps://play.google.com/sdks
\n

\n", + "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nYour app is using a version of a library that has been identified by the\nlibrary developer as a potential source of privacy and/or security risks. This\nmay be a violation of Google Play policies (see\nhttps://play.google.com/about/monetization-ads/ads/) and/or affect your app’s\nvisibility on the Play Store.\n

\n

\nWhen available, the individual error messages from lint will include details\nabout the reasons for this advisory.\n

\n

\nPlease try updating your app with an updated version of this library, or\nremove it from your app.\n

\n

\nMore information:
\nhttps://play.google.com/sdks
\nhttps://goo.gle/RiskyLibrary\n

\n", "tags": [ "security", "android" @@ -3452,7 +3555,7 @@ { "key": "SSLCertificateSocketFactoryCreateSocket", "name": "Insecure call to SSLCertificateSocketFactory.createSocket()", - "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nWhen SSLCertificateSocketFactory.createSocket() is called with an InetAddress\nas the first parameter, TLS/SSL hostname verification is not performed, which\ncould result in insecure network traffic caused by trusting arbitrary\nhostnames in TLS/SSL certificates presented by peers. In this case, developers\nmust ensure that the InetAddress is explicitly verified against the\ncertificate through other means, such as by calling\n`SSLCertificateSocketFactory.getDefaultHostnameVerifier() to get a\nHostnameVerifier and calling HostnameVerifier.verify().\n

\n

\n

\n", + "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nWhen SSLCertificateSocketFactory.createSocket() is called with an InetAddress\nas the first parameter, TLS/SSL hostname verification is not performed, which\ncould result in insecure network traffic caused by trusting arbitrary\nhostnames in TLS/SSL certificates presented by peers. In this case, developers\nmust ensure that the InetAddress is explicitly verified against the\ncertificate through other means, such as by calling\n`SSLCertificateSocketFactory.getDefaultHostnameVerifier() to get a\nHostnameVerifier and calling HostnameVerifier.verify().\n

\n

\nMore information:
\nhttps://goo.gle/SSLCertificateSocketFactoryCreateSocket
\n

\n", "tags": [ "security", "android" @@ -3464,7 +3567,7 @@ { "key": "SSLCertificateSocketFactoryGetInsecure", "name": "Call to SSLCertificateSocketFactory.getInsecure()", - "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nThe SSLCertificateSocketFactory.getInsecure() method returns an\nSSLSocketFactory with all TLS/SSL security checks disabled, which could result\nin insecure network traffic caused by trusting arbitrary TLS/SSL certificates\npresented by peers. This method should be avoided unless needed for a special\ncircumstance such as debugging. Instead,\nSSLCertificateSocketFactory.getDefault() should be used.\n

\n

\n

\n", + "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nThe SSLCertificateSocketFactory.getInsecure() method returns an\nSSLSocketFactory with all TLS/SSL security checks disabled, which could result\nin insecure network traffic caused by trusting arbitrary TLS/SSL certificates\npresented by peers. This method should be avoided unless needed for a special\ncircumstance such as debugging. Instead,\nSSLCertificateSocketFactory.getDefault() should be used.\n

\n

\nMore information:
\nhttps://goo.gle/SSLCertificateSocketFactoryGetInsecure
\n

\n", "tags": [ "security", "android" @@ -3473,10 +3576,21 @@ "severity": "MINOR", "constantDebtMinutes": 5 }, + { + "key": "ScheduleExactAlarm", + "name": "Scheduling Exact Alarms Without Required Permission", + "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nApplications looking to schedule exact alarms should ensure that the\nSCHEDULE_EXACT_ALARM permission is granted by calling the\nAlarmManager#canScheduleExactAlarms API before attempting to set an exact\nalarm. If the permission is not granted to your application, please consider\nrequesting it from the user by starting the\nACTION_REQUEST_SCHEDULE_EXACT_ALARM intent or gracefully falling back to\nanother option.\n

\n

\nMore information:
\nhttps://developer.android.com/training/scheduling/alarms#exact
\n

\n", + "tags": [ + "android" + ], + "type": "BUG", + "severity": "MAJOR", + "constantDebtMinutes": 5 + }, { "key": "ScopedStorage", "name": "Affected by scoped storage", - "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nScoped storage is enforced on Android 10+ (or Android 11+ if using\nrequestLegacyExternalStorage). In particular, WRITE_EXTERNAL_STORAGE will no\nlonger provide write access to all files; it will provide the equivalent of\nREAD_EXTERNAL_STORAGE instead.\n

\n

\nThe MANAGE_EXTERNAL_STORAGE permission can be used to manage all files, but it\nis rarely necessary and most apps on Google Play are not allowed to use it.\nMost apps should instead migrate to use scoped storage. To modify or delete\nfiles, apps should request write access from the user as described at\nhttps://goo.gle/android-mediastore-createwriterequest.\n

\n

\nTo learn more, read these resources: Play policy:
\nhttps://goo.gle/policy-storage-help Allowable use cases:
\nhttps://goo.gle/policy-storage-usecases\n

\n

\nMore information:
\nhttps://goo.gle/android-storage-usecases
\n

\n", + "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nScoped storage is enforced on Android 10+ (or Android 11+ if using\nrequestLegacyExternalStorage). In particular, WRITE_EXTERNAL_STORAGE will no\nlonger provide write access to all files; it will provide the equivalent of\nREAD_EXTERNAL_STORAGE instead.\n

\n

\nAs of Android 13, if you need to query or interact with MediaStore or media\nfiles on the shared storage, you should be using instead one or more new\nstorage permissions:
\n* android.permission.READ_MEDIA_IMAGES\n* android.permission.READ_MEDIA_VIDEO\n* android.permission.READ_MEDIA_AUDIO\n

\n

\nand then add maxSdkVersion="33" to the older permission. See the developer\nguide for how to do this:
\nhttps://developer.android.com/about/versions/13/behavior-changes-13#granular-m\nedia-permissions\n

\n

\nThe MANAGE_EXTERNAL_STORAGE permission can be used to manage all files, but it\nis rarely necessary and most apps on Google Play are not allowed to use it.\nMost apps should instead migrate to use scoped storage. To modify or delete\nfiles, apps should request write access from the user as described at\nhttps://goo.gle/android-mediastore-createwriterequest.\n

\n

\nTo learn more, read these resources: Play policy:
\nhttps://goo.gle/policy-storage-help Allowable use cases:
\nhttps://goo.gle/policy-storage-usecases\n

\n

\nMore information:
\nhttps://goo.gle/android-storage-usecases
\n

\n", "tags": [ "android" ], @@ -3520,7 +3634,7 @@ { "key": "SecureRandom", "name": "Using a fixed seed with SecureRandom", - "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nSpecifying a fixed seed will cause the instance to return a predictable\nsequence of numbers. This may be useful for testing but it is not appropriate\nfor secure use.\n

\n

\nMore information:
\nhttps://developer.android.com/reference/java/security/SecureRandom.html
\n

\n", + "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nSpecifying a fixed seed will cause the instance to return a predictable\nsequence of numbers. This may be useful for testing but it is not appropriate\nfor secure use.\n

\n

\nMore information:
\nhttps://goo.gle/SecureRandom
\nhttps://developer.android.com/reference/java/security/SecureRandom.html\n

\n", "tags": [ "security", "android" @@ -3552,10 +3666,21 @@ "severity": "MAJOR", "constantDebtMinutes": 5 }, + { + "key": "SetAndClearCommunicationDevice", + "name": "Clearing communication device", + "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nAfter selecting the audio device for communication use cases using\nsetCommunicationDevice(AudioDeviceInfo device), the selection is active as\nlong as the requesting application process lives, until\nclearCommunicationDevice() is called or until the device is disconnected. It\nis therefore important to clear the request when a call ends or the requesting\nactivity or service is stopped or destroyed.\n

\n

\n

\n", + "tags": [ + "android" + ], + "type": "CODE_SMELL", + "severity": "MINOR", + "constantDebtMinutes": 5 + }, { "key": "SetJavaScriptEnabled", "name": "Using setJavaScriptEnabled", - "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nYour code should not invoke setJavaScriptEnabled if you are not sure that your\napp really requires JavaScript support.\n

\n

\nMore information:
\nhttps://developer.android.com/training/articles/security-tips
\n

\n", + "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nYour code should not invoke setJavaScriptEnabled if you are not sure that your\napp really requires JavaScript support.\n

\n

\nMore information:
\nhttps://goo.gle/SetJavaScriptEnabled
\nhttps://developer.android.com/training/articles/security-tips\n

\n", "tags": [ "security", "android" @@ -3579,7 +3704,7 @@ { "key": "SetWorldReadable", "name": "File.setReadable() used to make file world-readable", - "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nSetting files world-readable is very dangerous, and likely to cause security\nholes in applications. It is strongly discouraged; instead, applications\nshould use more formal mechanisms for interactions such as ContentProvider,\nBroadcastReceiver, and Service.\n

\n

\n

\n", + "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nSetting files world-readable is very dangerous, and likely to cause security\nholes in applications. It is strongly discouraged; instead, applications\nshould use more formal mechanisms for interactions such as ContentProvider,\nBroadcastReceiver, and Service.\n

\n

\nMore information:
\nhttps://goo.gle/SetWorldReadable
\n

\n", "tags": [ "security", "android" @@ -3591,7 +3716,7 @@ { "key": "SetWorldWritable", "name": "File.setWritable() used to make file world-writable", - "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nSetting files world-writable is very dangerous, and likely to cause security\nholes in applications. It is strongly discouraged; instead, applications\nshould use more formal mechanisms for interactions such as ContentProvider,\nBroadcastReceiver, and Service.\n

\n

\n

\n", + "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nSetting files world-writable is very dangerous, and likely to cause security\nholes in applications. It is strongly discouraged; instead, applications\nshould use more formal mechanisms for interactions such as ContentProvider,\nBroadcastReceiver, and Service.\n

\n

\nMore information:
\nhttps://goo.gle/SetWorldWritable
\n

\n", "tags": [ "security", "android" @@ -3693,7 +3818,7 @@ { "key": "SourceLockedOrientationActivity", "name": "Incompatible setRequestedOrientation value", - "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nThe Activity should not be locked to a portrait orientation so that users can\ntake advantage of the multi-window environments and larger landscape-first\nscreens that Android runs on such as Chrome OS. To fix the issue, consider\ncalling setRequestedOrientation with the\nActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR or\nActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED options or removing the call all\ntogether.\n

\n

\n

\n", + "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nThe Activity should not be locked to a portrait orientation so that users can\ntake advantage of the multi-window environments and larger landscape-first\nscreens that Android runs on such as ChromeOS, tablets, and foldables. To fix\nthe issue, consider calling setRequestedOrientation with the\nActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR or\nActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED options or removing the call all\ntogether.\n

\n

\nMore information:
\nhttps://developer.android.com/guide/topics/large-screens/large-screen-cookbook#restricted_app_orientation
\n

\n", "tags": [ "android" ], @@ -3988,7 +4113,7 @@ { "key": "TrulyRandom", "name": "Weak RNG", - "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nKey generation, signing, encryption, and random number generation may not\nreceive cryptographically strong values due to improper initialization of the\nunderlying PRNG on Android 4.3 and below.\n

\n

\nIf your application relies on cryptographically secure random number\ngeneration you should apply the workaround described in\nhttps://android-developers.blogspot.com/2013/08/some-securerandom-thoughts.htm\nl .\n

\n

\nThis lint rule is mostly informational; it does not accurately detect whether\ncryptographically secure RNG is required, or whether the workaround has\nalready been applied. After reading the blog entry and updating your code if\nnecessary, you can disable this lint issue.\n

\n

\nMore information:
\nhttps://android-developers.blogspot.com/2013/08/some-securerandom-thoughts.html
\n

\n", + "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nKey generation, signing, encryption, and random number generation may not\nreceive cryptographically strong values due to improper initialization of the\nunderlying PRNG on Android 4.3 and below.\n

\n

\nIf your application relies on cryptographically secure random number\ngeneration you should apply the workaround described in\nhttps://android-developers.blogspot.com/2013/08/some-securerandom-thoughts.htm\nl .\n

\n

\nThis lint rule is mostly informational; it does not accurately detect whether\ncryptographically secure RNG is required, or whether the workaround has\nalready been applied. After reading the blog entry and updating your code if\nnecessary, you can disable this lint issue.\n

\n

\nMore information:
\nhttps://goo.gle/TrulyRandom
\nhttps://android-developers.blogspot.com/2013/08/some-securerandom-thoughts.html\n

\n", "tags": [ "security", "android" @@ -4000,7 +4125,7 @@ { "key": "TrustAllX509TrustManager", "name": "Insecure TLS/SSL trust manager", - "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nThis check looks for X509TrustManager implementations whose checkServerTrusted\nor checkClientTrusted methods do nothing (thus trusting any certificate chain)\nwhich could result in insecure network traffic caused by trusting arbitrary\nTLS/SSL certificates presented by peers.\n

\n

\n

\n", + "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nThis check looks for X509TrustManager implementations whose checkServerTrusted\nor checkClientTrusted methods do nothing (thus trusting any certificate chain)\nwhich could result in insecure network traffic caused by trusting arbitrary\nTLS/SSL certificates presented by peers.\n

\n

\nMore information:
\nhttps://goo.gle/TrustAllX509TrustManager
\n

\n", "tags": [ "security", "android" @@ -4162,7 +4287,7 @@ { "key": "UnprotectedSMSBroadcastReceiver", "name": "Unprotected SMS BroadcastReceiver", - "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nBroadcastReceivers that declare an intent-filter for SMS_DELIVER or\nSMS_RECEIVED must ensure that the caller has the BROADCAST_SMS permission,\notherwise it is possible for malicious actors to spoof intents.\n

\n

\n

\n", + "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nBroadcastReceivers that declare an intent-filter for SMS_DELIVER or\nSMS_RECEIVED must ensure that the caller has the BROADCAST_SMS permission,\notherwise it is possible for malicious actors to spoof intents.\n

\n

\nMore information:
\nhttps://goo.gle/UnprotectedSMSBroadcastReceiver
\n

\n", "tags": [ "security", "android" @@ -4183,6 +4308,30 @@ "severity": "MINOR", "constantDebtMinutes": 5 }, + { + "key": "UnsafeImplicitIntentLaunch", + "name": "Implicit intent matches an internal non-exported component", + "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\nNOTE: This issue is disabled by default!\nYou can enable it by adding --enable UnsafeImplicitIntentLaunch\n

\n

\nThis intent matches a non-exported component within the same app. In many\ncases, the app developer could instead use an explicit Intent to send messages\nto their internal components, ensuring that the messages are safely delivered\nwithout exposure to malicious apps on the device. Using such implicit intents\nwill result in a crash in an upcoming version of Android.\n

\n

\nMore information:
\nhttps://goo.gle/ImplicitIntentHijack
\n

\n", + "tags": [ + "security", + "android" + ], + "type": "BUG", + "severity": "MAJOR", + "constantDebtMinutes": 5 + }, + { + "key": "UnsafeIntentLaunch", + "name": "Launched Unsafe Intent", + "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nIntent that potentially could come from an untrusted source should not be\nlaunched from an unprotected component without first being sanitized. See this\nsupport FAQ for details: https://support.google.com/faqs/answer/9267555\n

\n

\n

\n", + "tags": [ + "security", + "android" + ], + "type": "CODE_SMELL", + "severity": "MINOR", + "constantDebtMinutes": 5 + }, { "key": "UnsafeNativeCodeLocation", "name": "Native code outside library directory", @@ -4198,7 +4347,7 @@ { "key": "UnsafeProtectedBroadcastReceiver", "name": "Unsafe Protected BroadcastReceiver", - "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\n`BroadcastReceiver`s that declare an intent-filter for a protected-broadcast\naction string must check that the received intent's action string matches the\nexpected value, otherwise it is possible for malicious actors to spoof\nintents.\n

\n

\n

\n", + "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\n`BroadcastReceiver`s that declare an intent-filter for a protected-broadcast\naction string must check that the received intent's action string matches the\nexpected value, otherwise it is possible for malicious actors to spoof\nintents.\n

\n

\nMore information:
\nhttps://goo.gle/UnsafeProtectedBroadcastReceiver
\n

\n", "tags": [ "security", "android" @@ -4210,7 +4359,19 @@ { "key": "UnspecifiedImmutableFlag", "name": "Missing PendingIntent mutability flag", - "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nApps targeting Android 12 and higher must specify either FLAG_IMMUTABLE or\nFLAG_MUTABLE when constructing a PendingIntent.\n

\n

\nMore information:
\nhttps://developer.android.com/about/versions/12/behavior-changes-12#pending-intent-mutability
\n

\n", + "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nApps targeting Android 12 and higher must specify either FLAG_IMMUTABLE or\nFLAG_MUTABLE when constructing a PendingIntent.\n

\n

\nFLAG_IMMUTABLE is available since target SDK 23, and is almost always the best\nchoice. See\nhttps://developer.android.com/guide/components/intents-filters#CreateImmutable\nPendingIntents for a list of common exceptions to this rule.\n

\n

\nMore information:
\nhttps://developer.android.com/about/versions/12/behavior-changes-12#pending-intent-mutability
\nhttps://goo.gle/UnspecifiedImmutableFlag\n

\n", + "tags": [ + "security", + "android" + ], + "type": "BUG", + "severity": "CRITICAL", + "constantDebtMinutes": 5 + }, + { + "key": "UnspecifiedRegisterReceiverFlag", + "name": "Missing registerReceiver() exported flag", + "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nA future platform release will require all receivers registering for\nnon-system broadcasts to include a flag indicating the receiver's exported\nstate. Apps registering for non-system broadcasts should use the\nContextCompat#registerReceiver APIs with flags set to either RECEIVER_EXPORTED\nor RECEIVER_NOT_EXPORTED.\n

\n

\nIf you are not expecting broadcasts from other apps on the device, register\nyour receiver with RECEIVER_NOT_EXPORTED to protect your receiver on all\nplatform releases.\n

\n

\nMore information:
\nhttps://developer.android.com/reference/androidx/core/content/ContextCompat#registerReceiver(android.content.Context,android.content.BroadcastReceiver,android.content.IntentFilter,int)
\n

\n", "tags": [ "security", "android" @@ -4222,7 +4383,7 @@ { "key": "UnsupportedChromeOsCameraSystemFeature", "name": "Looking for Rear Camera only feature", - "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nYou should look for the FEATURE_CAMERA_ANY features to include all possible\ncameras that may be on the device. Looking for FEATURE_CAMERA only looks for a\nrear facing camera, which certain tablets or Chrome OS devices don't have, as\nwell as newer device configurations and modes may place the device in a state\nwhere the rear camera is not available. To fix the issue, look for\nFEATURE_CAMERA_ANY instead.\n

\n

\n

\n", + "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nYou should look for the FEATURE_CAMERA_ANY features to include all possible\ncameras that may be on the device. Looking for FEATURE_CAMERA only looks for a\nrear facing camera, which certain large screen devices don't have, as well as\nnewer device configurations and modes may place the device in a state where\nthe rear camera is not available. To fix the issue, look for\nFEATURE_CAMERA_ANY instead.\n

\n

\nMore information:
\nhttps://developer.android.com/guide/topics/large-screens/large-screen-cookbook#chromebook_camera_support
\n

\n", "tags": [ "android" ], @@ -4233,7 +4394,7 @@ { "key": "UnsupportedChromeOsHardware", "name": "Unsupported Chrome OS Hardware Feature", - "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\nNOTE: This issue is disabled by default!\nYou can enable it by adding --enable UnsupportedChromeOsHardware\n

\n

\nThe <uses-feature> element should not require this unsupported Chrome OS\nhardware feature. Any uses-feature not explicitly marked with required="false"\nis necessary on the device to be installed on. Ensure that any features that\nmight prevent it from being installed on a Chrome OS device are reviewed and\nmarked as not required in the manifest.\n

\n

\nMore information:
\nhttps://developer.android.com/topic/arc/manifest.html#incompat-entries
\n

\n", + "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\nNOTE: This issue is disabled by default!\nYou can enable it by adding --enable UnsupportedChromeOsHardware\n

\n

\nThe <uses-feature> element should not require this unsupported large screen\nhardware feature. Any <uses-feature> not explicitly marked with\nrequired="false" is necessary on the device to be installed on. Ensure that\nany features that might prevent it from being installed on a ChromeOS, large\nscreen, or foldable device are reviewed and marked as not required in the\nmanifest.\n

\n

\nMore information:
\nhttps://developer.android.com/topic/arc/manifest.html#incompat-entries
\n

\n", "tags": [ "android" ], @@ -4403,6 +4564,18 @@ "severity": "MINOR", "constantDebtMinutes": 5 }, + { + "key": "UseTomlInstead", + "name": "Use TOML Version Catalog Instead", + "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nIf your project is using a libs.versions.toml file, you should place all\nGradle dependencies in the TOML file. This lint check looks for version\ndeclarations outside of the TOML file and suggests moving them (and in the\nIDE, provides a quickfix to performing the operation automatically).\n

\n

\n

\n", + "tags": [ + "productivity", + "android" + ], + "type": "CODE_SMELL", + "severity": "MINOR", + "constantDebtMinutes": 5 + }, { "key": "UseValueOf", "name": "Should use valueOf instead of new", @@ -4439,17 +4612,6 @@ "severity": "MINOR", "constantDebtMinutes": 5 }, - { - "key": "UsesMinSdkAttributes", - "name": "Minimum SDK and target SDK attributes not defined", - "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nThe manifest should contain a <uses-sdk> element which defines the minimum API\nLevel required for the application to run, as well as the target version (the\nhighest API level you have tested the version for).\n

\n

\nMore information:
\nhttps://developer.android.com/guide/topics/manifest/uses-sdk-element.html
\n

\n", - "tags": [ - "android" - ], - "type": "CODE_SMELL", - "severity": "MINOR", - "constantDebtMinutes": 5 - }, { "key": "UsingC2DM", "name": "Using C2DM", @@ -4465,7 +4627,7 @@ { "key": "UsingHttp", "name": "Using HTTP instead of HTTPS", - "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nThe Gradle Wrapper is available both via HTTP and HTTPS. HTTPS is more secure\nsince it protects against man-in-the-middle attacks etc. Older projects\ncreated in Android Studio used HTTP but we now default to HTTPS and recommend\nupgrading existing projects.\n

\n

\n

\n", + "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nThe Gradle Wrapper is available both via HTTP and HTTPS. HTTPS is more secure\nsince it protects against man-in-the-middle attacks etc. Older projects\ncreated in Android Studio used HTTP but we now default to HTTPS and recommend\nupgrading existing projects.\n

\n

\nMore information:
\nhttps://goo.gle/UsingHttp
\n

\n", "tags": [ "security", "android" @@ -4626,7 +4788,7 @@ { "key": "WatchFaceEditor", "name": "Watch face editor must use launchMode=\"standard\"", - "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nWatch face editor activities must be able to launch in the Wear OS app\nactivity task in order to work correctly. Thus only launchMode="standard" is\nallowed. The watch face will not be shown on the watch if it does not satisfy\nthis requirement.\n

\n

\n

\n", + "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nWatch face editor activities must be able to launch in the Wear OS companion\napp activity task in order to work correctly. Thus only launchMode="standard"\nis allowed. The watch face will not be shown on the watch if it does not\nsatisfy this requirement.\n

\n

\n

\n", "tags": [ "android" ], @@ -4704,7 +4866,7 @@ { "key": "WebViewClientOnReceivedSslError", "name": "Proceeds with the HTTPS connection despite SSL errors", - "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nThis check looks for onReceivedSslError implementations that invoke\nSslErrorHandler#proceed.\n

\n

\n

\n", + "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nThis check looks for onReceivedSslError implementations that invoke\nSslErrorHandler#proceed.\n

\n

\nMore information:
\nhttps://goo.gle/WebViewClientOnReceivedSslError
\n

\n", "tags": [ "security", "android" @@ -4773,7 +4935,7 @@ { "key": "WorldReadableFiles", "name": "openFileOutput() with MODE_WORLD_READABLE", - "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nThere are cases where it is appropriate for an application to write world\nreadable files, but these should be reviewed carefully to ensure that they\ncontain no private data that is leaked to other applications.\n

\n

\n

\n", + "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nThere are cases where it is appropriate for an application to write world\nreadable files, but these should be reviewed carefully to ensure that they\ncontain no private data that is leaked to other applications.\n

\n

\nMore information:
\nhttps://goo.gle/WorldReadableFiles
\n

\n", "tags": [ "security", "android" @@ -4785,7 +4947,7 @@ { "key": "WorldWriteableFiles", "name": "openFileOutput() with MODE_WORLD_WRITEABLE", - "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nThere are cases where it is appropriate for an application to write world\nwriteable files, but these should be reviewed carefully to ensure that they\ncontain no private data, and that if the file is modified by a malicious\napplication it does not trick or compromise your application.\n

\n

\n

\n", + "description": "

\nVendor: Android Open Source Project\nContact: https://groups.google.com/g/lint-dev\nFeedback: https://issuetracker.google.com/issues/new?component=192708\n

\n

\nThere are cases where it is appropriate for an application to write world\nwriteable files, but these should be reviewed carefully to ensure that they\ncontain no private data, and that if the file is modified by a malicious\napplication it does not trick or compromise your application.\n

\n

\nMore information:
\nhttps://goo.gle/WorldWriteableFiles
\n

\n", "tags": [ "security", "android" diff --git a/sonar-kotlin-external-linters/src/main/resources/org/sonar/l10n/kotlin/rules/ktlint/rules.json b/sonar-kotlin-external-linters/src/main/resources/org/sonar/l10n/kotlin/rules/ktlint/rules.json index b89a76bc4..3f958e712 100644 --- a/sonar-kotlin-external-linters/src/main/resources/org/sonar/l10n/kotlin/rules/ktlint/rules.json +++ b/sonar-kotlin-external-linters/src/main/resources/org/sonar/l10n/kotlin/rules/ktlint/rules.json @@ -35,6 +35,30 @@ "severity": "MAJOR", "constantDebtMinutes": 0 }, + { + "key": "standard:binary-expression-wrapping", + "name": "Binary Expression Wrapping", + "url": "https://ktlint.github.io/#rules", + "tags": [ + "ktlint", + "style" + ], + "type": "CODE_SMELL", + "severity": "MAJOR", + "constantDebtMinutes": 0 + }, + { + "key": "standard:blank-line-before-declaration", + "name": "Blank Line Before Declaration", + "url": "https://ktlint.github.io/#rules", + "tags": [ + "ktlint", + "style" + ], + "type": "CODE_SMELL", + "severity": "MAJOR", + "constantDebtMinutes": 0 + }, { "key": "standard:block-comment-initial-star-alignment", "name": "Block Comment Initial Star Alignment", @@ -47,6 +71,18 @@ "severity": "MAJOR", "constantDebtMinutes": 0 }, + { + "key": "standard:chain-method-continuation", + "name": "Chain Method Continuation", + "url": "https://ktlint.github.io/#rules", + "tags": [ + "ktlint", + "style" + ], + "type": "CODE_SMELL", + "severity": "MAJOR", + "constantDebtMinutes": 0 + }, { "key": "standard:chain-wrapping", "name": "Chain Wrapping", @@ -71,6 +107,18 @@ "severity": "MAJOR", "constantDebtMinutes": 0 }, + { + "key": "standard:class-signature", + "name": "Class Signature", + "url": "https://ktlint.github.io/#rules", + "tags": [ + "ktlint", + "style" + ], + "type": "CODE_SMELL", + "severity": "MAJOR", + "constantDebtMinutes": 0 + }, { "key": "standard:comment-spacing", "name": "Comment Spacing", @@ -167,6 +215,30 @@ "severity": "MAJOR", "constantDebtMinutes": 0 }, + { + "key": "standard:function-expression-body", + "name": "Function Expression Body", + "url": "https://ktlint.github.io/#rules", + "tags": [ + "ktlint", + "style" + ], + "type": "CODE_SMELL", + "severity": "MAJOR", + "constantDebtMinutes": 0 + }, + { + "key": "standard:function-literal", + "name": "Function Literal", + "url": "https://ktlint.github.io/#rules", + "tags": [ + "ktlint", + "style" + ], + "type": "CODE_SMELL", + "severity": "MAJOR", + "constantDebtMinutes": 0 + }, { "key": "standard:function-naming", "name": "Function Naming", @@ -215,6 +287,18 @@ "severity": "MAJOR", "constantDebtMinutes": 0 }, + { + "key": "standard:function-type-modifier-spacing", + "name": "Function Type Modifier Spacing", + "url": "https://ktlint.github.io/#rules", + "tags": [ + "ktlint", + "style" + ], + "type": "CODE_SMELL", + "severity": "MAJOR", + "constantDebtMinutes": 0 + }, { "key": "standard:function-type-reference-spacing", "name": "Function Type Reference Spacing", @@ -431,6 +515,18 @@ "severity": "MAJOR", "constantDebtMinutes": 0 }, + { + "key": "standard:no-empty-file", + "name": "No Empty File", + "url": "https://ktlint.github.io/#rules", + "tags": [ + "ktlint", + "style" + ], + "type": "CODE_SMELL", + "severity": "MAJOR", + "constantDebtMinutes": 0 + }, { "key": "standard:no-empty-first-line-in-class-body", "name": "No Empty First Line In Class Body", @@ -815,6 +911,18 @@ "severity": "MAJOR", "constantDebtMinutes": 0 }, + { + "key": "standard:statement-wrapping", + "name": "Statement Wrapping", + "url": "https://ktlint.github.io/#rules", + "tags": [ + "ktlint", + "style" + ], + "type": "CODE_SMELL", + "severity": "MAJOR", + "constantDebtMinutes": 0 + }, { "key": "standard:string-template", "name": "String Template", @@ -959,6 +1067,30 @@ "severity": "MAJOR", "constantDebtMinutes": 0 }, + { + "key": "standard:binary-expression-wrapping", + "name": "Binary Expression Wrapping", + "url": "https://ktlint.github.io/#rules", + "tags": [ + "ktlint", + "style" + ], + "type": "CODE_SMELL", + "severity": "MAJOR", + "constantDebtMinutes": 0 + }, + { + "key": "standard:blank-line-before-declaration", + "name": "Blank Line Before Declaration", + "url": "https://ktlint.github.io/#rules", + "tags": [ + "ktlint", + "style" + ], + "type": "CODE_SMELL", + "severity": "MAJOR", + "constantDebtMinutes": 0 + }, { "key": "standard:block-comment-initial-star-alignment", "name": "Block Comment Initial Star Alignment", @@ -971,6 +1103,18 @@ "severity": "MAJOR", "constantDebtMinutes": 0 }, + { + "key": "standard:chain-method-continuation", + "name": "Chain Method Continuation", + "url": "https://ktlint.github.io/#rules", + "tags": [ + "ktlint", + "style" + ], + "type": "CODE_SMELL", + "severity": "MAJOR", + "constantDebtMinutes": 0 + }, { "key": "standard:chain-wrapping", "name": "Chain Wrapping", @@ -995,6 +1139,18 @@ "severity": "MAJOR", "constantDebtMinutes": 0 }, + { + "key": "standard:class-signature", + "name": "Class Signature", + "url": "https://ktlint.github.io/#rules", + "tags": [ + "ktlint", + "style" + ], + "type": "CODE_SMELL", + "severity": "MAJOR", + "constantDebtMinutes": 0 + }, { "key": "standard:comment-spacing", "name": "Comment Spacing", @@ -1091,6 +1247,30 @@ "severity": "MAJOR", "constantDebtMinutes": 0 }, + { + "key": "standard:function-expression-body", + "name": "Function Expression Body", + "url": "https://ktlint.github.io/#rules", + "tags": [ + "ktlint", + "style" + ], + "type": "CODE_SMELL", + "severity": "MAJOR", + "constantDebtMinutes": 0 + }, + { + "key": "standard:function-literal", + "name": "Function Literal", + "url": "https://ktlint.github.io/#rules", + "tags": [ + "ktlint", + "style" + ], + "type": "CODE_SMELL", + "severity": "MAJOR", + "constantDebtMinutes": 0 + }, { "key": "standard:function-naming", "name": "Function Naming", @@ -1139,6 +1319,18 @@ "severity": "MAJOR", "constantDebtMinutes": 0 }, + { + "key": "standard:function-type-modifier-spacing", + "name": "Function Type Modifier Spacing", + "url": "https://ktlint.github.io/#rules", + "tags": [ + "ktlint", + "style" + ], + "type": "CODE_SMELL", + "severity": "MAJOR", + "constantDebtMinutes": 0 + }, { "key": "standard:function-type-reference-spacing", "name": "Function Type Reference Spacing", @@ -1355,6 +1547,18 @@ "severity": "MAJOR", "constantDebtMinutes": 0 }, + { + "key": "standard:no-empty-file", + "name": "No Empty File", + "url": "https://ktlint.github.io/#rules", + "tags": [ + "ktlint", + "style" + ], + "type": "CODE_SMELL", + "severity": "MAJOR", + "constantDebtMinutes": 0 + }, { "key": "standard:no-empty-first-line-in-class-body", "name": "No Empty First Line In Class Body", @@ -1739,6 +1943,18 @@ "severity": "MAJOR", "constantDebtMinutes": 0 }, + { + "key": "standard:statement-wrapping", + "name": "Statement Wrapping", + "url": "https://ktlint.github.io/#rules", + "tags": [ + "ktlint", + "style" + ], + "type": "CODE_SMELL", + "severity": "MAJOR", + "constantDebtMinutes": 0 + }, { "key": "standard:string-template", "name": "String Template", diff --git a/sonar-kotlin-external-linters/src/test/java/org/sonarsource/kotlin/externalreport/androidlint/AndroidLintRulesDefinitionTest.kt b/sonar-kotlin-external-linters/src/test/java/org/sonarsource/kotlin/externalreport/androidlint/AndroidLintRulesDefinitionTest.kt index 9769378c2..22915135f 100644 --- a/sonar-kotlin-external-linters/src/test/java/org/sonarsource/kotlin/externalreport/androidlint/AndroidLintRulesDefinitionTest.kt +++ b/sonar-kotlin-external-linters/src/test/java/org/sonarsource/kotlin/externalreport/androidlint/AndroidLintRulesDefinitionTest.kt @@ -35,7 +35,7 @@ internal class AndroidLintRulesDefinitionTest { assertThat(repository!!.name()).isEqualTo("Android Lint") assertThat(repository.language()).isEqualTo("kotlin") assertThat(repository.isExternal).isTrue - assertThat(repository.rules().size).isEqualTo(431) + assertThat(repository.rules().size).isEqualTo(445) val rule = repository.rule("AaptCrash") assertThat(rule).isNotNull assertThat(rule!!.name()).isEqualTo("Potential AAPT crash") diff --git a/sonar-kotlin-external-linters/src/test/java/org/sonarsource/kotlin/externalreport/ktlint/KtlintRulesDefinitionTest.kt b/sonar-kotlin-external-linters/src/test/java/org/sonarsource/kotlin/externalreport/ktlint/KtlintRulesDefinitionTest.kt index ad9dbeea5..74d219a3f 100644 --- a/sonar-kotlin-external-linters/src/test/java/org/sonarsource/kotlin/externalreport/ktlint/KtlintRulesDefinitionTest.kt +++ b/sonar-kotlin-external-linters/src/test/java/org/sonarsource/kotlin/externalreport/ktlint/KtlintRulesDefinitionTest.kt @@ -36,7 +36,7 @@ class KtlintRulesDefinitionTest { assertThat(repository.name()).isEqualTo("ktlint") assertThat(repository.language()).isEqualTo("kotlin") assertThat(repository.isExternal).isTrue - assertThat(repository.rules().size).isEqualTo(78) + assertThat(repository.rules().size).isEqualTo(87) val modifierOrder = repository.rule("standard:modifier-order")!! assertThat(modifierOrder).isNotNull assertThat(modifierOrder.name()).isEqualTo("Modifier Order") diff --git a/sonar-kotlin-plugin/sonarpedia.json b/sonar-kotlin-plugin/sonarpedia.json index b37bc9242..70594251b 100644 --- a/sonar-kotlin-plugin/sonarpedia.json +++ b/sonar-kotlin-plugin/sonarpedia.json @@ -3,7 +3,7 @@ "languages": [ "KOTLIN" ], - "latest-update": "2023-08-14T13:05:23.190619Z", + "latest-update": "2023-11-21T13:31:58.377021Z", "options": { "no-language-in-filenames": true, "preserve-filenames": true diff --git a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S1066.html b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S1066.html index edc6cf200..b3496872f 100644 --- a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S1066.html +++ b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S1066.html @@ -1,16 +1,36 @@

Why is this an issue?

-

Merging collapsible if statements increases the code’s readability.

-

Noncompliant code example

+

Nested code - blocks of code inside blocks of code - is eventually necessary, but increases complexity. This is why keeping the code as flat as +possible, by avoiding unnecessary nesting, is considered a good practice.

+

Merging if statements when possible will decrease the nesting of the code and improve its readability.

+

Code like

+
+if (condition1) {
+  if (condition2) {             // Noncompliant
+    /* ... */
+  }
+}
+
+

Will be more readable as

+
+if (condition1 && condition2) { // Compliant
+  /* ... */
+}
+
+

How to fix it

+

If merging the conditions seems to result in a more complex code, extracting the condition or part of it in a named function or variable is a +better approach to fix readability.

+

Code examples

+

Noncompliant code example

 if (file != null) {
-  if (file.isFile() || file.isDirectory()) {
+  if (file.isFile() || file.isDirectory()) {  // Noncompliant
     /* ... */
   }
 }
 
-

Compliant solution

+

Compliant solution

-if (file != null && isFileOrDirectory(file)) {
+if (file != null && isFileOrDirectory(file)) {   // Compliant
   /* ... */
 }
 fun isFileOrDirectory(file: File): Boolean {
diff --git a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S1066.json b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S1066.json
index f6857be37..732a6ea96 100644
--- a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S1066.json
+++ b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S1066.json
@@ -1,5 +1,5 @@
 {
-  "title": "Collapsible \"if\" statements should be merged",
+  "title": "Mergeable \"if\" statements should be combined",
   "type": "CODE_SMELL",
   "code": {
     "impacts": {
diff --git a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S1110.html b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S1110.html
index 22364e7e5..93587464e 100644
--- a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S1110.html
+++ b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S1110.html
@@ -1,24 +1,24 @@
 

Why is this an issue?

-

The use of parentheses, even those not required to enforce a desired order of operations, can clarify the intent behind a piece of code. But -redundant pairs of parentheses could be misleading, and should be removed.

+

Parentheses can disambiguate the order of operations in complex expressions and make the code easier to understand.

+
+a = (b * c) + (d * e); // Compliant: the intent is clear.
+
+

Redundant parentheses are parenthesis that do not change the behavior of the code, and do not clarify the intent. They can mislead and complexify +the code. They should be removed.

Noncompliant code example

-val x = (y / 2 + 1)  // Compliant even if the parentheses are ignored by the compiler
+val x = ((y / 2 + 1))  // Noncompliant
 
 if (a && ((x + y > 0))) {  // Noncompliant
-  //...
+  return ((x + 1))  // Noncompliant
 }
-
-return ((x + 1))  // Noncompliant
 

Compliant solution

 val x = (y / 2 + 1)
 
 if (a && (x + y > 0)) {
-  //...
+  return (x + 1)
 }
-
-return (x + 1)
 
diff --git a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S1125.html b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S1125.html index 98789829c..23e98df2e 100644 --- a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S1125.html +++ b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S1125.html @@ -1,7 +1,14 @@

Why is this an issue?

-

Redundant Boolean literals should be removed from expressions to improve readability.

-

Noncompliant code example

-
+

A boolean literal can be represented in two different ways: true or false. They can be combined with logical operators +(!, &&, ||, ==, !=) to produce logical expressions that represent truth values. However, comparing a boolean literal to a +variable or expression that evaluates to a boolean value is unnecessary and can make the code harder to read and understand. The more complex a +boolean expression is, the harder it will be for developers to understand its meaning and expected behavior, and it will favour the introduction of +new bugs.

+

How to tix it

+

Remove redundant boolean literals from expressions to improve readability and make the code more maintainable.

+

Code examples

+

Noncompliant code example

+
 if (booleanMethod() || false) { /* ... */ }
 doSomething(!false);
 
@@ -11,8 +18,8 @@ 

Noncompliant code example

booleanVariable = if (booleanMethod()) exp else true; booleanVariable = if (booleanMethod()) exp else false;
-

Compliant solution

-
+

Compliant solution

+
 if (booleanMethod()) { /* ... */ }
 doSomething(true);
 
diff --git a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S1128.html b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S1128.html
index f3cbf1f33..40d983260 100644
--- a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S1128.html
+++ b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S1128.html
@@ -1,39 +1,52 @@
 

Why is this an issue?

-

The imports part of a file should be handled by the Integrated Development Environment (IDE), not manually by the developer.

-

Unused and useless imports should not occur if that is the case.

-

Leaving them in reduces the code’s readability, since their presence can be confusing.

-

Noncompliant code example

-
-package my.company
-
-import kotlin.String            // Noncompliant; "kotlin" classes are always implicitly imported
-import my.company.SomeClass     // Noncompliant; same-package files are always implicitly imported
-import java.io.File             // Noncompliant; "File" is not used
-
-import my.company2.SomeType
-
-class ExampleClass {
-
-  val someString = ""
-  val something = SomeType()
-
+

Unnecessary imports refer to importing types that are not used or referenced anywhere in the code.

+

Although they don’t affect the runtime behavior of the application after compilation, removing them will:

+
    +
  • Improve the readability and maintainability of the code.
  • +
  • Help avoid potential naming conflicts.
  • +
  • Improve the build time, as the compiler has fewer lines to read and fewer types to resolve.
  • +
  • Reduce the number of items the code editor will show for auto-completion, thereby showing fewer irrelevant suggestions.
  • +
+

Exceptions

+

Imports for types mentioned in KDoc are ignored.

+

How to fix it

+

While it’s not difficult to remove these unneeded lines manually, modern code editors support the removal of every unnecessary import with a single +click from every file of the project.

+

Code examples

+

Noncompliant code example

+
+package myapp.helpers
+
+import java.io.IOException
+import java.nio.file.*
+import java.nio.file.*     // Noncompliant - package is imported twice
+import java.nio.*          // Noncompliant - nothing is used from that package
+
+object FileHelper {
+    fun readFirstLine(filePath: String)
+        = Files.readAllLines(Paths.get(filePath)).first()
 }
 
-

Compliant solution

-
-package my.company
-
-import java.io.File
-import my.company2.SomeType
+

Compliant solution

+
+package myapp.helpers
 
-class ExampleClass {
-
-  val someString = ""
-  val something = SomeType()
-  lateinit var fileUsage: File
+import java.io.IOException
+import java.nio.file.*
 
+object FileHelper {
+    fun readFirstLine(filePath: String)
+        = Files.readAllLines(Paths.get(filePath)).first()
 }
 
-

Exceptions

-

Imports for types mentioned in KDoc comments are ignored.

+

Resources

+

Documentation

+ +

Related rules

+
    +
  • {rule:kotlin:S1144} - Unused "private" methods should be removed
  • +
  • {rule:kotlin:S1481} - Unused local variables should be removed
  • +
diff --git a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S1128.json b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S1128.json index d3ad8e74a..1b4b7b19b 100644 --- a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S1128.json +++ b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S1128.json @@ -10,7 +10,7 @@ "status": "ready", "remediation": { "func": "Constant\/Issue", - "constantCost": "2min" + "constantCost": "1min" }, "tags": [ "unused" diff --git a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S1135.html b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S1135.html index 94db0ff87..c309194d6 100644 --- a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S1135.html +++ b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S1135.html @@ -1,5 +1,5 @@

Why is this an issue?

-

Developers often use TOOO tags to mark areas in the code where additional work or improvements are needed but are not implemented +

Developers often use TODO tags to mark areas in the code where additional work or improvements are needed but are not implemented immediately. However, these TODO tags sometimes get overlooked or forgotten, leading to incomplete or unfinished code. This code smell class aims to identify and address such unattended TODO tags to ensure a clean and maintainable codebase. This description will explore why this is a problem and how it can be fixed to improve the overall code quality.

diff --git a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S1144.html b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S1144.html index ad50d6bfe..19c7d1497 100644 --- a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S1144.html +++ b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S1144.html @@ -1,4 +1,30 @@ +

This rule raises an issue when a private function is never referenced in the code.

Why is this an issue?

-

private methods that are never executed are dead code: unnecessary, inoperative code that should be removed. Cleaning out dead code -decreases the size of the maintained codebase, making it easier to understand the program and preventing bugs from being introduced.

+

A function that is never called is dead code, and should be removed. Cleaning out dead code decreases the size of the maintained codebase, making +it easier to understand the program and preventing bugs from being introduced.

+

This rule detects functions that are never referenced from inside a translation unit, and cannot be referenced from the outside.

+

Code examples

+

Noncompliant code example

+
+class Foo: Serializable {
+  private fun unusedMethod() {...}
+  private fun writeObject(s: ObjectOutputStream) {...}  // Compliant, relates to the serialization mechanism
+  private fun readObject(s: ObjectOutputStream) {...}  // Compliant, relates to the serialization mechanism
+}
+
+

Compliant solution

+
+class Foo: Serializable {
+  private fun writeObject(s: ObjectOutputStream) {...}  // Compliant, relates to the serialization mechanism
+  private fun readObject(s: ObjectOutputStream) {...}  // Compliant, relates to the serialization mechanism
+}
+
+

Exceptions

+

This rule doesn’t raise issues for:

+
    +
  • annotated methods
  • +
  • methods with parameters that are annotated with @javax.enterprise.event.Observes
  • +
+

The rule does not take reflection into account, which means that issues will be raised on private methods that are only accessed using +the reflection API.

diff --git a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S1144.json b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S1144.json index 81518fc34..10b75147e 100644 --- a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S1144.json +++ b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S1144.json @@ -10,7 +10,7 @@ "status": "ready", "remediation": { "func": "Constant\/Issue", - "constantCost": "5min" + "constantCost": "2min" }, "tags": [ "unused" diff --git a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S117.html b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S117.html index 5734deb8d..86a05d504 100644 --- a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S117.html +++ b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S117.html @@ -1,4 +1,58 @@ +

Local variables and function parameters should be named consistently to communicate intent and improve maintainability. Rename your local variable +or function parameter to follow your project’s naming convention to address this issue.

Why is this an issue?

-

Shared naming conventions allow teams to collaborate effectively. This rule raises an issue when a local variable or function parameter name does -not match the provided regular expression.

+

A naming convention in software development is a set of guidelines for naming code elements like variables, functions, and classes.
Local +variables and function parameters hold the meaning of the written code. Their names should be meaningful and follow a consistent and easily +recognizable pattern.
Adhering to a consistent naming convention helps to make the code more readable and understandable, which makes it easier to +maintain and debug. It also ensures consistency in the code, especially when multiple developers are working on the same project.

+

This rule checks that local variable and function parameter names match a provided regular expression.

+

What is the potential impact?

+

Inconsistent naming of local variables and function parameters can lead to several issues in your code:

+
    +
  • Reduced Readability: inconsistent local variable and function parameter names make the code harder to read and understand; consequently, it is + more difficult to identify the purpose of each variable, spot errors, or comprehend the logic.
  • +
  • Difficulty in Identifying Variables: local variables and function parameters that don’t adhere to a standard naming convention are challenging + to identify; thus, the coding process slows down, especially when dealing with a large codebase.
  • +
  • Increased Risk of Errors: inconsistent or unclear local variable and function parameter names lead to misunderstandings about what the variable + represents. This ambiguity leads to incorrect assumptions and, consequently, bugs in the code.
  • +
  • Collaboration Difficulties: in a team setting, inconsistent naming conventions lead to confusion and miscommunication among team members.
  • +
  • Difficulty in Code Maintenance: inconsistent naming leads to an inconsistent codebase. The code is difficult to understand, and making changes + feels like refactoring constantly, as you face different naming methods. Ultimately, it makes the codebase harder to maintain.
  • +
+

In summary, not adhering to a naming convention for local variables and function parameters can lead to confusion, errors, and inefficiencies, +making the code harder to read, understand, and maintain.

+

How to fix it

+

First, familiarize yourself with the particular naming convention of the project in question. Then, update the name to match the convention, as +well as all usages of the name. For many IDEs, you can use built-in renaming and refactoring features to update all usages at once.

+

Code examples

+

Noncompliant code example

+

With the default regular expression ^`?[_a-z][a-zA-Z0-9]*`?$:

+
+fun printSomething(
+    IMPORTANT_PARAM: String // Noncompliant
+) {
+    val LOCAL = "" // Noncompliant
+    println(IMPORTANT_PARAM + LOCAL)
+}
+
+

Compliant solution

+
+fun printSomething(
+    importantParam: String
+) {
+    val local = ""
+    println(importantParam + local)
+}
+
+

Resources

+

Documentation

+ +

Related rules

+
    +
  • {rule:kotlin:S100} - Function names should comply with a naming convention
  • +
  • {rule:kotlin:S101} - Class names should comply with a naming convention
  • +
diff --git a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S1172.html b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S1172.html index 211c8b1be..bc1de1dac 100644 --- a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S1172.html +++ b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S1172.html @@ -1,3 +1,6 @@

Why is this an issue?

-

Unused parameters are misleading. Whatever the values passed to such parameters, the behavior will be the same.

+

A typical code smell known as unused function parameters refers to parameters declared in a function but not used anywhere within the function’s +body. While this might seem harmless at first glance, it can lead to confusion and potential errors in your code. Disregarding the values passed to +such parameters, the function’s behavior will be the same, but the programmer’s intention won’t be clearly expressed anymore. Therefore, removing +function parameters that are not being utilized is considered best practice.

diff --git a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S1186.html b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S1186.html index 0f920ed97..cec1fc864 100644 --- a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S1186.html +++ b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S1186.html @@ -1,8 +1,37 @@

Why is this an issue?

-

There are several reasons for a function not to have a function body:

+

An empty function is generally considered bad practice and can lead to confusion, readability, and maintenance issues. Empty functions bring no +functionality and are misleading to others as they might think the function implementation fulfills a specific and identified requirement.

+

There are several reasons for a function not to have a body:

  • It is an unintentional omission, and should be fixed to prevent an unexpected behavior in production.
  • It is not yet, or never will be, supported. In this case an exception should be thrown.
  • -
  • The function is an intentionally-blank override. In this case a nested comment should explain the reason for the blank override.
  • +
  • The method is an intentionally-blank override. In this case a nested comment should explain the reason for the blank override.
+

How to fix it

+

Code examples

+

Noncompliant code example

+
+fun shouldNotBeEmpty() {  // Noncompliant - method is empty
+}
+
+fun notImplemented() {  // Noncompliant - method is empty
+}
+
+fun emptyOnPurpose() {  // Noncompliant - method is empty
+}
+
+

Compliant solution

+
+fun shouldNotBeEmpty() {
+  doSomething()
+}
+
+fun notImplemented() {
+  throw UnsupportedOperationException("notImplemented() cannot be performed because ...")
+}
+
+fun emptyOnPurpose() {
+  // comment explaining why the method is empty
+}
+
diff --git a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S1192.html b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S1192.html index 9c54bec82..47d38bd4d 100644 --- a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S1192.html +++ b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S1192.html @@ -1,9 +1,16 @@

Why is this an issue?

-

Duplicated string literals make the process of refactoring error-prone, since you must be sure to update all occurrences.

-

On the other hand, constants can be referenced from many places, but only need to be updated in a single place.

-

Noncompliant code example

+

Duplicated string literals make the process of refactoring complex and error-prone, as any change would need to be propagated on all +occurrences.

+

Exceptions

+

To prevent generating some false-positives, literals having 5 or less characters are excluded as well as literals containing only letters, digits +and '_'.

+

How to fix it

+

Instead, use constants to replace the duplicated string literals. Constants can be referenced from many places, but only need to be updated in a +single place.

+

Code examples

+

Noncompliant code example

With the default threshold of 3:

-
+
 class A {
     fun run() {
         prepare("string literal")    // Noncompliant - "string literal" is duplicated 3 times
@@ -18,8 +25,8 @@ 

Noncompliant code example

} }
-

Compliant solution

-
+

Compliant solution

+
 class A {
     companion object {
         const val CONSTANT = "string literal"
@@ -32,7 +39,4 @@ 

Compliant solution

} }
-

Exceptions

-

To prevent generating some false-positives, literals having 5 or less characters are excluded as well as literals containing only letters, digits -and '_'.

diff --git a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S125.html b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S125.html index 86475f084..0d83de02c 100644 --- a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S125.html +++ b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S125.html @@ -1,4 +1,5 @@

Why is this an issue?

-

Programmers should not comment out code as it bloats programs and reduces readability.

-

Unused code should be deleted and can be retrieved from source control history if required.

+

Commented-out code distracts the focus from the actual executed code. It creates a noise that increases maintenance code. And because it is never +executed, it quickly becomes out of date and invalid.

+

Commented-out code should be deleted and can be retrieved from source control history if required.

diff --git a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S134.html b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S134.html index 999454dcc..040464f53 100644 --- a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S134.html +++ b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S134.html @@ -1,5 +1,11 @@

Why is this an issue?

-

Nested if, for, while, when, and try statements are key ingredients for making -what’s known as "Spaghetti code".

-

Such code is hard to read, refactor and therefore maintain.

+

Nested control flow statements if, for, while, when, and try are often key +ingredients in creating what’s known as "Spaghetti code". This code smell can make your program difficult to understand and maintain.

+

When numerous control structures are placed inside one another, the code becomes a tangled, complex web. This significantly reduces the code’s +readability and maintainability, and it also complicates the testing process.

+

Resources

+ diff --git a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S1481.html b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S1481.html index fbd7b2884..9f314d4bc 100644 --- a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S1481.html +++ b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S1481.html @@ -1,4 +1,40 @@

Why is this an issue?

-

If a local variable is declared but not used, it is dead code and should be removed. Doing so will improve maintainability because developers will -not wonder what the variable is used for.

+

An unused local variable is a variable that has been declared but is not used anywhere in the block of code where it is defined. It is dead code, +contributing to unnecessary complexity and leading to confusion when reading the code. Therefore, it should be removed from your code to maintain +clarity and efficiency.

+

What is the potential impact?

+

Having unused local variables in your code can lead to several issues:

+
    +
  • Decreased Readability: Unused variables can make your code more difficult to read. They add extra lines and complexity, which can distract from + the main logic of the code.
  • +
  • Misunderstanding: When other developers read your code, they may wonder why a variable is declared but not used. This can lead to confusion and + misinterpretation of the code’s intent.
  • +
  • Potential for Bugs: If a variable is declared but not used, it might indicate a bug or incomplete code. For example, if you declared a variable + intending to use it in a calculation, but then forgot to do so, your program might not work as expected.
  • +
  • Maintenance Issues: Unused variables can make code maintenance more difficult. If a programmer sees an unused variable, they might think it is + a mistake and try to 'fix' the code, potentially introducing new bugs.
  • +
  • Memory Usage: Although modern compilers are smart enough to ignore unused variables, not all compilers do this. In such cases, unused variables + take up memory space, leading to inefficient use of resources.
  • +
+

In summary, unused local variables can make your code less readable, more confusing, and harder to maintain, and they can potentially lead to bugs +or inefficient memory use. Therefore, it is best to remove them.

+

How to fix it

+

The fix for this issue is straightforward. Once you ensure the unused variable is not part of an incomplete implementation leading to bugs, you +just need to remove it.

+

Code examples

+

Noncompliant code example

+
+fun numberOfMinutes(hours: Int): Int {
+    val seconds: Int = 0 // Noncompliant - seconds is unused
+    val result: Int = hours * 60
+    return result
+}
+
+

Compliant solution

+
+fun numberOfMinutes(hours: Int): Int {
+    val result: Int = hours * 60
+    return result
+}
+
diff --git a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S1763.html b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S1763.html index dbf38202e..871185654 100644 --- a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S1763.html +++ b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S1763.html @@ -1,3 +1,4 @@ +

Once control flow has been moved out of the current code block, any subsequent statements become effectively unreachable.

Why is this an issue?

Jump statements (return, break and continue) move control flow out of the current code block. So any statements that come after a jump are dead code.

diff --git a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S1871.html b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S1871.html index dbcaaff00..c4150b218 100644 --- a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S1871.html +++ b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S1871.html @@ -1,25 +1,69 @@

Why is this an issue?

+

When the same code is duplicated in two or more separate branches of a conditional, it can make the code harder to understand, maintain, and can +potentially introduce bugs if one instance of the code is changed but others are not.

Having two clauses in a when statement or two branches in an if chain with the same implementation is at best duplicate -code, and at worst a coding error. If the same logic is truly needed for both instances, then in an if chain they should be combined, or -for a when, duplicates should be refactored.

-

Noncompliant code example

-
-fun s1871(x: Int) {
-    when (x) {
-        1 -> {
-            val y = x / 2
-            print(y)
-        }
-        2 -> {
-            val y = x / 2
-            print(y)
-        }
-    }
+code, and at worst a coding error.

+
+if (a >= 0 && a < 10) {
+  doFirstThing()
+  doTheThing()
+}
+else if (a >= 10 && a < 20) {
+  doTheOtherThing()
+}
+else if (a >= 20 && a < 50) { // Noncompliant; duplicates first condition
+  doFirstThing()
+  doTheThing()
+}
+else {
+  doTheRest()
+}
+
+
+when (x) {
+  1 -> {
+    doFirstThing()
+    doSomething()
+  }
+  2 -> doSomethingDifferent()
+  3 -> { // Noncompliant; duplicates case 1's implementation
+    doFirstThing()
+    doSomething()
+  }
+  else -> doTheRest()
+}
+
+

If the same logic is needed for both instances, then:

+
    +
  • in an if structure they should be combined
  • +
+
+if ((a >= 0 && a < 10) || (a >= 20 && a < 50)) {
+  doFirstThing()
+  doTheThing()
+}
+else if (a >= 10 && a < 20) {
+  doTheOtherThing()
+}
+else {
+  doTheRest()
+}
+
+
    +
  • for a when, the values should be put together in the branch expression list.
  • +
+
+when (x) {
+  1, 3 -> {
+    doFirstThing()
+    doSomething()
+  }
+  2 -> doSomethingDifferent()
+  else -> doTheRest()
 }
 

Exceptions

-

Blocks in an if chain that contain a single line of code are ignored, as are blocks in a when statement that contain a -single line of code with or without a following break.

+

Blocks in an if chain or in a when branch that contain a single line of code are ignored.

 if (a == 1) {
     doSomething()  //no issue, usually this is done on purpose to increase the readability
@@ -34,9 +78,14 @@ 

Exceptions

with default clauses, rule {rule:kotlin:S3923} raises a bug.

 if (a == 1) {
-  doSomething()  //Noncompliant, this might have been done on purpose but probably not
+  doSomething()  // Noncompliant, this might have been done on purpose but probably not
 } else if (a == 2) {
   doSomething()
 }
 
+

Resources

+

Related rules

+
    +
  • {rule:kotlin:S3923} - All branches in a conditional structure should not have exactly the same implementation
  • +
diff --git a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S1874.html b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S1874.html index a14f4f0e1..f50b81051 100644 --- a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S1874.html +++ b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S1874.html @@ -1,10 +1,28 @@

Why is this an issue?

-

Code annotated as deprecated should not be used since it will be removed sooner or later.

-

Noncompliant code example

+

Code is sometimes annotated as deprecated by developers maintaining libraries or APIs to indicate that the method, class, or other programming +element is no longer recommended for use. This is typically due to the introduction of a newer or more effective alternative. For example, when a +better solution has been identified, or when the existing code presents potential errors or security risks.

+

Deprecation is a good practice because it helps to phase out obsolete code in a controlled manner, without breaking existing software that may +still depend on it. It is a way to warn other developers not to use the deprecated element in new code, and to replace it in existing code when +possible.

+

Deprecated classes, interfaces, and their members should not be used, inherited or extended because they will eventually be removed. The +deprecation period allows you to make a smooth transition away from the aging, soon-to-be-retired technology.

+

Check the documentation or the deprecation message to understand why the code was deprecated and what the recommended alternative is.

-@Deprecated("")
-interface Old
+@Deprecated("This function is deprecated, use newFunction instead", ReplaceWith("newFunction()"))
+fun oldFunction() {
+    println("This is the old function.")
+}
 
-class Example : Old // Noncompliant
+fun newFunction() {
+    println("This is the new function.")
+}
+
+oldFunction() // Noncompliant: "oldFunction is deprecated"
 
+

Resources

+

Documentation

+ diff --git a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S2068.html b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S2068.html index c8e6aed48..da6e14aee 100644 --- a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S2068.html +++ b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S2068.html @@ -51,7 +51,6 @@

See

  • MITRE, CWE-798 - Use of Hard-coded Credentials
  • MITRE, CWE-259 - Use of Hard-coded Password
  • -
  • SANS Top 25 - Porous Defenses
  • Derived from FindSecBugs rule Hard Coded Password
  • diff --git a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S3329.html b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S3329.html index 0db63ee0c..5b3ba77b3 100644 --- a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S3329.html +++ b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S3329.html @@ -108,8 +108,12 @@

    Compliant solution

    How does this work?

    Use unique IVs

    -

    To ensure strong security, the initialization vectors for each encryption operation must be unique and random but they do not have to be -secret.

    +

    To ensure high security, initialization vectors must meet two important criteria:

    +
      +
    • IVs must be unique for each encryption operation.
    • +
    • For CBC and CFB modes, a secure FIPS-compliant random number generator should be used to generate unpredictable IVs.
    • +
    +

    The IV does not need be secret, so the IV or information sufficient to determine the IV may be transmitted along with the ciphertext.

    In the previous non-compliant example, the problem is not that the IV is hard-coded.
    It is that the same IV is used for multiple encryption attempts.

    Resources

    diff --git a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S3353.html b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S3353.html index 5f9bc790d..1bb75c0e0 100644 --- a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S3353.html +++ b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S3353.html @@ -8,7 +8,7 @@

    Readability and Understanding

    Wrong code

    Developers might intend for a variable to remain unchanged and have their code relying on that constraint. For example, a variable could be expected to have a specific range. Changing the value of the variable could break that constraint. Also, developers could have assigned the wrong -variable.

    +variable. If the developers inject a value into a variable with an annotation, they should declare it as late initialized.

    Declare variables that remain unchanged as val to avoid these mistakes.

    How to fix it

    Replace the keyword var with val.

    @@ -20,6 +20,11 @@

    Noncompliant code example

    allocBuffer(newLength) return resize } + +class MyClass { + @inject + private var myVar: Int = 0 // Noncompliant, `myVar` is late initialized and should be declared as such +}

    Compliant solution

    @@ -28,6 +33,11 @@ 

    Compliant solution

    allocBuffer(newLength) return resize } + +class MyClass { + @inject + private lateinit var myVar: Int // Compliant +}

    Resources

    Documentation

    diff --git a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S3776.html b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S3776.html index be9d04d0c..a150491fc 100644 --- a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S3776.html +++ b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S3776.html @@ -1,9 +1,31 @@ +

    This rule raises an issue when the code cognitive complexity of a function is above a certain threshold.

    Why is this an issue?

    -

    Cognitive Complexity is a measure of how hard the control flow of a function -is to understand. Functions with high Cognitive Complexity will be difficult to maintain.

    +

    Cognitive Complexity is a measure of how hard it is to understand the control flow of a unit of code. Code with high cognitive complexity is hard +to read, understand, test, and modify.

    +

    As a rule of thumb, high cognitive complexity is a sign that the code should be refactored into smaller, easier-to-manage pieces.

    +

    Which syntax in code does impact cognitive complexity score?

    +

    Here are the core concepts:

    +
      +
    • Cognitive complexity is incremented each time the code breaks the normal linear reading flow.
      This concerns, for example: + Loop structures, Conditionals, Catches, Switches, Jumps to label and mixed operators in condition.
    • +
    • Each nesting level adds a malus to the breaking call.
      During code reading, the deeper you go through nested layers, the + harder it becomes to keep the context in mind.
    • +
    • Method calls are free
      A well-picked method name is a summary of multiple lines of code. A reader can first explore a + high-level view of what the code is performing then go deeper and deeper by looking at called functions content.
      Note: This does not + apply to recursive calls, those will increment cognitive score.
    • +
    +

    The method of computation is fully detailed in the pdf linked in the resources.

    +

    What is the potential impact?

    +

    Developers spend more time reading and understanding code than writing it. High cognitive complexity slows down changes and increases the cost of +maintenance.

    Resources

    Documentation

    +

    Articles & blog posts

    + diff --git a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S3776.json b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S3776.json index f18253c54..d00a267dd 100644 --- a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S3776.json +++ b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S3776.json @@ -21,5 +21,5 @@ "ruleSpecification": "RSPEC-3776", "sqKey": "S3776", "scope": "All", - "quickfix": "unknown" + "quickfix": "infeasible" } diff --git a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S4347.html b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S4347.html index b9c0ad284..f0e626956 100644 --- a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S4347.html +++ b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S4347.html @@ -1,29 +1,75 @@ +

    When using SecureRandom, it is important not to use predictable seeds. This class is used to generate cryptographically strong random +numbers. Using a predictable seed will make its output predictable as well, which counteracts the use case of SecureRandom.

    Why is this an issue?

    -

    The java.security.SecureRandom class provides a strong random number generator (RNG) appropriate for cryptography. However, seeding it -with a constant or another predictable value will weaken it significantly. In general, it is much safer to rely on the seed provided by the -SecureRandom implementation.

    -

    This rule raises an issue when SecureRandom.setSeed() or SecureRandom(byte[]) are called with a seed that is either one -of:

    +

    java.security.SecureRandom is often used to generate random values for cryptographic algorithms. When a random number generator is +used for cryptographic purposes, the generated numbers must be as random and unpredictable as possible. When SecureRandom is improperly +seeded with a constant or a predictable value, its output will also be predictable.

    +

    This can have severe security implications for cryptographic operations that rely on the randomness of the generated numbers. By using a +predictable seed, an attacker can potentially guess or deduce the generated numbers, compromising the security of whatever cryptographic algorithm +relies on SecureRandom.

    +

    What is the potential impact?

    +

    It is crucial to understand that the strength of cryptographic algorithms heavily relies on the quality of the random numbers used. By improperly +seeding the SecureRandom class, we introduce a significant weakness that can be exploited by attackers.

    +

    Insecure cryptographic keys

    +

    One of the primary use cases for the SecureRandom class is generating cryptographic keys. If an attacker can predict the seed used to +initialize the SecureRandom instance, they may be able to derive the same keys. Depending on the use case, this can lead to multiple severe outcomes, +such as:

      -
    • a constant
    • -
    • the system time
    • +
    • Being able to decrypt sensitive documents, leading to privacy breaches or identity theft.
    • +
    • Gaining access to a private key used for signing, allowing an attacker to forge digital signatures and impersonate legitimate entities.
    • +
    • Bypassing authentication mechanisms that rely on public-key infrastructure (PKI), which can be abused to gain unauthorized access to systems or + networks.
    -

    Noncompliant code example

    -
    +

    Session hijacking and man-in-the-middle attack

    +

    Another scenario where this vulnerability can be exploited is in the generation of session tokens or nonces for secure communication protocols. If +an attacker can predict the seed used to generate these tokens, they can impersonate legitimate users or intercept sensitive information.

    +

    How to fix it in Java SE

    +

    Code examples

    +

    The following code uses a cryptographically strong random number generator to generate data that is not cryptographically strong.

    +

    Noncompliant code example

    +
    +import java.security.SecureRandom
    +
     val sr = SecureRandom()
     sr.setSeed(123456L) // Noncompliant
     val v = sr.nextInt()
     
    -
    +
    +import java.security.SecureRandom
    +
     val sr = SecureRandom("abcdefghijklmnop".toByteArray(charset("us-ascii"))) // Noncompliant
     val v = sr.nextInt()
     
    -

    Compliant solution

    -
    +

    Compliant solution

    +
    +import java.security.SecureRandom
    +
     val sr = SecureRandom()
     val v = sr.nextInt()
     
    +

    This solution is available for JDK 1.8 and higher.

    +
    +import java.security.SecureRandom
    +
    +val sr = SecureRandom.getInstanceStrong()
    +val v = sr.nextInt()
    +
    +

    How does this work?

    +

    When the randomly generated data needs to be cryptographically strong, SecureRandom is the correct class to use. However, its +documentation also cites that "any seed material passed to a SecureRandom object must be unpredictable". When no seed is passed by the +user to the object, the SecureRandom object chooses an unpredictable seed by default. Therefore, the easiest way to fix the issue is to +use the default constructor without any calls to SecureObject.setSeed().

    +

    To go the extra mile, SecureObject.getInstanceStrong() returns an instance of SecureObject that is guaranteed to use a +strong algorithm for its number generation.

    +

    If the randomly generated data is not used for cryptographic purposes and is not business critical, it may be a better choice to use +java.util.Random instead. In this case, setting a predictable seed may be acceptable depending on the situation.

    Resources

    +

    Documentation

    + +

    Standards

    • OWASP Top 10 2021 Category A2 - Cryptographic Failures
    • OWASP Top 10 2017 Category A6 - Security diff --git a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S4423.html b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S4423.html index d16d12176..c1d35a990 100644 --- a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S4423.html +++ b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S4423.html @@ -83,7 +83,7 @@

      Use TLS v1.2 or TLS v1.3

      How to fix it in OkHttp

      Code examples

      Noncompliant code example

      -
      +
       import okhttp3.ConnectionSpec;
       import okhttp3.TlsVersion;
       
      @@ -94,7 +94,7 @@ 

      Noncompliant code example

      }

      Compliant solution

      -
      +
       import okhttp3.ConnectionSpec;
       import okhttp3.TlsVersion;
       
      @@ -132,7 +132,6 @@ 

      Standards

    • OWASP Top 10 2017 Category A6 - Security Misconfiguration
    • MITRE, CWE-327 - Use of a Broken or Risky Cryptographic Algorithm
    • -
    • SANS Top 25 - Porous Defenses
    • Mobile AppSec Verification Standard - Cryptography Requirements
    • OWASP Mobile Top 10 2016 Category M5 - diff --git a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S4790.html b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S4790.html index e131da931..b345b9e56 100644 --- a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S4790.html +++ b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S4790.html @@ -56,6 +56,5 @@

      See

    • OWASP Mobile Top 10 2016 Category M5 - Insufficient Cryptography
    • MITRE, CWE-1240 - Use of a Risky Cryptographic Primitive
    • -
    • SANS Top 25 - Porous Defenses
    diff --git a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S4790.json b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S4790.json index 434345dd6..76ecc11cd 100644 --- a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S4790.json +++ b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S4790.json @@ -9,8 +9,7 @@ }, "status": "ready", "tags": [ - "cwe", - "spring" + "cwe" ], "defaultSeverity": "Critical", "ruleSpecification": "RSPEC-4790", diff --git a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S5322.html b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S5322.html index 196da25be..589932d46 100644 --- a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S5322.html +++ b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S5322.html @@ -79,7 +79,6 @@

    See

    Platform Usage
  • MITRE, CWE-925 - Improper Verification of Intent by Broadcast Receiver
  • MITRE, CWE-926 - Improper Export of Android Application Components
  • -
  • SANS Top 25 - Insecure Interaction Between Components
  • Android documentation - Broadcast Overview - Security considerations and best practices
  • diff --git a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S5324.html b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S5324.html index 029c683d3..939710389 100644 --- a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S5324.html +++ b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S5324.html @@ -47,14 +47,12 @@

    Compliant Solution

    See

    diff --git a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S5542.html b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S5542.html index 7d0d0b120..b7269ecef 100644 --- a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S5542.html +++ b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S5542.html @@ -131,7 +131,6 @@

    Standards

  • OWASP Top 10 2017 Category A6 - Security Misconfiguration
  • MITRE, CWE-327 - Use of a Broken or Risky Cryptographic Algorithm
  • -
  • SANS Top 25 - Porous Defenses
  • Mobile AppSec Verification Standard - Cryptography Requirements
  • OWASP Mobile Top 10 2016 Category M5 - diff --git a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S5547.html b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S5547.html index 917a76e1a..28e36d2ae 100644 --- a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S5547.html +++ b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S5547.html @@ -70,7 +70,6 @@

    Standards

  • OWASP Top 10 2017 Category A3 - Sensitive Data Exposure
  • MITRE, CWE-327 - Use of a Broken or Risky Cryptographic Algorithm
  • -
  • SANS Top 25 - Porous Defenses
  • Mobile AppSec Verification Standard - Cryptography Requirements
  • OWASP Mobile Top 10 2016 Category M5 - diff --git a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S6288.html b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S6288.html index fe92b5a55..c5f36d516 100644 --- a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S6288.html +++ b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S6288.html @@ -41,9 +41,9 @@

    Compliant Solution

    See

    • OWASP Top 10 2021 Category A4 - Insecure Design
    • -
    • developer.android.com - Android keystore system
    • -
    • developer.android.com - Require user authentication - for key use
    • +
    • developer.android.com - Android keystore system
    • +
    • developer.android.com - Require user + authentication for key use
    • Mobile AppSec Verification Standard - Authentication and Session Management Requirements
    • OWASP Mobile Top 10 2016 Category M4 - Insecure diff --git a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S6301.html b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S6301.html index 4a4b72180..bc666dced 100644 --- a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S6301.html +++ b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S6301.html @@ -1,42 +1,94 @@ +

      When storing local data in a mobile application, it is common to use a database that can be encrypted. When encryption of this database is enabled, +the encryption key must be protected properly.

      Why is this an issue?

      -

      Storing data locally is a common task for mobile applications. There are many convenient solutions that allow storing data persistently, for -example SQLiteDatabase and Realm. These systems can be initialized with a secret key in order to store the data encrypted.

      +

      Mobile applications often need to store data (which might be sensitive) locally. For Android, there exist several libraries that simplify this +process by offering a feature-rich database system. SQLCipher and Realm are examples of such libraries. These libraries often add support for database encryption, to protect the contents +from being read by other apps or by attackers.

      +

      When using encryption for such a database, it is important that the encryption key stays secret. If this key is hardcoded in the application, then +it should be considered compromised. The key will be known by anyone with access to the application’s binary code or source code. This means that the +sensitive encrypted data can be decrypted by anyone having access to the binary of the mobile application.

      +

      Furthermore, if the key is hardcoded, it is the same for every user. A compromise of this encryption key implicates every user of the app.

      The encryption key is meant to stay secret and should not be hard-coded in the application as it would mean that:

      -
        -
      • All user would use the same encryption key.
      • -
      • The encryption key would be known by anyone who as access to the source code or the application binary code.
      • -
      • Data stored encrypted in the database would not be protected.
      • -
      -

      There are different approaches how the key can be provided to encrypt and decrypt the database. One of the most convinient way to is to rely on -EncryptedSharedPreferences to store encryption keys. It can also be provided dynamically by the user of the application or fetched from a -remote server.

      -

      Noncompliant code example

      -

      SQLCipher

      -
      -val key = "gb09ym9ydoolp3w886d0tciczj6ve9kszqd65u7d126040gwy86xqimjpuuc788g"
      -val db = SQLiteDatabase.openOrCreateDatabase("test.db", key, null) // Noncompliant
      -
      -

      Realm

      -
      +

      What is the potential impact?

      +

      If an attacker is able to find the encryption key for the mobile database, this can potentially have severe consequences.

      +

      Theft of sensitive data

      +

      If a mobile database is encrypted, it is likely to contain data that is sensitive for the user or the app publisher. For example, it can contain +personally identifiable information (PII), financial data, login credentials, or other sensitive user data.

      +

      By not protecting the encryption key properly, it becomes very easy for an attacker to recover it and then decrypt the mobile database. At that +point, the theft of sensitive data might lead to identity theft, financial fraud, and other forms of malicious activities.

      +

      How to fix it in Realm

      +

      Code examples

      +

      In the example below, a local database is opened using a hardcoded key. To fix this, the key is moved to a secure location instead and retrieved +using a getKey() method.

      +

      Noncompliant code example

      +
       val key = "gb09ym9ydoolp3w886d0tciczj6ve9kszqd65u7d126040gwy86xqimjpuuc788g"
       val config = RealmConfiguration.Builder()
           .encryptionKey(key.toByteArray()) // Noncompliant
           .build()
       val realm = Realm.getInstance(config)
       
      -

      Compliant solution

      -

      SQLCipher

      -
      -val db = SQLiteDatabase.openOrCreateDatabase("test.db", getKey(), null)
      -
      -

      Realm

      -
      +

      Compliant solution

      +
       val config = RealmConfiguration.Builder()
           .encryptionKey(getKey())
           .build()
       val realm = Realm.getInstance(config)
       
      +

      How does this work?

      +

      Using Android’s builtin key storage options

      +

      The Android Keystore system allows apps to store encryption keys in a +container that is protected on a system level. Additionally, it can restrict when and how the keys are used. For example, it allows the app to require +user authentication (for example using a fingerprint) before the key is made available. This is the recommended way to store cryptographic keys on +Android.

      +

      Dynamically retrieving encryption keys remotely

      +

      As user devices are less trusted than controlled environments such as the application backend, the latter should be preferred for the storage of +encryption keys. This requires that a user’s device has an internet connection, which may not be suitable for every use case.

      +

      Going the extra mile

      +

      Avoid storing sensitive data on user devices

      +

      In general, it is always preferable to store as little sensitive data on user devices as possible.

      +

      Of course, some sensitive data always has to be stored on client devices, such as the data required for authentication. In this case, consider +whether the application logic can also function with a hash (or otherwise non-reversible form) of that data. For example, if an email address is +required for authentication, it might be possible to use and store a hashed version of this address instead.

      +

      How to fix it in SQLCipher

      +

      Code examples

      +

      In the example below, a local database is opened using a hardcoded key. To fix this, the key is moved to a secure location instead and retrieved +using a getKey() method.

      +

      Noncompliant code example

      +
      +val key = "gb09ym9ydoolp3w886d0tciczj6ve9kszqd65u7d126040gwy86xqimjpuuc788g"
      +val db = SQLiteDatabase.openOrCreateDatabase("test.db", key, null) // Noncompliant
      +
      +

      Compliant solution

      +
      +val db = SQLiteDatabase.openOrCreateDatabase("test.db", getKey(), null)
      +
      +

      How does this work?

      +

      Using Android’s builtin key storage options

      +

      The Android Keystore system allows apps to store encryption keys in a +container that is protected on a system level. Additionally, it can restrict when and how the keys are used. For example, it allows the app to require +user authentication (for example using a fingerprint) before the key is made available. This is the recommended way to store cryptographic keys on +Android.

      +

      Dynamically retrieving encryption keys remotely

      +

      As user devices are less trusted than controlled environments such as the application backend, the latter should be preferred for the storage of +encryption keys. This requires that a user’s device has an internet connection, which may not be suitable for every use case.

      +

      Going the extra mile

      +

      Avoid storing sensitive data on user devices

      +

      In general, it is always preferable to store as little sensitive data on user devices as possible.

      +

      Of course, some sensitive data always has to be stored on client devices, such as the data required for authentication. In this case, consider +whether the application logic can also function with a hash (or otherwise non-reversible form) of that data. For example, if an email address is +required for authentication, it might be possible to use and store a hashed version of this address instead.

      Resources

      +

      Documentation

      + +

      Standards

      • OWASP Top 10 2021 Category A2 - Cryptographic Failures
      • OWASP Top 10 2021 Category A4 - Insecure Design
      • diff --git a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S6432.html b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S6432.html index 5015cfcb2..6309deb30 100644 --- a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S6432.html +++ b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S6432.html @@ -1,41 +1,78 @@ +

        When encrypting data using AES-GCM or AES-CCM, it is essential not to reuse the same initialization vector (IV, also called nonce) with a given +key. To prevent this, it is recommended to either randomize the IV for each encryption or increment the IV after each encryption.

        Why is this an issue?

        -

        When encrypting data with Counter (CTR) derived block cipher modes of operation, it is essential not to reuse the same initialization vector (IV) -with a given key, such IV is called a "nonce" (number used only once). Galois/Counter (GCM) and Counter with Cipher Block Chaining-Message -Authentication Code (CCM) are both CTR-based modes of operation.

        -

        An attacker, who has knowledge of one plaintext (original content) and ciphertext (encrypted content) pair, is able to retrieve the corresponding -plaintext of any other ciphertext generated with the same IV and key. It also drastically decreases the key recovery computational complexity by -downgrading it to a simpler polynomial root-finding problem.

        -

        When using GCM, NIST recommends a 96 bit length nonce using a 'Deterministic' approach or at least 96 bits using a 'Random Bit Generator (RBG)'. -The 'Deterministic' construction involves a counter, which increments per encryption process. The 'RBG' construction, as the name suggests, generates -the nonce using a random bit generator. Collision probabilities (nonce-key pair reuse) using the 'RBG-based' approach require a shorter key rotation -period, 2^32 maximum invocations per key.

        -

        Noncompliant code example

        -
        +

        When encrypting data using a counter (CTR) derived block cipher mode of operation, it is essential not to reuse the same initialization vector (IV) +for a given key. An IV that complies with this requirement is called a "nonce" (number used once). Galois/Counter +(GCM) and Counter with Cipher Block Chaining-Message Authentication Code (CCM) are both derived from counter mode.

        +

        When using AES-GCM or AES-CCM, a given key and IV pair will create a "keystream" that is used to encrypt a plaintext (original content) into a +ciphertext (encrypted content.) For any key and IV pair, this keystream is always deterministic. Because of this property, encrypting several +plaintexts with one key and IV pair can be catastrophic. If an attacker has access to one plaintext and its associated ciphertext, they are able to +decrypt everything that was created using the same pair.

        +

        Additionally, IV reuse also drastically decreases the key recovery computational complexity by downgrading it to a simpler polynomial root-finding +problem. This means that even without access to a plaintext/ciphertext pair, an attacker may still be able to decrypt all the sensitive data.

        +

        What is the potential impact?

        +

        If the encryption that is being used is flawed, attackers might be able to exploit it in several ways. They might be able to decrypt existing +sensitive data or bypass key protections.

        +

        Below are some real-world scenarios that illustrate some impacts of an attacker exploiting the vulnerability.

        +

        Theft of sensitive data

        +

        The encrypted message might contain data that is considered sensitive and should not be known to third parties.

        +

        By not using the encryption algorithm correctly, the likelihood that an attacker might be able to recover the original sensitive data drastically +increases.

        +

        Additional attack surface

        +

        Encrypted values are often considered trusted, since under normal circumstances it would not be possible for a third party to modify them. If an +attacker is able to modify the cleartext of the encrypted message, it might be possible to trigger other vulnerabilities in the code.

        +

        How to fix it in Java Cryptography Extension

        +

        Code examples

        +

        The example uses a hardcoded IV as a nonce, which causes AES-CCM to be insecure. To fix it, a nonce is randomly generated instead.

        +

        Noncompliant code example

        +
         fun encrypt(key: ByteArray, ptxt: ByteArray) {
        -    val nonce: ByteArray = "7cVgr5cbdCZV".toByteArray() // The initialization vector is a static value
        +    val iv = "7cVgr5cbdCZV".toByteArray()
         
        -    val gcmSpec  = GCMParameterSpec(128, nonce) // The initialization vector is configured here
        -    val skeySpec = SecretKeySpec(key, "AES")
        +    val cipher = Cipher.getInstance("AES/GCM/NoPadding")
        +    val keySpec = SecretKeySpec(key, "AES")
        +    val gcmSpec = GCMParameterSpec(128, iv)
         
        -    val cipher: Cipher = Cipher.getInstance("AES/GCM/NoPadding")
        -    cipher.init(Cipher.ENCRYPT_MODE, skeySpec, gcmSpec) // Noncompliant
        +    cipher.init(Cipher.ENCRYPT_MODE, keySpec, gcmSpec) // Noncompliant
         }
         
        -

        Compliant solution

        -
        +

        Compliant solution

        +
         fun encrypt(key: ByteArray, ptxt: ByteArray) {
        -    val random: SecureRandom = SecureRandom()
        -    val nonce: ByteArray     = ByteArray(12)
        -    random.nextBytes(nonce) // Random 96 bit IV
        +    val random = SecureRandom()
        +    val iv = ByteArray(12)
        +    random.nextBytes(iv)
         
        -    val gcmSpec  = GCMParameterSpec(128, nonce)
        -    val skeySpec = SecretKeySpec(key, "AES")
        +    val cipher = Cipher.getInstance("AES/GCM/NoPadding")
        +    val keySpec = SecretKeySpec(key, "AES")
        +    val gcmSpec = GCMParameterSpec(128, iv)
         
        -    val cipher: Cipher = Cipher.getInstance("AES/GCM/NoPadding")
        -    cipher.init(Cipher.ENCRYPT_MODE, skeySpec, gcmSpec)
        +    cipher.init(Cipher.ENCRYPT_MODE, keySpec, gcmSpec)
         }
         
        +

        How does this work?

        +

        For AES-GCM and AES-CCM, NIST recommends generating a nonce using either a deterministic approach or using a 'Random Bit Generator (RBG)'.

        +

        Generating nonces using random number generation

        +

        When using a randomized approach, NIST recommends a nonce of at least 96 bits using a cryptographically secure pseudorandom number generator +(CSPRNG.) Such a generator can create output with a sufficiently low probability of the same number being output twice (also called a +collision) for a long time. However, after 232 generated numbers for the same key, NIST recommends rotating this key for a new +one. After that amount of generated numbers, the probability of a collision is high enough to be considered insecure.

        +

        The code example above demonstrates how CSPRNGs can be used to generate nonces.

        +

        Be careful to use a random number generator that is sufficiently secure. Default (non-cryptographically secure) RNGs might be more prone to +collisions in their output, which is catastrophic for counter-based encryption modes.

        +

        Deterministically generating nonces

        +

        One method to prevent the same IV from being used multiple times for the same key is to update the IV in a deterministic way after each encryption. +The most straightforward deterministic method for this is a counter.

        +

        The way this works is simple: for any key, the first IV is the number zero. After this IV is used to encrypt something with a key, it is +incremented for that key (and is now equal to 1). Although this requires additional bookkeeping, it should guarantee that for each encryption key, an +IV is never repeated.

        +

        For a secure implementation, NIST suggests generating these nonces in two parts: a fixed field and an invocation field. The fixed field should be +used to identify the device executing the encryption (for example, it could contain a device ID), such that for one key, no two devices can generate +the same nonce. The invocation field contains the counter as described above. For a 96-bit nonce, NIST recommends (but does not require) using a +32-bit fixed field and a 64-bit invocation field. Additional details can be found in the NIST Special Publication 800-38D.

        Resources

        +

        Standards

        • OWASP Top 10 2021 Category A2 - Cryptographic Failures
        • OWASP Top 10 2017 Category A3 - Sensitive Data Exposure diff --git a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S6511.html b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S6511.html index 67d25a9f0..85f37cb5c 100644 --- a/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S6511.html +++ b/sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/kotlin/rules/kotlin/S6511.html @@ -37,7 +37,7 @@

          Compliant solution

        Noncompliant code example

        When threshold = 2

        -
        +
         fun compare(a: Int, b: Int): Int {
             // ...
             return if (a > b) { // Noncompliant
        @@ -50,7 +50,7 @@ 

        Noncompliant code example

        }

        Compliant solution

        -
        +
         fun compare(a: Int, b: Int): Int {
             // ...
             return when { // Compliant
        diff --git a/utils-kotlin/README.md b/utils-kotlin/README.md
        index 37e85214a..a0d6d1b91 100644
        --- a/utils-kotlin/README.md
        +++ b/utils-kotlin/README.md
        @@ -22,8 +22,8 @@ To re-generate ktlint's [`rules.json`](../sonar-kotlin-plugin/src/main/resources
         
         To re-generate android lint's [`rules.json`](../../sonar-kotlin-plugin/src/main/resources/org/sonar/l10n/android/rules/androidlint/rules.json):
         
        -1. Update android lint with command `$ANDROID_SDK_HOME/tools/bin/sdkmanager --install "cmdline-tools;latest"`
        -2. Check Android Lint version with command `$ANDROID_SDK_HOME/cmdline-tools/$version/bin/lint --version`
        +1. Update android lint with command `$ANDROID_SDK_HOME/tools/bin/sdkmanager --install "cmdline-tools;latest"` (run with java sdk 8 to work around the split package problem)
        +2. Check Android Lint version with command `$ANDROID_SDK_HOME/cmdline-tools/$version/bin/lint --version` (requires java sdk 17)
         3. Export android lint help `$ANDROID_SDK_HOME/cmdline-tools/$version/bin/lint --show > utils-kotlin/src/main/resources/android-lint-help.txt`
         4. Run `./gradlew utils-kotlin:updateAndroidLintRules` from the project's root directory
         
        diff --git a/utils-kotlin/src/main/resources/android-lint-help.txt b/utils-kotlin/src/main/resources/android-lint-help.txt
        index 38ec1a267..4cea17926 100644
        --- a/utils-kotlin/src/main/resources/android-lint-help.txt
        +++ b/utils-kotlin/src/main/resources/android-lint-help.txt
        @@ -188,24 +188,6 @@ because of course the fields available on android.R are not the ones you'd
         expect from just looking at your own R class.
         
         
        -UsesMinSdkAttributes
        ---------------------
        -Summary: Minimum SDK and target SDK attributes not defined
        -
        -Priority: 9 / 10
        -Severity: Warning
        -Category: Correctness
        -Vendor: Android Open Source Project
        -Contact: https://groups.google.com/g/lint-dev
        -Feedback: https://issuetracker.google.com/issues/new?component=192708
        -
        -The manifest should contain a  element which defines the minimum API
        -Level required for the application to run, as well as the target version (the
        -highest API level you have tested the version for).
        -
        -More information: 
        -https://developer.android.com/guide/topics/manifest/uses-sdk-element.html
        -
         WrongViewCast
         -------------
         Summary: Mismatched view type
        @@ -640,6 +622,18 @@ requestLegacyExternalStorage). In particular, WRITE_EXTERNAL_STORAGE will no
         longer provide write access to all files; it will provide the equivalent of
         READ_EXTERNAL_STORAGE instead.
         
        +As of Android 13, if you need to query or interact with MediaStore or media
        +files on the shared storage, you should be using instead one or more new
        +storage permissions:
        +* android.permission.READ_MEDIA_IMAGES
        +* android.permission.READ_MEDIA_VIDEO
        +* android.permission.READ_MEDIA_AUDIO
        +
        +and then add maxSdkVersion="33" to the older permission. See the developer
        +guide for how to do this:
        +https://developer.android.com/about/versions/13/behavior-changes-13#granular-m
        +edia-permissions
        +
         The MANAGE_EXTERNAL_STORAGE permission can be used to manage all files, but it
         is rarely necessary and most apps on Google Play are not allowed to use it.
         Most apps should instead migrate to use scoped storage. To modify or delete
        @@ -1175,7 +1169,7 @@ Contact: https://groups.google.com/g/lint-dev
         Feedback: https://issuetracker.google.com/issues/new?component=192708
         
         Some methods have no side effects, and calling them without doing something
        -without the result is suspicious.
        +with the result is suspicious.
         
         
         CommitPrefEdits
        @@ -1327,6 +1321,24 @@ on a WorkContinuation to have it and its parent continuations enqueued inside
         WorkManager.
         
         
        +ExactAlarm
        +----------
        +Summary: Invalid Usage of Exact Alarms
        +
        +Priority: 6 / 10
        +Severity: Error
        +Category: Correctness
        +Vendor: Android Open Source Project
        +Contact: https://groups.google.com/g/lint-dev
        +Feedback: https://issuetracker.google.com/issues/new?component=192708
        +
        +The USE_EXACT_ALARM permission is only available when targeting API level 33
        +and above. Also, note that this permission is only permitted for apps whose
        +core functionality requires precisely-timed actions for user facing features.
        +
        +More information: 
        +https://developer.android.com/training/scheduling/alarms
        +
         ExifInterface
         -------------
         Summary: Using android.media.ExifInterface
        @@ -2181,35 +2193,6 @@ More information:
         https://developer.android.com/distribute/best-practices/develop/target-sdk.html
         https://developer.android.com/reference/android/os/Build.VERSION_CODES.html
         
        -Override
        ---------
        -Summary: Method conflicts with new inherited method
        -
        -Priority: 6 / 10
        -Severity: Error
        -Category: Correctness
        -Vendor: Android Open Source Project
        -Contact: https://groups.google.com/g/lint-dev
        -Feedback: https://issuetracker.google.com/issues/new?component=192708
        -
        -Suppose you are building against Android API 8, and you've subclassed
        -Activity. In your subclass you add a new method called isDestroyed(). At some
        -later point, a method of the same name and signature is added to Android. Your
        -method will now override the Android method, and possibly break its contract.
        -Your method is not calling super.isDestroyed(), since your compilation target
        -doesn't know about the method.
        -
        -The above scenario is what this lint detector looks for. The above example is
        -real, since isDestroyed() was added in API 17, but it will be true for any
        -method you have added to a subclass of an Android class where your build
        -target is lower than the version the method was introduced in.
        -
        -To fix this, either rename your method, or if you are really trying to augment
        -the builtin method if available, switch to a higher build target where you can
        -deliberately add @Override on your overriding method, and call super if
        -appropriate etc.
        -
        -
         OverrideAbstract
         ----------------
         Summary: Not overriding abstract methods on older platforms
        @@ -2353,6 +2336,28 @@ Some APIs require optional features to be present. This check makes sure that
         calls to these APIs are surrounded by a check which enforces this.
         
         
        +ScheduleExactAlarm
        +------------------
        +Summary: Scheduling Exact Alarms Without Required Permission
        +
        +Priority: 6 / 10
        +Severity: Error
        +Category: Correctness
        +Vendor: Android Open Source Project
        +Contact: https://groups.google.com/g/lint-dev
        +Feedback: https://issuetracker.google.com/issues/new?component=192708
        +
        +Applications looking to schedule exact alarms should ensure that the
        +SCHEDULE_EXACT_ALARM permission is granted by calling the
        +AlarmManager#canScheduleExactAlarms API before attempting to set an exact
        +alarm. If the permission is not granted to your application, please consider
        +requesting it from the user by starting the
        +ACTION_REQUEST_SCHEDULE_EXACT_ALARM intent or gracefully falling back to
        +another option.
        +
        +More information: 
        +https://developer.android.com/training/scheduling/alarms#exact
        +
         SdCardPath
         ----------
         Summary: Hardcoded reference to /sdcard
        @@ -3347,6 +3352,40 @@ In other words, use name, not  name .
         More information: 
         https://issuetracker.google.com/36988969
         
        +NoOp
        +----
        +Summary: NoOp Code
        +
        +Priority: 5 / 10
        +Severity: Warning
        +Category: Correctness
        +Vendor: Android Open Source Project
        +Contact: https://groups.google.com/g/lint-dev
        +Feedback: https://issuetracker.google.com/issues/new?component=192708
        +NOTE: This issue is disabled by default!
        +You can enable it by adding --enable NoOp
        +
        +This check looks for code which looks like it's a no-op -- usually leftover
        +expressions from interactive debugging, but in some cases bugs where you had
        +intended to do something with the expression such as assign it to a field.
        +
        +Available options:
        +
        +pure-getters (default is false):
        +Whether to assume methods with getter-names have no side effects.
        +
        +Getter methods (where names start with get or is, and have non-void return types, and no arguments) should not have side effects. With this option turned on, lint will assume that is the case and will list any getter calls whose results are ignored as suspicious code.
        +
        +To configure this option, use a lint.xml file with an