1use serde::{Deserialize, Serialize};
4use std::collections::HashMap;
5
6use super::auth::OAuth2Config;
7
8#[derive(Debug, Clone, Serialize, Deserialize)]
10#[serde(default)]
11#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
12#[derive(Default)]
13pub struct DeceptiveDeployConfig {
14 pub enabled: bool,
16 pub cors: Option<ProductionCorsConfig>,
18 pub rate_limit: Option<ProductionRateLimitConfig>,
20 #[serde(default)]
22 pub headers: HashMap<String, String>,
23 pub oauth: Option<ProductionOAuthConfig>,
25 pub custom_domain: Option<String>,
27 pub auto_tunnel: bool,
29 #[serde(skip_serializing_if = "Option::is_none")]
31 pub canary: Option<crate::deceptive_canary::DeceptiveCanaryConfig>,
32}
33
34impl DeceptiveDeployConfig {
35 pub fn production_preset() -> Self {
37 let mut headers = HashMap::new();
38 headers.insert("X-API-Version".to_string(), "1.0".to_string());
39 headers.insert("X-Request-ID".to_string(), "{{uuid}}".to_string());
40 headers.insert("X-Powered-By".to_string(), "MockForge".to_string());
41
42 Self {
43 enabled: true,
44 cors: Some(ProductionCorsConfig {
45 allowed_origins: vec!["*".to_string()],
46 allowed_methods: vec![
47 "GET".to_string(),
48 "POST".to_string(),
49 "PUT".to_string(),
50 "DELETE".to_string(),
51 "PATCH".to_string(),
52 "OPTIONS".to_string(),
53 ],
54 allowed_headers: vec!["*".to_string()],
55 allow_credentials: true,
56 }),
57 rate_limit: Some(ProductionRateLimitConfig {
58 requests_per_minute: 1000,
59 burst: 2000,
60 per_ip: true,
61 }),
62 headers,
63 oauth: None, custom_domain: None,
65 auto_tunnel: true,
66 canary: None,
67 }
68 }
69}
70
71#[derive(Debug, Clone, Serialize, Deserialize)]
73#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
74pub struct ProductionCorsConfig {
75 #[serde(default)]
77 pub allowed_origins: Vec<String>,
78 #[serde(default)]
80 pub allowed_methods: Vec<String>,
81 #[serde(default)]
83 pub allowed_headers: Vec<String>,
84 pub allow_credentials: bool,
86}
87
88#[derive(Debug, Clone, Serialize, Deserialize)]
90#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
91pub struct ProductionRateLimitConfig {
92 pub requests_per_minute: u32,
94 pub burst: u32,
96 pub per_ip: bool,
98}
99
100#[derive(Debug, Clone, Serialize, Deserialize)]
102#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
103pub struct ProductionOAuthConfig {
104 pub client_id: String,
106 pub client_secret: String,
108 pub introspection_url: String,
110 pub auth_url: Option<String>,
112 pub token_url: Option<String>,
114 pub token_type_hint: Option<String>,
116}
117
118impl From<ProductionOAuthConfig> for OAuth2Config {
119 fn from(prod: ProductionOAuthConfig) -> Self {
121 OAuth2Config {
122 client_id: prod.client_id,
123 client_secret: prod.client_secret,
124 introspection_url: prod.introspection_url,
125 auth_url: prod.auth_url,
126 token_url: prod.token_url,
127 token_type_hint: prod.token_type_hint,
128 }
129 }
130}
131
132#[derive(Debug, Clone, Serialize, Deserialize)]
134#[serde(default)]
135#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
136#[derive(Default)]
137pub struct PerformanceConfig {
138 pub compression: CompressionConfig,
140 pub connection_pool: ConnectionPoolConfig,
142 pub request_limits: RequestLimitsConfig,
144 pub workers: WorkerConfig,
146 pub circuit_breaker: CircuitBreakerConfig,
148}
149
150#[derive(Debug, Clone, Serialize, Deserialize)]
152#[serde(default)]
153#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
154pub struct CompressionConfig {
155 pub enabled: bool,
157 pub algorithm: String,
159 pub min_size: usize,
161 pub level: u32,
163 pub content_types: Vec<String>,
165}
166
167impl Default for CompressionConfig {
168 fn default() -> Self {
169 Self {
170 enabled: true,
171 algorithm: "gzip".to_string(),
172 min_size: 1024, level: 6,
174 content_types: vec![
175 "application/json".to_string(),
176 "application/xml".to_string(),
177 "text/plain".to_string(),
178 "text/html".to_string(),
179 "text/css".to_string(),
180 "application/javascript".to_string(),
181 ],
182 }
183 }
184}
185
186#[derive(Debug, Clone, Serialize, Deserialize)]
188#[serde(default)]
189#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
190pub struct ConnectionPoolConfig {
191 pub max_idle_per_host: usize,
193 pub max_connections: usize,
195 pub idle_timeout_secs: u64,
197 pub acquire_timeout_ms: u64,
199 pub enabled: bool,
201}
202
203impl Default for ConnectionPoolConfig {
204 fn default() -> Self {
205 Self {
206 max_idle_per_host: 10,
207 max_connections: 100,
208 idle_timeout_secs: 90,
209 acquire_timeout_ms: 5000,
210 enabled: true,
211 }
212 }
213}
214
215#[derive(Debug, Clone, Serialize, Deserialize)]
217#[serde(default)]
218#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
219pub struct RequestLimitsConfig {
220 pub max_body_size: usize,
222 pub max_header_size: usize,
224 pub max_headers: usize,
226 pub max_uri_length: usize,
228 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
230 pub per_route_limits: HashMap<String, usize>,
231}
232
233impl Default for RequestLimitsConfig {
234 fn default() -> Self {
235 Self {
236 max_body_size: 10 * 1024 * 1024, max_header_size: 16 * 1024, max_headers: 100,
239 max_uri_length: 8192,
240 per_route_limits: HashMap::new(),
241 }
242 }
243}
244
245#[derive(Debug, Clone, Serialize, Deserialize)]
247#[serde(default)]
248#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
249pub struct WorkerConfig {
250 pub threads: usize,
252 pub blocking_threads: usize,
254 pub stack_size: usize,
256 pub name_prefix: String,
258}
259
260impl Default for WorkerConfig {
261 fn default() -> Self {
262 Self {
263 threads: 0, blocking_threads: 512,
265 stack_size: 2 * 1024 * 1024, name_prefix: "mockforge-worker".to_string(),
267 }
268 }
269}
270
271#[derive(Debug, Clone, Serialize, Deserialize)]
273#[serde(default)]
274#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
275pub struct CircuitBreakerConfig {
276 pub enabled: bool,
278 pub failure_threshold: u32,
280 pub success_threshold: u32,
282 pub half_open_timeout_secs: u64,
284 pub window_size: u32,
286 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
288 pub per_endpoint: HashMap<String, EndpointCircuitBreakerConfig>,
289}
290
291impl Default for CircuitBreakerConfig {
292 fn default() -> Self {
293 Self {
294 enabled: false,
295 failure_threshold: 5,
296 success_threshold: 2,
297 half_open_timeout_secs: 30,
298 window_size: 10,
299 per_endpoint: HashMap::new(),
300 }
301 }
302}
303
304#[derive(Debug, Clone, Serialize, Deserialize)]
306#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
307pub struct EndpointCircuitBreakerConfig {
308 pub failure_threshold: u32,
310 pub success_threshold: u32,
312 pub half_open_timeout_secs: u64,
314}
315
316#[derive(Debug, Clone, Serialize, Deserialize)]
318#[serde(default)]
319#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
320pub struct ConfigHotReloadConfig {
321 pub enabled: bool,
323 pub check_interval_secs: u64,
325 pub debounce_delay_ms: u64,
327 #[serde(default, skip_serializing_if = "Vec::is_empty")]
329 pub watch_paths: Vec<String>,
330 pub reload_on_spec_change: bool,
332 pub reload_on_fixture_change: bool,
334 pub reload_on_plugin_change: bool,
336 pub graceful_reload: bool,
338 pub graceful_timeout_secs: u64,
340 pub validate_before_reload: bool,
342 pub rollback_on_failure: bool,
344}
345
346impl Default for ConfigHotReloadConfig {
347 fn default() -> Self {
348 Self {
349 enabled: false,
350 check_interval_secs: 5,
351 debounce_delay_ms: 1000,
352 watch_paths: Vec::new(),
353 reload_on_spec_change: true,
354 reload_on_fixture_change: true,
355 reload_on_plugin_change: true,
356 graceful_reload: true,
357 graceful_timeout_secs: 30,
358 validate_before_reload: true,
359 rollback_on_failure: true,
360 }
361 }
362}
363
364#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
366#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
367#[serde(rename_all = "lowercase")]
368pub enum SecretBackendType {
369 #[default]
371 None,
372 Vault,
374 AwsSecretsManager,
376 AzureKeyVault,
378 GcpSecretManager,
380 Kubernetes,
382 EncryptedFile,
384}
385
386#[derive(Debug, Clone, Serialize, Deserialize)]
388#[serde(default)]
389#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
390pub struct SecretBackendConfig {
391 pub provider: SecretBackendType,
393 #[serde(skip_serializing_if = "Option::is_none")]
395 pub vault: Option<VaultConfig>,
396 #[serde(skip_serializing_if = "Option::is_none")]
398 pub aws: Option<AwsSecretsConfig>,
399 #[serde(skip_serializing_if = "Option::is_none")]
401 pub azure: Option<AzureKeyVaultConfig>,
402 #[serde(skip_serializing_if = "Option::is_none")]
404 pub gcp: Option<GcpSecretManagerConfig>,
405 #[serde(skip_serializing_if = "Option::is_none")]
407 pub kubernetes: Option<KubernetesSecretsConfig>,
408 #[serde(skip_serializing_if = "Option::is_none")]
410 pub encrypted_file: Option<EncryptedFileConfig>,
411 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
413 pub mappings: HashMap<String, String>,
414 pub cache_ttl_secs: u64,
416 pub retry_attempts: u32,
418 pub retry_delay_ms: u64,
420}
421
422impl Default for SecretBackendConfig {
423 fn default() -> Self {
424 Self {
425 provider: SecretBackendType::None,
426 vault: None,
427 aws: None,
428 azure: None,
429 gcp: None,
430 kubernetes: None,
431 encrypted_file: None,
432 mappings: HashMap::new(),
433 cache_ttl_secs: 300, retry_attempts: 3,
435 retry_delay_ms: 1000,
436 }
437 }
438}
439
440#[derive(Debug, Clone, Serialize, Deserialize)]
442#[serde(default)]
443#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
444pub struct VaultConfig {
445 pub address: String,
447 #[serde(skip_serializing_if = "Option::is_none")]
449 pub namespace: Option<String>,
450 pub auth_method: VaultAuthMethod,
452 #[serde(skip_serializing_if = "Option::is_none")]
454 pub token: Option<String>,
455 #[serde(skip_serializing_if = "Option::is_none")]
457 pub role_id: Option<String>,
458 #[serde(skip_serializing_if = "Option::is_none")]
460 pub secret_id: Option<String>,
461 #[serde(skip_serializing_if = "Option::is_none")]
463 pub kubernetes_role: Option<String>,
464 pub mount_path: String,
466 pub path_prefix: String,
468 #[serde(skip_serializing_if = "Option::is_none")]
470 pub ca_cert_path: Option<String>,
471 pub skip_verify: bool,
473 pub timeout_secs: u64,
475}
476
477impl Default for VaultConfig {
478 fn default() -> Self {
479 Self {
480 address: "http://127.0.0.1:8200".to_string(),
481 namespace: None,
482 auth_method: VaultAuthMethod::Token,
483 token: None,
484 role_id: None,
485 secret_id: None,
486 kubernetes_role: None,
487 mount_path: "secret".to_string(),
488 path_prefix: "mockforge".to_string(),
489 ca_cert_path: None,
490 skip_verify: false,
491 timeout_secs: 30,
492 }
493 }
494}
495
496#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
498#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
499#[serde(rename_all = "lowercase")]
500pub enum VaultAuthMethod {
501 #[default]
503 Token,
504 AppRole,
506 Kubernetes,
508 AwsIam,
510 GitHub,
512 Ldap,
514 Userpass,
516}
517
518#[derive(Debug, Clone, Serialize, Deserialize)]
520#[serde(default)]
521#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
522pub struct AwsSecretsConfig {
523 pub region: String,
525 pub prefix: String,
527 pub use_iam_role: bool,
529 #[serde(skip_serializing_if = "Option::is_none")]
531 pub access_key_id: Option<String>,
532 #[serde(skip_serializing_if = "Option::is_none")]
534 pub secret_access_key: Option<String>,
535 #[serde(skip_serializing_if = "Option::is_none")]
537 pub endpoint_url: Option<String>,
538}
539
540impl Default for AwsSecretsConfig {
541 fn default() -> Self {
542 Self {
543 region: "us-east-1".to_string(),
544 prefix: "mockforge".to_string(),
545 use_iam_role: true,
546 access_key_id: None,
547 secret_access_key: None,
548 endpoint_url: None,
549 }
550 }
551}
552
553#[derive(Debug, Clone, Serialize, Deserialize)]
555#[serde(default)]
556#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
557pub struct AzureKeyVaultConfig {
558 pub vault_url: String,
560 #[serde(skip_serializing_if = "Option::is_none")]
562 pub tenant_id: Option<String>,
563 #[serde(skip_serializing_if = "Option::is_none")]
565 pub client_id: Option<String>,
566 #[serde(skip_serializing_if = "Option::is_none")]
568 pub client_secret: Option<String>,
569 pub use_managed_identity: bool,
571 pub prefix: String,
573}
574
575impl Default for AzureKeyVaultConfig {
576 fn default() -> Self {
577 Self {
578 vault_url: String::new(),
579 tenant_id: None,
580 client_id: None,
581 client_secret: None,
582 use_managed_identity: true,
583 prefix: "mockforge".to_string(),
584 }
585 }
586}
587
588#[derive(Debug, Clone, Serialize, Deserialize)]
590#[serde(default)]
591#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
592pub struct GcpSecretManagerConfig {
593 pub project_id: String,
595 pub prefix: String,
597 #[serde(skip_serializing_if = "Option::is_none")]
599 pub credentials_file: Option<String>,
600 pub use_default_credentials: bool,
602}
603
604impl Default for GcpSecretManagerConfig {
605 fn default() -> Self {
606 Self {
607 project_id: String::new(),
608 prefix: "mockforge".to_string(),
609 credentials_file: None,
610 use_default_credentials: true,
611 }
612 }
613}
614
615#[derive(Debug, Clone, Serialize, Deserialize)]
617#[serde(default)]
618#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
619pub struct KubernetesSecretsConfig {
620 pub namespace: String,
622 pub prefix: String,
624 #[serde(skip_serializing_if = "Option::is_none")]
626 pub label_selector: Option<String>,
627 pub in_cluster: bool,
629 #[serde(skip_serializing_if = "Option::is_none")]
631 pub kubeconfig_path: Option<String>,
632}
633
634impl Default for KubernetesSecretsConfig {
635 fn default() -> Self {
636 Self {
637 namespace: "default".to_string(),
638 prefix: "mockforge".to_string(),
639 label_selector: None,
640 in_cluster: true,
641 kubeconfig_path: None,
642 }
643 }
644}
645
646#[derive(Debug, Clone, Serialize, Deserialize)]
648#[serde(default)]
649#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
650pub struct EncryptedFileConfig {
651 pub file_path: String,
653 pub algorithm: String,
655 pub kdf: String,
657 #[serde(skip_serializing_if = "Option::is_none")]
659 pub master_key_env: Option<String>,
660 #[serde(skip_serializing_if = "Option::is_none")]
662 pub key_file: Option<String>,
663}
664
665impl Default for EncryptedFileConfig {
666 fn default() -> Self {
667 Self {
668 file_path: "secrets.enc".to_string(),
669 algorithm: "aes-256-gcm".to_string(),
670 kdf: "argon2id".to_string(),
671 master_key_env: Some("MOCKFORGE_MASTER_KEY".to_string()),
672 key_file: None,
673 }
674 }
675}
676
677#[derive(Debug, Clone, Serialize, Deserialize)]
679#[serde(default)]
680#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
681pub struct PluginResourceConfig {
682 pub enabled: bool,
684 pub max_memory_per_plugin: usize,
686 pub max_cpu_per_plugin: f64,
688 pub max_execution_time_ms: u64,
690 pub allow_network_access: bool,
692 #[serde(default, skip_serializing_if = "Vec::is_empty")]
694 pub allowed_fs_paths: Vec<String>,
695 pub max_concurrent_executions: usize,
697 #[serde(skip_serializing_if = "Option::is_none")]
699 pub cache_dir: Option<String>,
700 pub debug_logging: bool,
702 pub max_module_size: usize,
704 pub max_table_elements: usize,
706 pub max_stack_size: usize,
708}
709
710impl Default for PluginResourceConfig {
711 fn default() -> Self {
712 Self {
713 enabled: true,
714 max_memory_per_plugin: 10 * 1024 * 1024, max_cpu_per_plugin: 0.5, max_execution_time_ms: 5000, allow_network_access: false,
718 allowed_fs_paths: Vec::new(),
719 max_concurrent_executions: 10,
720 cache_dir: None,
721 debug_logging: false,
722 max_module_size: 5 * 1024 * 1024, max_table_elements: 1000,
724 max_stack_size: 2 * 1024 * 1024, }
726 }
727}
728
729#[derive(Debug, Clone, Serialize, Deserialize)]
731#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
732#[serde(default)]
733pub struct LoggingConfig {
734 pub level: String,
736 pub json_format: bool,
738 pub file_path: Option<String>,
740 pub max_file_size_mb: u64,
742 pub max_files: u32,
744}
745
746impl Default for LoggingConfig {
747 fn default() -> Self {
748 Self {
749 level: "info".to_string(),
750 json_format: false,
751 file_path: None,
752 max_file_size_mb: 10,
753 max_files: 5,
754 }
755 }
756}
757
758#[derive(Debug, Clone, Serialize, Deserialize)]
760#[serde(default, rename_all = "camelCase")]
761#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
762pub struct ChainingConfig {
763 pub enabled: bool,
765 pub max_chain_length: usize,
767 pub global_timeout_secs: u64,
769 pub enable_parallel_execution: bool,
771}
772
773impl Default for ChainingConfig {
774 fn default() -> Self {
775 Self {
776 enabled: false,
777 max_chain_length: 20,
778 global_timeout_secs: 300,
779 enable_parallel_execution: false,
780 }
781 }
782}
783
784#[derive(Debug, Clone, Serialize, Deserialize)]
786#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
787#[serde(default)]
788pub struct DataConfig {
789 pub default_rows: usize,
791 pub default_format: String,
793 pub locale: String,
795 pub templates: HashMap<String, String>,
797 pub rag: RagConfig,
799 #[serde(skip_serializing_if = "Option::is_none")]
801 pub persona_domain: Option<String>,
802 #[serde(default = "default_false")]
804 pub persona_consistency_enabled: bool,
805 #[serde(skip_serializing_if = "Option::is_none")]
807 pub persona_registry: Option<PersonaRegistryConfig>,
808}
809
810impl Default for DataConfig {
811 fn default() -> Self {
812 Self {
813 default_rows: 100,
814 default_format: "json".to_string(),
815 locale: "en".to_string(),
816 templates: HashMap::new(),
817 rag: RagConfig::default(),
818 persona_domain: None,
819 persona_consistency_enabled: false,
820 persona_registry: None,
821 }
822 }
823}
824
825#[derive(Debug, Clone, Serialize, Deserialize)]
827#[serde(default)]
828#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
829pub struct RagConfig {
830 pub enabled: bool,
832 #[serde(default)]
834 pub provider: String,
835 pub api_endpoint: Option<String>,
837 pub api_key: Option<String>,
839 pub model: Option<String>,
841 #[serde(default = "default_max_tokens")]
843 pub max_tokens: usize,
844 #[serde(default = "default_temperature")]
846 pub temperature: f64,
847 pub context_window: usize,
849 #[serde(default = "default_true")]
851 pub caching: bool,
852 #[serde(default = "default_cache_ttl")]
854 pub cache_ttl_secs: u64,
855 #[serde(default = "default_timeout")]
857 pub timeout_secs: u64,
858 #[serde(default = "default_max_retries")]
860 pub max_retries: usize,
861}
862
863fn default_max_tokens() -> usize {
864 1024
865}
866
867fn default_temperature() -> f64 {
868 0.7
869}
870
871fn default_true() -> bool {
872 true
873}
874
875fn default_cache_ttl() -> u64 {
876 3600
877}
878
879fn default_timeout() -> u64 {
880 30
881}
882
883fn default_max_retries() -> usize {
884 3
885}
886
887pub(crate) fn default_false() -> bool {
888 false
889}
890
891impl Default for RagConfig {
892 fn default() -> Self {
893 Self {
894 enabled: false,
895 provider: "openai".to_string(),
896 api_endpoint: None,
897 api_key: None,
898 model: Some("gpt-3.5-turbo".to_string()),
899 max_tokens: default_max_tokens(),
900 temperature: default_temperature(),
901 context_window: 4000,
902 caching: default_true(),
903 cache_ttl_secs: default_cache_ttl(),
904 timeout_secs: default_timeout(),
905 max_retries: default_max_retries(),
906 }
907 }
908}
909
910#[derive(Debug, Clone, Serialize, Deserialize)]
912#[serde(default)]
913#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
914#[derive(Default)]
915pub struct PersonaRegistryConfig {
916 #[serde(default = "default_false")]
918 pub persistent: bool,
919 #[serde(skip_serializing_if = "Option::is_none")]
921 pub storage_path: Option<String>,
922 #[serde(default)]
924 pub default_traits: HashMap<String, String>,
925}
926
927#[derive(Debug, Clone, Serialize, Deserialize)]
929#[serde(default)]
930#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
931pub struct MockAIConfig {
932 pub enabled: bool,
934 pub intelligent_behavior: crate::intelligent_behavior::IntelligentBehaviorConfig,
936 pub auto_learn: bool,
938 pub mutation_detection: bool,
940 pub ai_validation_errors: bool,
942 pub intelligent_pagination: bool,
944 #[serde(default)]
946 pub enabled_endpoints: Vec<String>,
947}
948
949impl Default for MockAIConfig {
950 fn default() -> Self {
951 Self {
952 enabled: false,
953 intelligent_behavior: crate::intelligent_behavior::IntelligentBehaviorConfig::default(),
954 auto_learn: true,
955 mutation_detection: true,
956 ai_validation_errors: true,
957 intelligent_pagination: true,
958 enabled_endpoints: Vec::new(),
959 }
960 }
961}
962
963#[derive(Debug, Clone, Serialize, Deserialize, Default)]
965#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
966#[serde(default)]
967pub struct ObservabilityConfig {
968 pub prometheus: PrometheusConfig,
970 pub opentelemetry: Option<OpenTelemetryConfig>,
972 pub recorder: Option<RecorderConfig>,
974 pub chaos: Option<ChaosEngConfig>,
976}
977
978#[derive(Debug, Clone, Serialize, Deserialize)]
980#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
981#[serde(default)]
982#[derive(Default)]
983pub struct SecurityConfig {
984 pub monitoring: SecurityMonitoringConfig,
986}
987
988#[derive(Debug, Clone, Serialize, Deserialize)]
990#[serde(default)]
991#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
992#[derive(Default)]
993pub struct SecurityMonitoringConfig {
994 pub siem: crate::security::siem::SiemConfig,
996 pub access_review: crate::security::access_review::AccessReviewConfig,
998 pub privileged_access: crate::security::privileged_access::PrivilegedAccessConfig,
1000 pub change_management: crate::security::change_management::ChangeManagementConfig,
1002 pub compliance_dashboard: crate::security::compliance_dashboard::ComplianceDashboardConfig,
1004 pub risk_assessment: crate::security::risk_assessment::RiskAssessmentConfig,
1006}
1007
1008#[derive(Debug, Clone, Serialize, Deserialize)]
1010#[serde(default)]
1011#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
1012pub struct PrometheusConfig {
1013 pub enabled: bool,
1015 pub port: u16,
1017 pub host: String,
1019 pub path: String,
1021}
1022
1023impl Default for PrometheusConfig {
1024 fn default() -> Self {
1025 Self {
1026 enabled: true,
1027 port: 9090,
1028 host: "0.0.0.0".to_string(),
1029 path: "/metrics".to_string(),
1030 }
1031 }
1032}
1033
1034#[derive(Debug, Clone, Serialize, Deserialize)]
1036#[serde(default)]
1037#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
1038pub struct OpenTelemetryConfig {
1039 pub enabled: bool,
1041 pub service_name: String,
1043 pub environment: String,
1045 pub jaeger_endpoint: String,
1047 pub otlp_endpoint: Option<String>,
1049 pub protocol: String,
1051 pub sampling_rate: f64,
1053}
1054
1055impl Default for OpenTelemetryConfig {
1056 fn default() -> Self {
1057 Self {
1058 enabled: false,
1059 service_name: "mockforge".to_string(),
1060 environment: "development".to_string(),
1061 jaeger_endpoint: "http://localhost:14268/api/traces".to_string(),
1062 otlp_endpoint: Some("http://localhost:4317".to_string()),
1063 protocol: "grpc".to_string(),
1064 sampling_rate: 1.0,
1065 }
1066 }
1067}
1068
1069#[derive(Debug, Clone, Serialize, Deserialize)]
1071#[serde(default)]
1072#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
1073pub struct RecorderConfig {
1074 pub enabled: bool,
1076 pub database_path: String,
1078 pub api_enabled: bool,
1080 pub api_port: Option<u16>,
1082 pub max_requests: i64,
1084 pub retention_days: i64,
1086 pub record_http: bool,
1088 pub record_grpc: bool,
1090 pub record_websocket: bool,
1092 pub record_graphql: bool,
1094 #[serde(default = "default_true")]
1097 pub record_proxy: bool,
1098}
1099
1100impl Default for RecorderConfig {
1101 fn default() -> Self {
1102 Self {
1103 enabled: false,
1104 database_path: "./mockforge-recordings.db".to_string(),
1105 api_enabled: true,
1106 api_port: None,
1107 max_requests: 10000,
1108 retention_days: 7,
1109 record_http: true,
1110 record_grpc: true,
1111 record_websocket: true,
1112 record_graphql: true,
1113 record_proxy: true,
1114 }
1115 }
1116}
1117
1118#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1120#[serde(default)]
1121#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
1122pub struct ChaosEngConfig {
1123 pub enabled: bool,
1125 pub latency: Option<LatencyInjectionConfig>,
1127 pub fault_injection: Option<FaultConfig>,
1129 pub rate_limit: Option<RateLimitingConfig>,
1131 pub traffic_shaping: Option<NetworkShapingConfig>,
1133 pub scenario: Option<String>,
1135}
1136
1137#[derive(Debug, Clone, Serialize, Deserialize)]
1139#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
1140pub struct LatencyInjectionConfig {
1141 pub enabled: bool,
1143 pub fixed_delay_ms: Option<u64>,
1145 pub random_delay_range_ms: Option<(u64, u64)>,
1147 pub jitter_percent: f64,
1149 pub probability: f64,
1151}
1152
1153#[derive(Debug, Clone, Serialize, Deserialize)]
1155#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
1156pub struct FaultConfig {
1157 pub enabled: bool,
1159 pub http_errors: Vec<u16>,
1161 pub http_error_probability: f64,
1163 pub connection_errors: bool,
1165 pub connection_error_probability: f64,
1167 pub timeout_errors: bool,
1169 pub timeout_ms: u64,
1171 pub timeout_probability: f64,
1173}
1174
1175#[derive(Debug, Clone, Serialize, Deserialize)]
1177#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
1178pub struct RateLimitingConfig {
1179 pub enabled: bool,
1181 pub requests_per_second: u32,
1183 pub burst_size: u32,
1185 pub per_ip: bool,
1187 pub per_endpoint: bool,
1189}
1190
1191#[derive(Debug, Clone, Serialize, Deserialize)]
1193#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
1194pub struct NetworkShapingConfig {
1195 pub enabled: bool,
1197 pub bandwidth_limit_bps: u64,
1199 pub packet_loss_percent: f64,
1201 pub max_connections: u32,
1203}