openzeppelin_relayer/models/signer/
repository.rs

1//! Repository layer models and data persistence for signers.
2//!
3//! This module provides the data layer representation of signers, including:
4//!
5//! - **Repository Models**: Data structures optimized for storage and retrieval
6//! - **Data Conversions**: Mapping between domain objects and repository representations
7//! - **Persistence Logic**: Storage-specific validation and constraints
8//!
9//! Acts as the bridge between the domain layer and actual data storage implementations
10//! (in-memory, Redis, etc.), ensuring consistent data representation across repositories.
11//!
12
13use crate::{
14    models::{
15        signer::{
16            AwsKmsSignerConfig, AzureKeyVaultAuthType, AzureKeyVaultSignerConfig, CdpSignerConfig,
17            GoogleCloudKmsSignerConfig, GoogleCloudKmsSignerKeyConfig,
18            GoogleCloudKmsSignerServiceAccountConfig, LocalSignerConfig, Signer, SignerConfig,
19            SignerValidationError, TurnkeySignerConfig, VaultSignerConfig,
20            VaultTransitSignerConfig,
21        },
22        SecretString,
23    },
24    utils::{
25        deserialize_option_secret_string, deserialize_secret_string, deserialize_secret_vec,
26        serialize_option_secret_string, serialize_secret_string, serialize_secret_vec,
27    },
28};
29use secrets::SecretVec;
30use serde::{Deserialize, Serialize};
31/// Repository model for signer storage and retrieval
32#[derive(Debug, Clone, Serialize, Deserialize)]
33pub struct SignerRepoModel {
34    pub id: String,
35    pub config: SignerConfigStorage,
36}
37
38#[derive(Debug, Clone, Serialize, Deserialize)]
39pub enum SignerConfigStorage {
40    Local(LocalSignerConfigStorage),
41    Vault(VaultSignerConfigStorage),
42    VaultTransit(VaultTransitSignerConfigStorage),
43    AwsKms(AwsKmsSignerConfigStorage),
44    AzureKeyVault(AzureKeyVaultSignerConfigStorage),
45    Turnkey(TurnkeySignerConfigStorage),
46    Cdp(CdpSignerConfigStorage),
47    GoogleCloudKms(Box<GoogleCloudKmsSignerConfigStorage>),
48}
49
50/// Local signer configuration for storage (with base64 encoding)
51#[derive(Debug, Clone, Serialize, Deserialize)]
52pub struct LocalSignerConfigStorage {
53    #[serde(
54        serialize_with = "serialize_secret_vec",
55        deserialize_with = "deserialize_secret_vec"
56    )]
57    pub raw_key: SecretVec<u8>,
58}
59
60impl From<LocalSignerConfig> for LocalSignerConfigStorage {
61    fn from(config: LocalSignerConfig) -> Self {
62        Self {
63            raw_key: config.raw_key,
64        }
65    }
66}
67
68impl From<LocalSignerConfigStorage> for LocalSignerConfig {
69    fn from(storage: LocalSignerConfigStorage) -> Self {
70        Self {
71            raw_key: storage.raw_key,
72        }
73    }
74}
75
76/// Storage representations for other signer types (these are simpler as they don't contain secrets that need encoding)
77#[derive(Debug, Clone, Serialize, Deserialize)]
78pub struct AwsKmsSignerConfigStorage {
79    pub region: Option<String>,
80    pub key_id: String,
81}
82
83#[derive(Debug, Clone, Serialize, Deserialize)]
84pub struct AzureKeyVaultSignerConfigStorage {
85    pub auth_type: Option<AzureKeyVaultAuthType>,
86    #[serde(
87        serialize_with = "serialize_option_secret_string",
88        deserialize_with = "deserialize_option_secret_string"
89    )]
90    pub tenant_id: Option<SecretString>,
91    #[serde(
92        serialize_with = "serialize_option_secret_string",
93        deserialize_with = "deserialize_option_secret_string"
94    )]
95    pub client_id: Option<SecretString>,
96    #[serde(
97        serialize_with = "serialize_option_secret_string",
98        deserialize_with = "deserialize_option_secret_string"
99    )]
100    pub client_secret: Option<SecretString>,
101    #[serde(
102        serialize_with = "serialize_option_secret_string",
103        deserialize_with = "deserialize_option_secret_string"
104    )]
105    pub federated_token_file: Option<SecretString>,
106    #[serde(
107        serialize_with = "serialize_secret_string",
108        deserialize_with = "deserialize_secret_string"
109    )]
110    pub vault_url: SecretString,
111    #[serde(
112        serialize_with = "serialize_secret_string",
113        deserialize_with = "deserialize_secret_string"
114    )]
115    pub key_name: SecretString,
116    pub key_version: Option<String>,
117}
118
119#[derive(Debug, Clone, Serialize, Deserialize)]
120pub struct VaultSignerConfigStorage {
121    pub address: String,
122    pub namespace: Option<String>,
123    #[serde(
124        serialize_with = "serialize_secret_string",
125        deserialize_with = "deserialize_secret_string"
126    )]
127    pub role_id: SecretString,
128    #[serde(
129        serialize_with = "serialize_secret_string",
130        deserialize_with = "deserialize_secret_string"
131    )]
132    pub secret_id: SecretString,
133    pub key_name: String,
134    pub mount_point: Option<String>,
135}
136
137#[derive(Debug, Clone, Serialize, Deserialize)]
138pub struct VaultTransitSignerConfigStorage {
139    pub key_name: String,
140    pub address: String,
141    pub namespace: Option<String>,
142    #[serde(
143        serialize_with = "serialize_secret_string",
144        deserialize_with = "deserialize_secret_string"
145    )]
146    pub role_id: SecretString,
147    #[serde(
148        serialize_with = "serialize_secret_string",
149        deserialize_with = "deserialize_secret_string"
150    )]
151    pub secret_id: SecretString,
152    pub pubkey: String,
153    pub mount_point: Option<String>,
154}
155
156#[derive(Debug, Clone, Serialize, Deserialize)]
157pub struct TurnkeySignerConfigStorage {
158    pub api_public_key: String,
159    #[serde(
160        serialize_with = "serialize_secret_string",
161        deserialize_with = "deserialize_secret_string"
162    )]
163    pub api_private_key: SecretString,
164    pub organization_id: String,
165    pub private_key_id: String,
166    pub public_key: String,
167}
168
169#[derive(Debug, Clone, Serialize, Deserialize)]
170pub struct CdpSignerConfigStorage {
171    pub api_key_id: String,
172    #[serde(
173        serialize_with = "serialize_secret_string",
174        deserialize_with = "deserialize_secret_string"
175    )]
176    pub api_key_secret: SecretString,
177    #[serde(
178        serialize_with = "serialize_secret_string",
179        deserialize_with = "deserialize_secret_string"
180    )]
181    pub wallet_secret: SecretString,
182    pub account_address: String,
183}
184
185/// Storage model for Google Cloud KMS service account configuration.
186#[derive(Debug, Clone, Serialize, Deserialize)]
187pub struct GoogleCloudKmsSignerServiceAccountConfigStorage {
188    #[serde(
189        serialize_with = "serialize_secret_string",
190        deserialize_with = "deserialize_secret_string"
191    )]
192    pub private_key: SecretString,
193    #[serde(
194        serialize_with = "serialize_secret_string",
195        deserialize_with = "deserialize_secret_string"
196    )]
197    pub private_key_id: SecretString,
198    #[serde(
199        serialize_with = "serialize_secret_string",
200        deserialize_with = "deserialize_secret_string"
201    )]
202    pub project_id: SecretString,
203    #[serde(
204        serialize_with = "serialize_secret_string",
205        deserialize_with = "deserialize_secret_string"
206    )]
207    pub client_email: SecretString,
208    #[serde(
209        serialize_with = "serialize_secret_string",
210        deserialize_with = "deserialize_secret_string"
211    )]
212    pub client_id: SecretString,
213    #[serde(
214        serialize_with = "serialize_secret_string",
215        deserialize_with = "deserialize_secret_string"
216    )]
217    pub auth_uri: SecretString,
218    #[serde(
219        serialize_with = "serialize_secret_string",
220        deserialize_with = "deserialize_secret_string"
221    )]
222    pub token_uri: SecretString,
223    #[serde(
224        serialize_with = "serialize_secret_string",
225        deserialize_with = "deserialize_secret_string"
226    )]
227    pub auth_provider_x509_cert_url: SecretString,
228    #[serde(
229        serialize_with = "serialize_secret_string",
230        deserialize_with = "deserialize_secret_string"
231    )]
232    pub client_x509_cert_url: SecretString,
233    #[serde(
234        serialize_with = "serialize_secret_string",
235        deserialize_with = "deserialize_secret_string"
236    )]
237    pub universe_domain: SecretString,
238}
239
240/// Storage model for Google Cloud KMS key configuration.
241///
242/// All string fields are encrypted at rest to prevent attackers from
243/// modifying key identifiers to point to different keys.
244#[derive(Debug, Clone, Serialize, Deserialize)]
245pub struct GoogleCloudKmsSignerKeyConfigStorage {
246    #[serde(
247        serialize_with = "serialize_secret_string",
248        deserialize_with = "deserialize_secret_string"
249    )]
250    pub location: SecretString,
251    #[serde(
252        serialize_with = "serialize_secret_string",
253        deserialize_with = "deserialize_secret_string"
254    )]
255    pub key_ring_id: SecretString,
256    #[serde(
257        serialize_with = "serialize_secret_string",
258        deserialize_with = "deserialize_secret_string"
259    )]
260    pub key_id: SecretString,
261    pub key_version: u32,
262}
263
264#[derive(Debug, Clone, Serialize, Deserialize)]
265pub struct GoogleCloudKmsSignerConfigStorage {
266    pub service_account: GoogleCloudKmsSignerServiceAccountConfigStorage,
267    pub key: GoogleCloudKmsSignerKeyConfigStorage,
268}
269
270/// Convert from domain model to repository model
271impl From<Signer> for SignerRepoModel {
272    fn from(signer: Signer) -> Self {
273        Self {
274            id: signer.id,
275            config: signer.config.into(),
276        }
277    }
278}
279
280/// Convert from repository model to domain model
281impl From<SignerRepoModel> for Signer {
282    fn from(repo_model: SignerRepoModel) -> Self {
283        Self {
284            id: repo_model.id,
285            config: repo_model.config.into(),
286        }
287    }
288}
289
290impl From<AwsKmsSignerConfig> for AwsKmsSignerConfigStorage {
291    fn from(config: AwsKmsSignerConfig) -> Self {
292        Self {
293            region: config.region,
294            key_id: config.key_id,
295        }
296    }
297}
298
299impl From<AwsKmsSignerConfigStorage> for AwsKmsSignerConfig {
300    fn from(storage: AwsKmsSignerConfigStorage) -> Self {
301        Self {
302            region: storage.region,
303            key_id: storage.key_id,
304        }
305    }
306}
307
308impl From<AzureKeyVaultSignerConfig> for AzureKeyVaultSignerConfigStorage {
309    fn from(config: AzureKeyVaultSignerConfig) -> Self {
310        Self {
311            auth_type: config.auth_type,
312            tenant_id: config.tenant_id,
313            client_id: config.client_id,
314            client_secret: config.client_secret,
315            federated_token_file: config.federated_token_file,
316            vault_url: config.vault_url,
317            key_name: config.key_name,
318            key_version: config.key_version,
319        }
320    }
321}
322
323impl From<AzureKeyVaultSignerConfigStorage> for AzureKeyVaultSignerConfig {
324    fn from(storage: AzureKeyVaultSignerConfigStorage) -> Self {
325        Self {
326            auth_type: storage.auth_type,
327            tenant_id: storage.tenant_id,
328            client_id: storage.client_id,
329            client_secret: storage.client_secret,
330            federated_token_file: storage.federated_token_file,
331            vault_url: storage.vault_url,
332            key_name: storage.key_name,
333            key_version: storage.key_version,
334        }
335    }
336}
337
338impl From<VaultSignerConfig> for VaultSignerConfigStorage {
339    fn from(config: VaultSignerConfig) -> Self {
340        Self {
341            address: config.address,
342            namespace: config.namespace,
343            role_id: config.role_id,
344            secret_id: config.secret_id,
345            key_name: config.key_name,
346            mount_point: config.mount_point,
347        }
348    }
349}
350
351impl From<VaultSignerConfigStorage> for VaultSignerConfig {
352    fn from(storage: VaultSignerConfigStorage) -> Self {
353        Self {
354            address: storage.address,
355            namespace: storage.namespace,
356            role_id: storage.role_id,
357            secret_id: storage.secret_id,
358            key_name: storage.key_name,
359            mount_point: storage.mount_point,
360        }
361    }
362}
363
364impl From<VaultTransitSignerConfig> for VaultTransitSignerConfigStorage {
365    fn from(config: VaultTransitSignerConfig) -> Self {
366        Self {
367            key_name: config.key_name,
368            address: config.address,
369            namespace: config.namespace,
370            role_id: config.role_id,
371            secret_id: config.secret_id,
372            pubkey: config.pubkey,
373            mount_point: config.mount_point,
374        }
375    }
376}
377
378impl From<VaultTransitSignerConfigStorage> for VaultTransitSignerConfig {
379    fn from(storage: VaultTransitSignerConfigStorage) -> Self {
380        Self {
381            key_name: storage.key_name,
382            address: storage.address,
383            namespace: storage.namespace,
384            role_id: storage.role_id,
385            secret_id: storage.secret_id,
386            pubkey: storage.pubkey,
387            mount_point: storage.mount_point,
388        }
389    }
390}
391
392impl From<TurnkeySignerConfig> for TurnkeySignerConfigStorage {
393    fn from(config: TurnkeySignerConfig) -> Self {
394        Self {
395            api_public_key: config.api_public_key,
396            api_private_key: config.api_private_key,
397            organization_id: config.organization_id,
398            private_key_id: config.private_key_id,
399            public_key: config.public_key,
400        }
401    }
402}
403
404impl From<TurnkeySignerConfigStorage> for TurnkeySignerConfig {
405    fn from(storage: TurnkeySignerConfigStorage) -> Self {
406        Self {
407            api_public_key: storage.api_public_key,
408            api_private_key: storage.api_private_key,
409            organization_id: storage.organization_id,
410            private_key_id: storage.private_key_id,
411            public_key: storage.public_key,
412        }
413    }
414}
415
416impl From<CdpSignerConfig> for CdpSignerConfigStorage {
417    fn from(config: CdpSignerConfig) -> Self {
418        Self {
419            api_key_id: config.api_key_id,
420            api_key_secret: config.api_key_secret,
421            wallet_secret: config.wallet_secret,
422            account_address: config.account_address,
423        }
424    }
425}
426
427impl From<CdpSignerConfigStorage> for CdpSignerConfig {
428    fn from(storage: CdpSignerConfigStorage) -> Self {
429        Self {
430            api_key_id: storage.api_key_id,
431            api_key_secret: storage.api_key_secret,
432            wallet_secret: storage.wallet_secret,
433            account_address: storage.account_address,
434        }
435    }
436}
437
438impl From<GoogleCloudKmsSignerConfig> for GoogleCloudKmsSignerConfigStorage {
439    fn from(config: GoogleCloudKmsSignerConfig) -> Self {
440        Self {
441            service_account: config.service_account.into(),
442            key: config.key.into(),
443        }
444    }
445}
446
447impl From<GoogleCloudKmsSignerConfigStorage> for GoogleCloudKmsSignerConfig {
448    fn from(storage: GoogleCloudKmsSignerConfigStorage) -> Self {
449        Self {
450            service_account: storage.service_account.into(),
451            key: storage.key.into(),
452        }
453    }
454}
455
456impl From<GoogleCloudKmsSignerServiceAccountConfig>
457    for GoogleCloudKmsSignerServiceAccountConfigStorage
458{
459    fn from(config: GoogleCloudKmsSignerServiceAccountConfig) -> Self {
460        Self {
461            private_key: config.private_key,
462            private_key_id: config.private_key_id,
463            project_id: config.project_id,
464            client_email: config.client_email,
465            client_id: config.client_id,
466            auth_uri: config.auth_uri,
467            token_uri: config.token_uri,
468            auth_provider_x509_cert_url: config.auth_provider_x509_cert_url,
469            client_x509_cert_url: config.client_x509_cert_url,
470            universe_domain: config.universe_domain,
471        }
472    }
473}
474
475impl From<GoogleCloudKmsSignerServiceAccountConfigStorage>
476    for GoogleCloudKmsSignerServiceAccountConfig
477{
478    fn from(storage: GoogleCloudKmsSignerServiceAccountConfigStorage) -> Self {
479        Self {
480            private_key: storage.private_key,
481            private_key_id: storage.private_key_id,
482            project_id: storage.project_id,
483            client_email: storage.client_email,
484            client_id: storage.client_id,
485            auth_uri: storage.auth_uri,
486            token_uri: storage.token_uri,
487            auth_provider_x509_cert_url: storage.auth_provider_x509_cert_url,
488            client_x509_cert_url: storage.client_x509_cert_url,
489            universe_domain: storage.universe_domain,
490        }
491    }
492}
493
494impl From<GoogleCloudKmsSignerKeyConfig> for GoogleCloudKmsSignerKeyConfigStorage {
495    fn from(config: GoogleCloudKmsSignerKeyConfig) -> Self {
496        Self {
497            location: config.location,
498            key_ring_id: config.key_ring_id,
499            key_id: config.key_id,
500            key_version: config.key_version,
501        }
502    }
503}
504
505impl From<GoogleCloudKmsSignerKeyConfigStorage> for GoogleCloudKmsSignerKeyConfig {
506    fn from(storage: GoogleCloudKmsSignerKeyConfigStorage) -> Self {
507        Self {
508            location: storage.location,
509            key_ring_id: storage.key_ring_id,
510            key_id: storage.key_id,
511            key_version: storage.key_version,
512        }
513    }
514}
515
516impl SignerRepoModel {
517    /// Validates the repository model using core validation logic
518    pub fn validate(&self) -> Result<(), SignerValidationError> {
519        let core_signer = Signer::from(self.clone());
520        core_signer.validate()
521    }
522}
523
524impl From<SignerConfig> for SignerConfigStorage {
525    fn from(config: SignerConfig) -> Self {
526        match config {
527            SignerConfig::Local(local) => SignerConfigStorage::Local(local.into()),
528            SignerConfig::Vault(vault) => SignerConfigStorage::Vault(vault.into()),
529            SignerConfig::VaultTransit(vault_transit) => {
530                SignerConfigStorage::VaultTransit(vault_transit.into())
531            }
532            SignerConfig::AwsKms(aws_kms) => SignerConfigStorage::AwsKms(aws_kms.into()),
533            SignerConfig::AzureKeyVault(azure) => SignerConfigStorage::AzureKeyVault(azure.into()),
534            SignerConfig::Turnkey(turnkey) => SignerConfigStorage::Turnkey(turnkey.into()),
535            SignerConfig::Cdp(cdp) => SignerConfigStorage::Cdp(cdp.into()),
536            SignerConfig::GoogleCloudKms(gcp) => {
537                SignerConfigStorage::GoogleCloudKms(Box::new((*gcp).into()))
538            }
539        }
540    }
541}
542
543impl From<SignerConfigStorage> for SignerConfig {
544    fn from(storage: SignerConfigStorage) -> Self {
545        match storage {
546            SignerConfigStorage::Local(local) => SignerConfig::Local(local.into()),
547            SignerConfigStorage::Vault(vault) => SignerConfig::Vault(vault.into()),
548            SignerConfigStorage::VaultTransit(vault_transit) => {
549                SignerConfig::VaultTransit(vault_transit.into())
550            }
551            SignerConfigStorage::AwsKms(aws_kms) => SignerConfig::AwsKms(aws_kms.into()),
552            SignerConfigStorage::AzureKeyVault(azure) => SignerConfig::AzureKeyVault(azure.into()),
553            SignerConfigStorage::Turnkey(turnkey) => SignerConfig::Turnkey(turnkey.into()),
554            SignerConfigStorage::Cdp(cdp) => SignerConfig::Cdp(cdp.into()),
555            SignerConfigStorage::GoogleCloudKms(gcp) => {
556                SignerConfig::GoogleCloudKms(Box::new((*gcp).into()))
557            }
558        }
559    }
560}
561
562impl SignerConfigStorage {
563    /// Get local signer config, returns error if not a local signer
564    pub fn get_local(&self) -> Option<&LocalSignerConfigStorage> {
565        match self {
566            Self::Local(config) => Some(config),
567            _ => None,
568        }
569    }
570
571    /// Get vault transit signer config, returns error if not a vault transit signer
572    pub fn get_vault_transit(&self) -> Option<&VaultTransitSignerConfigStorage> {
573        match self {
574            Self::VaultTransit(config) => Some(config),
575            _ => None,
576        }
577    }
578
579    /// Get vault signer config, returns error if not a vault signer
580    pub fn get_vault(&self) -> Option<&VaultSignerConfigStorage> {
581        match self {
582            Self::Vault(config) => Some(config),
583            _ => None,
584        }
585    }
586
587    /// Get turnkey signer config, returns error if not a turnkey signer
588    pub fn get_turnkey(&self) -> Option<&TurnkeySignerConfigStorage> {
589        match self {
590            Self::Turnkey(config) => Some(config),
591            _ => None,
592        }
593    }
594
595    /// Get CDP signer config, returns error if not a CDP signer
596    pub fn get_cdp(&self) -> Option<&CdpSignerConfigStorage> {
597        match self {
598            Self::Cdp(config) => Some(config),
599            _ => None,
600        }
601    }
602
603    /// Get google cloud kms signer config, returns error if not a google cloud kms signer
604    pub fn get_google_cloud_kms(&self) -> Option<&GoogleCloudKmsSignerConfigStorage> {
605        match self {
606            Self::GoogleCloudKms(config) => Some(config),
607            _ => None,
608        }
609    }
610
611    /// Get aws kms signer config, returns error if not an aws kms signer
612    pub fn get_aws_kms(&self) -> Option<&AwsKmsSignerConfigStorage> {
613        match self {
614            Self::AwsKms(config) => Some(config),
615            _ => None,
616        }
617    }
618
619    /// Get azure key vault signer config, returns error if not an azure key vault signer
620    pub fn get_azure_key_vault(&self) -> Option<&AzureKeyVaultSignerConfigStorage> {
621        match self {
622            Self::AzureKeyVault(config) => Some(config),
623            _ => None,
624        }
625    }
626}
627
628#[cfg(test)]
629mod tests {
630    use super::*;
631    use crate::models::signer::{LocalSignerConfig, SignerConfig};
632    use secrets::SecretVec;
633
634    #[test]
635    fn test_from_core_signer() {
636        let config = LocalSignerConfig {
637            raw_key: SecretVec::new(32, |v| v.fill(1)),
638        };
639
640        let core =
641            crate::models::signer::Signer::new("test-id".to_string(), SignerConfig::Local(config));
642
643        let repo_model = SignerRepoModel::from(core);
644        assert_eq!(repo_model.id, "test-id");
645        assert!(matches!(repo_model.config, SignerConfigStorage::Local(_)));
646    }
647
648    #[test]
649    fn test_to_core_signer() {
650        use crate::models::signer::AwsKmsSignerConfigStorage;
651
652        let domain_config = AwsKmsSignerConfigStorage {
653            region: Some("us-east-1".to_string()),
654            key_id: "test-key".to_string(),
655        };
656
657        let repo_model = SignerRepoModel {
658            id: "test-id".to_string(),
659            config: SignerConfigStorage::AwsKms(domain_config),
660        };
661
662        let core = Signer::from(repo_model);
663        assert_eq!(core.id, "test-id");
664        assert_eq!(
665            core.signer_type(),
666            crate::models::signer::SignerType::AwsKms
667        );
668    }
669
670    #[test]
671    fn test_validation() {
672        use secrets::SecretVec;
673
674        let domain_config = LocalSignerConfig {
675            raw_key: SecretVec::new(32, |v| v.fill(1)),
676        };
677        // Convert to storage config properly
678        let storage_config = LocalSignerConfigStorage::from(domain_config);
679
680        let repo_model = SignerRepoModel {
681            id: "test-id".to_string(),
682            config: SignerConfigStorage::Local(storage_config),
683        };
684
685        assert!(repo_model.validate().is_ok());
686    }
687
688    #[test]
689    fn test_local_config_storage_conversion() {
690        let domain_config = LocalSignerConfig {
691            raw_key: SecretVec::new(4, |v| v.copy_from_slice(&[1, 2, 3, 4])),
692        };
693
694        let storage_config = LocalSignerConfigStorage::from(domain_config.clone());
695        let converted_back = LocalSignerConfig::from(storage_config);
696
697        // Compare the actual secret data
698        let original_data = domain_config.raw_key.borrow();
699        let converted_data = converted_back.raw_key.borrow();
700        assert_eq!(*original_data, *converted_data);
701    }
702
703    #[test]
704    fn test_cdp_config_storage_conversion() {
705        use crate::models::SecretString;
706
707        let domain_config = CdpSignerConfig {
708            api_key_id: "test-api-key-id".to_string(),
709            api_key_secret: SecretString::new("test-api-secret"),
710            wallet_secret: SecretString::new("test-wallet-secret"),
711            account_address: "0x1234567890123456789012345678901234567890".to_string(),
712        };
713
714        let storage_config = CdpSignerConfigStorage::from(domain_config.clone());
715        let converted_back = CdpSignerConfig::from(storage_config);
716
717        assert_eq!(domain_config.api_key_id, converted_back.api_key_id);
718        assert_eq!(
719            domain_config.account_address,
720            converted_back.account_address
721        );
722        assert_eq!(
723            domain_config.api_key_secret.to_str(),
724            converted_back.api_key_secret.to_str()
725        );
726        assert_eq!(
727            domain_config.wallet_secret.to_str(),
728            converted_back.wallet_secret.to_str()
729        );
730    }
731
732    #[test]
733    fn test_signer_config_storage_get_cdp() {
734        use crate::models::SecretString;
735
736        let cdp_storage = CdpSignerConfigStorage {
737            api_key_id: "test-id".to_string(),
738            api_key_secret: SecretString::new("secret"),
739            wallet_secret: SecretString::new("wallet-secret"),
740            account_address: "0x1234567890123456789012345678901234567890".to_string(),
741        };
742
743        let config_storage = SignerConfigStorage::Cdp(cdp_storage);
744        let retrieved_cdp = config_storage.get_cdp();
745        assert!(retrieved_cdp.is_some());
746        assert_eq!(retrieved_cdp.unwrap().api_key_id, "test-id");
747    }
748
749    #[test]
750    fn test_signer_config_storage_get_cdp_from_non_cdp() {
751        let aws_storage = AwsKmsSignerConfigStorage {
752            region: Some("us-east-1".to_string()),
753            key_id: "test-key".to_string(),
754        };
755
756        let config_storage = SignerConfigStorage::AwsKms(aws_storage);
757        let retrieved_cdp = config_storage.get_cdp();
758        assert!(retrieved_cdp.is_none());
759    }
760}