Skip to content

Commit 39effdf

Browse files
GrigoriyPAuzhastik
authored andcommitted
YQ-3006 added secrets validation (#3872)
1 parent 3547830 commit 39effdf

File tree

9 files changed

+132
-60
lines changed

9 files changed

+132
-60
lines changed

ydb/core/kqp/executer_actor/kqp_executer_impl.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1598,7 +1598,7 @@ class TKqpExecuterBase : public TActorBootstrapped<TDerived> {
15981598
}
15991599

16001600
void GetSecretsSnapshot() {
1601-
RegisterDescribeSecretsActor(this->SelfId(), UserToken ? UserToken->GetUserSID() : "", SecretNames, this->ActorContext(), MaximalSecretsSnapshotWaitTime);
1601+
RegisterDescribeSecretsActor(this->SelfId(), UserToken ? UserToken->GetUserSID() : "", SecretNames, this->ActorContext().ActorSystem(), MaximalSecretsSnapshotWaitTime);
16021602
}
16031603

16041604
void GetResourcesSnapshot() {

ydb/core/kqp/federated_query/kqp_federated_query_actors.cpp

Lines changed: 64 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -24,31 +24,34 @@ class TDescribeSecretsActor: public NActors::TActorBootstrapped<TDescribeSecrets
2424
const bool isFound = snapshot->GetSecretValue(NMetadata::NSecret::TSecretIdOrValue::BuildAsId(secretId), secretValue);
2525
if (!isFound) {
2626
LastResponse = TEvDescribeSecretsResponse::TDescription(Ydb::StatusIds::BAD_REQUEST, { NYql::TIssue("secret with name '" + secretId.GetSecretId() + "' not found") });
27+
if (!SubscribedOnSecrets) {
28+
CompleteAndPassAway(LastResponse);
29+
}
2730
return;
2831
}
2932
secretValues.push_back(secretValue);
3033
}
31-
Promise.SetValue(TEvDescribeSecretsResponse::TDescription(secretValues));
3234

33-
UnsubscribeFromSecrets();
34-
PassAway();
35+
CompleteAndPassAway(TEvDescribeSecretsResponse::TDescription(secretValues));
3536
}
3637

3738
void Handle(NActors::TEvents::TEvWakeup::TPtr&) {
38-
Promise.SetValue(LastResponse);
39+
CompleteAndPassAway(LastResponse);
40+
}
41+
42+
void CompleteAndPassAway(const TEvDescribeSecretsResponse::TDescription& response) {
43+
Promise.SetValue(response);
3944

40-
UnsubscribeFromSecrets();
45+
if (SubscribedOnSecrets) {
46+
this->Send(NMetadata::NProvider::MakeServiceId(SelfId().NodeId()), new NMetadata::NProvider::TEvUnsubscribeExternal(GetSecretsSnapshotParser()));
47+
}
4148
PassAway();
4249
}
4350

4451
NMetadata::NFetcher::ISnapshotsFetcher::TPtr GetSecretsSnapshotParser() {
4552
return std::make_shared<NMetadata::NSecret::TSnapshotsFetcher>();
4653
}
4754

48-
void UnsubscribeFromSecrets() {
49-
this->Send(NMetadata::NProvider::MakeServiceId(SelfId().NodeId()), new NMetadata::NProvider::TEvUnsubscribeExternal(GetSecretsSnapshotParser()));
50-
}
51-
5255
public:
5356
TDescribeSecretsActor(const TString& ownerUserId, const std::vector<TString>& secretIds, NThreading::TPromise<TEvDescribeSecretsResponse::TDescription> promise, TDuration maximalSecretsSnapshotWaitTime)
5457
: SecretIds(CreateSecretIds(ownerUserId, secretIds))
@@ -64,8 +67,13 @@ class TDescribeSecretsActor: public NActors::TActorBootstrapped<TDescribeSecrets
6467
return;
6568
}
6669

67-
this->Send(NMetadata::NProvider::MakeServiceId(SelfId().NodeId()), new NMetadata::NProvider::TEvSubscribeExternal(GetSecretsSnapshotParser()));
68-
this->Schedule(MaximalSecretsSnapshotWaitTime, new NActors::TEvents::TEvWakeup());
70+
if (MaximalSecretsSnapshotWaitTime) {
71+
this->Send(NMetadata::NProvider::MakeServiceId(SelfId().NodeId()), new NMetadata::NProvider::TEvSubscribeExternal(GetSecretsSnapshotParser()));
72+
this->Schedule(MaximalSecretsSnapshotWaitTime, new NActors::TEvents::TEvWakeup());
73+
} else {
74+
this->Send(NMetadata::NProvider::MakeServiceId(SelfId().NodeId()), new NMetadata::NProvider::TEvAskSnapshot(GetSecretsSnapshotParser()));
75+
SubscribedOnSecrets = false;
76+
}
6977
Become(&TDescribeSecretsActor::StateFunc);
7078
}
7179

@@ -83,6 +91,7 @@ class TDescribeSecretsActor: public NActors::TActorBootstrapped<TDescribeSecrets
8391
NThreading::TPromise<TEvDescribeSecretsResponse::TDescription> Promise;
8492
TEvDescribeSecretsResponse::TDescription LastResponse;
8593
TDuration MaximalSecretsSnapshotWaitTime;
94+
bool SubscribedOnSecrets = true;
8695
};
8796

8897
} // anonymous namespace
@@ -91,13 +100,53 @@ IActor* CreateDescribeSecretsActor(const TString& ownerUserId, const std::vector
91100
return new TDescribeSecretsActor(ownerUserId, secretIds, promise, maximalSecretsSnapshotWaitTime);
92101
}
93102

94-
void RegisterDescribeSecretsActor(const NActors::TActorId& replyActorId, const TString& ownerUserId, const std::vector<TString>& secretIds, const TActorContext& actorContext, TDuration maximalSecretsSnapshotWaitTime) {
103+
void RegisterDescribeSecretsActor(const NActors::TActorId& replyActorId, const TString& ownerUserId, const std::vector<TString>& secretIds, NActors::TActorSystem* actorSystem, TDuration maximalSecretsSnapshotWaitTime) {
95104
auto promise = NThreading::NewPromise<TEvDescribeSecretsResponse::TDescription>();
96-
actorContext.Register(CreateDescribeSecretsActor(ownerUserId, secretIds, promise, maximalSecretsSnapshotWaitTime));
105+
actorSystem->Register(CreateDescribeSecretsActor(ownerUserId, secretIds, promise, maximalSecretsSnapshotWaitTime));
97106

98-
promise.GetFuture().Subscribe([actorContext, replyActorId](const NThreading::TFuture<TEvDescribeSecretsResponse::TDescription>& result){
99-
actorContext.Send(replyActorId, new TEvDescribeSecretsResponse(result.GetValue()));
107+
promise.GetFuture().Subscribe([actorSystem, replyActorId](const NThreading::TFuture<TEvDescribeSecretsResponse::TDescription>& result){
108+
actorSystem->Send(replyActorId, new TEvDescribeSecretsResponse(result.GetValue()));
100109
});
101110
}
102111

112+
NThreading::TFuture<TEvDescribeSecretsResponse::TDescription> DescribeExternalDataSourceSecrets(const NKikimrSchemeOp::TAuth& authDescription, const TString& ownerUserId, TActorSystem* actorSystem, TDuration maximalSecretsSnapshotWaitTime) {
113+
switch (authDescription.identity_case()) {
114+
case NKikimrSchemeOp::TAuth::kServiceAccount: {
115+
const TString& saSecretId = authDescription.GetServiceAccount().GetSecretName();
116+
auto promise = NThreading::NewPromise<TEvDescribeSecretsResponse::TDescription>();
117+
actorSystem->Register(CreateDescribeSecretsActor(ownerUserId, {saSecretId}, promise, maximalSecretsSnapshotWaitTime));
118+
return promise.GetFuture();
119+
}
120+
121+
case NKikimrSchemeOp::TAuth::kNone:
122+
return NThreading::MakeFuture(TEvDescribeSecretsResponse::TDescription({}));
123+
124+
case NKikimrSchemeOp::TAuth::kBasic: {
125+
const TString& passwordSecretId = authDescription.GetBasic().GetPasswordSecretName();
126+
auto promise = NThreading::NewPromise<TEvDescribeSecretsResponse::TDescription>();
127+
actorSystem->Register(CreateDescribeSecretsActor(ownerUserId, {passwordSecretId}, promise, maximalSecretsSnapshotWaitTime));
128+
return promise.GetFuture();
129+
}
130+
131+
case NKikimrSchemeOp::TAuth::kMdbBasic: {
132+
const TString& saSecretId = authDescription.GetMdbBasic().GetServiceAccountSecretName();
133+
const TString& passwordSecreId = authDescription.GetMdbBasic().GetPasswordSecretName();
134+
auto promise = NThreading::NewPromise<TEvDescribeSecretsResponse::TDescription>();
135+
actorSystem->Register(CreateDescribeSecretsActor(ownerUserId, {saSecretId, passwordSecreId}, promise, maximalSecretsSnapshotWaitTime));
136+
return promise.GetFuture();
137+
}
138+
139+
case NKikimrSchemeOp::TAuth::kAws: {
140+
const TString& awsAccessKeyIdSecretId = authDescription.GetAws().GetAwsAccessKeyIdSecretName();
141+
const TString& awsAccessKeyKeySecretId = authDescription.GetAws().GetAwsSecretAccessKeySecretName();
142+
auto promise = NThreading::NewPromise<TEvDescribeSecretsResponse::TDescription>();
143+
actorSystem->Register(CreateDescribeSecretsActor(ownerUserId, {awsAccessKeyIdSecretId, awsAccessKeyKeySecretId}, promise, maximalSecretsSnapshotWaitTime));
144+
return promise.GetFuture();
145+
}
146+
147+
case NKikimrSchemeOp::TAuth::IDENTITY_NOT_SET:
148+
return NThreading::MakeFuture(TEvDescribeSecretsResponse::TDescription(Ydb::StatusIds::BAD_REQUEST, { NYql::TIssue("identity case is not specified") }));
149+
}
150+
}
151+
103152
} // namespace NKikimr::NKqp
Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
#pragma once
22

33
#include <ydb/core/kqp/common/events/script_executions.h>
4+
#include <ydb/core/protos/flat_scheme_op.pb.h>
45

56
#include <ydb/library/actors/core/actor.h>
67

78

89
namespace NKikimr::NKqp {
910

10-
NActors::IActor* CreateDescribeSecretsActor(const TString& ownerUserId, const std::vector<TString>& secretIds, NThreading::TPromise<TEvDescribeSecretsResponse::TDescription> promise, TDuration maximalSecretsSnapshotWaitTime);
11-
void RegisterDescribeSecretsActor(const NActors::TActorId& replyActorId, const TString& ownerUserId, const std::vector<TString>& secretIds, const TActorContext& actorContext, TDuration maximalSecretsSnapshotWaitTime);
11+
IActor* CreateDescribeSecretsActor(const TString& ownerUserId, const std::vector<TString>& secretIds, NThreading::TPromise<TEvDescribeSecretsResponse::TDescription> promise, TDuration maximalSecretsSnapshotWaitTime = TDuration::Zero());
12+
13+
void RegisterDescribeSecretsActor(const TActorId& replyActorId, const TString& ownerUserId, const std::vector<TString>& secretIds, TActorSystem* actorSystem, TDuration maximalSecretsSnapshotWaitTime = TDuration::Zero());
14+
15+
NThreading::TFuture<TEvDescribeSecretsResponse::TDescription> DescribeExternalDataSourceSecrets(const NKikimrSchemeOp::TAuth& authDescription, const TString& ownerUserId, TActorSystem* actorSystem, TDuration maximalSecretsSnapshotWaitTime = TDuration::Zero());
1216

1317
} // namespace NKikimr::NKqp

ydb/core/kqp/federated_query/ya.make

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ PEERDIR(
1212
ydb/library/db_pool/protos
1313
ydb/library/yql/providers/common/http_gateway
1414
ydb/library/yql/providers/generic/connector/libcpp
15+
ydb/services/metadata/secret
1516
)
1617

1718
YQL_LAST_ABI_VERSION()

ydb/core/kqp/finalize_script_service/kqp_finalize_script_actor.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ class TScriptFinalizerActor : public TActorBootstrapped<TScriptFinalizerActor> {
7575
}
7676

7777
void FetchSecrets() {
78-
RegisterDescribeSecretsActor(SelfId(), UserToken_, SecretNames_, ActorContext(), MaximalSecretsSnapshotWaitTime_);
78+
RegisterDescribeSecretsActor(SelfId(), UserToken_, SecretNames_, ActorContext().ActorSystem(), MaximalSecretsSnapshotWaitTime_);
7979
}
8080

8181
void Handle(TEvDescribeSecretsResponse::TPtr& ev) {

ydb/core/kqp/gateway/behaviour/external_data_source/manager.cpp

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#include "manager.h"
33

44
#include <ydb/core/tx/tx_proxy/proxy.h>
5+
#include <ydb/core/kqp/federated_query/kqp_federated_query_actors.h>
56
#include <ydb/core/kqp/gateway/actors/scheme.h>
67
#include <ydb/core/kqp/gateway/utils/scheme_helpers.h>
78
#include <ydb/core/kqp/provider/yql_kikimr_gateway.h>
@@ -140,6 +141,20 @@ NThreading::TFuture<TExternalDataSourceManager::TYqlConclusionStatus> SendScheme
140141
});
141142
}
142143

144+
NThreading::TFuture<TExternalDataSourceManager::TYqlConclusionStatus> ValidateCreateExternalDatasource(const NKikimrSchemeOp::TExternalDataSourceDescription& externaDataSourceDesc, const TExternalDataSourceManager::TInternalModificationContext& context) {
145+
const auto& authDescription = externaDataSourceDesc.GetAuth();
146+
const auto& externalData = context.GetExternalData();
147+
const auto& userToken = externalData.GetUserToken();
148+
auto describeFuture = DescribeExternalDataSourceSecrets(authDescription, userToken ? userToken->GetUserSID() : "", externalData.GetActorSystem());
149+
150+
return describeFuture.Apply([](const NThreading::TFuture<TEvDescribeSecretsResponse::TDescription>& f) mutable {
151+
if (const auto& value = f.GetValue(); value.Status != Ydb::StatusIds::SUCCESS) {
152+
return TExternalDataSourceManager::TYqlConclusionStatus::Fail(NYql::YqlStatusFromYdbStatus(value.Status), value.Issues.ToString());
153+
}
154+
return TExternalDataSourceManager::TYqlConclusionStatus::Success();
155+
});
156+
}
157+
143158
}
144159

145160
NThreading::TFuture<TExternalDataSourceManager::TYqlConclusionStatus> TExternalDataSourceManager::DoModify(const NYql::TObjectSettingsImpl& settings,
@@ -176,7 +191,14 @@ NThreading::TFuture<TExternalDataSourceManager::TYqlConclusionStatus> TExternalD
176191
auto& schemeTx = *ev->Record.MutableTransaction()->MutableModifyScheme();
177192
FillCreateExternalDataSourceCommand(schemeTx, settings, context);
178193

179-
return SendSchemeRequest(ev.Release(), context.GetExternalData().GetActorSystem(), schemeTx.GetFailedOnAlreadyExists(), schemeTx.GetSuccessOnNotExist());
194+
auto validationFuture = ValidateCreateExternalDatasource(schemeTx.GetCreateExternalDataSource(), context);
195+
196+
return validationFuture.Apply([ev = ev.Release(), context, schemeTx](const NThreading::TFuture<TExternalDataSourceManager::TYqlConclusionStatus>& f) {
197+
if (const auto& value = f.GetValue(); value.IsFail()) {
198+
return NThreading::MakeFuture(value);
199+
}
200+
return SendSchemeRequest(ev, context.GetExternalData().GetActorSystem(), schemeTx.GetFailedOnAlreadyExists(), schemeTx.GetSuccessOnNotExist());
201+
});
180202
}
181203

182204
NThreading::TFuture<TExternalDataSourceManager::TYqlConclusionStatus> TExternalDataSourceManager::DropExternalDataSource(const NYql::TDropObjectSettings& settings,
@@ -240,11 +262,15 @@ NThreading::TFuture<NMetadata::NModifications::IOperationsManager::TYqlConclusio
240262
ev->Record.SetUserToken(context.GetUserToken()->GetSerializedToken());
241263
}
242264

265+
auto validationFuture = NThreading::MakeFuture(TExternalDataSourceManager::TYqlConclusionStatus::Success());
243266
auto& schemeTx = *ev->Record.MutableTransaction()->MutableModifyScheme();
244267
switch (schemeOperation.GetOperationCase()) {
245-
case NKqpProto::TKqpSchemeOperation::kCreateExternalDataSource:
246-
schemeTx.CopyFrom(schemeOperation.GetCreateExternalDataSource());
268+
case NKqpProto::TKqpSchemeOperation::kCreateExternalDataSource: {
269+
const auto& createExternalDataSource = schemeOperation.GetCreateExternalDataSource();
270+
validationFuture = ValidateCreateExternalDatasource(createExternalDataSource.GetCreateExternalDataSource(), context);
271+
schemeTx.CopyFrom(createExternalDataSource);
247272
break;
273+
}
248274
case NKqpProto::TKqpSchemeOperation::kAlterExternalDataSource:
249275
schemeTx.CopyFrom(schemeOperation.GetAlterExternalDataSource());
250276
break;
@@ -256,7 +282,12 @@ NThreading::TFuture<NMetadata::NModifications::IOperationsManager::TYqlConclusio
256282
TStringBuilder() << "Execution of prepare operation for EXTERNAL_DATA_SOURCE object: unsupported operation: " << int(schemeOperation.GetOperationCase())));
257283
}
258284

259-
return SendSchemeRequest(ev.Release(), context.GetActorSystem(), schemeTx.GetFailedOnAlreadyExists(), schemeTx.GetSuccessOnNotExist());
285+
return validationFuture.Apply([ev = ev.Release(), context, schemeTx](const NThreading::TFuture<TExternalDataSourceManager::TYqlConclusionStatus>& f) {
286+
if (const auto& value = f.GetValue(); value.IsFail()) {
287+
return NThreading::MakeFuture(value);
288+
}
289+
return SendSchemeRequest(ev, context.GetActorSystem(), schemeTx.GetFailedOnAlreadyExists(), schemeTx.GetSuccessOnNotExist());
290+
});
260291
}
261292

262293
}

ydb/core/kqp/gateway/kqp_metadata_loader.cpp

Lines changed: 1 addition & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -460,43 +460,7 @@ void UpdateExternalDataSourceSecretsValue(TTableMetadataResult& externalDataSour
460460

461461
NThreading::TFuture<TEvDescribeSecretsResponse::TDescription> LoadExternalDataSourceSecretValues(const NSchemeCache::TSchemeCacheNavigate::TEntry& entry, const TIntrusiveConstPtr<NACLib::TUserToken>& userToken, TDuration maximalSecretsSnapshotWaitTime, TActorSystem* actorSystem) {
462462
const auto& authDescription = entry.ExternalDataSourceInfo->Description.GetAuth();
463-
switch (authDescription.identity_case()) {
464-
case NKikimrSchemeOp::TAuth::kServiceAccount: {
465-
const TString& saSecretId = authDescription.GetServiceAccount().GetSecretName();
466-
auto promise = NewPromise<TEvDescribeSecretsResponse::TDescription>();
467-
actorSystem->Register(CreateDescribeSecretsActor(userToken ? userToken->GetUserSID() : "", {saSecretId}, promise, maximalSecretsSnapshotWaitTime));
468-
return promise.GetFuture();
469-
}
470-
471-
case NKikimrSchemeOp::TAuth::kNone:
472-
return MakeFuture(TEvDescribeSecretsResponse::TDescription({}));
473-
474-
case NKikimrSchemeOp::TAuth::kBasic: {
475-
const TString& passwordSecretId = authDescription.GetBasic().GetPasswordSecretName();
476-
auto promise = NewPromise<TEvDescribeSecretsResponse::TDescription>();
477-
actorSystem->Register(CreateDescribeSecretsActor(userToken ? userToken->GetUserSID() : "", {passwordSecretId}, promise, maximalSecretsSnapshotWaitTime));
478-
return promise.GetFuture();
479-
}
480-
481-
case NKikimrSchemeOp::TAuth::kMdbBasic: {
482-
const TString& saSecretId = authDescription.GetMdbBasic().GetServiceAccountSecretName();
483-
const TString& passwordSecreId = authDescription.GetMdbBasic().GetPasswordSecretName();
484-
auto promise = NewPromise<TEvDescribeSecretsResponse::TDescription>();
485-
actorSystem->Register(CreateDescribeSecretsActor(userToken ? userToken->GetUserSID() : "", {saSecretId, passwordSecreId}, promise, maximalSecretsSnapshotWaitTime));
486-
return promise.GetFuture();
487-
}
488-
489-
case NKikimrSchemeOp::TAuth::kAws: {
490-
const TString& awsAccessKeyIdSecretId = authDescription.GetAws().GetAwsAccessKeyIdSecretName();
491-
const TString& awsAccessKeyKeySecretId = authDescription.GetAws().GetAwsSecretAccessKeySecretName();
492-
auto promise = NewPromise<TEvDescribeSecretsResponse::TDescription>();
493-
actorSystem->Register(CreateDescribeSecretsActor(userToken ? userToken->GetUserSID() : "", {awsAccessKeyIdSecretId, awsAccessKeyKeySecretId}, promise, maximalSecretsSnapshotWaitTime));
494-
return promise.GetFuture();
495-
}
496-
497-
case NKikimrSchemeOp::TAuth::IDENTITY_NOT_SET:
498-
return MakeFuture(TEvDescribeSecretsResponse::TDescription(Ydb::StatusIds::BAD_REQUEST, { NYql::TIssue("identity case is not specified") }));
499-
}
463+
return DescribeExternalDataSourceSecrets(authDescription, userToken ? userToken->GetUserSID() : "", actorSystem, maximalSecretsSnapshotWaitTime);
500464
}
501465

502466
} // anonymous namespace

ydb/core/kqp/provider/yql_kikimr_gateway_ut.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -497,6 +497,27 @@ Y_UNIT_TEST_SUITE(KikimrIcGateway) {
497497
UNIT_ASSERT_VALUES_EQUAL(response.Metadata->ExternalSource.Properties.GetProperties().at("use_tls"), "true");
498498
UNIT_ASSERT_VALUES_EQUAL(response.Metadata->ExternalSource.Properties.GetProperties().at("schema"), "public");
499499
}
500+
501+
Y_UNIT_TEST(TestSecretsExistingValidation) {
502+
TKikimrRunner kikimr;
503+
kikimr.GetTestServer().GetRuntime()->GetAppData(0).FeatureFlags.SetEnableExternalDataSources(true);
504+
auto db = kikimr.GetTableClient();
505+
auto session = db.CreateSession().GetValueSync().GetSession();
506+
507+
TString secretId = "unexisting_secret_name";
508+
auto query = TStringBuilder() << R"(
509+
CREATE EXTERNAL DATA SOURCE `/Root/ExternalDataSource` WITH (
510+
SOURCE_TYPE="ObjectStorage",
511+
LOCATION="localhost",
512+
AUTH_METHOD="SERVICE_ACCOUNT",
513+
SERVICE_ACCOUNT_ID="",
514+
SERVICE_ACCOUNT_SECRET_NAME=")" << secretId << R"("
515+
);)";
516+
517+
auto result = session.ExecuteSchemeQuery(query).GetValueSync();
518+
UNIT_ASSERT_C(result.GetStatus() == NYdb::EStatus::BAD_REQUEST, result.GetIssues().ToString());
519+
UNIT_ASSERT_STRING_CONTAINS(result.GetIssues().ToOneLineString(), TStringBuilder() << "secret with name '" << secretId << "' not found");
520+
}
500521
}
501522

502523
} // namespace NYql

ydb/core/kqp/ut/scheme/kqp_scheme_ut.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4675,6 +4675,8 @@ Y_UNIT_TEST_SUITE(KqpScheme) {
46754675
auto session = db.CreateSession().GetValueSync().GetSession();
46764676
TString externalDataSourceName = "/Root/ExternalDataSource";
46774677
auto query = TStringBuilder() << R"(
4678+
CREATE OBJECT mysasignature (TYPE SECRET) WITH (value = "mysasignaturevalue");
4679+
46784680
CREATE EXTERNAL DATA SOURCE `)" << externalDataSourceName << R"(` WITH (
46794681
SOURCE_TYPE="ObjectStorage",
46804682
LOCATION="my-bucket",

0 commit comments

Comments
 (0)