diff --git a/src/compile/extensions/ado_script.rs b/src/compile/extensions/ado_script.rs index 96c6fad3..9e396cb6 100644 --- a/src/compile/extensions/ado_script.rs +++ b/src/compile/extensions/ado_script.rs @@ -427,6 +427,40 @@ mod tests { assert!(steps[2].contains("node '/tmp/ado-aw-scripts/ado-script/gate.js'")); } + #[test] + fn gate_and_import_eval_paths_consistent_with_download_step() { + let extract_dir = "/tmp/ado-aw-scripts/"; + assert!( + GATE_EVAL_PATH.starts_with(extract_dir), + "GATE_EVAL_PATH must be under the unzip -d destination" + ); + assert!( + IMPORT_EVAL_PATH.starts_with(extract_dir), + "IMPORT_EVAL_PATH must be under the unzip -d destination" + ); + let zip_prefix = "ado-script/"; + assert!( + GATE_EVAL_PATH + .strip_prefix(extract_dir) + .expect("gate path should include extract dir") + .starts_with(zip_prefix), + "GATE_EVAL_PATH suffix must match zip internal path prefix used in release.yml" + ); + assert!( + IMPORT_EVAL_PATH + .strip_prefix(extract_dir) + .expect("import path should include extract dir") + .starts_with(zip_prefix), + "IMPORT_EVAL_PATH suffix must match zip internal path prefix used in release.yml" + ); + let steps = install_and_download_steps(); + let download = &steps[1]; + assert!( + download.contains("-d /tmp/ado-aw-scripts/"), + "download step must unzip to /tmp/ado-aw-scripts/" + ); + } + #[test] fn prepare_steps_empty_when_inlined_imports_true() { let ext = ext_with(None, None, true); diff --git a/src/validate.rs b/src/validate.rs index 11ab0701..3f52d812 100644 --- a/src/validate.rs +++ b/src/validate.rs @@ -508,6 +508,17 @@ mod tests { assert!(!is_valid_version("1.0.0 -Source https://evil.com")); } + #[test] + fn test_is_valid_artifact_name() { + assert!(is_valid_artifact_name("my-artifact_v1.0")); + assert!(is_valid_artifact_name("drop")); + assert!(!is_valid_artifact_name("")); + assert!(!is_valid_artifact_name("my artifact")); + assert!(!is_valid_artifact_name("$(secretVar)")); + assert!(!is_valid_artifact_name("../../etc/passwd")); + assert!(!is_valid_artifact_name("{{inject}}")); + } + #[test] fn test_is_valid_arg() { assert!(is_valid_arg("--verbose")); @@ -601,6 +612,25 @@ mod tests { assert!(reject_ado_expressions("$[variables.x]", "param", "field").is_err()); } + #[test] + fn test_reject_ado_expressions_in_value_catches_injection_in_sequence() { + let seq = serde_yaml::Value::Sequence(vec![ + serde_yaml::Value::String("safe".to_string()), + serde_yaml::Value::String("$(secretVar)".to_string()), + ]); + let result = reject_ado_expressions_in_value(&seq, "myParam", "default"); + assert!(result.is_err(), "Sequence with ADO expression must be rejected"); + } + + #[test] + fn test_reject_ado_expressions_in_value_allows_safe_sequence() { + let seq = serde_yaml::Value::Sequence(vec![ + serde_yaml::Value::String("us-east".to_string()), + serde_yaml::Value::String("eu-west".to_string()), + ]); + assert!(reject_ado_expressions_in_value(&seq, "region", "default").is_ok()); + } + #[test] fn test_reject_pipeline_injection() { assert!(reject_pipeline_injection("normal value", "field").is_ok());