Refactor BlobClient into a StorageBlobService following per-call subscription pattern
- Dominant language
- Go
- Stars
- 569
- Forks
- 364
- Avg merge
- 2d 19h
- Merged PRs (30d)
- 136
Description
## Summary
The current `BlobClient` in `cli/azd/pkg/azsdk/storage/` is architecturally unique compared to other Azure service clients in the codebase. It binds the subscription/tenant at **construction time** via `AccountConfig`, whereas all other services (KeyVault, ContainerApps, ContainerRegistry, AppService, etc.) accept `subscriptionId` **per-call** and store only a `SubscriptionCredentialProvider`.
### Current pattern (BlobClient — exception)
```go
// Constructor locks in subscription via AccountConfig
func NewBlobSdkClient(credentialProvider, accountConfig *AccountConfig, ...) (*azblob.Client, error)
// Methods have no subscription parameter
type BlobClient interface {
Download(ctx context.Context, blobPath string) (io.ReadCloser, error)
Upload(ctx context.Context, blobPath string, reader io.Reader) error
// ...
}
```
### Standard pattern (KeyVault, ContainerApps, etc.)
```go
// Constructor takes credential provider only
func NewKeyVaultService(credentialProvider, ...) KeyVaultService
// Methods accept subscriptionId per-call
GetKeyVault(ctx, subscriptionId, resourceGroup, vaultName) (*KeyVault, error)
```
Interestingly, `FileShareService` in the same storage package already follows the standard per-call pattern.
### Proposal
Refactor the blob storage abstraction into a `StorageBlobService` that:
1. Follows the per-call `subscriptionId` pattern used by other Azure services
2. Stores a `SubscriptionCredentialProvider` rather than pre-resolved credentials
3. Can be consumed by the remote state feature (and any future blob storage consumers) without being locked to a single subscription at construction time
This is a code & design improvement — the current implementation works correctly for its single use case (remote state), but consolidating the pattern improves consistency and future extensibility.
Contributor guide
Assessment
This issue has not been assessed yet.