Skip to content

Conversation

@eric-maynard
Copy link
Contributor

@eric-maynard eric-maynard commented Aug 21, 2025

When we create a namespace or alter its location, we must confirm that this location is within the parent location. This PR introduces introduces a check similar to the one we have for tables, where custom locations are prohibited by default. This functionality is gated behind a new behavior change flag ALLOW_NAMESPACE_CUSTOM_LOCATION. In addition to allowing us to revert to the old behavior, this flag allows some tests relying on arbitrarily-located namespaces to pass (such as those from upstream Iceberg).

Fixes: #2417

Copy link
Contributor

@dimas-b dimas-b left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM overall 👍


public static final FeatureConfiguration<Boolean> ALLOW_NAMESPACE_LOCATION_ESCAPE =
PolarisConfiguration.<Boolean>builder()
.key("ALLOW_NAMESPACE_LOCATION_ESCAPE")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feature flags constitute our SemVer "API" surface, so I believe we need to formally send a discussion email to the dev ML about this flag.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Proactively +1 from my side :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is that so? That seems to create a weird incentive not to feature-flag anything.

In this particular case there's a behavior change due to the default setting of the flag so in that sense it's relevant to semver, but it's also a bugfix.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm +1 on this change already. So having extra discussion on the dev ML does not matter for me personally.

@flyrain WDYT?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 for the change as well. If this is more a bug fix, I don't think we even need this flag, the only reason we need the config is that existing behavior can be broken due to the change.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could even mark it deprecated in the beginning(this PR).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@flyrain : but what's you POV about requiring dev discussion for feature flags in general?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm supportive on having a discussion on dev mailing list. It's great to let more people know this behavior change/bug fix.

Copy link
Contributor Author

@eric-maynard eric-maynard Aug 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this case I think we want to have a flag for parity with tables -- the "bug" here IMO is that the default behavior is too lax, not that the lax behavior is accessible at all.

I'll create a quick thread to discuss the change in more detail, but in general my position is that it's not healthy for a project to require ML discussion for every new config. This creates an incentive to not protect changes with configs, and in the ideal world where all changes are config-protected this essentially necessitates an ML thread for every PR.

@eric-maynard eric-maynard marked this pull request as draft August 22, 2025 18:03
@eric-maynard
Copy link
Contributor Author

Pulling this back to draft to investigate -- we may need to just block all custom namespace locations like we do for tables in order to avoid scenarios where two namespaces overlap despite being within their parent entity

@eric-maynard eric-maynard changed the title Do not allow namespaces outside of allowed locations Disable custom namespace locations Aug 23, 2025
@eric-maynard
Copy link
Contributor Author

I've updated the PR to make this check more like the table one, which totally disallows custom locations by default.

@eric-maynard eric-maynard marked this pull request as ready for review August 23, 2025 06:33
"Cannot create namespace without a parent storage configuration");
}
boolean allowed =
parentEntity.getStorageConfigurationInfo().getAllowedLocations().stream()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AllowedLocations in the StorageConfig are an independent concept vs either of:

  1. Whether to allow "custom" locations outside of the default path hierarchy that uses namespace names
  2. Whether to allow "overlapping" locations

The most important one is validating that anything that can vend credentials resides under the allowedLocations.

Overlap and custom hierarchies in general are more common to disable validation for.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR isn't related to credential vending, but the location that a namespace is created at.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, I was explaining why your PR description is misleading:

in order for our overlap checks and assumptions around credential vending to be valid

Is this PR fixing assumptions around credential vending, or just adding an option for whether to enforce "standard" locations for namespaces? In general we shouldn't need namespaces to be standard to still provide the intended guarantees about enforcement of ALLOWED_LOCATIONS.

The more important bug to fix is enforcement of ALLOWED_LOCATIONS.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That clause is part of a sentence:

When we create a namespace or alter its location, we must confirm that this location is within the parent location ... in order for our overlap checks and assumptions around credential vending to be valid.

and is used in that sentence to articulate why we care that namespaces reside within their parent's location. Indeed, if you remove the clause from that context it could be misleading.

If there's another (more important) bugfix, let's submit that in parallel with this existing bugfix.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My clause was also part of a paragraph:

AllowedLocations in the StorageConfig are an independent concept vs either of:

  1. Whether to allow "custom" locations outside of the default path hierarchy that uses namespace names
  2. Whether to allow "overlapping" locations

The most important one is validating that anything that can vend credentials resides under the allowedLocations.

Overlap and custom hierarchies in general are more common to disable validation for.

Copy link
Contributor

@flyrain flyrain left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @eric-maynard for the fix. Left some comments.

FeatureConfiguration.ALLOW_NAMESPACE_CUSTOM_LOCATION, catalogEntity)) {
LOGGER.debug("Validating that namespace {} has a location inside its parent", namespace);
validateNamespaceLocation(entity, resolvedParent);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: It'd be nice to wrap this into a method, so that we don't duplicate them in two different places.

    if (!realmConfig.getConfig(FeatureConfiguration.ALLOW_NAMESPACE_LOCATION_OVERLAP)) {
      LOGGER.debug("Validating no overlap for {} with sibling tables or namespaces", namespace);
      validateNoLocationOverlap(entity, resolvedParent.getRawFullPath());
    } else {
      LOGGER.debug("Skipping location overlap validation for namespace '{}'", namespace);
    }
    if (!realmConfig.getConfig(
        FeatureConfiguration.ALLOW_NAMESPACE_CUSTOM_LOCATION, catalogEntity)) {
      LOGGER.debug("Validating that namespace {} has a location inside its parent", namespace);
      validateNamespaceLocation(entity, resolvedParent);
    }

flyrain
flyrain previously approved these changes Aug 26, 2025
@github-project-automation github-project-automation bot moved this from PRs In Progress to Ready to merge in Basic Kanban Board Aug 26, 2025
Copy link
Contributor

@flyrain flyrain left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@eric-maynard, thanks for moving it to BehaviorChangeConfiguration. By doing so, it discourages any users to use it. It is still useful for test purpose. We could remove it, once we figure out related tests.

Hi @dennishuo, would you take another look?

@eric-maynard eric-maynard merged commit 453e9fb into apache:main Sep 4, 2025
12 checks passed
@github-project-automation github-project-automation bot moved this from Ready to merge to Done in Basic Kanban Board Sep 4, 2025
@dimas-b
Copy link
Contributor

dimas-b commented Sep 4, 2025

@eric-maynard : These tests fail on main after this PR... not sure how they passed on the PR 😅 Could you take a look?

 IcebergAllowedLocationTest > testCreateTableInsideOfCatalogAllowedLocations(Path) FAILED
    java.lang.IllegalArgumentException at IcebergAllowedLocationTest.java:352

IcebergAllowedLocationTest > testCreateTableOutSideOfCatalogAllowedLocations(Path) FAILED
    java.lang.IllegalArgumentException at IcebergAllowedLocationTest.java:352

@eric-maynard
Copy link
Contributor Author

Hey @dimas-b, you're totally right, my bad. These two PRs had a conflict. I put up a fix in #2511.

I've talked to @flyrain about this in the past, but it would be pretty cool if we could have a merge queue and force PRs to pass CI before they actually merge.

@dimas-b
Copy link
Contributor

dimas-b commented Sep 5, 2025

+1 to merge queue... at least we should discuss it :)

snazy added a commit to snazy/polaris that referenced this pull request Nov 20, 2025
* Integration tests for Catalog Federation (apache#2344)

Adds a Junit5 integration test for catalog federation.

* Fix merge conflict in CatalogFederationIntegrationTest (apache#2420)

apache#2344 added a new test for catalog federation, but it looks like an undetected conflict with concurrent changes related to authentication have broken the test in main.

* chore(deps): update registry.access.redhat.com/ubi9/openjdk-21-runtime docker tag to v1.23-6.1755674729 (apache#2416)

* 2334 (apache#2427)

* Fix TableIdentifier in TaskFileIOSupplier (apache#2304)

we cant just convert a `TaskEntity` to a `IcebergTableLikeEntity` as the
`getTableIdentifier()` method will not return a correct value by using
the name of the task and its parent namespace (which is empty?).

task handlers instead need to pass in the `TableIdentifier` that they
already inferred via `TaskEntity.readData`.

* Fix NPE in CreateCatalog (apache#2435)

* Doc fix: Access control page update (apache#2424)

* 2418

* 2418

* fix(deps): update dependency software.amazon.awssdk:bom to v2.32.29 (apache#2443)

* Optimize PolicyCatalog.listPolicies (apache#2370)

this is a follow-up to apache#2290

the optimization is to use `listEntities` instead of `loadEntities` when
there is `policyType` filter to apply

* Add PolarisDiagnostics field to BaseMetaStoreManager (apache#2381)

* Add PolarisDiagnostics field to BaseMetaStoreManager

the ultimate goal is removing the `PolarisCallContext` parameter from every
`PolarisMetaStoreManager` interface method, so we make steps towards
reducing its usage first.

* Add feature flag to disallow custom S3 endpoints (apache#2442)

* Add new realm-level flag: `ALLOW_SETTING_S3_ENDPOINTS` (default: true)

* Enforce in `PolarisServiceImpl.validateStorageConfig()`

Fixes apache#2436

* Deprecate ActiveRolesProvider for removal (apache#2404)

* Client: fix openapi verbose output, remove doc generate, and skip test generations (apache#2439)

* Fix various issue in client code generation

* Use logger instead of print

* Add back exclude on __pycache__ as CI is not via Makefile

* Add back exclude on __pycache__ as CI is not via Makefile

* Add user principal tag in metrics (apache#2445)

* Added API change to enable tag

* Added test

* Added production readiness check

* fix(deps): update dependency io.opentelemetry.semconv:opentelemetry-semconv to v1.36.0 (apache#2454)

* fix(deps): update dependency com.google.cloud:google-cloud-storage-bom to v2.56.0 (apache#2447)

* fix(deps): update dependency gradle.plugin.org.jetbrains.gradle.plugin.idea-ext:gradle-idea-ext to v1.3 (apache#2428)

* Build: Make jandex dependency used for index generation managed (apache#2431)

Also allows specifying the jandex index version for the build.

This is a preparation step contributing to apache#2204, once a jandex fix for reproducible builds is available.

Co-authored-by: Alexandre Dutra <adutra@apache.org>

* Built: improve reproducible archive files (apache#2432)

As part of the effort for apache#2204, this change fixes a few aspects around reproducible builds:

Some Gradle projects produce archive files, but don't get the necessary Gradle archive-tasks settings applied: one not-published project but also the tarball&zip of the distribution. This change moves the logic to the new build-plugin `polaris-reproducible`.

Another change is to have some Quarkus generated jar files adhere to the same conventions, which are constant timestamps for the zip entries and a deterministic order of the entries. That's sadly not a full fix, as the classes that are generated or instumented by Quarkus differ in each build.

Contributes to apache#2204

* Remove commons-lang3 dependency (apache#2456)

outside of tests we can replace the functionality with jdk11 and guava.
also stop using `org.assertj.core.util` as its a non-public api.

* add refresh credentials property to loadTableResult (apache#2341)

* add refresh credentials property to loadTableResult

* IcebergCatalogAdapterTest: Added test to ensure refresh credentials endpoint is included

* delegate refresh credential endpoint configuration to storage integration

* GCP: Add refresh credential properties

* fix(deps): update dependency io.opentelemetry.semconv:opentelemetry-semconv to v1.37.0 (apache#2458)

* Add Delegator to all API Implementations (apache#2434)

Per the Dev ML, implements the Delegator pattern to add Events instrumentation to all Polaris APIs.

* Prefer java.util.Base64 over commons-codec (apache#2463)

`java.util.Base64` is available since java8 and we are already using it
in a few other spots.

in a follow-up we might be able to get rid of our `commons-codec` dependency
completely.

* Service: Move tests to the right package (apache#2469)

* Update versions in runtime LICENSE and NOTICE (apache#2468)

* fix(deps): update dependency com.adobe.testing:s3mock-testcontainers to v4.8.0 (apache#2475)

* fix(deps): update dependency com.gradleup.shadow:shadow-gradle-plugin to v9.1.0 (apache#2476)

* Service: Remove hadoop-common from polaris-runtime-service (apache#2462)

* Service: Always validate allowed locations from Storage Config (apache#2473)

* Add Community Sync Meeting 20250828 (apache#2477)

* Update dependency software.amazon.awssdk:bom to v2.33.0 (apache#2483)

* Remove PolarisCallContext.getDiagServices (apache#2415)

* Remove PolarisCallContext.getDiagServices usage

* Remove diagnostics from PolarisCallContext

* Feature: Expose resetCredentials via a new reset api to allow root user to reset credentials for an existing principal with custom values  (apache#2197)

* Add type-check to PolarisEntity subclass ctors (apache#2302)

currently one can freely "cast" any `PolarisEntity` to a more
specific type via their constructors.

this can lead to subtle bugs like we fixed in
a29f800

by adding type checks we discover a few more places where we need to be
more careful about how we construct new or handle existing entities.

note that we can add a check for `PolarisEntitySubType` in a followup,
but it requires more fixes currently.

* Fix CI (apache#2489)

Fix undetected merge conflict after apache#2197 + apache#2415 + apache#2434

* Use local diagnostics in TransactionWorkspaceMetaStoreManager

* Add resetCredentials to PolarisPrincipalsEventServiceDelegator

* Core: Prevent AIOOBE for negative codes in PolarisEntityType, PolarisPrivilege, ReturnStatus (apache#2490)

* feat(idgen): Start Implementation of NoSQL with the ID Generation Framework (apache#2131)

Create an ID Generation Framework.

Related to apache#650 & apache#844

Co-authored-by: Robert Stupp <snazy@snazy.de>
Co-authored-by: Dmitri Bourlatchkov <dmitri.bourlatchkov@gmail.com>

* perf(refactor): optimizing JdbcBasePersistenceImpl.listEntities (apache#2465)

- Reduced Column Selection: Only 6 columns instead of 16

- Eliminated Object Creation Overhead: Direct conversion to EntityNameLookupRecord without intermediate PolarisBaseEntity

* Add Polaris Events to Persistence (apache#1844)

* AWS CloudWatch Event Sink Implementation (apache#1965)

* Fix failing CI (apache#2498)

* Update actions/stale digest to 3a9db7e (apache#2499)

* Core: Prevent AIOOBE for negative policy codes in PredefinedPolicyType (apache#2486)

* Service: Add location tests for views (apache#2496)

* Update docker.io/jaegertracing/all-in-one Docker tag to v1.73.0 (apache#2500)

* Update dependency io.netty:netty-codec-http2 to v4.2.5.Final (apache#2495)

* Update actions/setup-python action to v6 (apache#2502)

* Update the Release Guide about the Helm Chart package (apache#2179)

* Update the Release Guide about the Helm Chart package

* Update release-guide.md

Co-authored-by: Pierre Laporte <pierre@pingtimeout.fr>

* Add missing commit message

* Whitespace

* Use Helm GPG plugin to sign the Helm chart

* Fix directories during Helm chart copy to SVN

* Add Helm index to SVN

* Use long name for svn checkout

* Ensure the Helm index is updated after the chart is moved to SVN dist release

* Do not publish any Docker image before the vote succeeds

* Typos

* Revert "Do not publish any Docker image before the vote succeeds"

This reverts commit 5617e65.

* Don't mention Helm values.yaml in the release guide as it doesn't contain version details

---------

Co-authored-by: Pierre Laporte <pierre@pingtimeout.fr>

* Update dependency com.azure:azure-sdk-bom to v1.2.38 (apache#2503)

* Update registry.access.redhat.com/ubi9/openjdk-21-runtime Docker tag to v1.23-6.1756793420 (apache#2504)

* Remove commons-codec dependency (apache#2474)

follow-up to f8ad77a

we can simply use guava instead and eliminate the extra dependency

* CLI: Remove SCRIPT_DIR and default config location to user home (apache#2448)

* Remove readInternalProperties helpers (apache#2506)

the functionality is already provided by the `PrincipalEntity`

* Add Events for Generic Table APIs (apache#2481)


This PR adds the Events instrumentation for the Generic Tables Service APIs, surrounding the default delegated call to the business logic APIs.

* Disable custom namespace locations (apache#2422)

When we create a namespace or alter its location, we must confirm that this location is within the parent location. This PR introduces introduces a check similar to the one we have for tables, where custom locations are prohibited by default. This functionality is gated behind a new behavior change flag `ALLOW_NAMESPACE_CUSTOM_LOCATION`. In addition to allowing us to revert to the old behavior, this flag allows some tests relying on arbitrarily-located namespaces to pass (such as those from upstream Iceberg).

Fixes: apache#2417

* fix for IcebergAllowedLocationTest (apache#2511)

* Remove unused config from SparkSessionBuilder (apache#2512)

Tests pass without it.

* Add Events for Policy Service APIs (apache#2479)

* Remove PolarisTestMetaStoreManager.jsonNode helper (apache#2513)

* Update dependency software.amazon.awssdk:bom to v2.33.4 (apache#2517)

* Update dependency com.nimbusds:nimbus-jose-jwt to v10.5 (apache#2514)

* Update dependency io.opentelemetry:opentelemetry-bom to v1.54.0 (apache#2515)

* Update dependency io.micrometer:micrometer-bom to v1.15.4 (apache#2519)

* Port missed OSS change

* NoSQL: adopt to updated test packages

* NoSQL: adapt to removed PolarisDiagnostics param

* NoSQL: fix libs.versions.toml

* NoSQL: include jandex plugin related changes from OSS

* NoSQL: changes for delete/set principal client-ID+secret

* Last merged commit c6176dc

---------

Co-authored-by: Pooja Nilangekar <poojan@umd.edu>
Co-authored-by: Eric Maynard <eric.maynard+oss@snowflake.com>
Co-authored-by: Mend Renovate <bot@renovateapp.com>
Co-authored-by: Yong Zheng <yongzheng0809@gmail.com>
Co-authored-by: Christopher Lambert <xn137@gmx.de>
Co-authored-by: Honah (Jonas) J. <honahx@apache.org>
Co-authored-by: Dmitri Bourlatchkov <dmitri.bourlatchkov@gmail.com>
Co-authored-by: Alexandre Dutra <adutra@apache.org>
Co-authored-by: fivetran-kostaszoumpatianos <kostas.zoumpatianos@fivetran.com>
Co-authored-by: Jason <jasonf20@gmail.com>
Co-authored-by: Adnan Hemani <adnan.h@berkeley.edu>
Co-authored-by: Yufei Gu <yufei@apache.org>
Co-authored-by: JB Onofré <jbonofre@apache.org>
Co-authored-by: fivetran-arunsuri <103934371+fivetran-arunsuri@users.noreply.github.com>
Co-authored-by: Adam Christian <105929021+adam-christian-software@users.noreply.github.com>
Co-authored-by: Artur Rakhmatulin <artur.rakhmatulin@gmail.com>
Co-authored-by: Pierre Laporte <pierre@pingtimeout.fr>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Namespaces can be created outside the parent catalog's allowedLocations

5 participants