|
@@ -270,6 +270,15 @@ public:
|
|
|
|
|
|
|
|
auto status = stub_->Get(&context, request, &response);
|
|
auto status = stub_->Get(&context, request, &response);
|
|
|
if (!status.ok()) {
|
|
if (!status.ok()) {
|
|
|
|
|
+ // v2.8.0 — a permission denial must NOT look like "no data".
|
|
|
|
|
+ // Returning empty here would leave an application unable to tell
|
|
|
|
|
+ // "you may not see this" from "there is nothing to see", so it
|
|
|
|
|
+ // would silently take the wrong branch. Same reasoning as the
|
|
|
|
|
+ // v2.4.2 change that stopped Find returning empty for a missing
|
|
|
|
|
+ // collection.
|
|
|
|
|
+ if (status.error_code() == grpc::StatusCode::PERMISSION_DENIED) {
|
|
|
|
|
+ throw std::runtime_error("access denied: get");
|
|
|
|
|
+ }
|
|
|
spdlog::error("Client::get failed: {}", status.error_message());
|
|
spdlog::error("Client::get failed: {}", status.error_message());
|
|
|
return std::nullopt;
|
|
return std::nullopt;
|
|
|
}
|
|
}
|
|
@@ -500,6 +509,15 @@ public:
|
|
|
|
|
|
|
|
auto status = stub_->Exists(&context, request, &response);
|
|
auto status = stub_->Exists(&context, request, &response);
|
|
|
if (!status.ok()) {
|
|
if (!status.ok()) {
|
|
|
|
|
+ // v2.8.0 — a permission denial must NOT look like "no data".
|
|
|
|
|
+ // Returning empty here would leave an application unable to tell
|
|
|
|
|
+ // "you may not see this" from "there is nothing to see", so it
|
|
|
|
|
+ // would silently take the wrong branch. Same reasoning as the
|
|
|
|
|
+ // v2.4.2 change that stopped Find returning empty for a missing
|
|
|
|
|
+ // collection.
|
|
|
|
|
+ if (status.error_code() == grpc::StatusCode::PERMISSION_DENIED) {
|
|
|
|
|
+ throw std::runtime_error("access denied: exists");
|
|
|
|
|
+ }
|
|
|
spdlog::error("Client::exists failed: {}", status.error_message());
|
|
spdlog::error("Client::exists failed: {}", status.error_message());
|
|
|
return false;
|
|
return false;
|
|
|
}
|
|
}
|
|
@@ -546,6 +564,15 @@ public:
|
|
|
throw std::runtime_error(status.error_message());
|
|
throw std::runtime_error(status.error_message());
|
|
|
}
|
|
}
|
|
|
if (!status.ok()) {
|
|
if (!status.ok()) {
|
|
|
|
|
+ // v2.8.0 — a permission denial must NOT look like "no data".
|
|
|
|
|
+ // Returning empty here would leave an application unable to tell
|
|
|
|
|
+ // "you may not see this" from "there is nothing to see", so it
|
|
|
|
|
+ // would silently take the wrong branch. Same reasoning as the
|
|
|
|
|
+ // v2.4.2 change that stopped Find returning empty for a missing
|
|
|
|
|
+ // collection.
|
|
|
|
|
+ if (status.error_code() == grpc::StatusCode::PERMISSION_DENIED) {
|
|
|
|
|
+ throw std::runtime_error("access denied: find");
|
|
|
|
|
+ }
|
|
|
spdlog::error("Client::find failed: {}", status.error_message());
|
|
spdlog::error("Client::find failed: {}", status.error_message());
|
|
|
return {};
|
|
return {};
|
|
|
}
|
|
}
|
|
@@ -599,6 +626,15 @@ public:
|
|
|
throw std::runtime_error(status.error_message()); // see find()
|
|
throw std::runtime_error(status.error_message()); // see find()
|
|
|
}
|
|
}
|
|
|
if (!status.ok()) {
|
|
if (!status.ok()) {
|
|
|
|
|
+ // v2.8.0 — a permission denial must NOT look like "no data".
|
|
|
|
|
+ // Returning empty here would leave an application unable to tell
|
|
|
|
|
+ // "you may not see this" from "there is nothing to see", so it
|
|
|
|
|
+ // would silently take the wrong branch. Same reasoning as the
|
|
|
|
|
+ // v2.4.2 change that stopped Find returning empty for a missing
|
|
|
|
|
+ // collection.
|
|
|
|
|
+ if (status.error_code() == grpc::StatusCode::PERMISSION_DENIED) {
|
|
|
|
|
+ throw std::runtime_error("access denied: findWithMetrics");
|
|
|
|
|
+ }
|
|
|
spdlog::error("Client::findWithMetrics failed: {}", status.error_message());
|
|
spdlog::error("Client::findWithMetrics failed: {}", status.error_message());
|
|
|
return {};
|
|
return {};
|
|
|
}
|
|
}
|
|
@@ -645,6 +681,15 @@ public:
|
|
|
|
|
|
|
|
auto status = stub_->Count(&context, request, &response);
|
|
auto status = stub_->Count(&context, request, &response);
|
|
|
if (!status.ok()) {
|
|
if (!status.ok()) {
|
|
|
|
|
+ // v2.8.0 — a permission denial must NOT look like "no data".
|
|
|
|
|
+ // Returning empty here would leave an application unable to tell
|
|
|
|
|
+ // "you may not see this" from "there is nothing to see", so it
|
|
|
|
|
+ // would silently take the wrong branch. Same reasoning as the
|
|
|
|
|
+ // v2.4.2 change that stopped Find returning empty for a missing
|
|
|
|
|
+ // collection.
|
|
|
|
|
+ if (status.error_code() == grpc::StatusCode::PERMISSION_DENIED) {
|
|
|
|
|
+ throw std::runtime_error("access denied: count");
|
|
|
|
|
+ }
|
|
|
spdlog::error("Client::count failed: {}", status.error_message());
|
|
spdlog::error("Client::count failed: {}", status.error_message());
|
|
|
return 0;
|
|
return 0;
|
|
|
}
|
|
}
|
|
@@ -1222,8 +1267,23 @@ public:
|
|
|
attachAuth(*context);
|
|
attachAuth(*context);
|
|
|
|
|
|
|
|
smartbotic::databasepb::SubscribeRequest request;
|
|
smartbotic::databasepb::SubscribeRequest request;
|
|
|
|
|
+ // v2.8.0 — subscribe was the one call left unqualified while every
|
|
|
|
|
+ // document call qualified. Two consequences, both cross-project leaks:
|
|
|
|
|
+ //
|
|
|
|
|
+ // * a bare name matched nothing, because events carry the qualified
|
|
|
|
|
+ // collection - so subscriptions silently never fired;
|
|
|
|
|
+ // * an EMPTY list means "every collection" server-side, which meant
|
|
|
|
|
+ // every collection in every PROJECT.
|
|
|
|
|
+ //
|
|
|
|
|
+ // Named collections are qualified like any other. For the "everything"
|
|
|
|
|
+ // case we send a `<project>:*` pattern instead of an empty request, so
|
|
|
|
|
+ // "all" means all of MY project. That needs no proto change - the
|
|
|
|
|
+ // pattern field already existed.
|
|
|
for (const auto& coll : collections) {
|
|
for (const auto& coll : collections) {
|
|
|
- request.add_collections(coll);
|
|
|
|
|
|
|
+ request.add_collections(qualify(coll));
|
|
|
|
|
+ }
|
|
|
|
|
+ if (collections.empty()) {
|
|
|
|
|
+ request.add_patterns(config_.project + ":*");
|
|
|
}
|
|
}
|
|
|
request.set_include_data(true);
|
|
request.set_include_data(true);
|
|
|
|
|
|