Falco engine changes to support multiple files in rule load results

The methods that throw exceptions from stringified results need to
additionally pass a rules_contents_t struct. This also meant that they
need to call the filename + content version of load_rules.

To avoid some duplicate code between the two load_rules_file methods,
move the work of opening the file into a private method
read_file(). It can throw an exception, which is passed through for
the void return method and caught + converted into a load_result error
for the method that returns a load_result.

Also, to avoid duplicate code between the void load_rules and
load_rules_file methods, add a private method interpret_load_result()
which throws an exception if the result has an error and prints
warnings otherwise if verbose is true.

Signed-off-by: Mark Stemm <mark.stemm@gmail.com>
This commit is contained in:
Mark Stemm 2022-08-08 16:38:06 -07:00 committed by poiana
parent 49b7f0474f
commit 3c7b6e037a
2 changed files with 62 additions and 36 deletions

View File

@ -18,6 +18,7 @@ limitations under the License.
#include <unistd.h> #include <unistd.h>
#include <string> #include <string>
#include <fstream> #include <fstream>
#include <functional>
#include <utility> #include <utility>
#include <sinsp.h> #include <sinsp.h>
@ -171,20 +172,7 @@ void falco_engine::load_rules(const string &rules_content, bool verbose, bool al
std::unique_ptr<load_result> res = load_rules(rules_content, no_name); std::unique_ptr<load_result> res = load_rules(rules_content, no_name);
if(verbose) interpret_load_result(res, no_name, rules_content, verbose);
{
// Here, verbose controls whether to additionally
// "log" e.g. print to stderr. What's logged is always
// non-verbose so it fits on a single line.
// todo(jasondellaluce): introduce a logging callback in Falco
fprintf(stderr, "%s\n", res->as_string(false).c_str());
}
if(!res->successful())
{
// The output here is always the full e.g. "verbose" output.
throw falco_exception(res->as_string(true).c_str());
}
} }
std::unique_ptr<load_result> falco_engine::load_rules(const std::string &rules_content, const std::string &name) std::unique_ptr<load_result> falco_engine::load_rules(const std::string &rules_content, const std::string &name)
@ -211,44 +199,33 @@ std::unique_ptr<load_result> falco_engine::load_rules(const std::string &rules_c
void falco_engine::load_rules_file(const std::string &rules_filename, bool verbose, bool all_events) void falco_engine::load_rules_file(const std::string &rules_filename, bool verbose, bool all_events)
{ {
std::unique_ptr<load_result> res = load_rules_file(rules_filename); std::string rules_content;
if(verbose) read_file(rules_filename, rules_content);
{
// Here, verbose controls whether to additionally
// "log" e.g. print to stderr. What's logged is always
// non-verbose so it fits on a single line.
// todo(jasondellaluce): introduce a logging callback in Falco
fprintf(stderr, "%s\n", res->as_string(false).c_str());
}
if(!res->successful()) std::unique_ptr<load_result> res = load_rules(rules_content, rules_filename);
{
// The output here is always the full e.g. "verbose" output. interpret_load_result(res, rules_filename, rules_content, verbose);
throw falco_exception(res->as_string(true).c_str());
}
} }
std::unique_ptr<load_result> falco_engine::load_rules_file(const string &rules_filename) std::unique_ptr<load_result> falco_engine::load_rules_file(const string &rules_filename)
{ {
ifstream is; std::string rules_content;
is.open(rules_filename); try {
if (!is.is_open()) read_file(rules_filename, rules_content);
}
catch (falco_exception &e)
{ {
rule_loader::context ctx(rules_filename); rule_loader::context ctx(rules_filename);
std::string empty;
std::unique_ptr<rule_loader::result> res(new rule_loader::result(rules_filename)); std::unique_ptr<rule_loader::result> res(new rule_loader::result(rules_filename));
res->add_error(load_result::LOAD_ERR_FILE_READ, "Could not open for reading.", ctx, empty); res->add_error(load_result::LOAD_ERR_FILE_READ, e.what(), ctx);
return std::move(res); return std::move(res);
} }
string rules_content((istreambuf_iterator<char>(is)),
istreambuf_iterator<char>());
return load_rules(rules_content, rules_filename); return load_rules(rules_content, rules_filename);
} }
@ -426,6 +403,44 @@ bool falco_engine::is_source_valid(const std::string &source)
return m_sources.at(source) != nullptr; return m_sources.at(source) != nullptr;
} }
void falco_engine::read_file(const std::string& filename, std::string& contents)
{
ifstream is;
is.open(filename);
if (!is.is_open())
{
throw falco_exception("Could not open " + filename + " for reading.");
}
contents.assign(istreambuf_iterator<char>(is),
istreambuf_iterator<char>());
}
void falco_engine::interpret_load_result(std::unique_ptr<load_result>& res,
const std::string& rules_filename,
const std::string& rules_content,
bool verbose)
{
falco::load_result::rules_contents_t rc = {{rules_filename, rules_content}};
if(!res->successful())
{
// The output here is always the full e.g. "verbose" output.
throw falco_exception(res->as_string(true, rc).c_str());
}
if(verbose && res->has_warnings())
{
// Here, verbose controls whether to additionally
// "log" e.g. print to stderr. What's logged is always
// non-verbose so it fits on a single line.
// todo(jasondellaluce): introduce a logging callback in Falco
fprintf(stderr, "%s\n", res->as_string(false, rc).c_str());
}
}
bool falco_engine::check_plugin_requirements( bool falco_engine::check_plugin_requirements(
const std::vector<plugin_version_requirement>& plugins, const std::vector<plugin_version_requirement>& plugins,
std::string& err) std::string& err)

View File

@ -233,6 +233,17 @@ public:
std::string& err); std::string& err);
private: private:
// Throws falco_exception if the file can not be read
void read_file(const std::string& filename, std::string& contents);
// For load_rules methods that throw exceptions on error,
// interpret a load_result and throw an exception if needed.
void interpret_load_result(std::unique_ptr<falco::load_result>& res,
const std::string& rules_filename,
const std::string& rules_content,
bool verbose);
indexed_vector<falco_source> m_sources; indexed_vector<falco_source> m_sources;
falco_source* find_source(std::size_t index); falco_source* find_source(std::size_t index);