From 550cdbd1762d17f01e1033919cb0d2f9712f28be Mon Sep 17 00:00:00 2001 From: Mark Stemm Date: Thu, 23 Jun 2022 17:55:50 -0700 Subject: [PATCH] Falco application changes to support rule loading result struct Update the load_rules_files and validate_rules_files actions to use the new falco_engine methods that return a rules result struct. The app action interface is the same, returning ::fatal on error, ok()/exit() otherwise. The difference is how any warnings/errors are obtained--from the struct instead of an exception. Signed-off-by: Mark Stemm --- falco.yaml | 4 +- .../falco/app_actions/load_rules_files.cpp | 21 +++++-- .../app_actions/validate_rules_files.cpp | 60 +++++++++++++++---- 3 files changed, 68 insertions(+), 17 deletions(-) diff --git a/falco.yaml b/falco.yaml index 82ae4c06..755e7f21 100644 --- a/falco.yaml +++ b/falco.yaml @@ -73,7 +73,9 @@ watch_config_files: true # time zone, as governed by /etc/localtime. time_format_iso_8601: false -# Whether to output events in json or text +# If "true", print falco alert messages and rules file +# loading/validation results as json, which allows for easier +# consumption by downstream programs. Default is "false". json_output: false # When using json output, whether or not to include the "output" property diff --git a/userspace/falco/app_actions/load_rules_files.cpp b/userspace/falco/app_actions/load_rules_files.cpp index 8722d8d6..cbec79c1 100644 --- a/userspace/falco/app_actions/load_rules_files.cpp +++ b/userspace/falco/app_actions/load_rules_files.cpp @@ -96,13 +96,24 @@ application::run_result application::load_rules_files() for (const auto& filename : m_state->config->m_loaded_rules_filenames) { falco_logger::log(LOG_INFO, "Loading rules from file " + filename + "\n"); + std::unique_ptr res; - try { - m_state->engine->load_rules_file(filename, m_options.verbose, m_options.all_events); - } - catch(falco_exception &e) + res = m_state->engine->load_rules_file(filename); + + // Print the full output if verbose is true + if(m_options.verbose && + (!res->successful() || res->has_warnings())) { - return run_result::fatal(string("Could not load rules file ") + filename + ": " + e.what()); + printf("%s\n", + (m_state->config->m_json_output ? + res->as_json().dump().c_str() : + res->as_string(true).c_str())); + } + + if(!res->successful()) + { + // Return the summary version as the error + return run_result::fatal(res->as_string(false)); } } diff --git a/userspace/falco/app_actions/validate_rules_files.cpp b/userspace/falco/app_actions/validate_rules_files.cpp index 08b624ee..c812662b 100644 --- a/userspace/falco/app_actions/validate_rules_files.cpp +++ b/userspace/falco/app_actions/validate_rules_files.cpp @@ -15,6 +15,7 @@ limitations under the License. */ #include "application.h" +#include using namespace falco::app; @@ -22,27 +23,64 @@ application::run_result application::validate_rules_files() { if(m_options.validate_rules_filenames.size() > 0) { + bool successful = true; + std::string summary; + falco_logger::log(LOG_INFO, "Validating rules file(s):\n"); for(auto file : m_options.validate_rules_filenames) { falco_logger::log(LOG_INFO, " " + file + "\n"); } + + // The json output encompasses all files so the + // validation result is a single json object. + nlohmann::json results = nlohmann::json::array(); + for(auto file : m_options.validate_rules_filenames) { - // Only include the prefix if there is more than one file - std::string prefix = (m_options.validate_rules_filenames.size() > 1 ? file + ": " : ""); - try { - m_state->engine->load_rules_file(file, m_options.verbose, m_options.all_events); - } - catch(falco_exception &e) + std::unique_ptr res; + + res = m_state->engine->load_rules_file(file); + + successful &= res->successful(); + + if(summary != "") { - printf("%s%s", prefix.c_str(), e.what()); - return run_result::fatal(prefix + e.what()); + summary += "\n"; + } + summary += file + ": " + (res->successful() ? "Ok" : "Invalid"); + + if(m_state->config->m_json_output) + { + results.push_back(res->as_json()); + } + else + { + // Print the full output when verbose is true + if(m_options.verbose && + (!res->successful() || res->has_warnings())) + { + printf("%s\n", res->as_string(true).c_str()); + } } - printf("%sOk\n", prefix.c_str()); } - falco_logger::log(LOG_INFO, "Ok\n"); - return run_result::exit(); + + if(m_state->config->m_json_output) + { + nlohmann::json res; + res["falco_load_results"] = results; + printf("%s\n", res.dump().c_str()); + } + + if(successful) + { + printf("%s\n", summary.c_str()); + return run_result::exit(); + } + else + { + return run_result::fatal(summary); + } } return run_result::ok();