1use serde::{Deserialize, Serialize};
7use std::collections::HashMap;
8
9use super::graph_properties::{GraphPropertyValue, ToNodeProperties};
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
13#[serde(rename_all = "snake_case")]
14pub enum CosoComponent {
15 ControlEnvironment,
18 RiskAssessment,
21 ControlActivities,
24 InformationCommunication,
28 MonitoringActivities,
32}
33
34impl std::fmt::Display for CosoComponent {
35 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
36 match self {
37 Self::ControlEnvironment => write!(f, "Control Environment"),
38 Self::RiskAssessment => write!(f, "Risk Assessment"),
39 Self::ControlActivities => write!(f, "Control Activities"),
40 Self::InformationCommunication => write!(f, "Information & Communication"),
41 Self::MonitoringActivities => write!(f, "Monitoring Activities"),
42 }
43 }
44}
45
46#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
55#[serde(rename_all = "snake_case")]
56pub enum CosoPrinciple {
57 IntegrityAndEthics,
61 BoardOversight,
64 OrganizationalStructure,
67 CommitmentToCompetence,
70 Accountability,
73
74 ClearObjectives,
78 IdentifyRisks,
82 FraudRisk,
85 ChangeIdentification,
88
89 ControlActions,
93 TechnologyControls,
96 PoliciesAndProcedures,
100
101 QualityInformation,
105 InternalCommunication,
108 ExternalCommunication,
111
112 OngoingMonitoring,
117 DeficiencyEvaluation,
121}
122
123impl CosoPrinciple {
124 pub fn component(&self) -> CosoComponent {
126 match self {
127 Self::IntegrityAndEthics
129 | Self::BoardOversight
130 | Self::OrganizationalStructure
131 | Self::CommitmentToCompetence
132 | Self::Accountability => CosoComponent::ControlEnvironment,
133
134 Self::ClearObjectives
136 | Self::IdentifyRisks
137 | Self::FraudRisk
138 | Self::ChangeIdentification => CosoComponent::RiskAssessment,
139
140 Self::ControlActions | Self::TechnologyControls | Self::PoliciesAndProcedures => {
142 CosoComponent::ControlActivities
143 }
144
145 Self::QualityInformation
147 | Self::InternalCommunication
148 | Self::ExternalCommunication => CosoComponent::InformationCommunication,
149
150 Self::OngoingMonitoring | Self::DeficiencyEvaluation => {
152 CosoComponent::MonitoringActivities
153 }
154 }
155 }
156
157 pub fn principle_number(&self) -> u8 {
159 match self {
160 Self::IntegrityAndEthics => 1,
161 Self::BoardOversight => 2,
162 Self::OrganizationalStructure => 3,
163 Self::CommitmentToCompetence => 4,
164 Self::Accountability => 5,
165 Self::ClearObjectives => 6,
166 Self::IdentifyRisks => 7,
167 Self::FraudRisk => 8,
168 Self::ChangeIdentification => 9,
169 Self::ControlActions => 10,
170 Self::TechnologyControls => 11,
171 Self::PoliciesAndProcedures => 12,
172 Self::QualityInformation => 13,
173 Self::InternalCommunication => 14,
174 Self::ExternalCommunication => 15,
175 Self::OngoingMonitoring => 16,
176 Self::DeficiencyEvaluation => 17,
177 }
178 }
179}
180
181impl std::fmt::Display for CosoPrinciple {
182 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
183 match self {
184 Self::IntegrityAndEthics => write!(f, "Integrity and Ethics"),
185 Self::BoardOversight => write!(f, "Board Oversight"),
186 Self::OrganizationalStructure => write!(f, "Organizational Structure"),
187 Self::CommitmentToCompetence => write!(f, "Commitment to Competence"),
188 Self::Accountability => write!(f, "Accountability"),
189 Self::ClearObjectives => write!(f, "Clear Objectives"),
190 Self::IdentifyRisks => write!(f, "Identify Risks"),
191 Self::FraudRisk => write!(f, "Fraud Risk"),
192 Self::ChangeIdentification => write!(f, "Change Identification"),
193 Self::ControlActions => write!(f, "Control Actions"),
194 Self::TechnologyControls => write!(f, "Technology Controls"),
195 Self::PoliciesAndProcedures => write!(f, "Policies and Procedures"),
196 Self::QualityInformation => write!(f, "Quality Information"),
197 Self::InternalCommunication => write!(f, "Internal Communication"),
198 Self::ExternalCommunication => write!(f, "External Communication"),
199 Self::OngoingMonitoring => write!(f, "Ongoing Monitoring"),
200 Self::DeficiencyEvaluation => write!(f, "Deficiency Evaluation"),
201 }
202 }
203}
204
205impl ToNodeProperties for CosoComponent {
206 fn node_type_name(&self) -> &'static str {
207 "coso_component"
208 }
209 fn node_type_code(&self) -> u16 {
210 500
211 }
212 fn to_node_properties(&self) -> HashMap<String, GraphPropertyValue> {
213 let mut p = HashMap::new();
214 p.insert("name".into(), GraphPropertyValue::String(self.to_string()));
215 p.insert(
216 "code".into(),
217 GraphPropertyValue::String(format!("{:?}", self)),
218 );
219 let principle_count = match self {
221 CosoComponent::ControlEnvironment => 5,
222 CosoComponent::RiskAssessment => 4,
223 CosoComponent::ControlActivities => 3,
224 CosoComponent::InformationCommunication => 3,
225 CosoComponent::MonitoringActivities => 2,
226 };
227 p.insert(
228 "principleCount".into(),
229 GraphPropertyValue::Int(principle_count),
230 );
231 p
232 }
233}
234
235impl ToNodeProperties for CosoPrinciple {
236 fn node_type_name(&self) -> &'static str {
237 "coso_principle"
238 }
239 fn node_type_code(&self) -> u16 {
240 501
241 }
242 fn to_node_properties(&self) -> HashMap<String, GraphPropertyValue> {
243 let mut p = HashMap::new();
244 p.insert("name".into(), GraphPropertyValue::String(self.to_string()));
245 p.insert(
246 "code".into(),
247 GraphPropertyValue::String(format!("{:?}", self)),
248 );
249 p.insert(
250 "number".into(),
251 GraphPropertyValue::Int(self.principle_number() as i64),
252 );
253 p.insert(
254 "componentId".into(),
255 GraphPropertyValue::String(format!("{:?}", self.component())),
256 );
257 p.insert(
258 "componentName".into(),
259 GraphPropertyValue::String(self.component().to_string()),
260 );
261 p
262 }
263}
264
265#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
267#[serde(rename_all = "snake_case")]
268pub enum ControlScope {
269 EntityLevel,
272 TransactionLevel,
275 ItGeneralControl,
278 ItApplicationControl,
281}
282
283impl std::fmt::Display for ControlScope {
284 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
285 match self {
286 Self::EntityLevel => write!(f, "Entity Level"),
287 Self::TransactionLevel => write!(f, "Transaction Level"),
288 Self::ItGeneralControl => write!(f, "IT General Control"),
289 Self::ItApplicationControl => write!(f, "IT Application Control"),
290 }
291 }
292}
293
294#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
296#[serde(rename_all = "snake_case")]
297pub enum CosoMaturityLevel {
298 NonExistent,
300 AdHoc,
303 Repeatable,
306 Defined,
309 Managed,
312 Optimized,
315}
316
317impl std::fmt::Display for CosoMaturityLevel {
318 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
319 match self {
320 Self::NonExistent => write!(f, "Non-Existent"),
321 Self::AdHoc => write!(f, "Ad Hoc"),
322 Self::Repeatable => write!(f, "Repeatable"),
323 Self::Defined => write!(f, "Defined"),
324 Self::Managed => write!(f, "Managed"),
325 Self::Optimized => write!(f, "Optimized"),
326 }
327 }
328}
329
330impl CosoMaturityLevel {
331 pub fn level(&self) -> u8 {
333 match self {
334 Self::NonExistent => 0,
335 Self::AdHoc => 1,
336 Self::Repeatable => 2,
337 Self::Defined => 3,
338 Self::Managed => 4,
339 Self::Optimized => 5,
340 }
341 }
342}
343
344#[cfg(test)]
345#[allow(clippy::unwrap_used)]
346mod tests {
347 use super::*;
348
349 #[test]
350 fn test_principle_component_mapping() {
351 assert_eq!(
353 CosoPrinciple::IntegrityAndEthics.component(),
354 CosoComponent::ControlEnvironment
355 );
356 assert_eq!(
357 CosoPrinciple::Accountability.component(),
358 CosoComponent::ControlEnvironment
359 );
360
361 assert_eq!(
363 CosoPrinciple::FraudRisk.component(),
364 CosoComponent::RiskAssessment
365 );
366
367 assert_eq!(
369 CosoPrinciple::ControlActions.component(),
370 CosoComponent::ControlActivities
371 );
372 assert_eq!(
373 CosoPrinciple::TechnologyControls.component(),
374 CosoComponent::ControlActivities
375 );
376
377 assert_eq!(
379 CosoPrinciple::QualityInformation.component(),
380 CosoComponent::InformationCommunication
381 );
382
383 assert_eq!(
385 CosoPrinciple::OngoingMonitoring.component(),
386 CosoComponent::MonitoringActivities
387 );
388 assert_eq!(
389 CosoPrinciple::DeficiencyEvaluation.component(),
390 CosoComponent::MonitoringActivities
391 );
392 }
393
394 #[test]
395 fn test_principle_numbers() {
396 assert_eq!(CosoPrinciple::IntegrityAndEthics.principle_number(), 1);
397 assert_eq!(CosoPrinciple::Accountability.principle_number(), 5);
398 assert_eq!(CosoPrinciple::ClearObjectives.principle_number(), 6);
399 assert_eq!(CosoPrinciple::ControlActions.principle_number(), 10);
400 assert_eq!(CosoPrinciple::QualityInformation.principle_number(), 13);
401 assert_eq!(CosoPrinciple::DeficiencyEvaluation.principle_number(), 17);
402 }
403
404 #[test]
405 fn test_maturity_level_ordering() {
406 assert!(CosoMaturityLevel::NonExistent < CosoMaturityLevel::AdHoc);
407 assert!(CosoMaturityLevel::AdHoc < CosoMaturityLevel::Repeatable);
408 assert!(CosoMaturityLevel::Repeatable < CosoMaturityLevel::Defined);
409 assert!(CosoMaturityLevel::Defined < CosoMaturityLevel::Managed);
410 assert!(CosoMaturityLevel::Managed < CosoMaturityLevel::Optimized);
411 }
412
413 #[test]
414 fn test_maturity_level_numeric() {
415 assert_eq!(CosoMaturityLevel::NonExistent.level(), 0);
416 assert_eq!(CosoMaturityLevel::Optimized.level(), 5);
417 }
418
419 #[test]
420 fn test_display_implementations() {
421 assert_eq!(
422 CosoComponent::ControlEnvironment.to_string(),
423 "Control Environment"
424 );
425 assert_eq!(
426 CosoPrinciple::IntegrityAndEthics.to_string(),
427 "Integrity and Ethics"
428 );
429 assert_eq!(ControlScope::EntityLevel.to_string(), "Entity Level");
430 assert_eq!(CosoMaturityLevel::Defined.to_string(), "Defined");
431 }
432
433 #[test]
434 fn test_serde_roundtrip() {
435 let component = CosoComponent::ControlActivities;
436 let json = serde_json::to_string(&component).unwrap();
437 let deserialized: CosoComponent = serde_json::from_str(&json).unwrap();
438 assert_eq!(component, deserialized);
439
440 let principle = CosoPrinciple::FraudRisk;
441 let json = serde_json::to_string(&principle).unwrap();
442 let deserialized: CosoPrinciple = serde_json::from_str(&json).unwrap();
443 assert_eq!(principle, deserialized);
444 }
445}