This is an automated email from the ASF dual-hosted git repository.
dominikriemer pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/streampipes.git
The following commit(s) were added to refs/heads/dev by this push:
new faa9e05ed4 refactor: Remove groovy support from adapter script
transformation (#4653)
faa9e05ed4 is described below
commit faa9e05ed44dd5f9c686db5e8f8d34cd825d2fd3
Author: Sven Oehler <[email protected]>
AuthorDate: Tue Jun 30 08:31:54 2026 +0200
refactor: Remove groovy support from adapter script transformation (#4653)
---
pom.xml | 7 -
.../management/management/GuessManagement.java | 2 +-
.../transformer/api/TransformationEngines.java | 26 ++
streampipes-connect-transformer-groovy/pom.xml | 78 -----
.../transformer/groovy/GroovyScriptContext.java | 25 --
.../transformer/groovy/GroovyScriptEngine.java | 80 ------
.../sandbox/RestrictedGroovyClassLoader.java | 59 ----
.../transformer/groovy/sandbox/SandboxPolicy.java | 187 ------------
.../transformer/groovy/sandbox/ScriptSandbox.java | 51 ----
.../ast/AstChecksCompilationCustomizer.java | 39 ---
.../groovy/sandbox/ast/AstChecksVisitor.java | 109 -------
.../sandbox/ast/SecureCustomizerFactory.java | 59 ----
.../error/SandboxCompilationMessageResolver.java | 112 --------
.../SandboxViolationClassNotFoundException.java | 26 --
.../sandbox/error/SandboxViolationException.java | 26 --
.../transformer/groovy/GroovyScriptEngineTest.java | 318 ---------------------
streampipes-extensions-management/pom.xml | 5 -
.../connect/AdapterWorkerManagement.java | 13 +
.../connect/adapter/ScriptContextResolver.java | 4 -
.../minimal/StreamPipesCoreApplicationMinimal.java | 2 -
streampipes-service-core/pom.xml | 5 -
.../service/core/StreamPipesCoreApplication.java | 2 -
streampipes-service-extensions/pom.xml | 5 -
.../StreamPipesExtensionsServiceBase.java | 2 -
24 files changed, 40 insertions(+), 1202 deletions(-)
diff --git a/pom.xml b/pom.xml
index f5bac2c0bf..c5f8dde27a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -60,7 +60,6 @@
<error-prone.version>2.10.0</error-prone.version>
<google-maps-services.version>2.2.0</google-maps-services.version>
<graalvm.js.version>25.0.2</graalvm.js.version>
- <groovy.version>5.0.3</groovy.version>
<grpc.version>1.80.0</grpc.version>
<guava.version>33.5.0-jre</guava.version>
<hadoop.version>3.4.1</hadoop.version>
@@ -459,11 +458,6 @@
<artifactId>commons-configuration2</artifactId>
<version>${commons-configuration2.version}</version>
</dependency>
- <dependency>
- <groupId>org.apache.groovy</groupId>
- <artifactId>groovy</artifactId>
- <version>${groovy.version}</version>
- </dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>fluent-hc</artifactId>
@@ -934,7 +928,6 @@
<module>streampipes-wrapper-siddhi</module>
<module>streampipes-wrapper-standalone</module>
<module>streampipes-connect-transformer-api</module>
- <module>streampipes-connect-transformer-groovy</module>
<module>streampipes-connect-transformer-js</module>
<module>streampipes-health-monitoring</module>
</modules>
diff --git
a/streampipes-connect-management/src/main/java/org/apache/streampipes/connect/management/management/GuessManagement.java
b/streampipes-connect-management/src/main/java/org/apache/streampipes/connect/management/management/GuessManagement.java
index 1cbde82a00..700ad4e0ac 100644
---
a/streampipes-connect-management/src/main/java/org/apache/streampipes/connect/management/management/GuessManagement.java
+++
b/streampipes-connect-management/src/main/java/org/apache/streampipes/connect/management/management/GuessManagement.java
@@ -131,7 +131,7 @@ public class GuessManagement {
throw new AdapterException("No samples available to transform");
}
- } catch (ScriptCompilationException | ScriptExecutionException e) {
+ } catch (ScriptCompilationException | ScriptExecutionException |
IllegalArgumentException e) {
throw new AdapterException(String.format("Could not execute script:
%s", e.getMessage()));
}
}
diff --git
a/streampipes-connect-transformer-api/src/main/java/org/apache/streampipes/connect/transformer/api/TransformationEngines.java
b/streampipes-connect-transformer-api/src/main/java/org/apache/streampipes/connect/transformer/api/TransformationEngines.java
index 99b2a8863c..01ee009441 100644
---
a/streampipes-connect-transformer-api/src/main/java/org/apache/streampipes/connect/transformer/api/TransformationEngines.java
+++
b/streampipes-connect-transformer-api/src/main/java/org/apache/streampipes/connect/transformer/api/TransformationEngines.java
@@ -24,6 +24,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
+import java.util.stream.Collectors;
public enum TransformationEngines {
@@ -36,9 +37,16 @@ public enum TransformationEngines {
}
public TransformationEngine getTransformationEngine(String language) {
+ validateSupportedLanguage(language);
return transformationEngines.get(language).get();
}
+ public void validateSupportedLanguage(String language) {
+ if (!transformationEngines.containsKey(language)) {
+ throw new IllegalArgumentException(unsupportedLanguageMessage(language));
+ }
+ }
+
public List<ScriptMetadata> getAvailableEngineMetadata() {
return transformationEngines
.values()
@@ -46,4 +54,22 @@ public enum TransformationEngines {
.map(transformationEngineSupplier ->
transformationEngineSupplier.get().metadata())
.toList();
}
+
+ private String unsupportedLanguageMessage(String language) {
+ var requestedLanguage = language == null || language.isBlank()
+ ? "missing"
+ : "'" + language + "'";
+
+ var supportedLanguages = transformationEngines.keySet()
+ .stream()
+ .sorted()
+ .collect(Collectors.joining(", "));
+
+ var message = "Unsupported script transformation language " +
requestedLanguage + ". ";
+ if (supportedLanguages.isBlank()) {
+ return message + "No script transformation languages are available.";
+ }
+
+ return message + "Supported languages: " + supportedLanguages + ".";
+ }
}
diff --git a/streampipes-connect-transformer-groovy/pom.xml
b/streampipes-connect-transformer-groovy/pom.xml
deleted file mode 100644
index e634d028da..0000000000
--- a/streampipes-connect-transformer-groovy/pom.xml
+++ /dev/null
@@ -1,78 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ 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.
- ~
- -->
-
-
-<project xmlns="http://maven.apache.org/POM/4.0.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <parent>
- <groupId>org.apache.streampipes</groupId>
- <artifactId>streampipes-parent</artifactId>
- <version>0.99.0-SNAPSHOT</version>
- </parent>
-
- <artifactId>streampipes-connect-transformer-groovy</artifactId>
-
- <properties>
- <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
- </properties>
-
- <dependencies>
- <dependency>
- <groupId>org.apache.streampipes</groupId>
- <artifactId>streampipes-connect-transformer-api</artifactId>
- <version>0.99.0-SNAPSHOT</version>
- </dependency>
- <dependency>
- <groupId>org.apache.streampipes</groupId>
- <artifactId>streampipes-client-api</artifactId>
- <version>0.99.0-SNAPSHOT</version>
- </dependency>
- <dependency>
- <groupId>org.apache.groovy</groupId>
- <artifactId>groovy</artifactId>
- </dependency>
- <dependency>
- <groupId>org.junit.jupiter</groupId>
- <artifactId>junit-jupiter-api</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.apache.streampipes</groupId>
- <artifactId>streampipes-client</artifactId>
- <version>0.99.0-SNAPSHOT</version>
- <scope>test</scope>
- </dependency>
- </dependencies>
-
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-checkstyle-plugin</artifactId>
- <configuration>
- <propertyExpansion>
-
checkstyle.config.base.path=${project.parent.basedir}/tools/maven
- </propertyExpansion>
- </configuration>
- </plugin>
- </plugins>
- </build>
-</project>
diff --git
a/streampipes-connect-transformer-groovy/src/main/java/org/apache/streampipes/connect/transformer/groovy/GroovyScriptContext.java
b/streampipes-connect-transformer-groovy/src/main/java/org/apache/streampipes/connect/transformer/groovy/GroovyScriptContext.java
deleted file mode 100644
index 4d5f0029e7..0000000000
---
a/streampipes-connect-transformer-groovy/src/main/java/org/apache/streampipes/connect/transformer/groovy/GroovyScriptContext.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * 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.streampipes.connect.transformer.groovy;
-
-import org.apache.streampipes.client.api.IStreamPipesClient;
-import org.apache.streampipes.connect.transformer.api.Context;
-
-public record GroovyScriptContext(IStreamPipesClient client) implements
Context {
-}
diff --git
a/streampipes-connect-transformer-groovy/src/main/java/org/apache/streampipes/connect/transformer/groovy/GroovyScriptEngine.java
b/streampipes-connect-transformer-groovy/src/main/java/org/apache/streampipes/connect/transformer/groovy/GroovyScriptEngine.java
deleted file mode 100644
index 1baf7f59d4..0000000000
---
a/streampipes-connect-transformer-groovy/src/main/java/org/apache/streampipes/connect/transformer/groovy/GroovyScriptEngine.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * 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.streampipes.connect.transformer.groovy;
-
-import org.apache.streampipes.connect.transformer.api.Context;
-import org.apache.streampipes.connect.transformer.api.OutputCollector;
-import org.apache.streampipes.connect.transformer.api.ScriptTransformer;
-import org.apache.streampipes.connect.transformer.api.TransformationEngine;
-import
org.apache.streampipes.connect.transformer.api.exception.ScriptCompilationException;
-import
org.apache.streampipes.connect.transformer.api.exception.ScriptExecutionException;
-import
org.apache.streampipes.connect.transformer.api.utils.TransformationEngineConversionUtils;
-import org.apache.streampipes.connect.transformer.groovy.sandbox.ScriptSandbox;
-import org.apache.streampipes.model.connect.ScriptMetadata;
-
-import groovy.lang.Binding;
-import groovy.lang.GroovyShell;
-import groovy.lang.Script;
-import org.codehaus.groovy.runtime.InvokerHelper;
-
-import java.util.Map;
-
-public class GroovyScriptEngine implements TransformationEngine {
-
- @Override
- public ScriptMetadata metadata() {
- return new ScriptMetadata(
- "groovy",
- "Groovy",
- "out.collect(input)"
- );
- }
-
- @Override
- public ScriptTransformer compile(String code) throws
ScriptCompilationException {
- GroovyShell shell =
ScriptSandbox.createShell(GroovyScriptEngine.class.getClassLoader());
- Script script;
- try {
- script = shell.parse(code);
- } catch (Exception e) {
- throw new
ScriptCompilationException(ScriptSandbox.resolveCompilationErrorMessage(e), e);
- }
-
- Class<? extends Script> scriptClass = script.getClass();
-
- return (input, out, ctx) -> execute(scriptClass, input, out, ctx);
- }
-
- private void execute(Class<? extends Script> scriptClass,
- Map<String, Object> input,
- OutputCollector<Map<String, Object>> out,
- Context ctx)
- throws ScriptExecutionException {
- try {
- Binding binding = new Binding();
- binding.setVariable("input", input);
- binding.setVariable("out",
TransformationEngineConversionUtils.convertingCollector(out,
metadata().language()));
- binding.setVariable("ctx", ctx);
- Script scriptInstance = InvokerHelper.createScript(scriptClass, binding);
- scriptInstance.run();
- } catch (Exception e) {
- throw new ScriptExecutionException("Groovy template execution failed",
e);
- }
- }
-}
diff --git
a/streampipes-connect-transformer-groovy/src/main/java/org/apache/streampipes/connect/transformer/groovy/sandbox/RestrictedGroovyClassLoader.java
b/streampipes-connect-transformer-groovy/src/main/java/org/apache/streampipes/connect/transformer/groovy/sandbox/RestrictedGroovyClassLoader.java
deleted file mode 100644
index adb3e28fca..0000000000
---
a/streampipes-connect-transformer-groovy/src/main/java/org/apache/streampipes/connect/transformer/groovy/sandbox/RestrictedGroovyClassLoader.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * 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.streampipes.connect.transformer.groovy.sandbox;
-
-import
org.apache.streampipes.connect.transformer.groovy.sandbox.error.SandboxViolationClassNotFoundException;
-
-import groovy.lang.GroovyClassLoader;
-import org.codehaus.groovy.control.CompilationFailedException;
-import org.codehaus.groovy.control.CompilerConfiguration;
-
-public final class RestrictedGroovyClassLoader extends GroovyClassLoader {
-
- public RestrictedGroovyClassLoader(ClassLoader parent, CompilerConfiguration
configuration) {
- super(parent, configuration);
- }
-
- @Override
- public Class<?> loadClass(String name) throws ClassNotFoundException {
- rejectForbiddenClass(name);
- return super.loadClass(name);
- }
-
- @Override
- protected Class<?> loadClass(String name, boolean resolve)
- throws ClassNotFoundException, CompilationFailedException {
- rejectForbiddenClass(name);
- return super.loadClass(name, resolve);
- }
-
- @Override
- public Class loadClass(String name, boolean lookupScriptFiles, boolean
preferClassOverScript, boolean resolve)
- throws ClassNotFoundException, CompilationFailedException {
- rejectForbiddenClass(name);
- return super.loadClass(name, lookupScriptFiles, preferClassOverScript,
resolve);
- }
-
- private void rejectForbiddenClass(String className) throws
ClassNotFoundException {
- if (SandboxPolicy.blocksType(className)) {
- throw new SandboxViolationClassNotFoundException(
- SandboxPolicy.VIOLATION_MESSAGE + ": access to class '" + className
+ "' is forbidden");
- }
- }
-}
diff --git
a/streampipes-connect-transformer-groovy/src/main/java/org/apache/streampipes/connect/transformer/groovy/sandbox/SandboxPolicy.java
b/streampipes-connect-transformer-groovy/src/main/java/org/apache/streampipes/connect/transformer/groovy/sandbox/SandboxPolicy.java
deleted file mode 100644
index 18b41e3b51..0000000000
---
a/streampipes-connect-transformer-groovy/src/main/java/org/apache/streampipes/connect/transformer/groovy/sandbox/SandboxPolicy.java
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * 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.streampipes.connect.transformer.groovy.sandbox;
-
-import groovy.lang.Binding;
-
-import java.util.List;
-import java.util.Set;
-
-public final class SandboxPolicy {
-
- public static final String VIOLATION_MESSAGE = "Groovy script violates
sandbox restrictions";
-
- private static final List<String> DISALLOWED_IMPORTS = List.of(
- "java.io.File",
- "java.io.FileInputStream",
- "java.io.FileOutputStream",
- "java.io.RandomAccessFile",
- "java.net.InetAddress",
- "java.net.ServerSocket",
- "java.net.Socket",
- "java.net.URI",
- "java.net.URL",
- "java.lang.Class",
- "java.lang.ClassLoader",
- "java.lang.Process",
- "java.lang.ProcessBuilder",
- "java.lang.Runtime",
- "java.lang.System",
- "java.lang.Thread",
- "java.nio.channels.FileChannel",
- "java.nio.file.Files",
- "java.nio.file.Path",
- "java.nio.file.Paths",
- "groovy.lang.GroovyClassLoader",
- "groovy.lang.GroovyShell",
- "groovy.transform.ASTTest",
- "groovy.util.Eval"
- );
- private static final List<String> DISALLOWED_STAR_IMPORTS = List.of(
- "java.io",
- "java.net",
- "java.nio",
- "java.nio.channels",
- "java.nio.file",
- "java.lang.reflect",
- "groovy.io"
- );
- private static final List<String> DISALLOWED_STATIC_IMPORTS = List.of(
- "java.lang.System",
- "java.lang.Runtime",
- "java.nio.file.Files",
- "java.nio.file.Paths"
- );
- private static final Set<String> DISABLED_GLOBAL_AST_TRANSFORMATIONS =
Set.of(
- "groovy.grape.GrabAnnotationTransformation",
- "org.codehaus.groovy.transform.ASTTestTransformation",
- "org.codehaus.groovy.transform.AnnotationCollectorTransform"
- );
- private static final Set<String> DISALLOWED_EXACT_TYPES = Set.of(
- "java.io.File",
- "java.io.FileInputStream",
- "java.io.FileOutputStream",
- "java.io.RandomAccessFile",
- "java.net.InetAddress",
- "java.net.ServerSocket",
- "java.net.Socket",
- "java.net.URI",
- "java.net.URL",
- "java.lang.Class",
- "java.lang.ClassLoader",
- "java.lang.Process",
- "java.lang.ProcessBuilder",
- "java.lang.Runtime",
- "java.lang.System",
- "java.lang.Thread",
- "java.nio.channels.FileChannel",
- "java.nio.file.Files",
- "java.nio.file.Path",
- "java.nio.file.Paths",
- "groovy.lang.GroovyClassLoader",
- "groovy.lang.GroovyShell",
- "groovy.transform.ASTTest",
- "groovy.util.Eval"
- );
- private static final Set<String> DISALLOWED_SIMPLE_TYPES = Set.of(
- "File",
- "FileInputStream",
- "FileOutputStream",
- "RandomAccessFile",
- "InetAddress",
- "ServerSocket",
- "Socket",
- "URI",
- "URL",
- "Class",
- "ClassLoader",
- "Process",
- "ProcessBuilder",
- "Runtime",
- "System",
- "Thread",
- "FileChannel",
- "Files",
- "Path",
- "Paths",
- "GroovyClassLoader",
- "GroovyShell",
- "ASTTest",
- "Eval"
- );
- private static final List<String> DISALLOWED_TYPE_PREFIXES = List.of(
- "java.io.",
- "java.net.",
- "java.nio.",
- "java.nio.channels.",
- "java.nio.file.",
- "java.lang.reflect.",
- "groovy.io."
- );
- private static final Set<String> DISALLOWED_PROPERTY_NAMES = Set.of(
- "class",
- "classLoader",
- "metaClass"
- );
-
- private SandboxPolicy() {
- }
-
- public static Binding createBinding() {
- return new Binding();
- }
-
- public static List<String> disallowedImports() {
- return DISALLOWED_IMPORTS;
- }
-
- public static List<String> disallowedStarImports() {
- return DISALLOWED_STAR_IMPORTS;
- }
-
- public static List<String> disallowedStaticImports() {
- return DISALLOWED_STATIC_IMPORTS;
- }
-
- public static Set<String> disabledGlobalAstTransformations() {
- return DISABLED_GLOBAL_AST_TRANSFORMATIONS;
- }
-
- public static Set<String> disallowedPropertyNames() {
- return DISALLOWED_PROPERTY_NAMES;
- }
-
- public static boolean blocksType(String typeName) {
- if (typeName == null || typeName.isBlank()) {
- return false;
- }
-
- if (DISALLOWED_EXACT_TYPES.contains(typeName) ||
DISALLOWED_SIMPLE_TYPES.contains(typeName)) {
- return true;
- }
-
- for (String prefix : DISALLOWED_TYPE_PREFIXES) {
- if (typeName.startsWith(prefix)) {
- return true;
- }
- }
-
- return false;
- }
-}
diff --git
a/streampipes-connect-transformer-groovy/src/main/java/org/apache/streampipes/connect/transformer/groovy/sandbox/ScriptSandbox.java
b/streampipes-connect-transformer-groovy/src/main/java/org/apache/streampipes/connect/transformer/groovy/sandbox/ScriptSandbox.java
deleted file mode 100644
index 2f26ec4365..0000000000
---
a/streampipes-connect-transformer-groovy/src/main/java/org/apache/streampipes/connect/transformer/groovy/sandbox/ScriptSandbox.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * 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.streampipes.connect.transformer.groovy.sandbox;
-
-import
org.apache.streampipes.connect.transformer.groovy.sandbox.ast.AstChecksCompilationCustomizer;
-import
org.apache.streampipes.connect.transformer.groovy.sandbox.ast.SecureCustomizerFactory;
-import
org.apache.streampipes.connect.transformer.groovy.sandbox.error.SandboxCompilationMessageResolver;
-
-import groovy.lang.GroovyShell;
-import org.codehaus.groovy.control.CompilerConfiguration;
-
-public final class ScriptSandbox {
-
- private ScriptSandbox() {
- }
-
- public static GroovyShell createShell(ClassLoader parent) {
- CompilerConfiguration configuration = new CompilerConfiguration();
-
configuration.setDisabledGlobalASTTransformations(SandboxPolicy.disabledGlobalAstTransformations());
- configuration.addCompilationCustomizers(
- SecureCustomizerFactory.create(),
- new AstChecksCompilationCustomizer()
- );
-
- return new GroovyShell(
- new RestrictedGroovyClassLoader(parent, configuration),
- SandboxPolicy.createBinding(),
- configuration
- );
- }
-
- public static String resolveCompilationErrorMessage(Exception error) {
- return SandboxCompilationMessageResolver.resolve(error);
- }
-}
diff --git
a/streampipes-connect-transformer-groovy/src/main/java/org/apache/streampipes/connect/transformer/groovy/sandbox/ast/AstChecksCompilationCustomizer.java
b/streampipes-connect-transformer-groovy/src/main/java/org/apache/streampipes/connect/transformer/groovy/sandbox/ast/AstChecksCompilationCustomizer.java
deleted file mode 100644
index 05a6a7751d..0000000000
---
a/streampipes-connect-transformer-groovy/src/main/java/org/apache/streampipes/connect/transformer/groovy/sandbox/ast/AstChecksCompilationCustomizer.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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.streampipes.connect.transformer.groovy.sandbox.ast;
-
-import org.codehaus.groovy.ast.ClassNode;
-import org.codehaus.groovy.classgen.GeneratorContext;
-import org.codehaus.groovy.control.CompilationFailedException;
-import org.codehaus.groovy.control.CompilePhase;
-import org.codehaus.groovy.control.SourceUnit;
-import org.codehaus.groovy.control.customizers.CompilationCustomizer;
-
-public final class AstChecksCompilationCustomizer extends
CompilationCustomizer {
-
- public AstChecksCompilationCustomizer() {
- super(CompilePhase.SEMANTIC_ANALYSIS);
- }
-
- @Override
- public void call(SourceUnit source, GeneratorContext context, ClassNode
classNode)
- throws CompilationFailedException {
- new AstChecksVisitor(source).visitClass(classNode);
- }
-}
diff --git
a/streampipes-connect-transformer-groovy/src/main/java/org/apache/streampipes/connect/transformer/groovy/sandbox/ast/AstChecksVisitor.java
b/streampipes-connect-transformer-groovy/src/main/java/org/apache/streampipes/connect/transformer/groovy/sandbox/ast/AstChecksVisitor.java
deleted file mode 100644
index 7fd75a2465..0000000000
---
a/streampipes-connect-transformer-groovy/src/main/java/org/apache/streampipes/connect/transformer/groovy/sandbox/ast/AstChecksVisitor.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * 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.streampipes.connect.transformer.groovy.sandbox.ast;
-
-import org.apache.streampipes.connect.transformer.groovy.sandbox.SandboxPolicy;
-import
org.apache.streampipes.connect.transformer.groovy.sandbox.error.SandboxViolationException;
-
-import org.codehaus.groovy.ast.ClassCodeVisitorSupport;
-import org.codehaus.groovy.ast.ClassNode;
-import org.codehaus.groovy.ast.expr.ClassExpression;
-import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
-import org.codehaus.groovy.ast.expr.Expression;
-import org.codehaus.groovy.ast.expr.MethodCallExpression;
-import org.codehaus.groovy.ast.expr.PropertyExpression;
-import org.codehaus.groovy.ast.expr.StaticMethodCallExpression;
-import org.codehaus.groovy.ast.expr.VariableExpression;
-import org.codehaus.groovy.control.SourceUnit;
-
-public final class AstChecksVisitor extends ClassCodeVisitorSupport {
-
- private final SourceUnit sourceUnit;
-
- public AstChecksVisitor(SourceUnit sourceUnit) {
- this.sourceUnit = sourceUnit;
- }
-
- @Override
- protected SourceUnit getSourceUnit() {
- return sourceUnit;
- }
-
- @Override
- public void visitConstructorCallExpression(ConstructorCallExpression call) {
- rejectForbiddenType(call.getType(), "constructor access");
- super.visitConstructorCallExpression(call);
- }
-
- @Override
- public void visitClassExpression(ClassExpression expression) {
- rejectForbiddenType(expression.getType(), "class access");
- super.visitClassExpression(expression);
- }
-
- @Override
- public void visitMethodCallExpression(MethodCallExpression call) {
- rejectForbiddenExpression(call.getObjectExpression(), "method access");
- super.visitMethodCallExpression(call);
- }
-
- @Override
- public void visitStaticMethodCallExpression(StaticMethodCallExpression call)
{
- rejectForbiddenType(call.getOwnerType(), "static method access");
- super.visitStaticMethodCallExpression(call);
- }
-
- @Override
- public void visitPropertyExpression(PropertyExpression expression) {
- String propertyName = expression.getPropertyAsString();
- if (propertyName != null &&
SandboxPolicy.disallowedPropertyNames().contains(propertyName)) {
- throw new SandboxViolationException(
- SandboxPolicy.VIOLATION_MESSAGE + ": access to property '" +
propertyName + "' is forbidden");
- }
-
- rejectForbiddenExpression(expression.getObjectExpression(), "property
access");
- super.visitPropertyExpression(expression);
- }
-
- private void rejectForbiddenExpression(Expression expression, String
operation) {
- if (expression instanceof ClassExpression classExpression) {
- rejectForbiddenType(classExpression.getType(), operation);
- } else if (expression instanceof VariableExpression variableExpression) {
- if (SandboxPolicy.blocksType(variableExpression.getName())) {
- throw new SandboxViolationException(
- SandboxPolicy.VIOLATION_MESSAGE + ": access to class '" +
variableExpression.getName() + "' is forbidden");
- }
- } else {
- rejectForbiddenType(expression.getType(), operation);
- }
- }
-
- private void rejectForbiddenType(ClassNode classNode, String operation) {
- if (classNode != null) {
- rejectForbiddenType(classNode.getName(), operation);
- }
- }
-
- private void rejectForbiddenType(String typeName, String operation) {
- if (SandboxPolicy.blocksType(typeName)) {
- throw new SandboxViolationException(
- SandboxPolicy.VIOLATION_MESSAGE + ": " + operation + " to '" +
typeName + "' is forbidden");
- }
- }
-}
diff --git
a/streampipes-connect-transformer-groovy/src/main/java/org/apache/streampipes/connect/transformer/groovy/sandbox/ast/SecureCustomizerFactory.java
b/streampipes-connect-transformer-groovy/src/main/java/org/apache/streampipes/connect/transformer/groovy/sandbox/ast/SecureCustomizerFactory.java
deleted file mode 100644
index 4447a0ac02..0000000000
---
a/streampipes-connect-transformer-groovy/src/main/java/org/apache/streampipes/connect/transformer/groovy/sandbox/ast/SecureCustomizerFactory.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * 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.streampipes.connect.transformer.groovy.sandbox.ast;
-
-import org.apache.streampipes.connect.transformer.groovy.sandbox.SandboxPolicy;
-
-import org.codehaus.groovy.control.customizers.SecureASTCustomizer;
-
-import java.util.List;
-
-public final class SecureCustomizerFactory {
-
- private SecureCustomizerFactory() {
- }
-
- public static SecureASTCustomizer create() {
- SecureASTCustomizer customizer = new SecureASTCustomizer();
- customizer.setClosuresAllowed(true);
- customizer.setMethodDefinitionAllowed(false);
- customizer.setPackageAllowed(false);
- customizer.setIndirectImportCheckEnabled(true);
- customizer.setDisallowedImports(SandboxPolicy.disallowedImports());
- customizer.setDisallowedStarImports(SandboxPolicy.disallowedStarImports());
-
customizer.setDisallowedStaticImports(SandboxPolicy.disallowedStaticImports());
-
customizer.setDisallowedStaticStarImports(SandboxPolicy.disallowedStaticImports());
- customizer.setDisallowedReceiversClasses(List.of(
- java.io.File.class,
- java.lang.Class.class,
- java.lang.ClassLoader.class,
- java.lang.Process.class,
- java.lang.ProcessBuilder.class,
- java.lang.Runtime.class,
- java.lang.System.class,
- java.lang.Thread.class,
- java.net.InetAddress.class,
- java.net.ServerSocket.class,
- java.net.Socket.class,
- java.net.URI.class,
- java.net.URL.class
- ));
- return customizer;
- }
-}
diff --git
a/streampipes-connect-transformer-groovy/src/main/java/org/apache/streampipes/connect/transformer/groovy/sandbox/error/SandboxCompilationMessageResolver.java
b/streampipes-connect-transformer-groovy/src/main/java/org/apache/streampipes/connect/transformer/groovy/sandbox/error/SandboxCompilationMessageResolver.java
deleted file mode 100644
index 75de065cef..0000000000
---
a/streampipes-connect-transformer-groovy/src/main/java/org/apache/streampipes/connect/transformer/groovy/sandbox/error/SandboxCompilationMessageResolver.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * 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.streampipes.connect.transformer.groovy.sandbox.error;
-
-import org.apache.streampipes.connect.transformer.groovy.sandbox.SandboxPolicy;
-
-import java.util.Optional;
-
-public final class SandboxCompilationMessageResolver {
-
- private SandboxCompilationMessageResolver() {
- }
-
- public static String resolve(Exception error) {
- Optional<SandboxViolationException> sandboxViolation =
findSandboxViolation(error);
- if (sandboxViolation.isPresent()) {
- return sandboxViolation.get().getMessage();
- }
-
- return extractViolationMessage(error.getMessage())
- .or(() -> extractAllowedError(error.getMessage()))
- .orElse("Failed to compile Groovy template");
- }
-
- private static Optional<SandboxViolationException>
findSandboxViolation(Throwable error) {
- Throwable current = error;
- while (current != null) {
- if (current instanceof SandboxViolationException sandboxViolation) {
- return Optional.of(sandboxViolation);
- } else if (current instanceof SandboxViolationClassNotFoundException
sandboxViolation) {
- return Optional.of(new
SandboxViolationException(sandboxViolation.getMessage()));
- } else if (current instanceof SecurityException securityException) {
- return toSandboxViolation(securityException.getMessage());
- }
- current = current.getCause();
- }
-
- return Optional.empty();
- }
-
- private static Optional<SandboxViolationException> toSandboxViolation(String
message) {
- if (message == null || message.isBlank()) {
- return Optional.empty();
- }
-
- if (message.contains(SandboxPolicy.VIOLATION_MESSAGE)) {
- return Optional.of(new SandboxViolationException(message));
- }
-
- if (message.contains("is not allowed")) {
- return Optional.of(new
SandboxViolationException(SandboxPolicy.VIOLATION_MESSAGE + ": " + message));
- }
-
- return Optional.empty();
- }
-
- private static Optional<String> extractViolationMessage(String message) {
- if (message == null) {
- return Optional.empty();
- }
-
- int messageIndex = message.indexOf(SandboxPolicy.VIOLATION_MESSAGE);
- if (messageIndex < 0) {
- return Optional.empty();
- }
-
- int lineBreakIndex = message.indexOf('\n', messageIndex);
- if (lineBreakIndex < 0) {
- return Optional.of(message.substring(messageIndex).trim());
- }
-
- return Optional.of(message.substring(messageIndex, lineBreakIndex).trim());
- }
-
- private static Optional<String> extractAllowedError(String message) {
- if (message == null) {
- return Optional.empty();
- }
-
- int messageIndex = message.indexOf("is not allowed");
- if (messageIndex < 0) {
- return Optional.empty();
- }
-
- int lineStartIndex = message.lastIndexOf('\n', messageIndex);
- int start = lineStartIndex < 0 ? 0 : lineStartIndex + 1;
- int lineBreakIndex = message.indexOf('\n', messageIndex);
- String extracted = (lineBreakIndex < 0 ? message.substring(start) :
message.substring(start, lineBreakIndex)).trim();
-
- if (extracted.isEmpty()) {
- return Optional.empty();
- }
-
- return Optional.of(SandboxPolicy.VIOLATION_MESSAGE + ": " + extracted);
- }
-}
diff --git
a/streampipes-connect-transformer-groovy/src/main/java/org/apache/streampipes/connect/transformer/groovy/sandbox/error/SandboxViolationClassNotFoundException.java
b/streampipes-connect-transformer-groovy/src/main/java/org/apache/streampipes/connect/transformer/groovy/sandbox/error/SandboxViolationClassNotFoundException.java
deleted file mode 100644
index af7cab2a3f..0000000000
---
a/streampipes-connect-transformer-groovy/src/main/java/org/apache/streampipes/connect/transformer/groovy/sandbox/error/SandboxViolationClassNotFoundException.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * 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.streampipes.connect.transformer.groovy.sandbox.error;
-
-public final class SandboxViolationClassNotFoundException extends
ClassNotFoundException {
-
- public SandboxViolationClassNotFoundException(String message) {
- super(message);
- }
-}
diff --git
a/streampipes-connect-transformer-groovy/src/main/java/org/apache/streampipes/connect/transformer/groovy/sandbox/error/SandboxViolationException.java
b/streampipes-connect-transformer-groovy/src/main/java/org/apache/streampipes/connect/transformer/groovy/sandbox/error/SandboxViolationException.java
deleted file mode 100644
index 765e1a901e..0000000000
---
a/streampipes-connect-transformer-groovy/src/main/java/org/apache/streampipes/connect/transformer/groovy/sandbox/error/SandboxViolationException.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * 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.streampipes.connect.transformer.groovy.sandbox.error;
-
-public final class SandboxViolationException extends SecurityException {
-
- public SandboxViolationException(String message) {
- super(message);
- }
-}
diff --git
a/streampipes-connect-transformer-groovy/src/test/java/org/apache/streampipes/connect/transformer/groovy/GroovyScriptEngineTest.java
b/streampipes-connect-transformer-groovy/src/test/java/org/apache/streampipes/connect/transformer/groovy/GroovyScriptEngineTest.java
deleted file mode 100644
index fa321b24c7..0000000000
---
a/streampipes-connect-transformer-groovy/src/test/java/org/apache/streampipes/connect/transformer/groovy/GroovyScriptEngineTest.java
+++ /dev/null
@@ -1,318 +0,0 @@
-/*
- * 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.streampipes.connect.transformer.groovy;
-
-import org.apache.streampipes.client.StreamPipesClient;
-import org.apache.streampipes.client.api.IAdapterApi;
-import org.apache.streampipes.client.api.IStreamPipesClient;
-import org.apache.streampipes.client.api.credentials.CredentialsProvider;
-import org.apache.streampipes.connect.transformer.api.Context;
-import
org.apache.streampipes.connect.transformer.api.exception.ScriptCompilationException;
-import
org.apache.streampipes.connect.transformer.api.exception.ScriptExecutionException;
-import org.apache.streampipes.model.connect.adapter.AdapterDescription;
-
-import org.junit.jupiter.api.Test;
-
-import java.lang.reflect.Proxy;
-import java.util.ArrayList;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertInstanceOf;
-import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
-public class GroovyScriptEngineTest {
-
- private final GroovyScriptEngine engine = new GroovyScriptEngine();
-
- @Test
- void compileAndExecuteSimplePassThroughScript() throws
ScriptCompilationException, ScriptExecutionException {
- var transformer = engine.compile("out.collect(input)");
- var output = new ArrayList<Map<String, Object>>();
-
- transformer.transform(
- new LinkedHashMap<>(Map.of("sensor", "machine-1", "value", 42)),
- output::add,
- null
- );
-
- assertEquals(1, output.size());
- assertEquals("machine-1", output.get(0).get("sensor"));
- assertEquals(42, output.get(0).get("value"));
- }
-
- @Test
- void compileAndExecuteFieldReshapingScript() throws
ScriptCompilationException, ScriptExecutionException {
- var transformer = engine.compile("""
- out.collect([
- reading: [
- sensor: input.sensor,
- value: input.value + 1
- ],
- tags: [input.tag, "processed"]
- ])
- """);
-
- var output = new ArrayList<Map<String, Object>>();
- transformer.transform(
- new LinkedHashMap<>(Map.of("sensor", "machine-2", "value", 9, "tag",
"lab")),
- output::add,
- null
- );
-
- assertEquals(1, output.size());
- assertEquals(Map.of("sensor", "machine-2", "value", 10),
output.get(0).get("reading"));
- assertEquals(java.util.List.of("lab", "processed"),
output.get(0).get("tags"));
- }
-
- @Test
- void executeProvidesOfflineClientThroughContext() throws
ScriptCompilationException, ScriptExecutionException {
- var transformer = engine.compile("""
- out.collect([
- hasClient: ctx.client() != null
- ])
- """);
-
- var output = new ArrayList<Map<String, Object>>();
- transformer.transform(
- Map.of("value", 1),
- output::add,
- new GroovyScriptContext(offlineClient())
- );
-
- assertEquals(1, output.size());
- assertEquals(true, output.get(0).get("hasClient"));
- }
-
- @Test
- void executeProvidesContextClientCompatibility() throws
ScriptCompilationException, ScriptExecutionException {
- var transformer = engine.compile("""
- out.collect([
- ping: ctx.client().ping()
- ])
- """);
-
- var output = new ArrayList<Map<String, Object>>();
- transformer.transform(
- Map.of("value", 1),
- output::add,
- new ScriptContext(new ScriptClient())
- );
-
- assertEquals(1, output.size());
- assertEquals("pong", output.get(0).get("ping"));
- }
-
- @Test
- void executeCanReadClientResultsInsideVm() throws
ScriptCompilationException, ScriptExecutionException {
- var transformer = engine.compile("""
- def adapters = ctx.client().adapters().all()
- out.collect([
- adapterId: adapters[0].elementId,
- adapterName: adapters[0].name
- ])
- """);
-
- var output = executeSingleEvent(
- transformer,
- Map.of("input", "value"),
- new GroovyScriptContext(scriptClientWithAdapters("adapter-groovy",
"Groovy Adapter"))
- );
-
- assertEquals("adapter-groovy", output.get("adapterId"));
- assertEquals("Groovy Adapter", output.get("adapterName"));
- }
-
- @Test
- void executeCanSendGuestObjectToClient() throws ScriptCompilationException,
ScriptExecutionException {
- var createdAdapters = new ArrayList<AdapterDescription>();
- var transformer = engine.compile("""
- def adapter = new
org.apache.streampipes.model.connect.adapter.AdapterDescription()
- adapter.elementId = "created-groovy"
- adapter.name = "Created From Groovy"
- adapter.running = false
- ctx.client().adapters().create(adapter)
- out.collect([created: adapter.elementId])
- """);
-
- var output = executeSingleEvent(
- transformer,
- Map.of("input", "value"),
- new
GroovyScriptContext(scriptClientWithCreateRecorder(createdAdapters))
- );
-
- assertEquals("created-groovy", output.get("created"));
- assertEquals(1, createdAdapters.size());
- assertEquals("created-groovy", createdAdapters.get(0).getElementId());
- assertEquals("Created From Groovy", createdAdapters.get(0).getName());
- assertFalse(createdAdapters.get(0).isRunning());
- }
-
- @Test
- void compileRejectsFileAccess() {
- assertSandboxViolation("new File('/tmp/blocked').text");
- }
-
- @Test
- void compileRejectsNioFileAccess() {
- assertSandboxViolation("Files.readString(Paths.get('/tmp/blocked'))");
- }
-
- @Test
- void compileRejectsEnvironmentAccess() {
- assertSandboxViolation("System.getenv('HOME')");
- }
-
- @Test
- void compileRejectsSystemExit() {
- assertSandboxViolation("System.exit(0)");
- }
-
- @Test
- void compileRejectsProcessExecution() {
- assertSandboxViolation("Runtime.getRuntime().exec('id')");
- }
-
- @Test
- void compileRejectsNetworkAccess() {
- assertSandboxViolation("new Socket('localhost', 80)");
- }
-
- @Test
- void compileRejectsExplicitDangerousImports() {
- assertSandboxViolation("""
- import java.lang.reflect.Method
- out.collect(input)
- """);
- }
-
- @Test
- void executeWrapsGroovyRuntimeErrors() throws ScriptCompilationException {
- var transformer = engine.compile("throw new
IllegalStateException('boom')");
-
- var exception = assertThrows(
- ScriptExecutionException.class,
- () -> transformer.transform(Map.of("value", 1), event -> {
- }, null)
- );
-
- assertEquals("Groovy template execution failed", exception.getMessage());
- assertInstanceOf(Exception.class, exception.getCause());
- }
-
- private void assertSandboxViolation(String script) {
- var exception = assertThrows(
- ScriptCompilationException.class,
- () -> engine.compile(script)
- );
-
- assertTrue(exception.getMessage().contains("sandbox restrictions"));
- }
-
- private static Map<String, Object> executeSingleEvent(
- org.apache.streampipes.connect.transformer.api.ScriptTransformer
transformer,
- Map<String, Object> input,
- Context context
- ) throws ScriptExecutionException {
- var output = new ArrayList<Map<String, Object>>();
- transformer.transform(new LinkedHashMap<>(input), output::add, context);
- return output.get(0);
- }
-
- private static CredentialsProvider emptyCredentials() {
- return List::of;
- }
-
- private static StreamPipesClient offlineClient() {
- return StreamPipesClient.create("localhost", 1, emptyCredentials(), true);
- }
-
- private static IStreamPipesClient scriptClientWithAdapters(String elementId,
String name) {
- var adapter = new AdapterDescription();
- adapter.setElementId(elementId);
- adapter.setName(name);
- return scriptClient(adapterApi(List.of(adapter), null));
- }
-
- private static IStreamPipesClient
scriptClientWithCreateRecorder(List<AdapterDescription> createdAdapters) {
- return scriptClient(adapterApi(List.of(), createdAdapters));
- }
-
- private static IStreamPipesClient scriptClient(IAdapterApi adapterApi) {
- return (IStreamPipesClient) Proxy.newProxyInstance(
- GroovyScriptEngineTest.class.getClassLoader(),
- new Class<?>[]{IStreamPipesClient.class},
- (proxy, method, args) -> switch (method.getName()) {
- case "adapters" -> adapterApi;
- case "getCredentials" -> emptyCredentials();
- case "getConfig", "getConnectionConfig" -> null;
- case "toString" -> "ScriptClientProxy";
- case "hashCode" -> System.identityHashCode(proxy);
- case "equals" -> proxy == args[0];
- default -> throw new UnsupportedOperationException("Unsupported
client method: " + method.getName());
- }
- );
- }
-
- private static IAdapterApi adapterApi(List<AdapterDescription> adapters,
List<AdapterDescription> createdAdapters) {
- return (IAdapterApi) Proxy.newProxyInstance(
- GroovyScriptEngineTest.class.getClassLoader(),
- new Class<?>[]{IAdapterApi.class},
- (proxy, method, args) -> switch (method.getName()) {
- case "all" -> adapters;
- case "create" -> {
- if (createdAdapters != null) {
- createdAdapters.add(new AdapterDescription((AdapterDescription)
args[0]));
- }
- yield null;
- }
- case "get" -> java.util.Optional.empty();
- case "delete", "update" -> null;
- case "toString" -> "AdapterApiProxy";
- case "hashCode" -> System.identityHashCode(proxy);
- case "equals" -> proxy == args[0];
- default -> throw new UnsupportedOperationException("Unsupported
adapter method: " + method.getName());
- }
- );
- }
-
- private static final class ScriptContext implements Context {
-
- private final ScriptClient client;
-
- private ScriptContext(ScriptClient client) {
- this.client = client;
- }
-
- public ScriptClient client() {
- return client;
- }
- }
-
- private static final class ScriptClient {
-
- public String ping() {
- return "pong";
- }
- }
-}
diff --git a/streampipes-extensions-management/pom.xml
b/streampipes-extensions-management/pom.xml
index 685223d0f0..5227780aa5 100644
--- a/streampipes-extensions-management/pom.xml
+++ b/streampipes-extensions-management/pom.xml
@@ -89,11 +89,6 @@
<artifactId>streampipes-vocabulary</artifactId>
<version>0.99.0-SNAPSHOT</version>
</dependency>
- <dependency>
- <groupId>org.apache.streampipes</groupId>
- <artifactId>streampipes-connect-transformer-groovy</artifactId>
- <version>0.99.0-SNAPSHOT</version>
- </dependency>
<!-- External dependencies -->
diff --git
a/streampipes-extensions-management/src/main/java/org/apache/streampipes/extensions/management/connect/AdapterWorkerManagement.java
b/streampipes-extensions-management/src/main/java/org/apache/streampipes/extensions/management/connect/AdapterWorkerManagement.java
index 4df5066ff1..ea0df9a89d 100644
---
a/streampipes-extensions-management/src/main/java/org/apache/streampipes/extensions/management/connect/AdapterWorkerManagement.java
+++
b/streampipes-extensions-management/src/main/java/org/apache/streampipes/extensions/management/connect/AdapterWorkerManagement.java
@@ -19,6 +19,7 @@
package org.apache.streampipes.extensions.management.connect;
import org.apache.streampipes.commons.exceptions.connect.AdapterException;
+import org.apache.streampipes.connect.transformer.api.TransformationEngines;
import org.apache.streampipes.extensions.api.connect.StreamPipesAdapter;
import
org.apache.streampipes.extensions.api.connect.context.IAdapterRuntimeContext;
import org.apache.streampipes.extensions.api.monitoring.SpMonitoringManager;
@@ -63,6 +64,7 @@ public class AdapterWorkerManagement {
if (adapter.isPresent()) {
var newAdapterInstance =
adapter.get().declareConfig().getSupplier().get();
+ validateScriptLanguage(adapterDescription);
runningAdapterInstances.addAdapter(
adapterDescription.getElementId(),
newAdapterInstance,
@@ -115,6 +117,17 @@ public class AdapterWorkerManagement {
return new AdapterContextGenerator().makeRuntimeContext(adapterInstanceId);
}
+ private void validateScriptLanguage(AdapterDescription adapterDescription)
throws AdapterException {
+ var transformationConfig = adapterDescription.getTransformationConfig();
+ if (transformationConfig != null && transformationConfig.isScriptActive())
{
+ try {
+
TransformationEngines.INSTANCE.validateSupportedLanguage(transformationConfig.getLanguage());
+ } catch (IllegalArgumentException e) {
+ throw new AdapterException(e.getMessage(), e);
+ }
+ }
+ }
+
private void resetMonitoring(String elementId) {
SpMonitoringManager.INSTANCE.reset(elementId);
}
diff --git
a/streampipes-extensions-management/src/main/java/org/apache/streampipes/extensions/management/connect/adapter/ScriptContextResolver.java
b/streampipes-extensions-management/src/main/java/org/apache/streampipes/extensions/management/connect/adapter/ScriptContextResolver.java
index a61f311a96..338fe6aeec 100644
---
a/streampipes-extensions-management/src/main/java/org/apache/streampipes/extensions/management/connect/adapter/ScriptContextResolver.java
+++
b/streampipes-extensions-management/src/main/java/org/apache/streampipes/extensions/management/connect/adapter/ScriptContextResolver.java
@@ -20,7 +20,6 @@ package
org.apache.streampipes.extensions.management.connect.adapter;
import org.apache.streampipes.client.api.IStreamPipesClient;
import org.apache.streampipes.connect.transformer.api.Context;
-import org.apache.streampipes.connect.transformer.groovy.GroovyScriptContext;
import org.apache.streampipes.connect.transformer.js.GraalJsScriptContext;
import
org.apache.streampipes.extensions.management.client.StreamPipesClientResolver;
@@ -40,9 +39,6 @@ public class ScriptContextResolver {
case "javascript" -> {
return new GraalJsScriptContext(client);
}
- case "groovy" -> {
- return new GroovyScriptContext(client);
- }
default -> throw new UnsupportedOperationException("Unsupported
language: " + language);
}
}
diff --git
a/streampipes-service-core-minimal/src/main/java/org/apache/streampipes/service/core/minimal/StreamPipesCoreApplicationMinimal.java
b/streampipes-service-core-minimal/src/main/java/org/apache/streampipes/service/core/minimal/StreamPipesCoreApplicationMinimal.java
index 467be87746..fa44840899 100644
---
a/streampipes-service-core-minimal/src/main/java/org/apache/streampipes/service/core/minimal/StreamPipesCoreApplicationMinimal.java
+++
b/streampipes-service-core-minimal/src/main/java/org/apache/streampipes/service/core/minimal/StreamPipesCoreApplicationMinimal.java
@@ -18,7 +18,6 @@
package org.apache.streampipes.service.core.minimal;
-import org.apache.streampipes.connect.transformer.groovy.GroovyScriptEngine;
import org.apache.streampipes.connect.transformer.js.GraalJsScriptEngine;
import org.apache.streampipes.messaging.mqtt.SpMqttProtocolFactory;
import org.apache.streampipes.messaging.nats.SpNatsProtocolFactory;
@@ -59,7 +58,6 @@ public class StreamPipesCoreApplicationMinimal extends
StreamPipesCoreApplicatio
new SpMqttProtocolFactory()
),
List.of(
- () -> new GroovyScriptEngine(),
() -> new GraalJsScriptEngine()
));
}
diff --git a/streampipes-service-core/pom.xml b/streampipes-service-core/pom.xml
index 62a2a2f4aa..0dec99dba5 100644
--- a/streampipes-service-core/pom.xml
+++ b/streampipes-service-core/pom.xml
@@ -52,11 +52,6 @@
<artifactId>streampipes-service-base</artifactId>
<version>0.99.0-SNAPSHOT</version>
</dependency>
- <dependency>
- <groupId>org.apache.streampipes</groupId>
- <artifactId>streampipes-connect-transformer-groovy</artifactId>
- <version>0.99.0-SNAPSHOT</version>
- </dependency>
<dependency>
<groupId>org.apache.streampipes</groupId>
<artifactId>streampipes-connect-transformer-js</artifactId>
diff --git
a/streampipes-service-core/src/main/java/org/apache/streampipes/service/core/StreamPipesCoreApplication.java
b/streampipes-service-core/src/main/java/org/apache/streampipes/service/core/StreamPipesCoreApplication.java
index c563d1f2b3..ab3570a0ea 100644
---
a/streampipes-service-core/src/main/java/org/apache/streampipes/service/core/StreamPipesCoreApplication.java
+++
b/streampipes-service-core/src/main/java/org/apache/streampipes/service/core/StreamPipesCoreApplication.java
@@ -23,7 +23,6 @@ import
org.apache.streampipes.connect.management.management.AdapterMasterManagem
import org.apache.streampipes.connect.management.management.WorkerRestClient;
import org.apache.streampipes.connect.transformer.api.TransformationEngine;
import org.apache.streampipes.connect.transformer.api.TransformationEngines;
-import org.apache.streampipes.connect.transformer.groovy.GroovyScriptEngine;
import org.apache.streampipes.connect.transformer.js.GraalJsScriptEngine;
import org.apache.streampipes.health.monitoring.ExtensionHealthCheck;
import org.apache.streampipes.health.monitoring.ResourceProvider;
@@ -129,7 +128,6 @@ public class StreamPipesCoreApplication extends
StreamPipesServiceBase {
new SpMqttProtocolFactory(),
new SpPulsarProtocolFactory()),
List.of(
- GroovyScriptEngine::new,
GraalJsScriptEngine::new
)
);
diff --git a/streampipes-service-extensions/pom.xml
b/streampipes-service-extensions/pom.xml
index 4d07bc7c9c..982d017749 100644
--- a/streampipes-service-extensions/pom.xml
+++ b/streampipes-service-extensions/pom.xml
@@ -39,11 +39,6 @@
<artifactId>streampipes-connect-transformer-api</artifactId>
<version>0.99.0-SNAPSHOT</version>
</dependency>
- <dependency>
- <groupId>org.apache.streampipes</groupId>
- <artifactId>streampipes-connect-transformer-groovy</artifactId>
- <version>0.99.0-SNAPSHOT</version>
- </dependency>
<dependency>
<groupId>org.apache.streampipes</groupId>
<artifactId>streampipes-connect-transformer-js</artifactId>
diff --git
a/streampipes-service-extensions/src/main/java/org/apache/streampipes/service/extensions/StreamPipesExtensionsServiceBase.java
b/streampipes-service-extensions/src/main/java/org/apache/streampipes/service/extensions/StreamPipesExtensionsServiceBase.java
index dc4681a204..e09c2871e7 100644
---
a/streampipes-service-extensions/src/main/java/org/apache/streampipes/service/extensions/StreamPipesExtensionsServiceBase.java
+++
b/streampipes-service-extensions/src/main/java/org/apache/streampipes/service/extensions/StreamPipesExtensionsServiceBase.java
@@ -22,7 +22,6 @@ import org.apache.streampipes.client.StreamPipesClient;
import org.apache.streampipes.commons.environment.Environments;
import org.apache.streampipes.connect.transformer.api.TransformationEngine;
import org.apache.streampipes.connect.transformer.api.TransformationEngines;
-import org.apache.streampipes.connect.transformer.groovy.GroovyScriptEngine;
import org.apache.streampipes.connect.transformer.js.GraalJsScriptEngine;
import org.apache.streampipes.extensions.api.limiter.SpRateLimiter;
import org.apache.streampipes.extensions.api.migration.IModelMigrator;
@@ -98,7 +97,6 @@ public abstract class StreamPipesExtensionsServiceBase
extends StreamPipesServic
SpRateLimiter.INSTANCE.createRateLimiter();
registerTransformationEngines(List.of(
- GroovyScriptEngine::new,
GraalJsScriptEngine::new
));