core: introduce resolvePathsOnly() in Resolver and PolarisResolutionManifest#3427
core: introduce resolvePathsOnly() in Resolver and PolarisResolutionManifest#3427sungwy wants to merge 2 commits intoapache:mainfrom
resolvePathsOnly() in Resolver and PolarisResolutionManifest#3427Conversation
There was a problem hiding this comment.
Pull request overview
This PR introduces a new path-only resolution API in the resolver stack to support an upcoming authorization refactor. The changes add a resolvePathsOnly() method that resolves reference catalogs, top-level entities, and paths without resolving the caller principal or any roles.
Changes:
- Introduced
MAX_RESOLVE_PASSESconstant to replace hard-coded loop limit - Added
resolvePathsOnly()methods toResolverandPolarisResolutionManifestthat skip principal and role resolution - Refactored
resolveReferenceCatalog()to extract common logic into newresolveReferenceCatalogWithoutRoles()method - Added test coverage for the new path-only resolution functionality
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
Resolver.java |
Introduced MAX_RESOLVE_PASSES constant, added resolvePathsOnly() and runResolvePassPathsOnly() methods for path-only resolution, refactored catalog resolution to extract resolveReferenceCatalogWithoutRoles() method |
PolarisResolutionManifest.java |
Added resolvePathsOnly() delegation method and updated comments to reference both resolution methods |
BaseResolverTest.java |
Added testResolvePathsOnlySkipsPrincipalAndRoles() test to verify path-only resolution skips principal and role activation |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // retry until a pass terminates, or we reached the maximum iteration count. Note that we | ||
| // should finish normally in no more than few passes so the 1000 limit is really to avoid | ||
| // spinning forever if there is a bug. |
There was a problem hiding this comment.
The comment mentions "1000 limit" but should reference the constant MAX_RESOLVE_PASSES instead to improve maintainability. Consider changing "the 1000 limit" to "the MAX_RESOLVE_PASSES limit" or just "this limit".
| * roles. Returns SUCCESS, PATH_COULD_NOT_BE_FULLY_RESOLVED, or ENTITY_COULD_NOT_BE_RESOLVED and | ||
| * never returns CALLER_PRINCIPAL_DOES_NOT_EXIST. | ||
| */ | ||
| public ResolverStatus resolvePathsOnly() { |
There was a problem hiding this comment.
nit: the method name sounds a bit obscure to me, TBH 😅 How about resolveNonIamEntities or resolveResourceEntities or resolveCatalogEntities? I personally prefer the latter, but I suppose it may still be confusing wrt "Catalog Roles". WDYT?
There was a problem hiding this comment.
Hmmm I agree that I'm not a fan of the current name, nor these options :)
But naming is important! Let me give this a bit more thought while we continue the review
| * incoming rest request, Once resolved, the request can be authorized. | ||
| */ | ||
| public class Resolver { | ||
| private static final int MAX_RESOLVE_PASSES = 1000; |
| * | ||
| * @return status of the resolve pass | ||
| */ | ||
| private ResolverStatus runResolvePassPathsOnly() { |
There was a problem hiding this comment.
WDYT about making a Resolver sub-class for the new logic?
There was a problem hiding this comment.
Hi @dimas-b - by that are you suggesting that that the new Resolver sub-class should be chosen over the existing Resolver through a runtime configuration?
There was a problem hiding this comment.
Yes, something like that... but it depends on how / where we actually change to the new call path... which is not obvious in this PR 🤔
|
@sungwy : how to you envision choosing which |
Good question @dimas-b. Today we effectively hard-code the resolver choice in handlers. There are two call sites:
If we introduce a new
Before refactor (handlers always resolve eagerly):
After refactor (authorizer controls resolution):
In summary: by moving existence checks into the Authorizer and standardizing catalog call sites on
|
|
@sungwy : thanks for the refactoring proposal... I need some more time to think about it 😅 Ideally, I'd like the resolver algorithm to be tunable per persistence impl. Some efficiencies can be found in the relatively new NoSQL impl. (e.g. the hierarchical ID-based lookup via the parents trail is probably not required, paths can be resolved directly). If other people have comments, I'd be interested to know their opinions too. |
I tried to convey the idea as best as possible here, but I think a proper RFC would be best given the scope of the proposal. I'm working on one, and I'll send it out on the mailing list once I clarify the doc with mentions of specific call sites I'm thinking of updating |
This is not a requirement I have been thinking of so far... how do you envision the relationship of persistence impl <-> resolver impl <-> auth impl to be in an ideal world? So far, I've only been thinking of a world where auth impl would affect the resolver's behavior |
Rough sketch :)
WDYT? |
adutra
left a comment
There was a problem hiding this comment.
Thanks @sungwy I like both the direction being taken here and the ideas outlined by @dimas-b here: #3427 (comment) !
We need to find a way to articulate the changes to Resolver not only with the authorizer (the "receiving end") but also with the authenticator (the "sending end"). Your work on external principals in #3250 is imho relevant: if a principal is external, I don't think we should call resolveAll anywhere, or resolveAll should react differently to external principals.
Looking forward to the design doc!
| @@ -812,14 +900,10 @@ private List<ResolvedPolarisEntity> resolvePrincipalRolesByName( | |||
| */ | |||
| private ResolverStatus resolveReferenceCatalog( | |||
There was a problem hiding this comment.
nit: I'd prefer to have this method renamed to resolveReferenceCatalogAndRoles and the one below to resolveReferenceCatalog.
Good idea about using the Principal's |
| resolutionManifest.addPath( | ||
| new ResolverPath(Arrays.asList(ns.levels()), PolarisEntityType.NAMESPACE), ns)); | ||
| ResolverStatus status = resolutionManifest.resolveAll(); | ||
| ResolverStatus status = resolutionManifest.resolvePathsOnly(); |
There was a problem hiding this comment.
Do we plan to make the same changes for other classes, like Cataloghanlder, PolicyCatalogHandler?
Introduce path‑only resolution API in the resolver stack without changing handler or authorizer behavior. While working on a PR to move the principal, roles and entity resolution logic into the
PolarisAuthorizerImpl, I learned that resolution is done for a few reasons:While (2) and (3) can be moved into the
PolarisAuthorizerin line with the suggestion discussed in this PR comment, (1) needs to still be executed in the Handlers after a successful authorization.Hence, introducing this path-only resolution API will allow a follow‑up auth refactor to decouple execution‑time path resolution from (2) and (3) for authorizable actions that are only require entity or path resolution, without attempting to resolve the principal, or associated roles.
Checklist
CHANGELOG.md(if needed)site/content/in-dev/unreleased(if needed)