openzeppelin_relayer/config/config_file/signer/
mod.rs

1//! Configuration file definitions for signer services.
2//!
3//! Provides configuration structures and validation for different signer types:
4//! - Test (temporary private keys)
5//! - Local keystore (encrypted JSON files)
6//! - HashiCorp Vault integration
7//! - Turnkey service integration
8//! - Google Cloud integration
9//! - AWS KMS integration (EVM only)
10use super::ConfigFileError;
11use serde::{Deserialize, Serialize};
12use std::collections::HashSet;
13use validator::Validate;
14
15mod local;
16pub use local::*;
17
18mod vault;
19pub use vault::*;
20
21mod vault_cloud;
22pub use vault_cloud::*;
23
24mod vault_transit;
25pub use vault_transit::*;
26
27mod turnkey;
28pub use turnkey::*;
29
30mod google_cloud_kms;
31pub use google_cloud_kms::*;
32
33mod aws_kms;
34pub use aws_kms::*;
35
36pub trait SignerConfigValidate {
37    fn validate(&self) -> Result<(), ConfigFileError>;
38}
39
40fn collect_validation_errors(errors: &validator::ValidationErrors) -> Vec<String> {
41    let mut messages = Vec::new();
42
43    for (field, field_errors) in errors.field_errors().iter() {
44        let field_msgs: Vec<String> = field_errors
45            .iter()
46            .map(|error| error.message.clone().unwrap_or_default().to_string())
47            .collect();
48        messages.push(format!("{}: {}", field, field_msgs.join(", ")));
49    }
50
51    for (struct_field, kind) in errors.errors().iter() {
52        if let validator::ValidationErrorsKind::Struct(nested) = kind {
53            let nested_msgs = collect_validation_errors(nested);
54            for msg in nested_msgs {
55                messages.push(format!("{}.{}", struct_field, msg));
56            }
57        }
58    }
59
60    messages
61}
62
63/// Validates a signer config using validator::Validate
64pub fn validate_with_validator<T>(config: &T) -> Result<(), ConfigFileError>
65where
66    T: SignerConfigValidate + Validate,
67{
68    match Validate::validate(config) {
69        Ok(_) => Ok(()),
70        Err(errors) => Err(ConfigFileError::InvalidFormat(
71            collect_validation_errors(&errors).join("; "),
72        )),
73    }
74}
75
76#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
77#[serde(deny_unknown_fields)]
78pub struct TestSignerFileConfig {}
79
80#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
81#[serde(tag = "type", rename_all = "lowercase", content = "config")]
82pub enum SignerFileConfigEnum {
83    Test(TestSignerFileConfig),
84    Local(LocalSignerFileConfig),
85    #[serde(rename = "aws_kms")]
86    AwsKms(AwsKmsSignerFileConfig),
87    Vault(VaultSignerFileConfig),
88    #[serde(rename = "vault_cloud")]
89    VaultCloud(VaultCloudSignerFileConfig),
90    #[serde(rename = "vault_transit")]
91    VaultTransit(VaultTransitSignerFileConfig),
92    Turnkey(TurnkeySignerFileConfig),
93    #[serde(rename = "google_cloud_kms")]
94    GoogleCloudKms(GoogleCloudKmsSignerFileConfig),
95}
96
97impl SignerFileConfigEnum {
98    pub fn get_local(&self) -> Option<&LocalSignerFileConfig> {
99        match self {
100            SignerFileConfigEnum::Local(local) => Some(local),
101            _ => None,
102        }
103    }
104
105    pub fn get_vault(&self) -> Option<&VaultSignerFileConfig> {
106        match self {
107            SignerFileConfigEnum::Vault(vault) => Some(vault),
108            _ => None,
109        }
110    }
111
112    pub fn get_vault_cloud(&self) -> Option<&VaultCloudSignerFileConfig> {
113        match self {
114            SignerFileConfigEnum::VaultCloud(vault_cloud) => Some(vault_cloud),
115            _ => None,
116        }
117    }
118
119    pub fn get_vault_transit(&self) -> Option<&VaultTransitSignerFileConfig> {
120        match self {
121            SignerFileConfigEnum::VaultTransit(vault_transit) => Some(vault_transit),
122            _ => None,
123        }
124    }
125
126    pub fn get_test(&self) -> Option<&TestSignerFileConfig> {
127        match self {
128            SignerFileConfigEnum::Test(test) => Some(test),
129            _ => None,
130        }
131    }
132
133    pub fn get_aws_kms(&self) -> Option<&AwsKmsSignerFileConfig> {
134        match self {
135            SignerFileConfigEnum::AwsKms(aws_kms) => Some(aws_kms),
136            _ => None,
137        }
138    }
139
140    pub fn get_turnkey(&self) -> Option<&TurnkeySignerFileConfig> {
141        match self {
142            SignerFileConfigEnum::Turnkey(turnkey) => Some(turnkey),
143            _ => None,
144        }
145    }
146
147    pub fn get_google_cloud_kms(&self) -> Option<&GoogleCloudKmsSignerFileConfig> {
148        match self {
149            SignerFileConfigEnum::GoogleCloudKms(google_cloud_kms) => Some(google_cloud_kms),
150            _ => None,
151        }
152    }
153}
154
155#[derive(Debug, Serialize, Deserialize, Clone)]
156#[serde(deny_unknown_fields)]
157pub struct SignerFileConfig {
158    pub id: String,
159    #[serde(flatten)]
160    pub config: SignerFileConfigEnum,
161}
162
163#[derive(Debug, Serialize, Deserialize, Clone)]
164#[serde(tag = "type", rename_all = "lowercase")]
165pub enum SignerFileConfigPassphrase {
166    Env { name: String },
167    Plain { value: String },
168}
169
170impl SignerFileConfig {
171    pub fn validate_signer(&self) -> Result<(), ConfigFileError> {
172        if self.id.is_empty() {
173            return Err(ConfigFileError::InvalidIdLength(
174                "Signer ID cannot be empty".into(),
175            ));
176        }
177
178        match &self.config {
179            SignerFileConfigEnum::Test(_) => Ok(()),
180            SignerFileConfigEnum::Local(local_config) => local_config.validate(),
181            SignerFileConfigEnum::AwsKms(aws_kms_config) => {
182                SignerConfigValidate::validate(aws_kms_config)
183            }
184            SignerFileConfigEnum::Vault(vault_config) => {
185                SignerConfigValidate::validate(vault_config)
186            }
187            SignerFileConfigEnum::VaultCloud(vault_cloud_config) => {
188                SignerConfigValidate::validate(vault_cloud_config)
189            }
190            SignerFileConfigEnum::VaultTransit(vault_transit_config) => {
191                SignerConfigValidate::validate(vault_transit_config)
192            }
193            SignerFileConfigEnum::Turnkey(turnkey_config) => {
194                SignerConfigValidate::validate(turnkey_config)
195            }
196            SignerFileConfigEnum::GoogleCloudKms(google_cloud_kms_config) => {
197                SignerConfigValidate::validate(google_cloud_kms_config)
198            }
199        }
200    }
201}
202
203#[derive(Debug, Serialize, Deserialize, Clone)]
204#[serde(deny_unknown_fields)]
205pub struct SignersFileConfig {
206    pub signers: Vec<SignerFileConfig>,
207}
208
209impl SignersFileConfig {
210    pub fn new(signers: Vec<SignerFileConfig>) -> Self {
211        Self { signers }
212    }
213
214    pub fn validate(&self) -> Result<(), ConfigFileError> {
215        if self.signers.is_empty() {
216            return Err(ConfigFileError::MissingField("signers".into()));
217        }
218
219        let mut ids = HashSet::new();
220        for signer in &self.signers {
221            signer.validate_signer()?;
222            if !ids.insert(signer.id.clone()) {
223                return Err(ConfigFileError::DuplicateId(signer.id.clone()));
224            }
225        }
226        Ok(())
227    }
228}
229
230#[cfg(test)]
231mod tests {
232    use crate::models::{PlainOrEnvValue, PlainOrEnvValueError, SecretString};
233
234    use super::*;
235    use serde_json::json;
236    use std::env;
237
238    #[test]
239    fn test_plain_or_env_config_value_plain() {
240        let plain = PlainOrEnvValue::Plain {
241            value: SecretString::new("test-value"),
242        };
243
244        assert_eq!(
245            plain.get_value().unwrap().to_str().as_str(),
246            "test-value".to_string()
247        );
248    }
249
250    #[test]
251    fn test_plain_or_env_config_value_env_exists() {
252        env::set_var("TEST_ENV_VAR", "env-test-value");
253
254        let env_value = PlainOrEnvValue::Env {
255            value: "TEST_ENV_VAR".to_string(),
256        };
257
258        assert_eq!(
259            env_value.get_value().unwrap().to_str().as_str(),
260            "env-test-value".to_string()
261        );
262        env::remove_var("TEST_ENV_VAR");
263    }
264
265    #[test]
266    fn test_plain_or_env_config_value_env_missing() {
267        env::remove_var("NONEXISTENT_TEST_VAR");
268
269        let env_value = PlainOrEnvValue::Env {
270            value: "NONEXISTENT_TEST_VAR".to_string(),
271        };
272
273        let result = env_value.get_value();
274        assert!(result.is_err());
275        assert!(matches!(
276            result,
277            Err(PlainOrEnvValueError::MissingEnvVar(_))
278        ));
279    }
280
281    #[test]
282    fn test_valid_signer_config() {
283        let config = json!({
284            "id": "local-signer",
285            "type": "local",
286            "config": {
287                "path": "tests/utils/test_keys/unit-test-local-signer.json",
288                "passphrase": {
289                    "type": "plain",
290                    "value": "secret",
291                }
292            }
293        });
294
295        let signer_config: SignerFileConfig = serde_json::from_value(config).unwrap();
296        assert!(signer_config.validate_signer().is_ok());
297    }
298
299    #[test]
300    fn test_valid_signer_config_env() {
301        env::set_var("LOCAL_SIGNER_KEY_PASSPHRASE", "mocked_value");
302
303        let config = json!({
304            "id": "local-signer",
305            "type": "local",
306            "config": {
307                "path": "tests/utils/test_keys/unit-test-local-signer.json",
308                "passphrase": {
309                    "type": "env",
310                    "value": "LOCAL_SIGNER_KEY_PASSPHRASE"
311                }
312            }
313        });
314
315        let signer_config: SignerFileConfig = serde_json::from_value(config).unwrap();
316        assert!(signer_config.validate_signer().is_ok());
317        env::remove_var("LOCAL_SIGNER_KEY_PASSPHRASE");
318    }
319
320    #[test]
321    fn test_duplicate_signer_ids() {
322        let config = json!({
323            "signers": [
324                {
325                  "id": "local-signer",
326                  "type": "local",
327                  "config": {
328                      "path": "tests/utils/test_keys/unit-test-local-signer.json",
329                      "passphrase": {
330                          "type": "plain",
331                          "value": "secret",
332                      }
333                  }
334                },
335                {
336                  "id": "local-signer",
337                  "type": "local",
338                  "config": {
339                      "path": "tests/utils/test_keys/unit-test-local-signer.json",
340                      "passphrase": {
341                          "type": "plain",
342                          "value": "secret",
343                      }
344                  }
345                }
346            ]
347        });
348
349        let signer_config: SignersFileConfig = serde_json::from_value(config).unwrap();
350        assert!(matches!(
351            signer_config.validate(),
352            Err(ConfigFileError::DuplicateId(_))
353        ));
354    }
355
356    #[test]
357    fn test_empty_signer_id() {
358        let config = json!({
359            "signers": [
360                {
361                  "id": "",
362                  "type": "local",
363                  "config": {
364                    "path": "tests/utils/test_keys/unit-test-local-signer.json",
365                    "passphrase": {
366                        "type": "plain",
367                        "value": "secret",
368                    }
369                }
370
371                }
372            ]
373        });
374
375        let signer_config: SignersFileConfig = serde_json::from_value(config).unwrap();
376        assert!(matches!(
377            signer_config.validate(),
378            Err(ConfigFileError::InvalidIdLength(_))
379        ));
380    }
381
382    #[test]
383    fn test_validate_test_signer() {
384        let config = json!({
385            "id": "test-signer",
386            "type": "test",
387            "config": {}
388        });
389
390        let signer_config: SignerFileConfig = serde_json::from_value(config).unwrap();
391        assert!(signer_config.validate_signer().is_ok());
392    }
393
394    #[test]
395    fn test_validate_vault_signer() {
396        let config = json!({
397            "id": "vault-signer",
398            "type": "vault",
399            "config": {
400                "address": "https://vault.example.com",
401                "role_id": {
402                    "type":"plain",
403                    "value":"role-123"
404                },
405                "secret_id": {
406                    "type":"plain",
407                    "value":"secret-456"
408                },
409                "key_name": "test-key"
410            }
411        });
412
413        let signer_config: SignerFileConfig = serde_json::from_value(config).unwrap();
414        assert!(signer_config.validate_signer().is_ok());
415    }
416
417    #[test]
418    fn test_validate_vault_cloud_signer() {
419        let config = json!({
420            "id": "vault-cloud-signer",
421            "type": "vault_cloud",
422            "config": {
423                "client_id": "client-123",
424                "client_secret": {
425                    "type": "plain",
426                    "value":"secret-abc"
427                },
428                "org_id": "org-456",
429                "project_id": "proj-789",
430                "app_name": "my-app",
431                "key_name": "cloud-key"
432            }
433        });
434
435        let signer_config: SignerFileConfig = serde_json::from_value(config).unwrap();
436        assert!(signer_config.validate_signer().is_ok());
437    }
438
439    #[test]
440    fn test_validate_vault_transit_signer() {
441        let config = json!({
442            "id": "vault-transit-signer",
443            "type": "vault_transit",
444            "config": {
445                "key_name": "transit-key",
446                "address": "https://vault.example.com",
447                "role_id": {
448                    "type":"plain",
449                    "value":"role-123"
450                },
451                "secret_id": {
452                    "type":"plain",
453                    "value":"secret-456"
454                },
455                "pubkey": "test-pubkey"
456            }
457        });
458
459        let signer_config: SignerFileConfig = serde_json::from_value(config).unwrap();
460        assert!(signer_config.validate_signer().is_ok());
461    }
462
463    #[test]
464    fn test_validate_vault_transit_signer_invalid() {
465        let config = json!({
466            "id": "vault-transit-signer",
467            "type": "vault_transit",
468            "config": {
469                "key_name": "",
470                "address": "https://vault.example.com",
471                "role_id": {
472                    "type":"plain",
473                    "value":"role-123"
474                },
475                "secret_id": {
476                    "type":"plain",
477                    "value":"secret-456"
478                },
479                "pubkey": "test-pubkey"
480            }
481        });
482
483        let signer_config: SignerFileConfig = serde_json::from_value(config).unwrap();
484        assert!(signer_config.validate_signer().is_err());
485    }
486
487    #[test]
488    fn test_validate_turnkey_signer() {
489        let config = json!({
490            "id": "turnkey-signer",
491            "type": "turnkey",
492            "config": {
493                "api_private_key": {"type": "plain", "value": "key"},
494                "api_public_key": "api_public_key",
495                "organization_id": "organization_id",
496                "private_key_id": "private_key_id",
497                "public_key": "public_key",
498            }
499        });
500
501        let signer_config: SignerFileConfig = serde_json::from_value(config).unwrap();
502        assert!(signer_config.validate_signer().is_ok());
503    }
504
505    #[test]
506    fn test_validate_turnkey_invalid() {
507        let config = json!({
508            "id": "turnkey-signer",
509            "type": "turnkey",
510            "config": {
511                "api_private_key": {"type": "plain", "value": "key"},
512                "api_public_key": "",
513                "organization_id": "organization_id",
514                "private_key_id": "private_key_id",
515                "public_key": "public_key",
516            }
517        });
518
519        let signer_config: SignerFileConfig = serde_json::from_value(config).unwrap();
520        assert!(signer_config.validate_signer().is_err());
521    }
522
523    #[test]
524    fn test_validate_google_cloud_kms_signer() {
525        let config = json!({
526            "id": "google-signer",
527            "type": "google_cloud_kms",
528            "config": {
529                "service_account": {
530                    "private_key": {
531                        "type": "plain",
532                        "value": "key"
533                    },
534                    "client_email": {
535                        "type": "plain",
536                        "value": "email"
537                    },
538                    "private_key_id": {
539                        "type": "plain",
540                        "value": "key_id"
541                    },
542                    "project_id": "id",
543                    "client_id": "client_id"
544                },
545                "key": {
546                    "key_id": "my-key",
547                    "key_ring_id": "my-keyring",
548                    "key_version": 1
549                }
550            }
551        });
552
553        let signer_config: SignerFileConfig = serde_json::from_value(config).unwrap();
554        assert!(signer_config.validate_signer().is_ok());
555    }
556
557    #[test]
558    fn test_validate_google_cloud_kms_invalid() {
559        let config = json!({
560            "id": "google-signer",
561            "type": "google_cloud_kms",
562            "config": {
563                "service_account": {
564                    "private_key": {
565                        "type": "plain",
566                        "value": "key"
567                    },
568                    "client_email": {
569                        "type": "plain",
570                        "value": "email"
571                    },
572                    "private_key_id": {
573                        "type": "plain",
574                        "value": "key_id"
575                    },
576                    "project_id": "",
577                    "client_id": "client_id"
578                },
579                "key": {
580                    "key_id": "my-key",
581                    "key_ring_id": "my-keyring",
582                    "key_version": 1
583                }
584            }
585        });
586
587        let signer_config: SignerFileConfig = serde_json::from_value(config).unwrap();
588        assert!(signer_config.validate_signer().is_err());
589    }
590
591    #[test]
592    fn test_empty_signers_array() {
593        let config = json!({
594            "signers": []
595        });
596
597        let signer_config: SignersFileConfig = serde_json::from_value(config).unwrap();
598        let result = signer_config.validate();
599        assert!(result.is_err());
600        assert!(matches!(result, Err(ConfigFileError::MissingField(_))));
601    }
602
603    #[test]
604    fn test_signers_file_config_new() {
605        let signer = SignerFileConfig {
606            id: "test-signer".to_string(),
607            config: SignerFileConfigEnum::Test(TestSignerFileConfig {}),
608        };
609
610        let config = SignersFileConfig::new(vec![signer.clone()]);
611        assert_eq!(config.signers.len(), 1);
612        assert_eq!(config.signers[0].id, "test-signer");
613        assert!(matches!(
614            config.signers[0].config,
615            SignerFileConfigEnum::Test(_)
616        ));
617    }
618
619    #[test]
620    fn test_serde_for_enum_variants() {
621        let test_config = json!({
622            "type": "test",
623            "config": {}
624        });
625        let parsed: SignerFileConfigEnum = serde_json::from_value(test_config).unwrap();
626        assert!(matches!(parsed, SignerFileConfigEnum::Test(_)));
627
628        let local_config = json!({
629            "type": "local",
630            "config": {
631                "path": "test-path",
632                "passphrase": {
633                    "type": "plain",
634                    "value": "test-passphrase"
635                }
636            }
637        });
638        let parsed: SignerFileConfigEnum = serde_json::from_value(local_config).unwrap();
639        assert!(matches!(parsed, SignerFileConfigEnum::Local(_)));
640
641        let vault_config = json!({
642            "type": "vault",
643            "config": {
644                "address": "https://vault.example.com",
645                "role_id": {"type": "plain", "value": "role-123"},
646                "secret_id": { "type": "plain", "value": "secret-456"},
647                "key_name": "test-key"
648            }
649        });
650        let parsed: SignerFileConfigEnum = serde_json::from_value(vault_config).unwrap();
651        assert!(matches!(parsed, SignerFileConfigEnum::Vault(_)));
652
653        let vault_cloud_config = json!({
654            "type": "vault_cloud",
655            "config": {
656                "client_id": "client-123",
657                "client_secret": {"type": "plain", "value": "secret-abc"},
658                "org_id": "org-456",
659                "project_id": "proj-789",
660                "app_name": "my-app",
661                "key_name": "cloud-key"
662            }
663        });
664        let parsed: SignerFileConfigEnum = serde_json::from_value(vault_cloud_config).unwrap();
665        assert!(matches!(parsed, SignerFileConfigEnum::VaultCloud(_)));
666
667        let vault_transit_config = json!({
668            "type": "vault_transit",
669            "config": {
670                "key_name": "transit-key",
671                "address": "https://vault.example.com",
672                "role_id": {"type": "plain", "value": "role-123"},
673                "secret_id": { "type": "plain", "value": "secret-456"},
674                "pubkey": "test-pubkey"
675            }
676        });
677        let parsed: SignerFileConfigEnum = serde_json::from_value(vault_transit_config).unwrap();
678        assert!(matches!(parsed, SignerFileConfigEnum::VaultTransit(_)));
679
680        let aws_kms_config = json!({
681            "type": "aws_kms",
682            "config": {
683                "region": "us-east-1",
684                "key_id": "test-key-id"
685            }
686        });
687        let parsed: SignerFileConfigEnum = serde_json::from_value(aws_kms_config).unwrap();
688        assert!(matches!(parsed, SignerFileConfigEnum::AwsKms(_)));
689
690        let turnkey_config = json!({
691            "type": "turnkey",
692            "config": {
693                "api_private_key": {"type": "plain", "value": "key"},
694                "api_public_key": "api_public_key",
695                "organization_id": "organization_id",
696                "private_key_id": "private_key_id",
697                "public_key": "public_key",
698            }
699        });
700        let parsed: SignerFileConfigEnum = serde_json::from_value(turnkey_config).unwrap();
701        assert!(matches!(parsed, SignerFileConfigEnum::Turnkey(_)));
702
703        let google_config = json!({
704            "type": "google_cloud_kms",
705            "config": {
706                "service_account": {
707                    "private_key": {"type": "plain", "value": "key"},
708                    "client_email": {"type": "plain", "value": "email"},
709                    "private_key_id": {"type": "plain", "value": "key_id"},
710                    "project_id": "id",
711                    "client_id": "client_id"
712                },
713                "key": {
714                    "key_id": "my-key",
715                    "key_ring_id": "my-keyring",
716                    "key_version": 1
717                }
718            }
719        });
720        let parsed: SignerFileConfigEnum = serde_json::from_value(google_config).unwrap();
721        assert!(matches!(parsed, SignerFileConfigEnum::GoogleCloudKms(_)));
722    }
723
724    #[test]
725    fn test_get_methods_for_signer_config() {
726        let test_config = SignerFileConfigEnum::Test(TestSignerFileConfig {});
727        assert!(test_config.get_test().is_some());
728        assert!(test_config.get_local().is_none());
729        assert!(test_config.get_vault().is_none());
730        assert!(test_config.get_vault_cloud().is_none());
731        assert!(test_config.get_vault_transit().is_none());
732        assert!(test_config.get_aws_kms().is_none());
733        assert!(test_config.get_turnkey().is_none());
734        assert!(test_config.get_google_cloud_kms().is_none());
735
736        let local_config = SignerFileConfigEnum::Local(LocalSignerFileConfig {
737            path: "test-path".to_string(),
738            passphrase: PlainOrEnvValue::Plain {
739                value: SecretString::new("test-passphrase"),
740            },
741        });
742        assert!(local_config.get_test().is_none());
743        assert!(local_config.get_local().is_some());
744        assert!(local_config.get_vault().is_none());
745        assert!(local_config.get_vault_cloud().is_none());
746        assert!(local_config.get_vault_transit().is_none());
747        assert!(local_config.get_aws_kms().is_none());
748        assert!(local_config.get_turnkey().is_none());
749        assert!(local_config.get_google_cloud_kms().is_none());
750
751        let vault_config = SignerFileConfigEnum::Vault(VaultSignerFileConfig {
752            address: "https://vault.example.com".to_string(),
753            namespace: None,
754            role_id: PlainOrEnvValue::Plain {
755                value: SecretString::new("role-123"),
756            },
757            secret_id: PlainOrEnvValue::Plain {
758                value: SecretString::new("secret-456"),
759            },
760            key_name: "test-key".to_string(),
761            mount_point: None,
762        });
763        assert!(vault_config.get_test().is_none());
764        assert!(vault_config.get_local().is_none());
765        assert!(vault_config.get_vault().is_some());
766        assert!(vault_config.get_vault_cloud().is_none());
767        assert!(vault_config.get_vault_transit().is_none());
768        assert!(vault_config.get_aws_kms().is_none());
769        assert!(vault_config.get_turnkey().is_none());
770        assert!(vault_config.get_google_cloud_kms().is_none());
771
772        let vault_cloud_config = SignerFileConfigEnum::VaultCloud(VaultCloudSignerFileConfig {
773            client_id: "client-123".to_string(),
774            client_secret: PlainOrEnvValue::Plain {
775                value: SecretString::new("secret-abc"),
776            },
777            org_id: "org-456".to_string(),
778            project_id: "proj-789".to_string(),
779            app_name: "my-app".to_string(),
780            key_name: "cloud-key".to_string(),
781        });
782        assert!(vault_cloud_config.get_test().is_none());
783        assert!(vault_cloud_config.get_local().is_none());
784        assert!(vault_cloud_config.get_vault().is_none());
785        assert!(vault_cloud_config.get_vault_cloud().is_some());
786        assert!(vault_cloud_config.get_vault_transit().is_none());
787        assert!(vault_cloud_config.get_aws_kms().is_none());
788
789        let vault_transit_config =
790            SignerFileConfigEnum::VaultTransit(VaultTransitSignerFileConfig {
791                key_name: "transit-key".to_string(),
792                address: "https://vault.example.com".to_string(),
793                role_id: PlainOrEnvValue::Plain {
794                    value: SecretString::new("role-123"),
795                },
796                secret_id: PlainOrEnvValue::Plain {
797                    value: SecretString::new("secret-456"),
798                },
799                pubkey: "test-pubkey".to_string(),
800                mount_point: None,
801                namespace: None,
802            });
803        assert!(vault_transit_config.get_test().is_none());
804        assert!(vault_transit_config.get_local().is_none());
805        assert!(vault_transit_config.get_vault().is_none());
806        assert!(vault_transit_config.get_vault_cloud().is_none());
807        assert!(vault_transit_config.get_vault_transit().is_some());
808        assert!(vault_transit_config.get_aws_kms().is_none());
809        assert!(vault_transit_config.get_turnkey().is_none());
810        assert!(vault_transit_config.get_google_cloud_kms().is_none());
811
812        let aws_kms_config = SignerFileConfigEnum::AwsKms(AwsKmsSignerFileConfig {
813            region: Some("us-east-1".to_string()),
814            key_id: "test-key-id".to_string(),
815        });
816        assert!(aws_kms_config.get_test().is_none());
817        assert!(aws_kms_config.get_local().is_none());
818        assert!(aws_kms_config.get_vault().is_none());
819        assert!(aws_kms_config.get_vault_cloud().is_none());
820        assert!(aws_kms_config.get_vault_transit().is_none());
821        assert!(aws_kms_config.get_aws_kms().is_some());
822        assert!(aws_kms_config.get_turnkey().is_none());
823        assert!(aws_kms_config.get_google_cloud_kms().is_none());
824
825        let turnkey_config = SignerFileConfigEnum::Turnkey(TurnkeySignerFileConfig {
826            api_private_key: PlainOrEnvValue::Plain {
827                value: SecretString::new("role-123"),
828            },
829            api_public_key: "api_public_key".to_string(),
830            organization_id: "organization_id".to_string(),
831            private_key_id: "private_key_id".to_string(),
832            public_key: "public_key".to_string(),
833        });
834        assert!(turnkey_config.get_test().is_none());
835        assert!(turnkey_config.get_local().is_none());
836        assert!(turnkey_config.get_vault().is_none());
837        assert!(turnkey_config.get_vault_cloud().is_none());
838        assert!(turnkey_config.get_vault_transit().is_none());
839        assert!(turnkey_config.get_aws_kms().is_none());
840        assert!(turnkey_config.get_turnkey().is_some());
841        assert!(turnkey_config.get_google_cloud_kms().is_none());
842
843        let google_cloud_kms_config =
844            SignerFileConfigEnum::GoogleCloudKms(GoogleCloudKmsSignerFileConfig {
845                service_account: ServiceAccountConfig {
846                    private_key: PlainOrEnvValue::Plain {
847                        value: SecretString::new("key"),
848                    },
849                    client_email: PlainOrEnvValue::Plain {
850                        value: SecretString::new("email"),
851                    },
852                    private_key_id: PlainOrEnvValue::Plain {
853                        value: SecretString::new("key_id"),
854                    },
855                    project_id: "id".to_string(),
856                    client_id: "client_id".to_string(),
857                    auth_uri: "uri".to_string(),
858                    token_uri: "uri".to_string(),
859                    client_x509_cert_url: "uri".to_string(),
860                    auth_provider_x509_cert_url: "uri".to_string(),
861                    universe_domain: "uri".to_string(),
862                },
863                key: KmsKeyConfig {
864                    location: "global".to_string(),
865                    key_id: "my-key".to_string(),
866                    key_ring_id: "my-keyring".to_string(),
867                    key_version: 1,
868                },
869            });
870        assert!(google_cloud_kms_config.get_test().is_none());
871        assert!(google_cloud_kms_config.get_local().is_none());
872        assert!(google_cloud_kms_config.get_vault().is_none());
873        assert!(google_cloud_kms_config.get_vault_cloud().is_none());
874        assert!(google_cloud_kms_config.get_vault_transit().is_none());
875        assert!(google_cloud_kms_config.get_aws_kms().is_none());
876        assert!(google_cloud_kms_config.get_turnkey().is_none());
877        assert!(google_cloud_kms_config.get_google_cloud_kms().is_some());
878    }
879}