Fixes 31740: Enforce caller policies on the Incident Manager listing (1.13 backport) (#31741) - #31936
Conversation
…(1.13 backport of #31741) A domain-restricted user saw failed test case incidents from every domain on the Incident Manager page. The two search-backed listing paths in EntityTimeSeriesRepository (plain listing and the latest=true aggregation) never received a SubjectContext, so RuleEvaluator#hasDomain's list-operation short-circuit was never backed by the search-side RBAC filtering it depends on, and no policy could restrict the listing. Threads the caller's SubjectContext through both paths, reusing the existing RBAC search machinery rather than adding a second enforcement path: - EntityTimeSeriesRepository#listFromSearchWithOffset / #listLatestFromSearch gain SubjectContext-aware overloads. - SearchRepository, AggregationManagementClient, and both ElasticSearch/OpenSearchAggregationManager gain a SubjectContext-aware aggregate() so latest=true cannot bypass the filtering applied to the plain listing. - TestCaseResolutionStatusResource passes the caller on both branches. This is not a straight cherry-pick of 8df0bb5: 1.13's ElasticSearchAggregationManager/OpenSearchAggregationManager have diverged from main (no ContextMemory feature here), so the RBAC-filtering change is hand-adapted onto 1.13's actual aggregate() implementation instead of reusing main's applyRbacQuery refactor verbatim. The upstream PR's DomainIsolationIT.java and DomainIsolation Playwright spec depend on test infrastructure (from #24180) that was never backported to 1.13, so this adds a standalone IncidentManagerDomainIsolationIT instead, following the existing MultiDomainHasDomainIT pattern already in use on this branch. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
❌ PR checklist incompleteThis PR cannot be merged until the following are addressed on its linked issue:
The fields live on the linked issue in the Shipping project (open the issue → right sidebar → Projects). After you set them, re-run this check (or push a commit) — issue/project changes do not re-trigger it automatically. Maintainers can bypass this check by adding the |
…, fix IT endpoint path Two follow-ups to 36c3697: 1. IncidentManagerDomainIsolationIT was hitting the wrong endpoint. There are two GET listings on TestCaseResolutionStatusResource: the base path (repository.list, DB-backed, unaffected by this fix and known to silently ignore its own domain param — a separate, out-of-scope bug) and /search/list (repository.listFromSearchWithOffset / listLatestFromSearch, the SubjectContext-aware path this fix actually changes). The IT was calling the base path, so it wasn't exercising the fix at all. Fixed to call /search/list, matching what the Incident Manager UI page itself calls. 2. Adds DomainIncidentIsolation.spec.ts (1.13 port of main's spec from #31741), covering the same regression at the UI level. This was left out of the initial backport on the assumption it needed new CI lane wiring, following a pattern from an unrelated ImportExport-lane investigation on a different branch. That doesn't apply here: 1.13 has no impact-map/path-filter test-selection layer — playwright-postgresql-e2e.yml triggers on any non-ignored path change and runs the full "chromium" project (default project, no explicit testMatch) across a fixed 6-way shard, so any new spec under playwright/e2e/Features/** is picked up automatically. The "DomainIsolation" project in playwright.config.ts is an unrelated compatibility shim for --project=DomainIsolation invocations and does not gate this. Ports the two missing dependencies from main: utils/domainIsolationUtils.ts (verbatim) and incidentManager.ts#seedFailedIncidents (adapted to poll /search/list instead of the base path, since that's the endpoint the spec's own assertions and this fix both depend on — polling the base, DB-backed path wouldn't actually confirm Elasticsearch indexing). The rest of main's DomainIsolation suite (search/lineage/task/dropdown/ listing isolation) still depends on #24180 infrastructure not backported to 1.13 and remains out of scope. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
❌ UI Checkstyle Failed❌ Core Components - I18n SyncCore-components ❌ Antd + Less Deprecation GuardA new Affected filesat Function._resolveFilename (node:internal/modules/cjs/loader:1401:15) Fix locally (fast - only checks files changed in this branch): make ui-checkstyle-changed |
Keep the diff minimal — the comment update was documentation-only and not needed for the fix itself. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…oject Gitar bot review on #31936 flagged that the spec runs under the default chromium project (fullyParallel, 3 CI workers) while its beforeAll/afterAll toggle the global searchSettings.enableAccessControl setting — the same reason SearchRBAC.spec.ts is already excluded from chromium and given its own isolated project. Left unisolated, concurrent chromium tests that touch search behavior could flake against the RBAC toggle mid-run. Routes the spec through the existing SearchRBAC project instead of adding a new project name, so no CI workflow change is needed (shard 1 already invokes --project=SearchRBAC). SearchRBAC previously had only one file, so it was trivially serial; adding a second file needs workers:1 to keep that guarantee — otherwise the two files are free to land on different workers and race each other on the same global setting. fullyParallel is left at its default: with workers:1 there's nothing for it to parallelize, so setting it explicitly would just be redundant. Not pushed yet, per instruction. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…n search helpers - applyRbacQuery (ES + OS) had 4 scattered return statements, violating this repo's single-trailing-return convention. Restructured to one result variable with a trailing return; behavior is unchanged. - domainIsolationUtils.ts carried three helpers ported from main (searchDomainInDropdownTree, searchDomainInListing, waitForDomainSearch) that nothing backported to 1.13 calls — only the other DomainIsolation specs (not backported) use them. Removed as dead code; re-add if/when those specs are backported. Not pushed yet, per instruction. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…'t exist on 1.13 CI run on #31936 showed both tests in this spec failing with "element(s) not found" on toBeVisible() — the incident-filter-bar testid this asserts on to confirm the page rendered doesn't exist in 1.13's IncidentManager.component.tsx at all (it's a main-only element I missed when porting the spec). Asserts on test-case-incident-manager-table instead, which does exist on 1.13 and is already what the per-row assertions further down rely on. Confirmed the other two Playwright shard failures in that run (GlossaryTermRelationsGraphNested, IngestionListNameSorting, GlossaryPermissions, CustomizeWidgets) are unrelated pre-existing flakiness, not caused by this PR. Not pushed yet, per instruction. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Greptile (P1) and Gitar bot review on #31936 both independently flagged the same real gap: IncidentManagerDomainIsolationIT toggles the global searchSettings.globalSettings.enableAccessControl flag without synchronizing against other concurrently-running (@execution(CONCURRENT)) IT classes that touch the same setting. A concurrent test could see RBAC unexpectedly enabled/disabled mid-run, or have its config replaced by this test's reset. This codebase already has a purpose-built fix for exactly this: SharedResourceLocks.SEARCH_SETTINGS + @ResourceLock, already used elsewhere (e.g. TypeResourceIT's TABLE_COLUMN_CUSTOM_PROPERTIES lock) — it just wasn't applied here. Adds it to the new test. MultiDomainHasDomainIT (the file IncidentManagerDomainIsolationIT's enable/restore pattern was copied from) has the same latent gap and was missing the lock too — fixing only the new test would leave it exposed to races against this pre-existing file, so this adds the same lock to its 3 test methods as well. Left the other bot findings on this PR alone where fixing them would mean diverging from main's own actual code (e.g. AggregationManagementClient's fail-open default aggregate() overload is main's real design, ported verbatim) or from main's own equivalent test-writing conventions (cleanup exceptions silently discarded, long single-method test bodies — both match main's DomainIsolationIT.java exactly). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Code Review ✅ Approved 5 resolved / 5 findingsThreads the caller subject through time-series search and aggregation paths to enforce Incident Manager listing policies, accompanied by integration and UI tests addressing multiple concurrency findings. ✅ 5 resolved✅ Quality: applyRbacQuery uses 4 scattered returns (style guideline)
✅ Bug: Incident isolation spec toggles global search RBAC in parallel project
✅ Quality: Unused exported helpers added to domainIsolationUtils.ts
✅ Bug: IT mutates global search settings under concurrent execution
✅ Security: Subject-aware aggregate() default overload fails open
OptionsDisplay: compact → Showing less information. Comment with these commands to change the behavior for this request:
Was this helpful? React with 👍 / 👎 | Powered by Gitar — free for open source |
Describe your changes:
Fixes #31740
1.13 backport of #31741.
A domain-restricted user saw failed test case incidents from every domain on the Incident Manager page. Opening one was correctly blocked, but the listed row already leaked the test case name, the table name and the full FQN.
RuleEvaluator#hasDomainshort-circuits totruefor list operations (a listing has no single resource to evaluate the condition against) and defers enforcement to search-side RBAC filtering. The two search-backed listing paths inEntityTimeSeriesRepositorynever received aSubjectContext, so that filtering never ran and no policy could restrict the listing — including withenableSearchAccessControlon.This threads the caller's
SubjectContextthrough both paths so the existing RBAC search machinery filters the query, same approach as the upstream fix.Not a straight cherry-pick
8df0bb573ddoesn't apply cleanly to1.13:ElasticSearchAggregationManager/OpenSearchAggregationManagerhave diverged frommain— 1.13 doesn't have the "ContextMemory" feature main'saggregate()wraps queries with (restrictToOrgWideMemories). TheSubjectContext-awareaggregate()overload and itsapplyRbacQueryhelper are hand-adapted onto 1.13's actual (undiverged)aggregate()implementation instead of reusing main's refactor verbatim.DomainIsolationIT.javadepends on test infrastructure from Feature Request: Improve domain isolation in UI and lineage for multi-tenant setups #24180 that was never backported to1.13(the file doesn't exist on this branch). This adds a standaloneIncidentManagerDomainIsolationITinstead, following theenableSearchAccessControl/restoreSearchAccessControl+TestNamespacepattern already established byMultiDomainHasDomainITon1.13.EntityTimeSeriesRepository,TestCaseResolutionStatusResource,SearchRepository,AggregationManagementClient,ElasticSearchClient,OpenSearchClient) matched1.13's current code closely enough to apply the same change directly.TestCaseResolutionStatusResourceon1.13has twoGETlistings worth noting since they're easy to conflate: the base path (repository.list, DB-backed viaListFilter/JDBI — not touched by this fix, and known to silently ignore its owndomainquery param, a separate pre-existing bug out of scope here) and/search/list(repository.listFromSearchWithOffset/listLatestFromSearch— theSubjectContext-aware path this fix actually changes, and what the Incident Manager UI page calls).Playwright
Initially left out on the assumption it needed new CI lane wiring, based on a pattern from an unrelated ImportExport-lane investigation on a different branch. That doesn't apply to
1.13: this branch has no impact-map/path-filter test-selection layer —playwright-postgresql-e2e.ymltriggers on any non-paths-ignored change and runs the fullchromiumproject (the default project, no explicittestMatch) across a fixed 6-way shard, so any new spec underplaywright/e2e/Features/**is picked up automatically. TheDomainIsolationproject inplaywright.config.tsis an unrelated compatibility shim for--project=DomainIsolationinvocations and doesn't gate this.Added
DomainIncidentIsolation.spec.ts(1.13 port of main's spec), plus its two missing dependencies:utils/domainIsolationUtils.ts— ported verbatim.incidentManager.ts#seedFailedIncidents— adapted to poll/search/listinstead of the base path, since that's the endpoint the spec's assertions and this fix both depend on (polling the base, DB-backed path wouldn't actually confirm Elasticsearch indexing).The rest of main's
DomainIsolationsuite (search/lineage/task/dropdown/listing isolation) still depends on#24180infrastructure not backported to1.13and remains out of scope.Type of change:
Tests:
Backend integration tests
IncidentManagerDomainIsolationIT#test_incidentListing_restrictedUserSeesOnlyOwnDomainIncidentsinopenmetadata-integration-tests/src/test/java/org/openmetadata/it/tests/IncidentManagerDomainIsolationIT.java. Seeds two domains, a domain-restricted user (DomainOnlyAccessRole), and incidents in each domain; asserts/search/listis filtered for bothlatest=falseandlatest=true— the aggregation path that carried the same gap.Not yet run against a live server in this session; this is its first execution in CI. It's a standard
*IT.javaunderopenmetadata-integration-tests, picked up automatically by the existing Maven integration-test phase.Playwright (UI) tests
openmetadata-ui/src/main/resources/ui/playwright/e2e/Features/DomainIsolation/DomainIncidentIsolation.spec.ts, ported from main. Runs under the defaultchromiumproject — no new CI lane needed (see above).Manual testing performed
Verified
mvn compile/mvn test-compilesucceed foropenmetadata-serviceandopenmetadata-integration-tests,mvn spotless:applymakes no further changes,yarn tsc:playwrightshows no new type errors from the added/modified files, andeslint/prettierpass clean on them. Not run against a live server in this session.Checklist:
Fixes <issue-number>: <short explanation>Fixes #<issue-number>above.Bug fix:
1.13.🤖 Generated with Claude Code
Greptile Summary
This backport threads the authenticated subject through time-series search and aggregation paths so Incident Manager listings honor caller policies.
Confidence Score: 5/5
The PR appears safe to merge.
No blocking failure remains.
Important Files Changed
Sequence Diagram
sequenceDiagram participant U as Restricted caller participant R as Incident status resource participant T as Time-series repository participant S as Search repository participant A as Search aggregation manager U->>R: GET /search/list R->>R: Resolve SubjectContext alt "latest=false" R->>T: listFromSearchWithOffset(..., subject) T->>S: listWithOffset(..., subject) S-->>U: Policy-filtered incidents else "latest=true" R->>T: listLatestFromSearch(..., subject) T->>S: aggregate(..., subject) S->>A: Apply RBAC query A-->>U: Policy-filtered latest incidents endReviews (6): Last reviewed commit: "Serialize IT tests that mutate global se..." | Re-trigger Greptile
Context used (3)