diff --git a/bindings/gcp/bucket/bucket.go b/bindings/gcp/bucket/bucket.go index 155d96abe..027702f57 100644 --- a/bindings/gcp/bucket/bucket.go +++ b/bindings/gcp/bucket/bucket.go @@ -110,13 +110,7 @@ func (g *GCPStorage) Init(ctx context.Context, metadata bindings.Metadata) error return err } - b, err := json.Marshal(m) - if err != nil { - return err - } - - clientOptions := option.WithCredentialsJSON(b) - client, err := storage.NewClient(ctx, clientOptions) + client, err := g.getClient(ctx, m) if err != nil { return err } @@ -127,6 +121,41 @@ func (g *GCPStorage) Init(ctx context.Context, metadata bindings.Metadata) error return nil } +func (g *GCPStorage) getClient(ctx context.Context, m *gcpMetadata) (*storage.Client, error) { + var client *storage.Client + var err error + + if m.Bucket == "" { + return nil, errors.New("missing property `bucket` in metadata") + } + if m.ProjectID == "" { + return nil, errors.New("missing property `project_id` in metadata") + } + + // Explicit authentication + if m.PrivateKeyID != "" { + var b []byte + b, err = json.Marshal(m) + if err != nil { + return nil, err + } + + clientOptions := option.WithCredentialsJSON(b) + client, err = storage.NewClient(ctx, clientOptions) + if err != nil { + return nil, err + } + } else { + // Implicit authentication, using GCP Application Default Credentials (ADC) + // Credentials search order: https://cloud.google.com/docs/authentication/application-default-credentials#order + client, err = storage.NewClient(ctx) + if err != nil { + return nil, err + } + } + return client, nil +} + func (g *GCPStorage) parseMetadata(meta bindings.Metadata) (*gcpMetadata, error) { m := gcpMetadata{} err := kitmd.DecodeMetadata(meta.Properties, &m) diff --git a/bindings/gcp/bucket/bucket_test.go b/bindings/gcp/bucket/bucket_test.go index e5200c00c..09392f044 100644 --- a/bindings/gcp/bucket/bucket_test.go +++ b/bindings/gcp/bucket/bucket_test.go @@ -15,6 +15,7 @@ package bucket import ( "encoding/json" + "errors" "testing" "github.com/stretchr/testify/assert" @@ -234,6 +235,30 @@ func TestMergeWithRequestMetadata(t *testing.T) { }) } +func TestInit(t *testing.T) { + t.Run("Init missing bucket from metadata", func(t *testing.T) { + m := bindings.Metadata{} + m.Properties = map[string]string{ + "projectID": "my_project_id", + } + gs := GCPStorage{logger: logger.NewLogger("test")} + err := gs.Init(t.Context(), m) + require.Error(t, err) + assert.Equal(t, err, errors.New("missing property `bucket` in metadata")) + }) + + t.Run("Init missing projectID from metadata", func(t *testing.T) { + m := bindings.Metadata{} + m.Properties = map[string]string{ + "bucket": "my_bucket", + } + gs := GCPStorage{logger: logger.NewLogger("test")} + err := gs.Init(t.Context(), m) + require.Error(t, err) + assert.Equal(t, err, errors.New("missing property `project_id` in metadata")) + }) +} + func TestGetOption(t *testing.T) { gs := GCPStorage{logger: logger.NewLogger("test")} gs.metadata = &gcpMetadata{} diff --git a/secretstores/gcp/secretmanager/secretmanager.go b/secretstores/gcp/secretmanager/secretmanager.go index 19c795204..21d20566f 100644 --- a/secretstores/gcp/secretmanager/secretmanager.go +++ b/secretstores/gcp/secretmanager/secretmanager.go @@ -88,12 +88,38 @@ func (s *Store) Init(ctx context.Context, metadataRaw secretstores.Metadata) err } func (s *Store) getClient(ctx context.Context, metadata *GcpSecretManagerMetadata) (*secretmanager.Client, error) { - b, _ := json.Marshal(metadata) - clientOptions := option.WithCredentialsJSON(b) + var client *secretmanager.Client + var err error - client, err := secretmanager.NewClient(ctx, clientOptions) - if err != nil { - return nil, err + if metadata.ProjectID == "" { + return nil, errors.New("missing property `project_id` in metadata") + } + + // Explicit authentication + if metadata.PrivateKeyID != "" { + if metadata.Type == "" { + return nil, errors.New("missing property `type` in metadata") + } + if metadata.PrivateKey == "" { + return nil, errors.New("missing property `private_key` in metadata") + } + if metadata.ClientEmail == "" { + return nil, errors.New("missing property `client_email` in metadata") + } + + b, _ := json.Marshal(metadata) + clientOptions := option.WithCredentialsJSON(b) + client, err = secretmanager.NewClient(ctx, clientOptions) + if err != nil { + return nil, err + } + } else { + // Implicit authentication, using GCP Application Default Credentials (ADC) + // Credentials search order: https://cloud.google.com/docs/authentication/application-default-credentials#order + client, err = secretmanager.NewClient(ctx) + if err != nil { + return nil, err + } } return client, nil @@ -183,18 +209,9 @@ func (s *Store) parseSecretManagerMetadata(metadataRaw secretstores.Metadata) (* return nil, fmt.Errorf("failed to decode metadata: %w", err) } - if meta.Type == "" { - return nil, errors.New("missing property `type` in metadata") - } if meta.ProjectID == "" { return nil, errors.New("missing property `project_id` in metadata") } - if meta.PrivateKey == "" { - return nil, errors.New("missing property `private_key` in metadata") - } - if meta.ClientEmail == "" { - return nil, errors.New("missing property `client_email` in metadata") - } return &meta, nil } diff --git a/secretstores/gcp/secretmanager/secretmanager_test.go b/secretstores/gcp/secretmanager/secretmanager_test.go index f8cb74dd0..1c478dd9d 100644 --- a/secretstores/gcp/secretmanager/secretmanager_test.go +++ b/secretstores/gcp/secretmanager/secretmanager_test.go @@ -76,11 +76,38 @@ func TestInit(t *testing.T) { t.Run("Init with missing `type` metadata", func(t *testing.T) { m.Properties = map[string]string{ - "dummy": "a", + "dummy": "a", + "private_key_id": "a", + "project_id": "a", } err := sm.Init(ctx, m) require.Error(t, err) - assert.Equal(t, err, errors.New("missing property `type` in metadata")) + assert.Equal(t, errors.New("failed to setup secretmanager client: missing property `type` in metadata"), err) + }) + + t.Run("Init with missing `private_key` metadata", func(t *testing.T) { + m.Properties = map[string]string{ + "dummy": "a", + "private_key_id": "a", + "type": "a", + "project_id": "a", + } + err := sm.Init(ctx, m) + require.Error(t, err) + assert.Equal(t, errors.New("failed to setup secretmanager client: missing property `private_key` in metadata"), err) + }) + + t.Run("Init with missing `client_email` metadata", func(t *testing.T) { + m.Properties = map[string]string{ + "dummy": "a", + "private_key_id": "a", + "private_key": "a", + "type": "a", + "project_id": "a", + } + err := sm.Init(ctx, m) + require.Error(t, err) + assert.Equal(t, errors.New("failed to setup secretmanager client: missing property `client_email` in metadata"), err) }) t.Run("Init with missing `project_id` metadata", func(t *testing.T) { @@ -91,6 +118,22 @@ func TestInit(t *testing.T) { require.Error(t, err) assert.Equal(t, err, errors.New("missing property `project_id` in metadata")) }) + + t.Run("Init with missing `project_id` metadata", func(t *testing.T) { + m.Properties = map[string]string{ + "type": "service_account", + } + err := sm.Init(ctx, m) + require.Error(t, err) + assert.Equal(t, err, errors.New("missing property `project_id` in metadata")) + }) + + t.Run("Init with empty metadata", func(t *testing.T) { + m.Properties = map[string]string{} + err := sm.Init(ctx, m) + require.Error(t, err) + assert.Equal(t, err, errors.New("missing property `project_id` in metadata")) + }) } func TestGetSecret(t *testing.T) { diff --git a/state/alicloud/tablestore/mock_client.go b/state/alicloud/tablestore/mock_client.go index f29678525..4718c2d83 100644 --- a/state/alicloud/tablestore/mock_client.go +++ b/state/alicloud/tablestore/mock_client.go @@ -16,6 +16,7 @@ package tablestore import ( "bytes" "encoding/binary" + "sync" "github.com/aliyun/aliyun-tablestore-go-sdk/tablestore" ) @@ -24,6 +25,7 @@ type mockClient struct { tablestore.TableStoreClient data map[string][]byte + mu sync.RWMutex } func (m *mockClient) DeleteRow(request *tablestore.DeleteRowRequest) (*tablestore.DeleteRowResponse, error) { @@ -36,7 +38,9 @@ func (m *mockClient) DeleteRow(request *tablestore.DeleteRowRequest) (*tablestor } } + m.mu.Lock() delete(m.data, key) + m.mu.Unlock() return nil, nil } @@ -51,7 +55,9 @@ func (m *mockClient) GetRow(request *tablestore.GetRowRequest) (*tablestore.GetR } } + m.mu.RLock() val := m.data[key] + m.mu.RUnlock() resp := &tablestore.GetRowResponse{ Columns: []*tablestore.AttributeColumn{{ @@ -87,7 +93,9 @@ func (m *mockClient) UpdateRow(req *tablestore.UpdateRowRequest) (*tablestore.Up } } + m.mu.Lock() m.data[key] = val + m.mu.Unlock() return nil, nil } @@ -97,6 +105,7 @@ func (m *mockClient) BatchGetRow(request *tablestore.BatchGetRowRequest) (*table TableToRowsResult: map[string][]tablestore.RowResult{}, } + m.mu.RLock() for _, criteria := range request.MultiRowQueryCriteria { tableRes := resp.TableToRowsResult[criteria.TableName] if tableRes == nil { @@ -136,12 +145,14 @@ func (m *mockClient) BatchGetRow(request *tablestore.BatchGetRowRequest) (*table } } } + m.mu.RUnlock() return resp, nil } func (m *mockClient) BatchWriteRow(request *tablestore.BatchWriteRowRequest) (*tablestore.BatchWriteRowResponse, error) { resp := &tablestore.BatchWriteRowResponse{} + m.mu.Lock() for _, changes := range request.RowChangesGroupByTable { for _, change := range changes { switch inst := change.(type) { @@ -174,6 +185,7 @@ func (m *mockClient) BatchWriteRow(request *tablestore.BatchWriteRowRequest) (*t } } } + m.mu.Unlock() return resp, nil } diff --git a/state/oracledatabase/oracledatabaseaccess.go b/state/oracledatabase/oracledatabaseaccess.go index 9a62ce6d4..fdd5374a5 100644 --- a/state/oracledatabase/oracledatabaseaccess.go +++ b/state/oracledatabase/oracledatabaseaccess.go @@ -514,8 +514,16 @@ func (o *oracleDatabaseAccess) ensureStateTable(stateTableName string) error { } func tableExists(db *sql.DB, tableName string) (bool, error) { - var tblCount int32 - err := db.QueryRow("SELECT count(table_name) tbl_count FROM user_tables WHERE table_name = upper(:tablename)", tableName).Scan(&tblCount) - exists := tblCount > 0 - return exists, err + //nolint:gosec + query := fmt.Sprintf("SELECT 1 FROM %s WHERE ROWNUM = 1", tableName) + + var dummy int + err := db.QueryRow(query).Scan(&dummy) + if err != nil { + if errors.Is(err, sql.ErrNoRows) { + return true, nil // Table exists but is empty + } + return false, nil // Likely a table does not exist error + } + return true, nil }