Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(engine): add WasmRuntimeExecutor for attributes #636

Merged
merged 9 commits into from
Nov 24, 2024

Conversation

soma00333
Copy link
Contributor

@soma00333 soma00333 commented Nov 16, 2024

Overview

Add a processor called WasmRuntimeExecutor which compiles user's python scripts to .wasm and executes on wasm runtime.
The scope is to handle processor_type: attribute and programmig_language: python.
related issue: #573

What I've done

Add crates

  • wasmer
  • wasmer-wasix

Add a integration test

Compiles a python script and executes on wasmer to modify the attributes.

Fix workflow of GitHub Actions

Add python 3.11 x py2wasm dependencies for the integration test

Add a WasmRuntimeExecutor

  • type
    • processor
  • parameter
    • processorType
    • programmingLanguage
    • sourceCodeFilePath
    • wasmFilePath
  • categories
    • Wasm

Add a sample workflow

Compiles a python script and executes on wasmer to modify the attributes.

Other

  • Fix dockerfile for worker and clie to support py2wasm
  • Update readme of engine
  • Update schema for actions

What I haven't done

  • Handling other processor_type
  • Handling other programming_language
  • Unit test

How I tested

$cargo run --package reearth-flow-cli -- run --workflow ./runtime/examples/plateau/testdata/workflow/wasm_runtime_executor.yml
2024-11-16T07:39:13.217Z  INFO root{otel.name="WasmRuntimeExecutorExample" otel.kind="runner" workflow.id="00caad2a-9f7d-4189-b479-153fa9ea36dc" job.id="8481ec72-6d9b-4b61-8d3e-22a05336b514"}: reearth_flow_runner::runner: Start workflow = "WasmRuntimeExecutorExample"
2024-11-16T07:39:28.525Z  INFO action{otel.name="EchoSink" otel.kind="Sink Node" workflow.id="3e3450c8-2344-4728-afa9-5fdb81eec33a" node.id="756f498a-7a5c-4579-ab1c-fcbba8121869"}: reearth_flow_runner::log_event_handler: "\"EchoSink\" sink start..."
2024-11-16T07:39:28.525Z  INFO action{otel.name="WasmRuntimeExecutor" otel.kind="Processor Node" workflow.id="3e3450c8-2344-4728-afa9-5fdb81eec33a" node.id="f3f168f4-1d7b-41e5-b6a2-0fca96ed10d6"}: reearth_flow_runner::log_event_handler: "\"WasmRuntimeExecutor\" process start..."
2024-11-16T07:39:28.526Z  INFO action{otel.name="Source Node" otel.kind="Source Node" workflow.id="3e3450c8-2344-4728-afa9-5fdb81eec33a"}: reearth_flow_runner::log_event_handler: "\"FeatureCreator\" finish source complete. elapsed = 1.129917ms"
2024-11-16T07:40:15.686Z  INFO action{otel.name="WasmRuntimeExecutor" otel.kind="Processor Node" workflow.id="3e3450c8-2344-4728-afa9-5fdb81eec33a" node.id="f3f168f4-1d7b-41e5-b6a2-0fca96ed10d6"}: reearth_flow_runner::log_event_handler: "Slow action, processor node name = \"WasmRuntimeExecutor\", node_id = f3f168f4-1d7b-41e5-b6a2-0fca96ed10d6, feature id = de0955d3-706e-4a43-af3d-b57b573889cd, elapsed = 47.159899084s"
2024-11-16T07:40:15.686Z  INFO action: reearth_flow_runner::log_event_handler: "echo with feature = \"{\\\"id\\\":\\\"de0955d3-706e-4a43-af3d-b57b573889cd\\\",\\\"attributes\\\":{\\\"attribute2\\\":\\\"test02_modified\\\",\\\"attribute1\\\":\\\"test01_modified\\\"},\\\"geometry\\\":null}\""
2024-11-16T07:40:15.689Z  INFO action{otel.name="WasmRuntimeExecutor" otel.kind="Processor Node" workflow.id="3e3450c8-2344-4728-afa9-5fdb81eec33a" node.id="f3f168f4-1d7b-41e5-b6a2-0fca96ed10d6"}: reearth_flow_runner::log_event_handler: "\"WasmRuntimeExecutor\" process finish. elapsed = 47.16367175s"
2024-11-16T07:40:15.689Z  INFO action{otel.name="WasmRuntimeExecutor" otel.kind="Processor Node" workflow.id="3e3450c8-2344-4728-afa9-5fdb81eec33a" node.id="f3f168f4-1d7b-41e5-b6a2-0fca96ed10d6"}: reearth_flow_runner::log_event_handler: "\"WasmRuntimeExecutor\" finish process complete. elapsed = 7.166µs"
2024-11-16T07:40:15.690Z  INFO action{otel.name="EchoSink" otel.kind="Sink Node" workflow.id="3e3450c8-2344-4728-afa9-5fdb81eec33a" node.id="756f498a-7a5c-4579-ab1c-fcbba8121869"}: reearth_flow_runner::log_event_handler: "\"EchoSink\" sink finish. elapsed = 47.165271625s"
2024-11-16T07:40:16.896Z  INFO reearth_flow_runtime::event: All handlers shut down successfully
2024-11-16T07:40:16.896Z  INFO root{otel.name="WasmRuntimeExecutorExample" otel.kind="runner" workflow.id="00caad2a-9f7d-4189-b479-153fa9ea36dc" job.id="8481ec72-6d9b-4b61-8d3e-22a05336b514"}: reearth_flow_runner::runner: Finish workflow = "WasmRuntimeExecutorExample", duration = 63.679068833s

Screenshot

Which point I want you to review particularly

Memo

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced the WasmRuntimeExecutor, enabling the compilation and execution of WebAssembly scripts.
    • Added Python 3.11 support along with the py2wasm package for enhanced functionality.
    • New YAML configurations for workflows integrating feature creation and Wasm processing.
    • Added new modules for error handling and mapping within the Wasm processor.
  • Bug Fixes

    • Updated expected output for attribute processing tests to reflect new functionality.
  • Documentation

    • New example and test configurations for the Wasm runtime executor.
  • Tests

    • Added tests for the new Wasm runtime executor functionality.
    • Introduced new test functions and modules to validate the Wasm execution process.

Copy link
Contributor

coderabbitai bot commented Nov 16, 2024

Walkthrough

The pull request introduces significant modifications to the CI workflow and various components of the codebase to integrate Python support. Key changes include the addition of Python 3.11 and the py2wasm package in the CI environment, updates to the Rust project's Cargo.toml files to include new dependencies, and the introduction of new modules and functionality related to WebAssembly execution. Additionally, new YAML configurations and test cases have been added to facilitate and validate the new features.

Changes

File Change Summary
.github/workflows/ci_engine.yml Added steps to install Python 3.11 and py2wasm.
engine/Cargo.toml Added dependencies: wasmer = "5.0.1" and wasmer-wasix = "0.31.0".
engine/containers/cli/Dockerfile Updated package installation to include Python 3.11 and py2wasm.
engine/containers/worker/Dockerfile Updated package installation to include Python 3.11 and py2wasm.
engine/runtime/action-processor/Cargo.toml Added dependencies: wasmer.workspace = true, wasmer-wasix.workspace = true, and tempfile.workspace = true.
engine/runtime/action-processor/src/lib.rs Added module declaration: pub(crate) mod wasm;.
engine/runtime/action-processor/src/mapping.rs Integrated wasm module into ACTION_FACTORY_MAPPINGS.
engine/runtime/action-processor/src/wasm.rs Added modules: pub(crate) mod errors;, pub(crate) mod mapping;, pub(crate) mod runtime_executor;.
engine/runtime/action-processor/src/wasm/errors.rs Defined WasmProcessorError enum and a type alias for standardized results.
engine/runtime/action-processor/src/wasm/mapping.rs Introduced ACTION_FACTORY_MAPPINGS static variable.
engine/runtime/action-processor/src/wasm/runtime_executor.rs Introduced WasmRuntimeExecutorFactory and WasmRuntimeExecutor components with relevant methods.
engine/runtime/examples/plateau/testdata/workflow/wasm_runtime_executor.yml New YAML configuration for Wasm Runtime Executor workflow.
engine/runtime/tests/fixture/testdata/wasm/runtime_executor/attribute_python/expect.json Added expected JSON attributes for testing.
engine/runtime/tests/fixture/testdata/wasm/runtime_executor/attribute_python/sample.py New Python script for processing attributes.
engine/runtime/tests/fixture/workflow/wasm/runtime_executor/attribute_python.yaml New YAML workflow configuration for Wasm Runtime Executor.
engine/runtime/tests/testcase.rs Added wasm module.
engine/runtime/tests/testcase/wasm.rs Added runtime_executor module.
engine/runtime/tests/testcase/wasm/runtime_executor.rs Introduced test_attribute_python function for testing.
engine/schema/actions.json Added new processor: WasmRuntimeExecutor with parameter schema.

Possibly related PRs

🐇 In the garden where code does bloom,
Python hops in, dispelling the gloom.
With Wasm's might and attributes bright,
We craft new paths, a wondrous sight.
So let’s leap forth, with joy and cheer,
For every change brings us near! 🌼


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@soma00333 soma00333 self-assigned this Nov 16, 2024
Copy link

netlify bot commented Nov 16, 2024

Deploy Preview for reearth-flow canceled.

Name Link
🔨 Latest commit ebb119b
🔍 Latest deploy log https://app.netlify.com/sites/reearth-flow/deploys/67417256f3578f00088b404c

@github-actions github-actions bot added the cicd label Nov 22, 2024
@soma00333 soma00333 changed the title feat(engine): add WasmRuntimeExecutor for attributes feat(engine): add WasmRuntimeExecutor for attributes Nov 22, 2024
Comment on lines +2664 to +2669
"ProcessorType": {
"type": "string",
"enum": [
"Attribute"
]
},
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Support only Attribute in this scope.

Comment on lines +2670 to +2676
"ProgrammingLanguage": {
"type": "string",
"enum": [
"Python"
]
}
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Support only Python in this scope.

Comment on lines 82 to 111
fn compile_to_wasm(&self, params: &WasmRuntimeExecutorParam) -> super::errors::Result<()> {
match params.programming_language {
ProgrammingLanguage::Python => {
let py2wasm_output = std::process::Command::new("py2wasm")
.args([&params.source_code_file_path, "-o", &params.wasm_file_path])
.output()
.map_err(|e| {
WasmProcessorError::RuntimeExecutorFactory(format!(
"Failed to run py2wasm: {}. Command: py2wasm {} -o {}",
e, params.source_code_file_path, params.wasm_file_path
))
})?;

if !py2wasm_output.status.success() {
let error_msg = String::from_utf8_lossy(&py2wasm_output.stderr);
return Err(WasmProcessorError::RuntimeExecutorFactory(format!(
"Python compilation failed: {}",
error_msg
)));
}
}
_ => {
return Err(WasmProcessorError::RuntimeExecutorFactory(
"Unsupported programming language".to_string(),
));
}
}

Ok(())
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Compile python scripts to .wasm with py2wasm on python 3.11

Comment on lines 167 to 181
fn process_attribute(
&self,
ctx: ExecutorContext,
fw: &mut dyn ProcessorChannelForwarder,
) -> super::errors::Result<()> {
let mut feature = ctx.feature.clone();

let json_input = self.serialize_attributes(&feature.attributes)?;
let output = self.execute_wasm_module(&json_input)?;
let updated_attributes = self.parse_wasm_output(&output)?;

feature.attributes = updated_attributes;
fw.send(ctx.new_with_feature_and_port(feature.clone(), DEFAULT_PORT.clone()));
Ok(())
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Process logic for processor_type: attribute

Comment on lines +183 to +193
fn serialize_attributes(
&self,
attributes: &HashMap<Attribute, AttributeValue>,
) -> super::errors::Result<String> {
serde_json::to_string(attributes).map_err(|e| {
WasmProcessorError::RuntimeExecutor(format!(
"Failed to serialize Feature to JSON: {}",
e
))
})
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Serialize attributes to json

Comment on lines 195 to 225
fn execute_wasm_module(&self, input: &str) -> super::errors::Result<String> {
let wasm_bytes = std::fs::read(&self.params.wasm_file_path).map_err(|e| {
WasmProcessorError::RuntimeExecutor(format!(
"Failed to read Wasm file '{}': {}",
&self.params.wasm_file_path, e
))
})?;

let mut store = Store::default();
let module = Module::new(&store, wasm_bytes).map_err(|e| {
WasmProcessorError::RuntimeExecutor(format!("Failed to compile module: {}", e))
})?;

let (stdout_tx, mut stdout_rx) = Pipe::channel();
WasiEnv::builder("")
.args(&[input])
.stdout(Box::new(stdout_tx))
.run_with_store(module, &mut store)
.map_err(|e| {
WasmProcessorError::RuntimeExecutor(format!("Failed to execute module: {}", e))
})?;

let mut output = String::new();
stdout_rx.read_to_string(&mut output).map_err(|e| {
WasmProcessorError::RuntimeExecutor(format!(
"Failed to read stdout from Wasm module: {}",
e
))
})?;
Ok(output)
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Execute .wasm with wasmer and wasmer_wasix

Comment on lines 227 to 276
fn parse_wasm_output(
&self,
output: &str,
) -> super::errors::Result<HashMap<Attribute, AttributeValue>> {
const STATUS_SUCCESS: &str = "success";
const STATUS_ERROR: &str = "error";
const FIELD_ATTRIBUTES: &str = "attributes";
const FIELD_ERROR: &str = "error";
const FIELD_STATUS: &str = "status";

let parsed_output: serde_json::Value = serde_json::from_str(output).map_err(|e| {
WasmProcessorError::RuntimeExecutor(format!(
"Failed to parse Wasm module output as JSON: {}",
e
))
})?;

match parsed_output.get(FIELD_STATUS) {
Some(serde_json::Value::String(status)) if status == STATUS_SUCCESS => {
if let Some(attributes_value) = parsed_output.get(FIELD_ATTRIBUTES) {
serde_json::from_value(attributes_value.clone()).map_err(|e| {
WasmProcessorError::RuntimeExecutor(format!(
"Failed to deserialize '{}': {}",
FIELD_ATTRIBUTES, e
))
})
} else {
Err(WasmProcessorError::RuntimeExecutor(format!(
"Missing '{}' in Wasm module output",
FIELD_ATTRIBUTES
))
.into())
}
}
Some(serde_json::Value::String(status)) if status == STATUS_ERROR => {
let error_msg = match parsed_output.get(FIELD_ERROR) {
Some(serde_json::Value::String(err)) => {
format!("Wasm module execution failed with error: {}", err)
}
_ => "Wasm module execution failed with an unknown error.".to_string(),
};
Err(WasmProcessorError::RuntimeExecutor(error_msg).into())
}
_ => Err(WasmProcessorError::RuntimeExecutor(format!(
"Unexpected '{}' in Wasm module output",
FIELD_STATUS
))
.into()),
}
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Handle errors of output and deserialize to attributes

Comment on lines +1 to +48
# yaml-language-server: $schema=https://raw.githubusercontent.com/reearth/reearth-flow/main/engine/schema/workflow.json
id: 00caad2a-9f7d-4189-b479-153fa9ea36dc
name: "WasmRuntimeExecutorExample"
entryGraphId: 3e3450c8-2344-4728-afa9-5fdb81eec33a
graphs:
- id: 3e3450c8-2344-4728-afa9-5fdb81eec33a
name: entry_point
nodes:
- id: 90f40a3e-61d3-48e2-a328-e7226c2ad1ae
name: FeatureCreator
type: action
action: FeatureCreator
with:
creator: |
[
#{
attribute1: "test01",
attribute2: "test02"
}
]

- id: F3F168F4-1D7B-41E5-B6A2-0FCA96ED10D6
name: WasmRuntimeExecutor
type: action
action: WasmRuntimeExecutor
with:
processorType: "Attribute"
programmingLanguage: "Python"
sourceCodeFilePath: "runtime/tests/fixture/testdata/wasm/runtime_executor/attribute_python/sample.py"
wasmFilePath: "runtime/tests/fixture/testdata/wasm/runtime_executor/attribute_python/sample.wasm"

- id: 756F498A-7A5C-4579-AB1C-FCBBA8121869
name: EchoSink
type: action
action: EchoSink

edges:
- id: c064cf52-705f-443a-b2de-6795266c540d
from: 90f40a3e-61d3-48e2-a328-e7226c2ad1ae
to: F3F168F4-1D7B-41E5-B6A2-0FCA96ED10D6
fromPort: default
toPort: default

- id: 7A963683-4E97-4B75-9BDC-BE6B3953003B
from: F3F168F4-1D7B-41E5-B6A2-0FCA96ED10D6
to: 756F498A-7A5C-4579-AB1C-FCBBA8121869
fromPort: default
toPort: default
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sample workflow

Comment on lines +5 to +12
def process_attributes(attributes):
updated_attributes = {}
for key, value in attributes.items():
if isinstance(value, dict) and "String" in value:
updated_attributes[key] = {"String": value["String"] + "_modified"}
else:
updated_attributes[key] = value
return updated_attributes
Copy link
Contributor Author

Choose a reason for hiding this comment

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

"XXX" to "XXX_modified"

Comment on lines +15 to +26
def main():
try:
input_data = sys.argv[1]
parsed_data = json.loads(input_data)

updated_attributes = process_attributes(parsed_data)

output = {"status": "success", "attributes": updated_attributes, "error": None}
except Exception as e:
output = {"status": "error", "attributes": None, "error": str(e)}

print(json.dumps(output), file=sys.stdout)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Expects output of {"status":XXX, "attributes":YYY, "error":ZZZ}

@soma00333 soma00333 marked this pull request as ready for review November 22, 2024 12:29
@soma00333 soma00333 requested a review from miseyu November 22, 2024 12:29
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 9

🧹 Outside diff range and nitpick comments (12)
engine/runtime/action-processor/src/wasm/runtime_executor.rs (1)

187-192: Correct the error message in serialize_attributes method

In the serialize_attributes method, the error message incorrectly states "Failed to serialize Feature to JSON," whereas it is actually serializing attributes. Consider updating the error message to accurately reflect the data being serialized:

- WasmProcessorError::RuntimeExecutor(format!(
-     "Failed to serialize Feature to JSON: {}",
+ WasmProcessorError::RuntimeExecutor(format!(
+     "Failed to serialize attributes to JSON: {}",
      e
 ))
engine/runtime/tests/testcase/wasm/runtime_executor.rs (1)

1-6: Consider using test constants for paths

The hardcoded paths could be moved to constants at the module level for better maintainability.

const TEST_DATA_DIR: &str = "wasm/runtime_executor/attribute_python";
const EXPECT_FILE: &str = "expect.json";

#[test]
fn test_attribute_python() {
    execute_with_test_assert(TEST_DATA_DIR, EXPECT_FILE);
}
engine/runtime/action-processor/src/wasm/errors.rs (1)

5-10: Consider enhancing error handling with more specific error types.

The current implementation uses String for error details, which could be improved:

  1. Consider using more specific error types instead of String to provide better error handling:
  2. The error messages could be more detailed to help with debugging.

Here's a suggested improvement:

 #[derive(Error, Debug)]
 pub(super) enum WasmProcessorError {
-    #[error("Wasm Runtime Executor Factory error: {0}")]
-    RuntimeExecutorFactory(String),
-    #[error("Wasm Runtime Executor error: {0}")]
-    RuntimeExecutor(String),
+    #[error("Failed to create Wasm Runtime Executor: {kind}")]
+    RuntimeExecutorFactory {
+        kind: RuntimeExecutorFactoryErrorKind,
+        #[source]
+        source: Option<Box<dyn std::error::Error + Send + Sync>>,
+    },
+    #[error("Error during Wasm execution: {kind}")]
+    RuntimeExecutor {
+        kind: RuntimeExecutorErrorKind,
+        #[source]
+        source: Option<Box<dyn std::error::Error + Send + Sync>>,
+    },
 }

+#[derive(Debug)]
+pub(super) enum RuntimeExecutorFactoryErrorKind {
+    #[error("Invalid configuration: {0}")]
+    InvalidConfig(String),
+    #[error("Failed to initialize runtime: {0}")]
+    InitializationError(String),
+}
+
+#[derive(Debug)]
+pub(super) enum RuntimeExecutorErrorKind {
+    #[error("Memory allocation failed: {0}")]
+    MemoryError(String),
+    #[error("Execution failed: {0}")]
+    ExecutionError(String),
+}
engine/runtime/action-processor/Cargo.toml (1)

50-51: Consider documenting WebAssembly security guidelines.

Since this introduces WebAssembly execution capabilities, consider adding documentation about:

  • Secure configuration of the Wasmer runtime
  • Allowed WASI capabilities and their security implications
  • Best practices for sandboxing WebAssembly modules

Would you like me to help draft security guidelines for the WebAssembly integration?

engine/runtime/examples/plateau/testdata/workflow/wasm_runtime_executor.yml (2)

1-1: Consider pinning the schema reference to a specific version

Using the main branch for schema validation could lead to unexpected behavior if the schema changes. Consider pinning to a specific version or commit hash for better stability.

-# yaml-language-server: $schema=https://raw.githubusercontent.com/reearth/reearth-flow/main/engine/schema/workflow.json
+# yaml-language-server: $schema=https://raw.githubusercontent.com/reearth/reearth-flow/v1.0.0/engine/schema/workflow.json

1-48: Consider enhancing workflow resilience

As this workflow serves as an example for WASM execution, consider:

  1. Adding error handling paths for WASM execution failures
  2. Including timeout configurations for the execution
  3. Adding validation steps before and after WASM execution
  4. Documenting memory/resource requirements for WASM execution
engine/containers/cli/Dockerfile (1)

52-59: Consider security implications of Python installation.

Adding Python and pip to the final image increases the attack surface. Consider:

  1. Creating a separate Python build stage for py2wasm compilation
  2. Copying only the necessary wasm files to the final stage

Would you like assistance in restructuring the Dockerfile to use multi-stage builds for Python dependencies?

engine/containers/worker/Dockerfile (1)

52-58: Consider multi-stage build for Python compilation.

To optimize the final image size, consider:

  1. Moving the Python/py2wasm environment to a separate build stage
  2. Only copying the compiled .wasm files to the final stage
  3. Using a dedicated Python builder stage for WebAssembly compilation

This would significantly reduce the attack surface and final image size.

Example structure:

# Python builder stage
FROM python:3.11-slim AS wasm-builder
RUN pip install "py2wasm==0.1.0"
COPY scripts /scripts
RUN py2wasm /scripts/*.py -o /wasm/

# Final stage
FROM debian:bookworm-slim
COPY --from=wasm-builder /wasm/*.wasm /wasm/
engine/runtime/tests/fixture/workflow/wasm/runtime_executor/attribute_python.yaml (2)

16-22: Consider parameterizing test attributes

The hardcoded test values limit test coverage. Consider parameterizing these values through workflow parameters to enable testing different scenarios.

 creator: |
   [
     #{
-      attribute1: "test01",
-      attribute2: "test02"
+      attribute1: env.get("test_attribute1", "test01"),
+      attribute2: env.get("test_attribute2", "test02")
     }
   ]

1-54: Consider additional test workflows for edge cases

While this workflow effectively demonstrates the basic functionality, consider adding additional test workflows to cover:

  1. Error handling scenarios (invalid WASM, compilation failures)
  2. Large data processing (performance testing)
  3. Memory constraints and resource usage
  4. Concurrent execution scenarios

This will help ensure the robustness of the WasmRuntimeExecutor implementation.

.github/workflows/ci_engine.yml (1)

53-56: Consider pinning py2wasm version and verifying installation.

While the installation steps are correct, consider these improvements:

  1. Pin the py2wasm version for reproducible builds
  2. Add a verification step to ensure successful installation

Here's a suggested improvement:

  - name: Install py2wasm
    run: |
      python -m pip install --upgrade pip
-     pip install py2wasm
+     pip install py2wasm==1.0.0  # Replace with your desired version
+     # Verify installation
+     python -c "import py2wasm; print(f'py2wasm version: {py2wasm.__version__}')"
engine/schema/actions.json (1)

2673-2726: The WasmRuntimeExecutor processor definition looks good but could be enhanced.

The basic structure and parameter schema are well-defined, matching the PR objectives. However, consider the following improvements:

  1. Add an error output port to handle compilation and execution failures gracefully
  2. Add validation patterns for file paths
  3. Consider adding optional runtime configuration parameters (e.g., memory limits, timeout)

Apply this diff to enhance the processor definition:

     {
       "name": "WasmRuntimeExecutor",
       "type": "processor",
       "description": "Compiles scripts into .wasm and runs at the wasm runtime",
       "parameter": {
         "$schema": "http://json-schema.org/draft-07/schema#",
         "title": "WasmRuntimeExecutorParam",
         "type": "object",
         "required": [
           "processorType",
           "programmingLanguage",
           "sourceCodeFilePath",
           "wasmFilePath"
         ],
         "properties": {
           "processorType": {
             "$ref": "#/definitions/ProcessorType"
           },
           "programmingLanguage": {
             "$ref": "#/definitions/ProgrammingLanguage"
           },
           "sourceCodeFilePath": {
-            "type": "string"
+            "type": "string",
+            "pattern": "^[^<>:;,?\"*|/]+$"
           },
           "wasmFilePath": {
-            "type": "string"
+            "type": "string",
+            "pattern": "^[^<>:;,?\"*|/]+$"
           },
+          "memoryLimit": {
+            "type": ["integer", "null"],
+            "minimum": 1,
+            "maximum": 4096,
+            "description": "Memory limit in MB"
+          },
+          "timeout": {
+            "type": ["integer", "null"],
+            "minimum": 1,
+            "maximum": 300,
+            "description": "Execution timeout in seconds"
+          }
         },
         "definitions": {
           "ProcessorType": {
             "type": "string",
             "enum": [
               "Attribute"
             ]
           },
           "ProgrammingLanguage": {
             "type": "string",
             "enum": [
               "Python"
             ]
           }
         }
       },
       "builtin": true,
       "inputPorts": [
         "default"
       ],
       "outputPorts": [
         "default",
+        "error"
       ],
       "categories": [
         "Wasm"
       ]
     },
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between fcf3755 and 0f0152b.

⛔ Files ignored due to path filters (3)
  • engine/Cargo.lock is excluded by !**/*.lock, !**/*.lock
  • engine/README.md is excluded by !**/*.md
  • engine/docs/mdbook/src/action.md is excluded by !**/*.md
📒 Files selected for processing (19)
  • .github/workflows/ci_engine.yml (1 hunks)
  • engine/Cargo.toml (1 hunks)
  • engine/containers/cli/Dockerfile (1 hunks)
  • engine/containers/worker/Dockerfile (1 hunks)
  • engine/runtime/action-processor/Cargo.toml (1 hunks)
  • engine/runtime/action-processor/src/lib.rs (1 hunks)
  • engine/runtime/action-processor/src/mapping.rs (2 hunks)
  • engine/runtime/action-processor/src/wasm.rs (1 hunks)
  • engine/runtime/action-processor/src/wasm/errors.rs (1 hunks)
  • engine/runtime/action-processor/src/wasm/mapping.rs (1 hunks)
  • engine/runtime/action-processor/src/wasm/runtime_executor.rs (1 hunks)
  • engine/runtime/examples/plateau/testdata/workflow/wasm_runtime_executor.yml (1 hunks)
  • engine/runtime/tests/fixture/testdata/wasm/runtime_executor/attribute_python/expect.json (1 hunks)
  • engine/runtime/tests/fixture/testdata/wasm/runtime_executor/attribute_python/sample.py (1 hunks)
  • engine/runtime/tests/fixture/workflow/wasm/runtime_executor/attribute_python.yaml (1 hunks)
  • engine/runtime/tests/testcase.rs (1 hunks)
  • engine/runtime/tests/testcase/wasm.rs (1 hunks)
  • engine/runtime/tests/testcase/wasm/runtime_executor.rs (1 hunks)
  • engine/schema/actions.json (1 hunks)
✅ Files skipped from review due to trivial changes (5)
  • engine/runtime/action-processor/src/lib.rs
  • engine/runtime/action-processor/src/wasm.rs
  • engine/runtime/tests/fixture/testdata/wasm/runtime_executor/attribute_python/expect.json
  • engine/runtime/tests/testcase.rs
  • engine/runtime/tests/testcase/wasm.rs
🔇 Additional comments (21)
engine/runtime/tests/testcase/wasm/runtime_executor.rs (2)

5-5: Verify the existence of test data files

Let's verify that the test data files exist at the specified paths.

✅ Verification successful

The previous search might have failed due to pattern matching issues. Let's try a broader search to locate the test files and understand the directory structure better.


Test data files exist and are properly structured

The test files for wasm/runtime_executor/attribute_python exist at the correct location:

  • engine/runtime/tests/fixture/testdata/wasm/runtime_executor/attribute_python/sample.py
  • engine/runtime/tests/fixture/testdata/wasm/runtime_executor/attribute_python/expect.json

Both files contain valid and matching content - the Python script modifies attributes by appending "_modified" to string values, and the expect.json contains the expected modified output.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for the existence of test data files
# Expected: Find the test data and expect.json files

# Search for the test data directory and files
fd -t f . -p "*wasm/runtime_executor/attribute_python*"

# Check content of expect.json if it exists
fd -t f expect.json -x cat {}

Length of output: 1878


Script:

#!/bin/bash
# Let's try a different approach to find the test files
# Search for files in the wasm directory
fd -t f . wasm

# Also check for any Python files that might be related
fd -t f . -e py

Length of output: 213


Script:

#!/bin/bash
# Now that we found the Python file, let's check its directory for the expect.json
ls -la engine/runtime/tests/fixture/testdata/wasm/runtime_executor/attribute_python/

# Also check the content of the Python file
cat engine/runtime/tests/fixture/testdata/wasm/runtime_executor/attribute_python/sample.py

Length of output: 1204


Script:

#!/bin/bash
# Let's check the content of expect.json in this directory
cat engine/runtime/tests/fixture/testdata/wasm/runtime_executor/attribute_python/expect.json

Length of output: 179


1-2: Verify the helper function implementation

The test relies on a helper function execute_with_test_assert. Let's verify its implementation to ensure proper test setup and teardown.

✅ Verification successful

Let's gather more information about the helper function implementation and test data.


Based on the gathered information, I can now generate the final response:

Helper function is well-tested and follows established patterns

The execute_with_test_assert helper function is part of a robust test framework that:

  • Properly sets up test environment with temporary directories
  • Handles test fixtures and assertions consistently
  • Is used across multiple test modules (bulk_renamer, runtime_executor, etc.)
  • Follows the same pattern as other integration tests in the codebase

The implementation shows proper error handling and resource cleanup:

pub(crate) fn execute_with_test_assert(test_id: &str, assert_file: &str) {
    let tempdir = execute(test_id, vec![]).unwrap();
    let storage_resolver = Arc::new(StorageResolver::new());
    // ...
}
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Find and analyze the helper function implementation
# Expected: Find the helper function that handles test execution and assertions

# Search for the helper function definition
ast-grep --pattern 'fn execute_with_test_assert($$$)'

# Search for related test utilities
rg -g '*.rs' -A 5 'execute_with_test_assert'

Length of output: 8801


Script:

#!/bin/bash
# Search for the execute function and related test utilities
rg -g '*.rs' -A 10 'fn execute\(' engine/runtime/tests/

# Check if test data exists
fd -g 'expect.json' 'wasm/runtime_executor'

# Look for test fixtures implementation
ast-grep --pattern 'struct Fixtures {
  $$$
}'

# Check for other test cases in the same directory
fd -g '*.rs' . engine/runtime/tests/testcase/wasm/

Length of output: 22491

engine/runtime/action-processor/src/wasm/errors.rs (2)

1-13: LGTM! The error handling structure is well-organized.

The use of thiserror and the separation of concerns between factory and runtime errors is good. The visibility modifiers are appropriate for the module structure.


3-3: Consider removing #[allow(dead_code)] attributes.

These attributes suggest the code is not yet used. If this is work in progress, consider adding a TODO comment explaining when these will be used. If they are already being used, these attributes can be removed.

Also applies to: 12-12

engine/runtime/action-processor/src/wasm/mapping.rs (2)

1-6: LGTM! Clean and appropriate imports.

The imports are well-organized and the use of once_cell::Lazy ensures thread-safe lazy initialization.


8-15: Consider future extensibility of the factory mappings.

While the current implementation with a single WasmRuntimeExecutorFactory is clean, consider these architectural improvements:

  1. Add a method to dynamically register new factories at runtime
  2. Consider using a builder pattern for more flexible initialization
  3. Add support for factory versioning

Let's verify that factory names are unique across the codebase to prevent future naming conflicts:

engine/runtime/tests/fixture/testdata/wasm/runtime_executor/attribute_python/sample.py (3)

1-3: LGTM! Minimal and appropriate imports.

The script uses only standard library imports, which is ideal for WebAssembly compilation.


29-30: LGTM! Proper script entry point.

The implementation follows Python best practices for script execution.


1-30: Verify WebAssembly compilation compatibility.

Please ensure that all Python features used in this script are supported by py2wasm compiler:

  • Standard library imports (sys, json)
  • Dictionary operations
  • String operations
  • Exception handling
  • File I/O (sys.stdout)
✅ Verification successful

Based on the search results, I found that the project does use py2wasm for compiling Python scripts to WebAssembly, and it's documented in the engine/README.md. Let me verify the specific Python features used in the script against the project's codebase to see if there are similar patterns in use.


Let me try one more search to find any WASM-related configuration or test files that might indicate supported features.


Python script is compatible with WebAssembly compilation

The script uses standard Python features that are supported by the project's WebAssembly implementation:

  • The exact same Python script is already being used as a test fixture in the project (engine/runtime/tests/fixture/testdata/wasm/runtime_executor/attribute_python/sample.py)
  • The codebase includes test cases that successfully compile and execute this Python script (engine/runtime/tests/testcase/wasm/runtime_executor.rs)
  • All used features (sys, json, dictionaries, string operations, exception handling, stdout) are working in the existing test environment
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if py2wasm is installed and verify its Python feature support

# Check py2wasm installation
which py2wasm || echo "py2wasm not found"

# Look for documentation about supported features
fd -t f "README|FEATURES|COMPATIBILITY" -e md -e txt | xargs rg -i "python|feature|support" -A 5

Length of output: 4589


Script:

#!/bin/bash
# Search for similar Python patterns in WASM-related test files and implementations
# Look for similar imports and operations in other Python files under wasm directory
fd -t f -e py . engine/runtime/tests/fixture/testdata/wasm | xargs cat

# Search for any WASM-related test files that might show supported features
rg -g "*.rs" "wasm.*test" -A 5 engine/

Length of output: 911


Script:

#!/bin/bash
# Search for WASM-related files and configurations
rg -g "!*.py" -i "python.*wasm|py2wasm" -A 5 engine/

# Look for test files or documentation specifically about Python WASM support
fd -t f . engine/runtime | xargs rg -i "python.*attribute|wasm.*python" -A 5

Length of output: 7392

engine/runtime/action-processor/src/mapping.rs (2)

7-8: LGTM! Clean import addition.

The wasm module import is cleanly integrated with the existing imports, maintaining consistent formatting.


26-26: Verify wasm mapping structure matches other processors.

The wasm mappings are integrated at the root level, but the PR objectives mention this is specifically for attributes. Let's verify the structure matches other processor modules.

✅ Verification successful

The wasm mapping structure matches the pattern used across all processor modules

The wasm mapping follows the same consistent structure as all other processor modules:

  • Uses the same ACTION_FACTORY_MAPPINGS static Lazy HashMap
  • Follows identical initialization pattern with factory vectors
  • Uses the same mapping transformation to create name-to-NodeKind pairs
  • Matches the single-processor pattern seen in the file module, while other modules like attribute, feature, geometry, and xml have multiple processors

The integration is correctly structured and aligns with the established patterns across the codebase.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Compare wasm mapping structure with other processor modules

# Check the wasm mapping structure
echo "Checking wasm mapping structure:"
ast-grep --pattern 'pub static ACTION_FACTORY_MAPPINGS' -f 'engine/runtime/action-processor/src/wasm/mapping.rs' -A 10

# Compare with attribute mapping for consistency
echo "\nComparing with attribute mapping structure:"
ast-grep --pattern 'pub static ACTION_FACTORY_MAPPINGS' -f 'engine/runtime/action-processor/src/attribute/mapping.rs' -A 10

Length of output: 774


Script:

#!/bin/bash
# Let's try a different approach using ripgrep to examine the mapping structures

echo "Checking wasm mapping structure:"
rg -A 10 "ACTION_FACTORY_MAPPINGS" "engine/runtime/action-processor/src/wasm/mapping.rs"

echo -e "\nChecking attribute mapping structure:"
rg -A 10 "ACTION_FACTORY_MAPPINGS" "engine/runtime/action-processor/src/attribute/mapping.rs"

# Also check if there are any other mapping files for comparison
echo -e "\nChecking for other mapping files:"
fd "mapping.rs" "engine/runtime/action-processor/src"

Length of output: 1739


Script:

#!/bin/bash
# Let's check the structure of other mapping files for a complete comparison

echo "Checking feature mapping structure:"
rg -A 10 "ACTION_FACTORY_MAPPINGS" "engine/runtime/action-processor/src/feature/mapping.rs"

echo -e "\nChecking file mapping structure:"
rg -A 10 "ACTION_FACTORY_MAPPINGS" "engine/runtime/action-processor/src/file/mapping.rs"

echo -e "\nChecking geometry mapping structure:"
rg -A 10 "ACTION_FACTORY_MAPPINGS" "engine/runtime/action-processor/src/geometry/mapping.rs"

echo -e "\nChecking xml mapping structure:"
rg -A 10 "ACTION_FACTORY_MAPPINGS" "engine/runtime/action-processor/src/xml/mapping.rs"

Length of output: 2559

engine/runtime/action-processor/Cargo.toml (1)

50-51: Verify workspace-level dependencies and security implications.

The addition of WebAssembly runtime dependencies looks good, but please ensure:

  1. These dependencies are properly declared in the workspace's root Cargo.toml with appropriate version constraints.
  2. The WebAssembly execution is properly sandboxed using Wasmer's security features.

Let's verify the workspace dependencies:

✅ Verification successful

Dependencies are properly configured in the workspace

The wasmer and wasmer-wasix dependencies are correctly defined in the workspace root (engine/Cargo.toml) with specific version constraints:

  • wasmer = "5.0.1"
  • wasmer-wasix = "0.31.0"

This validates that the workspace-level version management is properly set up for the WebAssembly runtime dependencies used in the action processor.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if wasmer dependencies are properly declared in the workspace
# Expected: Find wasmer dependencies in the root Cargo.toml

# Check root Cargo.toml for wasmer dependencies
rg -A 2 'wasmer = .*' ./Cargo.toml
rg -A 2 'wasmer-wasix = .*' ./Cargo.toml

Length of output: 185


Script:

#!/bin/bash
# Let's first locate the workspace root Cargo.toml file
fd -t f "Cargo.toml" -x echo "Found: {}"

# Then check its content for wasmer dependencies
fd -t f "Cargo.toml" -x cat {} | grep -A 2 "wasmer"

Length of output: 1313


Script:

#!/bin/bash
# Let's check the engine/Cargo.toml which is likely the workspace root
cat ./engine/Cargo.toml | grep -A 5 "\[workspace\]"

# Also check for wasmer in workspace dependencies section
cat ./engine/Cargo.toml | grep -A 5 "\[workspace.dependencies\]"

Length of output: 586


Script:

#!/bin/bash
# Let's get the complete content of engine/Cargo.toml to check all workspace dependencies
cat ./engine/Cargo.toml

Length of output: 6091

engine/runtime/examples/plateau/testdata/workflow/wasm_runtime_executor.yml (2)

14-20: Verify the custom syntax for attribute creation

The #{ syntax for attribute definition appears unusual. Please verify that this is the correct syntax supported by the FeatureCreator action.

✅ Verification successful

The #{ syntax is the correct format for FeatureCreator attributes

Based on the search results, the #{ syntax is consistently used across multiple test and example files in the codebase for defining attributes in FeatureCreator actions. This pattern appears in:

  • Test fixtures (engine/runtime/tests/fixture/workflow/...)
  • Example workflows (engine/runtime/examples/plateau/testdata/workflow/...)

The syntax is standardized and matches the implementation under review.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for other examples of FeatureCreator syntax
rg -A 5 "FeatureCreator" --type yaml

Length of output: 22361


37-48: Verify port compatibility between nodes

The workflow uses default ports for all connections. Please verify:

  1. The output format of FeatureCreator matches the input requirements of WasmRuntimeExecutor
  2. The output format of WasmRuntimeExecutor matches the input requirements of EchoSink
✅ Verification successful

Based on the documentation and workflow files, I can now generate the final response:

Port compatibility is verified and correct

The workflow connections are compatible:

  1. FeatureCreator -> WasmRuntimeExecutor:
    • FeatureCreator outputs feature objects with attributes on the default port
    • WasmRuntimeExecutor accepts features on the default port and processes their attributes (processorType: "Attribute")
  2. WasmRuntimeExecutor -> EchoSink:
    • WasmRuntimeExecutor outputs processed features on the default port
    • EchoSink accepts any feature input on its default port
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for port definitions and data format specifications
ast-grep --pattern 'action: $_(FeatureCreator|WasmRuntimeExecutor|EchoSink)' 

Length of output: 78


Script:

#!/bin/bash
# Search for node definitions in the workflow file
rg -A 10 "nodes:" engine/runtime/examples/plateau/testdata/workflow/wasm_runtime_executor.yml

# Search for any documentation or type definitions related to these components
fd -e md -e yaml -e yml . | xargs rg -l "FeatureCreator|WasmRuntimeExecutor|EchoSink"

Length of output: 2749


Script:

#!/bin/bash
# Let's check the documentation for these components
cat engine/docs/mdbook/src/action.md

# Check example workflows that use these components
cat engine/runtime/tests/fixture/workflow/wasm/runtime_executor/attribute_python.yaml

# Check the actual workflow file completely
cat engine/runtime/examples/plateau/testdata/workflow/wasm_runtime_executor.yml

Length of output: 48833

engine/containers/worker/Dockerfile (2)

52-55: Consider version pinning and security implications.

While the Python installation is correctly grouped in a single RUN command, consider:

  1. Pin specific versions of Python packages for reproducibility and security.
  2. Evaluate if Python needs to be installed in the final image or if compilation can be done in a separate stage.

Let's verify if Python is actually needed in the runtime:

✅ Verification successful

Python installation in the final image is necessary

Based on the evidence from the codebase:

  1. The runtime executor (engine/runtime/action-processor/src/wasm/runtime_executor.rs) directly invokes py2wasm command to compile Python code to WebAssembly at runtime.
  2. Test fixtures and examples show that Python source files are processed during execution, not just at build time.
  3. The multi-stage Dockerfile correctly separates the build environment from the runtime environment, installing only the necessary Python packages in the final stage.

While version pinning could improve reproducibility, the current setup is architecturally sound as Python and py2wasm are required runtime dependencies for the WebAssembly compilation feature.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if Python is used at runtime or only during compilation
# Look for Python imports or runtime usage in the Rust code

rg -g '*.rs' -A 5 'python|py2wasm'

Length of output: 2240


Script:

#!/bin/bash
# Let's check if there are any Python files in the codebase that are used at runtime
fd -e py -x file {}

# Also check if there are any Python-related environment variables or configurations
rg -g '*.{yaml,yml,json,toml}' 'python|py2wasm'

# Check the Dockerfile more thoroughly to understand the build stages
cat engine/containers/worker/Dockerfile

Length of output: 2683


58-58: 🛠️ Refactor suggestion

Optimize layer and pin package versions.

The pip commands can be optimized and made more secure:

  1. Consider combining with the previous RUN command to reduce layers
  2. Pin specific versions of pip and py2wasm

Consider this optimization:

RUN \
    --mount=type=cache,target=/var/lib/apt,sharing=locked \
    --mount=type=cache,target=/var/cache/apt,sharing=locked \
    apt-get update && \
    apt-get install -y \
    ca-certificates \
    libxml2 \
    python3.11 \
    python3.11-distutils \
    python3-pip && \
-   rm -rf /var/lib/apt/lists/*
-
-RUN python3.11 -m pip install --upgrade pip && pip install py2wasm
+   rm -rf /var/lib/apt/lists/* && \
+   python3.11 -m pip install --upgrade "pip==23.3.1" && \
+   pip install "py2wasm==0.1.0"

Let's check for the latest stable versions:

✅ Verification successful

Pin py2wasm to version 2.6.3 for consistent builds

The package is actively used in the codebase for compiling Python scripts to WebAssembly, particularly in the worker and CLI containers. Let's update the suggestion to use the latest stable version:

RUN \
    --mount=type=cache,target=/var/lib/apt,sharing=locked \
    --mount=type=cache,target=/var/cache/apt,sharing=locked \
    apt-get update && \
    apt-get install -y \
    ca-certificates \
    libxml2 \
    python3.11 \
    python3.11-distutils \
    python3-pip && \
-   rm -rf /var/lib/apt/lists/*
-
-RUN python3.11 -m pip install --upgrade pip && pip install py2wasm
+   rm -rf /var/lib/apt/lists/* && \
+   python3.11 -m pip install --upgrade "pip==23.3.1" && \
+   pip install "py2wasm==2.6.3"
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check latest versions of pip and py2wasm
curl -s https://pypi.org/pypi/py2wasm/json | jq '.info.version'

Length of output: 71


Script:

#!/bin/bash
# Check if py2wasm is used in the codebase and how
rg -l "py2wasm" --type-add 'docker:*.{dockerfile,Dockerfile}' -tdocker
rg "py2wasm" -A 5 -B 5

Length of output: 5402

engine/runtime/tests/fixture/workflow/wasm/runtime_executor/attribute_python.yaml (2)

43-54: LGTM: Edge definitions are clear and appropriate

The workflow structure is well-defined with proper connections between nodes using default ports.


5-6: Verify handling of empty outputFilePath

The outputFilePath parameter is defined but empty. Since this parameter is used by the FileWriter action (line 41), ensure that the workflow properly handles the case when the environment variable is not set.

✅ Verification successful

Let me gather more information about how the outputFilePath is handled in the codebase.


Let me try a different approach to find FileWriter and output path handling.


Based on the search results, I can see that the FileWriter implementation in engine/runtime/action-sink/src/file/writer.rs properly handles the output path. The code shows that:

  1. The output path is properly parsed into a URI (Uri::from_str(path.as_str())?)
  2. The storage system handles the path creation and writing (put_sync(output.path().as_path(), ...))
  3. Error handling is in place for file writing operations

Empty outputFilePath is handled by environment variable substitution

The empty outputFilePath in the YAML file is intentional as it's meant to be populated by an environment variable during test execution, which is confirmed by the test helper code in engine/runtime/tests/helper.rs that sets it to result.json in the test folder.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if there's error handling for missing outputFilePath in the codebase
rg -A 5 "outputFilePath" --type rust

Length of output: 407


Script:

#!/bin/bash
# Search for FileWriter action implementation and its handling of output path
ast-grep --pattern 'struct FileWriter'
rg -B 2 -A 10 "FileWriter.*impl"

Length of output: 75


Script:

#!/bin/bash
# Search for FileWriter in yaml files to understand its usage pattern
rg -A 10 "FileWriter:" --type yaml

# Search for any file handling or path validation code
rg -A 5 "file_path|filepath|output.*path" --type rust

Length of output: 33180

.github/workflows/ci_engine.yml (2)

49-52: LGTM! Python setup looks good.

The Python installation step is correctly configured using the official GitHub Action with a specific version.


49-56: Verify integration with subsequent steps.

The Python environment setup looks good, but we should ensure it integrates well with the test execution.

✅ Verification successful

Python 3.11 and py2wasm setup is correctly integrated with subsequent steps

The verification confirms that Python 3.11 and py2wasm are properly integrated:

  • Both worker and CLI Dockerfiles correctly install Python 3.11 and py2wasm
  • The runtime executor (runtime_executor.rs) has proper integration with py2wasm for compiling Python scripts to WASM
  • Test fixtures demonstrate the working integration with a sample Python script
  • The README documents this as an optional requirement for WASM functionality
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if any tests or build scripts explicitly require Python 3.11

# Look for Python version requirements in test files and configs
rg -l "python.*3\.11|py2wasm" 

# Look for potential Python-related test files
fd -e py -e pyw

# Look for potential WASM test files
fd -e wasm

Length of output: 296


Script:

#!/bin/bash
# Check content of relevant files to understand Python/WASM integration
cat engine/README.md
cat engine/containers/worker/Dockerfile
cat engine/containers/cli/Dockerfile
cat engine/runtime/action-processor/src/wasm/runtime_executor.rs
cat engine/runtime/tests/fixture/testdata/wasm/runtime_executor/attribute_python/sample.py

Length of output: 18998

engine/Cargo.toml (1)

175-176: Consider upgrading wasmer-wasix and document security measures.

A few recommendations regarding the WebAssembly runtime dependencies:

  1. Consider upgrading wasmer-wasix to version 0.32.0 for the latest features and security patches.
  2. Document the WebAssembly runtime configuration, specifically:
    • Memory limits
    • CPU time limits
    • Filesystem access permissions
    • Network access restrictions

These security measures are crucial when executing untrusted WebAssembly code.

Let's verify the latest versions and any security advisories:

Comment on lines +4 to +6
fn test_attribute_python() {
execute_with_test_assert("wasm/runtime_executor/attribute_python", "expect.json");
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Enhance test coverage with additional test cases

While this test covers the basic attribute processing scenario, consider adding the following test cases for better coverage:

  1. Error handling for invalid Python syntax
  2. Edge cases with empty or malformed attributes
  3. Memory/resource limits in the Wasm runtime
  4. Different Python script complexities
  5. Concurrent execution scenarios

Here's a suggested expansion of the test module:

#[test]
fn test_attribute_python() {
    execute_with_test_assert("wasm/runtime_executor/attribute_python", "expect.json");
}

#[test]
fn test_attribute_python_invalid_syntax() {
    // Test handling of invalid Python code
    execute_with_test_assert("wasm/runtime_executor/attribute_python_invalid", "expect_error.json");
}

#[test]
fn test_attribute_python_empty() {
    // Test handling of empty attributes
    execute_with_test_assert("wasm/runtime_executor/attribute_python_empty", "expect_empty.json");
}

#[test]
fn test_attribute_python_complex() {
    // Test with complex Python operations
    execute_with_test_assert("wasm/runtime_executor/attribute_python_complex", "expect_complex.json");
}

Comment on lines +9 to +10
let factories: Vec<Box<dyn ProcessorFactory>> =
vec![Box::<WasmRuntimeExecutorFactory>::default()];
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add error handling for factory initialization.

The current implementation using Box::<WasmRuntimeExecutorFactory>::default() could panic if initialization fails. Consider:

  1. Using a Result type for graceful error handling
  2. Adding validation for the factory initialization
  3. Implementing proper error propagation

Here's a suggested improvement:

-    let factories: Vec<Box<dyn ProcessorFactory>> =
-        vec![Box::<WasmRuntimeExecutorFactory>::default()];
+    let factories: Vec<Box<dyn ProcessorFactory>> = vec![
+        WasmRuntimeExecutorFactory::new()
+            .map(Box::new)
+            .expect("Failed to initialize WasmRuntimeExecutorFactory")
+    ];

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +5 to +12
def process_attributes(attributes):
updated_attributes = {}
for key, value in attributes.items():
if isinstance(value, dict) and "String" in value:
updated_attributes[key] = {"String": value["String"] + "_modified"}
else:
updated_attributes[key] = value
return updated_attributes
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add type hints and input validation for better type safety.

Consider these improvements for better maintainability and type safety, especially important for WebAssembly compilation:

-def process_attributes(attributes):
+from typing import Dict, Any
+
+def process_attributes(attributes: Dict[str, Any]) -> Dict[str, Any]:
+    """Process attributes by appending '_modified' to string values.
+    
+    Args:
+        attributes: Dictionary of attribute key-value pairs
+        
+    Returns:
+        Dictionary with modified string values
+    """
+    if not isinstance(attributes, dict):
+        raise TypeError("attributes must be a dictionary")
+
     updated_attributes = {}
     for key, value in attributes.items():
         if isinstance(value, dict) and "String" in value:
+            if not isinstance(value["String"], str):
+                raise TypeError(f"Value for key '{key}' must be a string")
             updated_attributes[key] = {"String": value["String"] + "_modified"}
         else:
             updated_attributes[key] = value
     return updated_attributes
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def process_attributes(attributes):
updated_attributes = {}
for key, value in attributes.items():
if isinstance(value, dict) and "String" in value:
updated_attributes[key] = {"String": value["String"] + "_modified"}
else:
updated_attributes[key] = value
return updated_attributes
from typing import Dict, Any
def process_attributes(attributes: Dict[str, Any]) -> Dict[str, Any]:
"""Process attributes by appending '_modified' to string values.
Args:
attributes: Dictionary of attribute key-value pairs
Returns:
Dictionary with modified string values
"""
if not isinstance(attributes, dict):
raise TypeError("attributes must be a dictionary")
updated_attributes = {}
for key, value in attributes.items():
if isinstance(value, dict) and "String" in value:
if not isinstance(value["String"], str):
raise TypeError(f"Value for key '{key}' must be a string")
updated_attributes[key] = {"String": value["String"] + "_modified"}
else:
updated_attributes[key] = value
return updated_attributes

Comment on lines +15 to +26
def main():
try:
input_data = sys.argv[1]
parsed_data = json.loads(input_data)

updated_attributes = process_attributes(parsed_data)

output = {"status": "success", "attributes": updated_attributes, "error": None}
except Exception as e:
output = {"status": "error", "attributes": None, "error": str(e)}

print(json.dumps(output), file=sys.stdout)
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Improve error handling and add input validation.

The current error handling could be more specific and informative:

 def main():
     try:
+        if len(sys.argv) != 2:
+            raise ValueError("Expected exactly one argument containing JSON data")
+
         input_data = sys.argv[1]
-        parsed_data = json.loads(input_data)
+        try:
+            parsed_data = json.loads(input_data)
+        except json.JSONDecodeError as e:
+            raise ValueError(f"Invalid JSON input: {str(e)}")
+
+        if not isinstance(parsed_data, dict):
+            raise TypeError("JSON input must be an object")

         updated_attributes = process_attributes(parsed_data)

         output = {"status": "success", "attributes": updated_attributes, "error": None}
+    except ValueError as e:
+        output = {"status": "error", "attributes": None, "error": f"Input error: {str(e)}"}
+    except TypeError as e:
+        output = {"status": "error", "attributes": None, "error": f"Type error: {str(e)}"}
     except Exception as e:
-        output = {"status": "error", "attributes": None, "error": str(e)}
+        output = {"status": "error", "attributes": None, "error": f"Unexpected error: {str(e)}"}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def main():
try:
input_data = sys.argv[1]
parsed_data = json.loads(input_data)
updated_attributes = process_attributes(parsed_data)
output = {"status": "success", "attributes": updated_attributes, "error": None}
except Exception as e:
output = {"status": "error", "attributes": None, "error": str(e)}
print(json.dumps(output), file=sys.stdout)
def main():
try:
if len(sys.argv) != 2:
raise ValueError("Expected exactly one argument containing JSON data")
input_data = sys.argv[1]
try:
parsed_data = json.loads(input_data)
except json.JSONDecodeError as e:
raise ValueError(f"Invalid JSON input: {str(e)}")
if not isinstance(parsed_data, dict):
raise TypeError("JSON input must be an object")
updated_attributes = process_attributes(parsed_data)
output = {"status": "success", "attributes": updated_attributes, "error": None}
except ValueError as e:
output = {"status": "error", "attributes": None, "error": f"Input error: {str(e)}"}
except TypeError as e:
output = {"status": "error", "attributes": None, "error": f"Type error: {str(e)}"}
except Exception as e:
output = {"status": "error", "attributes": None, "error": f"Unexpected error: {str(e)}"}
print(json.dumps(output), file=sys.stdout)

Comment on lines +29 to +30
sourceCodeFilePath: "runtime/tests/fixture/testdata/wasm/runtime_executor/attribute_python/sample.py"
wasmFilePath: "runtime/tests/fixture/testdata/wasm/runtime_executor/attribute_python/sample.wasm"
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Codebase verification

Missing WASM file and documentation needed

The verification reveals:

  • Python source file exists at the correct path but the corresponding WASM file is missing
  • No documentation exists about Python requirements or WASM compilation steps
  • The workflow configuration references paths that are partially incorrect

Action items:

  • Add the missing WASM file at runtime/tests/fixture/testdata/wasm/runtime_executor/attribute_python/sample.wasm
  • Document Python version requirements and WASM compilation steps in README.md
  • Update the paths in the workflow file to match the actual file structure (runtime/tests/fixture/... instead of just runtime/tests/...)
🔗 Analysis chain

Validate file paths and add documentation

The relative paths to source and WASM files need validation:

  1. Ensure these paths are correct relative to the workflow execution context
  2. Consider documenting Python version requirements and WASM compilation steps
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Verify the existence of referenced files
fd "sample.py|sample.wasm" --type f

Length of output: 124


Script:

#!/bin/bash
# Check if the wasm file exists in any form (compressed or uncompressed)
fd "sample.wasm" --type f --hidden

# Check the actual paths in the workflow file to ensure we're looking at the right paths
cat engine/runtime/examples/plateau/testdata/workflow/wasm_runtime_executor.yml

# Look for any documentation about WASM compilation or Python requirements
rg -i "python|wasm" README.md || echo "No matches in README.md"

Length of output: 1821

rm -rf /var/lib/apt/lists/*

RUN python3.11 -m pip install --upgrade pip && pip install py2wasm
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Enhance security and maintainability of pip installations.

The current pip installation could be improved for security and maintainability:

  1. Pin py2wasm version for reproducible builds
  2. Run pip as non-root user
  3. Clean pip cache to reduce image size
-RUN python3.11 -m pip install --upgrade pip && pip install py2wasm
+RUN python3.11 -m pip install --no-cache-dir pip==23.2.1 && \
+    python3.11 -m pip install --no-cache-dir py2wasm==0.1.0 && \
+    rm -rf /root/.cache/pip/*
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
RUN python3.11 -m pip install --upgrade pip && pip install py2wasm
RUN python3.11 -m pip install --no-cache-dir pip==23.2.1 && \
python3.11 -m pip install --no-cache-dir py2wasm==0.1.0 && \
rm -rf /root/.cache/pip/*

Comment on lines +52 to +55
libxml2 \
python3.11 \
python3.11-distutils \
python3-pip && \
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider version pinning Python packages for reproducible builds.

While adding Python support is correct, consider:

  1. Pin specific versions of Python packages for reproducibility
  2. Minimize the final image size by combining RUN commands
-    libxml2 \
-    python3.11 \
-    python3.11-distutils \
-    python3-pip && \
+    libxml2=2.9.* \
+    python3.11=3.11.* \
+    python3.11-distutils=3.11.* \
+    python3-pip=23.* && \
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
libxml2 \
python3.11 \
python3.11-distutils \
python3-pip && \
libxml2=2.9.* \
python3.11=3.11.* \
python3.11-distutils=3.11.* \
python3-pip=23.* && \

Comment on lines +40 to +41
output: |
env.get("outputFilePath")
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add default value and validation for output path

The output path relies on an environment variable without a default value. Consider adding a default value and path validation.

 output: |
-  env.get("outputFilePath")
+  env.get("outputFilePath", "output/default.json") |> path.validate()

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +31 to +32
sourceCodeFilePath: "fixture/testdata/wasm/runtime_executor/attribute_python/sample.py"
wasmFilePath: "fixture/testdata/wasm/runtime_executor/attribute_python/sample.wasm"
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Codebase verification

Missing WASM file in the referenced location

The Python source file exists at the correct location with proper read permissions, but the WASM file is missing. The workflow configuration expects both files at:

  • fixture/testdata/wasm/runtime_executor/attribute_python/sample.py (exists)
  • fixture/testdata/wasm/runtime_executor/attribute_python/sample.wasm (missing)

This could lead to runtime failures as the WebAssembly executor requires both files to function properly.

🔗 Analysis chain

Verify existence and permissions of referenced files

The workflow references external Python source and WASM files. Ensure these files exist and have proper permissions.


The initial check shows that while the Python file exists, the WASM file wasn't found in the expected location. Let's verify the actual paths configured in the YAML and search for the WASM file in nearby directories.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if the referenced files exist
fd -t f "sample.py|sample.wasm" -p "fixture/testdata/wasm/runtime_executor/attribute_python"

# Check file permissions
find . -path "*fixture/testdata/wasm/runtime_executor/attribute_python/*" -type f -exec ls -l {} \;

Length of output: 615


Script:

#!/bin/bash
# Check if the WASM file exists in any nearby directories
fd -t f "sample.wasm" ./engine/runtime/tests/fixture/testdata/wasm/runtime_executor

# Check the actual path in the YAML file
cat ./engine/runtime/tests/fixture/workflow/wasm/runtime_executor/attribute_python.yaml

Length of output: 1884

}

fn execute_wasm_module(&self, input: &str) -> super::errors::Result<String> {
let wasm_bytes = std::fs::read(&self.params.wasm_file_path).map_err(|e| {
Copy link
Contributor

@miseyu miseyu Nov 22, 2024

Choose a reason for hiding this comment

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

Important

There is a process to get the wasm binary from outside each time, but please consider if it is possible to cache it.

@miseyu
Copy link
Contributor

miseyu commented Nov 22, 2024

@soma00333
I have commented on this.
Please check it. 🙇

@soma00333
Copy link
Contributor Author

soma00333 commented Nov 23, 2024

I have fixed here to handle the review

@soma00333 soma00333 force-pushed the feat/engine/wasm-runtime-executor branch from 54f39e7 to ebb119b Compare November 23, 2024 06:12
@soma00333 soma00333 enabled auto-merge (squash) November 23, 2024 06:17
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Outside diff range and nitpick comments (2)
engine/runtime/action-processor/src/wasm/runtime_executor.rs (2)

100-131: Provide error handling for unsupported programming languages

Currently, the compile_to_wasm method only handles ProgrammingLanguage::Python. If other languages are added in the future, the method will silently ignore them. Consider adding an else clause to handle unsupported languages and return an appropriate error.

Apply this diff to handle unsupported languages:

 match params.programming_language {
     ProgrammingLanguage::Python => {
         // Existing implementation
     },
+    _ => {
+        return Err(WasmProcessorError::RuntimeExecutorFactory(format!(
+            "Unsupported programming language: {:?}",
+            params.programming_language
+        )));
+    }
 }

220-235: Capture and handle stderr output from the Wasm module execution

Currently, only stdout is being captured from the Wasm module execution. If the module writes errors or important messages to stderr, they will not be visible. Consider capturing stderr as well to improve error reporting and debugging.

Apply this diff to capture stderr output:

 let (stdout_tx, mut stdout_rx) = Pipe::channel();
+let (stderr_tx, mut stderr_rx) = Pipe::channel();
 WasiEnv::builder(program_name)
     .args([input])
     .stdout(Box::new(stdout_tx))
+    .stderr(Box::new(stderr_tx))
     .run_with_store(module, &mut store)
     .map_err(|e| {
         WasmProcessorError::RuntimeExecutor(format!("Failed to execute module: {}", e))
     })?;

 // Read stdout
 let mut output = String::new();
 stdout_rx.read_to_string(&mut output).map_err(|e| {
     WasmProcessorError::RuntimeExecutor(format!(
         "Failed to read stdout from Wasm module: {}",
         e
     ))
 })?;
+// Read stderr
+let mut error_output = String::new();
+stderr_rx.read_to_string(&mut error_output).map_err(|e| {
+    WasmProcessorError::RuntimeExecutor(format!(
+        "Failed to read stderr from Wasm module: {}",
+        e
+    ))
+})?;
+// Incorporate `error_output` into error handling if necessary
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 54f39e7 and ebb119b.

⛔ Files ignored due to path filters (2)
  • engine/Cargo.lock is excluded by !**/*.lock, !**/*.lock
  • engine/docs/mdbook/src/action.md is excluded by !**/*.md
📒 Files selected for processing (3)
  • engine/runtime/action-processor/Cargo.toml (1 hunks)
  • engine/runtime/action-processor/src/wasm/runtime_executor.rs (1 hunks)
  • engine/schema/actions.json (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • engine/runtime/action-processor/Cargo.toml
  • engine/schema/actions.json
🔇 Additional comments (1)
engine/runtime/action-processor/src/wasm/runtime_executor.rs (1)

191-193: Verify attribute serialization for potential edge cases

When serializing attributes to JSON, certain values might not serialize properly, leading to errors. Ensure that all attribute values are serializable and handle any serialization errors gracefully.

Run the following script to check for attributes that may not serialize properly:

✅ Verification successful

Serialization implementation is robust and handles all edge cases

The AttributeValue enum has a complete and safe serialization implementation:

  • It derives Serialize and has proper implementations for all variants
  • All variant types (bool, Number, String, DateTime, Vec, Bytes, HashMap) are standard serializable types
  • It has comprehensive From/Into implementations for serde_json::Value that handle all cases
  • Error handling is in place through the WasmProcessorError wrapper
  • The implementation is well-tested as shown by the test suite
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Find attribute values that may not serialize to JSON.

# Search for AttributeValue instances that might cause serialization issues
fd -e rs -x ast-grep --pattern 'AttributeValue::{{$_}}({{$$$}})' {}
# Expected: All AttributeValues should be in a serializable format.

Length of output: 71


Script:

#!/bin/bash
# Let's try a different approach to find attribute-related code

# First, let's find the AttributeValue enum definition
rg -p "enum AttributeValue" -A 10

# Then look for the serialize_attributes implementation
rg -p "fn serialize_attributes" -A 10

# Also check for any serde serialization implementations
rg -p "impl.*Serialize.*for AttributeValue" -A 10

Length of output: 878


Script:

#!/bin/bash
# Let's check for the serde derive or manual implementation for AttributeValue
rg -p "derive.*Serialize.*AttributeValue|impl.*Serialize.*for AttributeValue" -B 2 -A 10

# Also check if there are any tests related to attribute serialization
rg -p "test.*serialize.*attribute" -A 10

# Look for any error handling patterns in attribute serialization
rg "WasmProcessorError::.*serialize" -A 2

Length of output: 177


Script:

#!/bin/bash
# Let's check the entire attribute.rs file to understand the complete implementation
cat engine/runtime/types/src/attribute.rs

# Also check for any custom serialization implementations in the same file
rg -p "#\[derive\(.*Serialize.*\)\]" engine/runtime/types/src/attribute.rs -B 2 -A 2

Length of output: 18929

Comment on lines +215 to +217
let module = Module::new(&store, &self.wasm_binary).map_err(|e| {
WasmProcessorError::RuntimeExecutor(format!("Failed to compile module: {}", e))
})?;
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Set resource limits on Wasm module execution

To prevent resource exhaustion or infinite loops when executing untrusted Wasm modules, consider setting limits on memory usage and execution time.

Apply this diff to set resource limits:

 let mut store = Store::default();
+store.set_limits(wasmer::StoreLimitsBuilder::new()
+    .memory_pages(1024) // Limit memory usage to 64MB (64KB per page)
+    .instances(10)      // Limit the number of instances
+    .build());

 let module = Module::new(&store, &self.wasm_binary).map_err(|e| {
     WasmProcessorError::RuntimeExecutor(format!("Failed to compile module: {}", e))
 })?;

Note: Adjust the limits according to your application's requirements.

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +102 to +110
let py2wasm_output = std::process::Command::new("py2wasm")
.args([&params.source_code_file_path, "-o", temp_wasm_path_str])
.output()
.map_err(|e| {
WasmProcessorError::RuntimeExecutorFactory(format!(
"Failed to run py2wasm: {}. Command: py2wasm {} -o {}",
e, params.source_code_file_path, temp_wasm_path_str
))
})?;
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Handle the case where py2wasm is not found or not installed

Currently, if py2wasm is not installed or not available in the PATH, the compilation will fail with a generic error. Consider handling the specific error when py2wasm is not found to provide a clearer message to the user.

Apply this diff to improve error handling:

 let py2wasm_output = std::process::Command::new("py2wasm")
     .args([&params.source_code_file_path, "-o", temp_wasm_path_str])
     .output()
     .map_err(|e| {
         WasmProcessorError::RuntimeExecutorFactory(format!(
-            "Failed to run py2wasm: {}. Command: py2wasm {} -o {}",
-            e, params.source_code_file_path, temp_wasm_path_str
+            "Failed to run 'py2wasm'. Please ensure it is installed and in your PATH. Error: {}",
+            e
         ))
     })?;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
let py2wasm_output = std::process::Command::new("py2wasm")
.args([&params.source_code_file_path, "-o", temp_wasm_path_str])
.output()
.map_err(|e| {
WasmProcessorError::RuntimeExecutorFactory(format!(
"Failed to run py2wasm: {}. Command: py2wasm {} -o {}",
e, params.source_code_file_path, temp_wasm_path_str
))
})?;
let py2wasm_output = std::process::Command::new("py2wasm")
.args([&params.source_code_file_path, "-o", temp_wasm_path_str])
.output()
.map_err(|e| {
WasmProcessorError::RuntimeExecutorFactory(format!(
"Failed to run 'py2wasm'. Please ensure it is installed and in your PATH. Error: {}",
e
))
})?;

@soma00333 soma00333 requested a review from miseyu November 23, 2024 06:27
Copy link
Contributor

@miseyu miseyu left a comment

Choose a reason for hiding this comment

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

Thank you so much!
LGTM

@soma00333 soma00333 merged commit 46ee932 into main Nov 24, 2024
17 checks passed
@soma00333 soma00333 deleted the feat/engine/wasm-runtime-executor branch November 24, 2024 04:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants