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

raboof 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 f93583e80 orientdb: validate class name (#1821)
f93583e80 is described below

commit f93583e80e42949b5a63f4206fb26187ecd81b41
Author: PJ Fanning <[email protected]>
AuthorDate: Wed Aug 5 11:02:55 2026 +0100

    orientdb: validate class name (#1821)
---
 .../orientdb/impl/OrientDbSourceStage.scala        | 15 +++++
 .../orientdb/impl/OrientDbSourceStageSpec.scala    | 77 ++++++++++++++++++++++
 2 files changed, 92 insertions(+)

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 db7b85eec..c3b54ef4a 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
@@ -30,6 +30,19 @@ import scala.jdk.OptionConverters._
 /**
  * INTERNAL API
  */
+@InternalApi
+private[orientdb] object OrientDbSourceStage {
+  // Valid OrientDB class names: letters, digits, underscores; must start with 
letter or underscore
+  private val ValidClassName = "^[a-zA-Z_][a-zA-Z0-9_]*$".r
+
+  private[orientdb] def validateClassName(name: String): Unit = {
+    require(name != null && name.nonEmpty, "className must not be null or 
empty")
+    require(
+      ValidClassName.matches(name),
+      s"className contains invalid characters: '$name'. Only letters, digits, 
and underscores are allowed.")
+  }
+}
+
 @InternalApi
 private[orientdb] final class OrientDbSourceStage[T](className: String,
     query: Option[String],
@@ -37,6 +50,8 @@ private[orientdb] final class 
OrientDbSourceStage[T](className: String,
     clazz: Option[Class[T]] = None)
     extends GraphStage[SourceShape[OrientDbReadResult[T]]] {
 
+  OrientDbSourceStage.validateClassName(className)
+
   val out: Outlet[OrientDbReadResult[T]] = Outlet("OrientDBSource.out")
   override val shape = SourceShape(out)
   override def initialAttributes: Attributes =
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
new file mode 100644
index 000000000..0ef5c4993
--- /dev/null
+++ 
b/orientdb/src/test/scala/org/apache/pekko/stream/connectors/orientdb/impl/OrientDbSourceStageSpec.scala
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.pekko.stream.connectors.orientdb.impl
+
+import org.scalatest.matchers.should.Matchers
+import org.scalatest.wordspec.AnyWordSpec
+
+class OrientDbSourceStageSpec extends AnyWordSpec with Matchers {
+
+  "OrientDbSourceStage.validateClassName" should {
+
+    "accept valid class names" in {
+      OrientDbSourceStage.validateClassName("User")
+      OrientDbSourceStage.validateClassName("MyClass")
+      OrientDbSourceStage.validateClassName("_internal")
+      OrientDbSourceStage.validateClassName("Class123")
+      OrientDbSourceStage.validateClassName("my_class")
+    }
+
+    "reject null class name" in {
+      assertThrows[IllegalArgumentException] {
+        OrientDbSourceStage.validateClassName(null)
+      }
+    }
+
+    "reject empty class name" in {
+      assertThrows[IllegalArgumentException] {
+        OrientDbSourceStage.validateClassName("")
+      }
+    }
+
+    "reject class name with SQL injection attempt" in {
+      assertThrows[IllegalArgumentException] {
+        OrientDbSourceStage.validateClassName("User; DROP TABLE users; --")
+      }
+    }
+
+    "reject class name with quotes" in {
+      assertThrows[IllegalArgumentException] {
+        OrientDbSourceStage.validateClassName("User\" OR 1=1 --")
+      }
+    }
+
+    "reject class name starting with digit" in {
+      assertThrows[IllegalArgumentException] {
+        OrientDbSourceStage.validateClassName("123Class")
+      }
+    }
+
+    "reject class name with spaces" in {
+      assertThrows[IllegalArgumentException] {
+        OrientDbSourceStage.validateClassName("My Class")
+      }
+    }
+
+    "reject class name with special characters" in {
+      assertThrows[IllegalArgumentException] {
+        OrientDbSourceStage.validateClassName("Class@name")
+      }
+    }
+  }
+}


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

Reply via email to