Skip to content

feat: storage-scoped aws credentials#3409

Merged
dimas-b merged 10 commits intoapache:mainfrom
tokoko:aws-storage-credentials
Feb 23, 2026
Merged

feat: storage-scoped aws credentials#3409
dimas-b merged 10 commits intoapache:mainfrom
tokoko:aws-storage-credentials

Conversation

@tokoko
Copy link
Copy Markdown
Contributor

@tokoko tokoko commented Jan 9, 2026

Introduces 2 new configurations:

  • polaris.storage.aws.<storage-name>.access-key
  • polaris.storage.aws.<storage-name>.secret-key

Users can set these to override aws credentials per catalog. Each catalog looks up it's keys by using host of the first uri in the list of AllowedLocations or it's own configured storageName if available.

Fixes #2970

Optional<String> awsSecretKey();

@WithName("aws")
Map<String, StorageConfig> storages();
Copy link
Copy Markdown
Contributor

@dimas-b dimas-b Jan 9, 2026

Choose a reason for hiding this comment

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

@WithDefaults and/or @WithParentName might be helpful here... WDYT? e.g.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

See, replacing the awsAccessKey() and awsSecretKey() properties.

  @WithParentName
  Optional<StorageConfig> defaultSecrets();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@tokoko : WDYT about @WithParentName for config handling? I hope it might be a bit clearer.

Copy link
Copy Markdown
Member

@snazy snazy left a comment

Choose a reason for hiding this comment

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

Can we safely assume that a bucket name is "globally unique" across all realms? Mean, this approach is probably good enough to serve most users' needs. Just wondering whether there might be situations in multi-realm setups that would require a more fine-grained approach. We can certainly defer that to when we have a "secrets provider" API.

Optional<String> awsSecretKey();

@WithName("aws")
Map<String, StorageConfig> storages();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

See, replacing the awsAccessKey() and awsSecretKey() properties.

  @WithParentName
  Optional<StorageConfig> defaultSecrets();

@tokoko tokoko force-pushed the aws-storage-credentials branch from a70fa75 to 7eaf070 Compare January 31, 2026 16:03
@tokoko tokoko marked this pull request as ready for review January 31, 2026 17:05
@tokoko
Copy link
Copy Markdown
Contributor Author

tokoko commented Jan 31, 2026

@snazy from the discussion in the issue, I think the point is that it's pointless to try to come up with a way to infer a good storage name that will also be guaranteed to be unique. There might be more than one allowed buckets, the same bucket name could be referring to different buckets in s3 and minio and so on. So the PR tried to infer a "good enough" name from the first entry in allowed locations. Whenever that's impossible or incorrect, the user is free to set it's own name.

Copy link
Copy Markdown
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.

Thanks for the update, @tokoko !

It looks like we still need to make storage location parsing more robust, but otherwise this approach LGTM.

This PR enables Polaris deployments to be configured with a finite set of per-location credentials known ahead of time, which is a nice feature for Polaris Administrators, I guess.

There are on-going discussions about leveraging (developing) a Secrets Manager for loading credentials, so this part of the Polaris codebase may need to change soon, but I hope we can still preserver the basic feature of allowing per-bucket credentials.

All in all, I think this PR is worth merging as an intermediate solution since it helps some users while the bigger Secrets Manager is under development.

Copy link
Copy Markdown
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.

The only remaining (minor) concern from the my side is the use of @WithParentName in configuration... otherwise, I think we can merge.

@snazy , @adutra : WDYT?

dimas-b
dimas-b previously approved these changes Feb 9, 2026
Copy link
Copy Markdown
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.

This revision LGTM 👍

@adutra , @snazy : WDYT?

@github-project-automation github-project-automation Bot moved this from PRs In Progress to Ready to merge in Basic Kanban Board Feb 9, 2026
dimas-b
dimas-b previously approved these changes Feb 10, 2026
Comment thread spec/polaris-management-service.yml Outdated
@dimas-b
Copy link
Copy Markdown
Contributor

dimas-b commented Feb 10, 2026

As required for API and (major) config changes, I started this dev discussion: https://lists.apache.org/thread/33c50qx1bvoyp9x8wbv1ntkgpzcnpb41

Let's way a couple of days and see if other people have comments.

dimas-b
dimas-b previously approved these changes Feb 10, 2026
adutra
adutra previously approved these changes Feb 10, 2026
Copy link
Copy Markdown
Contributor

@adutra adutra left a comment

Choose a reason for hiding this comment

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

Thanks @tokoko for the PR, I think it has a lot of value!

General question, maybe naive: why not do the same, at least for GCS?

this.realmConfig = realmConfig;
}

public PolarisStorageIntegrationProviderImpl(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Some further cleanup (in a follow-up PR) would be nice here, as this constructor is now only used in 2 tests but it complicates the logic for resolving the creds quite a bit.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

yeah, that's for backwards-compat only

Copy link
Copy Markdown
Contributor

@collado-mike collado-mike left a comment

Choose a reason for hiding this comment

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

It would be nice if the credentials could be realm-scoped, but I suppose the original default credentials were never realm-scoped, so this isn't strictly worse. However, I think that falling back to the default credentials if a storage name is incorrectly specified is bad for security. Given the catalog admins ought to know the name of the storage credential set they want to use, I think falling back to default credentials allows for a potential security hole.

Comment on lines +134 to +140
default AwsCredentialsProvider stsCredentials(String storageName) {
if (storageName != null && aws().storages().containsKey(storageName)) {
StorageConfig storageConfig = aws().storages().get(storageName);
return StaticCredentialsProvider.create(
AwsBasicCredentials.create(storageConfig.accessKey(), storageConfig.secretKey()));
}
return stsCredentials();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This seems wrong - if the storage name was passed explicitly, why do we fall back on the default credentials? Seems we should throw here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

fixed. nice catch, thanks. missed this one on the latest change. now that storageName is always explicitly set, it no longer makes sense to fall back on the defaults.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎉

@github-project-automation github-project-automation Bot moved this from Ready to merge to PRs In Progress in Basic Kanban Board Feb 10, 2026
@dimas-b
Copy link
Copy Markdown
Contributor

dimas-b commented Feb 10, 2026

@collado-mike : my understanding is that this feature is generally usable only in situations when the admin owns Polaris deployment (otherwise it is not possible to configure per-name credentials at all, and the system falls back to current behaviour).

Additionally, the new behaviour is controlled by a feature flag, which is off by default. So existing users are not affected even when they upgrade to this code.

In self-hosted environments, the admin user is, of course, expected to be aware of how has permissions for creating catalogs and should act accordingly when electing to use this feature.

That said, defaulting to the global credential or not is probably the admin user's choice.

Would covering that behaviour with another feature flag address your concern?

@tokoko : Please share your perspective too.

@tokoko tokoko dismissed stale reviews from adutra and dimas-b via a469818 February 10, 2026 18:30
@tokoko
Copy link
Copy Markdown
Contributor Author

tokoko commented Feb 10, 2026

@collado-mike I agree it should ideally be realm-scoped, but that probably also applies to gcp and azure configs as well and I would like to avoid blowing up the scope of this PR.

@adutra the same reason, I guess. we don't use gcs and didn't want to unnecessary blow up the scope. plus, I think (!) the issue is not as relevant with gcs as there's not a lot of gcs-compatible products out there. if this mechanism ends up being used for table-level configs, that will probably change, though.

@collado-mike
Copy link
Copy Markdown
Contributor

my understanding is that this feature is generally usable only in situations when the admin owns Polaris deployment (otherwise it is not possible to configure per-name credentials at all, and the system falls back to current behaviour).

Additionally, the new behaviour is controlled by a feature flag, which is off by default. So existing users are not affected even when they upgrade to this code.

My concern isn't for existing users. It's for people who try to use the feature and accidentally or maliciously take advantage of this fallback. E.g., if an admin configures a credential called limited but accidentally fat-fingers likited, a catalog admin can create a catalog that tries to load the limited credentials and accidentally falls back to the default (possibly less restricted) credentials unknowingly. This silent failure leaves the admins completely unaware that there's an error in the configuration and, in the worst case, allows someone access to credentials they could use maliciously.

@tokoko
Copy link
Copy Markdown
Contributor Author

tokoko commented Feb 15, 2026

@collado-mike that was already fixed in the last commit in case you missed it, just making sure.. :)

@collado-mike
Copy link
Copy Markdown
Contributor

@collado-mike that was already fixed in the last commit in case you missed it, just making sure.. :)

@tokoko , I had not seen the revision. Thanks for pointing that out

@github-project-automation github-project-automation Bot moved this from PRs In Progress to Ready to merge in Basic Kanban Board Feb 16, 2026
@dimas-b
Copy link
Copy Markdown
Contributor

dimas-b commented Feb 17, 2026

If there are no fresh comments / concerns in GH or on the dev ML, I propose to merge on Feb 18.

Copy link
Copy Markdown
Contributor

@sfc-gh-ahemani sfc-gh-ahemani left a comment

Choose a reason for hiding this comment

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

Sorry, I'm late to the party :) But I think this is useful and we should merge this! Can see many future extensions including adding tags/etc. to the storage configurations and expanding this to other cloud providers potentially. Great addition!

@dimas-b dimas-b merged commit b03bc22 into apache:main Feb 23, 2026
15 checks passed
@github-project-automation github-project-automation Bot moved this from Ready to merge to Done in Basic Kanban Board Feb 23, 2026
sririshindra added a commit to sririshindra/polaris that referenced this pull request Mar 2, 2026
…ark)

- HierarchicalStorageConfigResolutionTest: add two unit tests verifying
  namespace storageName takes precedence over catalog, and that a null
  storageName at namespace level stops the hierarchy walk
- StorageNameHierarchyCredentialTest: new service-layer tests verifying
  hierarchy resolution reaches the credential provider when the flag is
  enabled, and that resolution is independent of the feature flag
- PolarisStorageConfigIntegrationTest: add three HTTP integration tests
  for namespace storageName roundtrip, table override, and
  delete-reverts-to-namespace behaviour
- PolarisSparkStorageNameHierarchyIntegrationTest: new Spark integration
  test class covering 13 named/unnamed storageName permutations across
  catalog, namespace, and table levels
- SparkStorageNameHierarchyIT: Quarkus integration test runner for the
  Spark hierarchy scenarios

Add storage-config integration and Spark credential-vending tests

runtime-service: harden storage-config resolution/conflict semantics

This commit completes the remaining Step 8 hardening scope for inline storage configuration after the apache#3409 rebase, focused on correctness and deterministic API behavior for namespace/table storage-config endpoints.

What changed:

- Added full table-path resolution helper in PolarisAdminService via resolveTablePath(...) and reused it from resolveTableEntity(...)

- Updated table effective GET logic in PolarisServiceImpl to resolve storage config from full ancestry (table -> namespace chain -> catalog) using FileIOUtil.findStorageInfoFromHierarchy(...)

- Added deterministic error mapping for namespace/table storage-config mutations:

  - optimistic-lock/path-race update outcomes mapped to CommitConflictException in PolarisAdminService.updateEntity(...)

  - endpoint handlers map CommitConflictException to HTTP 409

  - endpoint handlers map ForbiddenException to HTTP 403

- Kept storageName compatibility intact across API/internal model conversion paths

Tests added/updated:

- PolarisStorageConfigIntegrationTest

  - storageName roundtrip assertions for namespace/table

  - effective fallback chain assertions (table -> namespace -> catalog)

  - nested namespace ancestor fallback regression (ns1\u001Fns2\u001Fns3.table with config on ns1)

- PolarisServiceImplTest

  - 409 contract test for namespace set on concurrent update

  - 403 contract tests for table get/set/delete unauthorized behavior

- PolarisAdminServiceTest

  - updateEntity conflict mapping test (TARGET_ENTITY_CONCURRENTLY_MODIFIED -> CommitConflictException)

  - updateEntity entity-not-found mapping test

Validation run:

- ./gradlew :polaris-runtime-service:compileJava

- ./gradlew :polaris-runtime-service:spotlessApply

- ./gradlew :polaris-runtime-service:test --tests "org.apache.polaris.service.catalog.io.PolarisStorageConfigIntegrationTest" --tests "org.apache.polaris.service.admin.PolarisServiceImplTest" --tests "org.apache.polaris.service.admin.PolarisAdminServiceTest"

fix(storage-config): preserve storageName and prevent task payload serialization regression

Context:\n- Branch was rebased on main after apache#3409 (storage-scoped AWS credentials via storageName).\n- Two regressions were observed during validation:\n  1) storageName was dropped in namespace/table management API conversion helpers.\n  2) new helper getters were serialized into task payload JSON, breaking TableCleanupTaskHandlerTest.\n\nWhat changed:\n1) runtime/service/.../PolarisServiceImpl.java\n   - Preserve storageName in toInternalModel() for AWS/Azure/GCS/FILE.\n   - Preserve storageName in toApiModel() for AWS/Azure/GCS/FILE.\n   - Use FileStorageConfigInfo constructor variant that includes storageName.\n\n2) polaris-core/.../NamespaceEntity.java\n3) polaris-core/.../table/TableLikeEntity.java\n   - Add @JsonIgnore to getStorageConfigurationInfo() to keep it as a helper accessor only\n     and prevent Jackson from serializing it into generic entity JSON payloads (including task data).\n\nWhy:\n- apache#3409 credential lookup can resolve by storageName when RESOLVE_CREDENTIALS_BY_STORAGE_NAME is enabled.\n  Dropping storageName causes silent fallback to default credentials, which is incorrect behavior.\n- Serializing helper getters introduced an unexpected field (storageConfigurationInfo) into task payloads,\n  causing deserialization failures in TableCleanupTaskHandlerTest.\n\nValidation:\n- ./gradlew :polaris-runtime-service:compileJava\n- ./gradlew :polaris-runtime-service:test --tests org.apache.polaris.service.task.TableCleanupTaskHandlerTest\n\nBoth checks pass after this change.

feat: Implement Management API for inline storage configuration

Implement Step 8 of the inline storage configuration feature, adding
complete CRUD operations for namespace and table storage configs via
the Management API.

Changes:
- Implemented 6 storage config handlers in PolarisServiceImpl:
  * GET/PUT/DELETE namespace storage config
  * GET/PUT/DELETE table storage config
- Added conversion helpers between API and internal storage config models
- Added entity resolution helpers in PolarisAdminService
- Updated runtime/service tests to validate all CRUD operations (7/7 passing)
- Updated integration tests to verify end-to-end functionality

Key Features:
- Storage config hierarchy resolution (table → namespace → catalog)
- Support for all storage types (S3, Azure, GCS, FILE)
- Multipart namespace handling with unit separator encoding
- Proper error handling for non-existent entities (404 responses)
- Entity versioning and optimistic locking support

All tests passing with no compilation errors.

feat: Add Management API endpoints for namespace/table storage configuration

Implements Step 6 of inline storage configuration feature - Management API
design and endpoint exposure with test coverage.

Changes:
- Add 6 new REST endpoints to Management API specification:
  * GET /catalogs/{catalog}/namespaces/{namespace}/storage-config
  * PUT /catalogs/{catalog}/namespaces/{namespace}/storage-config
  * DELETE /catalogs/{catalog}/namespaces/{namespace}/storage-config
  * GET /catalogs/{catalog}/namespaces/{namespace}/tables/{table}/storage-config
  * PUT /catalogs/{catalog}/namespaces/{namespace}/tables/{table}/storage-config
  * DELETE /catalogs/{catalog}/namespaces/{namespace}/tables/{table}/storage-config

- Define API request/response models:
  * NamespaceStorageConfigResponse
  * TableStorageConfigResponse

- Implement handler stubs in PolarisServiceImpl:
  * All handlers return 501 NOT_IMPLEMENTED (placeholder for Step 8)
  * Proper method signatures with RealmContext and SecurityContext
  * Support for multipart namespace paths

- Add comprehensive test coverage (7 tests, all passing):
  * Test GET/PUT/DELETE for namespace storage configs
  * Test GET/PUT/DELETE for table storage configs
  * Test multipart namespace handling (e.g., "level1.level2.level3")
  * Test multiple cloud providers (AWS S3, Azure Blob, GCP GCS)

- Add helper methods to ManagementApi test utility:
  * getNamespaceStorageConfig()
  * setNamespaceStorageConfig()
  * deleteNamespaceStorageConfig()
  * getTableStorageConfig()
  * setTableStorageConfig()
  * deleteTableStorageConfig()

Technical Details:
- OpenAPI spec: spec/polaris-management-service.yml (+170 lines)
- Service implementation: PolarisServiceImpl.java (+138 lines)
- Test coverage: PolarisStorageConfigIntegrationTest.java (7/7 tests passing)
- Code generation: Regenerated API interfaces from OpenAPI spec

Test Results:
  Total: 7 tests
  Passed: 7 ✅
  Failed: 0
  Time: 0.822s

Next Steps:
- Step 7: Add authorization framework (privileges and access control)
- Step 8: Implement full CRUD logic with entity persistence

Related: DESIGN.md, STEP-06-MANAGEMENT-API.md

feat(storage): Add hierarchical storage config verification and comprehensive tests

Step 5: Verification and Documentation - Inline Storage Configuration Feature

This commit completes the verification phase of the hierarchical storage
configuration feature by adding comprehensive documentation and integration tests.

Changes:
- Enhanced javadoc in IcebergCatalog.loadFileIOForTableLike() to document
  hierarchical storage config resolution behavior (table > namespace > catalog)
- Enhanced javadoc in StorageAccessConfigProvider.getStorageAccessConfig() to
  explicitly document entity path search order and hierarchical resolution
- Added HierarchicalStorageConfigResolutionTest.java with 8 comprehensive
  integration test scenarios covering:
  * Table-level config overrides
  * Namespace-level config inheritance
  * Nested namespace hierarchies (4+ levels deep)
  * Catalog fallback behavior
  * Edge cases (empty paths, no configs anywhere)
  * Multiple configs at different levels with correct priority

Verification Results:
- All 8 new integration tests pass ✓
- FileIOUtilTest (8 tests from Step 4) pass ✓
- Entity storage config tests (from Step 2) pass ✓
- No regressions in existing tests
- Code formatted with spotlessApply

The hierarchical storage configuration feature is now fully verified at the
backend level. The resolution logic correctly walks the entity hierarchy
(table → namespace(s) → catalog) to find storage configuration, enabling
tables and namespaces to override storage settings inherited from parents.

Next: Step 6 will design the Management API to expose this feature to users.

Related: Inline Storage Configuration Feature Implementation

feat: Add hierarchical storage configuration support for tables and namespaces

This commit implements Step 4 of the inline storage configuration feature,
enabling tables and namespaces to override catalog-level storage settings.

Changes:
- Enhanced FileIOUtil.findStorageInfoFromHierarchy() with improved docs
  and debug logging for hierarchical resolution (table → namespace → catalog)
- Added comprehensive FileIOUtilTest with 8 test cases covering all
  resolution scenarios including nested namespaces
- Removed duplicate PolarisEntityUtil and PolarisEntityUtilTest that were
  created in Step 3 but are not needed in production code

Key insight: The hierarchical resolution was already working through the
existing StorageAccessConfigProvider → FileIOUtil production code path.
The credential cache requires the entity (not just config) for cache keys,
which is why FileIOUtil returns Optional<PolarisEntity>.

Testing:
- All 8 FileIOUtilTest tests pass
- Verifies table override, namespace fallback, catalog fallback
- Tests nested namespace scenarios (4 levels deep)
- Tests edge cases (no config, partial hierarchies)

Related: Step 2 added getStorageConfigurationInfo() to NamespaceEntity
and TableLikeEntity, which enabled this hierarchical resolution.

feat: Add storage configuration support to TableLikeEntity and NamespaceEntity

Add storage configuration getter methods to TableLikeEntity and NamespaceEntity,
enabling table-level and namespace-level storage configuration overrides. This
follows the existing pattern established by CatalogEntity and maintains
consistency across the codebase.

Changes:
- Add getStorageConfigurationInfo() to TableLikeEntity base class
  - Applies to all table types: IcebergTable, IcebergView, GenericTable
  - Retrieves config from entity's internal properties
  - Returns null if no configuration is set (backward compatible)

- Add getStorageConfigurationInfo() to NamespaceEntity
  - Enables namespace-level storage configuration overrides
  - Supports both single and nested namespaces
  - Follows same pattern as CatalogEntity

- Add comprehensive unit tests
  - TableLikeEntityStorageConfigTest: 5 tests covering IcebergTable,
    IcebergView, and GenericTable entities
  - NamespaceEntityStorageConfigTest: 6 tests covering single/nested
    namespaces, AWS/Azure configs, and base location integration

Design rationale:
- Methods added to specific entity classes (TableLikeEntity, NamespaceEntity)
  rather than base PolarisEntity class
- Maintains consistency with CatalogEntity implementation
- Keeps administrative entity types (Principal, Role, etc.) clean
- Uses existing serialization mechanism via PolarisEntityConstants
- No changes needed to FileIOUtil.findStorageInfoFromHierarchy() - it
  already detects storage configs in internalProperties

This implementation enables hierarchical storage configuration resolution:
Table → Namespace → Catalog, with existing FileIOUtil automatically
supporting the new entity-level configurations.

Related to: Inline Storage Configuration feature
sririshindra added a commit to sririshindra/polaris that referenced this pull request Mar 2, 2026
Add effective-source metadata for namespace/table storage-config GET responses
to remove ambiguity during hierarchy fallback and post-DELETE behavior.

This complements PR apache#3409 (storageName-based credentials): once hierarchy
resolution picks the effective config, callers can now observe where it came
from while storageName continues to drive named-credential lookup when enabled.

- add X-Polaris-Storage-Config-Source response header for GET namespace/table
- introduce source-aware effective resolution helpers in PolarisServiceImpl
- keep existing storageName conversion/fallback behavior unchanged
- extend PolarisStorageConfigIntegrationTest to assert source across fallback paths
sririshindra added a commit to sririshindra/polaris that referenced this pull request Mar 2, 2026
Namespace GET effective storage config skipped intermediate parent
namespaces: for ns1.ns2.ns3 with a config only on ns1, the resolver
jumped directly to the catalog instead of stopping at ns1. The root
cause was resolveEffectiveNamespaceStorageConfig performing a single
entity lookup then a catalog fallback, rather than using the same
FileIOUtil.findStorageInfoFromHierarchy leaf-to-root walk that the
table GET path already uses correctly.

This interacts with PR apache#3409 (storageName): if a parent namespace
carries a storageName for named-credential isolation, and the leaf
namespace has no config, the PR apache#3409 credential dispatch would silently
use the catalog's storageName instead of the ancestor's. The fix closes
that hole for namespace-level hierarchy resolution.

Changes:

- PolarisAdminService: add resolveNamespacePath() returning the full
  PolarisResolvedPathWrapper (catalog root → leaf namespace); refactor
  resolveNamespaceEntity() to delegate to it, eliminating duplicated
  manifest-resolution logic.

- PolarisServiceImpl.resolveEffectiveNamespaceStorageConfig: replace
  direct entity + catalog lookup with resolveNamespacePath() +
  findStorageInfoFromHierarchy(), aligning namespace GET with table GET.

- PolarisServiceImpl.resolveEffectiveTableStorageConfigWithSource:
  remove redundant pre-calls to resolveNamespaceEntity() and
  resolveTableEntity(); resolveTablePath() already validates existence
  and throws NotFoundException, so the extra round-trips were wasteful.

- Add Javadoc to STORAGE_CONFIG_SOURCE_HEADER, StorageConfigSource,
  ResolvedStorageConfig, toInternalModel/toApiModel (document storageName
  invariant), storageConfigFromEntity, sourceForEntityType, and both
  resolveEffective* helpers.

- PolarisStorageConfigIntegrationTest: add
  testGetNamespaceStorageConfigFallsBackToAncestorNamespace — creates
  ns1 → ns1.ns2 → ns1.ns2.ns3, places config on ns1 only, asserts
  namespace GET for ns1.ns2.ns3 returns source=NAMESPACE (not CATALOG).
@tokoko tokoko deleted the aws-storage-credentials branch April 22, 2026 13:47
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.

Support Per-Catalog AWS Credentials in MinIO Deployments

7 participants