in guard/src/commands/validate/cfn_reporter.rs [48:106]
fn report(&self,
writer: &mut dyn Write,
_status: Option<Status>,
failed_rules: &[&StatusContext],
passed_or_skipped: &[&StatusContext],
longest_rule_name: usize) -> crate::rules::Result<()> {
let failed = if !failed_rules.is_empty() {
let mut by_resource_name = HashMap::new();
for (idx, each_failed_rule) in failed_rules.iter().enumerate() {
let failed = find_all_failing_clauses(each_failed_rule);
for (clause_idx, each_failing_clause) in failed.iter().enumerate() {
match each_failing_clause.eval_type {
EvaluationType::Clause |
EvaluationType::BlockClause => {
if each_failing_clause.eval_type == EvaluationType::BlockClause {
match &each_failing_clause.msg {
Some(msg) => {
if msg.contains("DEFAULT") {
continue;
}
},
None => {
continue;
}
}
}
let mut resource_info = super::common::extract_name_info(
&each_failed_rule.context, each_failing_clause)?;
let (resource_name, property_path) = match CFN_RESOURCES.captures(&resource_info.path) {
Some(caps) => {
(caps["name"].to_string(), caps["rest"].replace("/", "."))
},
None =>
(format!("Rule {} Resource {} {}", each_failed_rule.context, idx, clause_idx), "".to_string())
};
resource_info.path = property_path;
by_resource_name.entry(resource_name).or_insert(Vec::new()).push(resource_info);
},
_ => unreachable!()
}
}
}
by_resource_name
} else { HashMap::new() };
let as_vec = passed_or_skipped.iter().map(|s| *s)
.collect::<Vec<&StatusContext>>();
let (skipped, passed): (Vec<&StatusContext>, Vec<&StatusContext>) = as_vec.iter()
.partition(|status| match status.status { // This uses the dereference deep trait of Rust
Some(Status::SKIP) => true,
_ => false
});
let skipped = skipped.iter().map(|s| s.context.clone()).collect::<HashSet<String>>();
let passed = passed.iter().map(|s| s.context.clone()).collect::<HashSet<String>>();
self.render.report(writer, self.rules_file_name, self.data_file_name, failed, passed, skipped, longest_rule_name)?;
Ok(())
}