diff --git a/server/src/steel/handlers.rs b/server/src/steel/handlers.rs index a918992..81a847a 100644 --- a/server/src/steel/handlers.rs +++ b/server/src/steel/handlers.rs @@ -1,4 +1,6 @@ // src/steel/handlers.rs pub mod evaluator; +pub mod engine; -pub use evaluator::{validate_script, validate_target_column}; +pub use engine::validate_steel_script; +pub use evaluator::validate_target_column; diff --git a/server/src/steel/handlers/engine.rs b/server/src/steel/handlers/engine.rs new file mode 100644 index 0000000..3bf3ec4 --- /dev/null +++ b/server/src/steel/handlers/engine.rs @@ -0,0 +1,34 @@ +// src/steel/handlers/engine.rs +use steel_core::{steel_vm::engine::Engine, rvals::SteelVal}; +use tonic::Status; + +pub fn validate_steel_script(script: &str) -> Result<(), Status> { + let mut engine = Engine::new(); + + // Basic syntax check + let parsed = engine.compile(script).map_err(|e| { + Status::invalid_argument(format!("Syntax error: {}", e)) + })?; + + // Validate required function signature + let has_transform = parsed.iter().any(|expr| match expr { + SteelVal::Func(f) => f.name() == Some("transform"), + _ => false, + }); + + if !has_transform { + return Err(Status::invalid_argument( + "Script must contain a 'transform' function" + )); + } + + // Simple sandboxed execution test + let test_input = SteelVal::StringV("test_data".into()); + + engine.call_function("transform", vec![test_input]) + .map_err(|e| { + Status::invalid_argument(format!("Runtime validation failed: {}", e)) + })?; + + Ok(()) +} diff --git a/server/src/steel/handlers/evaluator.rs b/server/src/steel/handlers/evaluator.rs index 1d686af..c0b74dd 100644 --- a/server/src/steel/handlers/evaluator.rs +++ b/server/src/steel/handlers/evaluator.rs @@ -1,9 +1,9 @@ // src/steel/handlers/evaluator.rs +use crate::validation::script::validate_script; use serde_json::Value; const SYSTEM_COLUMNS: &[&str] = &["id", "deleted", "firma", "created_at"]; -// Column validation pub fn validate_target_column( table_name: &str, target: &str, @@ -22,11 +22,3 @@ pub fn validate_target_column( Ok(()) } - -// Basic script validation -pub fn validate_script(script: &str) -> Result<(), String> { - if script.trim().is_empty() { - return Err("Script cannot be empty".to_string()); - } - Ok(()) -} diff --git a/server/src/steel/mod.rs b/server/src/steel/mod.rs index c89ced1..181dd66 100644 --- a/server/src/steel/mod.rs +++ b/server/src/steel/mod.rs @@ -1,3 +1,4 @@ // src/steel/mod.rs pub mod handlers; +pub mod validation; diff --git a/server/src/steel/validation/script.rs b/server/src/steel/validation/script.rs new file mode 100644 index 0000000..427fafc --- /dev/null +++ b/server/src/steel/validation/script.rs @@ -0,0 +1,30 @@ +// src/steel/validation/script.rs +use std::fmt; +use super::handlers::engine::validate_steel_script; +use tonic::Status; + +#[derive(Debug)] +pub enum ScriptValidationError { + EmptyScript, + SteelValidation(String), +} + +impl fmt::Display for ScriptValidationError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + ScriptValidationError::EmptyScript => write!(f, "Script cannot be empty"), + ScriptValidationError::SteelValidation(msg) => write!(f, "Steel validation error: {}", msg), + } + } +} + +pub fn validate_script(script: &str) -> Result<(), ScriptValidationError> { + if script.trim().is_empty() { + return Err(ScriptValidationError::EmptyScript); + } + + validate_steel_script(script) + .map_err(|e| ScriptValidationError::SteelValidation(e.message().to_string()))?; + + Ok(()) +} diff --git a/server/src/table_script/handlers/post_table_script.rs b/server/src/table_script/handlers/post_table_script.rs index 31b6431..ca9695f 100644 --- a/server/src/table_script/handlers/post_table_script.rs +++ b/server/src/table_script/handlers/post_table_script.rs @@ -2,7 +2,8 @@ use tonic::Status; use sqlx::{PgPool, Error as SqlxError}; use common::proto::multieko2::table_script::{PostTableScriptRequest, TableScriptResponse}; -use crate::steel::handlers::evaluator::{validate_script, validate_target_column}; +use crate::steel::handlers::evaluator::validate_target_column; +use crate::steel::validation::script::validate_script; pub async fn post_table_script( db_pool: &PgPool, @@ -20,8 +21,8 @@ pub async fn post_table_script( .ok_or_else(|| Status::not_found("Table definition not found"))?; // Call validation functions - validate_script(&request.script) // Changed from validate_syntax to validate_script - .map_err(|e| Status::invalid_argument(e))?; + validate_script(&request.script) + .map_err(|e| Status::invalid_argument(e.to_string()))?; validate_target_column(&table_def.table_name, &request.target_column, &table_def.columns) .map_err(|e| Status::invalid_argument(e))?;