Workspace aware sharing records - #6374
Conversation
Let a resource belong to multiple workspaces and be discoverable by workspace members through the existing DLS sharing mechanism. Adds a workspace: principal namespace: workspace IDs on a resource are projected into all_shared_principals, and a user's accessible workspaces are added to the DLS filter, so the existing terms intersection grants visibility via workspace membership with no new query shape. Spike scope (read/discovery path only): - SPI: ResourceProvider.workspacesField() (default null; additive) - Multi-value field extraction from the index op at index time - ResourceSharing.workspaces set: builder, XContent (omitted when empty), fromXContent, equals/hashCode/toString, version-guarded writeTo - getAllPrincipals() emits workspace:<id>; DLS adds the user's workspaces I/O-free from an in-memory User attribute (honors hot-path no-I/O rule) - Seed visibility from getAllPrincipals() (creator + workspaces) Not yet addressed (follow-ups, intentionally not stubbed): - Write path (hasPermission) cross-record resolution of workspace access levels from the workspace's own sharing record - WORKSPACES_INTRODUCED_VERSION is a compile-only placeholder - No registered NamedWriteable reader for ResourceSharing (pre-existing) - Lucene doc-values materialization needs an integration-test spike - User->workspaces attribute key and authc-time population are placeholders ResourceSharingTests: 21 tests, 0 failures. Signed-off-by: Darshit Chanpura <dchanp@amazon.com>
Grant a user access to a resource when they have the required access level on any workspace the resource belongs to, not just when the resource is shared with them directly. Generalizes the existing single-parent access recursion in hasPermission into a fan-out over the resource's containers: its hierarchical parent (if any) plus each of its workspaces. Each workspace is resolved through hasPermission against the workspace's own sharing record, so workspace collaborators and their access levels map through the workspace type's action groups (per issue opensearch-project#6119). Access is granted if any container grants it; evaluation short-circuits on the first grant. Spike notes / follow-ups: - Workspace resource type name is a placeholder ("workspace"); the real type comes from the workspace provider registered via the SPI. If no provider is registered, the workspace branch denies cleanly. - No cycle/depth guard yet; safe for the intended model (workspace records do not themselves carry workspaces) but should be added. ResourceAccessHandlerTests: 15 tests, 0 failures. Signed-off-by: Darshit Chanpura <dchanp@amazon.com>
Prevent unbounded recursion when a resource inherits access from its containers (parent and/or workspaces) and the container graph is malformed (e.g. a workspace that transitively contains itself). Threads a visited set of type:id keys through the permission walk; re-encountering an already-visited resource short-circuits to false, which is safe under the fan-out's OR semantics. The public hasPermission signature is unchanged; a private overload carries the set. ResourceAccessHandlerTests: 16 tests, 0 failures (adds a self- referential-workspace cycle case). Signed-off-by: Darshit Chanpura <dchanp@amazon.com>
Resource sharing was introduced in 3.3 and is not yet GA, and the workspaces field ships within that same not-yet-released feature, so no older node speaks a wire format that omits it. The version gate (and its placeholder constant) added nothing but a misleading TODO; serialize the field unconditionally. The pre-existing NamedWriteable reader gap for ResourceSharing is unchanged and still noted as a follow-up. Signed-off-by: Darshit Chanpura <dchanp@amazon.com>
Avoid an N+1 sequential-GET pattern when a resource inherits access from the workspaces it belongs to. Previously each container was resolved by a separate recursive hasPermission call, i.e. one GET per workspace, serially, on the privilege hot path. Fetch all of a resource's workspace sharing records in a single mget (they live in one index with known ids) and evaluate them in memory via a new pure recordGrantsAction helper. The single hierarchical parent is still resolved recursively so grandparent chains keep working, and the visited-set cycle guard now also pre-filters workspace ids before the batch. Workspace records are evaluated as leaves (their own share_with), matching the flat workspace model. ResourceAccessHandlerTests: 16 tests, 0 failures. Signed-off-by: Darshit Chanpura <dchanp@amazon.com>
PR Code Analyzer ❗AI-powered 'Code-Diff-Analyzer' found issues on commit 7412d76. ⛔ Hard block: Issues at High severity or above will block this PR from merging.
The table above displays the top 10 most important findings. Pull Requests Author(s): Please update your Pull Request according to the report above. Repository Maintainer(s): You can Thanks. |
PR Reviewer Guide 🔍(Review updated until commit 7412d76)Here are some key observations to aid the review process:
|
PR Code Suggestions ✨Latest suggestions up to bcc3024 Explore these optional code suggestions:
Previous suggestionsSuggestions up to commit 7412d76
Suggestions up to commit ac9b426
Suggestions up to commit 76670dd
|
Make the resource-sharing migrate endpoint workspace-aware so workspaces that predate resource sharing carry their membership into the sharing records created during migration. When a provider declares workspacesField(), read the (multi-valued) set of workspace IDs off each source-doc search hit and set it on the built ResourceSharing record, so getAllPrincipals() emits workspace:<id> and DLS/write-path inheritance work for backfilled records exactly as for records indexed while the feature is on. Providers that do not declare the field are unaffected. Extraction is factored into a package-private static extractWorkspaces helper (array or scalar, blank ids ignored, dot-notation paths), the migrate-path counterpart of ResourcePluginInfo.extractMultiValuedField- FromIndexOp. Does not address updating already-migrated (skippedExisting) records or materializing workspace collaborator records from frontend ACLs; both are tracked as follow-ups. MigrateResourceSharingInfoApiActionTests: 13 tests, 0 failures. Signed-off-by: Darshit Chanpura <dchanp@amazon.com>
ac9b426 to
7412d76
Compare
|
Persistent review updated to latest commit 7412d76 |
Two findings from the PR code analyzer: 1. (Medium, security) DLS resolved workspace membership from a user-influenceable custom attribute, which feeds authorization and could let a user claim arbitrary workspace membership and read those workspaces' resources. Since no trusted server-set source of membership is wired yet, disable the resolver (returns empty) with an explicit server-set-only contract, removing the escalation vector until the trusted mechanism exists. 2. (Robustness) The container cycle guard used a global visited set and denied re-entry, which could falsely deny a node reachable from more than one branch in a DAG. Scope the guard to the current ancestor (parent) chain and remove each key when its node resolves; workspaces are leaf-evaluated and no longer touch the set at all, so sibling branches can never falsely deny each other. Resources test package: 95 tests, 0 failures. Signed-off-by: Darshit Chanpura <dchanp@amazon.com>
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #6374 +/- ##
==========================================
- Coverage 75.33% 75.30% -0.03%
==========================================
Files 456 456
Lines 30075 30251 +176
Branches 4564 4596 +32
==========================================
+ Hits 22657 22781 +124
- Misses 5297 5337 +40
- Partials 2121 2133 +12
🚀 New features to boost your workflow:
|
Description
[Describe what this change achieves]
Issues Resolved
[List any issues this PR will resolve]
Is this a backport? If so, please add backport PR # and/or commits #, and remove
backport-failedlabel from the original PR.Do these changes introduce new permission(s) to be displayed in the static dropdown on the front-end? If so, please open a draft PR in the security dashboards plugin and link the draft PR here
Testing
[Please provide details of testing done: unit testing, integration testing and manual testing]
Check List
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
For more information on following Developer Certificate of Origin and signing off your commits, please check here.