From d79d53bdb2e9ecc13b72b8ab77124f9e21b1514f Mon Sep 17 00:00:00 2001 From: Will Buerger Date: Tue, 4 Apr 2023 16:59:04 +0000 Subject: SERVER-75343: Fix and centralize identifier redaction in SerializationOptions --- src/mongo/db/exec/exclusion_projection_executor.h | 2 +- src/mongo/db/exec/inclusion_projection_executor.h | 2 +- .../db/exec/projection_executor_redaction_test.cpp | 4 +- src/mongo/db/exec/projection_node.cpp | 8 +-- src/mongo/db/matcher/expression_expr_test.cpp | 4 +- src/mongo/db/matcher/expression_geo_test.cpp | 2 +- .../expression_internal_bucket_geo_within.cpp | 8 +-- src/mongo/db/matcher/expression_path.h | 7 +- .../db/matcher/expression_serialization_test.cpp | 36 +++++----- src/mongo/db/matcher/expression_tree.cpp | 6 +- .../schema/expression_internal_schema_eq.cpp | 2 +- ...xpression_internal_schema_match_array_index.cpp | 2 +- .../expression_internal_schema_str_length.cpp | 4 +- src/mongo/db/pipeline/accumulator_test.cpp | 8 +-- .../db/pipeline/aggregation_context_fixture.h | 4 +- .../db/pipeline/document_source_bucket_auto.cpp | 5 +- .../document_source_change_stream_oplog_match.cpp | 2 +- ...ent_source_change_stream_unwind_transaction.cpp | 2 +- .../db/pipeline/document_source_coll_stats.cpp | 2 +- src/mongo/db/pipeline/document_source_cursor.cpp | 2 +- src/mongo/db/pipeline/document_source_densify.cpp | 11 ++- .../db/pipeline/document_source_densify_test.cpp | 4 +- src/mongo/db/pipeline/document_source_exchange.cpp | 2 +- src/mongo/db/pipeline/document_source_facet.cpp | 2 +- src/mongo/db/pipeline/document_source_geo_near.cpp | 8 +-- .../db/pipeline/document_source_graph_lookup.cpp | 2 +- .../db/pipeline/document_source_group_base.cpp | 10 +-- .../db/pipeline/document_source_index_stats.cpp | 2 +- ...cument_source_internal_all_collection_stats.cpp | 4 +- ...t_source_internal_compute_geo_near_distance.cpp | 5 +- ..._source_internal_convert_bucket_index_stats.cpp | 2 +- .../document_source_internal_unpack_bucket.cpp | 13 ++-- .../unpack_bucket_exec_test.cpp | 4 +- .../document_source_list_cached_and_active_users.h | 2 +- .../pipeline/document_source_list_local_sessions.h | 2 +- .../db/pipeline/document_source_list_sessions.cpp | 2 +- src/mongo/db/pipeline/document_source_lookup.cpp | 2 +- src/mongo/db/pipeline/document_source_match.cpp | 2 +- .../db/pipeline/document_source_match_test.cpp | 6 +- src/mongo/db/pipeline/document_source_merge.cpp | 2 +- src/mongo/db/pipeline/document_source_out.cpp | 4 +- .../pipeline/document_source_plan_cache_stats.cpp | 2 +- .../document_source_plan_cache_stats_test.cpp | 4 +- src/mongo/db/pipeline/document_source_queue.cpp | 2 +- .../document_source_sequential_document_cache.cpp | 2 +- ...cument_source_set_variable_from_subpipeline.cpp | 2 +- .../pipeline/document_source_set_window_fields.cpp | 4 +- .../document_source_set_window_fields_test.cpp | 4 +- ...ument_source_single_document_transformation.cpp | 2 +- src/mongo/db/pipeline/document_source_skip.cpp | 2 +- src/mongo/db/pipeline/document_source_sort.cpp | 2 +- .../pipeline/document_source_streaming_group.cpp | 4 +- .../db/pipeline/document_source_telemetry.cpp | 12 ++-- src/mongo/db/pipeline/document_source_telemetry.h | 12 ++-- .../db/pipeline/document_source_union_with.cpp | 2 +- src/mongo/db/pipeline/document_source_unwind.cpp | 4 +- src/mongo/db/pipeline/expression.cpp | 49 ++++++-------- .../db/pipeline/expression_field_path_test.cpp | 4 +- src/mongo/db/pipeline/expression_function_test.cpp | 4 +- src/mongo/db/pipeline/expression_let_test.cpp | 4 +- src/mongo/db/pipeline/expression_test.cpp | 8 +-- src/mongo/db/pipeline/field_path.cpp | 14 ---- src/mongo/db/pipeline/field_path.h | 5 -- src/mongo/db/query/projection_ast_test.cpp | 4 +- src/mongo/db/query/projection_ast_util.cpp | 2 +- src/mongo/db/query/query_shape.cpp | 6 +- src/mongo/db/query/query_shape.h | 2 +- src/mongo/db/query/serialization_options.h | 79 ++++++++++++++++------ src/mongo/db/query/sort_pattern.cpp | 4 +- src/mongo/db/query/sort_pattern_test.cpp | 6 +- src/mongo/db/query/telemetry.cpp | 37 ++++------ src/mongo/db/query/telemetry.h | 2 +- src/mongo/db/query/telemetry_store_test.cpp | 12 ++-- ...e_analyze_shard_key_read_write_distribution.cpp | 2 +- .../document_source_resharding_ownership_match.cpp | 2 +- .../s/query/document_source_merge_cursors.cpp | 2 +- 76 files changed, 252 insertions(+), 259 deletions(-) diff --git a/src/mongo/db/exec/exclusion_projection_executor.h b/src/mongo/db/exec/exclusion_projection_executor.h index 475f65d8af1..06710575a0e 100644 --- a/src/mongo/db/exec/exclusion_projection_executor.h +++ b/src/mongo/db/exec/exclusion_projection_executor.h @@ -168,7 +168,7 @@ public: // excluded. If the _id node is not present, then explicitly set {_id: true} to avoid // ambiguity in the expected behavior of the serialized projection. _root->serialize(explain, &output, options); - auto idFieldName = options.serializeFieldName("_id"); + auto idFieldName = options.serializeFieldPath("_id"); if (output.peek()[idFieldName].missing()) { output.addField(idFieldName, Value{true}); } diff --git a/src/mongo/db/exec/inclusion_projection_executor.h b/src/mongo/db/exec/inclusion_projection_executor.h index 6ef0179a732..7fdd56644b6 100644 --- a/src/mongo/db/exec/inclusion_projection_executor.h +++ b/src/mongo/db/exec/inclusion_projection_executor.h @@ -225,7 +225,7 @@ public: // included. If the _id node is not present, then explicitly set {_id: false} to avoid // ambiguity in the expected behavior of the serialized projection. _root->serialize(explain, &output, options); - auto idFieldName = options.serializeFieldName("_id"); + auto idFieldName = options.serializeFieldPath("_id"); if (output.peek()[idFieldName].missing()) { output.addField(idFieldName, Value{false}); } diff --git a/src/mongo/db/exec/projection_executor_redaction_test.cpp b/src/mongo/db/exec/projection_executor_redaction_test.cpp index 9a7f0da3fec..b7ff9f1059c 100644 --- a/src/mongo/db/exec/projection_executor_redaction_test.cpp +++ b/src/mongo/db/exec/projection_executor_redaction_test.cpp @@ -65,9 +65,9 @@ std::string redactFieldNameForTest(StringData s) { TEST(Redaction, ProjectionTest) { SerializationOptions options; options.replacementForLiteralArgs = "?"; - options.redactFieldNames = true; + options.redactIdentifiers = true; - options.redactFieldNamesStrategy = redactFieldNameForTest; + options.identifierRedactionPolicy = redactFieldNameForTest; auto redactProj = [&](std::string obj) { return compileProjection(fromjson(obj))->serializeTransformation(boost::none, options); }; diff --git a/src/mongo/db/exec/projection_node.cpp b/src/mongo/db/exec/projection_node.cpp index 5f412693c99..0b98219ab5d 100644 --- a/src/mongo/db/exec/projection_node.cpp +++ b/src/mongo/db/exec/projection_node.cpp @@ -290,12 +290,12 @@ void ProjectionNode::serialize(boost::optional explai // Always put "_id" first if it was projected (implicitly or explicitly). if (_projectedFieldsSet.find("_id") != _projectedFieldsSet.end()) { - output->addField(options.serializeFieldName("_id"), Value(projVal)); + output->addField(options.serializeFieldPath("_id"), Value(projVal)); } for (auto&& projectedField : _projectedFields) { if (projectedField != "_id") { - output->addField(options.serializeFieldName(projectedField), Value(projVal)); + output->addField(options.serializeFieldPathFromString(projectedField), Value(projVal)); } } @@ -304,7 +304,7 @@ void ProjectionNode::serialize(boost::optional explai if (childIt != _children.end()) { MutableDocument subDoc; childIt->second->serialize(explain, &subDoc, options); - output->addField(options.serializeFieldName(field), subDoc.freezeToValue()); + output->addField(options.serializeFieldPathFromString(field), subDoc.freezeToValue()); } else { tassert(7241727, "computed fields must be allowed in inclusion projections.", @@ -313,7 +313,7 @@ void ProjectionNode::serialize(boost::optional explai tassert(7241728, "reached end of the expression iterator", expressionIt != _expressions.end()); - output->addField(options.serializeFieldName(field), + output->addField(options.serializeFieldPathFromString(field), expressionIt->second->serialize(options)); } } diff --git a/src/mongo/db/matcher/expression_expr_test.cpp b/src/mongo/db/matcher/expression_expr_test.cpp index 07e18df4660..bb008a536c1 100644 --- a/src/mongo/db/matcher/expression_expr_test.cpp +++ b/src/mongo/db/matcher/expression_expr_test.cpp @@ -812,8 +812,8 @@ TEST_F(ExprMatchTest, ExprRedactsCorrectly) { createMatcher(fromjson("{$expr: {$sum: [\"$a\", \"$b\"]}}")); SerializationOptions opts; - opts.redactFieldNamesStrategy = redactFieldNameForTest; - opts.redactFieldNames = true; + opts.identifierRedactionPolicy = redactFieldNameForTest; + opts.redactIdentifiers = true; opts.replacementForLiteralArgs = "?"; ASSERT_BSONOBJ_EQ_AUTO( // NOLINT diff --git a/src/mongo/db/matcher/expression_geo_test.cpp b/src/mongo/db/matcher/expression_geo_test.cpp index 85665e42904..92a06bf8b3b 100644 --- a/src/mongo/db/matcher/expression_geo_test.cpp +++ b/src/mongo/db/matcher/expression_geo_test.cpp @@ -158,7 +158,7 @@ TEST(ExpressionGeoTest, GeoNearEquivalent) { TEST(ExpressionGeoTest, SerializeGeoExpressions) { SerializationOptions opts = {}; - opts.redactFieldNames = true; + opts.redactIdentifiers = true; opts.replacementForLiteralArgs = "?"; { BSONObj query = fromjson("{$within: {$box: [{x: 4, y: 4}, [6, 6]]}}"); diff --git a/src/mongo/db/matcher/expression_internal_bucket_geo_within.cpp b/src/mongo/db/matcher/expression_internal_bucket_geo_within.cpp index 9d995f46e84..bb1edfde18b 100644 --- a/src/mongo/db/matcher/expression_internal_bucket_geo_within.cpp +++ b/src/mongo/db/matcher/expression_internal_bucket_geo_within.cpp @@ -197,12 +197,8 @@ void InternalBucketGeoWithinMatchExpression::serialize(BSONObjBuilder* builder, } withinRegionBob.doneFast(); // Serialize the field which is being searched over. - if (opts.redactFieldNames) { - bob.append(InternalBucketGeoWithinMatchExpression::kField, - opts.redactFieldNamesStrategy(_field)); - } else { - bob.append(InternalBucketGeoWithinMatchExpression::kField, _field); - } + bob.append(InternalBucketGeoWithinMatchExpression::kField, + opts.serializeFieldPathFromString(_field)); bob.doneFast(); } diff --git a/src/mongo/db/matcher/expression_path.h b/src/mongo/db/matcher/expression_path.h index 33f4cb751a2..1ca435c21ac 100644 --- a/src/mongo/db/matcher/expression_path.h +++ b/src/mongo/db/matcher/expression_path.h @@ -161,12 +161,7 @@ public: void serialize(BSONObjBuilder* out, SerializationOptions opts) const override { auto&& rhs = getSerializedRightHandSide(opts); if (opts.includePath) { - if (opts.redactFieldNames) { - auto redactedFieldName = opts.redactFieldNamesStrategy(path()); - out->append(redactedFieldName, rhs); - } else { - out->append(path(), rhs); - } + out->append(opts.serializeFieldPathFromString(path()), rhs); } else { out->appendElements(rhs); } diff --git a/src/mongo/db/matcher/expression_serialization_test.cpp b/src/mongo/db/matcher/expression_serialization_test.cpp index 1551039194b..d0bc9801753 100644 --- a/src/mongo/db/matcher/expression_serialization_test.cpp +++ b/src/mongo/db/matcher/expression_serialization_test.cpp @@ -1868,8 +1868,8 @@ TEST(SerializeInternalSchema, AllowedPropertiesRedactsCorrectly) { ASSERT_OK(objMatch.getStatus()); SerializationOptions opts; - opts.redactFieldNames = true; - opts.redactFieldNamesStrategy = redactFieldNameForTest; + opts.redactIdentifiers = true; + opts.identifierRedactionPolicy = redactFieldNameForTest; opts.replacementForLiteralArgs = "?"; ASSERT_BSONOBJ_EQ( @@ -1904,9 +1904,9 @@ std::unique_ptr createCondMatchExpression(BSO TEST(SerializeInternalSchema, CondMatchRedactsCorrectly) { SerializationOptions opts; - opts.redactFieldNames = true; + opts.redactIdentifiers = true; opts.replacementForLiteralArgs = "?"; - opts.redactFieldNamesStrategy = redactFieldNameForTest; + opts.identifierRedactionPolicy = redactFieldNameForTest; auto conditionQuery = BSON("age" << BSON("$lt" << 18)); auto thenQuery = BSON("job" << "student"); @@ -1946,8 +1946,8 @@ TEST(SerializeInternalSchema, MatchArrayIndexRedactsCorrectly) { BSONObjBuilder bob; SerializationOptions opts; - opts.redactFieldNames = true; - opts.redactFieldNamesStrategy = redactFieldNameForTest; + opts.redactIdentifiers = true; + opts.identifierRedactionPolicy = redactFieldNameForTest; opts.replacementForLiteralArgs = "?"; objMatch.getValue()->serialize(&bob, opts); @@ -1965,9 +1965,9 @@ TEST(SerializeInternalSchema, MatchArrayIndexRedactsCorrectly) { TEST(SerializeInternalSchema, MaxItemsRedactsCorrectly) { InternalSchemaMaxItemsMatchExpression maxItems("a.b"_sd, 2); SerializationOptions opts; - opts.redactFieldNames = true; + opts.redactIdentifiers = true; opts.replacementForLiteralArgs = "?"; - opts.redactFieldNamesStrategy = redactFieldNameForTest; + opts.identifierRedactionPolicy = redactFieldNameForTest; ASSERT_BSONOBJ_EQ(maxItems.getSerializedRightHandSide(opts), BSON("$_internalSchemaMaxItems" @@ -1986,9 +1986,9 @@ TEST(SerializeInternalSchema, MaxLengthRedactsCorrectly) { TEST(SerializeInternalSchema, MinItemsRedactsCorrectly) { InternalSchemaMinItemsMatchExpression minItems("a.b"_sd, 2); SerializationOptions opts; - opts.redactFieldNames = true; + opts.redactIdentifiers = true; opts.replacementForLiteralArgs = "?"; - opts.redactFieldNamesStrategy = redactFieldNameForTest; + opts.identifierRedactionPolicy = redactFieldNameForTest; ASSERT_BSONOBJ_EQ(minItems.getSerializedRightHandSide(opts), BSON("$_internalSchemaMinItems" @@ -2018,8 +2018,8 @@ TEST(SerializeInternalSchema, MinPropertiesRedactsCorrectly) { TEST(SerializeInternalSchema, ObjectMatchRedactsCorrectly) { SerializationOptions opts; - opts.redactFieldNames = true; - opts.redactFieldNamesStrategy = redactFieldNameForTest; + opts.redactIdentifiers = true; + opts.identifierRedactionPolicy = redactFieldNameForTest; opts.replacementForLiteralArgs = "?"; auto query = fromjson( " {a: {$_internalSchemaObjectMatch: {" @@ -2039,8 +2039,8 @@ TEST(SerializeInternalSchema, RootDocEqRedactsCorrectly) { auto query = fromjson("{$_internalSchemaRootDocEq: {a:1, b: {c: 1, d: [1]}}}"); boost::intrusive_ptr expCtx(new ExpressionContextForTest()); SerializationOptions opts; - opts.redactFieldNames = true; - opts.redactFieldNamesStrategy = redactFieldNameForTest; + opts.redactIdentifiers = true; + opts.identifierRedactionPolicy = redactFieldNameForTest; opts.replacementForLiteralArgs = "?"; auto objMatch = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(objMatch.getStatus()); @@ -2090,8 +2090,8 @@ TEST(SerializesInternalSchema, MaxPropertiesRedactsCorrectly) { TEST(SerializesInternalSchema, EqRedactsCorrectly) { SerializationOptions opts; - opts.redactFieldNamesStrategy = redactFieldNameForTest; - opts.redactFieldNames = true; + opts.identifierRedactionPolicy = redactFieldNameForTest; + opts.redactIdentifiers = true; opts.replacementForLiteralArgs = "?"; auto query = fromjson("{$_internalSchemaEq: {a:1, b: {c: 1, d: [1]}}}"); BSONObjBuilder bob; @@ -2116,8 +2116,8 @@ TEST(InternalSchemaAllElemMatchFromIndexMatchExpression, RedactsExpressionCorrec expr.getValue().get()); SerializationOptions opts; - opts.redactFieldNames = true; - opts.redactFieldNamesStrategy = redactFieldNameForTest; + opts.redactIdentifiers = true; + opts.identifierRedactionPolicy = redactFieldNameForTest; opts.replacementForLiteralArgs = "?"; ASSERT_BSONOBJ_EQ(BSON("$_internalSchemaAllElemMatchFromIndex" diff --git a/src/mongo/db/matcher/expression_tree.cpp b/src/mongo/db/matcher/expression_tree.cpp index 97a16d3b0db..5dae4cb0f6b 100644 --- a/src/mongo/db/matcher/expression_tree.cpp +++ b/src/mongo/db/matcher/expression_tree.cpp @@ -498,11 +498,7 @@ void NotMatchExpression::serialize(BSONObjBuilder* out, SerializationOptions opt BSONObjBuilder pathBob(out->subobjStart(path)); pathBob.append("$not", pathMatch->getSerializedRightHandSide(opts)); }; - if (opts.redactFieldNames) { - append(opts.redactFieldNamesStrategy(pathMatch->path())); - } else { - append(pathMatch->path()); - } + append(opts.serializeFieldPathFromString(pathMatch->path())); return; } return serializeNotExpressionToNor(expressionToNegate, out, opts); diff --git a/src/mongo/db/matcher/schema/expression_internal_schema_eq.cpp b/src/mongo/db/matcher/schema/expression_internal_schema_eq.cpp index d3e57b11bb2..43c0777f587 100644 --- a/src/mongo/db/matcher/schema/expression_internal_schema_eq.cpp +++ b/src/mongo/db/matcher/schema/expression_internal_schema_eq.cpp @@ -65,7 +65,7 @@ void InternalSchemaEqMatchExpression::debugString(StringBuilder& debug, BSONObj InternalSchemaEqMatchExpression::getSerializedRightHandSide( SerializationOptions opts) const { BSONObjBuilder eqObj; - if (opts.redactFieldNames || opts.replacementForLiteralArgs) { + if (opts.redactIdentifiers || opts.replacementForLiteralArgs) { if (_rhsElem.isABSONObj()) { BSONObjBuilder exprSpec(eqObj.subobjStart(kName)); opts.redactObjToBuilder(&exprSpec, _rhsElem.Obj()); diff --git a/src/mongo/db/matcher/schema/expression_internal_schema_match_array_index.cpp b/src/mongo/db/matcher/schema/expression_internal_schema_match_array_index.cpp index 2f000c524e9..fd1ce5f670e 100644 --- a/src/mongo/db/matcher/schema/expression_internal_schema_match_array_index.cpp +++ b/src/mongo/db/matcher/schema/expression_internal_schema_match_array_index.cpp @@ -78,7 +78,7 @@ BSONObj InternalSchemaMatchArrayIndexMatchExpression::getSerializedRightHandSide } if (auto placeHolder = _expression->getPlaceholder()) { matchArrayElemSubobj.append("namePlaceholder", - opts.serializeFieldName(placeHolder.get())); + opts.serializeFieldPathFromString(placeHolder.get())); } else { matchArrayElemSubobj.append("namePlaceholder", ""); } diff --git a/src/mongo/db/matcher/schema/expression_internal_schema_str_length.cpp b/src/mongo/db/matcher/schema/expression_internal_schema_str_length.cpp index bb8d3351e87..114e24e3ca9 100644 --- a/src/mongo/db/matcher/schema/expression_internal_schema_str_length.cpp +++ b/src/mongo/db/matcher/schema/expression_internal_schema_str_length.cpp @@ -54,9 +54,9 @@ BSONObj InternalSchemaStrLengthMatchExpression::getSerializedRightHandSide( SerializationOptions opts) const { BSONObjBuilder objBuilder; if (opts.replacementForLiteralArgs) { - objBuilder.append(opts.serializeFieldName(_name), opts.replacementForLiteralArgs.get()); + objBuilder.append(_name, opts.replacementForLiteralArgs.get()); } else { - objBuilder.append(opts.serializeFieldName(_name), _strLen); + objBuilder.append(_name, _strLen); } return objBuilder.obj(); } diff --git a/src/mongo/db/pipeline/accumulator_test.cpp b/src/mongo/db/pipeline/accumulator_test.cpp index 81c521d80fe..5a38b558fb7 100644 --- a/src/mongo/db/pipeline/accumulator_test.cpp +++ b/src/mongo/db/pipeline/accumulator_test.cpp @@ -1747,8 +1747,8 @@ Value parseAndSerializeAccumExpr( SerializationOptions options; std::string replacementChar = "?"; options.replacementForLiteralArgs = replacementChar; - options.redactFieldNames = true; - options.redactFieldNamesStrategy = redactFieldNameForTest; + options.redactIdentifiers = true; + options.identifierRedactionPolicy = redactFieldNameForTest; auto expCtx = make_intrusive(); auto expr = func(expCtx.get(), obj.firstElement(), expCtx->variablesParseState); return expr->serialize(options); @@ -1761,8 +1761,8 @@ Document parseAndSerializeAccum( SerializationOptions options; std::string replacementChar = "?"; options.replacementForLiteralArgs = replacementChar; - options.redactFieldNames = true; - options.redactFieldNamesStrategy = redactFieldNameForTest; + options.redactIdentifiers = true; + options.identifierRedactionPolicy = redactFieldNameForTest; auto expCtx = make_intrusive(); VariablesParseState vps = expCtx->variablesParseState; diff --git a/src/mongo/db/pipeline/aggregation_context_fixture.h b/src/mongo/db/pipeline/aggregation_context_fixture.h index 8ca80386393..17a921970b6 100644 --- a/src/mongo/db/pipeline/aggregation_context_fixture.h +++ b/src/mongo/db/pipeline/aggregation_context_fixture.h @@ -81,10 +81,10 @@ public: SerializationOptions options; if (performRedaction) { options.replacementForLiteralArgs = "?"; - options.redactFieldNamesStrategy = [](StringData s) -> std::string { + options.identifierRedactionPolicy = [](StringData s) -> std::string { return str::stream() << "HASH<" << s << ">"; }; - options.redactFieldNames = true; + options.redactIdentifiers = true; } std::vector serialized; docSource.serializeToArray(serialized, options); diff --git a/src/mongo/db/pipeline/document_source_bucket_auto.cpp b/src/mongo/db/pipeline/document_source_bucket_auto.cpp index 80bf8034b5f..599d1d54a36 100644 --- a/src/mongo/db/pipeline/document_source_bucket_auto.cpp +++ b/src/mongo/db/pipeline/document_source_bucket_auto.cpp @@ -393,8 +393,9 @@ Value DocumentSourceBucketAuto::serialize(SerializationOptions opts) const { MutableDocument outputSpec(_accumulatedFields.size()); for (auto&& accumulatedField : _accumulatedFields) { intrusive_ptr accum = accumulatedField.makeAccumulator(); - outputSpec[opts.serializeFieldName(accumulatedField.fieldName)] = Value(accum->serialize( - accumulatedField.expr.initializer, accumulatedField.expr.argument, opts)); + outputSpec[opts.serializeFieldPathFromString(accumulatedField.fieldName)] = + Value(accum->serialize( + accumulatedField.expr.initializer, accumulatedField.expr.argument, opts)); } insides["output"] = outputSpec.freezeToValue(); diff --git a/src/mongo/db/pipeline/document_source_change_stream_oplog_match.cpp b/src/mongo/db/pipeline/document_source_change_stream_oplog_match.cpp index db46615ce3a..8302bc3bc2a 100644 --- a/src/mongo/db/pipeline/document_source_change_stream_oplog_match.cpp +++ b/src/mongo/db/pipeline/document_source_change_stream_oplog_match.cpp @@ -214,7 +214,7 @@ Value DocumentSourceChangeStreamOplogMatch::serialize(SerializationOptions opts) sub.done(); } else { BSONObjBuilder sub(builder.subobjStart(kStageName)); - if (opts.replacementForLiteralArgs || opts.redactFieldNames) { + if (opts.replacementForLiteralArgs || opts.redactIdentifiers) { sub.append(DocumentSourceChangeStreamOplogMatchSpec::kFilterFieldName, getMatchExpression()->serialize(opts)); } else { diff --git a/src/mongo/db/pipeline/document_source_change_stream_unwind_transaction.cpp b/src/mongo/db/pipeline/document_source_change_stream_unwind_transaction.cpp index e0dfedd0529..0c4263238dc 100644 --- a/src/mongo/db/pipeline/document_source_change_stream_unwind_transaction.cpp +++ b/src/mongo/db/pipeline/document_source_change_stream_unwind_transaction.cpp @@ -141,7 +141,7 @@ Value DocumentSourceChangeStreamUnwindTransaction::serialize(SerializationOption } Value spec; - if (opts.replacementForLiteralArgs || opts.redactFieldNames) { + if (opts.replacementForLiteralArgs || opts.redactIdentifiers) { spec = Value(DOC(DocumentSourceChangeStreamUnwindTransactionSpec::kFilterFieldName << _expression->serialize(opts))); } else { diff --git a/src/mongo/db/pipeline/document_source_coll_stats.cpp b/src/mongo/db/pipeline/document_source_coll_stats.cpp index b771cf08433..6e8efcca9aa 100644 --- a/src/mongo/db/pipeline/document_source_coll_stats.cpp +++ b/src/mongo/db/pipeline/document_source_coll_stats.cpp @@ -129,7 +129,7 @@ DocumentSource::GetNextResult DocumentSourceCollStats::doGetNext() { } Value DocumentSourceCollStats::serialize(SerializationOptions opts) const { - if (opts.redactFieldNames || opts.replacementForLiteralArgs) { + if (opts.redactIdentifiers || opts.replacementForLiteralArgs) { MONGO_UNIMPLEMENTED_TASSERT(7484352); } return Value(Document{{getSourceName(), _collStatsSpec.toBSON()}}); diff --git a/src/mongo/db/pipeline/document_source_cursor.cpp b/src/mongo/db/pipeline/document_source_cursor.cpp index 520e999c10a..f01f2e0d347 100644 --- a/src/mongo/db/pipeline/document_source_cursor.cpp +++ b/src/mongo/db/pipeline/document_source_cursor.cpp @@ -210,7 +210,7 @@ void DocumentSourceCursor::recordPlanSummaryStats() { Value DocumentSourceCursor::serialize(SerializationOptions opts) const { auto verbosity = opts.verbosity; - if (opts.redactFieldNames || opts.replacementForLiteralArgs) { + if (opts.redactIdentifiers || opts.replacementForLiteralArgs) { MONGO_UNIMPLEMENTED_TASSERT(7484350); } // We never parse a DocumentSourceCursor, so we only serialize for explain. diff --git a/src/mongo/db/pipeline/document_source_densify.cpp b/src/mongo/db/pipeline/document_source_densify.cpp index a24ca77793d..f035cff11f7 100644 --- a/src/mongo/db/pipeline/document_source_densify.cpp +++ b/src/mongo/db/pipeline/document_source_densify.cpp @@ -635,13 +635,12 @@ boost::intrusive_ptr DocumentSourceInternalDensify::createFromBs Value DocumentSourceInternalDensify::serialize(SerializationOptions opts) const { MutableDocument spec; - spec[kFieldFieldName] = Value(opts.serializeFieldName(_field.fullPath())); + spec[kFieldFieldName] = Value(opts.serializeFieldPath(_field)); std::vector serializedPartitionByFields(_partitions.size()); - std::transform( - _partitions.begin(), - _partitions.end(), - serializedPartitionByFields.begin(), - [&](FieldPath field) -> Value { return Value(opts.serializeFieldName(field.fullPath())); }); + std::transform(_partitions.begin(), + _partitions.end(), + serializedPartitionByFields.begin(), + [&](FieldPath field) -> Value { return Value(opts.serializeFieldPath(field)); }); spec[kPartitionByFieldsFieldName] = Value(serializedPartitionByFields); spec[kRangeFieldName] = _range.serialize(opts); MutableDocument out; diff --git a/src/mongo/db/pipeline/document_source_densify_test.cpp b/src/mongo/db/pipeline/document_source_densify_test.cpp index 3a960afe02d..38290d12504 100644 --- a/src/mongo/db/pipeline/document_source_densify_test.cpp +++ b/src/mongo/db/pipeline/document_source_densify_test.cpp @@ -1320,7 +1320,7 @@ TEST_F(DensifyRedactionTest, RedactionFullBoundsWithPartitionFields) { auto spec = fromjson(R"({ $densify: { field: "foo", - partitionByFields: ["a", "b", "c"], + partitionByFields: ["a", "b", "c.d"], range: { bounds: "full", step: 100 @@ -1336,7 +1336,7 @@ TEST_F(DensifyRedactionTest, RedactionFullBoundsWithPartitionFields) { "partitionByFields": [ "HASH", "HASH", - "HASH" + "HASH.HASH" ], "range": { "step": "?", diff --git a/src/mongo/db/pipeline/document_source_exchange.cpp b/src/mongo/db/pipeline/document_source_exchange.cpp index dd23d00b94f..2d6999f4a7d 100644 --- a/src/mongo/db/pipeline/document_source_exchange.cpp +++ b/src/mongo/db/pipeline/document_source_exchange.cpp @@ -94,7 +94,7 @@ const char* DocumentSourceExchange::getSourceName() const { } Value DocumentSourceExchange::serialize(SerializationOptions opts) const { - if (opts.redactFieldNames || opts.replacementForLiteralArgs) { + if (opts.redactIdentifiers || opts.replacementForLiteralArgs) { MONGO_UNIMPLEMENTED_TASSERT(7484348); } return Value(DOC(getSourceName() << _exchange->getSpec().toBSON())); diff --git a/src/mongo/db/pipeline/document_source_facet.cpp b/src/mongo/db/pipeline/document_source_facet.cpp index f16b4c9be03..be3dfc3b646 100644 --- a/src/mongo/db/pipeline/document_source_facet.cpp +++ b/src/mongo/db/pipeline/document_source_facet.cpp @@ -186,7 +186,7 @@ DocumentSource::GetNextResult DocumentSourceFacet::doGetNext() { } Value DocumentSourceFacet::serialize(SerializationOptions opts) const { - if (opts.redactFieldNames || opts.replacementForLiteralArgs) { + if (opts.redactIdentifiers || opts.replacementForLiteralArgs) { MONGO_UNIMPLEMENTED_TASSERT(7484347); } diff --git a/src/mongo/db/pipeline/document_source_geo_near.cpp b/src/mongo/db/pipeline/document_source_geo_near.cpp index 912bc29a6b4..5e966e09cd5 100644 --- a/src/mongo/db/pipeline/document_source_geo_near.cpp +++ b/src/mongo/db/pipeline/document_source_geo_near.cpp @@ -64,7 +64,7 @@ Value DocumentSourceGeoNear::serialize(SerializationOptions opts) const { MutableDocument result; if (keyFieldPath) { - result.setField(kKeyFieldName, Value(keyFieldPath->redactedFullPath(opts))); + result.setField(kKeyFieldName, Value(opts.serializeFieldPath(*keyFieldPath))); } auto nearValue = [&]() -> Value { @@ -76,7 +76,7 @@ Value DocumentSourceGeoNear::serialize(SerializationOptions opts) const { } }(); result.setField("near", nearValue); - result.setField("distanceField", Value(distanceField->redactedFullPath(opts))); + result.setField("distanceField", Value(opts.serializeFieldPath(*distanceField))); if (maxDistance) { result.setField("maxDistance", opts.serializeLiteralValue(*maxDistance)); @@ -86,7 +86,7 @@ Value DocumentSourceGeoNear::serialize(SerializationOptions opts) const { result.setField("minDistance", opts.serializeLiteralValue(*minDistance)); } - if (opts.redactFieldNames || opts.replacementForLiteralArgs) { + if (opts.redactIdentifiers || opts.replacementForLiteralArgs) { auto matchExpr = uassertStatusOK(MatchExpressionParser::parse(query, pExpCtx)); result.setField("query", Value(matchExpr->serialize(opts))); } else { @@ -98,7 +98,7 @@ Value DocumentSourceGeoNear::serialize(SerializationOptions opts) const { } if (includeLocs) - result.setField("includeLocs", Value(includeLocs->redactedFullPath(opts))); + result.setField("includeLocs", Value(opts.serializeFieldPath(*includeLocs))); return Value(DOC(getSourceName() << result.freeze())); } diff --git a/src/mongo/db/pipeline/document_source_graph_lookup.cpp b/src/mongo/db/pipeline/document_source_graph_lookup.cpp index 244939c2d61..fb160a019a6 100644 --- a/src/mongo/db/pipeline/document_source_graph_lookup.cpp +++ b/src/mongo/db/pipeline/document_source_graph_lookup.cpp @@ -584,7 +584,7 @@ void DocumentSourceGraphLookUp::checkMemoryUsage() { void DocumentSourceGraphLookUp::serializeToArray(std::vector& array, SerializationOptions opts) const { auto explain = opts.verbosity; - if (opts.redactFieldNames || opts.replacementForLiteralArgs) { + if (opts.redactIdentifiers || opts.replacementForLiteralArgs) { MONGO_UNIMPLEMENTED_TASSERT(7484344); } diff --git a/src/mongo/db/pipeline/document_source_group_base.cpp b/src/mongo/db/pipeline/document_source_group_base.cpp index befa8986626..71c75eb00ac 100644 --- a/src/mongo/db/pipeline/document_source_group_base.cpp +++ b/src/mongo/db/pipeline/document_source_group_base.cpp @@ -99,7 +99,8 @@ Value DocumentSourceGroupBase::serialize(SerializationOptions opts) const { invariant(_idExpressions.size() == _idFieldNames.size()); MutableDocument md; for (size_t i = 0; i < _idExpressions.size(); i++) { - md[opts.serializeFieldName(_idFieldNames[i])] = _idExpressions[i]->serialize(opts); + md[opts.serializeFieldPathFromString(_idFieldNames[i])] = + _idExpressions[i]->serialize(opts); } insides["_id"] = md.freezeToValue(); } @@ -107,8 +108,9 @@ Value DocumentSourceGroupBase::serialize(SerializationOptions opts) const { // Add the remaining fields. for (auto&& accumulatedField : _accumulatedFields) { intrusive_ptr accum = accumulatedField.makeAccumulator(); - insides[opts.serializeFieldName(accumulatedField.fieldName)] = Value(accum->serialize( - accumulatedField.expr.initializer, accumulatedField.expr.argument, opts)); + insides[opts.serializeFieldPathFromString(accumulatedField.fieldName)] = + Value(accum->serialize( + accumulatedField.expr.initializer, accumulatedField.expr.argument, opts)); } if (_doingMerge) { @@ -124,7 +126,7 @@ Value DocumentSourceGroupBase::serialize(SerializationOptions opts) const { MutableDocument md; for (size_t i = 0; i < _accumulatedFields.size(); i++) { - md[opts.serializeFieldName(_accumulatedFields[i].fieldName)] = + md[opts.serializeFieldPathFromString(_accumulatedFields[i].fieldName)] = opts.serializeLiteralValue(static_cast( _memoryTracker[_accumulatedFields[i].fieldName].maxMemoryBytes())); } diff --git a/src/mongo/db/pipeline/document_source_index_stats.cpp b/src/mongo/db/pipeline/document_source_index_stats.cpp index d8e07355efa..f730ff9eb02 100644 --- a/src/mongo/db/pipeline/document_source_index_stats.cpp +++ b/src/mongo/db/pipeline/document_source_index_stats.cpp @@ -79,7 +79,7 @@ intrusive_ptr DocumentSourceIndexStats::createFromBson( } Value DocumentSourceIndexStats::serialize(SerializationOptions opts) const { - if (opts.redactFieldNames || opts.replacementForLiteralArgs) { + if (opts.redactIdentifiers || opts.replacementForLiteralArgs) { MONGO_UNIMPLEMENTED_TASSERT(7484342); } return Value(DOC(getSourceName() << Document())); diff --git a/src/mongo/db/pipeline/document_source_internal_all_collection_stats.cpp b/src/mongo/db/pipeline/document_source_internal_all_collection_stats.cpp index 27f74f41025..5eb4e7625aa 100644 --- a/src/mongo/db/pipeline/document_source_internal_all_collection_stats.cpp +++ b/src/mongo/db/pipeline/document_source_internal_all_collection_stats.cpp @@ -129,7 +129,7 @@ Pipeline::SourceContainer::iterator DocumentSourceInternalAllCollectionStats::do void DocumentSourceInternalAllCollectionStats::serializeToArray(std::vector& array, SerializationOptions opts) const { auto explain = opts.verbosity; - if (opts.redactFieldNames || opts.replacementForLiteralArgs) { + if (opts.redactIdentifiers || opts.replacementForLiteralArgs) { MONGO_UNIMPLEMENTED_TASSERT(7484341); } if (explain) { @@ -170,7 +170,7 @@ const char* DocumentSourceInternalAllCollectionStats::getSourceName() const { } Value DocumentSourceInternalAllCollectionStats::serialize(SerializationOptions opts) const { - if (opts.redactFieldNames || opts.replacementForLiteralArgs) { + if (opts.redactIdentifiers || opts.replacementForLiteralArgs) { MONGO_UNIMPLEMENTED_TASSERT(7484340); } return Value(Document{{getSourceName(), _internalAllCollectionStatsSpec.toBSON()}}); diff --git a/src/mongo/db/pipeline/document_source_internal_compute_geo_near_distance.cpp b/src/mongo/db/pipeline/document_source_internal_compute_geo_near_distance.cpp index cb5d89b632f..65681cdca94 100644 --- a/src/mongo/db/pipeline/document_source_internal_compute_geo_near_distance.cpp +++ b/src/mongo/db/pipeline/document_source_internal_compute_geo_near_distance.cpp @@ -142,14 +142,13 @@ DocumentSource::GetNextResult DocumentSourceInternalGeoNearDistance::doGetNext() } Value DocumentSourceInternalGeoNearDistance::serialize(SerializationOptions opts) const { - MutableDocument out; out.setField(DocumentSourceInternalGeoNearDistance::kNearFieldName, opts.serializeLiteralValue(_coords)); out.setField(DocumentSourceInternalGeoNearDistance::kKeyFieldName, - Value(opts.serializeFieldName(_key))); + Value(opts.serializeFieldPathFromString(_key))); out.setField(DocumentSourceInternalGeoNearDistance::kDistanceFieldFieldName, - Value(opts.serializeFieldName(_distanceField.fullPath()))); + Value(opts.serializeFieldPath(_distanceField))); out.setField(DocumentSourceInternalGeoNearDistance::kDistanceMultiplierFieldName, opts.serializeLiteralValue(_distanceMultiplier)); diff --git a/src/mongo/db/pipeline/document_source_internal_convert_bucket_index_stats.cpp b/src/mongo/db/pipeline/document_source_internal_convert_bucket_index_stats.cpp index 4a53382a23d..6f4e0e58ea6 100644 --- a/src/mongo/db/pipeline/document_source_internal_convert_bucket_index_stats.cpp +++ b/src/mongo/db/pipeline/document_source_internal_convert_bucket_index_stats.cpp @@ -146,7 +146,7 @@ boost::intrusive_ptr DocumentSourceInternalConvertBucketIndexSta } Value DocumentSourceInternalConvertBucketIndexStats::serialize(SerializationOptions opts) const { - if (opts.redactFieldNames || opts.replacementForLiteralArgs) { + if (opts.redactIdentifiers || opts.replacementForLiteralArgs) { MONGO_UNIMPLEMENTED_TASSERT(7484337); } diff --git a/src/mongo/db/pipeline/document_source_internal_unpack_bucket.cpp b/src/mongo/db/pipeline/document_source_internal_unpack_bucket.cpp index d05ae51d35b..d338b88bedb 100644 --- a/src/mongo/db/pipeline/document_source_internal_unpack_bucket.cpp +++ b/src/mongo/db/pipeline/document_source_internal_unpack_bucket.cpp @@ -489,7 +489,7 @@ void DocumentSourceInternalUnpackBucket::serializeToArray(std::vector& ar const auto& spec = _bucketUnpacker.bucketSpec(); std::vector fields; for (auto&& field : spec.fieldSet()) { - fields.emplace_back(opts.serializeFieldName(field)); + fields.emplace_back(opts.serializeFieldPathFromString(field)); } if (((_bucketUnpacker.includeMetaField() && _bucketUnpacker.behavior() == BucketSpec::Behavior::kInclude) || @@ -498,12 +498,14 @@ void DocumentSourceInternalUnpackBucket::serializeToArray(std::vector& ar std::find(spec.computedMetaProjFields().cbegin(), spec.computedMetaProjFields().cend(), *spec.metaField()) == spec.computedMetaProjFields().cend()) - fields.emplace_back(opts.serializeFieldName(*spec.metaField())); + fields.emplace_back(opts.serializeFieldPathFromString(*spec.metaField())); out.addField(behavior, Value{std::move(fields)}); - out.addField(timeseries::kTimeFieldName, Value{opts.serializeFieldName(spec.timeField())}); + out.addField(timeseries::kTimeFieldName, + Value{opts.serializeFieldPathFromString(spec.timeField())}); if (spec.metaField()) { - out.addField(timeseries::kMetaFieldName, Value{opts.serializeFieldName(*spec.metaField())}); + out.addField(timeseries::kMetaFieldName, + Value{opts.serializeFieldPathFromString(*spec.metaField())}); } out.addField(kBucketMaxSpanSeconds, opts.serializeLiteralValue(Value{_bucketMaxSpanSeconds})); if (_assumeNoMixedSchemaData) @@ -525,7 +527,8 @@ void DocumentSourceInternalUnpackBucket::serializeToArray(std::vector& ar spec.computedMetaProjFields().cend(), std::back_inserter(compFields), [opts](auto&& projString) { - return Value{opts.serializeFieldName(projString)}; + return Value{ + opts.serializeFieldPathFromString(projString)}; }); return compFields; }()}); diff --git a/src/mongo/db/pipeline/document_source_internal_unpack_bucket_test/unpack_bucket_exec_test.cpp b/src/mongo/db/pipeline/document_source_internal_unpack_bucket_test/unpack_bucket_exec_test.cpp index 3dd4d527acc..8ca1f6ec75d 100644 --- a/src/mongo/db/pipeline/document_source_internal_unpack_bucket_test/unpack_bucket_exec_test.cpp +++ b/src/mongo/db/pipeline/document_source_internal_unpack_bucket_test/unpack_bucket_exec_test.cpp @@ -936,8 +936,8 @@ TEST_F(InternalUnpackBucketExecTest, RedactsCorrectly) { "bucketMaxSpanSeconds: 3600, computedMetaProjFields: ['a', 'b', 'c']}}"); auto array = std::vector{}; SerializationOptions opts; - opts.redactFieldNamesStrategy = redactFieldNameForTest; - opts.redactFieldNames = true; + opts.identifierRedactionPolicy = redactFieldNameForTest; + opts.redactIdentifiers = true; opts.replacementForLiteralArgs = "?"; DocumentSourceInternalUnpackBucket::createFromBsonInternal(bson.firstElement(), getExpCtx()) ->serializeToArray(array, opts); diff --git a/src/mongo/db/pipeline/document_source_list_cached_and_active_users.h b/src/mongo/db/pipeline/document_source_list_cached_and_active_users.h index a9a31707a77..d86611ac874 100644 --- a/src/mongo/db/pipeline/document_source_list_cached_and_active_users.h +++ b/src/mongo/db/pipeline/document_source_list_cached_and_active_users.h @@ -88,7 +88,7 @@ public: } Value serialize(SerializationOptions opts = SerializationOptions()) const final override { - if (opts.redactFieldNames || opts.replacementForLiteralArgs) { + if (opts.redactIdentifiers || opts.replacementForLiteralArgs) { MONGO_UNIMPLEMENTED_TASSERT(7484330); } return Value(Document{{getSourceName(), Document{}}}); diff --git a/src/mongo/db/pipeline/document_source_list_local_sessions.h b/src/mongo/db/pipeline/document_source_list_local_sessions.h index d3c8c47d127..1244c2fa0ff 100644 --- a/src/mongo/db/pipeline/document_source_list_local_sessions.h +++ b/src/mongo/db/pipeline/document_source_list_local_sessions.h @@ -102,7 +102,7 @@ public: } Value serialize(SerializationOptions opts = SerializationOptions()) const final override { - if (opts.redactFieldNames || opts.replacementForLiteralArgs) { + if (opts.redactIdentifiers || opts.replacementForLiteralArgs) { MONGO_UNIMPLEMENTED_TASSERT(7484328); } return Value(Document{{getSourceName(), _spec.toBSON()}}); diff --git a/src/mongo/db/pipeline/document_source_list_sessions.cpp b/src/mongo/db/pipeline/document_source_list_sessions.cpp index e1f2ea650a3..2370d5d324a 100644 --- a/src/mongo/db/pipeline/document_source_list_sessions.cpp +++ b/src/mongo/db/pipeline/document_source_list_sessions.cpp @@ -75,7 +75,7 @@ boost::intrusive_ptr DocumentSourceListSessions::createFromBson( } Value DocumentSourceListSessions::serialize(SerializationOptions opts) const { - if (opts.redactFieldNames || opts.replacementForLiteralArgs) { + if (opts.redactIdentifiers || opts.replacementForLiteralArgs) { MONGO_UNIMPLEMENTED_TASSERT(7484327); } ListSessionsSpec spec; diff --git a/src/mongo/db/pipeline/document_source_lookup.cpp b/src/mongo/db/pipeline/document_source_lookup.cpp index 976ce9c78e5..ef96a3a83ec 100644 --- a/src/mongo/db/pipeline/document_source_lookup.cpp +++ b/src/mongo/db/pipeline/document_source_lookup.cpp @@ -1024,7 +1024,7 @@ void DocumentSourceLookUp::appendSpecificExecStats(MutableDocument& doc) const { void DocumentSourceLookUp::serializeToArray(std::vector& array, SerializationOptions opts) const { auto explain = opts.verbosity; - if (opts.redactFieldNames || opts.replacementForLiteralArgs) { + if (opts.redactIdentifiers || opts.replacementForLiteralArgs) { MONGO_UNIMPLEMENTED_TASSERT(7484326); } diff --git a/src/mongo/db/pipeline/document_source_match.cpp b/src/mongo/db/pipeline/document_source_match.cpp index 8e5bb956a0b..8856a1def3b 100644 --- a/src/mongo/db/pipeline/document_source_match.cpp +++ b/src/mongo/db/pipeline/document_source_match.cpp @@ -69,7 +69,7 @@ const char* DocumentSourceMatch::getSourceName() const { } Value DocumentSourceMatch::serialize(SerializationOptions opts) const { - if (opts.verbosity || opts.redactFieldNames || opts.replacementForLiteralArgs) { + if (opts.verbosity || opts.redactIdentifiers || opts.replacementForLiteralArgs) { return Value(DOC(getSourceName() << Document(_expression->serialize(opts)))); } return Value(DOC(getSourceName() << Document(getQuery()))); diff --git a/src/mongo/db/pipeline/document_source_match_test.cpp b/src/mongo/db/pipeline/document_source_match_test.cpp index 718a2a565f6..e699537521d 100644 --- a/src/mongo/db/pipeline/document_source_match_test.cpp +++ b/src/mongo/db/pipeline/document_source_match_test.cpp @@ -708,10 +708,10 @@ TEST_F(DocumentSourceMatchTest, RedactionWithAnd) { $match: { $and: [ { - a: 'abc' + "a.c": "abc" }, { - b: { + "b": { $gt: 10 } } @@ -723,7 +723,7 @@ TEST_F(DocumentSourceMatchTest, RedactionWithAnd) { "$match": { "$and": [ { - "HASH": { + "HASH.HASH": { "$eq": "?" } }, diff --git a/src/mongo/db/pipeline/document_source_merge.cpp b/src/mongo/db/pipeline/document_source_merge.cpp index 00b033a5b34..d21c8392324 100644 --- a/src/mongo/db/pipeline/document_source_merge.cpp +++ b/src/mongo/db/pipeline/document_source_merge.cpp @@ -534,7 +534,7 @@ boost::optional DocumentSourceMerge::distr Value DocumentSourceMerge::serialize(SerializationOptions opts) const { auto explain = opts.verbosity; - if (opts.redactFieldNames || opts.replacementForLiteralArgs) { + if (opts.redactIdentifiers || opts.replacementForLiteralArgs) { MONGO_UNIMPLEMENTED_TASSERT(7484324); } diff --git a/src/mongo/db/pipeline/document_source_out.cpp b/src/mongo/db/pipeline/document_source_out.cpp index 772e3c95ed3..113ce0b77cb 100644 --- a/src/mongo/db/pipeline/document_source_out.cpp +++ b/src/mongo/db/pipeline/document_source_out.cpp @@ -214,8 +214,8 @@ boost::intrusive_ptr DocumentSourceOut::createFromBson( Value DocumentSourceOut::serialize(SerializationOptions opts) const { MutableDocument spec; // Do not include the tenantId in the serialized 'outputNs'. - spec["db"] = Value(opts.serializeFieldName(_outputNs.dbName().db())); - spec["coll"] = Value(opts.serializeFieldName(_outputNs.coll())); + spec["db"] = Value(opts.serializeIdentifier(_outputNs.dbName().db())); + spec["coll"] = Value(opts.serializeIdentifier(_outputNs.coll())); return Value(Document{{kStageName, spec.freezeToValue()}}); } diff --git a/src/mongo/db/pipeline/document_source_plan_cache_stats.cpp b/src/mongo/db/pipeline/document_source_plan_cache_stats.cpp index 80d16e01d72..ddfcae2457e 100644 --- a/src/mongo/db/pipeline/document_source_plan_cache_stats.cpp +++ b/src/mongo/db/pipeline/document_source_plan_cache_stats.cpp @@ -62,7 +62,7 @@ void DocumentSourcePlanCacheStats::serializeToArray(std::vector& array, if (opts.verbosity) { tassert(7513100, "$planCacheStats is not equipped to serialize in explain mode with redaction on", - !opts.redactFieldNames && !opts.replacementForLiteralArgs); + !opts.redactIdentifiers && !opts.replacementForLiteralArgs); array.push_back(Value{ Document{{kStageName, Document{{"match"_sd, diff --git a/src/mongo/db/pipeline/document_source_plan_cache_stats_test.cpp b/src/mongo/db/pipeline/document_source_plan_cache_stats_test.cpp index 126c3e90374..1c803c311d6 100644 --- a/src/mongo/db/pipeline/document_source_plan_cache_stats_test.cpp +++ b/src/mongo/db/pipeline/document_source_plan_cache_stats_test.cpp @@ -155,10 +155,10 @@ TEST_F(DocumentSourcePlanCacheStatsTest, RedactsSuccessfullyAfterAbsorbingMatch) SerializationOptions options; options.replacementForLiteralArgs = "?"; - options.redactFieldNamesStrategy = [](StringData s) -> std::string { + options.identifierRedactionPolicy = [](StringData s) -> std::string { return str::stream() << "HASH<" << s << ">"; }; - options.redactFieldNames = true; + options.redactIdentifiers = true; pipeline->optimizePipeline(); ASSERT_EQ(1u, pipeline->getSources().size()); diff --git a/src/mongo/db/pipeline/document_source_queue.cpp b/src/mongo/db/pipeline/document_source_queue.cpp index 3d3019188c1..7014a159842 100644 --- a/src/mongo/db/pipeline/document_source_queue.cpp +++ b/src/mongo/db/pipeline/document_source_queue.cpp @@ -81,7 +81,7 @@ DocumentSource::GetNextResult DocumentSourceQueue::doGetNext() { } Value DocumentSourceQueue::serialize(SerializationOptions opts) const { - if (opts.redactFieldNames || opts.replacementForLiteralArgs) { + if (opts.redactIdentifiers || opts.replacementForLiteralArgs) { MONGO_UNIMPLEMENTED_TASSERT(7484319); } diff --git a/src/mongo/db/pipeline/document_source_sequential_document_cache.cpp b/src/mongo/db/pipeline/document_source_sequential_document_cache.cpp index 5fd98a6d381..5cd3563cfe8 100644 --- a/src/mongo/db/pipeline/document_source_sequential_document_cache.cpp +++ b/src/mongo/db/pipeline/document_source_sequential_document_cache.cpp @@ -156,7 +156,7 @@ Pipeline::SourceContainer::iterator DocumentSourceSequentialDocumentCache::doOpt } Value DocumentSourceSequentialDocumentCache::serialize(SerializationOptions opts) const { - if (opts.redactFieldNames || opts.replacementForLiteralArgs) { + if (opts.redactIdentifiers || opts.replacementForLiteralArgs) { MONGO_UNIMPLEMENTED_TASSERT(7484315); } if (opts.verbosity) { diff --git a/src/mongo/db/pipeline/document_source_set_variable_from_subpipeline.cpp b/src/mongo/db/pipeline/document_source_set_variable_from_subpipeline.cpp index 010e4685a8a..bb5ccb6bf93 100644 --- a/src/mongo/db/pipeline/document_source_set_variable_from_subpipeline.cpp +++ b/src/mongo/db/pipeline/document_source_set_variable_from_subpipeline.cpp @@ -54,7 +54,7 @@ REGISTER_INTERNAL_DOCUMENT_SOURCE(setVariableFromSubPipeline, true); Value DocumentSourceSetVariableFromSubPipeline::serialize(SerializationOptions opts) const { - if (opts.redactFieldNames || opts.replacementForLiteralArgs) { + if (opts.redactIdentifiers || opts.replacementForLiteralArgs) { MONGO_UNIMPLEMENTED_TASSERT(7484314); } diff --git a/src/mongo/db/pipeline/document_source_set_window_fields.cpp b/src/mongo/db/pipeline/document_source_set_window_fields.cpp index 1b31e29d707..c06e89155c5 100644 --- a/src/mongo/db/pipeline/document_source_set_window_fields.cpp +++ b/src/mongo/db/pipeline/document_source_set_window_fields.cpp @@ -140,7 +140,7 @@ WindowFunctionStatement WindowFunctionStatement::parse(BSONElement elem, } void WindowFunctionStatement::serialize(MutableDocument& outputFields, SerializationOptions opts) const { - outputFields[opts.serializeFieldName(fieldName)] = expr->serialize(opts); + outputFields[opts.serializeFieldPathFromString(fieldName)] = expr->serialize(opts); } list> document_source_set_window_fields::create( @@ -307,7 +307,7 @@ Value DocumentSourceInternalSetWindowFields::serialize(SerializationOptions opts MutableDocument md; for (auto&& [fieldName, function] : _executableOutputs) { - md[opts.serializeFieldName(fieldName)] = opts.serializeLiteralValue( + md[opts.serializeFieldPathFromString(fieldName)] = opts.serializeLiteralValue( static_cast(_memoryTracker[fieldName].maxMemoryBytes())); } diff --git a/src/mongo/db/pipeline/document_source_set_window_fields_test.cpp b/src/mongo/db/pipeline/document_source_set_window_fields_test.cpp index 4e0dfbcc189..e6705d64e01 100644 --- a/src/mongo/db/pipeline/document_source_set_window_fields_test.cpp +++ b/src/mongo/db/pipeline/document_source_set_window_fields_test.cpp @@ -260,7 +260,7 @@ TEST_F(DocumentSourceSetWindowFieldsTest, RedactionOnExpMovingAvgOperator) { auto spec = fromjson( R"({ $setWindowFields: { - partitionBy: '$foo', + partitionBy: '$foo.bar', sortBy: { bar: 1 }, @@ -280,7 +280,7 @@ TEST_F(DocumentSourceSetWindowFieldsTest, RedactionOnExpMovingAvgOperator) { ASSERT_BSONOBJ_EQ_AUTO( // NOLINT R"({ "$_internalSetWindowFields": { - "partitionBy": "$HASH", + "partitionBy": "$HASH.HASH", "sortBy": { "HASH": 1 }, diff --git a/src/mongo/db/pipeline/document_source_single_document_transformation.cpp b/src/mongo/db/pipeline/document_source_single_document_transformation.cpp index 109e0883b52..6604fff1784 100644 --- a/src/mongo/db/pipeline/document_source_single_document_transformation.cpp +++ b/src/mongo/db/pipeline/document_source_single_document_transformation.cpp @@ -88,7 +88,7 @@ void DocumentSourceSingleDocumentTransformation::doDispose() { } Value DocumentSourceSingleDocumentTransformation::serialize(SerializationOptions opts) const { - if (opts.redactFieldNames || opts.replacementForLiteralArgs) { + if (opts.redactIdentifiers || opts.replacementForLiteralArgs) { MONGO_UNIMPLEMENTED_TASSERT(7484312); } diff --git a/src/mongo/db/pipeline/document_source_skip.cpp b/src/mongo/db/pipeline/document_source_skip.cpp index 6eda5a592f5..2d05d6695a7 100644 --- a/src/mongo/db/pipeline/document_source_skip.cpp +++ b/src/mongo/db/pipeline/document_source_skip.cpp @@ -73,7 +73,7 @@ DocumentSource::GetNextResult DocumentSourceSkip::doGetNext() { } Value DocumentSourceSkip::serialize(SerializationOptions opts) const { - if (opts.redactFieldNames || opts.replacementForLiteralArgs) { + if (opts.redactIdentifiers || opts.replacementForLiteralArgs) { MONGO_UNIMPLEMENTED_TASSERT(7484311); } diff --git a/src/mongo/db/pipeline/document_source_sort.cpp b/src/mongo/db/pipeline/document_source_sort.cpp index bc6d90b7386..7c313743662 100644 --- a/src/mongo/db/pipeline/document_source_sort.cpp +++ b/src/mongo/db/pipeline/document_source_sort.cpp @@ -284,7 +284,7 @@ boost::intrusive_ptr DocumentSourceSort::clone( void DocumentSourceSort::serializeToArray(std::vector& array, SerializationOptions opts) const { auto explain = opts.verbosity; - if (opts.redactFieldNames || opts.replacementForLiteralArgs) { + if (opts.redactIdentifiers || opts.replacementForLiteralArgs) { MONGO_UNIMPLEMENTED_TASSERT(7484310); } diff --git a/src/mongo/db/pipeline/document_source_streaming_group.cpp b/src/mongo/db/pipeline/document_source_streaming_group.cpp index 7a019b55f95..4b6dea86d22 100644 --- a/src/mongo/db/pipeline/document_source_streaming_group.cpp +++ b/src/mongo/db/pipeline/document_source_streaming_group.cpp @@ -157,10 +157,10 @@ void DocumentSourceStreamingGroup::serializeAdditionalFields(MutableDocument& ou SerializationOptions opts) const { std::vector monotonicIdFields; if (_idFieldNames.empty()) { - monotonicIdFields.emplace_back(opts.serializeFieldName("_id")); + monotonicIdFields.emplace_back(opts.serializeFieldPath("_id")); } else { for (size_t i : _monotonicExpressionIndexes) { - monotonicIdFields.emplace_back(opts.serializeFieldName(_idFieldNames[i])); + monotonicIdFields.emplace_back(opts.serializeFieldPathFromString(_idFieldNames[i])); } } out[kMonotonicIdFieldsSpecField] = Value(std::move(monotonicIdFields)); diff --git a/src/mongo/db/pipeline/document_source_telemetry.cpp b/src/mongo/db/pipeline/document_source_telemetry.cpp index f226c53982c..4d81065855f 100644 --- a/src/mongo/db/pipeline/document_source_telemetry.cpp +++ b/src/mongo/db/pipeline/document_source_telemetry.cpp @@ -49,23 +49,23 @@ bool parseTelemetryEmbeddedObject(BSONObj embeddedObj) { uassert(ErrorCodes::FailedToParse, str::stream() << DocumentSourceTelemetry::kStageName - << " parameters object may only contain one field, 'redactFieldNames'. Found: " + << " parameters object may only contain one field, 'redactIdentifiers'. Found: " << embeddedObj.toString(), embeddedObj.nFields() == 1); uassert(ErrorCodes::FailedToParse, str::stream() << DocumentSourceTelemetry::kStageName - << " parameters object may only contain 'redactFieldNames' option. Found: " + << " parameters object may only contain 'redactIdentifiers' option. Found: " << embeddedObj.firstElementFieldName(), - embeddedObj.hasField("redactFieldNames")); + embeddedObj.hasField("redactIdentifiers")); uassert(ErrorCodes::FailedToParse, str::stream() << DocumentSourceTelemetry::kStageName - << " redactFieldNames parameter must be boolean. Found type: " + << " redactIdentifiers parameter must be boolean. Found type: " << typeName(embeddedObj.firstElementType()), embeddedObj.firstElementType() == BSONType::Bool); - fieldNameRedaction = embeddedObj["redactFieldNames"].trueValue(); + fieldNameRedaction = embeddedObj["redactIdentifiers"].trueValue(); } return fieldNameRedaction; } @@ -144,7 +144,7 @@ DocumentSource::GetNextResult DocumentSourceTelemetry::doGetNext() { const auto partitionReadTime = Timestamp{Timestamp(Date_t::now().toMillisSinceEpoch() / 1000, 0)}; for (auto&& [key, metrics] : *partition) { - auto swKey = metrics->redactKey(key, _redactFieldNames, pExpCtx->opCtx); + auto swKey = metrics->redactKey(key, _redactIdentifiers, pExpCtx->opCtx); if (!swKey.isOK()) { LOGV2_DEBUG(7349403, 3, diff --git a/src/mongo/db/pipeline/document_source_telemetry.h b/src/mongo/db/pipeline/document_source_telemetry.h index befd91851de..fff298025f0 100644 --- a/src/mongo/db/pipeline/document_source_telemetry.h +++ b/src/mongo/db/pipeline/document_source_telemetry.h @@ -47,9 +47,9 @@ public: static std::unique_ptr parse(const NamespaceString& nss, const BSONElement& spec); - LiteParsed(std::string parseTimeName, bool redactFieldNames) + LiteParsed(std::string parseTimeName, bool redactIdentifiers) : LiteParsedDocumentSource(std::move(parseTimeName)), - _redactFieldNames(redactFieldNames) {} + _redactIdentifiers(redactIdentifiers) {} stdx::unordered_set getInvolvedNamespaces() const override { return stdx::unordered_set(); @@ -74,7 +74,7 @@ public: transactionNotSupported(kStageName); } - bool _redactFieldNames; + bool _redactIdentifiers; }; static boost::intrusive_ptr createFromBson( @@ -112,8 +112,8 @@ public: private: DocumentSourceTelemetry(const boost::intrusive_ptr& expCtx, - bool redactFieldNames = false) - : DocumentSource(kStageName, expCtx), _redactFieldNames(redactFieldNames) {} + bool redactIdentifiers = false) + : DocumentSource(kStageName, expCtx), _redactIdentifiers(redactIdentifiers) {} GetNextResult doGetNext() final; @@ -130,7 +130,7 @@ private: TelemetryStore::PartitionId _currentPartition = -1; // When true, redact field names from returned query shapes. - bool _redactFieldNames; + bool _redactIdentifiers; }; } // namespace mongo diff --git a/src/mongo/db/pipeline/document_source_union_with.cpp b/src/mongo/db/pipeline/document_source_union_with.cpp index 3506561f46a..fd745b37e0c 100644 --- a/src/mongo/db/pipeline/document_source_union_with.cpp +++ b/src/mongo/db/pipeline/document_source_union_with.cpp @@ -328,7 +328,7 @@ void DocumentSourceUnionWith::doDispose() { Value DocumentSourceUnionWith::serialize(SerializationOptions opts) const { auto explain = opts.verbosity; - if (opts.redactFieldNames || opts.replacementForLiteralArgs) { + if (opts.redactIdentifiers || opts.replacementForLiteralArgs) { MONGO_UNIMPLEMENTED_TASSERT(7484307); } diff --git a/src/mongo/db/pipeline/document_source_unwind.cpp b/src/mongo/db/pipeline/document_source_unwind.cpp index 8e3e6c4a602..b5ae2df4865 100644 --- a/src/mongo/db/pipeline/document_source_unwind.cpp +++ b/src/mongo/db/pipeline/document_source_unwind.cpp @@ -296,10 +296,10 @@ Pipeline::SourceContainer::iterator DocumentSourceUnwind::doOptimizeAt( Value DocumentSourceUnwind::serialize(SerializationOptions opts) const { return Value(DOC( getSourceName() << DOC( - "path" << _unwindPath.redactedFullPathWithPrefix(opts) << "preserveNullAndEmptyArrays" + "path" << opts.serializeFieldPathWithPrefix(_unwindPath) << "preserveNullAndEmptyArrays" << (_preserveNullAndEmptyArrays ? opts.serializeLiteralValue(true) : Value()) << "includeArrayIndex" - << (_indexPath ? Value((*_indexPath).redactedFullPath(opts)) : Value())))); + << (_indexPath ? Value(opts.serializeFieldPath(*_indexPath)) : Value())))); } DepsTracker::State DocumentSourceUnwind::getDependencies(DepsTracker* deps) const { diff --git a/src/mongo/db/pipeline/expression.cpp b/src/mongo/db/pipeline/expression.cpp index c239ab05d1e..7800bdec863 100644 --- a/src/mongo/db/pipeline/expression.cpp +++ b/src/mongo/db/pipeline/expression.cpp @@ -2390,7 +2390,8 @@ Value ExpressionObject::serialize(SerializationOptions options) const { } MutableDocument outputDoc; for (auto&& pair : _expressions) { - outputDoc.addField(options.serializeFieldName(pair.first), pair.second->serialize(options)); + outputDoc.addField(options.serializeFieldPathFromString(pair.first), + pair.second->serialize(options)); } return outputDoc.freezeToValue(); } @@ -2594,29 +2595,19 @@ auto getPrefixAndPath(FieldPath path) { Value ExpressionFieldPath::serialize(SerializationOptions options) const { auto [prefix, path] = getPrefixAndPath(_fieldPath); - if (options.redactFieldNames) { - // This is a variable. - if (prefix.length() == 2) { - if (path.getPathLength() == 1 && Variables::isBuiltin(_variable)) { - // Nothing to redact. - return Value(prefix + path.fullPath()); - } else if (path.getPathLength() == 1) { - // This may be a variable or a field path, but either way it needs to be redacted. - return Value(prefix + path.redactedFullPath(options)); - } else if (path.getPathLength() > 1 && Variables::isBuiltin(_variable)) { - // The first component of this path is a system variable, so keep that and redact - // the rest. - return Value(prefix + path.front() + "." + path.tail().redactedFullPath(options)); - } else { - // This path has multiple components, and each part is from the user. Redact every - // component. - return Value(prefix + path.redactedFullPath(options)); - } + // First handles special cases for redaction of system variables. User variables will fall + // through to the default full redaction case. + if (options.redactIdentifiers && prefix.length() == 2) { + if (path.getPathLength() == 1 && Variables::isBuiltin(_variable)) { + // Nothing to redact for builtin variables. + return Value(prefix + path.fullPath()); + } else if (path.getPathLength() > 1 && Variables::isBuiltin(_variable)) { + // The first component of this path is a system variable, so keep that and redact + // the rest. + return Value(prefix + path.front() + "." + options.serializeFieldPath(path.tail())); } - return Value(path.redactedFullPathWithPrefix(options)); - } else { - return Value(prefix + path.fullPath()); } + return Value(prefix + options.serializeFieldPath(path)); } Expression::ComputedPaths ExpressionFieldPath::getComputedPaths(const std::string& exprFieldPath, @@ -2954,8 +2945,8 @@ Value ExpressionLet::serialize(SerializationOptions options) const { for (VariableMap::const_iterator it = _variables.begin(), end = _variables.end(); it != end; ++it) { auto key = it->second.name; - if (options.redactFieldNames) { - key = options.redactFieldNamesStrategy(key); + if (options.redactIdentifiers) { + key = options.identifierRedactionPolicy(key); } vars[key] = it->second.expression->serialize(options); } @@ -8138,13 +8129,12 @@ intrusive_ptr ExpressionGetField::optimize() { Value ExpressionGetField::serialize(SerializationOptions options) const { MutableDocument argDoc; - if (options.redactFieldNames) { + if (options.redactIdentifiers) { // The parser guarantees that the '_children[_kField]' expression evaluates to a constant // string. auto strPath = static_cast(_children[_kField].get())->getValue().getString(); - FieldPath fp(strPath); - argDoc.addField("field"_sd, Value(fp.redactedFullPath(options))); + argDoc.addField("field"_sd, Value(options.serializeFieldPathFromString(strPath))); } else { argDoc.addField("field"_sd, _children[_kField]->serialize(options)); } @@ -8262,13 +8252,12 @@ intrusive_ptr ExpressionSetField::optimize() { Value ExpressionSetField::serialize(SerializationOptions options) const { MutableDocument argDoc; - if (options.redactFieldNames) { + if (options.redactIdentifiers) { // The parser guarantees that the '_children[_kField]' expression evaluates to a constant // string. auto strPath = static_cast(_children[_kField].get())->getValue().getString(); - FieldPath fp(strPath); - argDoc.addField("field"_sd, Value(fp.redactedFullPath(options))); + argDoc.addField("field"_sd, Value(options.serializeFieldPathFromString(strPath))); } else { argDoc.addField("field"_sd, _children[_kField]->serialize(options)); } diff --git a/src/mongo/db/pipeline/expression_field_path_test.cpp b/src/mongo/db/pipeline/expression_field_path_test.cpp index 4fba45c34a2..4b332d9e4f4 100644 --- a/src/mongo/db/pipeline/expression_field_path_test.cpp +++ b/src/mongo/db/pipeline/expression_field_path_test.cpp @@ -233,8 +233,8 @@ TEST(FieldPath, ScalarVariableWithDottedFieldPathOptimizesToConstantMissingValue TEST(FieldPath, SerializeWithRedaction) { SerializationOptions options; - options.redactFieldNamesStrategy = redactFieldNameForTest; - options.redactFieldNames = true; + options.identifierRedactionPolicy = redactFieldNameForTest; + options.redactIdentifiers = true; auto expCtx = ExpressionContextForTest{}; intrusive_ptr expression = diff --git a/src/mongo/db/pipeline/expression_function_test.cpp b/src/mongo/db/pipeline/expression_function_test.cpp index d5bd70397b8..640804b55b4 100644 --- a/src/mongo/db/pipeline/expression_function_test.cpp +++ b/src/mongo/db/pipeline/expression_function_test.cpp @@ -50,8 +50,8 @@ TEST(ExpressionFunction, SerializeAndRedactArgs) { SerializationOptions options; std::string replacementChar = "?"; options.replacementForLiteralArgs = replacementChar; - options.redactFieldNames = true; - options.redactFieldNamesStrategy = redactFieldNameForTest; + options.redactIdentifiers = true; + options.identifierRedactionPolicy = redactFieldNameForTest; auto expCtx = ExpressionContextForTest(); auto expr = BSON("$function" << BSON("body" diff --git a/src/mongo/db/pipeline/expression_let_test.cpp b/src/mongo/db/pipeline/expression_let_test.cpp index 75d6ee09ac0..fe4e1291fc5 100644 --- a/src/mongo/db/pipeline/expression_let_test.cpp +++ b/src/mongo/db/pipeline/expression_let_test.cpp @@ -44,8 +44,8 @@ std::string redactFieldNameForTest(StringData s) { TEST(RedactionTest, ExpressionLet) { SerializationOptions options; - options.redactFieldNamesStrategy = redactFieldNameForTest; - options.redactFieldNames = true; + options.identifierRedactionPolicy = redactFieldNameForTest; + options.redactIdentifiers = true; auto expCtx = ExpressionContextForTest{}; diff --git a/src/mongo/db/pipeline/expression_test.cpp b/src/mongo/db/pipeline/expression_test.cpp index 04cc5c22ebf..ba1cf96b27c 100644 --- a/src/mongo/db/pipeline/expression_test.cpp +++ b/src/mongo/db/pipeline/expression_test.cpp @@ -3731,8 +3731,8 @@ TEST(ExpressionGetFieldTest, GetFieldSerializesAndRedactsCorrectly) { SerializationOptions options; std::string replacementChar = "?"; options.replacementForLiteralArgs = replacementChar; - options.redactFieldNamesStrategy = redactFieldNameForTest; - options.redactFieldNames = true; + options.identifierRedactionPolicy = redactFieldNameForTest; + options.redactIdentifiers = true; auto expCtx = ExpressionContextForTest{}; VariablesParseState vps = expCtx.variablesParseState; @@ -3776,8 +3776,8 @@ TEST(ExpressionSetFieldTest, SetFieldRedactsCorrectly) { SerializationOptions options; std::string replacementChar = "?"; options.replacementForLiteralArgs = replacementChar; - options.redactFieldNamesStrategy = redactFieldNameForTest; - options.redactFieldNames = true; + options.identifierRedactionPolicy = redactFieldNameForTest; + options.redactIdentifiers = true; auto expCtx = ExpressionContextForTest{}; VariablesParseState vps = expCtx.variablesParseState; diff --git a/src/mongo/db/pipeline/field_path.cpp b/src/mongo/db/pipeline/field_path.cpp index 7f2fb3cd5ea..9a0a53f61fc 100644 --- a/src/mongo/db/pipeline/field_path.cpp +++ b/src/mongo/db/pipeline/field_path.cpp @@ -164,18 +164,4 @@ FieldPath FieldPath::concat(const FieldPath& tail) const { return FieldPath(std::move(concat), std::move(newDots), std::move(newHashes)); } - -std::string FieldPath::redactedFullPath(SerializationOptions opts) const { - if (!opts.redactFieldNames) { - return fullPath(); - } - std::stringstream redacted; - for (size_t i = 0; i < getPathLength(); ++i) { - if (i > 0) { - redacted << "."; - } - redacted << opts.redactFieldNamesStrategy(getFieldName(i)); - } - return redacted.str(); -} } // namespace mongo diff --git a/src/mongo/db/pipeline/field_path.h b/src/mongo/db/pipeline/field_path.h index e185a7d7601..60792a5e2d2 100644 --- a/src/mongo/db/pipeline/field_path.h +++ b/src/mongo/db/pipeline/field_path.h @@ -36,7 +36,6 @@ #include "mongo/base/string_data.h" #include "mongo/bson/bson_depth.h" #include "mongo/db/exec/document_value/document_internal.h" -#include "mongo/db/query/serialization_options.h" #include "mongo/util/assert_util.h" namespace mongo { @@ -130,7 +129,6 @@ public: const std::string& fullPath() const { return _fieldPath; } - std::string redactedFullPath(SerializationOptions opts) const; /** * Returns the full path, including the prefix 'FieldPath::prefix'. @@ -138,9 +136,6 @@ public: std::string fullPathWithPrefix() const { return prefix + _fieldPath; } - std::string redactedFullPathWithPrefix(SerializationOptions opts) const { - return prefix + redactedFullPath(opts); - } /** * A FieldPath like this but missing the first element (useful for recursion). diff --git a/src/mongo/db/query/projection_ast_test.cpp b/src/mongo/db/query/projection_ast_test.cpp index 16e7e7463b0..13959074151 100644 --- a/src/mongo/db/query/projection_ast_test.cpp +++ b/src/mongo/db/query/projection_ast_test.cpp @@ -780,8 +780,8 @@ std::string redactFieldNameForTest(StringData s) { TEST_F(ProjectionASTTest, TestASTRedaction) { SerializationOptions options; options.replacementForLiteralArgs = "?"; - options.redactFieldNames = true; - options.redactFieldNamesStrategy = redactFieldNameForTest; + options.redactIdentifiers = true; + options.identifierRedactionPolicy = redactFieldNameForTest; auto proj = fromjson("{'a.b': 1}"); diff --git a/src/mongo/db/query/projection_ast_util.cpp b/src/mongo/db/query/projection_ast_util.cpp index 7719ca3db96..ca415b4aecf 100644 --- a/src/mongo/db/query/projection_ast_util.cpp +++ b/src/mongo/db/query/projection_ast_util.cpp @@ -91,7 +91,7 @@ public: protected: std::string getFieldName() { - return _options.serializeFieldName(_context->childPath()); + return _options.serializeFieldPathFromString(_context->childPath()); } PathTrackingVisitorContext* _context; diff --git a/src/mongo/db/query/query_shape.cpp b/src/mongo/db/query/query_shape.cpp index fcfe0cb361e..4f5bddc1788 100644 --- a/src/mongo/db/query/query_shape.cpp +++ b/src/mongo/db/query/query_shape.cpp @@ -38,11 +38,11 @@ BSONObj predicateShape(const MatchExpression* predicate) { } BSONObj predicateShape(const MatchExpression* predicate, - std::function redactFieldNamesStrategy) { + std::function identifierRedactionPolicy) { SerializationOptions opts; opts.replacementForLiteralArgs = kLiteralArgString; - opts.redactFieldNamesStrategy = redactFieldNamesStrategy; - opts.redactFieldNames = true; + opts.identifierRedactionPolicy = identifierRedactionPolicy; + opts.redactIdentifiers = true; return predicate->serialize(opts); } diff --git a/src/mongo/db/query/query_shape.h b/src/mongo/db/query/query_shape.h index c072fa8b95e..3ec7c6696b6 100644 --- a/src/mongo/db/query/query_shape.h +++ b/src/mongo/db/query/query_shape.h @@ -52,6 +52,6 @@ constexpr StringData kLiteralArgString = "?"_sd; BSONObj predicateShape(const MatchExpression* predicate); BSONObj predicateShape(const MatchExpression* predicate, - std::function redactFieldNamesStrategy); + std::function identifierRedactionPolicy); } // namespace mongo::query_shape diff --git a/src/mongo/db/query/serialization_options.h b/src/mongo/db/query/serialization_options.h index 6858ddd0c30..4cd00dd3faf 100644 --- a/src/mongo/db/query/serialization_options.h +++ b/src/mongo/db/query/serialization_options.h @@ -32,6 +32,7 @@ #include "mongo/bson/bsonobj.h" #include "mongo/bson/bsonobjbuilder.h" #include "mongo/db/exec/document_value/value.h" +#include "mongo/db/pipeline/field_path.h" #include "mongo/db/query/explain_options.h" #include "mongo/util/assert_util.h" #include @@ -62,19 +63,64 @@ struct SerializationOptions { SerializationOptions(ExplainOptions::Verbosity verbosity_) : verbosity(verbosity_) {} - SerializationOptions(std::function redactFieldNamesStrategy_, + SerializationOptions(std::function identifierRedactionPolicy_, boost::optional replacementForLiteralArgs_) : replacementForLiteralArgs(replacementForLiteralArgs_), - redactFieldNames(redactFieldNamesStrategy_), - redactFieldNamesStrategy(redactFieldNamesStrategy_) {} + redactIdentifiers(identifierRedactionPolicy_), + identifierRedactionPolicy(identifierRedactionPolicy_) {} - std::string serializeFieldName(StringData str) const { - if (redactFieldNames) { - return redactFieldNamesStrategy(str); + // Helper function for redacting identifiable information (like collection/db names). + // Note: serializeFieldPath/serializeFieldPathFromString should be used for redacting field + // names. + std::string serializeIdentifier(StringData str) const { + if (redactIdentifiers) { + return identifierRedactionPolicy(str); } return str.toString(); } + std::string serializeFieldPath(FieldPath path) const { + if (redactIdentifiers) { + std::stringstream redacted; + for (size_t i = 0; i < path.getPathLength(); ++i) { + if (i > 0) { + redacted << "."; + } + redacted << identifierRedactionPolicy(path.getFieldName(i)); + } + return redacted.str(); + } + return path.fullPath(); + } + + std::string serializeFieldPathWithPrefix(FieldPath path) const { + return "$" + serializeFieldPath(path); + } + + std::string serializeFieldPathFromString(StringData path) const { + if (redactIdentifiers) { + // Some valid field names are considered invalid as a FieldPath (for example, fields + // like "foo.$bar" where a sub-component is prefixed with "$"). For now, if + // serializeFieldPath errors due to an "invalid" field name, we'll serialize that field + // name with this placeholder. + // TODO SERVER-75623 Implement full redaction for all field names and remove placeholder + try { + return serializeFieldPath(path); + } catch (DBException&) { + return serializeFieldPath("dollarPlaceholder"); + } + } + return path.toString(); + } + + template + Value serializeLiteralValue(T n) const { + if (replacementForLiteralArgs) { + return Value(*replacementForLiteralArgs); + } + return Value(n); + } + // Helper functions for redacting BSONObj. Does not take into account anything to do with MQL // semantics, redacts all field names and literals in the passed in obj. void redactArrayToBuilder(BSONArrayBuilder* bab, std::vector array) { @@ -96,9 +142,10 @@ struct SerializationOptions { } } } + void redactObjToBuilder(BSONObjBuilder* bob, BSONObj objToRedact) { for (const auto& elem : objToRedact) { - auto fieldName = serializeFieldName(elem.fieldName()); + auto fieldName = serializeFieldPath(elem.fieldName()); if (elem.type() == BSONType::Object) { BSONObjBuilder subObj(bob->subobjStart(fieldName)); redactObjToBuilder(&subObj, elem.Obj()); @@ -117,14 +164,6 @@ struct SerializationOptions { } } - template - Value serializeLiteralValue(T n) { - if (replacementForLiteralArgs) { - return Value(*replacementForLiteralArgs); - } - return Value(n); - } - // 'replacementForLiteralArgs' is an independent option to serialize in a genericized format // with the aim of similar "shaped" queries serializing to the same object. For example, if // set to '?' then the serialization of {a: {$gt: 2}} will result in {a: {$gt: '?'}}, as @@ -135,11 +174,11 @@ struct SerializationOptions { // 4, so the serialization expected would be {$and: [{a: {$gt: '?'}}, {b: {$lt: '?'}}]}. boost::optional replacementForLiteralArgs = boost::none; - // If true the caller must set redactFieldNamesStrategy. 'redactFieldNames' if set along with - // a strategy the redaction strategy will be called on any field paths/names encountered - // before serializing them. - bool redactFieldNames = false; - std::function redactFieldNamesStrategy = defaultRedactionStrategy; + // If true the caller must set identifierRedactionPolicy. 'redactIdentifiers' if set along with + // a strategy the redaction strategy will be called on any personal identifiable information + // (e.g., field paths/names, collection names) encountered before serializing them. + bool redactIdentifiers = false; + std::function identifierRedactionPolicy = defaultRedactionStrategy; // If set, serializes without including the path. For example {a: {$gt: 2}} would serialize // as just {$gt: 2}. diff --git a/src/mongo/db/query/sort_pattern.cpp b/src/mongo/db/query/sort_pattern.cpp index 2a10de80aa3..6d84418ce0e 100644 --- a/src/mongo/db/query/sort_pattern.cpp +++ b/src/mongo/db/query/sort_pattern.cpp @@ -120,7 +120,7 @@ Document SortPattern::serialize(SortKeySerialization serializationMode, for (size_t i = 0; i < n; ++i) { if (_sortPattern[i].fieldPath) { std::stringstream serializedFieldName; - if (!options.redactFieldNames) { + if (!options.redactIdentifiers) { // Append a named integer based on whether the sort is ascending/descending. serializedFieldName << _sortPattern[i].fieldPath->fullPath(); } else { @@ -130,7 +130,7 @@ Document SortPattern::serialize(SortKeySerialization serializationMode, if (index > 0) { serializedFieldName << "."; } - serializedFieldName << options.redactFieldNamesStrategy( + serializedFieldName << options.identifierRedactionPolicy( _sortPattern[i].fieldPath->getFieldName(index)); } } diff --git a/src/mongo/db/query/sort_pattern_test.cpp b/src/mongo/db/query/sort_pattern_test.cpp index 872b6640b43..3bb4286137c 100644 --- a/src/mongo/db/query/sort_pattern_test.cpp +++ b/src/mongo/db/query/sort_pattern_test.cpp @@ -49,8 +49,8 @@ TEST(SerializeSortPatternTest, SerializeAndRedactFieldName) { auto expCtx = getExpCtx(); auto sortPattern = SortPattern(fromjson("{val: 1}"), expCtx); SerializationOptions opts = {}; - opts.redactFieldNames = true; - opts.redactFieldNamesStrategy = redactFieldNameForTest; + opts.redactIdentifiers = true; + opts.identifierRedactionPolicy = redactFieldNameForTest; // Most basic sort pattern, confirm that field name gets redacted. ASSERT_DOCUMENT_EQ_AUTO( // NOLINT @@ -86,7 +86,7 @@ TEST(SerializeSortPatternTest, SerializeNoRedaction) { auto expCtx = getExpCtx(); auto sortPattern = SortPattern(fromjson("{val: 1}"), expCtx); SerializationOptions opts = {}; - opts.redactFieldNames = false; + opts.redactIdentifiers = false; ASSERT_DOCUMENT_EQ_AUTO( // NOLINT R"({"val":1})", sortPattern.serialize(SortPattern::SortKeySerialization::kForPipelineSerialization, opts)); diff --git a/src/mongo/db/query/telemetry.cpp b/src/mongo/db/query/telemetry.cpp index ad1e4d45e44..61bd1d26965 100644 --- a/src/mongo/db/query/telemetry.cpp +++ b/src/mongo/db/query/telemetry.cpp @@ -156,22 +156,15 @@ BSONObj redactHintComponent(BSONObj obj, const SerializationOptions& opts, bool tassert(7421703, "Hinted field must be a string with $hint operator", elem.type() == BSONType::String); - if (opts.redactFieldNames) { - bob.append(hintSpecialField, FieldPath(elem.String()).redactedFullPath(opts)); - } else { - bob.append(hintSpecialField, elem.String()); - } + bob.append(hintSpecialField, opts.serializeFieldPathFromString(elem.String())); continue; } - std::string fieldName = elem.fieldName(); - if (opts.redactFieldNames) { - fieldName = FieldPath(fieldName).redactedFullPath(opts); - } if (opts.replacementForLiteralArgs && redactValues) { - bob.append(fieldName, opts.replacementForLiteralArgs.get()); + bob.append(opts.serializeFieldPathFromString(elem.fieldName()), + opts.replacementForLiteralArgs.get()); } else { - bob.appendAs(elem, fieldName); + bob.appendAs(elem, opts.serializeFieldPathFromString(elem.fieldName())); } } return bob.obj(); @@ -191,7 +184,7 @@ BSONObj redactLetSpec(BSONObj letSpec, Expression::parseOperand(expCtx.get(), elem, expCtx->variablesParseState) ->serialize(opts); // Note that this will throw on deeply nested let variables. - redactedValue.addToBsonObj(&bob, opts.serializeFieldName(elem.fieldName())); + redactedValue.addToBsonObj(&bob, opts.serializeFieldPathFromString(elem.fieldName())); } return bob.obj(); } @@ -203,7 +196,7 @@ StatusWith makeTelemetryKey(const FindCommandRequest& findCommand, // TODO: SERVER-75156 Factor query shape out of telemetry. That ticket will involve splitting // this function up and moving most of it to another, non-telemetry related header. - if (!opts.redactFieldNames && !opts.replacementForLiteralArgs) { + if (!opts.redactIdentifiers && !opts.replacementForLiteralArgs) { // Short circuit if no redaction needs to be done. BSONObjBuilder bob; findCommand.serialize({}, &bob); @@ -222,12 +215,12 @@ StatusWith makeTelemetryKey(const FindCommandRequest& findCommand, auto nss = ns.nss().value(); if (nss.tenantId()) { cmdNs.append("tenantId", - opts.serializeFieldName(nss.tenantId().value().toString())); + opts.serializeIdentifier(nss.tenantId().value().toString())); } - cmdNs.append("db", opts.serializeFieldName(nss.db())); - cmdNs.append("coll", opts.serializeFieldName(nss.coll())); + cmdNs.append("db", opts.serializeIdentifier(nss.db())); + cmdNs.append("coll", opts.serializeIdentifier(nss.coll())); } else { - cmdNs.append("uuid", opts.serializeFieldName(ns.uuid()->toString())); + cmdNs.append("uuid", opts.serializeIdentifier(ns.uuid()->toString())); } cmdNs.done(); } @@ -237,10 +230,10 @@ StatusWith makeTelemetryKey(const FindCommandRequest& findCommand, auto nssOrUUID = findCommand.getNamespaceOrUUID(); std::string toSerialize; if (nssOrUUID.uuid()) { - toSerialize = opts.serializeFieldName(nssOrUUID.toString()); + toSerialize = opts.serializeIdentifier(nssOrUUID.toString()); } else { // Database is set at the command level, only serialize the collection here. - toSerialize = opts.serializeFieldName(nssOrUUID.nss()->coll()); + toSerialize = opts.serializeIdentifier(nssOrUUID.nss()->coll()); } bob.append(FindCommandRequest::kCommandName, toSerialize); } @@ -335,7 +328,7 @@ StatusWith makeTelemetryKey(const FindCommandRequest& findCommand, return boost::none; }(); if (appName.has_value()) { - bob.append("applicationName", opts.serializeFieldName(appName.value())); + bob.append("applicationName", opts.serializeIdentifier(appName.value())); } return bob.obj(); @@ -569,13 +562,13 @@ static const StringData replacementForLiteralArgs = "?"_sd; } // namespace StatusWith TelemetryMetrics::redactKey(const BSONObj& key, - bool redactFieldNames, + bool redactIdentifiers, OperationContext* opCtx) const { // The redacted key for each entry is cached on first computation. However, if the redaction // straegy has flipped (from no redaction to SHA256, vice versa), we just return the key passed // to the function, so entries returned to the user match the redaction strategy requested in // the most recent telemetry command. - if (!redactFieldNames) { + if (!redactIdentifiers) { return key; } if (_redactedKey) { diff --git a/src/mongo/db/query/telemetry.h b/src/mongo/db/query/telemetry.h index 622269e98fb..3735ce334f8 100644 --- a/src/mongo/db/query/telemetry.h +++ b/src/mongo/db/query/telemetry.h @@ -130,7 +130,7 @@ public: * Redact a given telemetry key and set _keySize. */ StatusWith redactKey(const BSONObj& key, - bool redactFieldNames, + bool redactIdentifiers, OperationContext* opCtx) const; /** diff --git a/src/mongo/db/query/telemetry_store_test.cpp b/src/mongo/db/query/telemetry_store_test.cpp index 387e42cbc42..d2e8e505008 100644 --- a/src/mongo/db/query/telemetry_store_test.cpp +++ b/src/mongo/db/query/telemetry_store_test.cpp @@ -130,8 +130,8 @@ TEST_F(TelemetryStoreTest, CorrectlyRedactsFindCommandRequestAllFields) { fcr.setFilter(BSON("a" << 1)); SerializationOptions opts; opts.replacementForLiteralArgs = "?"; - opts.redactFieldNames = true; - opts.redactFieldNamesStrategy = redactFieldNameForTest; + opts.redactIdentifiers = true; + opts.identifierRedactionPolicy = redactFieldNameForTest; auto redacted = uassertStatusOK(telemetry::makeTelemetryKey(fcr, opts, expCtx)); @@ -392,8 +392,8 @@ TEST_F(TelemetryStoreTest, CorrectlyRedactsFindCommandRequestEmptyFields) { fcr.setProjection(BSONObj()); SerializationOptions opts; opts.replacementForLiteralArgs = "?"; - opts.redactFieldNames = true; - opts.redactFieldNamesStrategy = redactFieldNameForTest; + opts.redactIdentifiers = true; + opts.identifierRedactionPolicy = redactFieldNameForTest; auto redacted = uassertStatusOK(telemetry::makeTelemetryKey(fcr, opts, expCtx)); ASSERT_BSONOBJ_EQ_AUTO( // NOLINT @@ -475,8 +475,8 @@ TEST_F(TelemetryStoreTest, CorrectlyRedactsHintsWithOptions) { redacted); fcr.setHint(BSON("z" << 1 << "c" << 1)); - opts.redactFieldNamesStrategy = redactFieldNameForTest; - opts.redactFieldNames = true; + opts.identifierRedactionPolicy = redactFieldNameForTest; + opts.redactIdentifiers = true; opts.replacementForLiteralArgs = boost::none; redacted = uassertStatusOK(telemetry::makeTelemetryKey(fcr, opts, expCtx)); ASSERT_BSONOBJ_EQ_AUTO( // NOLINT diff --git a/src/mongo/db/s/document_source_analyze_shard_key_read_write_distribution.cpp b/src/mongo/db/s/document_source_analyze_shard_key_read_write_distribution.cpp index 57296b406a4..6687bdf45d8 100644 --- a/src/mongo/db/s/document_source_analyze_shard_key_read_write_distribution.cpp +++ b/src/mongo/db/s/document_source_analyze_shard_key_read_write_distribution.cpp @@ -312,7 +312,7 @@ DocumentSourceAnalyzeShardKeyReadWriteDistribution::createFromBson( Value DocumentSourceAnalyzeShardKeyReadWriteDistribution::serialize( SerializationOptions opts) const { - if (opts.redactFieldNames || opts.replacementForLiteralArgs) { + if (opts.redactIdentifiers || opts.replacementForLiteralArgs) { MONGO_UNIMPLEMENTED_TASSERT(7484305); } diff --git a/src/mongo/db/s/resharding/document_source_resharding_ownership_match.cpp b/src/mongo/db/s/resharding/document_source_resharding_ownership_match.cpp index e9c0a78a282..dd4a900f812 100644 --- a/src/mongo/db/s/resharding/document_source_resharding_ownership_match.cpp +++ b/src/mongo/db/s/resharding/document_source_resharding_ownership_match.cpp @@ -93,7 +93,7 @@ StageConstraints DocumentSourceReshardingOwnershipMatch::constraints( } Value DocumentSourceReshardingOwnershipMatch::serialize(SerializationOptions opts) const { - if (opts.redactFieldNames || opts.replacementForLiteralArgs) { + if (opts.redactIdentifiers || opts.replacementForLiteralArgs) { MONGO_UNIMPLEMENTED_TASSERT(7484302); } diff --git a/src/mongo/s/query/document_source_merge_cursors.cpp b/src/mongo/s/query/document_source_merge_cursors.cpp index eebbefe7b2e..9a35057412a 100644 --- a/src/mongo/s/query/document_source_merge_cursors.cpp +++ b/src/mongo/s/query/document_source_merge_cursors.cpp @@ -117,7 +117,7 @@ DocumentSource::GetNextResult DocumentSourceMergeCursors::doGetNext() { Value DocumentSourceMergeCursors::serialize(SerializationOptions opts) const { invariant(!_blockingResultsMerger); invariant(_armParams); - if (opts.redactFieldNames || opts.replacementForLiteralArgs) { + if (opts.redactIdentifiers || opts.replacementForLiteralArgs) { MONGO_UNIMPLEMENTED_TASSERT(7484301); } -- cgit v1.2.1