1#![allow(
12 clippy::doc_markdown,
13 clippy::struct_excessive_bools,
14 clippy::must_use_candidate,
15 clippy::missing_const_for_fn,
16 clippy::unreadable_literal,
17 clippy::unnecessary_self_imports,
18 clippy::return_self_not_must_use,
19 clippy::missing_errors_doc,
20 clippy::missing_panics_doc,
21 clippy::module_name_repetitions,
22 clippy::use_self,
23 clippy::derive_partial_eq_without_eq
24)]
25
26use serde::{Deserialize, Serialize};
27use std::collections::HashMap;
28
29#[derive(Debug, Clone, Serialize, Deserialize)]
33#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
34pub struct HttpValidationConfig {
35 pub mode: String,
37}
38
39#[derive(Debug, Clone, Serialize, Deserialize, Default)]
41#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
42pub struct HttpCorsConfig {
43 pub enabled: bool,
45 #[serde(default)]
47 pub allowed_origins: Vec<String>,
48 #[serde(default)]
50 pub allowed_methods: Vec<String>,
51 #[serde(default)]
53 pub allowed_headers: Vec<String>,
54 #[serde(default = "default_cors_allow_credentials")]
57 pub allow_credentials: bool,
58}
59
60fn default_cors_allow_credentials() -> bool {
61 false
62}
63
64#[derive(Debug, Clone, Serialize, Deserialize)]
66#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
67#[serde(default)]
68pub struct HttpConfig {
69 pub enabled: bool,
71 pub port: u16,
73 pub host: String,
75 pub openapi_spec: Option<String>,
77 pub cors: Option<HttpCorsConfig>,
79 pub request_timeout_secs: u64,
81 pub validation: Option<HttpValidationConfig>,
83 pub aggregate_validation_errors: bool,
85 pub validate_responses: bool,
87 pub response_template_expand: bool,
89 pub validation_status: Option<u16>,
91 pub validation_overrides: HashMap<String, String>,
93 pub skip_admin_validation: bool,
95 pub auth: Option<AuthConfig>,
97 #[serde(skip_serializing_if = "Option::is_none")]
99 pub tls: Option<HttpTlsConfig>,
100}
101
102impl Default for HttpConfig {
103 fn default() -> Self {
104 Self {
105 enabled: true,
106 port: 3000,
107 host: "0.0.0.0".to_string(),
108 openapi_spec: None,
109 cors: Some(HttpCorsConfig {
110 enabled: true,
111 allowed_origins: vec!["*".to_string()],
112 allowed_methods: vec![
113 "GET".to_string(),
114 "POST".to_string(),
115 "PUT".to_string(),
116 "DELETE".to_string(),
117 "PATCH".to_string(),
118 "OPTIONS".to_string(),
119 ],
120 allowed_headers: vec!["content-type".to_string(), "authorization".to_string()],
121 allow_credentials: false, }),
123 request_timeout_secs: 30,
124 validation: Some(HttpValidationConfig {
125 mode: "enforce".to_string(),
126 }),
127 aggregate_validation_errors: true,
128 validate_responses: false,
129 response_template_expand: false,
130 validation_status: None,
131 validation_overrides: HashMap::new(),
132 skip_admin_validation: true,
133 auth: None,
134 tls: None,
135 }
136 }
137}
138
139#[derive(Debug, Clone, Serialize, Deserialize)]
141#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
142pub struct HttpTlsConfig {
143 pub enabled: bool,
145 pub cert_file: String,
147 pub key_file: String,
149 #[serde(skip_serializing_if = "Option::is_none")]
151 pub ca_file: Option<String>,
152 #[serde(default = "default_tls_min_version")]
154 pub min_version: String,
155 #[serde(default, skip_serializing_if = "Vec::is_empty")]
157 pub cipher_suites: Vec<String>,
158 #[serde(default)]
160 pub require_client_cert: bool,
161 #[serde(default = "default_mtls_mode")]
163 pub mtls_mode: String,
164}
165
166fn default_mtls_mode() -> String {
167 "off".to_string()
168}
169
170fn default_tls_min_version() -> String {
171 "1.2".to_string()
172}
173
174impl Default for HttpTlsConfig {
175 fn default() -> Self {
176 Self {
177 enabled: true,
178 cert_file: String::new(),
179 key_file: String::new(),
180 ca_file: None,
181 min_version: "1.2".to_string(),
182 cipher_suites: Vec::new(),
183 require_client_cert: false,
184 mtls_mode: "off".to_string(),
185 }
186 }
187}
188
189#[derive(Debug, Clone, Serialize, Deserialize)]
191#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
192#[serde(default)]
193pub struct WebSocketConfig {
194 pub enabled: bool,
196 pub port: u16,
198 pub host: String,
200 pub replay_file: Option<String>,
202 pub connection_timeout_secs: u64,
204}
205
206impl Default for WebSocketConfig {
207 fn default() -> Self {
208 Self {
209 enabled: true,
210 port: 3001,
211 host: "0.0.0.0".to_string(),
212 replay_file: None,
213 connection_timeout_secs: 300,
214 }
215 }
216}
217
218#[derive(Debug, Clone, Serialize, Deserialize)]
220#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
221#[serde(default)]
222pub struct GrpcConfig {
223 pub enabled: bool,
225 pub port: u16,
227 pub host: String,
229 pub proto_dir: Option<String>,
231 pub tls: Option<TlsConfig>,
233}
234
235impl Default for GrpcConfig {
236 fn default() -> Self {
237 Self {
238 enabled: true,
239 port: 50051,
240 host: "0.0.0.0".to_string(),
241 proto_dir: None,
242 tls: None,
243 }
244 }
245}
246
247#[derive(Debug, Clone, Serialize, Deserialize)]
249#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
250#[serde(default)]
251pub struct GraphQLConfig {
252 pub enabled: bool,
254 pub port: u16,
256 pub host: String,
258 pub schema_path: Option<String>,
260 pub handlers_dir: Option<String>,
262 pub playground_enabled: bool,
264 pub upstream_url: Option<String>,
266 pub introspection_enabled: bool,
268}
269
270impl Default for GraphQLConfig {
271 fn default() -> Self {
272 Self {
273 enabled: true,
274 port: 4000,
275 host: "0.0.0.0".to_string(),
276 schema_path: None,
277 handlers_dir: None,
278 playground_enabled: true,
279 upstream_url: None,
280 introspection_enabled: true,
281 }
282 }
283}
284
285#[derive(Debug, Clone, Serialize, Deserialize)]
287#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
288pub struct TlsConfig {
289 pub cert_path: String,
291 pub key_path: String,
293}
294
295#[derive(Debug, Clone, Serialize, Deserialize)]
297#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
298#[serde(default)]
299pub struct MqttConfig {
300 pub enabled: bool,
302 pub port: u16,
304 pub host: String,
306 pub max_connections: usize,
308 pub max_packet_size: usize,
310 pub keep_alive_secs: u16,
312 pub fixtures_dir: Option<std::path::PathBuf>,
314 pub enable_retained_messages: bool,
316 pub max_retained_messages: usize,
318}
319
320impl Default for MqttConfig {
321 fn default() -> Self {
322 Self {
323 enabled: false,
324 port: 1883,
325 host: "0.0.0.0".to_string(),
326 max_connections: 1000,
327 max_packet_size: 268435456, keep_alive_secs: 60,
329 fixtures_dir: None,
330 enable_retained_messages: true,
331 max_retained_messages: 10000,
332 }
333 }
334}
335
336#[derive(Debug, Clone, Serialize, Deserialize)]
338#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
339#[serde(default)]
340pub struct SmtpConfig {
341 pub enabled: bool,
343 pub port: u16,
345 pub host: String,
347 pub hostname: String,
349 pub fixtures_dir: Option<std::path::PathBuf>,
351 pub timeout_secs: u64,
353 pub max_connections: usize,
355 pub enable_mailbox: bool,
357 pub max_mailbox_messages: usize,
359 pub enable_starttls: bool,
361 pub tls_cert_path: Option<std::path::PathBuf>,
363 pub tls_key_path: Option<std::path::PathBuf>,
365}
366
367impl Default for SmtpConfig {
368 fn default() -> Self {
369 Self {
370 enabled: false,
371 port: 1025,
372 host: "0.0.0.0".to_string(),
373 hostname: "mockforge-smtp".to_string(),
374 fixtures_dir: Some(std::path::PathBuf::from("./fixtures/smtp")),
375 timeout_secs: 300,
376 max_connections: 10,
377 enable_mailbox: true,
378 max_mailbox_messages: 1000,
379 enable_starttls: false,
380 tls_cert_path: None,
381 tls_key_path: None,
382 }
383 }
384}
385
386#[derive(Debug, Clone, Serialize, Deserialize)]
388#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
389#[serde(default)]
390pub struct FtpConfig {
391 pub enabled: bool,
393 pub port: u16,
395 pub host: String,
397 pub passive_ports: (u16, u16),
399 pub max_connections: usize,
401 pub timeout_secs: u64,
403 pub allow_anonymous: bool,
405 pub fixtures_dir: Option<std::path::PathBuf>,
407 pub virtual_root: std::path::PathBuf,
409}
410
411impl Default for FtpConfig {
412 fn default() -> Self {
413 Self {
414 enabled: false,
415 port: 2121,
416 host: "0.0.0.0".to_string(),
417 passive_ports: (50000, 51000),
418 max_connections: 100,
419 timeout_secs: 300,
420 allow_anonymous: true,
421 fixtures_dir: None,
422 virtual_root: std::path::PathBuf::from("/mockforge"),
423 }
424 }
425}
426
427#[derive(Debug, Clone, Serialize, Deserialize)]
429#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
430#[serde(default)]
431pub struct KafkaConfig {
432 pub enabled: bool,
434 pub port: u16,
436 pub host: String,
438 pub broker_id: i32,
440 pub max_connections: usize,
442 pub log_retention_ms: i64,
444 pub log_segment_bytes: i64,
446 pub fixtures_dir: Option<std::path::PathBuf>,
448 pub auto_create_topics: bool,
450 pub default_partitions: i32,
452 pub default_replication_factor: i16,
454}
455
456impl Default for KafkaConfig {
457 fn default() -> Self {
458 Self {
459 enabled: false,
460 port: 9092, host: "0.0.0.0".to_string(),
462 broker_id: 1,
463 max_connections: 1000,
464 log_retention_ms: 604800000, log_segment_bytes: 1073741824, fixtures_dir: None,
467 auto_create_topics: true,
468 default_partitions: 3,
469 default_replication_factor: 1,
470 }
471 }
472}
473
474#[derive(Debug, Clone, Serialize, Deserialize)]
476#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
477#[serde(default)]
478pub struct AmqpConfig {
479 pub enabled: bool,
481 pub port: u16,
483 pub host: String,
485 pub max_connections: usize,
487 pub max_channels_per_connection: u16,
489 pub frame_max: u32,
491 pub heartbeat_interval: u16,
493 pub fixtures_dir: Option<std::path::PathBuf>,
495 pub virtual_hosts: Vec<String>,
497 pub tls_enabled: bool,
499 pub tls_port: u16,
501 pub tls_cert_path: Option<std::path::PathBuf>,
503 pub tls_key_path: Option<std::path::PathBuf>,
505 pub tls_ca_path: Option<std::path::PathBuf>,
507 pub tls_client_auth: bool,
509}
510
511impl Default for AmqpConfig {
512 fn default() -> Self {
513 Self {
514 enabled: false,
515 port: 5672, host: "0.0.0.0".to_string(),
517 max_connections: 1000,
518 max_channels_per_connection: 100,
519 frame_max: 131072, heartbeat_interval: 60,
521 fixtures_dir: None,
522 virtual_hosts: vec!["/".to_string()],
523 tls_enabled: false,
524 tls_port: 5671, tls_cert_path: None,
526 tls_key_path: None,
527 tls_ca_path: None,
528 tls_client_auth: false,
529 }
530 }
531}
532
533#[derive(Debug, Clone, Serialize, Deserialize)]
535#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
536#[serde(default)]
537pub struct TcpConfig {
538 pub enabled: bool,
540 pub port: u16,
542 pub host: String,
544 pub max_connections: usize,
546 pub timeout_secs: u64,
548 pub fixtures_dir: Option<std::path::PathBuf>,
550 pub echo_mode: bool,
552 pub enable_tls: bool,
554 pub tls_cert_path: Option<std::path::PathBuf>,
556 pub tls_key_path: Option<std::path::PathBuf>,
558}
559
560impl Default for TcpConfig {
561 fn default() -> Self {
562 Self {
563 enabled: false,
564 port: 9999,
565 host: "0.0.0.0".to_string(),
566 max_connections: 1000,
567 timeout_secs: 300,
568 fixtures_dir: Some(std::path::PathBuf::from("./fixtures/tcp")),
569 echo_mode: true,
570 enable_tls: false,
571 tls_cert_path: None,
572 tls_key_path: None,
573 }
574 }
575}
576
577#[derive(Debug, Clone, Serialize, Deserialize)]
579#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
580#[serde(default)]
581pub struct AdminConfig {
582 pub enabled: bool,
584 pub port: u16,
586 pub host: String,
588 pub auth_required: bool,
590 pub username: Option<String>,
592 pub password: Option<String>,
594 pub mount_path: Option<String>,
596 pub api_enabled: bool,
598 pub prometheus_url: String,
600}
601
602impl Default for AdminConfig {
603 fn default() -> Self {
604 let default_host = if std::env::var("DOCKER_CONTAINER").is_ok()
607 || std::env::var("container").is_ok()
608 || std::path::Path::new("/.dockerenv").exists()
609 {
610 "0.0.0.0".to_string()
611 } else {
612 "127.0.0.1".to_string()
613 };
614
615 Self {
616 enabled: false,
617 port: 9080,
618 host: default_host,
619 auth_required: false,
620 username: None,
621 password: None,
622 mount_path: None,
623 api_enabled: true,
624 prometheus_url: "http://localhost:9090".to_string(),
625 }
626 }
627}
628
629#[derive(Debug, Clone, Serialize, Deserialize)]
631#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
632#[serde(default)]
633pub struct LoggingConfig {
634 pub level: String,
636 pub json_format: bool,
638 pub file_path: Option<String>,
640 pub max_file_size_mb: u64,
642 pub max_files: u32,
644}
645
646impl Default for LoggingConfig {
647 fn default() -> Self {
648 Self {
649 level: "info".to_string(),
650 json_format: false,
651 file_path: None,
652 max_file_size_mb: 10,
653 max_files: 5,
654 }
655 }
656}
657
658#[derive(Debug, Clone, Serialize, Deserialize)]
660#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
661pub struct ProtocolConfig {
662 pub enabled: bool,
664}
665
666#[derive(Debug, Clone, Serialize, Deserialize)]
668#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
669pub struct ProtocolsConfig {
670 pub http: ProtocolConfig,
672 pub graphql: ProtocolConfig,
674 pub grpc: ProtocolConfig,
676 pub websocket: ProtocolConfig,
678 pub smtp: ProtocolConfig,
680 pub mqtt: ProtocolConfig,
682 pub ftp: ProtocolConfig,
684 pub kafka: ProtocolConfig,
686 pub rabbitmq: ProtocolConfig,
688 pub amqp: ProtocolConfig,
690 pub tcp: ProtocolConfig,
692}
693
694impl Default for ProtocolsConfig {
695 fn default() -> Self {
696 Self {
697 http: ProtocolConfig { enabled: true },
698 graphql: ProtocolConfig { enabled: true },
699 grpc: ProtocolConfig { enabled: true },
700 websocket: ProtocolConfig { enabled: true },
701 smtp: ProtocolConfig { enabled: false },
702 mqtt: ProtocolConfig { enabled: true },
703 ftp: ProtocolConfig { enabled: false },
704 kafka: ProtocolConfig { enabled: false },
705 rabbitmq: ProtocolConfig { enabled: false },
706 amqp: ProtocolConfig { enabled: false },
707 tcp: ProtocolConfig { enabled: false },
708 }
709 }
710}
711
712#[derive(Debug, Clone, Serialize, Deserialize)]
716#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
717#[serde(default)]
718pub struct AuthConfig {
719 pub jwt: Option<JwtConfig>,
721 pub oauth2: Option<OAuth2Config>,
723 pub basic_auth: Option<BasicAuthConfig>,
725 pub api_key: Option<ApiKeyConfig>,
727 pub require_auth: bool,
729}
730
731#[derive(Debug, Clone, Serialize, Deserialize)]
733#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
734pub struct JwtConfig {
735 pub secret: Option<String>,
737 pub rsa_public_key: Option<String>,
739 pub ecdsa_public_key: Option<String>,
741 pub issuer: Option<String>,
743 pub audience: Option<String>,
745 pub algorithms: Vec<String>,
747}
748
749#[derive(Debug, Clone, Serialize, Deserialize)]
751#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
752pub struct OAuth2Config {
753 pub client_id: String,
755 pub client_secret: String,
757 pub introspection_url: String,
759 pub auth_url: Option<String>,
761 pub token_url: Option<String>,
763 pub token_type_hint: Option<String>,
765}
766
767#[derive(Debug, Clone, Serialize, Deserialize)]
769#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
770pub struct BasicAuthConfig {
771 pub credentials: HashMap<String, String>,
773}
774
775#[derive(Debug, Clone, Serialize, Deserialize)]
777#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
778pub struct ApiKeyConfig {
779 pub header_name: String,
781 pub query_name: Option<String>,
783 pub keys: Vec<String>,
785}
786
787impl Default for AuthConfig {
788 fn default() -> Self {
789 Self {
790 jwt: None,
791 oauth2: None,
792 basic_auth: None,
793 api_key: Some(ApiKeyConfig {
794 header_name: "X-API-Key".to_string(),
795 query_name: None,
796 keys: vec![],
797 }),
798 require_auth: false,
799 }
800 }
801}
802
803#[derive(Debug, Clone, Serialize, Deserialize)]
807#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
808pub struct RouteConfig {
809 pub path: String,
811 pub method: String,
813 pub request: Option<RouteRequestConfig>,
815 pub response: RouteResponseConfig,
817 #[serde(default)]
819 pub fault_injection: Option<RouteFaultInjectionConfig>,
820 #[serde(default)]
822 pub latency: Option<RouteLatencyConfig>,
823}
824
825#[derive(Debug, Clone, Serialize, Deserialize)]
827#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
828pub struct RouteRequestConfig {
829 pub validation: Option<RouteValidationConfig>,
831}
832
833#[derive(Debug, Clone, Serialize, Deserialize)]
835#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
836pub struct RouteResponseConfig {
837 pub status: u16,
839 #[serde(default)]
841 pub headers: HashMap<String, String>,
842 pub body: Option<serde_json::Value>,
844}
845
846#[derive(Debug, Clone, Serialize, Deserialize)]
848#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
849pub struct RouteValidationConfig {
850 pub schema: serde_json::Value,
852}
853
854#[derive(Debug, Clone, Serialize, Deserialize)]
856#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
857pub struct RouteFaultInjectionConfig {
858 pub enabled: bool,
860 pub probability: f64,
862 pub fault_types: Vec<RouteFaultType>,
864}
865
866#[derive(Debug, Clone, Serialize, Deserialize)]
868#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
869#[serde(tag = "type", rename_all = "snake_case")]
870pub enum RouteFaultType {
871 HttpError {
873 status_code: u16,
875 message: Option<String>,
877 },
878 ConnectionError {
880 message: Option<String>,
882 },
883 Timeout {
885 duration_ms: u64,
887 message: Option<String>,
889 },
890 PartialResponse {
892 truncate_percent: f64,
894 },
895 PayloadCorruption {
897 corruption_type: String,
899 },
900}
901
902#[derive(Debug, Clone, Serialize, Deserialize)]
904#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
905pub struct RouteLatencyConfig {
906 pub enabled: bool,
908 pub probability: f64,
910 pub fixed_delay_ms: Option<u64>,
912 pub random_delay_range_ms: Option<(u64, u64)>,
914 pub jitter_percent: f64,
916 #[serde(default)]
918 pub distribution: LatencyDistribution,
919}
920
921#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
923#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
924#[serde(rename_all = "snake_case")]
925#[derive(Default)]
926pub enum LatencyDistribution {
927 #[default]
929 Fixed,
930 Normal {
932 mean_ms: f64,
934 std_dev_ms: f64,
936 },
937 Exponential {
939 lambda: f64,
941 },
942 Uniform,
944}
945
946impl Default for RouteFaultInjectionConfig {
947 fn default() -> Self {
948 Self {
949 enabled: false,
950 probability: 0.0,
951 fault_types: Vec::new(),
952 }
953 }
954}
955
956impl Default for RouteLatencyConfig {
957 fn default() -> Self {
958 Self {
959 enabled: false,
960 probability: 1.0,
961 fixed_delay_ms: None,
962 random_delay_range_ms: None,
963 jitter_percent: 0.0,
964 distribution: LatencyDistribution::Fixed,
965 }
966 }
967}
968
969#[derive(Debug, Clone, Serialize, Deserialize)]
973#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
974#[serde(default)]
975#[derive(Default)]
976pub struct PerformanceConfig {
977 pub compression: CompressionConfig,
979 pub connection_pool: ConnectionPoolConfig,
981 pub request_limits: RequestLimitsConfig,
983 pub workers: WorkerConfig,
985 pub circuit_breaker: CircuitBreakerConfig,
987}
988
989#[derive(Debug, Clone, Serialize, Deserialize)]
991#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
992#[serde(default)]
993pub struct CompressionConfig {
994 pub enabled: bool,
996 pub algorithm: String,
998 pub min_size: usize,
1000 pub level: u32,
1002 pub content_types: Vec<String>,
1004}
1005
1006impl Default for CompressionConfig {
1007 fn default() -> Self {
1008 Self {
1009 enabled: true,
1010 algorithm: "gzip".to_string(),
1011 min_size: 1024, level: 6,
1013 content_types: vec![
1014 "application/json".to_string(),
1015 "application/xml".to_string(),
1016 "text/plain".to_string(),
1017 "text/html".to_string(),
1018 "text/css".to_string(),
1019 "application/javascript".to_string(),
1020 ],
1021 }
1022 }
1023}
1024
1025#[derive(Debug, Clone, Serialize, Deserialize)]
1027#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
1028#[serde(default)]
1029pub struct ConnectionPoolConfig {
1030 pub max_idle_per_host: usize,
1032 pub max_connections: usize,
1034 pub idle_timeout_secs: u64,
1036 pub acquire_timeout_ms: u64,
1038 pub enabled: bool,
1040}
1041
1042impl Default for ConnectionPoolConfig {
1043 fn default() -> Self {
1044 Self {
1045 max_idle_per_host: 10,
1046 max_connections: 100,
1047 idle_timeout_secs: 90,
1048 acquire_timeout_ms: 5000,
1049 enabled: true,
1050 }
1051 }
1052}
1053
1054#[derive(Debug, Clone, Serialize, Deserialize)]
1056#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
1057#[serde(default)]
1058pub struct RequestLimitsConfig {
1059 pub max_body_size: usize,
1061 pub max_header_size: usize,
1063 pub max_headers: usize,
1065 pub max_uri_length: usize,
1067 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
1069 pub per_route_limits: HashMap<String, usize>,
1070}
1071
1072impl Default for RequestLimitsConfig {
1073 fn default() -> Self {
1074 Self {
1075 max_body_size: 10 * 1024 * 1024, max_header_size: 16 * 1024, max_headers: 100,
1078 max_uri_length: 8192,
1079 per_route_limits: HashMap::new(),
1080 }
1081 }
1082}
1083
1084#[derive(Debug, Clone, Serialize, Deserialize)]
1086#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
1087#[serde(default)]
1088pub struct WorkerConfig {
1089 pub threads: usize,
1091 pub blocking_threads: usize,
1093 pub stack_size: usize,
1095 pub name_prefix: String,
1097}
1098
1099impl Default for WorkerConfig {
1100 fn default() -> Self {
1101 Self {
1102 threads: 0, blocking_threads: 512,
1104 stack_size: 2 * 1024 * 1024, name_prefix: "mockforge-worker".to_string(),
1106 }
1107 }
1108}
1109
1110#[derive(Debug, Clone, Serialize, Deserialize)]
1112#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
1113#[serde(default)]
1114pub struct CircuitBreakerConfig {
1115 pub enabled: bool,
1117 pub failure_threshold: u32,
1119 pub success_threshold: u32,
1121 pub half_open_timeout_secs: u64,
1123 pub window_size: u32,
1125 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
1127 pub per_endpoint: HashMap<String, EndpointCircuitBreakerConfig>,
1128}
1129
1130impl Default for CircuitBreakerConfig {
1131 fn default() -> Self {
1132 Self {
1133 enabled: false,
1134 failure_threshold: 5,
1135 success_threshold: 2,
1136 half_open_timeout_secs: 30,
1137 window_size: 10,
1138 per_endpoint: HashMap::new(),
1139 }
1140 }
1141}
1142
1143#[derive(Debug, Clone, Serialize, Deserialize)]
1145#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
1146pub struct EndpointCircuitBreakerConfig {
1147 pub failure_threshold: u32,
1149 pub success_threshold: u32,
1151 pub half_open_timeout_secs: u64,
1153}
1154
1155#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
1159#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
1160#[serde(rename_all = "lowercase")]
1161pub enum SecretBackendType {
1162 #[default]
1164 None,
1165 Vault,
1167 AwsSecretsManager,
1169 AzureKeyVault,
1171 GcpSecretManager,
1173 Kubernetes,
1175 EncryptedFile,
1177}
1178
1179#[derive(Debug, Clone, Serialize, Deserialize)]
1181#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
1182#[serde(default)]
1183pub struct SecretBackendConfig {
1184 pub provider: SecretBackendType,
1186 #[serde(skip_serializing_if = "Option::is_none")]
1188 pub vault: Option<VaultConfig>,
1189 #[serde(skip_serializing_if = "Option::is_none")]
1191 pub aws: Option<AwsSecretsConfig>,
1192 #[serde(skip_serializing_if = "Option::is_none")]
1194 pub azure: Option<AzureKeyVaultConfig>,
1195 #[serde(skip_serializing_if = "Option::is_none")]
1197 pub gcp: Option<GcpSecretManagerConfig>,
1198 #[serde(skip_serializing_if = "Option::is_none")]
1200 pub kubernetes: Option<KubernetesSecretsConfig>,
1201 #[serde(skip_serializing_if = "Option::is_none")]
1203 pub encrypted_file: Option<EncryptedFileConfig>,
1204 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
1206 pub mappings: HashMap<String, String>,
1207 pub cache_ttl_secs: u64,
1209 pub retry_attempts: u32,
1211 pub retry_delay_ms: u64,
1213}
1214
1215impl Default for SecretBackendConfig {
1216 fn default() -> Self {
1217 Self {
1218 provider: SecretBackendType::None,
1219 vault: None,
1220 aws: None,
1221 azure: None,
1222 gcp: None,
1223 kubernetes: None,
1224 encrypted_file: None,
1225 mappings: HashMap::new(),
1226 cache_ttl_secs: 300, retry_attempts: 3,
1228 retry_delay_ms: 1000,
1229 }
1230 }
1231}
1232
1233#[derive(Debug, Clone, Serialize, Deserialize)]
1235#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
1236#[serde(default)]
1237pub struct VaultConfig {
1238 pub address: String,
1240 #[serde(skip_serializing_if = "Option::is_none")]
1242 pub namespace: Option<String>,
1243 pub auth_method: VaultAuthMethod,
1245 #[serde(skip_serializing_if = "Option::is_none")]
1247 pub token: Option<String>,
1248 #[serde(skip_serializing_if = "Option::is_none")]
1250 pub role_id: Option<String>,
1251 #[serde(skip_serializing_if = "Option::is_none")]
1253 pub secret_id: Option<String>,
1254 #[serde(skip_serializing_if = "Option::is_none")]
1256 pub kubernetes_role: Option<String>,
1257 pub mount_path: String,
1259 pub path_prefix: String,
1261 #[serde(skip_serializing_if = "Option::is_none")]
1263 pub ca_cert_path: Option<String>,
1264 pub skip_verify: bool,
1266 pub timeout_secs: u64,
1268}
1269
1270impl Default for VaultConfig {
1271 fn default() -> Self {
1272 Self {
1273 address: "http://127.0.0.1:8200".to_string(),
1274 namespace: None,
1275 auth_method: VaultAuthMethod::Token,
1276 token: None,
1277 role_id: None,
1278 secret_id: None,
1279 kubernetes_role: None,
1280 mount_path: "secret".to_string(),
1281 path_prefix: "mockforge".to_string(),
1282 ca_cert_path: None,
1283 skip_verify: false,
1284 timeout_secs: 30,
1285 }
1286 }
1287}
1288
1289#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
1291#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
1292#[serde(rename_all = "lowercase")]
1293pub enum VaultAuthMethod {
1294 #[default]
1296 Token,
1297 AppRole,
1299 Kubernetes,
1301 AwsIam,
1303 GitHub,
1305 Ldap,
1307 Userpass,
1309}
1310
1311#[derive(Debug, Clone, Serialize, Deserialize)]
1313#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
1314#[serde(default)]
1315pub struct AwsSecretsConfig {
1316 pub region: String,
1318 pub prefix: String,
1320 pub use_iam_role: bool,
1322 #[serde(skip_serializing_if = "Option::is_none")]
1324 pub access_key_id: Option<String>,
1325 #[serde(skip_serializing_if = "Option::is_none")]
1327 pub secret_access_key: Option<String>,
1328 #[serde(skip_serializing_if = "Option::is_none")]
1330 pub endpoint_url: Option<String>,
1331}
1332
1333impl Default for AwsSecretsConfig {
1334 fn default() -> Self {
1335 Self {
1336 region: "us-east-1".to_string(),
1337 prefix: "mockforge".to_string(),
1338 use_iam_role: true,
1339 access_key_id: None,
1340 secret_access_key: None,
1341 endpoint_url: None,
1342 }
1343 }
1344}
1345
1346#[derive(Debug, Clone, Serialize, Deserialize)]
1348#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
1349#[serde(default)]
1350pub struct AzureKeyVaultConfig {
1351 pub vault_url: String,
1353 #[serde(skip_serializing_if = "Option::is_none")]
1355 pub tenant_id: Option<String>,
1356 #[serde(skip_serializing_if = "Option::is_none")]
1358 pub client_id: Option<String>,
1359 #[serde(skip_serializing_if = "Option::is_none")]
1361 pub client_secret: Option<String>,
1362 pub use_managed_identity: bool,
1364 pub prefix: String,
1366}
1367
1368impl Default for AzureKeyVaultConfig {
1369 fn default() -> Self {
1370 Self {
1371 vault_url: String::new(),
1372 tenant_id: None,
1373 client_id: None,
1374 client_secret: None,
1375 use_managed_identity: true,
1376 prefix: "mockforge".to_string(),
1377 }
1378 }
1379}
1380
1381#[derive(Debug, Clone, Serialize, Deserialize)]
1383#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
1384#[serde(default)]
1385pub struct GcpSecretManagerConfig {
1386 pub project_id: String,
1388 pub prefix: String,
1390 #[serde(skip_serializing_if = "Option::is_none")]
1392 pub credentials_file: Option<String>,
1393 pub use_default_credentials: bool,
1395}
1396
1397impl Default for GcpSecretManagerConfig {
1398 fn default() -> Self {
1399 Self {
1400 project_id: String::new(),
1401 prefix: "mockforge".to_string(),
1402 credentials_file: None,
1403 use_default_credentials: true,
1404 }
1405 }
1406}
1407
1408#[derive(Debug, Clone, Serialize, Deserialize)]
1410#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
1411#[serde(default)]
1412pub struct KubernetesSecretsConfig {
1413 pub namespace: String,
1415 pub prefix: String,
1417 #[serde(skip_serializing_if = "Option::is_none")]
1419 pub label_selector: Option<String>,
1420 pub in_cluster: bool,
1422 #[serde(skip_serializing_if = "Option::is_none")]
1424 pub kubeconfig_path: Option<String>,
1425}
1426
1427impl Default for KubernetesSecretsConfig {
1428 fn default() -> Self {
1429 Self {
1430 namespace: "default".to_string(),
1431 prefix: "mockforge".to_string(),
1432 label_selector: None,
1433 in_cluster: true,
1434 kubeconfig_path: None,
1435 }
1436 }
1437}
1438
1439#[derive(Debug, Clone, Serialize, Deserialize)]
1441#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
1442#[serde(default)]
1443pub struct EncryptedFileConfig {
1444 pub file_path: String,
1446 pub algorithm: String,
1448 pub kdf: String,
1450 #[serde(skip_serializing_if = "Option::is_none")]
1452 pub master_key_env: Option<String>,
1453 #[serde(skip_serializing_if = "Option::is_none")]
1455 pub key_file: Option<String>,
1456}
1457
1458impl Default for EncryptedFileConfig {
1459 fn default() -> Self {
1460 Self {
1461 file_path: "secrets.enc".to_string(),
1462 algorithm: "aes-256-gcm".to_string(),
1463 kdf: "argon2id".to_string(),
1464 master_key_env: Some("MOCKFORGE_MASTER_KEY".to_string()),
1465 key_file: None,
1466 }
1467 }
1468}
1469
1470#[derive(Debug, Clone, Serialize, Deserialize)]
1474#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
1475#[serde(default)]
1476pub struct BehavioralCloningConfig {
1477 pub enabled: bool,
1479 pub database_path: Option<String>,
1481 pub enable_middleware: bool,
1483 pub min_sequence_frequency: f64,
1485 pub min_requests_per_trace: Option<i32>,
1487 #[serde(default)]
1489 pub flow_recording: FlowRecordingConfig,
1490 #[serde(default)]
1492 pub scenario_replay: ScenarioReplayConfig,
1493}
1494
1495#[derive(Debug, Clone, Serialize, Deserialize)]
1497#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
1498#[serde(default)]
1499pub struct FlowRecordingConfig {
1500 pub enabled: bool,
1502 pub group_by: String,
1504 pub time_window_seconds: u64,
1506}
1507
1508impl Default for FlowRecordingConfig {
1509 fn default() -> Self {
1510 Self {
1511 enabled: true,
1512 group_by: "trace_id".to_string(),
1513 time_window_seconds: 300, }
1515 }
1516}
1517
1518#[derive(Debug, Clone, Serialize, Deserialize)]
1520#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
1521#[serde(default)]
1522pub struct ScenarioReplayConfig {
1523 pub enabled: bool,
1525 pub default_mode: String,
1527 pub active_scenarios: Vec<String>,
1529}
1530
1531impl Default for ScenarioReplayConfig {
1532 fn default() -> Self {
1533 Self {
1534 enabled: true,
1535 default_mode: "strict".to_string(),
1536 active_scenarios: Vec::new(),
1537 }
1538 }
1539}
1540
1541impl Default for BehavioralCloningConfig {
1542 fn default() -> Self {
1543 Self {
1544 enabled: false,
1545 database_path: None,
1546 enable_middleware: false,
1547 min_sequence_frequency: 0.1, min_requests_per_trace: None,
1549 flow_recording: FlowRecordingConfig::default(),
1550 scenario_replay: ScenarioReplayConfig::default(),
1551 }
1552 }
1553}
1554
1555#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1559#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
1560#[serde(default)]
1561pub struct ConsumerContractsConfig {
1562 pub enabled: bool,
1564 pub auto_register: bool,
1566 pub track_usage: bool,
1568}
1569
1570#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1572#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
1573#[serde(default)]
1574pub struct ContractsConfig {
1575 pub fitness_rules: Vec<FitnessRuleConfig>,
1577}
1578
1579#[derive(Debug, Clone, Serialize, Deserialize)]
1581#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
1582pub struct FitnessRuleConfig {
1583 pub name: String,
1585 pub scope: String,
1587 #[serde(rename = "type")]
1589 pub rule_type: FitnessRuleType,
1590 #[serde(skip_serializing_if = "Option::is_none")]
1592 pub max_percent_increase: Option<f64>,
1593 #[serde(skip_serializing_if = "Option::is_none")]
1595 pub max_fields: Option<u32>,
1596 #[serde(skip_serializing_if = "Option::is_none")]
1598 pub max_depth: Option<u32>,
1599}
1600
1601#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1603#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
1604#[serde(rename_all = "snake_case")]
1605pub enum FitnessRuleType {
1606 ResponseSizeDelta,
1608 NoNewRequiredFields,
1610 FieldCount,
1612 SchemaComplexity,
1614}
1615
1616#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1620#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
1621#[serde(default)]
1622pub struct DriftLearningConfig {
1623 pub enabled: bool,
1625 #[serde(default)]
1627 pub mode: DriftLearningMode,
1628 #[serde(default = "default_learning_sensitivity")]
1630 pub sensitivity: f64,
1631 #[serde(default = "default_learning_decay")]
1633 pub decay: f64,
1634 #[serde(default = "default_min_samples")]
1636 pub min_samples: u64,
1637 #[serde(default)]
1639 pub persona_adaptation: bool,
1640 #[serde(default)]
1642 pub persona_learning: HashMap<String, bool>, #[serde(default)]
1645 pub endpoint_learning: HashMap<String, bool>, }
1647
1648#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default)]
1650#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
1651#[serde(rename_all = "snake_case")]
1652pub enum DriftLearningMode {
1653 #[default]
1655 Behavioral,
1656 Statistical,
1658 Hybrid,
1660}
1661
1662fn default_learning_sensitivity() -> f64 {
1663 0.2
1664}
1665
1666fn default_learning_decay() -> f64 {
1667 0.05
1668}
1669
1670fn default_min_samples() -> u64 {
1671 10
1672}
1673
1674#[derive(Debug, Clone, Serialize, Deserialize)]
1678#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
1679pub struct ProductionCorsConfig {
1680 #[serde(default)]
1682 pub allowed_origins: Vec<String>,
1683 #[serde(default)]
1685 pub allowed_methods: Vec<String>,
1686 #[serde(default)]
1688 pub allowed_headers: Vec<String>,
1689 pub allow_credentials: bool,
1691}
1692
1693#[derive(Debug, Clone, Serialize, Deserialize)]
1695#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
1696pub struct ProductionRateLimitConfig {
1697 pub requests_per_minute: u32,
1699 pub burst: u32,
1701 pub per_ip: bool,
1703}
1704
1705#[derive(Debug, Clone, Serialize, Deserialize)]
1707#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
1708pub struct ProductionOAuthConfig {
1709 pub client_id: String,
1711 pub client_secret: String,
1713 pub introspection_url: String,
1715 pub auth_url: Option<String>,
1717 pub token_url: Option<String>,
1719 pub token_type_hint: Option<String>,
1721}
1722
1723impl From<ProductionOAuthConfig> for OAuth2Config {
1724 fn from(prod: ProductionOAuthConfig) -> Self {
1726 OAuth2Config {
1727 client_id: prod.client_id,
1728 client_secret: prod.client_secret,
1729 introspection_url: prod.introspection_url,
1730 auth_url: prod.auth_url,
1731 token_url: prod.token_url,
1732 token_type_hint: prod.token_type_hint,
1733 }
1734 }
1735}
1736
1737#[derive(Debug, Clone, Serialize, Deserialize)]
1741#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
1742#[serde(default)]
1743pub struct PluginResourceConfig {
1744 pub enabled: bool,
1746 pub max_memory_per_plugin: usize,
1748 pub max_cpu_per_plugin: f64,
1750 pub max_execution_time_ms: u64,
1752 pub allow_network_access: bool,
1754 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1756 pub allowed_fs_paths: Vec<String>,
1757 pub max_concurrent_executions: usize,
1759 #[serde(skip_serializing_if = "Option::is_none")]
1761 pub cache_dir: Option<String>,
1762 pub debug_logging: bool,
1764 pub max_module_size: usize,
1766 pub max_table_elements: usize,
1768 pub max_stack_size: usize,
1770}
1771
1772impl Default for PluginResourceConfig {
1773 fn default() -> Self {
1774 Self {
1775 enabled: true,
1776 max_memory_per_plugin: 10 * 1024 * 1024, max_cpu_per_plugin: 0.5, max_execution_time_ms: 5000, allow_network_access: false,
1780 allowed_fs_paths: Vec::new(),
1781 max_concurrent_executions: 10,
1782 cache_dir: None,
1783 debug_logging: false,
1784 max_module_size: 5 * 1024 * 1024, max_table_elements: 1000,
1786 max_stack_size: 2 * 1024 * 1024, }
1788 }
1789}
1790
1791#[derive(Debug, Clone, Serialize, Deserialize)]
1795#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
1796#[serde(default)]
1797pub struct ConfigHotReloadConfig {
1798 pub enabled: bool,
1800 pub check_interval_secs: u64,
1802 pub debounce_delay_ms: u64,
1804 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1806 pub watch_paths: Vec<String>,
1807 pub reload_on_spec_change: bool,
1809 pub reload_on_fixture_change: bool,
1811 pub reload_on_plugin_change: bool,
1813 pub graceful_reload: bool,
1815 pub graceful_timeout_secs: u64,
1817 pub validate_before_reload: bool,
1819 pub rollback_on_failure: bool,
1821}
1822
1823impl Default for ConfigHotReloadConfig {
1824 fn default() -> Self {
1825 Self {
1826 enabled: false,
1827 check_interval_secs: 5,
1828 debounce_delay_ms: 1000,
1829 watch_paths: Vec::new(),
1830 reload_on_spec_change: true,
1831 reload_on_fixture_change: true,
1832 reload_on_plugin_change: true,
1833 graceful_reload: true,
1834 graceful_timeout_secs: 30,
1835 validate_before_reload: true,
1836 rollback_on_failure: true,
1837 }
1838 }
1839}
1840
1841#[derive(Debug, Clone, Serialize, Deserialize)]
1845#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
1846#[serde(default, rename_all = "camelCase")]
1847pub struct ChainingConfig {
1848 pub enabled: bool,
1850 pub max_chain_length: usize,
1852 pub global_timeout_secs: u64,
1854 pub enable_parallel_execution: bool,
1856}
1857
1858impl Default for ChainingConfig {
1859 fn default() -> Self {
1860 Self {
1861 enabled: false,
1862 max_chain_length: 20,
1863 global_timeout_secs: 300,
1864 enable_parallel_execution: false,
1865 }
1866 }
1867}
1868
1869#[derive(Debug, Clone, Serialize, Deserialize)]
1873#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
1874#[serde(default)]
1875pub struct DataConfig {
1876 pub default_rows: usize,
1878 pub default_format: String,
1880 pub locale: String,
1882 pub templates: HashMap<String, String>,
1884 pub rag: RagConfig,
1886 #[serde(skip_serializing_if = "Option::is_none")]
1888 pub persona_domain: Option<String>,
1889 #[serde(default = "default_false")]
1891 pub persona_consistency_enabled: bool,
1892 #[serde(skip_serializing_if = "Option::is_none")]
1894 pub persona_registry: Option<PersonaRegistryConfig>,
1895}
1896
1897impl Default for DataConfig {
1898 fn default() -> Self {
1899 Self {
1900 default_rows: 100,
1901 default_format: "json".to_string(),
1902 locale: "en".to_string(),
1903 templates: HashMap::new(),
1904 rag: RagConfig::default(),
1905 persona_domain: None,
1906 persona_consistency_enabled: false,
1907 persona_registry: None,
1908 }
1909 }
1910}
1911
1912#[derive(Debug, Clone, Serialize, Deserialize)]
1914#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
1915#[serde(default)]
1916pub struct RagConfig {
1917 pub enabled: bool,
1919 #[serde(default)]
1921 pub provider: String,
1922 pub api_endpoint: Option<String>,
1924 pub api_key: Option<String>,
1926 pub model: Option<String>,
1928 #[serde(default = "default_max_tokens")]
1930 pub max_tokens: usize,
1931 #[serde(default = "default_temperature")]
1933 pub temperature: f64,
1934 pub context_window: usize,
1936 #[serde(default = "default_true")]
1938 pub caching: bool,
1939 #[serde(default = "default_cache_ttl")]
1941 pub cache_ttl_secs: u64,
1942 #[serde(default = "default_timeout")]
1944 pub timeout_secs: u64,
1945 #[serde(default = "default_max_retries")]
1947 pub max_retries: usize,
1948}
1949
1950fn default_max_tokens() -> usize {
1951 1024
1952}
1953
1954fn default_temperature() -> f64 {
1955 0.7
1956}
1957
1958fn default_true() -> bool {
1959 true
1960}
1961
1962fn default_false() -> bool {
1963 false
1964}
1965
1966fn default_cache_ttl() -> u64 {
1967 3600
1968}
1969
1970fn default_timeout() -> u64 {
1971 30
1972}
1973
1974fn default_max_retries() -> usize {
1975 3
1976}
1977
1978impl Default for RagConfig {
1979 fn default() -> Self {
1980 Self {
1981 enabled: false,
1982 provider: "openai".to_string(),
1983 api_endpoint: None,
1984 api_key: None,
1985 model: Some("gpt-3.5-turbo".to_string()),
1986 max_tokens: default_max_tokens(),
1987 temperature: default_temperature(),
1988 context_window: 4000,
1989 caching: default_true(),
1990 cache_ttl_secs: default_cache_ttl(),
1991 timeout_secs: default_timeout(),
1992 max_retries: default_max_retries(),
1993 }
1994 }
1995}
1996
1997#[derive(Debug, Clone, Serialize, Deserialize)]
1999#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
2000#[serde(default)]
2001#[derive(Default)]
2002pub struct PersonaRegistryConfig {
2003 #[serde(default = "default_false")]
2005 pub persistent: bool,
2006 #[serde(skip_serializing_if = "Option::is_none")]
2008 pub storage_path: Option<String>,
2009 #[serde(default)]
2011 pub default_traits: HashMap<String, String>,
2012}
2013
2014#[derive(Debug, Clone, Serialize, Deserialize)]
2018#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
2019#[serde(default)]
2020pub struct PrometheusConfig {
2021 pub enabled: bool,
2023 pub port: u16,
2025 pub host: String,
2027 pub path: String,
2029}
2030
2031impl Default for PrometheusConfig {
2032 fn default() -> Self {
2033 Self {
2034 enabled: true,
2035 port: 9090,
2036 host: "0.0.0.0".to_string(),
2037 path: "/metrics".to_string(),
2038 }
2039 }
2040}
2041
2042#[derive(Debug, Clone, Serialize, Deserialize)]
2044#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
2045#[serde(default)]
2046pub struct OpenTelemetryConfig {
2047 pub enabled: bool,
2049 pub service_name: String,
2051 pub environment: String,
2053 pub jaeger_endpoint: String,
2055 pub otlp_endpoint: Option<String>,
2057 pub protocol: String,
2059 pub sampling_rate: f64,
2061}
2062
2063impl Default for OpenTelemetryConfig {
2064 fn default() -> Self {
2065 Self {
2066 enabled: false,
2067 service_name: "mockforge".to_string(),
2068 environment: "development".to_string(),
2069 jaeger_endpoint: "http://localhost:14268/api/traces".to_string(),
2070 otlp_endpoint: Some("http://localhost:4317".to_string()),
2071 protocol: "grpc".to_string(),
2072 sampling_rate: 1.0,
2073 }
2074 }
2075}
2076
2077#[derive(Debug, Clone, Serialize, Deserialize)]
2079#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
2080#[serde(default)]
2081pub struct RecorderConfig {
2082 pub enabled: bool,
2084 pub database_path: String,
2086 pub api_enabled: bool,
2088 pub api_port: Option<u16>,
2090 pub max_requests: i64,
2092 pub retention_days: i64,
2094 pub record_http: bool,
2096 pub record_grpc: bool,
2098 pub record_websocket: bool,
2100 pub record_graphql: bool,
2102 #[serde(default = "default_true")]
2105 pub record_proxy: bool,
2106}
2107
2108impl Default for RecorderConfig {
2109 fn default() -> Self {
2110 Self {
2111 enabled: false,
2112 database_path: "./mockforge-recordings.db".to_string(),
2113 api_enabled: true,
2114 api_port: None,
2115 max_requests: 10000,
2116 retention_days: 7,
2117 record_http: true,
2118 record_grpc: true,
2119 record_websocket: true,
2120 record_graphql: true,
2121 record_proxy: true,
2122 }
2123 }
2124}
2125
2126#[derive(Debug, Clone, Serialize, Deserialize, Default)]
2128#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
2129#[serde(default)]
2130pub struct ObservabilityConfig {
2131 pub prometheus: PrometheusConfig,
2133 pub opentelemetry: Option<OpenTelemetryConfig>,
2135 pub recorder: Option<RecorderConfig>,
2137 pub chaos: Option<ChaosEngConfig>,
2139}
2140
2141#[derive(Debug, Clone, Serialize, Deserialize, Default)]
2145#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
2146#[serde(default)]
2147pub struct ChaosEngConfig {
2148 pub enabled: bool,
2150 pub latency: Option<LatencyInjectionConfig>,
2152 pub fault_injection: Option<FaultConfig>,
2154 pub rate_limit: Option<RateLimitingConfig>,
2156 pub traffic_shaping: Option<NetworkShapingConfig>,
2158 pub scenario: Option<String>,
2160}
2161
2162#[derive(Debug, Clone, Serialize, Deserialize)]
2164#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
2165pub struct LatencyInjectionConfig {
2166 pub enabled: bool,
2168 pub fixed_delay_ms: Option<u64>,
2170 pub random_delay_range_ms: Option<(u64, u64)>,
2172 pub jitter_percent: f64,
2174 pub probability: f64,
2176}
2177
2178#[derive(Debug, Clone, Serialize, Deserialize)]
2180#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
2181pub struct FaultConfig {
2182 pub enabled: bool,
2184 pub http_errors: Vec<u16>,
2186 pub http_error_probability: f64,
2188 pub connection_errors: bool,
2190 pub connection_error_probability: f64,
2192 pub timeout_errors: bool,
2194 pub timeout_ms: u64,
2196 pub timeout_probability: f64,
2198}
2199
2200#[derive(Debug, Clone, Serialize, Deserialize)]
2202#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
2203pub struct RateLimitingConfig {
2204 pub enabled: bool,
2206 pub requests_per_second: u32,
2208 pub burst_size: u32,
2210 pub per_ip: bool,
2212 pub per_endpoint: bool,
2214}
2215
2216#[derive(Debug, Clone, Serialize, Deserialize)]
2218#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
2219pub struct NetworkShapingConfig {
2220 pub enabled: bool,
2222 pub bandwidth_limit_bps: u64,
2224 pub packet_loss_percent: f64,
2226 pub max_connections: u32,
2228}
2229
2230#[derive(Debug, Clone, Serialize, Deserialize)]
2234#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
2235pub struct IncidentStorageConfig {
2236 pub use_cache: bool,
2238 pub use_database: bool,
2240 pub retention_days: u32,
2242}
2243
2244impl Default for IncidentStorageConfig {
2245 fn default() -> Self {
2246 Self {
2247 use_cache: true,
2248 use_database: true,
2249 retention_days: 90,
2250 }
2251 }
2252}
2253
2254#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
2261#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
2262#[serde(rename_all = "snake_case")]
2263#[derive(Default)]
2264pub enum RealityLevel {
2265 StaticStubs = 1,
2267 LightSimulation = 2,
2269 #[default]
2271 ModerateRealism = 3,
2272 HighRealism = 4,
2274 ProductionChaos = 5,
2276}
2277
2278impl RealityLevel {
2279 pub fn value(&self) -> u8 {
2281 *self as u8
2282 }
2283
2284 pub fn name(&self) -> &'static str {
2286 match self {
2287 RealityLevel::StaticStubs => "Static Stubs",
2288 RealityLevel::LightSimulation => "Light Simulation",
2289 RealityLevel::ModerateRealism => "Moderate Realism",
2290 RealityLevel::HighRealism => "High Realism",
2291 RealityLevel::ProductionChaos => "Production Chaos",
2292 }
2293 }
2294
2295 pub fn description(&self) -> &'static str {
2297 match self {
2298 RealityLevel::StaticStubs => "Simple, instant responses with no chaos",
2299 RealityLevel::LightSimulation => "Minimal latency, basic intelligence",
2300 RealityLevel::ModerateRealism => "Some chaos, moderate latency, full intelligence",
2301 RealityLevel::HighRealism => "Increased chaos, realistic latency, session state",
2302 RealityLevel::ProductionChaos => {
2303 "Maximum chaos, production-like latency, full features"
2304 }
2305 }
2306 }
2307
2308 pub fn from_value(value: u8) -> Option<Self> {
2310 match value {
2311 1 => Some(RealityLevel::StaticStubs),
2312 2 => Some(RealityLevel::LightSimulation),
2313 3 => Some(RealityLevel::ModerateRealism),
2314 4 => Some(RealityLevel::HighRealism),
2315 5 => Some(RealityLevel::ProductionChaos),
2316 _ => None,
2317 }
2318 }
2319
2320 pub fn all() -> Vec<Self> {
2322 vec![
2323 RealityLevel::StaticStubs,
2324 RealityLevel::LightSimulation,
2325 RealityLevel::ModerateRealism,
2326 RealityLevel::HighRealism,
2327 RealityLevel::ProductionChaos,
2328 ]
2329 }
2330}
2331
2332#[derive(Debug, Clone, Serialize, Deserialize)]
2338#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
2339#[serde(default)]
2340pub struct RealitySliderConfig {
2341 pub level: RealityLevel,
2343 pub enabled: bool,
2345}
2346
2347impl Default for RealitySliderConfig {
2348 fn default() -> Self {
2349 Self {
2350 level: RealityLevel::ModerateRealism,
2351 enabled: true,
2352 }
2353 }
2354}