Skip to content

Commit b012081

Browse files
committed
merge from main
2 parents 953b5a0 + b174b9d commit b012081

File tree

37 files changed

+634
-81
lines changed

37 files changed

+634
-81
lines changed

.github/workflows/python-client.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ jobs:
5151
java-version: '21'
5252

5353
- name: Set up Python ${{ matrix.python-version }}
54-
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
54+
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6
5555
with:
5656
python-version: ${{ matrix.python-version }}
5757

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ client-regenerate: client-setup-env ## Regenerate the client code
140140
.PHONY: client-unit-test
141141
client-unit-test: client-setup-env ## Run client unit tests
142142
@echo "--- Running client unit tests ---"
143-
@$(ACTIVATE_AND_CD) && SCRIPT_DIR="non-existing-mock-directory" poetry run pytest test/
143+
@$(ACTIVATE_AND_CD) && poetry run pytest test/
144144
@echo "--- Client unit tests complete ---"
145145

146146
.PHONY: client-integration-test

client/python/cli/command/profiles.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ def _load_profiles(self) -> Dict[str, Dict[str, str]]:
5656
if not os.path.exists(CONFIG_FILE):
5757
return {}
5858
with open(CONFIG_FILE, "r") as f:
59+
print(f"Loading profiles from {CONFIG_FILE}")
5960
return json.load(f)
6061

6162
def _save_profiles(self, profiles: Dict[str, Dict[str, str]]) -> None:

client/python/cli/constants.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -371,9 +371,5 @@ class Namespaces:
371371
CLIENT_PROFILE_ENV = "CLIENT_PROFILE"
372372
DEFAULT_HOSTNAME = "localhost"
373373
DEFAULT_PORT = 8181
374-
CONFIG_DIR = os.environ.get("SCRIPT_DIR")
375-
if CONFIG_DIR is None:
376-
raise Exception(
377-
"The SCRIPT_DIR environment variable is not set. Please set it to the Polaris's script directory."
378-
)
374+
CONFIG_DIR = (os.environ.get("POLARIS_HOME") or "").strip() or os.path.expanduser("~/.polaris")
379375
CONFIG_FILE = os.path.join(CONFIG_DIR, ".polaris.json")

getting-started/telemetry/docker-compose.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ services:
8585

8686
# Jaeger (OpenTelemetry traces collector)
8787
jaeger:
88-
image: docker.io/jaegertracing/all-in-one:1.72.0
88+
image: docker.io/jaegertracing/all-in-one:1.73.0
8989
ports:
9090
# Jaeger gRPC collector, used by Polaris
9191
- "4317:4317"

gradle/libs.versions.toml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,8 @@ assertj-core = { module = "org.assertj:assertj-core", version = "3.27.4" }
4444
auth0-jwt = { module = "com.auth0:java-jwt", version = "4.5.0" }
4545
awssdk-bom = { module = "software.amazon.awssdk:bom", version = "2.33.0" }
4646
awaitility = { module = "org.awaitility:awaitility", version = "4.3.0" }
47-
azuresdk-bom = { module = "com.azure:azure-sdk-bom", version = "1.2.37" }
47+
azuresdk-bom = { module = "com.azure:azure-sdk-bom", version = "1.2.38" }
4848
caffeine = { module = "com.github.ben-manes.caffeine:caffeine", version = "3.2.2" }
49-
commons-codec = { module = "commons-codec:commons-codec", version = "1.19.0" }
5049
commons-lang3 = { module = "org.apache.commons:commons-lang3", version = "3.18.0" }
5150
commons-text = { module = "org.apache.commons:commons-text", version = "1.14.0" }
5251
eclipselink = { module = "org.eclipse.persistence:eclipselink", version = "4.0.7" }

integration-tests/src/main/java/org/apache/polaris/service/it/ext/SparkSessionBuilder.java

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -164,13 +164,9 @@ private void applySingleCatalogConfig(CatalogConfig catalog) {
164164

165165
// Add endpoint configuration
166166
Preconditions.checkNotNull(catalog.endpoints, "endpoints is required");
167-
builder
168-
.config(
169-
String.format("spark.sql.catalog.%s.uri", catalog.catalogName),
170-
catalog.endpoints.catalogApiEndpoint().toString())
171-
.config(
172-
String.format("spark.sql.catalog.%s.header.realm", catalog.catalogName),
173-
catalog.endpoints.realmId());
167+
builder.config(
168+
String.format("spark.sql.catalog.%s.uri", catalog.catalogName),
169+
catalog.endpoints.catalogApiEndpoint().toString());
174170

175171
// Add token configuration
176172
if (catalog.token != null) {

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

Lines changed: 77 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,11 @@
2020

2121
import static org.apache.polaris.service.it.env.PolarisClient.polarisClient;
2222
import static org.assertj.core.api.Assertions.assertThat;
23+
import static org.assertj.core.api.Assertions.assertThatCode;
2324
import static org.assertj.core.api.Assertions.assertThatThrownBy;
2425
import static org.awaitility.Awaitility.await;
2526

27+
import com.google.common.collect.ImmutableMap;
2628
import jakarta.ws.rs.ProcessingException;
2729
import jakarta.ws.rs.client.Entity;
2830
import jakarta.ws.rs.client.Invocation;
@@ -67,6 +69,7 @@
6769
import org.apache.polaris.core.admin.model.PolarisCatalog;
6870
import org.apache.polaris.core.admin.model.PrincipalRole;
6971
import org.apache.polaris.core.admin.model.StorageConfigInfo;
72+
import org.apache.polaris.core.config.BehaviorChangeConfiguration;
7073
import org.apache.polaris.core.entity.CatalogEntity;
7174
import org.apache.polaris.core.entity.PolarisEntityConstants;
7275
import org.apache.polaris.service.it.env.ClientPrincipal;
@@ -76,6 +79,7 @@
7679
import org.apache.polaris.service.it.env.RestApi;
7780
import org.apache.polaris.service.it.ext.PolarisIntegrationTestExtension;
7881
import org.assertj.core.api.InstanceOfAssertFactories;
82+
import org.assertj.core.api.ThrowableAssert;
7983
import org.junit.jupiter.api.AfterAll;
8084
import org.junit.jupiter.api.AfterEach;
8185
import org.junit.jupiter.api.BeforeAll;
@@ -84,6 +88,8 @@
8488
import org.junit.jupiter.api.TestInfo;
8589
import org.junit.jupiter.api.extension.ExtendWith;
8690
import org.junit.jupiter.api.io.TempDir;
91+
import org.junit.jupiter.params.ParameterizedTest;
92+
import org.junit.jupiter.params.provider.ValueSource;
8793

8894
/**
8995
* @implSpec This test expects the server to be configured with the following features configured:
@@ -186,11 +192,30 @@ private static void createCatalog(
186192
String principalRoleName,
187193
StorageConfigInfo storageConfig,
188194
String defaultBaseLocation) {
189-
CatalogProperties props =
195+
createCatalog(
196+
catalogName,
197+
catalogType,
198+
principalRoleName,
199+
storageConfig,
200+
defaultBaseLocation,
201+
ImmutableMap.of());
202+
}
203+
204+
private static void createCatalog(
205+
String catalogName,
206+
Catalog.TypeEnum catalogType,
207+
String principalRoleName,
208+
StorageConfigInfo storageConfig,
209+
String defaultBaseLocation,
210+
Map<String, String> additionalProperties) {
211+
CatalogProperties.Builder propsBuilder =
190212
CatalogProperties.builder(defaultBaseLocation)
191213
.addProperty(
192-
CatalogEntity.REPLACE_NEW_LOCATION_PREFIX_WITH_CATALOG_DEFAULT_KEY, "file:/")
193-
.build();
214+
CatalogEntity.REPLACE_NEW_LOCATION_PREFIX_WITH_CATALOG_DEFAULT_KEY, "file:/");
215+
for (var entry : additionalProperties.entrySet()) {
216+
propsBuilder.addProperty(entry.getKey(), entry.getValue());
217+
}
218+
CatalogProperties props = propsBuilder.build();
194219
Catalog catalog =
195220
catalogType.equals(Catalog.TypeEnum.INTERNAL)
196221
? PolarisCatalog.builder()
@@ -641,4 +666,53 @@ public void testRequestBodyTooLarge() throws Exception {
641666
});
642667
}
643668
}
669+
670+
@ParameterizedTest
671+
@ValueSource(booleans = {true, false})
672+
public void testNamespaceOutsideCatalog(boolean allowNamespaceLocationEscape) throws IOException {
673+
String catalogName = client.newEntityName("testNamespaceOutsideCatalog_specificLocation");
674+
String catalogLocation = baseLocation.resolve(catalogName + "/catalog").toString();
675+
String badLocation = baseLocation.resolve(catalogName + "/ns").toString();
676+
createCatalog(
677+
catalogName,
678+
Catalog.TypeEnum.INTERNAL,
679+
principalRoleName,
680+
FileStorageConfigInfo.builder(StorageConfigInfo.StorageTypeEnum.FILE)
681+
.setAllowedLocations(List.of(catalogLocation))
682+
.build(),
683+
catalogLocation,
684+
ImmutableMap.of(
685+
BehaviorChangeConfiguration.ALLOW_NAMESPACE_CUSTOM_LOCATION.catalogConfig(),
686+
String.valueOf(allowNamespaceLocationEscape)));
687+
try (RESTSessionCatalog sessionCatalog = newSessionCatalog(catalogName)) {
688+
SessionCatalog.SessionContext sessionContext = SessionCatalog.SessionContext.createEmpty();
689+
sessionCatalog.createNamespace(sessionContext, Namespace.of("good_namespace"));
690+
ThrowableAssert.ThrowingCallable createBadNamespace =
691+
() ->
692+
sessionCatalog.createNamespace(
693+
sessionContext,
694+
Namespace.of("bad_namespace"),
695+
ImmutableMap.of("location", badLocation));
696+
if (!allowNamespaceLocationEscape) {
697+
assertThatThrownBy(createBadNamespace)
698+
.isInstanceOf(BadRequestException.class)
699+
.hasMessageContaining("custom location");
700+
} else {
701+
assertThatCode(createBadNamespace).doesNotThrowAnyException();
702+
}
703+
ThrowableAssert.ThrowingCallable createBadChildGoodParent =
704+
() ->
705+
sessionCatalog.createNamespace(
706+
sessionContext,
707+
Namespace.of("good_namespace", "bad_child"),
708+
ImmutableMap.of("location", badLocation));
709+
if (!allowNamespaceLocationEscape) {
710+
assertThatThrownBy(createBadChildGoodParent)
711+
.isInstanceOf(BadRequestException.class)
712+
.hasMessageContaining("custom location");
713+
} else {
714+
assertThatCode(createBadChildGoodParent).doesNotThrowAnyException();
715+
}
716+
}
717+
}
644718
}

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,8 @@ public abstract class PolarisRestCatalogIntegrationBase extends CatalogTests<RES
173173
Map.of(
174174
"polaris.config.allow.unstructured.table.location", "true",
175175
"polaris.config.allow.external.table.location", "true",
176-
"polaris.config.list-pagination-enabled", "true");
176+
"polaris.config.list-pagination-enabled", "true",
177+
"polaris.config.namespace-custom-location.enabled", "true");
177178

178179
/**
179180
* Get the storage configuration information for the catalog.

plugins/spark/v3.5/integration/src/intTest/java/org/apache/polaris/spark/quarkus/it/SparkIntegrationBase.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ public void before(
100100
CatalogProperties props = new CatalogProperties("s3://my-bucket/path/to/data");
101101
props.putAll(s3Container.getS3ConfigProperties());
102102
props.put("polaris.config.drop-with-purge.enabled", "true");
103+
props.put("polaris.config.namespace-custom-location.enabled", "true");
103104
Catalog catalog =
104105
PolarisCatalog.builder()
105106
.setType(Catalog.TypeEnum.INTERNAL)

0 commit comments

Comments
 (0)