diff --git a/Cargo.toml b/Cargo.toml index a1f481c..13ba25a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,6 +49,7 @@ wfe-containerd = { version = "1.0.0", path = "wfe-containerd" } # YAML serde_yaml = "0.9" +yaml-merge-keys = { version = "0.8", features = ["serde_yaml"] } regex = "1" # Deno runtime diff --git a/wfe-yaml/Cargo.toml b/wfe-yaml/Cargo.toml index 56f8a25..198f765 100644 --- a/wfe-yaml/Cargo.toml +++ b/wfe-yaml/Cargo.toml @@ -15,6 +15,7 @@ wfe-core = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } serde_yaml = { workspace = true } +yaml-merge-keys = { workspace = true } async-trait = { workspace = true } tokio = { workspace = true } thiserror = { workspace = true } diff --git a/wfe-yaml/src/lib.rs b/wfe-yaml/src/lib.rs index 28a3234..7f39ba2 100644 --- a/wfe-yaml/src/lib.rs +++ b/wfe-yaml/src/lib.rs @@ -8,6 +8,8 @@ pub mod validation; use std::collections::HashMap; +use serde::de::Error as _; + use crate::compiler::CompiledWorkflow; use crate::error::YamlWorkflowError; @@ -23,6 +25,10 @@ pub fn load_workflow( /// Load workflows from a YAML string, applying variable interpolation. /// Returns a Vec of compiled workflows (supports multi-workflow files). +/// +/// Supports YAML 1.1 merge keys (`<<: *anchor`) via the `yaml-merge-keys` +/// crate. serde_yaml 0.9 implements YAML 1.2 which dropped merge keys; +/// we preprocess the YAML to resolve them before deserialization. pub fn load_workflow_from_str( yaml: &str, config: &HashMap, @@ -30,8 +36,14 @@ pub fn load_workflow_from_str( // Interpolate variables. let interpolated = interpolation::interpolate(yaml, config)?; - // Parse YAML as multi-workflow file. - let file: schema::YamlWorkflowFile = serde_yaml::from_str(&interpolated)?; + // Parse to a generic YAML value first, then resolve merge keys (<<:). + // This adds YAML 1.1 merge key support on top of serde_yaml 0.9's YAML 1.2 parser. + let raw_value: serde_yaml::Value = serde_yaml::from_str(&interpolated)?; + let merged_value = yaml_merge_keys::merge_keys_serde(raw_value) + .map_err(|e| YamlWorkflowError::Parse(serde_yaml::Error::custom(format!("merge key resolution failed: {e}"))))?; + + // Deserialize the merge-resolved value into our schema. + let file: schema::YamlWorkflowFile = serde_yaml::from_value(merged_value)?; let specs = resolve_workflow_specs(file)?;