Skip to content

Commit

Permalink
Fixes and more tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Anilm3 committed Sep 20, 2024
1 parent 600e66a commit 4ff6ada
Show file tree
Hide file tree
Showing 6 changed files with 304 additions and 21 deletions.
19 changes: 8 additions & 11 deletions src/condition/scalar_condition.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -196,10 +196,7 @@ eval_result scalar_negated_condition::eval(condition_cache &cache, const object_
cache.targets.assign(1, nullptr);
}

// This type of scalar condition only accepts a single target
const auto &target = targets_[0];

auto [object, attr] = store.get_target(target.index);
auto [object, attr] = store.get_target(target_.index);
if (object == nullptr || object == cache.targets[0]) {
return {};
}
Expand All @@ -210,19 +207,19 @@ eval_result scalar_negated_condition::eval(condition_cache &cache, const object_
}

bool match = false;
if (target.source == data_source::keys) {
object::key_iterator it(object, target.key_path, objects_excluded, limits_);
if (target_.source == data_source::keys) {
object::key_iterator it(object, target_.key_path, objects_excluded, limits_);
match = eval_target<bool>(
it, target.name, ephemeral, *matcher, target.transformers, limits_, deadline);
it, target_.name, ephemeral, *matcher, target_.transformers, limits_, deadline);
} else {
object::value_iterator it(object, target.key_path, objects_excluded, limits_);
object::value_iterator it(object, target_.key_path, objects_excluded, limits_);
match = eval_target<bool>(
it, target.name, ephemeral, *matcher, target.transformers, limits_, deadline);
it, target_.name, ephemeral, *matcher, target_.transformers, limits_, deadline);
}

if (!match) {
cache.match = {{{{"input"sv, object_to_string(*object), target.name,
{target.key_path.begin(), target.key_path.end()}}},
cache.match = {{{{"input"sv, object_to_string(*object), target_.name,
{target_.key_path.begin(), target_.key_path.end()}}},
{}, matcher_name_, matcher->to_string(), ephemeral}};
return {true, ephemeral};
}
Expand Down
10 changes: 7 additions & 3 deletions src/condition/scalar_condition.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,11 @@ class scalar_negated_condition : public base_condition {
throw std::invalid_argument("Matcher initialised without arguments");
}

targets_ = std::move(args[0].targets);
if (args[0].targets.size() > 1) {
throw std::invalid_argument("Negated matchers don't support variadic arguments");
}

target_ = std::move(args[0].targets[0]);
}

eval_result eval(condition_cache &cache, const object_store &store,
Expand All @@ -75,7 +79,7 @@ class scalar_negated_condition : public base_condition {

void get_addresses(std::unordered_map<target_index, std::string> &addresses) const override
{
for (const auto &target : targets_) { addresses.emplace(target.index, target.name); }
addresses.emplace(target_.index, target_.name);
}

static constexpr auto arguments()
Expand All @@ -86,7 +90,7 @@ class scalar_negated_condition : public base_condition {
protected:
std::unique_ptr<matcher::base> matcher_;
std::string data_id_;
std::vector<condition_target> targets_;
condition_target target_;
std::string matcher_name_;
const object_limits limits_;
};
Expand Down
111 changes: 111 additions & 0 deletions tests/condition/scalar_condition_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
// Unless explicitly stated otherwise all files in this repository are
// dual-licensed under the Apache-2.0 License or BSD-3-Clause License.
//
// This product includes software developed at Datadog (https://www.datadoghq.com/).
// Copyright 2021 Datadog, Inc.

#include "../test.hpp"
#include "condition/scalar_condition.hpp"
#include "matcher/regex_match.hpp"
#include "utils.hpp"

using namespace ddwaf;
using namespace std::literals;

namespace {

template <typename... Args> condition_parameter gen_variadic_param(Args... addresses)
{
return {{{std::string{addresses}, get_target_index(addresses)}...}};
}
TEST(TestScalarCondition, TooManyAddressesInConstructor)
{
EXPECT_THROW((scalar_condition{std::make_unique<matcher::regex_match>(".*", 0, true), {},
{gen_variadic_param("server.request.uri_raw"),
gen_variadic_param("server.request.query")}}),
std::invalid_argument);
}

TEST(TestScalarCondition, NoAddressesInConstructor)
{
EXPECT_THROW((scalar_condition{std::make_unique<matcher::regex_match>(".*", 0, true), {}, {}}),
std::invalid_argument);
}

TEST(TestScalarCondition, NoMatch)
{
scalar_condition cond{std::make_unique<matcher::regex_match>(".*", 0, true), {},
{gen_variadic_param("server.request.uri_raw")}};

ddwaf_object tmp;
ddwaf_object root;
ddwaf_object_map(&root);
ddwaf_object_map_add(&root, "server.request.uri_raw", ddwaf_object_invalid(&tmp));

object_store store;
store.insert(root);

ddwaf::timer deadline{2s};
condition_cache cache;
auto res = cond.eval(cache, store, {}, {}, deadline);
ASSERT_FALSE(res.outcome);
ASSERT_FALSE(res.ephemeral);
}

TEST(TestScalarCondition, SimpleMatch)
{
scalar_condition cond{std::make_unique<matcher::regex_match>(".*", 0, true), {},
{gen_variadic_param("server.request.uri_raw")}};

ddwaf_object tmp;
ddwaf_object root;
ddwaf_object_map(&root);
ddwaf_object_map_add(&root, "server.request.uri_raw", ddwaf_object_string(&tmp, "hello"));

object_store store;
store.insert(root);

ddwaf::timer deadline{2s};
condition_cache cache;
auto res = cond.eval(cache, store, {}, {}, deadline);
ASSERT_TRUE(res.outcome);
ASSERT_FALSE(res.ephemeral);
}

TEST(TestScalarCondition, CachedMatch)
{
scalar_condition cond{std::make_unique<matcher::regex_match>(".*", 0, true), {},
{gen_variadic_param("server.request.uri_raw")}, {}};

ddwaf::timer deadline{2s};
condition_cache cache;

ddwaf_object tmp;
ddwaf_object root;

{
ddwaf_object_map(&root);
ddwaf_object_map_add(&root, "server.request.uri_raw", ddwaf_object_string(&tmp, "hello"));

object_store store;
store.insert(root);

auto res = cond.eval(cache, store, {}, {}, deadline);
ASSERT_TRUE(res.outcome);
ASSERT_FALSE(res.ephemeral);
}

{
ddwaf_object_map(&root);
ddwaf_object_map_add(&root, "server.request.uri_raw", ddwaf_object_string(&tmp, "hello"));

object_store store;
store.insert(root);

auto res = cond.eval(cache, store, {}, {}, deadline);
ASSERT_FALSE(res.outcome);
ASSERT_FALSE(res.ephemeral);
}
}

} // namespace
123 changes: 123 additions & 0 deletions tests/condition/scalar_negated_condition_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
// Unless explicitly stated otherwise all files in this repository are
// dual-licensed under the Apache-2.0 License or BSD-3-Clause License.
//
// This product includes software developed at Datadog (https://www.datadoghq.com/).
// Copyright 2021 Datadog, Inc.

#include "../test.hpp"
#include "condition/scalar_condition.hpp"
#include "matcher/regex_match.hpp"
#include "utils.hpp"

using namespace ddwaf;
using namespace std::literals;

namespace {

template <typename... Args> condition_parameter gen_variadic_param(Args... addresses)
{
return {{{std::string{addresses}, get_target_index(addresses)}...}};
}

TEST(TestScalarNegatedCondition, VariadicTargetInConstructor)
{
EXPECT_THROW(
(scalar_negated_condition{std::make_unique<matcher::regex_match>(".*", 0, true), {},
{gen_variadic_param("server.request.uri_raw", "server.request.query")}, {}}),
std::invalid_argument);
}

TEST(TestScalarNegatedCondition, TooManyAddressesInConstructor)
{
EXPECT_THROW(
(scalar_negated_condition{std::make_unique<matcher::regex_match>(".*", 0, true), {},
{gen_variadic_param("server.request.uri_raw"),
gen_variadic_param("server.request.query")},
{}}),
std::invalid_argument);
}

TEST(TestScalarNegatedCondition, NoAddressesInConstructor)
{
EXPECT_THROW((scalar_negated_condition{
std::make_unique<matcher::regex_match>(".*", 0, true), {}, {}, {}}),
std::invalid_argument);
}

TEST(TestScalarNegatedCondition, NoMatch)
{
scalar_negated_condition cond{std::make_unique<matcher::regex_match>(".*", 0, true), {},
{gen_variadic_param("server.request.uri_raw")}, {}};

ddwaf_object tmp;
ddwaf_object root;
ddwaf_object_map(&root);
ddwaf_object_map_add(&root, "server.request.uri_raw", ddwaf_object_string(&tmp, "hello"));

object_store store;
store.insert(root);

ddwaf::timer deadline{2s};
condition_cache cache;
auto res = cond.eval(cache, store, {}, {}, deadline);
ASSERT_FALSE(res.outcome);
ASSERT_FALSE(res.ephemeral);
}

TEST(TestScalarNegatedCondition, SimpleMatch)
{
scalar_negated_condition cond{std::make_unique<matcher::regex_match>(".*", 0, true), {},
{gen_variadic_param("server.request.uri_raw")}, {}};

ddwaf_object tmp;
ddwaf_object root;
ddwaf_object_map(&root);
ddwaf_object_map_add(&root, "server.request.uri_raw", ddwaf_object_invalid(&tmp));

object_store store;
store.insert(root);

ddwaf::timer deadline{2s};
condition_cache cache;
auto res = cond.eval(cache, store, {}, {}, deadline);
ASSERT_TRUE(res.outcome);
ASSERT_FALSE(res.ephemeral);
}

TEST(TestScalarNegatedCondition, CachedMatch)
{
scalar_negated_condition cond{std::make_unique<matcher::regex_match>(".*", 0, true), {},
{gen_variadic_param("server.request.uri_raw")}, {}};

ddwaf::timer deadline{2s};
condition_cache cache;

ddwaf_object tmp;
ddwaf_object root;

{
ddwaf_object_map(&root);
ddwaf_object_map_add(&root, "server.request.uri_raw", ddwaf_object_invalid(&tmp));

object_store store;
store.insert(root);

auto res = cond.eval(cache, store, {}, {}, deadline);
ASSERT_TRUE(res.outcome);
ASSERT_FALSE(res.ephemeral);
}

{
ddwaf_object_map(&root);
ddwaf_object_map_add(&root, "server.request.uri_raw", ddwaf_object_invalid(&tmp));

object_store store;
store.insert(root);

auto res = cond.eval(cache, store, {}, {}, deadline);
ASSERT_FALSE(res.outcome);
ASSERT_FALSE(res.ephemeral);
}
}

} // namespace
37 changes: 37 additions & 0 deletions tests/expression_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,43 @@ TEST(TestExpression, SimpleMatch)
}}});
}

TEST(TestExpression, SimpleNegatedMatch)
{
test::expression_builder builder(1);
builder.start_condition();
builder.add_argument();
builder.add_target("server.request.query");
builder.end_condition<matcher::regex_match, false>(".*", 5, true);

auto expr = builder.build();

ddwaf_object root;
ddwaf_object tmp;
ddwaf_object_map(&root);
ddwaf_object_map_add(&root, "server.request.query", ddwaf_object_string(&tmp, "val"));

ddwaf::object_store store;
store.insert(root);

ddwaf::timer deadline{2s};

expression::cache_type cache;
auto res = expr->eval(cache, store, {}, {}, deadline);
EXPECT_TRUE(res.outcome);
EXPECT_FALSE(res.ephemeral);

auto matches = expr->get_matches(cache);
EXPECT_EQ(matches.size(), 1);
EXPECT_FALSE(matches[0].ephemeral);
EXPECT_MATCHES(matches, {.op = "!match_regex",
.op_value = ".*",
.highlight = "",
.args = {{
.value = "val",
.address = "server.request.query",
}}});
}

TEST(TestExpression, EphemeralMatch)
{
test::expression_builder builder(1);
Expand Down
25 changes: 18 additions & 7 deletions tests/test_utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,21 +66,32 @@ class expression_builder {

void start_condition() { arguments_.clear(); }

template <typename T, typename... Args>
template <typename T, bool Expected = true, typename... Args>
void end_condition(Args... args)
requires std::is_base_of_v<matcher::base, T>
{
conditions_.emplace_back(
std::make_unique<scalar_condition>(std::make_unique<T>(std::forward<Args>(args)...),
std::string{}, std::move(arguments_)));
if constexpr (Expected) {
conditions_.emplace_back(
std::make_unique<scalar_condition>(std::make_unique<T>(std::forward<Args>(args)...),
std::string{}, std::move(arguments_)));
} else {
conditions_.emplace_back(std::make_unique<scalar_negated_condition>(
std::make_unique<T>(std::forward<Args>(args)...), std::string{},
std::move(arguments_), "!" + std::string{T::matcher_name}));
}
}

template <typename T>
template <typename T, bool Expected = true>
void end_condition_with_data(std::string data_id)
requires std::is_base_of_v<matcher::base, T>
{
conditions_.emplace_back(std::make_unique<scalar_condition>(
std::unique_ptr<matcher::base>{}, std::move(data_id), std::move(arguments_)));
if constexpr (Expected) {
conditions_.emplace_back(std::make_unique<scalar_condition>(
std::unique_ptr<matcher::base>{}, std::move(data_id), std::move(arguments_)));
} else {
conditions_.emplace_back(std::make_unique<scalar_negated_condition>(
std::unique_ptr<matcher::base>{}, std::move(data_id), std::move(arguments_)));
}
}

template <typename T>
Expand Down

0 comments on commit 4ff6ada

Please sign in to comment.