cfn-guard 3.2.0

AWS CloudFormation Guard is an open-source general-purpose policy-as-code evaluation tool. It provides developers with a simple-to-use, yet powerful and expressive domain-specific language (DSL) to define policies and enables developers to validate JSON- or YAML- formatted structured data with those policies.
Documentation
use crate::rules::exprs::AccessQuery;
use crate::rules::path_value::{PathAwareValue, QueryResolver};
use crate::rules::values::CmpOperator;
use crate::rules::{EvaluationContext, EvaluationType, Result, Status};
use std::convert::TryFrom;

pub(super) struct MetadataAppender<'d> {
    pub(super) delegate: &'d dyn EvaluationContext,
    pub(super) root_context: &'d PathAwareValue,
}

impl<'d> EvaluationContext for MetadataAppender<'d> {
    fn resolve_variable(&self, variable: &str) -> Result<Vec<&PathAwareValue>> {
        self.delegate.resolve_variable(variable)
    }

    fn rule_status(&self, rule_name: &str) -> Result<Status> {
        self.delegate.rule_status(rule_name)
    }

    #[allow(clippy::never_loop)]
    fn end_evaluation(
        &self,
        eval_type: EvaluationType,
        context: &str,
        msg: String,
        from: Option<PathAwareValue>,
        to: Option<PathAwareValue>,
        status: Option<Status>,
        cmp: Option<(CmpOperator, bool)>,
    ) {
        let msg = if eval_type == EvaluationType::Clause {
            match status {
                Some(status) => loop {
                    if status == Status::FAIL {
                        if let Some(value) = &from {
                            let path = value.self_path();
                            if path.0.starts_with("/Resources") {
                                let parts = path.0.splitn(4, '/').collect::<Vec<&str>>();
                                if parts.len() == 4 {
                                    let query = format!(
                                        "Resources['{}'].Metadata[ keys == /^aws/ ]",
                                        parts[2]
                                    );
                                    let AccessQuery {
                                        query,
                                        match_all: all,
                                    } = AccessQuery::try_from(query.as_str()).unwrap();
                                    if let Ok(selected) =
                                        self.root_context.select(all, &query, self)
                                    {
                                        break format!("{}\nMetadata: {:?}", msg, selected);
                                    }
                                }
                            }
                        }
                    }
                    break msg;
                },
                None => msg,
            }
        } else {
            msg
        };
        self.delegate
            .end_evaluation(eval_type, context, msg, from, to, status, cmp)
    }

    fn start_evaluation(&self, eval_type: EvaluationType, context: &str) {
        self.delegate.start_evaluation(eval_type, context)
    }
}

#[cfg(test)]
#[path = "aws_meta_appender_tests.rs"]
mod aws_meta_appender_tests;