You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
PR #27987 ("strict literal matching across alert filter functions") changed AlertsRuleEvaluator.matchAnyEntityFqn from a substring regex (Pattern.compile(value).matcher(fqn).find()) to exact equality (entityFqns.contains(fqn)). That was a correct security/correctness fix (regex injection, crashes on metacharacter names, substring false positives) — but it silently removed a capability customers relied on: filtering by a parent FQN (a service / database / glossary / classification) to match all of its descendants.
Example: an alert with Source = databaseSchema and matchAnyEntityFqn({'Snowflake Integration'}) (a service FQN) matched all schemas under that service before the upgrade, and matched nothing after — "no change events". This regressed every hierarchical source (table, database, chart/dashboard, topic, mlmodel, pipeline, glossaryTerm, tag, dataProduct, …), not just databaseSchema.
Fix
Backend (the restore).matchAnyEntityFqn now matches when the entity FQN equals a listed FQN or is a descendant of one, using the existing literal, segment-anchored helper FullyQualifiedName.isParent (no regex). This restores subtree matching for existing alerts with no migration (the stored condition just starts matching again) while preserving every guarantee from #27987 — its regex-metacharacter and "unrelated FQN" tests still pass.
Backend-driven hierarchy. The source→ancestor mapping lives in the backend: a new containerEntities field on the notification/filter resource descriptors (subscriptionResourceDescriptor / filterResourceDescriptor), populated per source in EventSubResourceDescriptor.json and served through getNotificationsFilterDescriptors. The UI consumes it — no hardcoded hierarchy.
UI picker. The "Entity FQN" filter now searches the source index plus its ancestor indexes, so a user can select a parent (service/database/…) for a child source. Ancestor options render as Snowflake Integration.* (display only) to convey "everything under this"; the stored value stays the plain FQN.
AlertsUtil Jest: getFqnSearchIndexes index expansion (hierarchical vs flat source) and the FQN picker's multi-index search.
Notes
No data migration needed; existing alerts heal on deploy.
The truly-dynamic alternative (deriving the hierarchy from entity relationships) isn't available; containerEntities is the curated list, now owned by the backend and served to all clients.
Restores hierarchical FQN filtering by matching entities against exact names or descendants using backend-defined container relationships. Resolved issues related to NPEs, duplicated logic, and label overflow.
✅ 4 resolved✅ Edge Case: matchesFqnOrDescendant can NPE when entity FQN is null
📄 openmetadata-service/src/main/java/org/openmetadata/service/events/subscription/AlertsRuleEvaluator.java:147-161
The previous implementation used entityFqns.contains(entity.getFullyQualifiedName()), which is null-safe (List.contains(null) returns false). The new matchesFqnOrDescendant calls entityFqn.equals(listedFqn) and FullyQualifiedName.isParent(entityFqn, listedFqn) (which does childFqn.startsWith(...)). If entity.getFullyQualifiedName() is null for some change event, this now throws a NullPointerException instead of returning false. Most entities have an FQN set, so this is an edge case, but it is a behavioral regression from null-safe to NPE. Consider guarding against a null entity FQN before the loop.
✅ Bug: dataProduct->domain mapping is not an FQN ancestor, won't match
📄 openmetadata-service/src/main/resources/json/data/EventSubResourceDescriptor.json:326-327
In EventSubResourceDescriptor.json the dataProduct source declares containerEntities: ["domain"]. The new descendant-matching relies on FullyQualifiedName.isParent(entityFqn, listedFqn), which is a pure string prefix check (entityFqn.startsWith(parentFqn + ".")). However a DataProduct's fullyQualifiedName is NOT a descendant of its Domain's FQN: DataProductRepository sets the FQN to just the quoted data-product name (findByNameOrNull(FullyQualifiedName.quoteName(updated.getName()))), and the Domain is only a relationship, not an FQN prefix. As a result, the UI will let a user pick a Domain (rendered as Domain.*) as the Entity FQN filter for a dataProduct source, the plain domain FQN is stored, but isParent(dataProductFqn, domainFqn) is always false — so the alert silently matches nothing. This re-creates exactly the "no change events" regression this PR is trying to fix, for the dataProduct source.
Contrast with the other mappings which are genuine FQN prefixes (tag->classification = classification.tag, glossaryTerm->glossary = glossary.term, table->databaseService/database/databaseSchema, etc.) and do work.
Suggested fix: remove the containerEntities entry for dataProduct (since domain is not an FQN ancestor), or implement domain scoping for data products via a mechanism other than FQN-prefix matching.
✅ Quality: Duplicated 'all' container-entity logic and magic string across two pages
📄 openmetadata-ui/src/main/resources/ui/src/pages/AddNotificationPage/AddNotificationPage.tsx:234-244📄 openmetadata-ui/src/main/resources/ui/src/pages/AddObservabilityPage/AddObservabilityPage.tsx:203-213
The containerEntities memo logic added in AddNotificationPage.tsx (lines 234-244) and AddObservabilityPage.tsx (lines 203-213) is byte-for-byte identical, including the hardcoded selectedTrigger === 'all' comparison and the same explanatory comment. There is no centralized EntityType.ALL constant, so the raw string 'all' is used directly in both files (and implicitly mirrors SearchIndex.ALL = 'all' used in AlertsUtil.getFqnSearchIndexes). This duplication invites drift: a future change to how the 'all' source aggregates container entities must be applied in two places, and the magic string is easy to typo. Consider extracting a shared helper (e.g. in AlertsUtil) such as getContainerEntitiesForTrigger(resources, selectedTrigger) consumed by both pages, and referencing a shared constant instead of the literal 'all'.
✅ Quality: Removed maxTagTextLength may let long FQN tags overflow
📄 openmetadata-ui/src/main/resources/ui/src/components/Alerts/FQNListSelect/FQNListSelect.component.tsx:101-115📄 openmetadata-ui/src/main/resources/ui/src/utils/Alerts/AlertsUtil.tsx:952-962
The migration from AsyncSelect to FQNListSelect dropped the maxTagTextLength={45} prop and replaced it with a custom tagRender that uses <Typography.Text className="break-all">{label}</Typography.Text> with no truncation. Previously long FQNs were truncated to 45 characters in the multi-select tags; now they wrap and can make tags very tall, especially when several long FQNs are selected. Since the .* suffix already lengthens container labels, consider re-applying truncation (e.g. via CSS ellipsis or by truncating label in tagRender) to preserve the prior compact layout.
Changes have been cherry-picked to the 1.13 branch.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
backendsafe to testAdd this label to run secure Github workflows on PRsTo releaseWill cherry-pick this PR into the release branch
4 participants
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #28834
Problem
PR #27987 ("strict literal matching across alert filter functions") changed
AlertsRuleEvaluator.matchAnyEntityFqnfrom a substring regex (Pattern.compile(value).matcher(fqn).find()) to exact equality (entityFqns.contains(fqn)). That was a correct security/correctness fix (regex injection, crashes on metacharacter names, substring false positives) — but it silently removed a capability customers relied on: filtering by a parent FQN (a service / database / glossary / classification) to match all of its descendants.Example: an alert with
Source = databaseSchemaandmatchAnyEntityFqn({'Snowflake Integration'})(a service FQN) matched all schemas under that service before the upgrade, and matched nothing after — "no change events". This regressed every hierarchical source (table, database, chart/dashboard, topic, mlmodel, pipeline, glossaryTerm, tag, dataProduct, …), not just databaseSchema.Fix
Backend (the restore).
matchAnyEntityFqnnow matches when the entity FQN equals a listed FQN or is a descendant of one, using the existing literal, segment-anchored helperFullyQualifiedName.isParent(no regex). This restores subtree matching for existing alerts with no migration (the stored condition just starts matching again) while preserving every guarantee from #27987 — its regex-metacharacter and "unrelated FQN" tests still pass.Backend-driven hierarchy. The source→ancestor mapping lives in the backend: a new
containerEntitiesfield on the notification/filterresource descriptors (subscriptionResourceDescriptor/filterResourceDescriptor), populated per source inEventSubResourceDescriptor.jsonand served throughgetNotificationsFilterDescriptors. The UI consumes it — no hardcoded hierarchy.UI picker. The "Entity FQN" filter now searches the source index plus its ancestor indexes, so a user can select a parent (service/database/…) for a child source. Ancestor options render as
Snowflake Integration.*(display only) to convey "everything under this"; the stored value stays the plain FQN.Tests
AlertsRuleEvaluatorResourceIT(mirrors fix(alerts): strict literal matching across alert filter functions #27987's harness): descendant-positive (service/database/exact), sibling & mid-segment prefix-collision negatives, child-FQN-does-not-match-parent — plus all fix(alerts): strict literal matching across alert filter functions #27987 literal-matching tests kept green (41 run, 0 failures, on Postgres).AlertsUtilJest:getFqnSearchIndexesindex expansion (hierarchical vs flat source) and the FQN picker's multi-index search.Notes
containerEntitiesis the curated list, now owned by the backend and served to all clients.ON CONFLICTbatch dedup), which addressed a different alert bug surfaced in the same customer report.