summaryrefslogtreecommitdiff
path: root/src/mongo/db/matcher
diff options
context:
space:
mode:
authorTed Tuckman <ted.tuckman@mongodb.com>2023-02-28 15:34:40 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2023-02-28 17:02:01 +0000
commitd5e281bc80818c7398e1b96af78a53096b6611da (patch)
tree413377d4439f637cfde8c33e036b8ccf7bc86be0 /src/mongo/db/matcher
parente4f411f089d825af8aa0d77fe05657cc27e297fe (diff)
downloadmongo-d5e281bc80818c7398e1b96af78a53096b6611da.tar.gz
SERVER-73709 Enable redaction for expressions inside $expr
Diffstat (limited to 'src/mongo/db/matcher')
-rw-r--r--src/mongo/db/matcher/expression_expr.cpp3
-rw-r--r--src/mongo/db/matcher/expression_expr_test.cpp113
2 files changed, 114 insertions, 2 deletions
diff --git a/src/mongo/db/matcher/expression_expr.cpp b/src/mongo/db/matcher/expression_expr.cpp
index cd7f27fa9ba..c8f6a2aad9e 100644
--- a/src/mongo/db/matcher/expression_expr.cpp
+++ b/src/mongo/db/matcher/expression_expr.cpp
@@ -78,8 +78,7 @@ Value ExprMatchExpression::evaluateExpression(const MatchableDocument* doc) cons
}
void ExprMatchExpression::serialize(BSONObjBuilder* out, SerializationOptions opts) const {
- // TODO aggregation expressions should support some of the new options.
- *out << "$expr" << _expression->serialize(false);
+ *out << "$expr" << _expression->serialize(opts);
}
bool ExprMatchExpression::equivalent(const MatchExpression* other) const {
diff --git a/src/mongo/db/matcher/expression_expr_test.cpp b/src/mongo/db/matcher/expression_expr_test.cpp
index 6401357cc61..57d793d27d7 100644
--- a/src/mongo/db/matcher/expression_expr_test.cpp
+++ b/src/mongo/db/matcher/expression_expr_test.cpp
@@ -38,6 +38,7 @@
#include "mongo/db/pipeline/expression_context_for_test.h"
#include "mongo/db/query/collation/collator_interface_mock.h"
#include "mongo/unittest/death_test.h"
+#include "mongo/unittest/inline_auto_update.h"
#include "mongo/unittest/unittest.h"
namespace mongo {
@@ -86,6 +87,10 @@ public:
return checked_cast<ExprMatchExpression*>(_matchExpression.get());
}
+ BSONObj serialize(SerializationOptions opts) {
+ return _matchExpression->serialize(opts);
+ }
+
private:
const boost::intrusive_ptr<ExpressionContextForTest> _expCtx;
std::unique_ptr<MatchExpression> _matchExpression;
@@ -795,5 +800,113 @@ DEATH_TEST_REGEX(ExprMatchTest, GetChildFailsIndexGreaterThanZero, "Tripwire ass
ASSERT_THROWS_CODE(matchExpr->getChild(0), AssertionException, 6400207);
}
+/**
+ * A default redaction strategy that generates easy to check results for testing purposes.
+ */
+std::string redactFieldNameForTest(StringData s) {
+ return str::stream() << "HASH(" << s << ")";
+}
+
+TEST_F(ExprMatchTest, ExprRedactsCorrectly) {
+ boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest());
+ createMatcher(fromjson("{$expr: {$sum: [\"$a\", \"$b\"]}}"));
+
+ SerializationOptions opts;
+ opts.redactFieldNamesStrategy = redactFieldNameForTest;
+ opts.redactFieldNames = true;
+ opts.replacementForLiteralArgs = "?";
+
+ ASSERT_STR_EQ_AUTO(
+ "{ $expr: { $sum: [ \"$HASH(a)\", \"$HASH(b)\" ] } }", // NOLINT (test auto-update)
+ serialize(opts).toString());
+
+ createMatcher(fromjson("{$expr: {$sum: [\"$a\", \"b\"]}}"));
+ ASSERT_STR_EQ_AUTO(
+ "{ $expr: { $sum: [ \"$HASH(a)\", { $const: \"?\" } ] } }", // NOLINT (test auto-update)
+ serialize(opts).toString());
+
+ createMatcher(fromjson("{$expr: {$sum: [\"$a.b\", \"$b\"]}}"));
+ ASSERT_STR_EQ_AUTO(
+ "{ $expr: { $sum: [ \"$HASH(a).HASH(b)\", \"$HASH(b)\" ] } }", // NOLINT (test auto-update)
+ // auto-update)
+ // auto-update)
+ // auto-update)
+ serialize(opts).toString());
+
+ createMatcher(fromjson("{$expr: {$eq: [\"$a\", \"$$NOW\"]}}"));
+ ASSERT_STR_EQ_AUTO(
+ "{ $and: [ { HASH(a): { $_internalExprEq: \"?\" } }, { $expr: { $eq: [ \"$HASH(a)\", { "
+ "$const: \"?\" } ] } } ] }",
+ serialize(opts).toString());
+
+ createMatcher(fromjson("{$expr: {$eq: [\"$a\", \"$$NOW\"]}}"));
+ ASSERT_STR_EQ_AUTO(
+ "{ $and: [ { HASH(a): { $_internalExprEq: \"?\" } }, { $expr: { $eq: [ \"$HASH(a)\", { "
+ "$const: \"?\" } ] } } ] }",
+ serialize(opts).toString());
+
+ createMatcher(fromjson("{$expr: {$getField: {field: \"b\", input: {a: 1, b: 2}}}}"));
+ ASSERT_STR_EQ_AUTO(
+ "{ $expr: { $getField: { field: \"HASH(b)\", input: { $const: \"?\" } } } }", // NOLINT
+ // (test
+ // auto-update)
+ serialize(opts).toString());
+
+ createMatcher(fromjson("{$expr: {$getField: {field: \"b\", input: \"$a\"}}}"));
+ ASSERT_STR_EQ_AUTO(
+ "{ $expr: { $getField: { field: \"HASH(b)\", input: \"$HASH(a)\" } } }", // NOLINT (test
+ // auto-update)
+ serialize(opts).toString());
+
+ createMatcher(fromjson("{$expr: {$getField: {field: \"b\", input: {a: 1, b: \"$c\"}}}}"));
+ ASSERT_STR_EQ_AUTO(
+ "{ $expr: { $getField: { field: \"HASH(b)\", input: { HASH(a): { $const: \"?\" }, "
+ "HASH(b): \"$HASH(c)\" } } } }",
+ serialize(opts).toString());
+
+ createMatcher(fromjson("{$expr: {$getField: {field: \"b.c\", input: {a: 1, b: \"$c\"}}}}"));
+ ASSERT_STR_EQ_AUTO(
+ "{ $expr: { $getField: { field: \"HASH(b).HASH(c)\", input: { HASH(a): { $const: \"?\" }, "
+ "HASH(b): \"$HASH(c)\" } } } }",
+ serialize(opts).toString());
+
+ createMatcher(
+ fromjson("{$expr: {$setField: {field: \"b\", input: {a: 1, b: \"$c\"}, value: 5}}}"));
+ ASSERT_STR_EQ_AUTO(
+ "{ $expr: { $setField: { field: \"HASH(b)\", input: { HASH(a): { $const: \"?\" }, "
+ "HASH(b): \"$HASH(c)\" }, value: { $const: \"?\" } } } }",
+ serialize(opts).toString());
+
+ createMatcher(fromjson(
+ "{$expr: {$setField: {field: \"b.c\", input: {a: 1, b: \"$c\"}, value: \"$d\"}}}"));
+ ASSERT_STR_EQ_AUTO(
+ "{ $expr: { $setField: { field: \"HASH(b).HASH(c)\", input: { HASH(a): { $const: \"?\" }, "
+ "HASH(b): \"$HASH(c)\" }, value: \"$HASH(d)\" } } }",
+ serialize(opts).toString());
+
+ createMatcher(fromjson(
+ "{$expr: {$setField: {field: \"b.c\", input: {a: 1, b: \"$c\"}, value: \"$d.e\"}}}"));
+ ASSERT_STR_EQ_AUTO(
+ "{ $expr: { $setField: { field: \"HASH(b).HASH(c)\", input: { HASH(a): { $const: \"?\" }, "
+ "HASH(b): \"$HASH(c)\" }, value: \"$HASH(d).HASH(e)\" } } }",
+ serialize(opts).toString());
+
+ createMatcher(
+ fromjson("{$expr: {$setField: {field: \"b\", input: {a: 1, b: \"$c\"}, value: {a: 1, b: 2, "
+ "c: 3}}}}"));
+ ASSERT_STR_EQ_AUTO(
+ "{ $expr: { $setField: { field: \"HASH(b)\", input: { HASH(a): { $const: \"?\" }, "
+ "HASH(b): \"$HASH(c)\" }, value: { $const: \"?\" } } } }",
+ serialize(opts).toString());
+
+ createMatcher(
+ fromjson("{$expr: {$setField: {field: \"b\", input: {a: 1, b: \"$c\"}, value: {a: 1, b: 2, "
+ "c: \"$d\"}}}}"));
+ ASSERT_STR_EQ_AUTO(
+ "{ $expr: { $setField: { field: \"HASH(b)\", input: { HASH(a): { $const: \"?\" }, "
+ "HASH(b): \"$HASH(c)\" }, value: { HASH(a): { $const: \"?\" }, HASH(b): { $const: \"?\" "
+ "}, HASH(c): \"$HASH(d)\" } } } }",
+ serialize(opts).toString());
+}
} // namespace
} // namespace mongo