Rule loader changes to support result objects

Changes to the rule loader to support result objects:

- Instead of throwing falco_exception on internal error, throw a
  rule_load_exception instead, which contains distinct
  error/message/context information.

- A context object contains a chain of location structs chaining from
  the document root to the object where the error occurred. Each
  location has a file position (as a YAML::Mark), an item
  type (e.g. "rule", "list", "exception"), and an item name (e.g. "Write
  Below Etc"). This will allow showing the exact location of an
  error (e.g. list item/exception field) while also remembering the item
  that contained it.

- All the _info structs now contain a context so errors that occur
  after yaml parsing can still point to the original location in the
  yaml file.

- rule_loader::result is an implementation of the abstract class
  defined in falco_load_result. The implementation keeps track of a
  list of errors/warnigns that used to be in the configuration object,

- Clean up compile_ methods to just throw rule_load_exceptions or
  return nothing, and ensure that all rule_load_exceptions are caught in
  compile(). When caught, errors are added to the result object.

Signed-off-by: Mark Stemm <mark.stemm@gmail.com>
This commit is contained in:
Mark Stemm
2022-06-15 17:06:37 -07:00
committed by poiana
parent cbe7cceb87
commit f7f6d72ac0
2 changed files with 784 additions and 236 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -20,8 +20,10 @@ limitations under the License.
#include <string> #include <string>
#include <vector> #include <vector>
#include <yaml-cpp/yaml.h> #include <yaml-cpp/yaml.h>
#include <nlohmann/json.hpp>
#include "falco_rule.h" #include "falco_rule.h"
#include "falco_source.h" #include "falco_source.h"
#include "falco_load_result.h"
#include "indexed_vector.h" #include "indexed_vector.h"
@@ -31,34 +33,111 @@ limitations under the License.
class rule_loader class rule_loader
{ {
public: public:
/*! class context
\brief Represents a section of text from which a certain info
struct has been decoded
*/
struct context
{ {
std::string content; public:
struct location
/*!
\brief Wraps an error by adding info about the text section
*/
inline std::string error(std::string err) const
{ {
std::string cnt = content; // The original location in the document
err += "\n---\n"; YAML::Mark mark;
err += trim(cnt);
err += "\n---";
return err;
}
/*! // The kind of item at this location
\brief Appends another text section info to this one // (e.g. "list", "macro", "rule", "exception", etc)
*/ std::string item_type;
inline void append(context& m)
{ // The name of this item (e.g. "Write Below Etc",
content += "\n\n"; // etc).
content += m.content; std::string item_name;
} };
context(const std::string& name);
context(const YAML::Node& mark,
const std::string item_type,
const std::string item_name,
const context& parent);
virtual ~context() = default;
// Return a snippet of the provided rules content
// corresponding to this context.
std::string snippet(const std::string& content) const;
std::string as_string();
nlohmann::json as_json();
private:
std::string name;
// A chain of locations from the current item, its
// parent, possibly older ancestors.
std::vector<location> m_locs;
};
struct warning
{
falco::load_result::warning_code wc;
std::string msg;
context ctx;
std::string snippet;
};
struct error
{
falco::load_result::error_code ec;
std::string msg;
context ctx;
std::string snippet;
};
class rule_load_exception : public std::exception
{
public:
rule_load_exception(falco::load_result::error_code ec, std::string msg, const context& ctx);
virtual ~rule_load_exception();
const char* what();
falco::load_result::error_code ec;
std::string msg;
context ctx;
std::string errstr;
};
/*!
\brief Contains the result of loading rule definitions
*/
class result : public falco::load_result
{
public:
result(const std::string &name);
virtual ~result() = default;
virtual bool successful() override;
virtual bool has_warnings() override;
virtual const std::string& as_string(bool verbose) override;
virtual const nlohmann::json& as_json() override;
void add_error(falco::load_result::error_code ec,
const std::string& msg,
const context& ctx,
const std::string& rules_content);
void add_warning(falco::load_result::warning_code ec,
const std::string& msg,
const context& ctx,
const std::string& rules_content);
protected:
const std::string& as_summary_string();
const std::string& as_verbose_string();
std::string name;
bool success;
std::vector<error> errors;
std::vector<warning> warnings;
std::string res_summary_string;
std::string res_verbose_string;
nlohmann::json res_json;
}; };
/*! /*!
@@ -68,13 +147,17 @@ public:
{ {
explicit configuration( explicit configuration(
const std::string& cont, const std::string& cont,
const indexed_vector<falco_source>& srcs) const indexed_vector<falco_source>& srcs,
: content(cont), sources(srcs) {} std::string name)
: content(cont), sources(srcs), name(name)
{
res.reset(new result(name));
}
const std::string& content; const std::string& content;
const indexed_vector<falco_source>& sources; const indexed_vector<falco_source>& sources;
std::vector<std::string> errors; std::string name;
std::vector<std::string> warnings; std::unique_ptr<result> res;
std::string output_extra; std::string output_extra;
uint16_t default_ruleset_id; uint16_t default_ruleset_id;
bool replace_output_container_info; bool replace_output_container_info;
@@ -86,6 +169,10 @@ public:
*/ */
struct engine_version_info struct engine_version_info
{ {
engine_version_info(context &ctx);
~engine_version_info() = default;
context ctx;
uint32_t version; uint32_t version;
}; };
@@ -94,15 +181,26 @@ public:
*/ */
struct plugin_version_info struct plugin_version_info
{ {
// This differs from the other _info structs by having
// a default constructor. This allows it to be used
// by falco_engine, which aliases the type.
plugin_version_info();
plugin_version_info(context &ctx);
~plugin_version_info() = default;
context ctx;
std::string name; std::string name;
std::string version; std::string version;
}; };
/*! /*!
\brief Represents infos about a list \brief Represents infos about a list
*/ */
struct list_info struct list_info
{ {
list_info(context &ctx);
~list_info() = default;
context ctx; context ctx;
bool used; bool used;
size_t index; size_t index;
@@ -112,11 +210,15 @@ public:
}; };
/*! /*!
\brief Represents infos about a macro \brief Represents infos about a macro
*/ */
struct macro_info struct macro_info
{ {
macro_info(context &ctx);
~macro_info() = default;
context ctx; context ctx;
context cond_ctx;
bool used; bool used;
size_t index; size_t index;
size_t visibility; size_t visibility;
@@ -130,6 +232,9 @@ public:
*/ */
struct rule_exception_info struct rule_exception_info
{ {
rule_exception_info(context &ctx);
~rule_exception_info() = default;
/*! /*!
\brief This is necessary due to the dynamic-typed nature of \brief This is necessary due to the dynamic-typed nature of
exceptions. Each of fields, comps, and values, can either be a exceptions. Each of fields, comps, and values, can either be a
@@ -148,6 +253,7 @@ public:
} }
}; };
context ctx;
std::string name; std::string name;
entry fields; entry fields;
entry comps; entry comps;
@@ -155,11 +261,16 @@ public:
}; };
/*! /*!
\brief Represents infos about a rule \brief Represents infos about a rule
*/ */
struct rule_info struct rule_info
{ {
rule_info(context &ctx);
~rule_info() = default;
context ctx; context ctx;
context cond_ctx;
context output_ctx;
size_t index; size_t index;
size_t visibility; size_t visibility;
std::string name; std::string name;
@@ -185,7 +296,7 @@ public:
/*! /*!
\brief Uses the internal state to compile a list of falco_rules \brief Uses the internal state to compile a list of falco_rules
*/ */
virtual bool compile(configuration& cfg, indexed_vector<falco_rule>& out) const; virtual void compile(configuration& cfg, indexed_vector<falco_rule>& out) const;
/*! /*!
\brief Returns the set of all required versions for each plugin according \brief Returns the set of all required versions for each plugin according