Aug 08 2025 dev (#336)

* sync code

* sync code

* sync code

---------

Co-authored-by: Ned Wright <nedwright@proton.me>
This commit is contained in:
Daniel-Eisenberg
2025-08-10 13:21:52 +03:00
committed by GitHub
parent dd19bf6158
commit 6bbc89712a
153 changed files with 4864 additions and 1018 deletions

View File

@@ -15,6 +15,18 @@
using namespace std;
template<class Archive>
void
ExternalSourceError::serialize(Archive &ar)
{
ar(
cereal::make_nvp("sourceID", source_id),
cereal::make_nvp("sourceName", source_name),
cereal::make_nvp("statusCode", status_code),
cereal::make_nvp("errorMessage", error_message)
);
}
void
IntelligenceQueryResponse::loadFromJson(const std::string &json_response)
{
@@ -35,4 +47,14 @@ IntelligenceQueryResponse::serialize(Archive &ar)
try {
ar(cereal::make_nvp("cursor", cursor));
} catch (...) {}
try {
ar(cereal::make_nvp("externalSourcesErrorStatus", external_sources_errors));
} catch (...) {}
}
const std::vector<ExternalSourceError> &
IntelligenceQueryResponse::getExternalSourcesErrorStatus() const
{
return external_sources_errors;
}

View File

@@ -36,6 +36,7 @@ static const string query_uri = "/api/v2/intelligence/assets/query";
static const string queries_uri = "/api/v2/intelligence/assets/queries";
static const string fog_health_uri = "/access-manager/health/live";
static const string intelligence_health_uri = "/show-health";
static const string time_range_invalidation_uri = "/api/v2/intelligence/invalidation/get";
class I_InvalidationCallBack
{
@@ -83,6 +84,12 @@ public:
first = false;
}
void
setAgentId(const string &_agent_id)
{
agent_id = _agent_id;
}
RestCall
genJson() const
{
@@ -90,7 +97,7 @@ public:
res << "{ \"apiVersion\": \"v2\", \"communicationType\": \"sync\", \"callbackType\": \"invalidation\", ";
auto details = Singleton::Consume<I_AgentDetails>::by<IntelligenceComponentV2>();
res << "\"name\": \"" << details->getAgentId() << "\", ";
res << "\"name\": \"" << (agent_id.empty() ? details->getAgentId() : agent_id) << "\", ";
auto rest = Singleton::Consume<I_RestApi>::by<IntelligenceComponentV2>();
res << "\"url\": \"http://127.0.0.1:" << rest->getListeningPort() <<"/set-new-invalidation\", ";
res << "\"capabilities\": { \"getBulkCallback\": " << "true" << " }, ";
@@ -106,6 +113,7 @@ public:
private:
bool first = true;
stringstream stream;
string agent_id = "";
};
class InvalidationCallBack : Singleton::Provide<I_InvalidationCallBack>::SelfInterface
@@ -137,10 +145,12 @@ public:
bool empty() const { return callbacks.empty(); }
InvalidationRegistration::RestCall
getRegistration() const
getRegistration(const string& agent_id) const
{
InvalidationRegistration registration;
registration.setAgentId(agent_id);
for (auto &registed_invalidation : callbacks) {
registration.addInvalidation(registed_invalidation.second.first);
}
@@ -394,11 +404,24 @@ public:
return sendIntelligence(invalidation).ok();
}
Maybe<vector<Invalidation>>
getInvalidations(TimeRangeInvalidations request) const override
{
auto res = sendIntelligence(request);
if (res.ok()) return res.unpack().getInvalidations();
return res.passErr();
}
Maybe<uint>
registerInvalidation(const Invalidation &invalidation, const function<void(const Invalidation &)> &cb) override
registerInvalidation(
const Invalidation &invalidation,
const function<void(const Invalidation &)> &cb,
const string &AgentId
) override
{
if (!invalidation.isLegalInvalidation()) return genError("Attempting to register invalid invalidation");
auto res = invalidations.emplace(invalidation, cb);
agent_id = AgentId;
sendRecurringInvalidationRegistration();
return res;
}
@@ -504,7 +527,7 @@ private:
const string &server,
const string &port_setting,
const bool should_send_access_token = false
) const
) const
{
auto port = getSetting<uint>("intelligence", port_setting);
if (!port.ok()) {
@@ -548,6 +571,16 @@ private:
return load_status.passErr();
}
Maybe<Response>
createResponse(const string &response_body) const
{
Response response(response_body, 0, false);
auto load_status = response.loadInvalidations();
if (load_status.ok()) return response;
dbgWarning(D_INTELLIGENCE) << "Could not create intelligence response.";
return load_status.passErr();
}
Maybe<Response>
sendIntelligenceRequestImpl(const Invalidation &invalidation, const MessageMetadata &local_req_md) const
{
@@ -642,6 +675,39 @@ private:
return createResponse(req_data->getBody(), query_request);
}
Maybe<Response>
sendIntelligenceRequestImpl(
const TimeRangeInvalidations &request,
const MessageMetadata &global_req_md) const
{
dbgFlow(D_INTELLIGENCE) << "Sending time range invalidations request";
auto json_body = request.genJson();
if (!json_body.ok()) return json_body.passErr();
auto req_data = message->sendSyncMessage(
HTTPMethod::POST,
time_range_invalidation_uri,
*json_body,
MessageCategory::INTELLIGENCE,
global_req_md
);
if (!req_data.ok()) {
dbgWarning(D_INTELLIGENCE)
<< "Could not send time range invalidations request. "
<< req_data.getErr().getBody()
<< " "
<< req_data.getErr().toString();
return genError("Could not send time range invalidations request.");
}
if (req_data->getHTTPStatusCode() != HTTPStatusCode::HTTP_OK) {
dbgWarning(D_INTELLIGENCE) << "Invalid intelligence response: " << req_data->toString();
return genError(req_data->toString());
}
return createResponse(req_data->getBody());
}
map<string, string>
getHTTPHeaders() const
{
@@ -651,7 +717,7 @@ private:
if (tenant == "") tenant = "Global";
headers["X-Tenant-Id"] = tenant;
auto rest = Singleton::Consume<I_RestApi>::by<IntelligenceComponentV2>();
auto agent = details->getAgentId() + ":" + to_string(rest->getListeningPort());
auto agent = (agent_id.empty() ? details->getAgentId() : agent_id) + ":" + to_string(rest->getListeningPort());
headers["X-Source-Id"] = agent;
return headers;
@@ -662,7 +728,7 @@ private:
{
if (invalidations.empty()) return;
sendLocalIntelligenceToLocalServer(invalidations.getRegistration());
sendLocalIntelligenceToLocalServer(invalidations.getRegistration(agent_id));
}
Maybe<Response>
@@ -678,6 +744,7 @@ private:
InvalidationCallBack invalidations;
I_Messaging *message = nullptr;
I_MainLoop *mainloop = nullptr;
string agent_id = "";
};
IntelligenceComponentV2::IntelligenceComponentV2()

View File

@@ -1,8 +1,13 @@
#include <sstream>
namespace Intelligence { class Response; }
#include <vector>
namespace Intelligence
{
class Response;
class Invalidation;
}
std::ostream & operator<<(std::ostream &os, const Intelligence::Response &);
#include "intelligence_comp_v2.h"
std::ostream & operator<<(std::ostream &os, const Intelligence::Invalidation &);
std::ostream & operator<<(std::ostream &os, const std::vector<Intelligence::Invalidation> &);
#include "config.h"
#include "config_component.h"
@@ -15,6 +20,8 @@ std::ostream & operator<<(std::ostream &os, const Intelligence::Response &);
#include "mock/mock_agent_details.h"
#include "read_attribute_v2.h"
#include "singleton.h"
#include "intelligence_comp_v2.h"
#include "intelligence_invalidation.h"
using namespace std;
using namespace testing;
@@ -1397,3 +1404,68 @@ TEST_F(IntelligenceComponentTestV2, localIntelligenceHealthy)
EXPECT_TRUE(intell->isIntelligenceHealthy());
}
TEST_F(IntelligenceComponentTestV2, getInvalidations)
{
Debug::setUnitTestFlag(D_INTELLIGENCE, Debug::DebugLevel::TRACE);
I_Intelligence_IS_V2 *intell = Singleton::Consume<I_Intelligence_IS_V2>::by<IntelligenceComponentTestV2>();
Debug::setNewDefaultStdout(&cout);
HTTPResponse response_str(
HTTPStatusCode::HTTP_OK,
string(
"{ \"invalidations\": [ { "
"\"class\": \"aaa\", "
"\"category\": \"bbb\", "
"\"family\": \"ccc\", "
"\"group\": \"ddd\", "
"\"order\": \"eee\", "
"\"kind\": \"fff\", "
"\"objectType\": \"asset\", "
"\"sourceId\": \"id\", "
"\"mainAttributes\": [ { \"attr\": \"2\" } ], "
"\"attributes\": [ { \"ipv4Addresses\": [ \"1.1.1.2\" ], "
"\"ipv4AddressesRange\": [ { \"max\": \"1.1.1.5\", \"min\": \"1.1.1.1\" } ] } ]"
" } ] }"
)
);
Intelligence::TimeRangeInvalidations time_range_invalidations(1622505600, 1622592000);
auto json_body = time_range_invalidations.genJson();
EXPECT_TRUE(json_body.ok());
EXPECT_CALL(mock_rest, getListeningPort()).WillOnce(Return(8888));
EXPECT_CALL(
messaging_mock,
sendSyncMessage(
HTTPMethod::POST,
"/api/v2/intelligence/invalidation/get",
json_body.unpack(),
MessageCategory::INTELLIGENCE,
_
)
).WillOnce(Return(response_str));
auto main_attr = Intelligence::StrAttributes()
.addStringAttr("attr", "2");
Intelligence::IpAddressRange range("1.1.1.1", "1.1.1.5");
Intelligence::IpAttributes attributes = Intelligence::IpAttributes()
.addIpv4Addresses("1.1.1.2")
.addIpv4AddressRanges(range);
auto invalidation = Intelligence::Invalidation("aaa")
.addMainAttr(main_attr)
.addAttr(attributes)
.setSourceId("id")
.setClassifier(Intelligence::ClassifierType::FAMILY, "ccc")
.setClassifier(Intelligence::ClassifierType::CATEGORY, "bbb")
.setClassifier(Intelligence::ClassifierType::GROUP, "ddd")
.setClassifier(Intelligence::ClassifierType::ORDER, "eee")
.setClassifier(Intelligence::ClassifierType::KIND, "fff")
.setObjectType(Intelligence::ObjectType::ASSET);
auto res = intell->getInvalidations(time_range_invalidations);
EXPECT_TRUE(res.ok());
EXPECT_TRUE(res.unpack().front().matches(invalidation));
}

View File

@@ -63,6 +63,28 @@ TEST(IntelligenceQueryTestV2, genJsonPrettySingleRequestProxied) {
EXPECT_EQ(*query.genJson(), expected);
}
TEST(IntelligenceQueryTestV2, genJsonPrettySingleRequestExternalError) {
QueryRequest request(Condition::EQUALS, "phase", "testing", true, AttributeKeyType::MAIN, true);
vector<QueryRequest> requests = {request};
Intelligence::IntelligenceRequest query(requests, true, false, true, MessageMetadata("", 0));
std::string expected = "{\n"
" \"queryTypes\": {\n"
" \"proxyToCloud\": true\n"
" },\n"
" \"limit\": 20,\n"
" \"fullResponse\": true,\n"
" \"externalSourcesErrorStatus\": true,\n"
" \"query\": {\n"
" \"operator\": \"equals\",\n"
" \"key\": \"mainAttributes.phase\",\n"
" \"value\": \"testing\"\n"
" }\n"
"}";
EXPECT_EQ(*query.genJson(), expected);
}
TEST(IntelligenceQueryTestV2, genJsonUnprettySingleRequest) {
QueryRequest request(Condition::EQUALS, "phase", "testing", true);
vector<QueryRequest> requests = {request};

View File

@@ -87,13 +87,14 @@ TEST(QueryRequestTestV2, QueryTest)
range2.push_back("224.11.10.16");
range2.push_back("224.11.10.31");
QueryRequest request3(Condition::RANGE, "ipv4AddressesRange", range1, true);
QueryRequest request3(Condition::RANGE, "ipv4AddressesRange", range1, true, AttributeKeyType::MAIN, true);
request3.addCondition(Condition::RANGE, "ipv4AddressesRange", range2);
string output_json3=
"{\n"
" \"limit\": 20,\n"
" \"fullResponse\": true,\n"
" \"externalSourcesErrorStatus\": true,\n"
" \"query\": {\n"
" \"operator\": \"and\",\n"
" \"operands\": [\n"

View File

@@ -145,7 +145,8 @@ TEST(QueryResponseTestV2, QueryResponseTestV2)
" ],\n"
" \"status\": \"done\",\n"
" \"totalNumAssets\": 2,\n"
" \"cursor\": \"start\"\n"
" \"cursor\": \"start\",\n"
" \"externalSourcesErrorStatus\": []\n"
"}\n"
);
@@ -159,6 +160,8 @@ TEST(QueryResponseTestV2, QueryResponseTestV2)
EXPECT_EQ(obj2.getAmountOfAssets(), 2u);
EXPECT_EQ(obj.getResponseStatus(), ResponseStatus::DONE);
EXPECT_EQ(obj2.getResponseStatus(), ResponseStatus::DONE);
EXPECT_TRUE(obj.getExternalSourcesErrorStatus().empty());
EXPECT_TRUE(obj2.getExternalSourcesErrorStatus().empty());
EXPECT_EQ(obj.getData().begin()->getAssetSchemaVersion(), 1u);
EXPECT_EQ(obj.getData().begin()->getAssetType(), "workload-cloud-ip");
EXPECT_EQ(obj.getData().begin()->getAssetTypeSchemaVersion(), 1u);
@@ -217,6 +220,86 @@ TEST(QueryResponseTestV2, QueryResponseTestV2)
EXPECT_EQ(asset_sources_it->getData1().toString(), "Max");
}
TEST(QueryResponseTestV2, ExternalSourcesErrorStatusTestV2)
{
DataString data;
IntelligenceQueryResponseT<stringData1> obj;
string string_attribute(
"{\n"
" \"assetCollections\": [\n"
" {\n"
" \"schemaVersion\": 1,\n"
" \"assetType\": \"workload-cloud-ip\",\n"
" \"assetTypeSchemaVersion\": 1,\n"
" \"permissionType\": \"tenant\",\n"
" \"permissionGroupId\": \"some-group-id\",\n"
" \"name\": \"[1.1.1.1]\",\n"
" \"class\": \"workload\",\n"
" \"category\": \"cloud\",\n"
" \"family\": \"ip\",\n"
" \"group\": \"\",\n"
" \"order\": \"\",\n"
" \"kind\": \"\",\n"
" \"mainAttributes\": {\n"
" \"team\": \"hapoel\"\n"
" },\n"
" \"sources\": [\n"
" {\n"
" \"tenantId\": \"175bb55c-e36f-4ac5-a7b1-7afa1229aa00\",\n"
" \"sourceId\": \"54d7de10-7b2e-4505-955b-cc2c2c7aaa00\",\n"
" \"assetId\": \"50255c3172b4fb7fda93025f0bfaa7abefd1\",\n"
" \"ttl\": 120,\n"
" \"expirationTime\": \"2020-07-29T11:21:12.253Z\",\n"
" \"confidence\": 500,\n"
" \"attributes\": {\n"
" \"color\": \"red\",\n"
" \"user\": \"Omry\",\n"
" \"owners\": { \"names\": [ { \"name1\": \"Bob\", \"name2\": \"Alice\" } ] }\n"
" }\n"
" }\n"
" ]\n"
" }\n"
" ],\n"
" \"status\": \"done\",\n"
" \"totalNumAssets\": 1,\n"
" \"cursor\": \"start\",\n"
" \"externalSourcesErrorStatus\": [\n"
" {\n"
" \"sourceID\": \"54d7de10-7b2e-4505-955b-cc2c2c7aaa00\",\n"
" \"sourceName\": \"test-source-1\",\n"
" \"statusCode\": 500,\n"
" \"errorMessage\": \"Internal server error\"\n"
" },\n"
" {\n"
" \"sourceID\": \"a1b2c3d4-5678-9abc-def0-123456789abc\",\n"
" \"sourceName\": \"test-source-2\",\n"
" \"statusCode\": 404,\n"
" \"errorMessage\": \"Not found\"\n"
" }\n"
" ]\n"
"}\n"
);
stringstream ss(string_attribute);
{
cereal::JSONInputArchive ar(ss);
obj.serialize(ar);
}
const auto& errors = obj.getExternalSourcesErrorStatus();
EXPECT_EQ(errors.size(), 2u);
EXPECT_EQ(errors[0].getSourceID(), "54d7de10-7b2e-4505-955b-cc2c2c7aaa00");
EXPECT_EQ(errors[0].getSourceName(), "test-source-1");
EXPECT_EQ(errors[0].getStatusCode(), 500u);
EXPECT_EQ(errors[0].getErrorMessage(), "Internal server error");
EXPECT_EQ(errors[1].getSourceID(), "a1b2c3d4-5678-9abc-def0-123456789abc");
EXPECT_EQ(errors[1].getSourceName(), "test-source-2");
EXPECT_EQ(errors[1].getStatusCode(), 404u);
EXPECT_EQ(errors[1].getErrorMessage(), "Not found");
}
TEST(QueryResponseTestV2, MainAttributesTestV2)
{
DataString data;

View File

@@ -58,6 +58,20 @@ Response::load()
return {};
}
Maybe<void>
Response::loadInvalidations()
{
try {
stringstream in;
in.str(json_response);
cereal::JSONInputArchive in_ar(in);
in_ar(cereal::make_nvp("invalidations", invalidations));
} catch(const std::exception &e) {
return genError("Load invalidations failed. Error: " + string(e.what()));
}
return {};
}
Intelligence_IS_V2::ResponseStatus
Response::getResponseStatus() const
{

View File

@@ -25,13 +25,22 @@ USE_DEBUG_FLAG(D_INTELLIGENCE);
using namespace Intelligence;
using namespace std;
Invalidation::Invalidation()
:
source_id(genError<string>("")),
object_type(genError<string>("")),
invalidation_type(genError<string>("")),
listening_id(genError<string>("")),
registration_id(genError<string>(""))
{}
Invalidation::Invalidation(const string &class_value)
:
source_id(genError<void>()),
object_type(genError<void>()),
invalidation_type(genError<void>()),
listening_id(genError<void>()),
registration_id(genError<void>())
source_id(genError<string>("")),
object_type(genError<string>("")),
invalidation_type(genError<string>("")),
listening_id(genError<string>("")),
registration_id(genError<string>(""))
{
setClassifier(ClassifierType::CLASS, class_value);
}
@@ -72,10 +81,14 @@ Invalidation::report(I_Intelligence_IS_V2 *interface) const
}
Maybe<uint>
Invalidation::startListening(I_Intelligence_IS_V2 *interface, const function<void(const Invalidation &)> &cb)
Invalidation::startListening(
I_Intelligence_IS_V2 *interface,
const function<void(const Invalidation &)> &cb,
const string &AgentId
)
{
registration_id = to_string(boost::uuids::random_generator()());
auto res = interface->registerInvalidation(*this, cb);
auto res = interface->registerInvalidation(*this, cb, AgentId);
if (res.ok()) listening_id = *res;
return res;
}
@@ -243,6 +256,117 @@ Invalidation::matches(const Invalidation &other) const
return true;
}
void
Invalidation::serialize(cereal::JSONInputArchive &ar)
{
std::string class_ = "";
std::string category = "";
std::string family = "";
std::string group = "";
std::string order = "";
std::string kind = "";
std::string object_type_;
std::string invalidation_type_;
std::string source_id_;
uint listening_id_;
std::string registration_id_;
try {
ar(cereal::make_nvp("class", class_));
} catch (const cereal::Exception &e) {
dbgError(D_INTELLIGENCE) << e.what();
}
try {
ar(cereal::make_nvp("category", category));
} catch (const cereal::Exception &e) {
dbgError(D_INTELLIGENCE) << e.what();
}
try {
ar(cereal::make_nvp("family", family));
} catch (const cereal::Exception &e) {
dbgError(D_INTELLIGENCE) << e.what();
}
try {
ar(cereal::make_nvp("group", group));
} catch (const cereal::Exception &e) {
dbgError(D_INTELLIGENCE) << e.what();
}
try {
ar(cereal::make_nvp("order", order));
} catch (const cereal::Exception &e) {
dbgError(D_INTELLIGENCE) << e.what();
}
try {
ar(cereal::make_nvp("kind", kind));
} catch (const cereal::Exception &e) {
dbgError(D_INTELLIGENCE) << e.what();
}
try {
ar(cereal::make_nvp("mainAttributes", main_attributes));
ar(cereal::make_nvp("attributes", attributes));
} catch (const cereal::Exception &e) {
dbgError(D_INTELLIGENCE) << e.what();
}
try {
ar(cereal::make_nvp("objectType", object_type_));
auto it = stringToObjectTypeMap.find(object_type_);
if (it != stringToObjectTypeMap.end()) {
object_type = it->second;
} else {
throw std::invalid_argument("Invalid string for ObjectType: " + object_type_);
}
} catch (const cereal::Exception &e) {
dbgError(D_INTELLIGENCE) << e.what();
}
try {
ar(cereal::make_nvp("sourceId", source_id_));
source_id = source_id_;
} catch (const cereal::Exception &e) {
dbgError(D_INTELLIGENCE) << e.what();
}
try {
ar(cereal::make_nvp("invalidationRegistrationId", registration_id_));
registration_id = registration_id_;
} catch (const cereal::Exception &e) {
dbgError(D_INTELLIGENCE) << e.what();
}
try {
ar(cereal::make_nvp("invalidationType", invalidation_type_));
auto it = stringToInvalidationTypeMap.find(invalidation_type_);
if (it != stringToInvalidationTypeMap.end()) {
invalidation_type = it->second;
} else {
throw std::invalid_argument("Invalid string for InvalidationType: " + invalidation_type_);
}
} catch (const cereal::Exception &e) {
dbgError(D_INTELLIGENCE) << e.what();
}
try {
ar(cereal::make_nvp("listeningId", listening_id_));
listening_id = listening_id_;
} catch (const cereal::Exception &e) {
dbgError(D_INTELLIGENCE) << e.what();
}
classifiers[ClassifierType::CLASS] = class_;
classifiers[ClassifierType::CATEGORY] = category;
classifiers[ClassifierType::FAMILY] = family;
classifiers[ClassifierType::GROUP] = group;
classifiers[ClassifierType::ORDER] = order;
classifiers[ClassifierType::KIND] = kind;
}
Invalidation &
Invalidation::addAttr(const IpAttributes &attr)
{
@@ -257,7 +381,7 @@ Invalidation::addMainAttr(const StrAttributes &attr)
return *this;
}
Maybe<string, void>
Maybe<string>
Invalidation::getRegistrationID() const{
return registration_id;
}

View File

@@ -30,11 +30,13 @@ QueryRequest::QueryRequest(
const string &key,
const string &value,
bool full_reponse,
AttributeKeyType attribute_type
AttributeKeyType attribute_type,
bool _external_sources_error_status
) {
query = SerializableQueryFilter(condition_type, createAttributeString(key, attribute_type), value);
assets_limit = default_assets_limit;
full_response = full_reponse;
external_sources_error_status = _external_sources_error_status;
}
QueryRequest::QueryRequest(
@@ -42,11 +44,13 @@ QueryRequest::QueryRequest(
const string &key,
const int64_t &value,
bool full_reponse,
AttributeKeyType attribute_type
AttributeKeyType attribute_type,
bool _external_sources_error_status
) {
query = SerializableQueryFilter(condition_type, createAttributeString(key, attribute_type), value);
assets_limit = default_assets_limit;
full_response = full_reponse;
external_sources_error_status = _external_sources_error_status;
}
QueryRequest::QueryRequest(
@@ -54,11 +58,13 @@ QueryRequest::QueryRequest(
const string &key,
const vector<string> &value,
bool full_reponse,
AttributeKeyType attribute_type
AttributeKeyType attribute_type,
bool _external_sources_error_status
) {
query = SerializableQueryFilter(condition_type, createAttributeString(key, attribute_type), value);
assets_limit = default_assets_limit;
full_response = full_reponse;
external_sources_error_status = _external_sources_error_status;
}
Maybe<string>
@@ -83,10 +89,15 @@ QueryRequest::save(cereal::JSONOutputArchive &ar) const
{
ar(
cereal::make_nvp("limit", assets_limit),
cereal::make_nvp("fullResponse", full_response),
cereal::make_nvp("query", query)
cereal::make_nvp("fullResponse", full_response)
);
if (external_sources_error_status) {
ar(cereal::make_nvp("externalSourcesErrorStatus", external_sources_error_status));
}
ar(cereal::make_nvp("query", query));
auto objTypeString = convertObjectTypeToString();
if (objTypeString.ok()) {
ar(cereal::make_nvp("objectType", *objTypeString));
@@ -236,6 +247,7 @@ QueryRequest::calcQueryRequestOperator(const QueryRequest &other_query, const Op
res_req_query.query = res_query_filter;
res_req_query.assets_limit = this->assets_limit;
res_req_query.full_response = this->full_response;
res_req_query.external_sources_error_status = this->external_sources_error_status;
res_req_query.cursor = this->cursor;
res_req_query.requested_attributes = this->requested_attributes;
res_req_query.query_types = this->query_types;