From 9efed35efb447a25b3086c66430d0b5595da3762 Mon Sep 17 00:00:00 2001 From: Aleksandr Misonizhnik Date: Wed, 27 May 2026 18:59:58 +0200 Subject: [PATCH] test: repro for "Method name metavar constraints intersection" rule-load crash Loads an inline taint rule whose sink pattern binds two method-name metavars ($COND and $METHOD), both constrained via metavariable-pattern, and asserts the rule loads without blocking errors. It currently FAILS: the automata transform cannot intersect two constrained method-name metavars (MethodName.unify TODO, MethodFormulaSimplifier.kt), so loading reports BLOCKING BUILD_TRANSFORM_TO_AUTOMATA. Demonstrates that metavariable-pattern does not avoid the crash (same as metavariable-regex). --- .../semgrep/MetavarPatternBothReproTest.kt | 77 +++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 core/opentaint-java-querylang/src/test/kotlin/org/opentaint/semgrep/MetavarPatternBothReproTest.kt diff --git a/core/opentaint-java-querylang/src/test/kotlin/org/opentaint/semgrep/MetavarPatternBothReproTest.kt b/core/opentaint-java-querylang/src/test/kotlin/org/opentaint/semgrep/MetavarPatternBothReproTest.kt new file mode 100644 index 000000000..c98368ce5 --- /dev/null +++ b/core/opentaint-java-querylang/src/test/kotlin/org/opentaint/semgrep/MetavarPatternBothReproTest.kt @@ -0,0 +1,77 @@ +package org.opentaint.semgrep + +import org.opentaint.semgrep.pattern.SemgrepErrorEntry +import org.opentaint.semgrep.pattern.SemgrepLoadTrace +import org.opentaint.semgrep.pattern.SemgrepRuleLoader +import kotlin.io.path.Path +import kotlin.test.Test +import kotlin.test.assertTrue + +class MetavarPatternBothReproTest { + private fun blockingErrors(ruleText: String): List { + val trace = SemgrepLoadTrace() + val loader = SemgrepRuleLoader() + loader.registerRuleSet(ruleText, Path("repro.yaml"), Path("."), trace) + loader.loadRules() + return buildList { + for (file in trace.fileTraces) { + file.entries.filterIsInstance().forEach { add("${it.severity}/${it.step}: ${it.message}") } + for (rule in file.ruleTraces) { + rule.entries.filterIsInstance().forEach { add("${it.severity}/${it.step}: ${it.message}") } + rule.steps.forEach { s -> s.entries.filterIsInstance().forEach { add("${it.severity}/${it.step}: ${it.message}") } } + } + } + } + } + + @Test + fun `metavariable-pattern on BOTH COND and METHOD`() { + val rule = """ + rules: + - id: repro-both-metavar-pattern + options: + lib: true + severity: NOTE + message: x + languages: [java] + mode: taint + pattern-sinks: + - patterns: + - pattern: | + (org.springframework.ldap.query.LdapQuery ${'$'}Q) = (org.springframework.ldap.query.ConditionCriteria ${'$'}C).${'$'}COND(${'$'}UNTRUSTED); + ...; + (${'$'}CTXTYPE ${'$'}CTX).${'$'}METHOD(${'$'}Q, ...); + - metavariable-pattern: + metavariable: ${'$'}COND + pattern-either: + - pattern: is + - pattern: like + - pattern: whitespaceWildcardsLike + - pattern: gte + - pattern: lte + - metavariable-pattern: + metavariable: ${'$'}CTXTYPE + pattern-either: + - pattern: org.springframework.ldap.core.LdapTemplate + - metavariable-pattern: + metavariable: ${'$'}METHOD + pattern-either: + - pattern: find + - pattern: findOne + - pattern: search + - pattern: searchForContext + - pattern: searchForObject + - pattern: list + - pattern: lookup + - pattern: authenticate + - pattern: findByDn + - pattern: listBindings + - pattern: lookupContext + - pattern: rename + - focus-metavariable: ${'$'}UNTRUSTED + """.trimIndent() + + val errors = blockingErrors(rule) + assertTrue(errors.isEmpty(), "metavariable-pattern on both COND and METHOD still errors:\n" + errors.joinToString("\n")) + } +}