diff --git a/cmd/sops/main.go b/cmd/sops/main.go index 18701f05d..c426a7fa3 100644 --- a/cmd/sops/main.go +++ b/cmd/sops/main.go @@ -860,7 +860,14 @@ func jsonValueToTreeInsertableValue(jsonValue string) (interface{}, error) { return nil, common.NewExitError("Invalid --set value format", codes.ErrorInvalidSetFormat) } } - return valueToInsert.(sops.TreeBranches)[0], nil + // Fix for #461 + // Attempt conversion to TreeBranches to handle yaml multidoc. If conversion fails it's + // most likely a string value, so just return it as-is. + values, ok := valueToInsert.(sops.TreeBranches) + if !ok { + return valueToInsert, nil + } + return values[0], nil } func extractSetArguments(set string) (path []interface{}, valueToInsert interface{}, err error) { diff --git a/functional-tests/src/lib.rs b/functional-tests/src/lib.rs index 01ec5379e..3e00ad4c7 100644 --- a/functional-tests/src/lib.rs +++ b/functional-tests/src/lib.rs @@ -260,6 +260,46 @@ b: ba"# } panic!("Output YAML does not have the expected structure"); } + + #[test] + fn set_yaml_file_string() { + let file_path = prepare_temp_file("test_set_string.yaml", + r#"a: 2 +b: ba"# + .as_bytes()); + Command::new(SOPS_BINARY_PATH) + .arg("-e") + .arg("-i") + .arg(file_path.clone()) + .output() + .expect("Error running sops"); + Command::new(SOPS_BINARY_PATH) + .arg("-e") + .arg("-i") + .arg("--set") + .arg(r#"["a"] "aaa""#) + .arg(file_path.clone()) + .output() + .expect("Error running sops"); + let output = Command::new(SOPS_BINARY_PATH) + .arg("-d") + .arg("-i") + .arg(file_path.clone()) + .output() + .expect("Error running sops"); + println!("stdout: {}, stderr: {}", + String::from_utf8_lossy(&output.stdout), + String::from_utf8_lossy(&output.stderr)); + let mut s = String::new(); + File::open(file_path).unwrap().read_to_string(&mut s).unwrap(); + let data: Value = serde_yaml::from_str(&s).expect("Error parsing sops's YAML output"); + if let Value::Mapping(data) = data { + let a = data.get(&Value::String("a".to_owned())).unwrap(); + assert_eq!(a, &Value::String("aaa".to_owned())); + } else { + panic!("Output JSON does not have the expected structure"); + } + } #[test] fn decrypt_file_no_mac() {