This is an automated email from the ASF dual-hosted git repository.

pjfanning pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/pekko-connectors.git


The following commit(s) were added to refs/heads/main by this push:
     new dd540083a OrientDB: only validate className when it is used in a query 
(#1874)
dd540083a is described below

commit dd540083a1cff84fd2289d032d10ad416d999f8f
Author: PJ Fanning <[email protected]>
AuthorDate: Thu Oct 1 07:38:59 2026 +0100

    OrientDB: only validate className when it is used in a query (#1874)
    
    Motivation:
    OrientDbSourceStage validates className in its constructor
    unconditionally, including when an explicit query is supplied. In that
    case className is never used: createLogic ignores it in both query
    branches, and the SELECT that interpolates it is only built when query is
    empty.
    
    Both DSLs require className as a positional argument, so a caller reading
    purely by query must pass a syntactically valid dummy class name to get
    past a check that guards a string their query never reaches.
    
    Modification:
    Validate only when query is empty, which is exactly when className is
    interpolated into "SELECT * FROM $className".
    
    Result:
    Query-only reads no longer need a placeholder class name. The injection
    guard is unchanged wherever className actually reaches SQL.
    
    Tests:
    Extended OrientDbSourceStageSpec with stage-level tests: an invalid class
    name is still rejected with no query, a valid one is accepted, and a
    class name that is empty, null, or malformed is accepted when a query is
    given. Verified the query-mode test fails without this change. 11 tests
    pass. Ran orientdb/mimaReportBinaryIssues (clean) and the module scalafmt
    checks.
    
    References:
    Follow-up to #1821.
---
 .../orientdb/impl/OrientDbSourceStage.scala        |  5 ++-
 .../orientdb/impl/OrientDbSourceStageSpec.scala    | 36 ++++++++++++++++++++++
 2 files changed, 40 insertions(+), 1 deletion(-)

diff --git 
a/orientdb/src/main/scala/org/apache/pekko/stream/connectors/orientdb/impl/OrientDbSourceStage.scala
 
b/orientdb/src/main/scala/org/apache/pekko/stream/connectors/orientdb/impl/OrientDbSourceStage.scala
index c3b54ef4a..5271429ef 100644
--- 
a/orientdb/src/main/scala/org/apache/pekko/stream/connectors/orientdb/impl/OrientDbSourceStage.scala
+++ 
b/orientdb/src/main/scala/org/apache/pekko/stream/connectors/orientdb/impl/OrientDbSourceStage.scala
@@ -50,7 +50,10 @@ private[orientdb] final class 
OrientDbSourceStage[T](className: String,
     clazz: Option[Class[T]] = None)
     extends GraphStage[SourceShape[OrientDbReadResult[T]]] {
 
-  OrientDbSourceStage.validateClassName(className)
+  // `className` is interpolated into the SELECT below, so it has to be 
validated.
+  // When an explicit `query` is given the class name is never used, and 
callers
+  // are not required to supply a meaningful one.
+  if (query.isEmpty) OrientDbSourceStage.validateClassName(className)
 
   val out: Outlet[OrientDbReadResult[T]] = Outlet("OrientDBSource.out")
   override val shape = SourceShape(out)
diff --git 
a/orientdb/src/test/scala/org/apache/pekko/stream/connectors/orientdb/impl/OrientDbSourceStageSpec.scala
 
b/orientdb/src/test/scala/org/apache/pekko/stream/connectors/orientdb/impl/OrientDbSourceStageSpec.scala
index 0ef5c4993..7095f5b02 100644
--- 
a/orientdb/src/test/scala/org/apache/pekko/stream/connectors/orientdb/impl/OrientDbSourceStageSpec.scala
+++ 
b/orientdb/src/test/scala/org/apache/pekko/stream/connectors/orientdb/impl/OrientDbSourceStageSpec.scala
@@ -17,6 +17,8 @@
 
 package org.apache.pekko.stream.connectors.orientdb.impl
 
+import com.orientechnologies.orient.core.db.ODatabasePool
+import org.apache.pekko.stream.connectors.orientdb.OrientDbSourceSettings
 import org.scalatest.matchers.should.Matchers
 import org.scalatest.wordspec.AnyWordSpec
 
@@ -74,4 +76,38 @@ class OrientDbSourceStageSpec extends AnyWordSpec with 
Matchers {
       }
     }
   }
+
+  "OrientDbSourceStage" should {
+
+    // the pool is never used: construction fails (or not) before the stage 
runs
+    def settings: OrientDbSourceSettings =
+      OrientDbSourceSettings(null.asInstanceOf[ODatabasePool])
+
+    "reject an invalid class name when no query is given" in {
+      // the class name is interpolated into "SELECT * FROM $className"
+      assertThrows[IllegalArgumentException] {
+        new OrientDbSourceStage[Nothing]("User; DROP TABLE users; --", None, 
settings)
+      }
+    }
+
+    "accept a valid class name when no query is given" in {
+      noException should be thrownBy {
+        new OrientDbSourceStage[Nothing]("User", None, settings)
+      }
+    }
+
+    "not validate the class name when an explicit query is given" in {
+      // the class name is unused in query mode, so callers are not required
+      // to supply a meaningful one
+      noException should be thrownBy {
+        new OrientDbSourceStage[Nothing]("", Some("SELECT * FROM User"), 
settings)
+      }
+      noException should be thrownBy {
+        new OrientDbSourceStage[Nothing](null, Some("SELECT * FROM User"), 
settings)
+      }
+      noException should be thrownBy {
+        new OrientDbSourceStage[Nothing]("not a valid name", Some("SELECT * 
FROM User"), settings)
+      }
+    }
+  }
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to