// Copyright IBM Corp. 2020, 2026 // SPDX-License-Identifier: BUSL-1.1 package plugin import ( "github.com/hashicorp/boundary/internal/db/timestamp" "github.com/hashicorp/boundary/internal/oplog" "github.com/hashicorp/boundary/internal/storage/plugin/store" "github.com/hashicorp/boundary/internal/types/resource" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/structpb" ) // StorageBucket represents a bucket within an external object store. It contains secret // data needed to create and read objects within the external object store. type StorageBucket struct { *store.StorageBucket tableName string `gorm:"-"` Secrets *structpb.Struct `gorm:"-"` } func allocStorageBucket() *StorageBucket { return &StorageBucket{ StorageBucket: &store.StorageBucket{}, } } // clone provides a deep copy of the storage bucket with the exception of the // secret. The secret shallow copied. func (s *StorageBucket) clone() *StorageBucket { cp := proto.Clone(s.StorageBucket) newSecret := proto.Clone(s.Secrets) sb := &StorageBucket{ StorageBucket: cp.(*store.StorageBucket), Secrets: newSecret.(*structpb.Struct), } // proto.Clone will convert slices with length and capacity of 0 to nil. // Fix this since gorm treats empty slices differently than nil. if s.Attributes != nil && len(s.Attributes) == 0 && sb.Attributes == nil { sb.Attributes = []byte{} } return sb } // TableName returns the table name for the storage bucket. func (s *StorageBucket) TableName() string { if s.tableName != "" { return s.tableName } return "storage_plugin_storage_bucket" } // SetTableName sets the table name. func (s *StorageBucket) SetTableName(n string) { s.tableName = n } // GetResourceType implements the boundary.Resource interface. func (s *StorageBucket) GetResourceType() resource.Type { return resource.StorageBucket } func (s *StorageBucket) oplog(op oplog.OpType) oplog.Metadata { metadata := oplog.Metadata{ "resource-public-id": []string{s.PublicId}, "resource-type": []string{"plugin-storage-bucket"}, "op-type": []string{op.String()}, } if s.ScopeId != "" { metadata["scope-id"] = []string{s.ScopeId} } return metadata } type storageBucketAgg struct { PublicId string `gorm:"primary_key"` ScopeId string Name string Description string CreateTime *timestamp.Timestamp UpdateTime *timestamp.Timestamp Version uint32 PluginId string BucketName string BucketPrefix string WorkerFilter string Attributes []byte SecretsEncrypted []byte SecretsHmac []byte KeyId string StorageBucketCredentialId string } // TableName returns the table name for gorm func (sba *storageBucketAgg) TableName() string { return "storage_plugin_storage_bucket_with_secret" } func (sba *storageBucketAgg) GetPublicId() string { return sba.PublicId } func (sba *storageBucketAgg) toStorageBucketAndSBC() (*StorageBucket, error) { sb := allocStorageBucket() sb.PublicId = sba.PublicId sb.ScopeId = sba.ScopeId sb.Name = sba.Name sb.Description = sba.Description sb.CreateTime = sba.CreateTime sb.UpdateTime = sba.UpdateTime sb.Version = sba.Version sb.PluginId = sba.PluginId sb.BucketName = sba.BucketName sb.BucketPrefix = sba.BucketPrefix sb.WorkerFilter = sba.WorkerFilter sb.Attributes = sba.Attributes sb.SecretsHmac = sba.SecretsHmac sb.StorageBucketCredentialId = sba.StorageBucketCredentialId return sb, nil } type deletedStorageBucket struct { PublicId string `gorm:"primary_key"` DeleteTime *timestamp.Timestamp } // TableName returns the tablename to override the default gorm table name func (s *deletedStorageBucket) TableName() string { return "storage_plugin_storage_bucket_deleted" }