[SDK Index] Show recommended versions
... in policy and outadated issues. This change also adds a remark
saying that the recommended versions are not reviwed by Google and tells
users to carefully evaluate any third party libraries before integrating
them into their apps.
Bug: 336826464
Test: GooglePlaySdkIndexTest
Change-Id: I06b258d5823e4d694781a3cc746dd16d252819b7
diff --git a/lint/libs/lint-checks/src/main/java/com/android/tools/lint/checks/GooglePlaySdkIndex.kt b/lint/libs/lint-checks/src/main/java/com/android/tools/lint/checks/GooglePlaySdkIndex.kt
index 14c18d9..39147a7 100644
--- a/lint/libs/lint-checks/src/main/java/com/android/tools/lint/checks/GooglePlaySdkIndex.kt
+++ b/lint/libs/lint-checks/src/main/java/com/android/tools/lint/checks/GooglePlaySdkIndex.kt
@@ -383,8 +383,9 @@
artifactId: String,
versionString: String,
): List<String> {
+ val recommendedVersions = getPolicyRecommendedVersions(groupId, artifactId, versionString)
return getPolicyLabels(getLabels(groupId, artifactId, versionString)).map { label ->
- "[Prevents app release in Google Play Console] $groupId:$artifactId version $versionString has $label issues that will block publishing of your app to Play Console"
+ "[Prevents app release in Google Play Console] $groupId:$artifactId version $versionString has $label issues that will block publishing of your app to Play Console$recommendedVersions"
}
}
@@ -394,8 +395,9 @@
artifactId: String,
versionString: String,
): List<String> {
+ val recommendedVersions = getPolicyRecommendedVersions(groupId, artifactId, versionString)
return getPolicyLabels(getLabels(groupId, artifactId, versionString)).map { label ->
- "$groupId:$artifactId version $versionString has $label issues that will block publishing of your app to Play Console in the future"
+ "$groupId:$artifactId version $versionString has $label issues that will block publishing of your app to Play Console in the future$recommendedVersions"
}
}
@@ -416,12 +418,20 @@
}
/** Generate a message for a library that has blocking outdated issues */
- fun generateBlockingOutdatedMessage(groupId: String, artifactId: String, versionString: String) =
- "[Prevents app release in Google Play Console] $groupId:$artifactId version $versionString has been reported as outdated by its author and will block publishing of your app to Play Console"
+ fun generateBlockingOutdatedMessage(
+ groupId: String,
+ artifactId: String,
+ versionString: String,
+ ): String {
+ val recommendedVersions = getOutdatedRecommendedVersions(groupId, artifactId, versionString)
+ return "[Prevents app release in Google Play Console] $groupId:$artifactId version $versionString has been reported as outdated by its author and will block publishing of your app to Play Console$recommendedVersions"
+ }
/** Generate a message for a library that has non-blocking outdated issues */
- fun generateOutdatedMessage(groupId: String, artifactId: String, versionString: String) =
- "$groupId:$artifactId version $versionString has been reported as outdated by its author"
+ fun generateOutdatedMessage(groupId: String, artifactId: String, versionString: String): String {
+ val recommendedVersions = getOutdatedRecommendedVersions(groupId, artifactId, versionString)
+ return "$groupId:$artifactId version $versionString has been reported as outdated by its author$recommendedVersions"
+ }
/** Generate a message for a library that has blocking issues */
fun generateBlockingGenericIssueMessage(
@@ -527,4 +537,41 @@
if (message.isNullOrBlank()) return ""
return ". Note: $message"
}
+
+ private fun getOutdatedRecommendedVersions(
+ groupId: String,
+ artifactId: String,
+ versionString: String,
+ ): String {
+ val labels = getLabels(groupId, artifactId, versionString) ?: return ""
+ val outdatedIssue = labels.outdatedIssueInfo ?: return ""
+ return generateRecommendedList(outdatedIssue.recommendedVersionsList)
+ }
+
+ private fun getPolicyRecommendedVersions(
+ groupId: String,
+ artifactId: String,
+ versionString: String,
+ ): String {
+ val labels = getLabels(groupId, artifactId, versionString) ?: return ""
+ val policyIssue = labels.policyIssuesInfo ?: return ""
+ return generateRecommendedList(policyIssue.recommendedVersionsList)
+ }
+
+ private fun generateRecommendedList(listOfVersions: List<LibraryVersionRange?>?): String {
+ val ranges =
+ (listOfVersions ?: return "").filterNotNull().joinToString("\n") { range ->
+ if (range.upperBound.isNullOrBlank()) {
+ " - ${range.lowerBound} or higher"
+ } else if (range.upperBound != range.lowerBound) {
+ " - From ${range.lowerBound} to ${range.upperBound}"
+ } else {
+ " - ${range.lowerBound}"
+ }
+ }
+ if (ranges.isEmpty()) return ""
+ return ".\nThe library author recommends using versions:\n$ranges\n" +
+ "These versions have not been reviewed by Google Play. They could contain vulnerabilities or policy violations. " +
+ "Carefully evaluate any third-party SDKs before integrating them into your app."
+ }
}
diff --git a/lint/libs/lint-tests/src/test/java/com/android/tools/lint/checks/GooglePlaySdkIndexTest.kt b/lint/libs/lint-tests/src/test/java/com/android/tools/lint/checks/GooglePlaySdkIndexTest.kt
index 2095407..a33e067 100644
--- a/lint/libs/lint-tests/src/test/java/com/android/tools/lint/checks/GooglePlaySdkIndexTest.kt
+++ b/lint/libs/lint-tests/src/test/java/com/android/tools/lint/checks/GooglePlaySdkIndexTest.kt
@@ -294,6 +294,19 @@
.addViolatedSdkPolicies(
LibraryVersionLabels.PolicyIssuesInfo.SdkPolicy.SDK_POLICY_MALWARE
)
+ .addRecommendedVersions(
+ LibraryVersionRange.newBuilder()
+ .setLowerBound("7.1.9")
+ .setUpperBound("7.1.9")
+ )
+ .addRecommendedVersions(
+ LibraryVersionRange.newBuilder()
+ .setLowerBound("7.2.1")
+ .setUpperBound("7.3.0")
+ )
+ .addRecommendedVersions(
+ LibraryVersionRange.newBuilder().setLowerBound("8.0.0")
+ )
)
.setSeverity(LibraryVersionLabels.Severity.BLOCKING_SEVERITY)
)
@@ -347,8 +360,8 @@
LibraryIdentifier.newBuilder()
.setMavenId(
LibraryIdentifier.MavenIdentifier.newBuilder()
- .setGroupId("no.url")
- .setArtifactId("no.url")
+ .setGroupId("no.url.group")
+ .setArtifactId("no.url.artifact")
.build()
)
)
@@ -394,6 +407,11 @@
.setLowerBound("1.0.1")
.setUpperBound("1.0.2")
)
+ .addRecommendedVersions(
+ LibraryVersionRange.newBuilder()
+ .setLowerBound("1.0.4")
+ .setUpperBound("1.0.4")
+ )
// An open range
.addRecommendedVersions(
LibraryVersionRange.newBuilder().setLowerBound("2.0.0")
@@ -593,6 +611,21 @@
}
@Test
+ fun `multiple policy types issue message with recommended versions`() {
+ verifyPolicyMessages(
+ "7.1.8",
+ listOf("User Data policy", "Malware policy"),
+ recommendedVersions =
+ ".\nThe library author recommends using versions:\n" +
+ " - 7.1.9\n" +
+ " - From 7.2.1 to 7.3.0\n" +
+ " - 8.0.0 or higher\n" +
+ "These versions have not been reviewed by Google Play. They could contain vulnerabilities or policy violations. " +
+ "Carefully evaluate any third-party SDKs before integrating them into your app.",
+ )
+ }
+
+ @Test
fun `unknown policy type issue message`() {
verifyPolicyMessages("7.1.10", listOf("Permissions policy", "policy"))
}
@@ -638,6 +671,20 @@
assertThat(index.generateCriticalMessage("log4j", "log4j", "1.2.13")).isEqualTo(expectedMessage)
}
+ @Test
+ fun `Outdated issue with recommended versions`() {
+ val expectedMessage =
+ "no.url.group:no.url.artifact version 1.0.0 has been reported as outdated by its author.\n" +
+ "The library author recommends using versions:\n" +
+ " - From 1.0.1 to 1.0.2\n" +
+ " - 1.0.4\n" +
+ " - 2.0.0 or higher\n" +
+ "These versions have not been reviewed by Google Play. They could contain vulnerabilities or policy violations. " +
+ "Carefully evaluate any third-party SDKs before integrating them into your app."
+ assertThat(index.generateOutdatedMessage("no.url.group", "no.url.artifact", "1.0.0"))
+ .isEqualTo(expectedMessage)
+ }
+
private fun countOutdatedIssues(): Int {
var result = 0
for (sdk in proto.sdksList) {
@@ -702,11 +749,15 @@
return result
}
- private fun verifyPolicyMessages(version: String, policyTypes: List<String>) {
+ private fun verifyPolicyMessages(
+ version: String,
+ policyTypes: List<String>,
+ recommendedVersions: String = "",
+ ) {
index.showPolicyIssues = true
val expectedBlockingMessages =
policyTypes.map { policyType ->
- "[Prevents app release in Google Play Console] com.example.ads.third.party:example version $version has $policyType issues that will block publishing of your app to Play Console"
+ "[Prevents app release in Google Play Console] com.example.ads.third.party:example version $version has $policyType issues that will block publishing of your app to Play Console$recommendedVersions"
}
assertThat(
index.generateBlockingPolicyMessages("com.example.ads.third.party", "example", version)
@@ -714,7 +765,7 @@
.isEqualTo(expectedBlockingMessages)
val expectedNonBlockingMessages =
policyTypes.map { policyType ->
- "com.example.ads.third.party:example version $version has $policyType issues that will block publishing of your app to Play Console in the future"
+ "com.example.ads.third.party:example version $version has $policyType issues that will block publishing of your app to Play Console in the future$recommendedVersions"
}
assertThat(index.generatePolicyMessages("com.example.ads.third.party", "example", version))
.isEqualTo(expectedNonBlockingMessages)