diff --git a/test/boost/audit_rule_test.cc b/test/boost/audit_rule_test.cc index 46e6d28b8f..5f6cd9675c 100644 --- a/test/boost/audit_rule_test.cc +++ b/test/boost/audit_rule_test.cc @@ -8,13 +8,19 @@ #include +#include + #include +#include #include "audit/audit.hh" #include "audit/audit_rule.hh" +#include "db/config.hh" using namespace seastar; +namespace bpo = boost::program_options; + namespace { audit::audit_rule make_rule(std::vector sinks, @@ -97,3 +103,114 @@ BOOST_AUTO_TEST_CASE(test_json_round_trip) { BOOST_CHECK_EQUAL(audit::audit_rules_to_json_string({}), "[]"); } + +BOOST_AUTO_TEST_CASE(test_config_audit_rules_yaml) { + db::config cfg; + BOOST_CHECK(cfg.audit_rules().empty()); + + cfg.read_from_yaml( + "audit_rules:\n" + " - sinks: [table]\n" + " categories: [DML, DDL]\n" + " qualified_table_names: [ks.t1]\n" + " roles: ['admin\\*', 'domain\\\\user', 'user[0-9]', '!(guest)']\n"); + + BOOST_CHECK(cfg.audit_rules.source() == utils::config_file::config_source::SettingsFile); + BOOST_REQUIRE_EQUAL(cfg.audit_rules().size(), 1u); + BOOST_CHECK(cfg.audit_rules()[0].categories.contains(audit::statement_category::DML)); + BOOST_CHECK(cfg.audit_rules()[0].categories.contains(audit::statement_category::DDL)); + BOOST_CHECK_EQUAL(cfg.audit_rules()[0].roles[0], "admin\\*"); + + auto parsed = audit::parse_audit_rules_from_json(cfg.audit_rules.value_as_json()._res); + BOOST_REQUIRE_EQUAL(parsed.size(), 1u); + BOOST_CHECK(parsed[0] == cfg.audit_rules()[0]); +} + +BOOST_AUTO_TEST_CASE(test_config_audit_rules_cql) { + db::config cfg; + + std::vector observed; + auto observer = cfg.audit_rules.observe([&observed] (const std::vector& rules) { + observed = rules; + }); + BOOST_CHECK(cfg.audit_rules.set_value( + R"([{"sinks":["syslog"],"categories":["AUTH"],"qualified_table_names":[],"roles":["*"]}])", + utils::config_file::config_source::CQL)); + BOOST_CHECK(cfg.audit_rules.source() == utils::config_file::config_source::CQL); + BOOST_REQUIRE_EQUAL(observed.size(), 1u); + BOOST_CHECK_EQUAL(observed[0].sinks[0], "syslog"); + BOOST_CHECK(observed[0].categories.contains(audit::statement_category::AUTH)); +} + +BOOST_AUTO_TEST_CASE(test_config_audit_rules_cli) { + db::config cfg; + + auto desc = cfg.get_options_description(); + bpo::variables_map vm; + const char* argv[] = {"test", "--audit-rules", R"([{"sinks":["table"],"categories":["DML"],"qualified_table_names":["ks.t1"],"roles":["*"]}])"}; + bpo::store(bpo::parse_command_line(3, argv, desc), vm); + bpo::notify(vm); + BOOST_REQUIRE_EQUAL(cfg.audit_rules().size(), 1u); + BOOST_CHECK_EQUAL(cfg.audit_rules()[0].qualified_table_names[0], "ks.t1"); +} + +BOOST_AUTO_TEST_CASE(test_config_audit_rules_rejects_invalid_values) { + db::config cfg; + BOOST_CHECK_THROW( + cfg.read_from_yaml( + "audit_rules:\n" + " - sinks: [kafka]\n" + " categories: [DML]\n" + " qualified_table_names: []\n" + " roles: []\n"), + std::exception); + + // Each required field missing in turn. + BOOST_CHECK_THROW(cfg.read_from_yaml( + "audit_rules:\n" + " - categories: [DML]\n" + " qualified_table_names: []\n" + " roles: []\n"), std::exception); + BOOST_CHECK_THROW(cfg.read_from_yaml( + "audit_rules:\n" + " - sinks: [table]\n" + " qualified_table_names: []\n" + " roles: []\n"), std::exception); + BOOST_CHECK_THROW(cfg.read_from_yaml( + "audit_rules:\n" + " - sinks: [table]\n" + " categories: [DML]\n" + " roles: []\n"), std::exception); + BOOST_CHECK_THROW(cfg.read_from_yaml( + "audit_rules:\n" + " - sinks: [table]\n" + " categories: [DML]\n" + " qualified_table_names: []\n"), std::exception); + // Scalar value where array is expected. + BOOST_CHECK_THROW(cfg.read_from_yaml( + "audit_rules:\n" + " - sinks: table\n" + " categories: [DML]\n" + " qualified_table_names: []\n" + " roles: []\n"), std::exception); + BOOST_CHECK_THROW(cfg.read_from_yaml( + "audit_rules:\n" + " - sinks: [table]\n" + " categories: DML\n" + " qualified_table_names: []\n" + " roles: []\n"), std::exception); + BOOST_CHECK_THROW(cfg.read_from_yaml( + "audit_rules:\n" + " - sinks: [table]\n" + " categories: [DML]\n" + " qualified_table_names: ks.t1\n" + " roles: []\n"), std::exception); + BOOST_CHECK_THROW(cfg.read_from_yaml( + "audit_rules:\n" + " - sinks: [table]\n" + " categories: [DML]\n" + " qualified_table_names: []\n" + " roles: '*'\n"), std::exception); + + BOOST_CHECK_THROW(cfg.audit_rules.set_value(sstring("{not json}"), utils::config_file::config_source::CQL), std::exception); +}