1use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct CostModel {
11 pub component_added: u32,
13 pub component_removed: u32,
15 pub version_patch: u32,
17 pub version_minor: u32,
19 pub version_major: u32,
21 pub license_changed: u32,
23 pub supplier_changed: u32,
25 pub vulnerability_introduced: u32,
27 pub vulnerability_resolved: i32,
29 pub dependency_added: u32,
31 pub dependency_removed: u32,
33 pub hash_mismatch: u32,
35}
36
37impl Default for CostModel {
38 fn default() -> Self {
39 Self {
40 component_added: 10,
41 component_removed: 10,
42 version_patch: 2,
43 version_minor: 4,
44 version_major: 7,
45 license_changed: 6,
46 supplier_changed: 4,
47 vulnerability_introduced: 15,
48 vulnerability_resolved: -3,
49 dependency_added: 5,
50 dependency_removed: 5,
51 hash_mismatch: 8,
52 }
53 }
54}
55
56impl CostModel {
57 pub fn security_focused() -> Self {
59 Self {
60 vulnerability_introduced: 25,
61 vulnerability_resolved: -5,
62 hash_mismatch: 15,
63 supplier_changed: 8,
64 ..Default::default()
65 }
66 }
67
68 pub fn compliance_focused() -> Self {
70 Self {
71 license_changed: 12,
72 supplier_changed: 8,
73 ..Default::default()
74 }
75 }
76
77 pub fn version_change_cost(
79 &self,
80 old: &Option<semver::Version>,
81 new: &Option<semver::Version>,
82 ) -> u32 {
83 match (old, new) {
84 (Some(old_ver), Some(new_ver)) => {
85 if old_ver.major != new_ver.major {
86 self.version_major
87 } else if old_ver.minor != new_ver.minor {
88 self.version_minor
89 } else if old_ver.patch != new_ver.patch {
90 self.version_patch
91 } else {
92 0
93 }
94 }
95 (None, Some(_)) | (Some(_), None) => self.version_minor,
96 (None, None) => 0,
97 }
98 }
99
100 #[allow(clippy::too_many_arguments)]
102 pub fn calculate_semantic_score(
103 &self,
104 components_added: usize,
105 components_removed: usize,
106 version_changes: usize,
107 license_changes: usize,
108 vulns_introduced: usize,
109 vulns_resolved: usize,
110 deps_added: usize,
111 deps_removed: usize,
112 ) -> f64 {
113 let score = (components_added as u32 * self.component_added)
114 + (components_removed as u32 * self.component_removed)
115 + (version_changes as u32 * self.version_minor)
116 + (license_changes as u32 * self.license_changed)
117 + (vulns_introduced as u32 * self.vulnerability_introduced)
118 + (deps_added as u32 * self.dependency_added)
119 + (deps_removed as u32 * self.dependency_removed);
120
121 let reward = vulns_resolved as i32 * self.vulnerability_resolved;
122
123 (score as i32 + reward) as f64
124 }
125}