diff --git a/unit_tests/engine/test_rule_loader.cpp b/unit_tests/engine/test_rule_loader.cpp index f5fb40a4..042f55d0 100644 --- a/unit_tests/engine/test_rule_loader.cpp +++ b/unit_tests/engine/test_rule_loader.cpp @@ -374,6 +374,34 @@ TEST_F(engine_loader_test, macro_override_append_before_macro_definition) ASSERT_TRUE(check_error_message(ERROR_NO_PREVIOUS_MACRO)); } +TEST_F(engine_loader_test, macro_override_replace_before_macro_definition) +{ + std::string rules_content = R"END( + +- macro: open_simple + condition: or evt.type = openat2 + override: + condition: replace + +- macro: open_simple + condition: evt.type in (open,openat) + +- rule: test_rule + desc: simple rule + condition: open_simple + output: command=%proc.cmdline + priority: INFO + +)END"; + + // The first override defines a macro that is overridden by the second macro definition + ASSERT_TRUE(load_rules(rules_content, "rules.yaml")); + std::string rule_name = "test_rule"; + auto rule_description = m_engine->describe_rule(&rule_name, {}); + ASSERT_EQ(rule_description["rules"][0]["details"]["condition_compiled"].template get(), + "evt.type in (open, openat)"); +} + TEST_F(engine_loader_test, macro_append_before_macro_definition) { std::string rules_content = R"END( @@ -470,7 +498,27 @@ TEST_F(engine_loader_test, rule_override_append_before_rule_definition) )END"; ASSERT_FALSE(load_rules(rules_content, "rules.yaml")); - ASSERT_TRUE(check_error_message(ERROR_NO_PREVIOUS_RULE)); + ASSERT_TRUE(check_error_message(ERROR_NO_PREVIOUS_RULE_APPEND)); +} + +TEST_F(engine_loader_test, rule_override_replace_before_rule_definition) +{ + std::string rules_content = R"END( +- rule: test_rule + condition: and proc.name = cat + override: + condition: replace + +- rule: test_rule + desc: simple rule + condition: evt.type in (open,openat) + output: command=%proc.cmdline + priority: INFO + +)END"; + + ASSERT_FALSE(load_rules(rules_content, "rules.yaml")); + ASSERT_TRUE(check_error_message(ERROR_NO_PREVIOUS_RULE_REPLACE)); } TEST_F(engine_loader_test, rule_append_before_rule_definition) @@ -489,7 +537,7 @@ TEST_F(engine_loader_test, rule_append_before_rule_definition) )END"; ASSERT_FALSE(load_rules(rules_content, "rules.yaml")); - ASSERT_TRUE(check_error_message(ERROR_NO_PREVIOUS_RULE)); + ASSERT_TRUE(check_error_message(ERROR_NO_PREVIOUS_RULE_APPEND)); } TEST_F(engine_loader_test, rule_override_append_after_rule_definition) @@ -594,6 +642,33 @@ TEST_F(engine_loader_test, list_override_append_before_list_definition) ASSERT_TRUE(check_error_message(ERROR_NO_PREVIOUS_LIST)); } +TEST_F(engine_loader_test, list_override_replace_before_list_definition) +{ + std::string rules_content = R"END( +- list: dev_creation_binaries + items: ["csi-provisioner", "csi-attacher"] + override: + items: replace + +- list: dev_creation_binaries + items: [blkid] + +- rule: test_rule + desc: simple rule + condition: evt.type = execve and proc.name in (dev_creation_binaries) + output: command=%proc.cmdline + priority: INFO + +)END"; + + // With override replace we define a first list that then is overridden by the second one. + ASSERT_TRUE(load_rules(rules_content, "rules.yaml")); + std::string rule_name = "test_rule"; + auto rule_description = m_engine->describe_rule(&rule_name, {}); + ASSERT_EQ(rule_description["rules"][0]["details"]["condition_compiled"].template get(), + "(evt.type = execve and proc.name in (blkid))"); +} + TEST_F(engine_loader_test, list_append_before_list_definition) { std::string rules_content = R"END( diff --git a/userspace/engine/rule_loader_collector.cpp b/userspace/engine/rule_loader_collector.cpp index 9c8b31c9..fdeef81e 100644 --- a/userspace/engine/rule_loader_collector.cpp +++ b/userspace/engine/rule_loader_collector.cpp @@ -20,6 +20,7 @@ limitations under the License. #include "falco_engine.h" #include "rule_loader_collector.h" +#include "rule_loading_messages.h" #define THROW(cond, err, ctx) { if ((cond)) { throw rule_loader::rule_load_exception(falco::load_result::LOAD_ERR_VALIDATE, (err), (ctx)); } } @@ -239,7 +240,7 @@ void rule_loader::collector::append(configuration& cfg, rule_update_info& info) { auto prev = m_rule_infos.at(info.name); - THROW(!prev, ERROR_NO_PREVIOUS_RULE, info.ctx); + THROW(!prev, ERROR_NO_PREVIOUS_RULE_APPEND, info.ctx); THROW(!info.has_any_value(), "Appended rule must have exceptions or condition property", // "Appended rule must have at least one field that can be appended to", // TODO replace with this and update testing @@ -322,9 +323,7 @@ void rule_loader::collector::selective_replace(configuration& cfg, rule_update_i { auto prev = m_rule_infos.at(info.name); - THROW(!prev, - "An replace to a rule was requested but no rule by that name already exists", - info.ctx); + THROW(!prev, ERROR_NO_PREVIOUS_RULE_REPLACE, info.ctx); THROW(!info.has_any_value(), "The rule must have at least one field that can be replaced", info.ctx); diff --git a/userspace/engine/rule_loading_messages.h b/userspace/engine/rule_loading_messages.h index a0e62ac4..18476b64 100644 --- a/userspace/engine/rule_loading_messages.h +++ b/userspace/engine/rule_loading_messages.h @@ -1,16 +1,16 @@ #pragma once -// Error message used when both 'override' and 'append' keys are specified. +// todo: rename putting error at the beginning #define OVERRIDE_APPEND_ERROR_MESSAGE "Keys 'override' and 'append: true' cannot be used together. Add an 'append' entry (e.g. 'condition: append') under 'override' instead." -// Warning message used when 'append' key is used. #define WARNING_APPEND_MESSAGE "'append' key is deprecated. Add an 'append' entry (e.g. 'condition: append') under 'override' instead." -// Warning message used when 'enabled' is used without 'override' key. #define WARNING_ENABLED_MESSAGE "The standalone 'enabled' key usage is deprecated. The correct approach requires also a 'replace' entry under the 'override' key (i.e. 'enabled: replace')." #define ERROR_NO_PREVIOUS_MACRO "Macro uses 'append' or 'override.condition: append' but no macro by that name already exists" #define ERROR_NO_PREVIOUS_LIST "List uses 'append' or 'override.items: append' but no list by that name already exists" -#define ERROR_NO_PREVIOUS_RULE "Rule uses 'append' or 'override.: append' but no rule by that name already exists" +#define ERROR_NO_PREVIOUS_RULE_APPEND "Rule uses 'append' or 'override.: append' but no rule by that name already exists" + +#define ERROR_NO_PREVIOUS_RULE_REPLACE "An 'override.: replace' to a rule was requested but no rule by that name already exists"