Skip to content

feat(dsl): Add OpenMetadata DSL module for alert rules and governance#27605

Open
Dev0907 wants to merge 1 commit intoopen-metadata:mainfrom
Dev0907:feature/openmetadata-dsl
Open

feat(dsl): Add OpenMetadata DSL module for alert rules and governance#27605
Dev0907 wants to merge 1 commit intoopen-metadata:mainfrom
Dev0907:feature/openmetadata-dsl

Conversation

@Dev0907
Copy link
Copy Markdown

@Dev0907 Dev0907 commented Apr 21, 2026

Description
This PR introduces the OpenMetadata DSL (Domain-Specific Language) module - a powerful engine for creating sophisticated alert rules, governance policies, and automation workflows using natural, expressive syntax.

Features Implemented
🚨 Smart Alerts Engine

  • Multi-category support (data quality, performance, security, compliance)
  • Real-time expression evaluation
  • Template library ready
    🛡️ Data Governance
  • Rule-based entity evaluation
  • Violation tracking capabilities
  • Compliance automation
    🔒 Security Functions
  • hasTag() - Check if entity has specific tag
  • hasChanged() - Detect field changes
  • isOwner() - Verify ownership
  • daysSinceLastUpdate() - Track data freshness

Files Changed
File
openmetadata-dsl/pom.xml
OpenMetadataDSL.java
DSLExpressionParser.java
DSLContext.java
DSLExpression.java
DSLVariable.java
DSLExamples.java
pom.xml (root)

Example Usage
// Data quality rule
"entity.entityType == 'table' AND isEmpty(entity.description)"
// Compliance rule
"contains(entity.name, 'customer') AND NOT hasTag('GDPR-Compliant')"
// Security rule
"contains(entity.name, 'ssn') AND NOT hasTag('Security-Classified')"


Summary by Gitar

  • DSL Engine Improvements:
    • Added security validation in matches function with a 100-character limit to mitigate potential ReDoS attacks.
    • Enhanced binary expression evaluation including support for the NOT logical operator and robust null handling for == and !=.
    • Added support for service entity field access and implemented detailed exception logging for runtime evaluation errors.
  • Testing:
    • Added comprehensive OpenMetadataDSLTest suite covering operators, field access, function evaluation, and various entity states.

This will update automatically on new commits.

@github-actions
Copy link
Copy Markdown
Contributor

Hi there 👋 Thanks for your contribution!

The OpenMetadata team will review the PR shortly! Once it has been labeled as safe to test, the CI workflows
will start executing and we'll be able to make sure everything is working as expected.

Let us know if you need any help!

Comment on lines +152 to +159
private Object callFunction(String name, java.util.List<DSLExpression> args, DSLContext ctx) {
Function<DSLContext, ?> fn = functions.get(name);
if (fn == null) {
log.warn("Unknown function: {}", name);
return null;
}
return fn.apply(ctx);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚨 Bug: callFunction ignores parsed arguments — all functions broken

The callFunction method retrieves the registered Function<DSLContext, Object> and calls fn.apply(ctx), which returns an inner lambda (e.g., (String s, String search) -> ...). However, it never invokes that inner lambda with the actual parsed arguments. The args parameter is completely ignored. This means every function call (contains(), hasTag(), isEmpty(), etc.) will return the lambda object itself rather than executing it, so no function in the DSL will work correctly.

Suggested fix:

Evaluate each argument via `evaluate(arg, context)`, then reflectively or via a typed dispatch invoke the returned functional interface with those evaluated arguments. Alternatively, redesign the function registry to accept `(DSLContext, List<Object>) -> Object` so callFunction can pass arguments directly.

Was this helpful? React with 👍 / 👎 | Reply gitar fix to apply this suggestion

@github-actions
Copy link
Copy Markdown
Contributor

Hi there 👋 Thanks for your contribution!

The OpenMetadata team will review the PR shortly! Once it has been labeled as safe to test, the CI workflows
will start executing and we'll be able to make sure everything is working as expected.

Let us know if you need any help!

Comment thread openmetadata-dsl/src/main/java/org/openmetadata/dsl/OpenMetadataDSL.java Outdated
Comment thread openmetadata-dsl/pom.xml
@github-actions
Copy link
Copy Markdown
Contributor

Hi there 👋 Thanks for your contribution!

The OpenMetadata team will review the PR shortly! Once it has been labeled as safe to test, the CI workflows
will start executing and we'll be able to make sure everything is working as expected.

Let us know if you need any help!

@Dev0907 Dev0907 force-pushed the feature/openmetadata-dsl branch from 0bb08a7 to 2f0b2ad Compare April 21, 2026 17:20
@Dev0907 Dev0907 requested a review from a team as a code owner April 21, 2026 17:20
@github-actions
Copy link
Copy Markdown
Contributor

Hi there 👋 Thanks for your contribution!

The OpenMetadata team will review the PR shortly! Once it has been labeled as safe to test, the CI workflows
will start executing and we'll be able to make sure everything is working as expected.

Let us know if you need any help!

- Add DSL engine for evaluating alert rules and governance policies
- Support field access, comparisons (==, !=, >, <, >=, <=)
- Support logical operators (AND, OR, NOT)
- Built-in functions: contains, startsWith, length, matches, hasTag, hasChanged, isOwner
- Fix ReDoS vulnerability by limiting regex complexity
- Add comprehensive unit tests
@Dev0907 Dev0907 force-pushed the feature/openmetadata-dsl branch from 2f0b2ad to ee8f6c1 Compare April 21, 2026 17:30
@github-actions
Copy link
Copy Markdown
Contributor

Hi there 👋 Thanks for your contribution!

The OpenMetadata team will review the PR shortly! Once it has been labeled as safe to test, the CI workflows
will start executing and we'll be able to make sure everything is working as expected.

Let us know if you need any help!

Comment on lines +171 to +184
private Object callFunction(String name, java.util.List<DSLExpression> args, DSLContext ctx) {
Function<DSLContext, ?> fn = functions.get(name);
if (fn == null) {
log.warn("Unknown function: {}", name);
return null;
}
// For functions that don't need args, just apply
try {
return fn.apply(ctx);
} catch (Exception e) {
log.error("Error calling function: {}", name, e);
return null;
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚨 Bug: callFunction ignores parsed arguments — all functions broken

The callFunction method receives args (the parsed function arguments from the AST) but completely ignores them. It only calls fn.apply(ctx), which returns the inner lambda (e.g., (String s, String search) -> s.contains(search)) rather than actually invoking it with the evaluated arguments.

This means every function call (contains(), hasTag(), isEmpty(), etc.) returns a lambda object instead of a boolean/value result. Since a lambda object is not instanceof Boolean, evaluateCondition will always return false for any expression involving a function call. This effectively breaks the entire DSL engine for its core use cases (governance rules, alert conditions).

The fix requires evaluating each argument expression, then dispatching to the function with those evaluated values. The current two-layer lambda design (ctx -> (args) -> result) is unnecessarily complex — consider simplifying to a single BiFunction<DSLContext, List<Object>, Object> pattern.

Suggested fix:

// Replace the function registry type and callFunction:
private final Map<String, BiFunction<DSLContext, List<Object>, Object>> functions;

// Register like:
functions.put("contains", (ctx, args) -> {
  String s = (String) args.get(0);
  String search = (String) args.get(1);
  return s != null && s.contains(search);
});

// In callFunction, evaluate args first:
List<Object> evalArgs = args.stream()
    .map(a -> evaluate(a, context))
    .collect(Collectors.toList());
return fn.apply(ctx, evalArgs);

Was this helpful? React with 👍 / 👎 | Reply gitar fix to apply this suggestion

Comment on lines +127 to +141
private Object evaluate(DSLExpression ast, DSLContext context) {
if (ast == null) {
return false;
}
switch (ast.getType()) {
case BOOLEAN:
return ast.getBooleanValue();
case FIELD:
return getFieldValue(ast.getFieldName(), context);
case FUNCTION:
return callFunction(ast.getFunctionName(), ast.getArguments(), context);
case BINARY_EXPR:
return evaluateBinaryExpression(ast, context);
default:
return false;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Bug: evaluate() missing STRING and NUMBER cases — literals ignored

The evaluate method's switch statement handles BOOLEAN, FIELD, FUNCTION, and BINARY_EXPR but omits STRING and NUMBER (and VARIABLE, CONDITIONAL). The parser correctly produces STRING and NUMBER expression nodes (e.g., for 'table' or 5 in comparisons), but evaluate() falls through to default: return false for these types.

This means the right-hand side of entity.entityType == 'table' evaluates to false (a Boolean) instead of the string "table", so equality comparisons with literals will always produce incorrect results.

Suggested fix:

case STRING:
  return ast.getStringValue();
case NUMBER:
  return ast.getNumberValue();

Was this helpful? React with 👍 / 👎 | Reply gitar fix to apply this suggestion

Comment thread openmetadata-dsl/pom.xml
Comment on lines +33 to +40
<artifactId>antlr4-runtime</artifactId>
<version>4.9.3</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>6.1.14</version>
</dependency>
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Quality: Unused antlr4 and spring-core deps with version conflicts

The openmetadata-dsl/pom.xml declares dependencies on antlr4-runtime:4.9.3 and spring-core:6.1.14, but neither is imported or used anywhere in the module's source code. The parser is hand-written using java.util.regex. Additionally, these hardcoded versions conflict with the parent POM's managed versions (antlr:4.13.2, spring:6.2.11), which could cause classpath issues at runtime if the module is included in a larger build. Remove unused dependencies or, if they are planned for future use, at least use ${antlr.version} / ${spring.version} from the parent POM.

Suggested fix:

Remove the unused dependencies:
<!-- Remove these from pom.xml -->
<dependency>
  <groupId>org.antlr</groupId>
  <artifactId>antlr4-runtime</artifactId>
  ...
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-core</artifactId>
  ...
</dependency>

Was this helpful? React with 👍 / 👎 | Reply gitar fix to apply this suggestion

Comment on lines +43 to +57
functions.put("matches", ctx -> (String s, String regex) -> {
if (s == null || regex == null) {
return false;
}
// Limit regex complexity to prevent ReDoS
if (regex.length() > 100) {
log.warn("Regex too long, rejecting for security");
return false;
}
try {
return s.matches(regex);
} catch (Exception e) {
log.warn("Invalid regex pattern: {}", regex);
return false;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Security: Regex length check insufficient to prevent ReDoS

The matches() function limits regex length to 100 characters but does not restrict dangerous patterns. A short regex like (a+)+b (11 chars) can cause catastrophic backtracking on input "aaaaaaaaaaaaaaaaaaaaa". Since DSL expressions are likely user-supplied (alert rules, governance policies), this is an exploitable denial-of-service vector.

Consider running the regex with a timeout, using Pattern.compile with a bounded match via Matcher + interrupt, or restricting to a safe regex subset (e.g., no nested quantifiers).

Suggested fix:

// Execute regex with a timeout using a separate thread:
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<Boolean> future = executor.submit(() -> s.matches(regex));
try {
  return future.get(100, TimeUnit.MILLISECONDS);
} catch (TimeoutException e) {
  future.cancel(true);
  log.warn("Regex timed out: {}", regex);
  return false;
}

Was this helpful? React with 👍 / 👎 | Reply gitar fix to apply this suggestion

@gitar-bot
Copy link
Copy Markdown

gitar-bot Bot commented Apr 21, 2026

Code Review 🚫 Blocked 6 resolved / 11 findings

Initial OpenMetadata DSL module implementation introduces critical regressions where function arguments are ignored and literal evaluation is incomplete. Unresolved critical and important issues regarding dependency conflicts and ReDoS risks must be addressed before integration.

🚨 Bug: callFunction ignores parsed arguments — all functions broken

📄 openmetadata-dsl/src/main/java/org/openmetadata/dsl/OpenMetadataDSL.java:152-159

The callFunction method retrieves the registered Function<DSLContext, Object> and calls fn.apply(ctx), which returns an inner lambda (e.g., (String s, String search) -> ...). However, it never invokes that inner lambda with the actual parsed arguments. The args parameter is completely ignored. This means every function call (contains(), hasTag(), isEmpty(), etc.) will return the lambda object itself rather than executing it, so no function in the DSL will work correctly.

Suggested fix
Evaluate each argument via `evaluate(arg, context)`, then reflectively or via a typed dispatch invoke the returned functional interface with those evaluated arguments. Alternatively, redesign the function registry to accept `(DSLContext, List<Object>) -> Object` so callFunction can pass arguments directly.
🚨 Bug: callFunction ignores parsed arguments — all functions broken

📄 openmetadata-dsl/src/main/java/org/openmetadata/dsl/OpenMetadataDSL.java:171-184 📄 openmetadata-dsl/src/main/java/org/openmetadata/dsl/OpenMetadataDSL.java:36-50

The callFunction method receives args (the parsed function arguments from the AST) but completely ignores them. It only calls fn.apply(ctx), which returns the inner lambda (e.g., (String s, String search) -> s.contains(search)) rather than actually invoking it with the evaluated arguments.

This means every function call (contains(), hasTag(), isEmpty(), etc.) returns a lambda object instead of a boolean/value result. Since a lambda object is not instanceof Boolean, evaluateCondition will always return false for any expression involving a function call. This effectively breaks the entire DSL engine for its core use cases (governance rules, alert conditions).

The fix requires evaluating each argument expression, then dispatching to the function with those evaluated values. The current two-layer lambda design (ctx -> (args) -> result) is unnecessarily complex — consider simplifying to a single BiFunction<DSLContext, List<Object>, Object> pattern.

Suggested fix
// Replace the function registry type and callFunction:
private final Map<String, BiFunction<DSLContext, List<Object>, Object>> functions;

// Register like:
functions.put("contains", (ctx, args) -> {
  String s = (String) args.get(0);
  String search = (String) args.get(1);
  return s != null && s.contains(search);
});

// In callFunction, evaluate args first:
List<Object> evalArgs = args.stream()
    .map(a -> evaluate(a, context))
    .collect(Collectors.toList());
return fn.apply(ctx, evalArgs);
⚠️ Bug: evaluate() missing STRING and NUMBER cases — literals ignored

📄 openmetadata-dsl/src/main/java/org/openmetadata/dsl/OpenMetadataDSL.java:127-141

The evaluate method's switch statement handles BOOLEAN, FIELD, FUNCTION, and BINARY_EXPR but omits STRING and NUMBER (and VARIABLE, CONDITIONAL). The parser correctly produces STRING and NUMBER expression nodes (e.g., for 'table' or 5 in comparisons), but evaluate() falls through to default: return false for these types.

This means the right-hand side of entity.entityType == 'table' evaluates to false (a Boolean) instead of the string "table", so equality comparisons with literals will always produce incorrect results.

Suggested fix
case STRING:
  return ast.getStringValue();
case NUMBER:
  return ast.getNumberValue();
⚠️ Quality: Unused antlr4 and spring-core deps with version conflicts

📄 openmetadata-dsl/pom.xml:33-40

The openmetadata-dsl/pom.xml declares dependencies on antlr4-runtime:4.9.3 and spring-core:6.1.14, but neither is imported or used anywhere in the module's source code. The parser is hand-written using java.util.regex. Additionally, these hardcoded versions conflict with the parent POM's managed versions (antlr:4.13.2, spring:6.2.11), which could cause classpath issues at runtime if the module is included in a larger build. Remove unused dependencies or, if they are planned for future use, at least use ${antlr.version} / ${spring.version} from the parent POM.

Suggested fix
Remove the unused dependencies:
<!-- Remove these from pom.xml -->
<dependency>
  <groupId>org.antlr</groupId>
  <artifactId>antlr4-runtime</artifactId>
  ...
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-core</artifactId>
  ...
</dependency>
⚠️ Security: Regex length check insufficient to prevent ReDoS

📄 openmetadata-dsl/src/main/java/org/openmetadata/dsl/OpenMetadataDSL.java:43-57

The matches() function limits regex length to 100 characters but does not restrict dangerous patterns. A short regex like (a+)+b (11 chars) can cause catastrophic backtracking on input "aaaaaaaaaaaaaaaaaaaaa". Since DSL expressions are likely user-supplied (alert rules, governance policies), this is an exploitable denial-of-service vector.

Consider running the regex with a timeout, using Pattern.compile with a bounded match via Matcher + interrupt, or restricting to a safe regex subset (e.g., no nested quantifiers).

Suggested fix
// Execute regex with a timeout using a separate thread:
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<Boolean> future = executor.submit(() -> s.matches(regex));
try {
  return future.get(100, TimeUnit.MILLISECONDS);
} catch (TimeoutException e) {
  future.cancel(true);
  log.warn("Regex timed out: {}", regex);
  return false;
}
✅ 6 resolved
Bug: Field lookups fail — "entity." prefix not stripped

📄 openmetadata-dsl/src/main/java/org/openmetadata/dsl/OpenMetadataDSL.java:130-144 📄 openmetadata-dsl/src/main/java/org/openmetadata/dsl/DSLExpressionParser.java:26-32
The tokenizer regex [a-zA-Z_][a-zA-Z0-9_.]* matches dotted paths as a single token, so entity.entityType becomes the token entity.entityType. But getFieldValue() switches on bare names like "entityType", "name", etc. Every field access in a DSL expression like entity.entityType == 'table' will hit the default case and return null, making all field-based comparisons fail.

Bug: ast.getValue() does not exist — compilation error

📄 openmetadata-dsl/src/main/java/org/openmetadata/dsl/OpenMetadataDSL.java:116-128 📄 openmetadata-dsl/src/main/java/org/openmetadata/dsl/DSLExpression.java:35-43
DSLExpression is a Lombok @Data class with fields booleanValue, numberValue, stringValue, etc. There is no value field, so getValue() does not exist. The evaluate() method calls ast.getValue() for the BOOLEAN case (line 118), which will fail to compile. Additionally, the STRING and NUMBER expression types are not handled in the evaluate() switch and will silently return false.

Bug: NOT operator not implemented in evaluator

📄 openmetadata-dsl/src/main/java/org/openmetadata/dsl/OpenMetadataDSL.java:166-180 📄 openmetadata-dsl/src/main/java/org/openmetadata/dsl/DSLExpressionParser.java:134-147
The parser correctly creates a BINARY_EXPR node with operator("NOT") for NOT expressions, but evaluateBinaryExpression() has no case for "NOT" in its switch statement. It falls through to default: return false, meaning NOT hasTag('GDPR-Compliant') will always evaluate to false. This breaks all compliance/security example rules that use NOT.

Security: ReDoS vulnerability via user-supplied regex in matches()

📄 openmetadata-dsl/src/main/java/org/openmetadata/dsl/OpenMetadataDSL.java:43
The matches function passes user-supplied regex directly to String.matches() without any complexity limits or timeout. A malicious or careless user can craft a pathological regex (e.g., (a+)+$) that causes catastrophic backtracking, potentially hanging the evaluation thread and causing denial of service.

Quality: Wrong license header in DSLExpression.java (GPL vs Apache)

📄 openmetadata-dsl/src/main/java/org/openmetadata/dsl/DSLExpression.java:1-8
DSLExpression.java has a license header referencing the GNU General Public License, while the entire project and all other new files use Apache License 2.0. This is a licensing inconsistency that could create legal ambiguity.

...and 1 more resolved from earlier reviews

🤖 Prompt for agents
Code Review: Initial OpenMetadata DSL module implementation introduces critical regressions where function arguments are ignored and literal evaluation is incomplete. Unresolved critical and important issues regarding dependency conflicts and ReDoS risks must be addressed before integration.

1. 🚨 Bug: callFunction ignores parsed arguments — all functions broken
   Files: openmetadata-dsl/src/main/java/org/openmetadata/dsl/OpenMetadataDSL.java:152-159

   The `callFunction` method retrieves the registered `Function<DSLContext, Object>` and calls `fn.apply(ctx)`, which returns an inner lambda (e.g., `(String s, String search) -> ...`). However, it never invokes that inner lambda with the actual parsed arguments. The `args` parameter is completely ignored. This means every function call (`contains()`, `hasTag()`, `isEmpty()`, etc.) will return the lambda object itself rather than executing it, so no function in the DSL will work correctly.

   Suggested fix:
   Evaluate each argument via `evaluate(arg, context)`, then reflectively or via a typed dispatch invoke the returned functional interface with those evaluated arguments. Alternatively, redesign the function registry to accept `(DSLContext, List<Object>) -> Object` so callFunction can pass arguments directly.

2. 🚨 Bug: callFunction ignores parsed arguments — all functions broken
   Files: openmetadata-dsl/src/main/java/org/openmetadata/dsl/OpenMetadataDSL.java:171-184, openmetadata-dsl/src/main/java/org/openmetadata/dsl/OpenMetadataDSL.java:36-50

   The `callFunction` method receives `args` (the parsed function arguments from the AST) but completely ignores them. It only calls `fn.apply(ctx)`, which returns the *inner lambda* (e.g., `(String s, String search) -> s.contains(search)`) rather than actually invoking it with the evaluated arguments.
   
   This means every function call (`contains()`, `hasTag()`, `isEmpty()`, etc.) returns a lambda object instead of a boolean/value result. Since a lambda object is not `instanceof Boolean`, `evaluateCondition` will always return `false` for any expression involving a function call. This effectively breaks the entire DSL engine for its core use cases (governance rules, alert conditions).
   
   The fix requires evaluating each argument expression, then dispatching to the function with those evaluated values. The current two-layer lambda design (`ctx -> (args) -> result`) is unnecessarily complex — consider simplifying to a single `BiFunction<DSLContext, List<Object>, Object>` pattern.

   Suggested fix:
   // Replace the function registry type and callFunction:
   private final Map<String, BiFunction<DSLContext, List<Object>, Object>> functions;
   
   // Register like:
   functions.put("contains", (ctx, args) -> {
     String s = (String) args.get(0);
     String search = (String) args.get(1);
     return s != null && s.contains(search);
   });
   
   // In callFunction, evaluate args first:
   List<Object> evalArgs = args.stream()
       .map(a -> evaluate(a, context))
       .collect(Collectors.toList());
   return fn.apply(ctx, evalArgs);

3. ⚠️ Bug: evaluate() missing STRING and NUMBER cases — literals ignored
   Files: openmetadata-dsl/src/main/java/org/openmetadata/dsl/OpenMetadataDSL.java:127-141

   The `evaluate` method's switch statement handles `BOOLEAN`, `FIELD`, `FUNCTION`, and `BINARY_EXPR` but omits `STRING` and `NUMBER` (and `VARIABLE`, `CONDITIONAL`). The parser correctly produces `STRING` and `NUMBER` expression nodes (e.g., for `'table'` or `5` in comparisons), but `evaluate()` falls through to `default: return false` for these types.
   
   This means the right-hand side of `entity.entityType == 'table'` evaluates to `false` (a Boolean) instead of the string `"table"`, so equality comparisons with literals will always produce incorrect results.

   Suggested fix:
   case STRING:
     return ast.getStringValue();
   case NUMBER:
     return ast.getNumberValue();

4. ⚠️ Quality: Unused antlr4 and spring-core deps with version conflicts
   Files: openmetadata-dsl/pom.xml:33-40

   The `openmetadata-dsl/pom.xml` declares dependencies on `antlr4-runtime:4.9.3` and `spring-core:6.1.14`, but neither is imported or used anywhere in the module's source code. The parser is hand-written using `java.util.regex`. Additionally, these hardcoded versions conflict with the parent POM's managed versions (`antlr:4.13.2`, `spring:6.2.11`), which could cause classpath issues at runtime if the module is included in a larger build. Remove unused dependencies or, if they are planned for future use, at least use `${antlr.version}` / `${spring.version}` from the parent POM.

   Suggested fix:
   Remove the unused dependencies:
   <!-- Remove these from pom.xml -->
   <dependency>
     <groupId>org.antlr</groupId>
     <artifactId>antlr4-runtime</artifactId>
     ...
   </dependency>
   <dependency>
     <groupId>org.springframework</groupId>
     <artifactId>spring-core</artifactId>
     ...
   </dependency>

5. ⚠️ Security: Regex length check insufficient to prevent ReDoS
   Files: openmetadata-dsl/src/main/java/org/openmetadata/dsl/OpenMetadataDSL.java:43-57

   The `matches()` function limits regex length to 100 characters but does not restrict dangerous patterns. A short regex like `(a+)+b` (11 chars) can cause catastrophic backtracking on input `"aaaaaaaaaaaaaaaaaaaaa"`. Since DSL expressions are likely user-supplied (alert rules, governance policies), this is an exploitable denial-of-service vector.
   
   Consider running the regex with a timeout, using `Pattern.compile` with a bounded match via `Matcher` + interrupt, or restricting to a safe regex subset (e.g., no nested quantifiers).

   Suggested fix:
   // Execute regex with a timeout using a separate thread:
   ExecutorService executor = Executors.newSingleThreadExecutor();
   Future<Boolean> future = executor.submit(() -> s.matches(regex));
   try {
     return future.get(100, TimeUnit.MILLISECONDS);
   } catch (TimeoutException e) {
     future.cancel(true);
     log.warn("Regex timed out: {}", regex);
     return false;
   }

Options

Display: compact → Showing less information.

Comment with these commands to change:

Compact
gitar display:verbose         

Was this helpful? React with 👍 / 👎 | Gitar

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants