fix(search): restore ContextMemory search for owners and shared principals - #30593
Conversation
#29541 kept PRIVATE/SHARED memories out of the search index, but GET /contextCenter/memories serves the ContextCenter listing from search whenever it is given a query, filter, sort or offset — which the UI always sends. Owners stopped finding their own memories and shared principals stopped finding the ones shared with them. Index every memory again and enforce shareConfig visibility per query instead. The request builders now fail closed: a search path that never resolved the caller's subject gets org-wide memories only, so a forgotten call site cannot leak. Paths that build raw requests — field query, aggregations, lineage and entity-relationship traversals, doc-by-id — apply the same restriction explicitly. Restricted memories stay out of the vector index behind a new isVectorEmbeddable hook. Vector chunk documents carry no visibility fields and the vector query path takes no subject, so it cannot be filtered per caller. Also stubs the indexing policy on globally registered mock repositories, which left SearchRepositoryTest failing on main. Refs #29541 Co-Authored-By: Claude <noreply@anthropic.com>
✅ PR checks passedThe linked issue has a description and all required Shipping project fields set. Thanks! |
✅ Playwright Results — workflow succeededValidated commit ✅ 1385 passed · ❌ 0 failed · 🟡 5 flaky · ⏭️ 5 skipped · 🧰 0 lifecycle flaky PerformanceBlocking targets: ✅ met · Optimization targets: 🟡 in progress Shard-job maxima below are not the full workflow wall time; the linked run includes build, fixture, planning, and reporting. 🕒 Full workflow signal wall (to summary) 54m 18s ⏱️ Max setup 3m 6s · max shard execution 16m 24s · max shard-job elapsed before upload 21m 14s · reporting 9s 🌐 180.91 requests/attempt · 2.13 app boots/UI scenario · 10.37% common-shard skew Optimization targets still in progress:
🟡 5 flaky test(s) (passed on retry)
How to debug locally# Download playwright-test-results-<shard> artifact and unzip
npx playwright show-trace path/to/trace.zip # view trace |
#30528 marked these describe.fixme after the memory listing stopped returning PRIVATE/SHARED entries. That was the #29541 regression this branch fixes, not a test problem — the suites build Private, Shared and Entity fixtures and assert what a dataConsumer sees. CustomizeDetailPage stays fixme; it is unrelated to this change. Refs #30528 Co-Authored-By: Claude <noreply@anthropic.com>
getEntityTypeCounts built through the request builder without ever resolving the caller, so the fail-closed org-wide-only default always applied — even for an admin or a memory's owner. The contextMemory count then disagreed with the search-backed /contextCenter/memories listing, which does show those callers their PRIVATE and SHARED memories. SearchResource already had the SubjectContext and used it only for domains; thread it down to the aggregation managers and apply the same per-subject filter the listing uses. The subject-less overload stays and still fails closed, so an unidentifiable caller is unaffected. Co-Authored-By: Claude <noreply@anthropic.com>
|
Code Review ✅ Approved 1 resolved / 1 findingsRestores keyword-search indexing for restricted ContextMemory documents while enforcing subject visibility at query time, addressing the entityTypeCounts undercount finding. No issues found. ✅ 1 resolved✅ Edge Case: entityTypeCounts undercounts contextMemory for admins/owners
OptionsDisplay: compact → Showing less information. Comment with these commands to change the behavior for this request:
Was this helpful? React with 👍 / 👎 | Gitar | Powered by Gitar — free for open source |
…ipals (#30593) * fix(search): restore ContextMemory search for owners and shared users #29541 kept PRIVATE/SHARED memories out of the search index, but GET /contextCenter/memories serves the ContextCenter listing from search whenever it is given a query, filter, sort or offset — which the UI always sends. Owners stopped finding their own memories and shared principals stopped finding the ones shared with them. Index every memory again and enforce shareConfig visibility per query instead. The request builders now fail closed: a search path that never resolved the caller's subject gets org-wide memories only, so a forgotten call site cannot leak. Paths that build raw requests — field query, aggregations, lineage and entity-relationship traversals, doc-by-id — apply the same restriction explicitly. Restricted memories stay out of the vector index behind a new isVectorEmbeddable hook. Vector chunk documents carry no visibility fields and the vector query path takes no subject, so it cannot be filtered per caller. Also stubs the indexing policy on globally registered mock repositories, which left SearchRepositoryTest failing on main. Refs #29541 Co-Authored-By: Claude <noreply@anthropic.com> * test(playwright): re-enable ContextCenter memory suites #30528 marked these describe.fixme after the memory listing stopped returning PRIVATE/SHARED entries. That was the #29541 regression this branch fixes, not a test problem — the suites build Private, Shared and Entity fixtures and assert what a dataConsumer sees. CustomizeDetailPage stays fixme; it is unrelated to this change. Refs #30528 Co-Authored-By: Claude <noreply@anthropic.com> * fix(search): resolve subject for entityTypeCounts getEntityTypeCounts built through the request builder without ever resolving the caller, so the fail-closed org-wide-only default always applied — even for an admin or a memory's owner. The contextMemory count then disagreed with the search-backed /contextCenter/memories listing, which does show those callers their PRIVATE and SHARED memories. SearchResource already had the SubjectContext and used it only for domains; thread it down to the aggregation managers and apply the same per-subject filter the listing uses. The subject-less overload stays and still fails closed, so an unidentifiable caller is unaffected. Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>



Fixes #30596
Describe your changes:
I worked on restoring ContextMemory search for owners and shared principals because #29541 kept
PRIVATE/SHAREDmemories out of the search index entirely, andGET /contextCenter/memoriesserves the ContextCenter listing from search whenever it is given a query, filter, sort or offset — which the UI always sends (ContextCenterMemoriesPage.tsx:178,ContextCenterDashboardPage.tsx:218). The result was that a user could not see or find their own private memories anywhere in the ContextCenter. This PR indexes every memory again and enforcesshareConfigvisibility per query instead, making the request builders fail closed so a search path that forgets to resolve the caller cannot leak.Type of change:
High-level design:
Why not simply revert #29541. The index-time gate was the only thing preventing several unfiltered search paths from returning other users' memories. Reverting it alone would have reopened them, so the query-time model had to be completed first.
Enforcement now has one rule and one fallback.
ContextMemorySearchVisibility(unchanged in behaviour) filters memories tovisibility == EntityOR owner OR shared-with-subject.{Elastic,Open}SearchRequestBuilder.build()— the choke point every wrapped search funnels through — ANDs in a new fail-closed org-wide-only filter unless the caller marked the request resolved viacontextMemoryVisibilityResolved().applyContextMemoryVisibilitymarks it only when the subject is actually identifiable (isSubjectResolvable), so internal callers passing anullsubject fall back to the restrictive default rather than searching unfiltered.Paths that build raw requests bypass that choke point, so they call
restrictToOrgWideMemories(...)explicitly:searchByField,searchBySourceUrl, both aggregation managers, the hierarchy rewrite (whoseminimumShouldMatch(1)had demoted the filter to ashouldsibling), the entity-relationship traversals, andEsUtils/OsUtilslineage.getDocByIDruns no query at all, so it checksContextMemorySearchVisibility.isOrgWideReadableon the fetched document.Vector/RAG deliberately stays restricted. New
EntityRepository.isVectorEmbeddable(defaults toisSearchIndexable, overridden only byContextMemoryRepository) keeps non-org-wide memories out of the vector index on both the live path and the reindex bulk sinks, andclearEntityEmbeddingremoves the stale entity-docembeddingon anEntity → Privateflip that a partial merge would otherwise leave kNN-matchable. This is required rather than preferred: vector chunk documents carry neithervisibilitynorsharedWithIds,VectorSearchQueryBuilderhas a closed filter allowlist, andVectorIndexService.search(...)takes noSubjectContext— there is nothing to filter on and nowhere to filter. Behaviour there is unchanged from #29541, so this is not a regression.Rollout. Memories created while #29541 was in effect are absent from the index and are only written on their next update — a search reindex of
contextMemoryis needed to backfill them.ContextMemoryRepository.getReindexFilter()no longer restricts by visibility, so reader and counter stay balanced and the staged index still promotes.ListFilter.MEMORY_SEARCH_VISIBILITY_PARAMis removed as dead. No schema or data migration.Tests:
Use cases covered
PRIVATEmemory through the search-backed/contextCenter/memorieslisting (q,sortByandoffsetvariants) and through global search.sharedWithfinds aSHAREDmemory the same way.PRIVATE/SHAREDmemory on any search path.Unit tests
SearchRequestBuilderMemoryVisibilityTest(fail-closed default in both request builders; only an identified subject may mark a request resolved).ContextMemorySearchVisibilityTest(org-wide-only filter shape,should-only outer bool sominimum_should_matchstays 1,isOrgWideReadable),ContextMemoryRepositoryTest,ListFilterTest,VectorEmbeddingHandlerTest, both*BulkSinkBehaviorTest.mvn test -pl openmetadata-service→ 6980 run, 0 failures. Note this is better thanmain: the same suite onorigin/mainfails 6SearchRepositoryTesttests, because fix(search): enforce ContextMemory visibility at index time, not per-query #29541 madeEntity.isSearchIndexableconsultENTITY_REPOSITORY_MAPwhileEntityCsvTest/RuleEvaluatorTestregister never-torn-down mock repositories that answerfalse. Fixed here by stubbing the policy hooks on those mocks.Backend integration tests
openmetadata-integration-tests/.ContextMemoryIT.restrictedMemoriesAreSearchableByOwnerAndSharedPrincipalOnlyandContextMemoryIT.memoryStaysInSearchIndexAcrossVisibilityFlips.createMinimalRequest/createRequestno longer forceENTITY, soBaseEntityIT's generic search-index tests now themselves cover a restricted memory reaching the index. These two require the Docker stack and were not run locally.Ingestion integration tests
Playwright (UI) tests
Manual testing performed
Ran against a local stack (Postgres + OpenSearch) with an admin token and a second, non-admin principal, A/B against a server built from
main:PRIVATE,SHARED, org-wide, non-admin-owned and shared-with-non-admin memories; confirmed all five reachcontext_memory_search_index, and that only the org-wide one carries anembeddingfield./contextCenter/memorieswithsortBy/offset/q: admin sees all five; the non-admin sees exactly its own private, the one shared with it, and the org-wide one.main:GET /lineage/getLineage?fqn=<private-memory>returned the memory's answer text onmainand is indistinguishable from "not found" here;getPlatformLineage?view=all,/search/fieldQuery(index=contextMemoryandindex=all),/search/get/{index}/doc/{id},/search/aggregateand/search/entityTypeCountslikewise./search/queryand/search/fieldQueryagainst theuserandtagindices return byte-identical results on both builds.contextMemory-scoped reindex and confirmedPRIVATE/SHAREDmemories are backfilled and returned by the search-backed listing.UI screen recording / screenshots:
Not applicable.
Checklist:
I have read the CONTRIBUTING document.
My PR title is
Fixes <issue-number>: <short explanation>My PR is linked to a GitHub issue via
Fixes #<issue-number>above.I have commented on my code, particularly in hard-to-understand areas.
For JSON Schema changes: I updated the migration scripts or explained why it is not needed.
For UI changes: I attached a screen recording and/or screenshots above.
I have added tests (unit / integration / Playwright as applicable) and listed them above.
I have added a test that covers the exact scenario we are fixing.
Greptile Summary
This PR restores keyword-search indexing and subject-aware retrieval of restricted ContextMemory documents.
Confidence Score: 3/5
The PR is not yet safe to merge because hierarchy search still hides authorized PRIVATE and SHARED memories from owners and shared principals.
The hierarchy rewrite places the subject-aware query inside a should group and then applies an unconditional org-wide-only filter, so restricted memories remain excluded even when the caller owns them or is explicitly shared on them.
Files Needing Attention: openmetadata-service/src/main/java/org/openmetadata/service/search/elasticsearch/ElasticSearchSearchManager.java; openmetadata-service/src/main/java/org/openmetadata/service/search/opensearch/OpenSearchSearchManager.java
Important Files Changed
Reviews (3): Last reviewed commit: "fix(search): resolve subject for entityT..." | Re-trigger Greptile