1use crate::models::{
13 ApiError, AwsKmsSignerConfig, GoogleCloudKmsSignerConfig, GoogleCloudKmsSignerKeyConfig,
14 GoogleCloudKmsSignerServiceAccountConfig, LocalSignerConfig, SecretString, Signer,
15 SignerConfig, TurnkeySignerConfig, VaultSignerConfig, VaultTransitSignerConfig,
16};
17use secrets::SecretVec;
18use serde::{Deserialize, Serialize};
19use utoipa::ToSchema;
20use zeroize::Zeroize;
21
22#[derive(Debug, Serialize, Deserialize, ToSchema, Zeroize)]
24#[serde(deny_unknown_fields)]
25pub struct LocalSignerRequestConfig {
26 pub key: String,
27}
28
29#[derive(Debug, Serialize, Deserialize, ToSchema, Zeroize)]
31#[serde(deny_unknown_fields)]
32pub struct AwsKmsSignerRequestConfig {
33 pub region: String,
34 pub key_id: String,
35}
36
37#[derive(Debug, Serialize, Deserialize, ToSchema, Zeroize)]
39#[serde(deny_unknown_fields)]
40pub struct VaultSignerRequestConfig {
41 pub address: String,
42 #[schema(nullable = false)]
43 pub namespace: Option<String>,
44 pub role_id: String,
45 pub secret_id: String,
46 pub key_name: String,
47 #[schema(nullable = false)]
48 pub mount_point: Option<String>,
49}
50
51#[derive(Debug, Serialize, Deserialize, ToSchema, Zeroize)]
53#[serde(deny_unknown_fields)]
54pub struct VaultTransitSignerRequestConfig {
55 pub key_name: String,
56 pub address: String,
57 #[schema(nullable = false)]
58 pub namespace: Option<String>,
59 pub role_id: String,
60 pub secret_id: String,
61 pub pubkey: String,
62 #[schema(nullable = false)]
63 pub mount_point: Option<String>,
64}
65
66#[derive(Debug, Serialize, Deserialize, ToSchema, Zeroize)]
68#[serde(deny_unknown_fields)]
69pub struct TurnkeySignerRequestConfig {
70 pub api_public_key: String,
71 pub api_private_key: String,
72 pub organization_id: String,
73 pub private_key_id: String,
74 pub public_key: String,
75}
76
77#[derive(Debug, Serialize, Deserialize, ToSchema, Zeroize)]
79#[serde(deny_unknown_fields)]
80pub struct GoogleCloudKmsSignerServiceAccountRequestConfig {
81 pub private_key: String,
82 pub private_key_id: String,
83 pub project_id: String,
84 pub client_email: String,
85 pub client_id: String,
86 pub auth_uri: String,
87 pub token_uri: String,
88 pub auth_provider_x509_cert_url: String,
89 pub client_x509_cert_url: String,
90 pub universe_domain: String,
91}
92
93#[derive(Debug, Serialize, Deserialize, ToSchema, Zeroize)]
95#[serde(deny_unknown_fields)]
96pub struct GoogleCloudKmsSignerKeyRequestConfig {
97 pub location: String,
98 pub key_ring_id: String,
99 pub key_id: String,
100 pub key_version: u32,
101}
102
103#[derive(Debug, Serialize, Deserialize, ToSchema, Zeroize)]
105#[serde(deny_unknown_fields)]
106pub struct GoogleCloudKmsSignerRequestConfig {
107 pub service_account: GoogleCloudKmsSignerServiceAccountRequestConfig,
108 pub key: GoogleCloudKmsSignerKeyRequestConfig,
109}
110
111#[derive(Debug, Serialize, Deserialize, ToSchema, Zeroize)]
113#[serde(untagged)]
114pub enum SignerConfigRequest {
115 Local(LocalSignerRequestConfig),
116 AwsKms(AwsKmsSignerRequestConfig),
117 Vault(VaultSignerRequestConfig),
118 VaultTransit(VaultTransitSignerRequestConfig),
119 Turnkey(TurnkeySignerRequestConfig),
120 GoogleCloudKms(GoogleCloudKmsSignerRequestConfig),
121}
122
123#[derive(Debug, Serialize, Deserialize, ToSchema)]
125#[serde(rename_all = "lowercase")]
126pub enum SignerTypeRequest {
127 #[serde(rename = "plain")]
128 Local,
129 #[serde(rename = "aws_kms")]
130 AwsKms,
131 Vault,
132 #[serde(rename = "vault_transit")]
133 VaultTransit,
134 Turnkey,
135 #[serde(rename = "google_cloud_kms")]
136 GoogleCloudKms,
137}
138
139impl zeroize::Zeroize for SignerTypeRequest {
140 fn zeroize(&mut self) {
141 }
143}
144
145#[derive(Debug, Serialize, Deserialize, ToSchema, Zeroize)]
147#[serde(deny_unknown_fields)]
148pub struct SignerCreateRequest {
149 #[schema(nullable = false)]
151 pub id: Option<String>,
152 #[serde(rename = "type")]
154 pub signer_type: SignerTypeRequest,
155 pub config: SignerConfigRequest,
157}
158
159#[derive(Debug, Serialize, Deserialize, ToSchema, Zeroize)]
162#[serde(deny_unknown_fields)]
163pub struct SignerUpdateRequest {}
164
165impl From<GoogleCloudKmsSignerServiceAccountRequestConfig>
166 for GoogleCloudKmsSignerServiceAccountConfig
167{
168 fn from(config: GoogleCloudKmsSignerServiceAccountRequestConfig) -> Self {
169 Self {
170 private_key: SecretString::new(&config.private_key),
171 private_key_id: SecretString::new(&config.private_key_id),
172 project_id: config.project_id,
173 client_email: SecretString::new(&config.client_email),
174 client_id: config.client_id,
175 auth_uri: config.auth_uri,
176 token_uri: config.token_uri,
177 auth_provider_x509_cert_url: config.auth_provider_x509_cert_url,
178 client_x509_cert_url: config.client_x509_cert_url,
179 universe_domain: config.universe_domain,
180 }
181 }
182}
183
184impl From<GoogleCloudKmsSignerKeyRequestConfig> for GoogleCloudKmsSignerKeyConfig {
185 fn from(config: GoogleCloudKmsSignerKeyRequestConfig) -> Self {
186 Self {
187 location: config.location,
188 key_ring_id: config.key_ring_id,
189 key_id: config.key_id,
190 key_version: config.key_version,
191 }
192 }
193}
194
195impl TryFrom<SignerConfigRequest> for SignerConfig {
196 type Error = ApiError;
197
198 fn try_from(config: SignerConfigRequest) -> Result<Self, Self::Error> {
199 let domain_config = match config {
200 SignerConfigRequest::Local(local_config) => {
201 let key_bytes = hex::decode(&local_config.key)
203 .map_err(|e| ApiError::BadRequest(format!(
204 "Invalid hex key format: {}. Key must be a 64-character hex string (32 bytes).", e
205 )))?;
206
207 let raw_key = SecretVec::new(key_bytes.len(), |buffer| {
208 buffer.copy_from_slice(&key_bytes);
209 });
210
211 SignerConfig::Local(LocalSignerConfig { raw_key })
212 }
213 SignerConfigRequest::AwsKms(aws_config) => SignerConfig::AwsKms(AwsKmsSignerConfig {
214 region: Some(aws_config.region),
215 key_id: aws_config.key_id,
216 }),
217 SignerConfigRequest::Vault(vault_config) => SignerConfig::Vault(VaultSignerConfig {
218 address: vault_config.address,
219 namespace: vault_config.namespace,
220 role_id: SecretString::new(&vault_config.role_id),
221 secret_id: SecretString::new(&vault_config.secret_id),
222 key_name: vault_config.key_name,
223 mount_point: vault_config.mount_point,
224 }),
225 SignerConfigRequest::VaultTransit(vault_transit_config) => {
226 SignerConfig::VaultTransit(VaultTransitSignerConfig {
227 key_name: vault_transit_config.key_name,
228 address: vault_transit_config.address,
229 namespace: vault_transit_config.namespace,
230 role_id: SecretString::new(&vault_transit_config.role_id),
231 secret_id: SecretString::new(&vault_transit_config.secret_id),
232 pubkey: vault_transit_config.pubkey,
233 mount_point: vault_transit_config.mount_point,
234 })
235 }
236 SignerConfigRequest::Turnkey(turnkey_config) => {
237 SignerConfig::Turnkey(TurnkeySignerConfig {
238 api_public_key: turnkey_config.api_public_key,
239 api_private_key: SecretString::new(&turnkey_config.api_private_key),
240 organization_id: turnkey_config.organization_id,
241 private_key_id: turnkey_config.private_key_id,
242 public_key: turnkey_config.public_key,
243 })
244 }
245 SignerConfigRequest::GoogleCloudKms(gcp_kms_config) => {
246 SignerConfig::GoogleCloudKms(GoogleCloudKmsSignerConfig {
247 service_account: gcp_kms_config.service_account.into(),
248 key: gcp_kms_config.key.into(),
249 })
250 }
251 };
252
253 domain_config.validate().map_err(ApiError::from)?;
255
256 Ok(domain_config)
257 }
258}
259
260impl TryFrom<SignerCreateRequest> for Signer {
261 type Error = ApiError;
262
263 fn try_from(request: SignerCreateRequest) -> Result<Self, Self::Error> {
264 let id = request
266 .id
267 .unwrap_or_else(|| uuid::Uuid::new_v4().to_string());
268
269 let config_matches_type = matches!(
271 (&request.signer_type, &request.config),
272 (SignerTypeRequest::Local, SignerConfigRequest::Local(_))
273 | (SignerTypeRequest::AwsKms, SignerConfigRequest::AwsKms(_))
274 | (SignerTypeRequest::Vault, SignerConfigRequest::Vault(_))
275 | (
276 SignerTypeRequest::VaultTransit,
277 SignerConfigRequest::VaultTransit(_)
278 )
279 | (SignerTypeRequest::Turnkey, SignerConfigRequest::Turnkey(_))
280 | (
281 SignerTypeRequest::GoogleCloudKms,
282 SignerConfigRequest::GoogleCloudKms(_)
283 )
284 );
285
286 if !config_matches_type {
287 return Err(ApiError::BadRequest(format!(
288 "Signer type '{:?}' does not match the provided configuration",
289 request.signer_type
290 )));
291 }
292
293 let config = SignerConfig::try_from(request.config)?;
295
296 let signer = Signer::new(id, config);
298
299 signer.validate().map_err(ApiError::from)?;
301
302 Ok(signer)
303 }
304}
305
306#[cfg(test)]
307mod tests {
308 use super::*;
309 use crate::models::signer::SignerType;
310
311 #[test]
312 fn test_json_deserialization_local_signer() {
313 let json = r#"{
314 "id": "test-local-signer",
315 "type": "plain",
316 "config": {
317 "key": "1111111111111111111111111111111111111111111111111111111111111111"
318 }
319 }"#;
320
321 let result: Result<SignerCreateRequest, _> = serde_json::from_str(json);
322
323 assert!(
324 result.is_ok(),
325 "Failed to deserialize local signer: {:?}",
326 result.err()
327 );
328
329 let request = result.unwrap();
330 assert_eq!(request.id, Some("test-local-signer".to_string()));
331
332 match request.config {
333 SignerConfigRequest::Local(local_config) => {
334 assert_eq!(
335 local_config.key,
336 "1111111111111111111111111111111111111111111111111111111111111111"
337 );
338 }
339 _ => panic!("Expected Local config variant"),
340 }
341 }
342
343 #[test]
344 fn test_json_deserialization_aws_kms_signer() {
345 let json = r#"{
346 "id": "test-aws-signer",
347 "type": "aws_kms",
348 "config": {
349 "region": "us-east-1",
350 "key_id": "test-key-id"
351 }
352 }"#;
353
354 let result: Result<SignerCreateRequest, _> = serde_json::from_str(json);
355
356 assert!(
357 result.is_ok(),
358 "Failed to deserialize AWS KMS signer: {:?}",
359 result.err()
360 );
361
362 let request = result.unwrap();
363 assert_eq!(request.id, Some("test-aws-signer".to_string()));
364
365 match request.config {
366 SignerConfigRequest::AwsKms(aws_config) => {
367 assert_eq!(aws_config.region, "us-east-1");
368 assert_eq!(aws_config.key_id, "test-key-id");
369 }
370 _ => panic!("Expected AwsKms config variant"),
371 }
372 }
373
374 #[test]
375 fn test_json_deserialization_vault_signer() {
376 let json = r#"{
377 "id": "test-vault-signer",
378 "type": "vault",
379 "config": {
380 "address": "https://vault.example.com",
381 "namespace": null,
382 "role_id": "test-role-id",
383 "secret_id": "test-secret-id",
384 "key_name": "test-key",
385 "mount_point": null
386 }
387 }"#;
388
389 let result: Result<SignerCreateRequest, _> = serde_json::from_str(json);
390
391 assert!(
392 result.is_ok(),
393 "Failed to deserialize Vault signer: {:?}",
394 result.err()
395 );
396
397 let request = result.unwrap();
398 assert_eq!(request.id, Some("test-vault-signer".to_string()));
399
400 match request.config {
401 SignerConfigRequest::Vault(vault_config) => {
402 assert_eq!(vault_config.address, "https://vault.example.com");
403 assert_eq!(vault_config.namespace, None);
404 assert_eq!(vault_config.role_id, "test-role-id");
405 assert_eq!(vault_config.secret_id, "test-secret-id");
406 assert_eq!(vault_config.key_name, "test-key");
407 assert_eq!(vault_config.mount_point, None);
408 }
409 _ => panic!("Expected Vault config variant"),
410 }
411 }
412
413 #[test]
414 fn test_json_deserialization_turnkey_signer() {
415 let json = r#"{
416 "id": "test-turnkey-signer",
417 "type": "turnkey",
418 "config": {
419 "api_public_key": "test-public-key",
420 "api_private_key": "test-private-key",
421 "organization_id": "test-org",
422 "private_key_id": "test-private-key-id",
423 "public_key": "test-public-key"
424 }
425 }"#;
426
427 let result: Result<SignerCreateRequest, _> = serde_json::from_str(json);
428
429 assert!(
430 result.is_ok(),
431 "Failed to deserialize Turnkey signer: {:?}",
432 result.err()
433 );
434
435 let request = result.unwrap();
436 assert_eq!(request.id, Some("test-turnkey-signer".to_string()));
437
438 match request.config {
439 SignerConfigRequest::Turnkey(turnkey_config) => {
440 assert_eq!(turnkey_config.api_public_key, "test-public-key");
441 assert_eq!(turnkey_config.api_private_key, "test-private-key");
442 assert_eq!(turnkey_config.organization_id, "test-org");
443 assert_eq!(turnkey_config.private_key_id, "test-private-key-id");
444 assert_eq!(turnkey_config.public_key, "test-public-key");
445 }
446 _ => panic!("Expected Turnkey config variant"),
447 }
448 }
449
450 #[test]
451 fn test_json_serialization_local_signer() {
452 let request = SignerCreateRequest {
453 id: Some("test-local-signer".to_string()),
454 signer_type: SignerTypeRequest::Local,
455 config: SignerConfigRequest::Local(LocalSignerRequestConfig {
456 key: "1111111111111111111111111111111111111111111111111111111111111111".to_string(),
457 }),
458 };
459
460 let json_result = serde_json::to_string_pretty(&request);
461
462 assert!(
463 json_result.is_ok(),
464 "Failed to serialize local signer: {:?}",
465 json_result.err()
466 );
467
468 let json = json_result.unwrap();
469
470 let deserialize_result: Result<SignerCreateRequest, _> = serde_json::from_str(&json);
472 assert!(
473 deserialize_result.is_ok(),
474 "Failed to deserialize back: {:?}",
475 deserialize_result.err()
476 );
477 }
478
479 #[test]
480 fn test_json_serialization_aws_kms_signer() {
481 let request = SignerCreateRequest {
482 id: Some("test-aws-signer".to_string()),
483 signer_type: SignerTypeRequest::AwsKms,
484 config: SignerConfigRequest::AwsKms(AwsKmsSignerRequestConfig {
485 region: "us-east-1".to_string(),
486 key_id: "test-key-id".to_string(),
487 }),
488 };
489
490 let json_result = serde_json::to_string_pretty(&request);
491
492 assert!(
493 json_result.is_ok(),
494 "Failed to serialize AWS KMS signer: {:?}",
495 json_result.err()
496 );
497
498 let json = json_result.unwrap();
499
500 let deserialize_result: Result<SignerCreateRequest, _> = serde_json::from_str(&json);
502 assert!(
503 deserialize_result.is_ok(),
504 "Failed to deserialize back: {:?}",
505 deserialize_result.err()
506 );
507 }
508
509 #[test]
510 fn test_type_config_mismatch_validation() {
511 let json = r#"{
513 "id": "test-mismatch-signer",
514 "type": "aws_kms",
515 "config": {
516 "key": "1111111111111111111111111111111111111111111111111111111111111111"
517 }
518 }"#;
519
520 let result: Result<SignerCreateRequest, _> = serde_json::from_str(json);
521
522 assert!(result.is_ok(), "JSON deserialization should succeed");
524
525 let request = result.unwrap();
526
527 let signer_result = Signer::try_from(request);
529 assert!(
530 signer_result.is_err(),
531 "Type mismatch should cause validation error"
532 );
533
534 if let Err(ApiError::BadRequest(msg)) = signer_result {
535 assert!(
536 msg.contains("does not match"),
537 "Error should mention type mismatch: {}",
538 msg
539 );
540 } else {
541 panic!("Expected BadRequest error for type mismatch");
542 }
543 }
544
545 #[test]
547 fn test_valid_aws_kms_create_request() {
548 let request = SignerCreateRequest {
549 id: Some("test-aws-signer".to_string()),
550 signer_type: SignerTypeRequest::AwsKms,
551 config: SignerConfigRequest::AwsKms(AwsKmsSignerRequestConfig {
552 region: "us-east-1".to_string(),
553 key_id: "test-key-id".to_string(),
554 }),
555 };
556
557 let result = Signer::try_from(request);
558 assert!(result.is_ok());
559
560 let signer = result.unwrap();
561 assert_eq!(signer.id, "test-aws-signer");
562 assert_eq!(signer.signer_type(), SignerType::AwsKms);
563
564 if let Some(aws_config) = signer.config.get_aws_kms() {
566 assert_eq!(aws_config.region, Some("us-east-1".to_string()));
567 assert_eq!(aws_config.key_id, "test-key-id");
568 } else {
569 panic!("Expected AWS KMS config");
570 }
571 }
572
573 #[test]
574 fn test_valid_vault_create_request() {
575 let request = SignerCreateRequest {
576 id: Some("test-vault-signer".to_string()),
577 signer_type: SignerTypeRequest::Vault,
578 config: SignerConfigRequest::Vault(VaultSignerRequestConfig {
579 address: "https://vault.example.com".to_string(),
580 namespace: None,
581 role_id: "test-role-id".to_string(),
582 secret_id: "test-secret-id".to_string(),
583 key_name: "test-key".to_string(),
584 mount_point: None,
585 }),
586 };
587
588 let result = Signer::try_from(request);
589 assert!(result.is_ok());
590
591 let signer = result.unwrap();
592 assert_eq!(signer.id, "test-vault-signer");
593 assert_eq!(signer.signer_type(), SignerType::Vault);
594 }
595
596 #[test]
597 fn test_invalid_aws_kms_empty_key_id() {
598 let request = SignerCreateRequest {
599 id: Some("test-signer".to_string()),
600 signer_type: SignerTypeRequest::AwsKms,
601 config: SignerConfigRequest::AwsKms(AwsKmsSignerRequestConfig {
602 region: "us-east-1".to_string(),
603 key_id: "".to_string(), }),
605 };
606
607 let result = Signer::try_from(request);
608 assert!(result.is_err());
609
610 if let Err(ApiError::BadRequest(msg)) = result {
611 assert!(msg.contains("Key ID cannot be empty"));
612 } else {
613 panic!("Expected BadRequest error for empty key ID");
614 }
615 }
616
617 #[test]
618 fn test_invalid_vault_empty_address() {
619 let request = SignerCreateRequest {
620 id: Some("test-signer".to_string()),
621 signer_type: SignerTypeRequest::Vault,
622 config: SignerConfigRequest::Vault(VaultSignerRequestConfig {
623 address: "".to_string(), namespace: None,
625 role_id: "test-role".to_string(),
626 secret_id: "test-secret".to_string(),
627 key_name: "test-key".to_string(),
628 mount_point: None,
629 }),
630 };
631
632 let result = Signer::try_from(request);
633 assert!(result.is_err());
634 }
635
636 #[test]
637 fn test_invalid_vault_invalid_url() {
638 let request = SignerCreateRequest {
639 id: Some("test-signer".to_string()),
640 signer_type: SignerTypeRequest::Vault,
641 config: SignerConfigRequest::Vault(VaultSignerRequestConfig {
642 address: "not-a-url".to_string(), namespace: None,
644 role_id: "test-role".to_string(),
645 secret_id: "test-secret".to_string(),
646 key_name: "test-key".to_string(),
647 mount_point: None,
648 }),
649 };
650
651 let result = Signer::try_from(request);
652 assert!(result.is_err());
653
654 if let Err(ApiError::BadRequest(msg)) = result {
655 assert!(msg.contains("Address must be a valid URL"));
656 } else {
657 panic!("Expected BadRequest error for invalid URL");
658 }
659 }
660
661 #[test]
662 fn test_create_request_generates_uuid_when_no_id() {
663 let request = SignerCreateRequest {
664 id: None,
665 signer_type: SignerTypeRequest::Local,
666 config: SignerConfigRequest::Local(LocalSignerRequestConfig {
667 key: "1111111111111111111111111111111111111111111111111111111111111111".to_string(), }),
669 };
670
671 let result = Signer::try_from(request);
672 assert!(result.is_ok());
673
674 let signer = result.unwrap();
675 assert!(!signer.id.is_empty());
676 assert_eq!(signer.signer_type(), SignerType::Local);
677
678 assert!(uuid::Uuid::parse_str(&signer.id).is_ok());
680 }
681
682 #[test]
683 fn test_invalid_id_format() {
684 let request = SignerCreateRequest {
685 id: Some("invalid@id".to_string()), signer_type: SignerTypeRequest::Local,
687 config: SignerConfigRequest::Local(LocalSignerRequestConfig {
688 key: "2222222222222222222222222222222222222222222222222222222222222222".to_string(), }),
690 };
691
692 let result = Signer::try_from(request);
693 assert!(result.is_err());
694
695 if let Err(ApiError::BadRequest(msg)) = result {
696 assert!(msg.contains("ID must contain only letters, numbers, dashes and underscores"));
697 } else {
698 panic!("Expected BadRequest error with validation message");
699 }
700 }
701
702 #[test]
703 fn test_test_signer_creation() {
704 let request = SignerCreateRequest {
705 id: Some("test-signer".to_string()),
706 signer_type: SignerTypeRequest::Local,
707 config: SignerConfigRequest::Local(LocalSignerRequestConfig {
708 key: "3333333333333333333333333333333333333333333333333333333333333333".to_string(), }),
710 };
711
712 let result = Signer::try_from(request);
713 assert!(result.is_ok());
714
715 let signer = result.unwrap();
716 assert_eq!(signer.id, "test-signer");
717 assert_eq!(signer.signer_type(), SignerType::Local);
718 }
719
720 #[test]
721 fn test_local_signer_creation() {
722 let request = SignerCreateRequest {
723 id: Some("local-signer".to_string()),
724 signer_type: SignerTypeRequest::Local,
725 config: SignerConfigRequest::Local(LocalSignerRequestConfig {
726 key: "4444444444444444444444444444444444444444444444444444444444444444".to_string(), }),
728 };
729
730 let result = Signer::try_from(request);
731 assert!(result.is_ok());
732
733 let signer = result.unwrap();
734 assert_eq!(signer.id, "local-signer");
735 assert_eq!(signer.signer_type(), SignerType::Local);
736 }
737
738 #[test]
739 fn test_valid_turnkey_create_request() {
740 let request = SignerCreateRequest {
741 id: Some("test-turnkey-signer".to_string()),
742 signer_type: SignerTypeRequest::Turnkey,
743 config: SignerConfigRequest::Turnkey(TurnkeySignerRequestConfig {
744 api_public_key: "test-public-key".to_string(),
745 api_private_key: "test-private-key".to_string(),
746 organization_id: "test-org".to_string(),
747 private_key_id: "test-private-key-id".to_string(),
748 public_key: "test-public-key".to_string(),
749 }),
750 };
751
752 let result = Signer::try_from(request);
753 assert!(result.is_ok());
754
755 let signer = result.unwrap();
756 assert_eq!(signer.id, "test-turnkey-signer");
757 assert_eq!(signer.signer_type(), SignerType::Turnkey);
758
759 if let Some(turnkey_config) = signer.config.get_turnkey() {
760 assert_eq!(turnkey_config.api_public_key, "test-public-key");
761 assert_eq!(turnkey_config.organization_id, "test-org");
762 } else {
763 panic!("Expected Turnkey config");
764 }
765 }
766
767 #[test]
768 fn test_valid_vault_transit_create_request() {
769 let request = SignerCreateRequest {
770 id: Some("test-vault-transit-signer".to_string()),
771 signer_type: SignerTypeRequest::VaultTransit,
772 config: SignerConfigRequest::VaultTransit(VaultTransitSignerRequestConfig {
773 key_name: "test-key".to_string(),
774 address: "https://vault.example.com".to_string(),
775 namespace: None,
776 role_id: "test-role".to_string(),
777 secret_id: "test-secret".to_string(),
778 pubkey: "test-pubkey".to_string(),
779 mount_point: None,
780 }),
781 };
782
783 let result = Signer::try_from(request);
784 assert!(result.is_ok());
785
786 let signer = result.unwrap();
787 assert_eq!(signer.id, "test-vault-transit-signer");
788 assert_eq!(signer.signer_type(), SignerType::VaultTransit);
789 }
790
791 #[test]
792 fn test_valid_google_cloud_kms_create_request() {
793 let request = SignerCreateRequest {
794 id: Some("test-gcp-kms-signer".to_string()),
795 signer_type: SignerTypeRequest::GoogleCloudKms,
796 config: SignerConfigRequest::GoogleCloudKms(GoogleCloudKmsSignerRequestConfig {
797 service_account: GoogleCloudKmsSignerServiceAccountRequestConfig {
798 private_key: "test-private-key".to_string(),
799 private_key_id: "test-key-id".to_string(),
800 project_id: "test-project".to_string(),
801 client_email: "test@email.com".to_string(),
802 client_id: "test-client-id".to_string(),
803 auth_uri: "https://accounts.google.com/o/oauth2/auth".to_string(),
804 token_uri: "https://oauth2.googleapis.com/token".to_string(),
805 auth_provider_x509_cert_url: "https://www.googleapis.com/oauth2/v1/certs".to_string(),
806 client_x509_cert_url: "https://www.googleapis.com/robot/v1/metadata/x509/test%40test.iam.gserviceaccount.com".to_string(),
807 universe_domain: "googleapis.com".to_string(),
808 },
809 key: GoogleCloudKmsSignerKeyRequestConfig {
810 location: "global".to_string(),
811 key_ring_id: "test-ring".to_string(),
812 key_id: "test-key".to_string(),
813 key_version: 1,
814 },
815 }),
816 };
817
818 let result = Signer::try_from(request);
819 assert!(result.is_ok());
820
821 let signer = result.unwrap();
822 assert_eq!(signer.id, "test-gcp-kms-signer");
823 assert_eq!(signer.signer_type(), SignerType::GoogleCloudKms);
824 }
825
826 #[test]
827 fn test_invalid_local_hex_key() {
828 let request = SignerCreateRequest {
829 id: Some("test-signer".to_string()),
830 signer_type: SignerTypeRequest::Local,
831 config: SignerConfigRequest::Local(LocalSignerRequestConfig {
832 key: "invalid-hex".to_string(), }),
834 };
835
836 let result = Signer::try_from(request);
837 assert!(result.is_err());
838 if let Err(ApiError::BadRequest(msg)) = result {
839 assert!(msg.contains("Invalid hex key format"));
840 }
841 }
842
843 #[test]
844 fn test_invalid_turnkey_empty_key() {
845 let request = SignerCreateRequest {
846 id: Some("test-signer".to_string()),
847 signer_type: SignerTypeRequest::Turnkey,
848 config: SignerConfigRequest::Turnkey(TurnkeySignerRequestConfig {
849 api_public_key: "".to_string(), api_private_key: "test-private-key".to_string(),
851 organization_id: "test-org".to_string(),
852 private_key_id: "test-private-key-id".to_string(),
853 public_key: "test-public-key".to_string(),
854 }),
855 };
856
857 let result = Signer::try_from(request);
858 assert!(result.is_err());
859 if let Err(ApiError::BadRequest(msg)) = result {
860 assert!(msg.contains("API public key cannot be empty"));
861 }
862 }
863}