Skip to content

Commit 2b994fe

Browse files
authored
Ban javax.* dependencies (#3866)
The `javax.*` group ID artifacts are often GPL+CE licensed, which is often concerning, even if it is not a real issue. Technically, we do not need those dependencies in production code. This means that we can savely remove those dependencies from the Quarkus production runtime. Due to the Spark integration tests, as Spark needs the old Servlet API in the `javax.*` namespace, we cannot globally ban the old servlet API, which causes some special handling.
1 parent 077f76c commit 2b994fe

File tree

5 files changed

+118
-45
lines changed

5 files changed

+118
-45
lines changed

build-logic/src/main/kotlin/polaris-java.gradle.kts

Lines changed: 54 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,13 @@
1717
* under the License.
1818
*/
1919

20+
import asf.AsfProject.Companion.unsafeCast
2021
import java.util.Properties
2122
import kotlin.jvm.java
2223
import net.ltgt.gradle.errorprone.CheckSeverity
2324
import net.ltgt.gradle.errorprone.errorprone
2425
import org.gradle.api.tasks.compile.JavaCompile
2526
import org.gradle.api.tasks.testing.Test
26-
import org.gradle.kotlin.dsl.assign
2727
import org.gradle.kotlin.dsl.named
2828
import org.kordamp.gradle.plugin.jandex.JandexExtension
2929
import org.kordamp.gradle.plugin.jandex.JandexPlugin
@@ -238,26 +238,62 @@ tasks.register("printRuntimeClasspath").configure {
238238
}
239239
}
240240

241-
configurations.all {
242-
rootProject
243-
.file("gradle/banned-dependencies.txt")
244-
.readText(Charsets.UTF_8)
245-
.trim()
246-
.lines()
247-
.map { it.trim() }
248-
.filterNot { it.isBlank() || it.startsWith("#") }
249-
.forEach { line ->
250-
val idx = line.indexOf(':')
251-
if (idx == -1) {
252-
exclude(group = line)
253-
} else {
254-
val group = line.substring(0, idx)
255-
val module = line.substring(idx + 1)
256-
exclude(group = group, module = module)
257-
}
241+
class BannedDependency(val group: String, val module: String?) {
242+
fun exclude(configuration: Configuration) = configuration.exclude(group = group, module = module)
243+
244+
companion object {
245+
fun parseList(file: File): List<BannedDependency> =
246+
file
247+
.readText(Charsets.UTF_8)
248+
.trim()
249+
.lines()
250+
.map { it.trim() }
251+
.filterNot { it.isBlank() || it.startsWith("#") }
252+
.map { line ->
253+
val idx = line.indexOf(':')
254+
if (idx == -1) {
255+
BannedDependency(line, null)
256+
} else {
257+
val group = line.substring(0, idx)
258+
val module = line.substring(idx + 1)
259+
BannedDependency(group, module)
260+
}
261+
}
262+
}
263+
}
264+
265+
class BannedDependencies(
266+
val globallyBanned: List<BannedDependency>,
267+
val quarkusProdBanned: List<BannedDependency>,
268+
) {
269+
fun applyTo(configuration: Configuration) {
270+
globallyBanned.forEach { it.exclude(configuration) }
271+
if (configuration.name.startsWith("quarkusProd")) {
272+
quarkusProdBanned.forEach { it.exclude(configuration) }
258273
}
274+
}
275+
276+
fun applyTo(configurations: ConfigurationContainer) {
277+
configurations.all { applyTo(this) }
278+
}
279+
}
280+
281+
fun bannedDependencies(): BannedDependencies {
282+
return if (rootProject.extra.has("bannedDependencies")) {
283+
unsafeCast(rootProject.extra["bannedDependencies"]) as BannedDependencies
284+
} else {
285+
val bannedDependencies =
286+
BannedDependencies(
287+
BannedDependency.parseList(rootProject.file("gradle/banned-dependencies.txt")),
288+
BannedDependency.parseList(rootProject.file("gradle/banned-quarkus-prod-dependencies.txt")),
289+
)
290+
rootProject.extra["bannedDependencies"] = bannedDependencies
291+
bannedDependencies
292+
}
259293
}
260294

295+
bannedDependencies().applyTo(configurations)
296+
261297
gradle.sharedServices.registerIfAbsent(
262298
"intTestParallelismConstraint",
263299
TestingParallelismHelper::class.java,

gradle/banned-dependencies.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#
1919

2020
# This file contains the globally banned dependencies.
21+
2122
# Each banned dependency must be in the form
2223
# <group-id> ':' <module>
2324
# or
@@ -26,6 +27,12 @@
2627

2728
# Contains old javax.* annotations that we do not want
2829
com.google.code.findbugs:jsr305
30+
javax.annotation:javax.annotation-api
31+
javax.servlet.jsp:jsp-api
32+
# Cannot globally ban javax.servlet:javax.servlet-api, because it is needed by Spark 3.5 integration tests
33+
javax.validation:validation-api
34+
javax.ws.rs:jsr311-api
35+
2936

3037
# See https://github.com/RoaringBitmap/RoaringBitmap/issues/749, should only use org.roaringbitmap:RoaringBitmap
3138
com.github.RoaringBitmap.RoaringBitmap
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#
2+
# Licensed to the Apache Software Foundation (ASF) under one
3+
# or more contributor license agreements. See the NOTICE file
4+
# distributed with this work for additional information
5+
# regarding copyright ownership. The ASF licenses this file
6+
# to you under the Apache License, Version 2.0 (the
7+
# "License"); you may not use this file except in compliance
8+
# with the License. You may obtain a copy of the License at
9+
#
10+
# http://www.apache.org/licenses/LICENSE-2.0
11+
#
12+
# Unless required by applicable law or agreed to in writing,
13+
# software distributed under the License is distributed on an
14+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
# KIND, either express or implied. See the License for the
16+
# specific language governing permissions and limitations
17+
# under the License.
18+
#
19+
20+
# This file contains the dependencies banned from Quarkus production runtime.
21+
22+
# Each banned dependency must be in the form
23+
# <group-id> ':' <module>
24+
# or
25+
# <group-id>
26+
27+
28+
# Contains old javax.* annotations that we do not want
29+
javax.servlet:javax.servlet-api

integration-tests/build.gradle.kts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ dependencies {
5858
exclude("org.slf4j", "jul-to-slf4j")
5959
}
6060

61+
implementation(libs.jakarta.ws.rs.api)
62+
6163
implementation(platform(libs.junit.bom))
6264
implementation("org.junit.jupiter:junit-jupiter")
6365
implementation("org.junit.jupiter:junit-jupiter-api")

integration-tests/src/main/java/org/apache/polaris/service/it/test/PolarisManagementServiceIntegrationTest.java

Lines changed: 26 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@
1818
*/
1919
package org.apache.polaris.service.it.test;
2020

21-
import static javax.ws.rs.core.Response.Status.CREATED;
22-
import static javax.ws.rs.core.Response.Status.FORBIDDEN;
21+
import static jakarta.ws.rs.core.Response.Status.CREATED;
22+
import static jakarta.ws.rs.core.Response.Status.FORBIDDEN;
2323
import static org.apache.polaris.service.it.env.PolarisClient.polarisClient;
2424
import static org.apache.polaris.service.it.test.PolarisApplicationIntegrationTest.PRINCIPAL_ROLE_ALL;
2525
import static org.assertj.core.api.Assertions.assertThat;
@@ -188,7 +188,7 @@ public void testListCatalogsUnauthorized() {
188188
managementApi.createPrincipal(client.newEntityName("a_new_user"));
189189
String authToken = client.obtainToken(principal);
190190
try (Response response = client.managementApi(authToken).request("v1/catalogs").get()) {
191-
assertThat(response).returns(Response.Status.FORBIDDEN.getStatusCode(), Response::getStatus);
191+
assertThat(response).returns(FORBIDDEN.getStatusCode(), Response::getStatus);
192192
}
193193
}
194194

@@ -200,7 +200,7 @@ public void testCreateCatalog() {
200200
.post(
201201
Entity.json(
202202
"{\"catalog\":{\"type\":\"INTERNAL\",\"name\":\"my-catalog\",\"properties\":{\"default-base-location\":\"s3://my-bucket/path/to/data\"},\"storageConfigInfo\":{\"storageType\":\"S3\",\"roleArn\":\"arn:aws:iam::123456789012:role/my-role\",\"externalId\":\"externalId\",\"userArn\":\"userArn\",\"allowedLocations\":[\"s3://my-old-bucket/path/to/data\"]}}}"))) {
203-
assertThat(response).returns(Response.Status.CREATED.getStatusCode(), Response::getStatus);
203+
assertThat(response).returns(CREATED.getStatusCode(), Response::getStatus);
204204
}
205205

206206
// 204 Successful delete
@@ -230,7 +230,7 @@ public void testCreateCatalogWithInvalidName() {
230230
.setStorageConfigInfo(awsConfigModel)
231231
.build();
232232
try (Response response = managementApi.request("v1/catalogs").post(Entity.json(catalog))) {
233-
assertThat(response).returns(Response.Status.CREATED.getStatusCode(), Response::getStatus);
233+
assertThat(response).returns(CREATED.getStatusCode(), Response::getStatus);
234234
}
235235

236236
String longInvalidName = newRandomString(MAX_IDENTIFIER_LENGTH + 1);
@@ -282,7 +282,7 @@ public void testCreateCatalogWithAzureStorageConfig() {
282282
.build();
283283
try (Response response =
284284
managementApi.request("v1/catalogs").post(Entity.json(new CreateCatalogRequest(catalog)))) {
285-
assertThat(response).returns(Response.Status.CREATED.getStatusCode(), Response::getStatus);
285+
assertThat(response).returns(CREATED.getStatusCode(), Response::getStatus);
286286
}
287287
try (Response response = managementApi.request("v1/catalogs/my-catalog").get()) {
288288
assertThat(response).returns(Response.Status.OK.getStatusCode(), Response::getStatus);
@@ -431,7 +431,7 @@ public void testUpdateCatalogWithoutDefaultBaseLocationInUpdate() {
431431
.build();
432432
try (Response response =
433433
managementApi.request("v1/catalogs").post(Entity.json(new CreateCatalogRequest(catalog)))) {
434-
assertThat(response).returns(Response.Status.CREATED.getStatusCode(), Response::getStatus);
434+
assertThat(response).returns(CREATED.getStatusCode(), Response::getStatus);
435435
}
436436

437437
// 200 successful GET after creation
@@ -819,7 +819,7 @@ public void testListPrincipalsUnauthorized() {
819819
managementApi.createPrincipal(client.newEntityName("new_admin"));
820820
String authToken = client.obtainToken(principal);
821821
try (Response response = client.managementApi(authToken).request("v1/principals").get()) {
822-
assertThat(response).returns(Response.Status.FORBIDDEN.getStatusCode(), Response::getStatus);
822+
assertThat(response).returns(FORBIDDEN.getStatusCode(), Response::getStatus);
823823
}
824824
}
825825

@@ -842,7 +842,7 @@ public void testCreatePrincipalAndRotateCredentials() {
842842
managementApi
843843
.request("v1/principals/{p}/rotate", Map.of("p", principal.getName()))
844844
.post(Entity.json(""))) {
845-
assertThat(response).returns(Response.Status.FORBIDDEN.getStatusCode(), Response::getStatus);
845+
assertThat(response).returns(FORBIDDEN.getStatusCode(), Response::getStatus);
846846
}
847847

848848
String oldUserToken = client.obtainToken(creds);
@@ -853,7 +853,7 @@ public void testCreatePrincipalAndRotateCredentials() {
853853
.managementApi(oldUserToken)
854854
.request("v1/principals/{p}", Map.of("p", principal.getName()))
855855
.get()) {
856-
assertThat(response).returns(Response.Status.FORBIDDEN.getStatusCode(), Response::getStatus);
856+
assertThat(response).returns(FORBIDDEN.getStatusCode(), Response::getStatus);
857857
ErrorResponse error = response.readEntity(ErrorResponse.class);
858858
assertThat(error)
859859
.isNotNull()
@@ -932,7 +932,7 @@ public void testCreatePrincipalAndResetCredentialsWithCustomValues() {
932932
.request("v1/principals/{p}/reset", Map.of("p", principal.getName()))
933933
.post(Entity.json(customBody))) {
934934

935-
assertThat(response).returns(Response.Status.FORBIDDEN.getStatusCode(), Response::getStatus);
935+
assertThat(response).returns(FORBIDDEN.getStatusCode(), Response::getStatus);
936936
}
937937
}
938938

@@ -1288,7 +1288,7 @@ public void testCreateListUpdateAndDeleteCatalogRole() {
12881288
.request("v1/catalogs/{cat}/catalog-roles", Map.of("cat", catalogName))
12891289
.post(Entity.json(new CreateCatalogRoleRequest(catalogRole)))) {
12901290

1291-
assertThat(response).returns(Response.Status.CREATED.getStatusCode(), Response::getStatus);
1291+
assertThat(response).returns(CREATED.getStatusCode(), Response::getStatus);
12921292
}
12931293

12941294
// Second attempt to create the same entity should fail with CONFLICT.
@@ -1428,7 +1428,7 @@ public void testAssignListAndRevokePrincipalRoles() {
14281428
.request("v1/principals")
14291429
.post(Entity.json(new CreatePrincipalRequest(principal1, false)))) {
14301430

1431-
assertThat(response).returns(Response.Status.CREATED.getStatusCode(), Response::getStatus);
1431+
assertThat(response).returns(CREATED.getStatusCode(), Response::getStatus);
14321432
}
14331433

14341434
Principal principal2 = new Principal(client.newEntityName("myprincipal2"));
@@ -1437,7 +1437,7 @@ public void testAssignListAndRevokePrincipalRoles() {
14371437
.request("v1/principals")
14381438
.post(Entity.json(new CreatePrincipalRequest(principal2, false)))) {
14391439

1440-
assertThat(response).returns(Response.Status.CREATED.getStatusCode(), Response::getStatus);
1440+
assertThat(response).returns(CREATED.getStatusCode(), Response::getStatus);
14411441
}
14421442

14431443
// One PrincipalRole
@@ -1450,7 +1450,7 @@ public void testAssignListAndRevokePrincipalRoles() {
14501450
.request(
14511451
"v1/principals/{prince}/principal-roles", Map.of("prince", principal1.getName()))
14521452
.put(Entity.json(principalRole))) {
1453-
assertThat(response).returns(Response.Status.CREATED.getStatusCode(), Response::getStatus);
1453+
assertThat(response).returns(CREATED.getStatusCode(), Response::getStatus);
14541454
}
14551455

14561456
// Should list myprincipalrole
@@ -1582,7 +1582,7 @@ public void testAssignListAndRevokeCatalogRoles() {
15821582
.request("v1/catalogs/{cat}/catalog-roles", Map.of("cat", catalog.getName()))
15831583
.post(Entity.json(new CreateCatalogRoleRequest(catalogRole)))) {
15841584

1585-
assertThat(response).returns(Response.Status.CREATED.getStatusCode(), Response::getStatus);
1585+
assertThat(response).returns(CREATED.getStatusCode(), Response::getStatus);
15861586
}
15871587

15881588
// Create another one in a different catalog.
@@ -1601,7 +1601,7 @@ public void testAssignListAndRevokeCatalogRoles() {
16011601
.request("v1/catalogs/{cat}/catalog-roles", Map.of("cat", otherCatalog.getName()))
16021602
.post(Entity.json(new CreateCatalogRoleRequest(otherCatalogRole)))) {
16031603

1604-
assertThat(response).returns(Response.Status.CREATED.getStatusCode(), Response::getStatus);
1604+
assertThat(response).returns(CREATED.getStatusCode(), Response::getStatus);
16051605
}
16061606

16071607
// Assign both the roles to mypr1
@@ -1612,7 +1612,7 @@ public void testAssignListAndRevokeCatalogRoles() {
16121612
Map.of("pr", principalRole1.getName(), "cat", catalog.getName()))
16131613
.put(Entity.json(new GrantCatalogRoleRequest(catalogRole)))) {
16141614

1615-
assertThat(response).returns(Response.Status.CREATED.getStatusCode(), Response::getStatus);
1615+
assertThat(response).returns(CREATED.getStatusCode(), Response::getStatus);
16161616
}
16171617
try (Response response =
16181618
managementApi
@@ -1621,7 +1621,7 @@ public void testAssignListAndRevokeCatalogRoles() {
16211621
Map.of("pr", principalRole1.getName(), "cat", otherCatalog.getName()))
16221622
.put(Entity.json(new GrantCatalogRoleRequest(otherCatalogRole)))) {
16231623

1624-
assertThat(response).returns(Response.Status.CREATED.getStatusCode(), Response::getStatus);
1624+
assertThat(response).returns(CREATED.getStatusCode(), Response::getStatus);
16251625
}
16261626

16271627
// Should list only mycr
@@ -1787,7 +1787,7 @@ public void testCatalogAdminGrantAndRevokeCatalogRoles() {
17871787
+ "/"
17881788
+ catalogRoleName)
17891789
.delete()) {
1790-
assertThat(response).returns(Response.Status.FORBIDDEN.getStatusCode(), Response::getStatus);
1790+
assertThat(response).returns(FORBIDDEN.getStatusCode(), Response::getStatus);
17911791
}
17921792

17931793
// The service admin can revoke the role because it has the
@@ -1879,8 +1879,7 @@ public void testServiceAdminCanTransferCatalogAdmin() {
18791879
+ catalogName
18801880
+ "/catalog_admin")
18811881
.delete()) {
1882-
assertThat(response)
1883-
.returns(Response.Status.FORBIDDEN.getStatusCode(), Response::getStatus);
1882+
assertThat(response).returns(FORBIDDEN.getStatusCode(), Response::getStatus);
18841883
}
18851884
} finally {
18861885
// grant the admin role back to service_admin so that cleanup can happen
@@ -1953,7 +1952,7 @@ public void testCatalogAdminGrantAndRevokeCatalogRolesFromWrongCatalog() {
19531952
.managementApi(catalogAdminToken)
19541953
.request("v1/principal-roles/" + principalRoleName + "/catalog-roles/" + catalogName2)
19551954
.put(Entity.json(new GrantCatalogRoleRequest(new CatalogRole(catalogRoleName))))) {
1956-
assertThat(response).returns(Response.Status.FORBIDDEN.getStatusCode(), Response::getStatus);
1955+
assertThat(response).returns(FORBIDDEN.getStatusCode(), Response::getStatus);
19571956
}
19581957
}
19591958

@@ -2046,7 +2045,7 @@ public void testTableManageAccessCanGrantAndRevokeFromCatalogRoles() {
20462045
.request("v1/principal-roles/" + principalRoleName + "/catalog-roles/" + catalogName)
20472046
.put(
20482047
Entity.json(new GrantCatalogRoleRequest(new CatalogRole("target_catalog_role"))))) {
2049-
assertThat(response).returns(Response.Status.FORBIDDEN.getStatusCode(), Response::getStatus);
2048+
assertThat(response).returns(FORBIDDEN.getStatusCode(), Response::getStatus);
20502049
}
20512050

20522051
// The user cannot grant catalog-level privileges to the catalog role
@@ -2223,7 +2222,7 @@ public void testCreateAndUpdateCatalogRoleWithReservedProperties() {
22232222
managementApi
22242223
.request("v1/catalogs/{cat}/catalog-roles", Map.of("cat", catalogName))
22252224
.post(Entity.json(new CreateCatalogRoleRequest(okCatalogRole)))) {
2226-
assertThat(response).returns(Response.Status.CREATED.getStatusCode(), Response::getStatus);
2225+
assertThat(response).returns(CREATED.getStatusCode(), Response::getStatus);
22272226
}
22282227

22292228
UpdateCatalogRoleRequest updateRequest =
@@ -2271,7 +2270,7 @@ public void testCreateAndUpdatePrincipalRoleWithReservedProperties() {
22712270
managementApi
22722271
.request("v1/principal-roles")
22732272
.post(Entity.json(new CreatePrincipalRoleRequest(goodPrincipalRole)))) {
2274-
assertThat(response).returns(Response.Status.CREATED.getStatusCode(), Response::getStatus);
2273+
assertThat(response).returns(CREATED.getStatusCode(), Response::getStatus);
22752274
}
22762275

22772276
UpdatePrincipalRoleRequest badUpdate =
@@ -2310,7 +2309,7 @@ public void testCreateAndUpdatePrincipalWithReservedProperties() {
23102309
managementApi
23112310
.request("v1/principals")
23122311
.post(Entity.json(new CreatePrincipalRequest(goodPrincipal, false)))) {
2313-
assertThat(response).returns(Response.Status.CREATED.getStatusCode(), Response::getStatus);
2312+
assertThat(response).returns(CREATED.getStatusCode(), Response::getStatus);
23142313
}
23152314

23162315
UpdatePrincipalRequest badUpdate =

0 commit comments

Comments
 (0)