feat(storage): sign Azure layer-file uploads with a SAS - #3634
feat(storage): sign Azure layer-file uploads with a SAS#3634michalsuba-e2b wants to merge 1 commit into
Conversation
…load headers
Azure's Put Blob requires the request header "x-ms-blob-type: BlockBlob". A SAS can
only pin response headers, so no signed URL alone can satisfy it and the provider
refused to issue one at all — every template build with a COPY instruction failed on
Azure at the get-signed-URL step.
UploadSignedURL now returns {URL, Headers} instead of a bare URL, and the header
travels with the URL through the gRPC and public API responses for the upload client
to apply. Azure mints a create+write blob SAS with whichever credential the provider
already authenticated with: a user delegation key for a token credential (the managed
identity path), or the shared key when one is configured. A SAS-only connection string
can sign neither and now says so at construction and at the call. GCS, S3 and the
filesystem provider return nil headers and byte-identical URLs.
The proto and OpenAPI additions are additive — url stays optional, and a client that
ignores the new field parses the response unchanged.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
CI attribution, for the reviewer:
|
|
Live-environment validation on an Azure BYOC env (miso9), dev |
Stacked on #3633 (base is that branch; review only the second commit).
Azure's
Put Blobrequires the request headerx-ms-blob-type: BlockBlob, which a SAS cannot carry — it only pins response headers. The provider therefore refused to issue an upload URL at all, so every template build with aCOPYinstruction failed on Azure at the get-signed-URL step.UploadSignedURLnow returns{URL, Headers}instead of a bare URL, and the header travels with the URL throughInitLayerFileUploadResponse.uploadHeaders(proto field 3) andTemplateBuildFileUpload.headers(OpenAPI) for the upload client to apply. Azure mints a create+write blob SAS with whichever credential the provider already authenticated with: a user delegation key for a token credential (the managed-identity path), or the shared key when one is configured. A SAS-only connection string can sign neither and now says so at construction and at the call site. GCS, S3 and the filesystem provider return nil headers and byte-identical URLs.Additive on both contract surfaces:
urlstays optional,headers/uploadHeadersare new, and a client ignoring them parses the response unchanged. Consumers: the JS and Python SDKs (getFileUploadLink/build_api.py), which apply the headers in a follow-up PR on e2b-dev/E2B; edge and belt pass the gRPC response through schema-blind, so they need no change.Verification (all local,
go test -count=1):400, with the returned header →201and the blob reads back. Mutation-verified (drop the header from the response, the test fails).comp=userdelegationkeyfetch andskoid/sktid/sp=cw/spr=httpson the SAS. The RBAC grant behind that fetch is the one thing not exercisable locally.golangci-lintclean on the touched packages; orchestrator package tested with-racein a linux container.Not verified here: a live Azure deploy and a real multi-
COPYacceptance build.Sponsor: @michalsuba-e2b
🤖 Generated with Claude Code