Repository: getsops/sops (language: python)

Issue:
sops encrypt will encrypt with a broken configuration file, leading to no master key being saved 
`sops -e` will run with a broken config (only when the creation_rule is a map, `- blah:` works, `-blah` doesn't) and not save a master key.

```
$ cat .sops.yaml 
creation_rules:
  - blah:
$ cat foo.yaml 
foo: bar
$ sops -e foo.yaml 
foo: ENC[AES256_GCM,data:qVOZ,iv:z+vaqV+xcNzghECBO4Cv6zv+wY8ROAAiCFQTzVZB+KU=,tag:R5KV4+Ioke1mtH+2SAuu9g==,type:str]
sops:
    kms: []
    gcp_kms: []
    azure_kv: []
    lastmodified: '2019-06-11T21:54:58Z'
    mac: ENC[AES256_GCM,data:zo2uiTvpVZyP1C+q5g4YQw52MpvRKKZ9bjtSrCPUptSwKgo9G3VGLbvgkqHBqvAkXWxgSR+JLgl2iZLr5Jur1tUDsFEMxd2++8cbpgpCDKUVG6/WMlfxIROyvZKteyyZokwWaspVe5vxpMAdCO7BavwmmOwaRvnp5f+Dq7vDJ3k=,iv:9HsScdpvTCm7DAtVtdOfZ6fYp4J8kO8L9qzKxF6hs5Q=,tag:UnoQYfGhC0K1GPG6zjGgTQ==,type:str]
    pgp: []
    unencrypted_suffix: _unencrypted
    version: 3.2.0
```

Interesting edge case. Tested on both 3.2.0 and 3.3.1


Discussion / hints:
Discovered by typoing `- key_groups:` as `- keygroups:`

Fix patch:
diff --git a/sops.go b/sops.go
index 4b97292a1..718f51bf8 100644
--- a/sops.go
+++ b/sops.go
@@ -700,6 +700,11 @@ func (m *Metadata) UpdateMasterKeysWithKeyServices(dataKey []byte, svcs []keyser
 			fmt.Errorf("no key services provided, cannot update master keys"),
 		}
 	}
+	if len(m.KeyGroups) == 0 {
+		return []error{
+			fmt.Errorf("no key groups provided"),
+		}
+	}
 	var parts [][]byte
 	if len(m.KeyGroups) == 1 {
 		// If there's only one key group, we can't do Shamir. All keys
@@ -726,6 +731,11 @@ func (m *Metadata) UpdateMasterKeysWithKeyServices(dataKey []byte, svcs []keyser
 	}
 	for i, group := range m.KeyGroups {
 		part := parts[i]
+		if len(group) == 0 {
+			return []error{
+				fmt.Errorf("empty key group provided"),
+			}
+		}
 		for _, key := range group {
 			svcKey := keyservice.KeyFromMasterKey(key)
 			var keyErrs []error


Test patch:
diff --git a/functional-tests/.sops.yaml b/functional-tests/.sops.yaml
index 3e346dd5e..17dd2be78 100644
--- a/functional-tests/.sops.yaml
+++ b/functional-tests/.sops.yaml
@@ -11,6 +11,12 @@ creation_rules:
         - FBC7B9E2A4F9289AC0C1D4843D16CEE4A27381B4
       - pgp:
         - B611A2F9F11D0FF82568805119F9B5DAEA91FF86
+    - path_regex: test_no_keygroups.yaml
+    - path_regex: test_zero_keygroups.yaml
+      key_groups: []
+    - path_regex: test_empty_keygroup.yaml
+      key_groups:
+        - {}
     - pgp: FBC7B9E2A4F9289AC0C1D4843D16CEE4A27381B4
 destination_rules:
     - s3_bucket: "sops-publish-functional-tests"
diff --git a/functional-tests/src/lib.rs b/functional-tests/src/lib.rs
index 2ec7a891b..223dab704 100644
--- a/functional-tests/src/lib.rs
+++ b/functional-tests/src/lib.rs
@@ -949,6 +949,66 @@ b: ba"#
         );
     }
 
+    #[test]
+    fn test_no_keygroups() {
+        // The .sops.yaml file ensures this file is encrypted by zero keygroups
+        let file_path = prepare_temp_file("test_no_keygroups.yaml", "a: secret".as_bytes());
+        let output = Command::new(SOPS_BINARY_PATH)
+            .arg("encrypt")
+            .arg("-i")
+            .arg(file_path.clone())
+            .output()
+            .expect("Error running sops");
+        assert!(
+            !output.status.success(),
+            "SOPS succeeded encrypting a file without a key group"
+        );
+        assert_eq!(
+            std::str::from_utf8(&output.stderr).unwrap(),
+            "Could not generate data key: [empty key group provided]\n"
+        );
+    }
+
+    #[test]
+    fn test_zero_keygroups() {
+        // The .sops.yaml file ensures this file is encrypted by zero keygroups
+        let file_path = prepare_temp_file("test_zero_keygroups.yaml", "a: secret".as_bytes());
+        let output = Command::new(SOPS_BINARY_PATH)
+            .arg("encrypt")
+            .arg("-i")
+            .arg(file_path.clone())
+            .output()
+            .expect("Error running sops");
+        assert!(
+            !output.status.success(),
+            "SOPS succeeded encrypting a file without a key group"
+        );
+        assert_eq!(
+            std::str::from_utf8(&output.stderr).unwrap(),
+            "Could not generate data key: [empty key group provided]\n"
+        );
+    }
+
+    #[test]
+    fn test_empty_keygroup() {
+        // The .sops.yaml file ensures this file is encrypted by zero keygroups
+        let file_path = prepare_temp_file("test_empty_keygroup.yaml", "a: secret".as_bytes());
+        let output = Command::new(SOPS_BINARY_PATH)
+            .arg("encrypt")
+            .arg("-i")
+            .arg(file_path.clone())
+            .output()
+            .expect("Error running sops");
+        assert!(
+            !output.status.success(),
+            "SOPS succeeded encrypting a file without a key group"
+        );
+        assert_eq!(
+            std::str::from_utf8(&output.stderr).unwrap(),
+            "Could not generate data key: [empty key group provided]\n"
+        );
+    }
+
     #[test]
     fn extract_string() {
         let file_path = prepare_temp_file(