Evaluate a boolean `if:` expression against the current execution context. Returns `true` if the step should run, `false` if it should be skipped. The evaluation is wrapped in a [`tokio::time::timeout`] to prevent a malicious or pathological expression from blocking a Tokio worker thread.
(
expr: &str,
trigger_ctx: &TriggerContext,
step_outputs: &HashMap<String, JsonValue>,
)
| 362 | /// The evaluation is wrapped in a [`tokio::time::timeout`] to prevent a |
| 363 | /// malicious or pathological expression from blocking a Tokio worker thread. |
| 364 | pub async fn evaluate_condition( |
| 365 | expr: &str, |
| 366 | trigger_ctx: &TriggerContext, |
| 367 | step_outputs: &HashMap<String, JsonValue>, |
| 368 | ) -> Result<bool, WorkflowError> { |
| 369 | let ctx = build_eval_context(trigger_ctx, step_outputs)?; |
| 370 | let expr_owned = expr.to_owned(); |
| 371 | |
| 372 | // Bound expression complexity to prevent pathological evaluation times. |
| 373 | // The spawn_blocking thread cannot be cancelled by tokio::time::timeout — |
| 374 | // it will run to completion even after timeout. Length-limiting the expression |
| 375 | // prevents worst-case O(2^n) evaluation paths. |
| 376 | const MAX_EXPR_LEN: usize = 4096; |
| 377 | if expr_owned.len() > MAX_EXPR_LEN { |
| 378 | return Err(WorkflowError::ConditionError(format!( |
| 379 | "condition expression exceeds {} byte limit", |
| 380 | MAX_EXPR_LEN |
| 381 | ))); |
| 382 | } |
| 383 | |
| 384 | let result = tokio::time::timeout( |
| 385 | EVAL_TIMEOUT, |
| 386 | tokio::task::spawn_blocking(move || evalexpr::eval_boolean_with_context(&expr_owned, &ctx)), |
| 387 | ) |
| 388 | .await |
| 389 | .map_err(|_| { |
| 390 | WorkflowError::ConditionError(format!( |
| 391 | "'{expr}': evaluation timed out after {}ms", |
| 392 | EVAL_TIMEOUT.as_millis() |
| 393 | )) |
| 394 | })? |
| 395 | .map_err(|e| WorkflowError::ConditionError(format!("'{expr}': eval task panicked: {e}")))? |
| 396 | .map_err(|e| WorkflowError::ConditionError(format!("'{expr}': {e}")))?; |
| 397 | |
| 398 | Ok(result) |
| 399 | } |
| 400 | |
| 401 | /// Resolve all template variables in a step's action fields. |
| 402 | /// |
no test coverage detected