1use crate::apiversioning::Version;
8use crate::error::{CoreError, CoreResult, ErrorContext};
9use std::collections::{HashMap, HashSet};
10use std::sync::{Arc, RwLock};
11use std::time::{Duration, Instant};
12
13static GLOBAL_VALIDATOR: std::sync::OnceLock<Arc<EcosystemValidator>> = std::sync::OnceLock::new();
15
16#[derive(Debug)]
18pub struct EcosystemValidator {
19 registry: Arc<RwLock<ModuleRegistry>>,
20 compatibilitymatrix: Arc<RwLock<CompatibilityMatrix>>,
21 validation_cache: Arc<RwLock<ValidationCache>>,
22 policies: Arc<RwLock<ValidationPolicies>>,
23}
24
25#[allow(dead_code)]
26impl EcosystemValidator {
27 pub fn new() -> CoreResult<Self> {
29 Ok(Self {
30 registry: Arc::new(RwLock::new(ModuleRegistry::new())),
31 compatibilitymatrix: Arc::new(RwLock::new(CompatibilityMatrix::new())),
32 validation_cache: Arc::new(RwLock::new(ValidationCache::new())),
33 policies: Arc::new(RwLock::new(ValidationPolicies::default())),
34 })
35 }
36
37 pub fn global() -> CoreResult<Arc<Self>> {
39 Ok(GLOBAL_VALIDATOR
40 .get_or_init(|| Arc::new(Self::new().expect("Operation failed")))
41 .clone())
42 }
43
44 pub fn register_module(&self, module: ModuleInfo) -> CoreResult<()> {
46 let mut registry = self.registry.write().map_err(|_| {
47 CoreError::InvalidState(crate::error::ErrorContext {
48 message: "Failed to acquire registry lock".to_string(),
49 location: None,
50 cause: None,
51 })
52 })?;
53
54 registry.register(module)?;
55
56 let mut cache = self.validation_cache.write().map_err(|_| {
58 CoreError::InvalidState(ErrorContext {
59 message: "Failed to acquire cache lock".to_string(),
60 location: Some(crate::error::ErrorLocation::new(file!(), line!())),
61 cause: None,
62 })
63 })?;
64 cache.invalidate_module_related_cache();
65
66 Ok(())
67 }
68
69 pub fn validate_ecosystem(&self) -> CoreResult<EcosystemValidationResult> {
71 let start_time = Instant::now();
72
73 {
75 let cache = self.validation_cache.read().map_err(|_| {
76 CoreError::InvalidState(ErrorContext {
77 message: "Failed to acquire cache lock".to_string(),
78 location: Some(crate::error::ErrorLocation::new(file!(), line!())),
79 cause: None,
80 })
81 })?;
82 if let Some(cachedresult) = cache.get_ecosystem_validation() {
83 if cachedresult.is_recent(Duration::from_secs(300)) {
84 return Ok(cachedresult.result.clone());
86 }
87 }
88 }
89
90 let registry = self.registry.read().map_err(|_| {
91 CoreError::InvalidState(crate::error::ErrorContext {
92 message: "Failed to acquire registry lock".to_string(),
93 location: None,
94 cause: None,
95 })
96 })?;
97 let policies = self.policies.read().map_err(|_| {
98 CoreError::InvalidState(ErrorContext {
99 message: "Failed to acquire policies lock".to_string(),
100 location: Some(crate::error::ErrorLocation::new(file!(), line!())),
101 cause: None,
102 })
103 })?;
104
105 let mut result = EcosystemValidationResult::new();
106
107 for module in registry.all_modules() {
109 let moduleresult = self.validate_module_internal(module, &policies)?;
110 result.add_moduleresult(module.name.clone(), moduleresult);
111 }
112
113 let compatibilityresult = self.validate_inter_module_compatibility(®istry, &policies)?;
115 result.add_compatibilityresult(compatibilityresult);
116
117 let api_stabilityresult = self.validate_api_stability(®istry, &policies)?;
119 result.add_api_stabilityresult(api_stabilityresult);
120
121 let version_consistencyresult = self.validate_version_consistency(®istry)?;
123 result.add_version_consistencyresult(version_consistencyresult);
124
125 result.validation_time = start_time.elapsed();
126 result.timestamp = Instant::now();
127
128 {
130 let mut cache = self.validation_cache.write().map_err(|_| {
131 CoreError::InvalidState(ErrorContext {
132 message: "Failed to acquire cache lock".to_string(),
133 location: Some(crate::error::ErrorLocation::new(file!(), line!())),
134 cause: None,
135 })
136 })?;
137 cache.cache_ecosystem_validation(result.clone());
138 }
139
140 Ok(result)
141 }
142
143 pub fn validate_module(&self, modulename: &str) -> CoreResult<ModuleValidationResult> {
145 let registry = self.registry.read().map_err(|_| {
146 CoreError::InvalidState(crate::error::ErrorContext {
147 message: "Failed to acquire registry lock".to_string(),
148 location: None,
149 cause: None,
150 })
151 })?;
152 let policies = self.policies.read().map_err(|_| {
153 CoreError::InvalidState(ErrorContext {
154 message: "Failed to acquire policies lock".to_string(),
155 location: Some(crate::error::ErrorLocation::new(file!(), line!())),
156 cause: None,
157 })
158 })?;
159
160 let module = registry.get_module(modulename).ok_or_else(|| {
161 CoreError::ValidationError(ErrorContext {
162 message: format!("Module '{modulename}' not found in registry"),
163 location: None,
164 cause: None,
165 })
166 })?;
167
168 self.validate_module_internal(module, &policies)
169 }
170
171 fn validate_module_internal(
172 &self,
173 module: &ModuleInfo,
174 policies: &ValidationPolicies,
175 ) -> CoreResult<ModuleValidationResult> {
176 let mut result = ModuleValidationResult::new(module.name.clone());
177
178 if let Err(e) = Version::parse(&module.version) {
180 result.adderror(ValidationError::new(
181 ValidationErrorType::InvalidVersion,
182 format!("Invalid _version format '{}': {}", module.version, e),
183 ));
184 }
185
186 for dep in &module.dependencies {
188 let depresult = self.validate_dependencypolicies(module, dep, policies)?;
189 if !depresult.is_valid() {
190 result.adderror(ValidationError::new(
191 ValidationErrorType::DependencyError,
192 format!("Dependency validation failed for '{}'", dep.name),
193 ));
194 }
195 }
196
197 let apiresult = ApiStabilityCheck {
201 is_stable: true,
202 breakingchanges: Vec::new(),
203 };
204 if !apiresult.is_valid() {
205 result.adderror(ValidationError::new(
206 ValidationErrorType::ApiCompatibility,
207 "API surface validation failed".to_string(),
208 ));
209 }
210
211 for feature in &module.features {
213 if !self.is_feature_compatible(feature, policies)? {
214 result.add_warning(ValidationWarning::new(
215 ValidationWarningType::FeatureCompatibility,
216 format!("Feature '{feature}' may have compatibility issues"),
217 ));
218 }
219 }
220
221 if policies.enforce_security_checks {
223 let securityresult = self.validate_module_security(module)?;
224 if !securityresult.is_secure() {
225 result.adderror(ValidationError::new(
226 ValidationErrorType::SecurityViolation,
227 "Module failed security validation".to_string(),
228 ));
229 }
230 }
231
232 Ok(result)
233 }
234
235 fn validate_dependencypolicies(
236 &self,
237 module: &ModuleInfo,
238 dep: &DependencyInfo,
239 policies: &ValidationPolicies,
240 ) -> CoreResult<DependencyValidationResult> {
241 let mut result = DependencyValidationResult::new(dep.name.clone());
242
243 let registry = self.registry.read().map_err(|_| {
245 CoreError::InvalidState(crate::error::ErrorContext {
246 message: "Failed to acquire registry lock".to_string(),
247 location: None,
248 cause: None,
249 })
250 })?;
251
252 if let Some(dep_module) = registry.get_module(&dep.name) {
253 let dep_version = Version::parse(&dep_module.version).map_err(|e| {
255 CoreError::ValidationError(ErrorContext {
256 message: format!("Invalid dependency version: {e}"),
257 location: None,
258 cause: None,
259 })
260 })?;
261
262 if !dep.version_requirement.version(&dep_version) {
263 result.add_incompatibility(format!(
264 "Version mismatch: required {}, found {}",
265 dep.version_requirement, dep_version
266 ));
267 }
268
269 if self.has_circular_dependency(&module.name, &dep.name) {
271 result.add_incompatibility("Circular dependency detected".to_string());
272 }
273 } else {
274 result.add_incompatibility("Dependency not found in ecosystem".to_string());
275 }
276
277 Ok(result)
278 }
279
280 fn validate_inter_module_compatibility(
281 &self,
282 registry: &ModuleRegistry,
283 policies: &ValidationPolicies,
284 ) -> CoreResult<CompatibilityValidationResult> {
285 let mut result = CompatibilityValidationResult::new();
286 let modules = registry.all_modules();
287
288 let mut matrix = self.compatibilitymatrix.write().map_err(|_| {
290 CoreError::InvalidState(ErrorContext::new(
291 "Failed to acquire matrix lock".to_string(),
292 ))
293 })?;
294
295 for module_a in &modules {
296 for module_b in &modules {
297 if module_a.name != module_b.name {
298 let compatibility =
299 self.check_module_compatibility(module_a, module_b, policies)?;
300 (*matrix).b(&module_a.name, &module_b.name, compatibility.clone());
301
302 if !compatibility.is_compatible() {
303 result.add_incompatibility(format!(
304 "Modules '{}' and '{}' are incompatible: {}",
305 module_a.name,
306 module_b.name,
307 compatibility.reason_2()
308 ));
309 }
310 }
311 }
312 }
313
314 Ok(result)
315 }
316
317 fn check_module_compatibility(
318 &self,
319 module_a: &ModuleInfo,
320 module_b: &ModuleInfo,
321 policies: &ValidationPolicies,
322 ) -> CoreResult<ModuleCompatibility> {
323 let version_a = Version::parse(&module_a.version).map_err(|e| {
325 CoreError::ValidationError(ErrorContext {
326 message: format!("Invalid _version for module '{}': {}", module_a.name, e),
327 location: Some(crate::error::ErrorLocation::new(file!(), line!())),
328 cause: None,
329 })
330 })?;
331 let version_b = Version::parse(&module_b.version).map_err(|e| {
332 CoreError::ValidationError(ErrorContext {
333 message: format!("Invalid _version for module '{}': {}", module_b.name, e),
334 location: Some(crate::error::ErrorLocation::new(file!(), line!())),
335 cause: None,
336 })
337 })?;
338
339 if !self.areversions_compatible(&version_a.to_string(), &version_b.to_string()) {
340 return Ok(ModuleCompatibility::incompatible(format!(
341 "Version incompatibility: {version_a} vs {version_b}"
342 )));
343 }
344
345 if !self.are_apis_compatible(&module_a.apisurface, &module_b.apisurface) {
347 return Ok(ModuleCompatibility::incompatible(
348 "API incompatibility".to_string(),
349 ));
350 }
351
352 if !self.are_features_compatible(&module_a.features, &module_b.features) {
354 return Ok(ModuleCompatibility::incompatible(
355 "Feature incompatibility".to_string(),
356 ));
357 }
358
359 Ok(ModuleCompatibility::compatible())
360 }
361
362 fn validate_api_stability(
363 &self,
364 registry: &ModuleRegistry,
365 policies: &ValidationPolicies,
366 ) -> CoreResult<ApiStabilityResult> {
367 let mut result = ApiStabilityResult::new();
368
369 for module in registry.all_modules() {
370 if let Some(_previous_version) = registry.get_previous_version(&module.name) {
372 let stability_check = self.check_api_stability(&module.name);
373 if !stability_check.is_stable() {
374 result.add_breaking_change(
375 module.name.clone(),
376 stability_check.breakingchanges().to_vec(),
377 );
378 }
379 }
380
381 if !self.is_api_properly_versioned(&module.apisurface) {
383 result.add_versioning_violation(
384 module.name.clone(),
385 "API not properly versioned".to_string(),
386 );
387 }
388 }
389
390 Ok(result)
391 }
392
393 fn validate_version_consistency(
394 &self,
395 registry: &ModuleRegistry,
396 ) -> CoreResult<VersionConsistencyResult> {
397 let mut result = VersionConsistencyResult::new();
398 let modules = registry.all_modules();
399
400 let mut version_map: HashMap<String, Vec<Version>> = HashMap::new();
402
403 for module in &modules {
404 let version = Version::parse(&module.version).map_err(|e| {
405 CoreError::ValidationError(ErrorContext {
406 message: format!("Invalid version for module '{}': {}", module.name, e),
407 location: Some(crate::error::ErrorLocation::new(file!(), line!())),
408 cause: None,
409 })
410 })?;
411 version_map
412 .entry(module.name.clone())
413 .or_default()
414 .push(version);
415 }
416
417 for (modulename, versions) in version_map {
418 if versions.len() > 1 {
419 result.add_conflict(modulename, versions);
420 }
421 }
422
423 for module in &modules {
425 for dep in &module.dependencies {
426 if let Some(dep_module) = registry.get_module(&dep.name) {
427 let dep_version = Version::parse(&dep_module.version).map_err(|e| {
428 CoreError::ValidationError(ErrorContext {
429 message: format!(
430 "Invalid _version format for dependency {}: {}",
431 dep.name, e
432 ),
433 location: Some(crate::error::ErrorLocation::new(file!(), line!())),
434 cause: None,
435 })
436 })?;
437 if !dep.version_requirement.version(&dep_version) {
438 result.add_dependency_mismatch(
439 module.name.clone(),
440 dep.name.clone(),
441 dep.version_requirement.clone(),
442 dep_version,
443 );
444 }
445 }
446 }
447 }
448
449 Ok(result)
450 }
451
452 #[allow(dead_code)]
453 fn surface(
454 &self,
455 apisurface: &ApiSurface,
456 policies: &ValidationPolicies,
457 ) -> CoreResult<ApiValidationResult> {
458 let mut result = ApiValidationResult::new();
459
460 for api in &apisurface.public_apis {
462 if !self.is_api_properly_documented(api)? {
463 result.add_documentation_issue(api.name.clone());
464 }
465
466 if policies.enforce_semver && !self.is_api_semver_compliant(api)? {
467 result.add_semver_violation(api.name.clone());
468 }
469 }
470
471 for api in &apisurface.deprecated_apis {
473 if !api.has_migration_path() {
474 result.add_deprecation_issue(
475 api.name.clone(),
476 "No migration path provided".to_string(),
477 );
478 }
479 }
480
481 Ok(result)
482 }
483
484 fn validate_module_security(
485 &self,
486 module: &ModuleInfo,
487 ) -> CoreResult<SecurityValidationResult> {
488 let mut result = SecurityValidationResult::new(module.name.clone());
489
490 for dep in &module.dependencies {
492 if self.has_known_vulnerabilities(&dep.name) {
493 result.add_vulnerability(format!(
494 "Dependency '{}' has known vulnerabilities",
495 dep.name
496 ));
497 }
498 }
499
500 if !module.features.contains(&"security".to_string())
502 && self.requires_security_features(module)?
503 {
504 result.add_security_issue("Module should enable security features".to_string());
505 }
506
507 Ok(result)
508 }
509
510 #[allow(dead_code)]
512 fn check_circular_dependencies(
513 &self,
514 modulename: &str,
515 dependencies: &[DependencyInfo],
516 ) -> CoreResult<bool> {
517 for dep in dependencies {
519 if dep.name == modulename {
520 return Ok(true);
521 }
522 }
523 Ok(false)
524 }
525
526 fn check_version_compatibility(
527 &self,
528 version_a: &Version,
529 version_b: &Version,
530 policies: &ValidationPolicies,
531 ) -> bool {
532 if policies.strict_version_matching {
533 version_a == version_b
534 } else {
535 version_a.major == version_b.major
537 }
538 }
539
540 fn check_api_compatibility(&self, api_a: &ApiSurface, apib: &ApiSurface) -> CoreResult<bool> {
541 Ok(api_a.public_apis.len() == apib.public_apis.len())
544 }
545
546 fn check_feature_compatibility(
547 &self,
548 _features_a: &[String],
549 _features_b: &[String],
550 ) -> CoreResult<bool> {
551 Ok(true)
555 }
556
557 fn validate_apipolicies(
558 &self,
559 previous: &ApiSurface,
560 current: &ApiSurface,
561 policies: &ValidationPolicies,
562 ) -> CoreResult<ApiStabilityCheck> {
563 let mut breakingchanges = Vec::new();
564
565 for prev_api in &previous.public_apis {
567 if !current
568 .public_apis
569 .iter()
570 .any(|api| api.name == prev_api.name)
571 {
572 breakingchanges.push(format!("API '{}' was removed", prev_api.name));
573 }
574 }
575
576 for current_api in ¤t.public_apis {
578 if let Some(prev_api) = previous
579 .public_apis
580 .iter()
581 .find(|api| api.name == current_api.name)
582 {
583 if current_api.signature != prev_api.signature {
584 breakingchanges.push(format!("API '{}' signature changed", current_api.name));
585 }
586 }
587 }
588
589 Ok(ApiStabilityCheck::new(
590 breakingchanges.is_empty(),
591 breakingchanges,
592 ))
593 }
594
595 fn is_apisurface_versioned(&self, apisurface: &ApiSurface) -> CoreResult<bool> {
596 for api in &apisurface.public_apis {
598 if api.since_version.is_none() {
599 return Ok(false);
600 }
601 }
602 Ok(true)
603 }
604
605 fn is_feature_compatible(
606 &self,
607 feature: &str,
608 policies: &ValidationPolicies,
609 ) -> CoreResult<bool> {
610 Ok(!policies.incompatible_features.contains(feature))
612 }
613
614 fn is_api_properly_documented(&self, api: &ApiInfo) -> CoreResult<bool> {
615 Ok(!api.documentation.is_empty())
616 }
617
618 fn is_api_semver_compliant(&self, api: &ApiInfo) -> CoreResult<bool> {
619 Ok(api.since_version.is_some())
621 }
622
623 fn req(&self, _module: &ModuleInfo, _versionreq: &VersionRequirement) -> CoreResult<bool> {
624 Ok(false)
626 }
627
628 fn requires_security_features(&self, module: &ModuleInfo) -> CoreResult<bool> {
629 Ok(module.name.contains("network") || module.name.contains("auth"))
631 }
632
633 pub fn updatepolicies(&self, newpolicies: ValidationPolicies) -> CoreResult<()> {
635 let mut policies = self.policies.write().map_err(|_| {
636 CoreError::InvalidState(ErrorContext::new(
637 "Failed to acquire policies lock".to_string(),
638 ))
639 })?;
640 *policies = newpolicies;
641
642 let mut cache = self.validation_cache.write().map_err(|_| {
644 CoreError::InvalidState(ErrorContext::new(
645 "Failed to acquire cache lock".to_string(),
646 ))
647 })?;
648 cache.clear();
649
650 Ok(())
651 }
652
653 pub fn get_ecosystem_health(&self) -> CoreResult<EcosystemHealth> {
655 let validationresult = self.validate_ecosystem()?;
656 Ok(EcosystemHealth::from_validationresult(&validationresult))
657 }
658
659 pub fn has_circular_dependency(&self, _module: &str, dependency: &str) -> bool {
660 false
662 }
663
664 pub fn areversions_compatible(&self, _version_a: &str, _versionb: &str) -> bool {
665 true
667 }
668
669 pub fn are_apis_compatible(&self, _api_a: &ApiSurface, _apib: &ApiSurface) -> bool {
670 true
672 }
673
674 pub fn are_features_compatible(&self, _features_a: &[String], _featuresb: &[String]) -> bool {
675 true
677 }
678
679 pub fn check_api_stability(&self, module: &str) -> ApiStabilityCheck {
680 ApiStabilityCheck::new(true, vec![])
682 }
683
684 pub fn is_api_properly_versioned(&self, _apisurface: &ApiSurface) -> bool {
685 true
687 }
688
689 pub fn has_known_vulnerabilities(&self, module: &str) -> bool {
690 false
692 }
693}
694
695#[derive(Debug)]
697pub struct ModuleRegistry {
698 modules: HashMap<String, ModuleInfo>,
699 previousversions: HashMap<String, ModuleInfo>,
700}
701
702impl ModuleRegistry {
703 pub fn new() -> Self {
704 Self {
705 modules: HashMap::new(),
706 previousversions: HashMap::new(),
707 }
708 }
709
710 pub fn register(&mut self, module: ModuleInfo) -> CoreResult<()> {
711 if let Some(existing) = self.modules.get(&module.name) {
713 self.previousversions
714 .insert(module.name.clone(), existing.clone());
715 }
716
717 self.modules.insert(module.name.clone(), module);
718 Ok(())
719 }
720
721 pub fn get_module(&self, name: &str) -> Option<&ModuleInfo> {
722 self.modules.get(name)
723 }
724
725 pub fn get_previous_version(&self, name: &str) -> Option<&ModuleInfo> {
726 self.previousversions.get(name)
727 }
728
729 pub fn all_modules(&self) -> Vec<&ModuleInfo> {
730 self.modules.values().collect()
731 }
732
733 pub fn module_count(&self) -> usize {
734 self.modules.len()
735 }
736}
737
738impl Default for ModuleRegistry {
739 fn default() -> Self {
740 Self::new()
741 }
742}
743
744#[derive(Debug, Clone)]
746pub struct ModuleInfo {
747 pub name: String,
748 pub version: String,
749 pub dependencies: Vec<DependencyInfo>,
750 pub apisurface: ApiSurface,
751 pub features: Vec<String>,
752 pub metadata: ModuleMetadata,
753}
754
755#[derive(Debug, Clone)]
756pub struct DependencyInfo {
757 pub name: String,
758 pub version_requirement: VersionRequirement,
759 pub optional: bool,
760}
761
762#[derive(Debug, Clone)]
763pub struct VersionRequirement {
764 pub requirement: String,
765}
766
767impl VersionRequirement {
768 pub fn new(requirement: &str) -> Self {
769 Self {
770 requirement: requirement.to_string(),
771 }
772 }
773
774 pub fn version(&self, version: &Version) -> bool {
775 self.requirement == version.to_string()
778 }
779}
780
781impl std::fmt::Display for VersionRequirement {
782 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
783 write!(f, "{}", self.requirement)
784 }
785}
786
787#[derive(Debug, Clone)]
788pub struct ApiSurface {
789 pub public_apis: Vec<ApiInfo>,
790 pub deprecated_apis: Vec<DeprecatedApiInfo>,
791}
792
793#[derive(Debug, Clone)]
794pub struct ApiInfo {
795 pub name: String,
796 pub signature: String,
797 pub documentation: String,
798 pub since_version: Option<Version>,
799 pub stability: ApiStability,
800}
801
802#[derive(Debug, Clone)]
803pub struct DeprecatedApiInfo {
804 pub name: String,
805 pub deprecated_since: Version,
806 pub removal_version: Option<Version>,
807 pub migration_path: Option<String>,
808}
809
810impl DeprecatedApiInfo {
811 pub fn has_migration_path(&self) -> bool {
812 self.migration_path.is_some()
813 }
814}
815
816#[derive(Debug, Clone, Copy, PartialEq, Eq)]
817pub enum ApiStability {
818 Stable,
819 Unstable,
820 Experimental,
821}
822
823#[derive(Debug, Clone)]
824pub struct ModuleMetadata {
825 pub author: String,
826 pub description: String,
827 pub license: String,
828 pub repository: Option<String>,
829 pub build_time: Option<String>,
830}
831
832#[derive(Debug)]
834pub struct CompatibilityMatrix {
835 matrix: HashMap<(String, String), ModuleCompatibility>,
836}
837
838impl CompatibilityMatrix {
839 pub fn new() -> Self {
840 Self {
841 matrix: HashMap::new(),
842 }
843 }
844
845 pub fn b(&mut self, module_a: &str, moduleb: &str, compatibility: ModuleCompatibility) {
846 self.matrix
847 .insert((module_a.to_string(), moduleb.to_string()), compatibility);
848 }
849
850 pub fn b_2(&self, module_a: &str, moduleb: &str) -> Option<&ModuleCompatibility> {
851 self.matrix
852 .get(&(module_a.to_string(), moduleb.to_string()))
853 }
854}
855
856impl Default for CompatibilityMatrix {
857 fn default() -> Self {
858 Self::new()
859 }
860}
861
862#[derive(Debug, Clone)]
863pub struct ModuleCompatibility {
864 compatible: bool,
865 reason: String,
866}
867
868impl ModuleCompatibility {
869 pub fn compatible() -> Self {
870 Self {
871 compatible: true,
872 reason: String::new(),
873 }
874 }
875
876 pub fn incompatible(reason: String) -> Self {
877 Self {
878 compatible: false,
879 reason,
880 }
881 }
882}
883
884impl ModuleCompatibility {
885 pub fn is_compatible(&self) -> bool {
886 self.compatible
887 }
888
889 pub fn reason_2(&self) -> &str {
890 &self.reason
891 }
892}
893
894#[derive(Debug)]
896pub struct ValidationCache {
897 ecosystem_validation: Option<CachedValidationResult>,
898 module_validations: HashMap<String, CachedModuleValidation>,
899}
900
901impl ValidationCache {
902 pub fn new() -> Self {
903 Self {
904 ecosystem_validation: None,
905 module_validations: HashMap::new(),
906 }
907 }
908
909 pub fn cache_ecosystem_validation(&mut self, result: EcosystemValidationResult) {
910 self.ecosystem_validation = Some(CachedValidationResult {
911 result,
912 timestamp: Instant::now(),
913 });
914 }
915
916 pub fn get_ecosystem_validation(&self) -> Option<&CachedValidationResult> {
917 self.ecosystem_validation.as_ref()
918 }
919
920 pub fn invalidate_module_related_cache(&mut self) {
921 self.ecosystem_validation = None;
922 self.module_validations.clear();
923 }
924
925 pub fn clear(&mut self) {
926 self.ecosystem_validation = None;
927 self.module_validations.clear();
928 }
929}
930
931impl Default for ValidationCache {
932 fn default() -> Self {
933 Self::new()
934 }
935}
936
937#[derive(Debug, Clone)]
938pub struct CachedValidationResult {
939 pub result: EcosystemValidationResult,
940 pub timestamp: Instant,
941}
942
943impl CachedValidationResult {
944 pub fn age(&self, maxage: Duration) -> bool {
945 self.timestamp.elapsed() < maxage
946 }
947
948 pub fn is_recent(&self, maxage: Duration) -> bool {
949 self.age(maxage)
950 }
951}
952
953#[derive(Debug)]
954pub struct CachedModuleValidation {
955 pub result: ModuleValidationResult,
956 pub timestamp: Instant,
957}
958
959#[derive(Debug, Clone)]
961pub struct ValidationPolicies {
962 pub enforce_semver: bool,
963 pub strict_version_matching: bool,
964 pub enforce_security_checks: bool,
965 pub allow_deprecated_apis: bool,
966 pub max_dependency_depth: usize,
967 pub incompatible_features: HashSet<String>,
968 pub required_features: HashSet<String>,
969}
970
971impl Default for ValidationPolicies {
972 fn default() -> Self {
973 Self {
974 enforce_semver: true,
975 strict_version_matching: false,
976 enforce_security_checks: true,
977 allow_deprecated_apis: true,
978 max_dependency_depth: 10,
979 incompatible_features: HashSet::new(),
980 required_features: HashSet::new(),
981 }
982 }
983}
984
985#[derive(Debug, Clone)]
987pub struct EcosystemValidationResult {
988 pub timestamp: Instant,
989 pub validation_time: Duration,
990 pub moduleresults: HashMap<String, ModuleValidationResult>,
991 pub compatibilityresult: CompatibilityValidationResult,
992 pub api_stabilityresult: ApiStabilityResult,
993 pub version_consistencyresult: VersionConsistencyResult,
994 pub overall_status: ValidationStatus,
995}
996
997impl EcosystemValidationResult {
998 pub fn new() -> Self {
999 Self {
1000 timestamp: Instant::now(),
1001 validation_time: Duration::ZERO,
1002 moduleresults: HashMap::new(),
1003 compatibilityresult: CompatibilityValidationResult::new(),
1004 api_stabilityresult: ApiStabilityResult::new(),
1005 version_consistencyresult: VersionConsistencyResult::new(),
1006 overall_status: ValidationStatus::Unknown,
1007 }
1008 }
1009
1010 pub fn name(&mut self, modulename: String, result: ModuleValidationResult) {
1011 self.moduleresults.insert(modulename, result);
1012 self.update_overall_status();
1013 }
1014
1015 pub fn add_moduleresult(&mut self, modulename: String, result: ModuleValidationResult) {
1016 self.moduleresults.insert(modulename, result);
1017 self.update_overall_status();
1018 }
1019
1020 pub fn add_compatibilityresult(&mut self, result: CompatibilityValidationResult) {
1021 self.compatibilityresult = result;
1022 self.update_overall_status();
1023 }
1024
1025 pub fn add_api_stabilityresult(&mut self, result: ApiStabilityResult) {
1026 self.api_stabilityresult = result;
1027 self.update_overall_status();
1028 }
1029
1030 pub fn add_version_consistencyresult(&mut self, result: VersionConsistencyResult) {
1031 self.version_consistencyresult = result;
1032 self.update_overall_status();
1033 }
1034
1035 fn update_overall_status(&mut self) {
1036 let haserrors = self.moduleresults.values().any(|r| !r.errors.is_empty())
1037 || !self.compatibilityresult.incompatibilities.is_empty()
1038 || !self.api_stabilityresult.breakingchanges.is_empty()
1039 || !self.version_consistencyresult.conflicts.is_empty();
1040
1041 let has_warnings = self.moduleresults.values().any(|r| !r.warnings.is_empty());
1042
1043 self.overall_status = if haserrors {
1044 ValidationStatus::Failed
1045 } else if has_warnings {
1046 ValidationStatus::Warning
1047 } else {
1048 ValidationStatus::Passed
1049 };
1050 }
1051
1052 pub fn is_valid(&self) -> bool {
1053 matches!(
1054 self.overall_status,
1055 ValidationStatus::Passed | ValidationStatus::Warning
1056 )
1057 }
1058
1059 pub fn error_count(&self) -> usize {
1060 self.moduleresults
1061 .values()
1062 .map(|r| r.errors.len())
1063 .sum::<usize>()
1064 + self.compatibilityresult.incompatibilities.len()
1065 + self.api_stabilityresult.breakingchanges.len()
1066 + self.version_consistencyresult.conflicts.len()
1067 }
1068
1069 pub fn warning_count(&self) -> usize {
1070 self.moduleresults.values().map(|r| r.warnings.len()).sum()
1071 }
1072}
1073
1074impl Default for EcosystemValidationResult {
1075 fn default() -> Self {
1076 Self::new()
1077 }
1078}
1079
1080#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1081pub enum ValidationStatus {
1082 Unknown,
1083 Passed,
1084 Warning,
1085 Failed,
1086}
1087
1088#[derive(Debug, Clone)]
1090pub struct ModuleValidationResult {
1091 pub modulename: String,
1092 pub errors: Vec<ValidationError>,
1093 pub warnings: Vec<ValidationWarning>,
1094 pub status: ValidationStatus,
1095}
1096
1097impl ModuleValidationResult {
1098 pub fn new(modulename: String) -> Self {
1099 Self {
1100 modulename,
1101 errors: Vec::new(),
1102 warnings: Vec::new(),
1103 status: ValidationStatus::Unknown,
1104 }
1105 }
1106
1107 pub fn adderror(&mut self, error: ValidationError) {
1108 self.errors.push(error);
1109 self.status = ValidationStatus::Failed;
1110 }
1111
1112 pub fn add_warning(&mut self, warning: ValidationWarning) {
1113 self.warnings.push(warning);
1114 if self.status == ValidationStatus::Unknown {
1115 self.status = ValidationStatus::Warning;
1116 }
1117 }
1118
1119 pub fn is_valid(&self) -> bool {
1120 self.errors.is_empty()
1121 }
1122}
1123
1124#[derive(Debug, Clone)]
1125pub struct ValidationError {
1126 pub errortype: ValidationErrorType,
1127 pub message: String,
1128 pub context: Option<String>,
1129}
1130
1131impl ValidationError {
1132 pub fn new(errortype: ValidationErrorType, message: String) -> Self {
1133 Self {
1134 errortype,
1135 message,
1136 context: None,
1137 }
1138 }
1139}
1140
1141#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1142pub enum ValidationErrorType {
1143 InvalidVersion,
1144 DependencyError,
1145 ApiCompatibility,
1146 SecurityViolation,
1147 FeatureConflict,
1148}
1149
1150#[derive(Debug, Clone)]
1151pub struct ValidationWarning {
1152 pub warningtype: ValidationWarningType,
1153 pub message: String,
1154}
1155
1156impl ValidationWarning {
1157 pub fn new(warningtype: ValidationWarningType, message: String) -> Self {
1158 Self {
1159 warningtype,
1160 message,
1161 }
1162 }
1163}
1164
1165#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1166pub enum ValidationWarningType {
1167 FeatureCompatibility,
1168 PerformanceImpact,
1169 DeprecationWarning,
1170}
1171
1172#[derive(Debug, Clone)]
1174pub struct CompatibilityValidationResult {
1175 pub incompatibilities: Vec<String>,
1176}
1177
1178impl CompatibilityValidationResult {
1179 pub fn new() -> Self {
1180 Self {
1181 incompatibilities: Vec::new(),
1182 }
1183 }
1184
1185 pub fn add_incompatibility(&mut self, incompatibility: String) {
1186 self.incompatibilities.push(incompatibility);
1187 }
1188}
1189
1190impl Default for CompatibilityValidationResult {
1191 fn default() -> Self {
1192 Self::new()
1193 }
1194}
1195
1196#[derive(Debug, Clone)]
1197pub struct ApiStabilityResult {
1198 pub breakingchanges: HashMap<String, Vec<String>>,
1199 pub versioning_violations: HashMap<String, String>,
1200}
1201
1202impl ApiStabilityResult {
1203 pub fn new() -> Self {
1204 Self {
1205 breakingchanges: HashMap::new(),
1206 versioning_violations: HashMap::new(),
1207 }
1208 }
1209
1210 pub fn add_breaking_change(&mut self, module: String, changes: Vec<String>) {
1211 self.breakingchanges.insert(module, changes);
1212 }
1213
1214 pub fn add_versioning_violation(&mut self, module: String, violation: String) {
1215 self.versioning_violations.insert(module, violation);
1216 }
1217}
1218
1219impl Default for ApiStabilityResult {
1220 fn default() -> Self {
1221 Self::new()
1222 }
1223}
1224
1225#[derive(Debug, Clone)]
1226pub struct VersionConsistencyResult {
1227 pub conflicts: HashMap<String, Vec<Version>>,
1228 pub dependency_mismatches: Vec<DependencyMismatch>,
1229}
1230
1231impl VersionConsistencyResult {
1232 pub fn new() -> Self {
1233 Self {
1234 conflicts: HashMap::new(),
1235 dependency_mismatches: Vec::new(),
1236 }
1237 }
1238
1239 pub fn add_conflict(&mut self, module: String, versions: Vec<Version>) {
1240 self.conflicts.insert(module, versions);
1241 }
1242
1243 pub fn add_dependency_mismatch(
1244 &mut self,
1245 module: String,
1246 dependency: String,
1247 required: VersionRequirement,
1248 found: Version,
1249 ) {
1250 self.dependency_mismatches.push(DependencyMismatch {
1251 module,
1252 dependency,
1253 required,
1254 found,
1255 });
1256 }
1257}
1258
1259impl Default for VersionConsistencyResult {
1260 fn default() -> Self {
1261 Self::new()
1262 }
1263}
1264
1265#[derive(Debug, Clone)]
1266pub struct DependencyMismatch {
1267 pub module: String,
1268 pub dependency: String,
1269 pub required: VersionRequirement,
1270 pub found: Version,
1271}
1272
1273#[derive(Debug, Clone)]
1275pub struct DependencyValidationResult {
1276 pub dependency_name: String,
1277 pub incompatibilities: Vec<String>,
1278}
1279
1280impl DependencyValidationResult {
1281 pub fn new(modulename: String) -> Self {
1282 Self {
1283 dependency_name: modulename,
1284 incompatibilities: Vec::new(),
1285 }
1286 }
1287
1288 pub fn add_incompatibility(&mut self, incompatibility: String) {
1289 self.incompatibilities.push(incompatibility);
1290 }
1291
1292 pub fn is_valid(&self) -> bool {
1293 self.incompatibilities.is_empty()
1294 }
1295}
1296
1297#[derive(Debug, Clone)]
1298pub struct ApiValidationResult {
1299 pub documentation_issues: Vec<String>,
1300 pub semver_violations: Vec<String>,
1301 pub deprecation_issues: HashMap<String, String>,
1302}
1303
1304impl ApiValidationResult {
1305 pub fn new() -> Self {
1306 Self {
1307 documentation_issues: Vec::new(),
1308 semver_violations: Vec::new(),
1309 deprecation_issues: HashMap::new(),
1310 }
1311 }
1312
1313 pub fn name(&mut self, apiname: String) {
1314 self.documentation_issues.push(apiname);
1315 }
1316
1317 pub fn add_documentation_issue(&mut self, apiname: String) {
1318 self.documentation_issues.push(apiname);
1319 }
1320
1321 pub fn name_2(&mut self, apiname: String) {
1322 self.semver_violations.push(apiname);
1323 }
1324
1325 pub fn add_semver_violation(&mut self, apiname: String) {
1326 self.semver_violations.push(apiname);
1327 }
1328
1329 pub fn name_3(&mut self, apiname: String, issue: String) {
1330 self.deprecation_issues.insert(apiname, issue);
1331 }
1332
1333 pub fn add_deprecation_issue(&mut self, apiname: String, issue: String) {
1334 self.deprecation_issues.insert(apiname, issue);
1335 }
1336
1337 pub fn is_valid(&self) -> bool {
1338 self.documentation_issues.is_empty()
1339 && self.semver_violations.is_empty()
1340 && self.deprecation_issues.is_empty()
1341 }
1342}
1343
1344impl Default for ApiValidationResult {
1345 fn default() -> Self {
1346 Self::new()
1347 }
1348}
1349
1350#[derive(Debug, Clone)]
1351pub struct SecurityValidationResult {
1352 pub modulename: String,
1353 pub vulnerabilities: Vec<String>,
1354 pub security_issues: Vec<String>,
1355}
1356
1357impl SecurityValidationResult {
1358 pub fn new(modulename: String) -> Self {
1359 Self {
1360 modulename,
1361 vulnerabilities: Vec::new(),
1362 security_issues: Vec::new(),
1363 }
1364 }
1365
1366 pub fn add_vulnerability(&mut self, vulnerability: String) {
1367 self.vulnerabilities.push(vulnerability);
1368 }
1369
1370 pub fn add_security_issue(&mut self, issue: String) {
1371 self.security_issues.push(issue);
1372 }
1373
1374 pub fn is_secure(&self) -> bool {
1375 self.vulnerabilities.is_empty() && self.security_issues.is_empty()
1376 }
1377}
1378
1379#[derive(Debug, Clone)]
1380pub struct ApiStabilityCheck {
1381 pub is_stable: bool,
1382 pub breakingchanges: Vec<String>,
1383}
1384
1385impl ApiStabilityCheck {
1386 pub fn new(is_stable: bool, breakingchanges: Vec<String>) -> Self {
1387 Self {
1388 is_stable,
1389 breakingchanges,
1390 }
1391 }
1392
1393 pub fn is_stable(&self) -> bool {
1394 self.is_stable
1395 }
1396
1397 pub fn breakingchanges(&self) -> &[String] {
1398 &self.breakingchanges
1399 }
1400
1401 pub fn is_valid(&self) -> bool {
1402 self.is_stable && self.breakingchanges.is_empty()
1403 }
1404}
1405
1406#[derive(Debug, Clone)]
1408pub struct EcosystemHealth {
1409 pub overall_status: HealthStatus,
1410 pub module_count: usize,
1411 pub error_count: usize,
1412 pub warning_count: usize,
1413 pub compatibility_score: f64,
1414 pub recommendations: Vec<String>,
1415}
1416
1417#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1418pub enum HealthStatus {
1419 Excellent,
1420 Good,
1421 Fair,
1422 Poor,
1423 Critical,
1424}
1425
1426impl EcosystemHealth {
1427 pub fn from_validationresult(result: &EcosystemValidationResult) -> Self {
1428 let module_count = result.moduleresults.len();
1429 let error_count = result.error_count();
1430 let warning_count = result.warning_count();
1431
1432 let compatibility_score = if module_count == 0 {
1433 1.0
1434 } else {
1435 1.0 - (error_count as f64 / (module_count as f64 * 10.0))
1436 };
1437
1438 let overall_status = match error_count {
1439 0 => {
1440 if warning_count == 0 {
1441 HealthStatus::Excellent
1442 } else {
1443 HealthStatus::Good
1444 }
1445 }
1446 1..=5 => HealthStatus::Fair,
1447 6..=15 => HealthStatus::Poor,
1448 _ => HealthStatus::Critical,
1449 };
1450
1451 let recommendations = Self::generate_recommendations(result);
1452
1453 Self {
1454 overall_status,
1455 module_count,
1456 error_count,
1457 warning_count,
1458 compatibility_score: compatibility_score.clamp(0.0, 1.0),
1459 recommendations,
1460 }
1461 }
1462
1463 fn generate_recommendations(result: &EcosystemValidationResult) -> Vec<String> {
1464 let mut recommendations = Vec::new();
1465
1466 if result.error_count() > 0 {
1467 recommendations
1468 .push("Address validation errors before production deployment".to_string());
1469 }
1470
1471 if !result.api_stabilityresult.breakingchanges.is_empty() {
1472 recommendations
1473 .push("Review API breaking changes and update version numbers".to_string());
1474 }
1475
1476 if !result.version_consistencyresult.conflicts.is_empty() {
1477 recommendations.push("Resolve version conflicts between modules".to_string());
1478 }
1479
1480 if result.warning_count() > 10 {
1481 recommendations
1482 .push("Consider addressing warnings to improve ecosystem stability".to_string());
1483 }
1484
1485 recommendations
1486 }
1487}
1488
1489#[allow(dead_code)]
1491pub fn initialize_ecosystem_validation() -> CoreResult<()> {
1492 let validator = EcosystemValidator::global()?;
1493
1494 validator.register_module(create_core_module_info())?;
1496
1497 Ok(())
1500}
1501
1502#[allow(dead_code)]
1503fn create_core_module_info() -> ModuleInfo {
1504 ModuleInfo {
1505 name: "scirs2-core".to_string(),
1506 version: "1.0.0".to_string(),
1507 dependencies: Vec::new(),
1508 apisurface: ApiSurface {
1509 public_apis: vec![ApiInfo {
1510 name: "validate_ecosystem".to_string(),
1511 signature: "fn validate_ecosystem() -> CoreResult<EcosystemValidationResult>"
1512 .to_string(),
1513 documentation: "Validates the entire ecosystem compatibility".to_string(),
1514 since_version: Some(Version::new(1, 0, 0)),
1515 stability: ApiStability::Stable,
1516 }],
1517 deprecated_apis: Vec::new(),
1518 },
1519 features: vec!["validation".to_string(), "ecosystem".to_string()],
1520 metadata: ModuleMetadata {
1521 author: "SciRS2 Team".to_string(),
1522 description: "Core utilities for SciRS2 ecosystem".to_string(),
1523 license: "MIT".to_string(),
1524 repository: Some("https://github.com/cool-japan/scirs".to_string()),
1525 build_time: None,
1526 },
1527 }
1528}
1529
1530#[cfg(test)]
1531mod tests {
1532 use super::*;
1533
1534 #[test]
1535 fn test_validator_creation() {
1536 let validator = EcosystemValidator::new().expect("Operation failed");
1537 }
1539
1540 #[test]
1541 fn test_module_registration() {
1542 let validator = EcosystemValidator::new().expect("Operation failed");
1543 let module = create_core_module_info();
1544
1545 validator.register_module(module).expect("Operation failed");
1546
1547 let result = validator
1548 .validate_module("scirs2-core")
1549 .expect("Operation failed");
1550 assert!(result.is_valid());
1551 }
1552
1553 #[test]
1554 fn test_ecosystem_validation() {
1555 let validator = EcosystemValidator::new().expect("Operation failed");
1556 validator
1557 .register_module(create_core_module_info())
1558 .expect("Operation failed");
1559
1560 let result = validator.validate_ecosystem().expect("Operation failed");
1561 assert!(result.is_valid());
1562 }
1563
1564 #[test]
1565 fn test_version_requirement() {
1566 let req = VersionRequirement::new("1.0.0");
1567 let version = Version::new(1, 0, 0);
1568
1569 assert!(req.version(&version));
1570 }
1571
1572 #[test]
1573 fn test_ecosystem_health() {
1574 let mut result = EcosystemValidationResult::new();
1575 result.add_moduleresult(
1576 "test".to_string(),
1577 ModuleValidationResult::new("test".to_string()),
1578 );
1579
1580 let health = EcosystemHealth::from_validationresult(&result);
1581 assert_eq!(health.overall_status, HealthStatus::Excellent);
1582 }
1583}