Skip to content

feat(s3): SigV4 pre-signed URL generation#80

Draft
Im5tu wants to merge 1 commit into
mainfrom
feat/s3-presigned-urls
Draft

feat(s3): SigV4 pre-signed URL generation#80
Im5tu wants to merge 1 commit into
mainfrom
feat/s3-presigned-urls

Conversation

@Im5tu

@Im5tu Im5tu commented Jul 7, 2026

Copy link
Copy Markdown
Owner

What

Adds AWS SigV4 pre-signed URL generation to the S3 client so object bytes can transfer directly to/from S3 via a time-limited URL, instead of being proxied through the calling application. The motivating case: moving large uploads/downloads off the ~6 MB AWS Lambda synchronous invoke limit.

Changes

  • Goa.Clients.Core: new public IRequestPresigner + PresignParameters, implemented by an internal RequestPresigner that produces query-string SigV4 signatures (X-Amz-Algorithm/Credential/Date/Expires/SignedHeaders/Security-Token/Signature) using the UNSIGNED-PAYLOAD content hash. Registered in AddGoaService.
  • Goa.Clients.S3: IS3Client.PresignGetObjectAsync and PresignPutObjectAsync, reusing the existing BuildObjectUri / ValidateBucketAndKey so the signed path matches the byte-exact S3 key encoding used by the header-signing path.
    • GET: optional response-content-type / response-content-disposition overrides (signed).
    • PUT: optional ContentLength binding — signs content-length so S3 rejects a differently-sized body, capping upload size.

Safety / correctness

  • Session tokens are included and signed; expiry is clamped to the SigV4 7-day maximum.
  • Caller-supplied reserved X-Amz-* query params and the host header are rejected (they are produced and signed internally); signed header values are whitespace-normalized per spec.
  • No reflection; builds clean under IsAotCompatible=true with warnings-as-errors.

Tests

  • Deterministic known-answer unit tests reproduce the AWS-documented example signature (aeeed9bb…), independently cross-checked — genuine proof of the canonicalization, string-to-sign, signing-key, and encoding. Also covers session-token encoding, extra-query-param encoding, expiry clamp, whitespace collapse, and the reserved-name guards. All passing.
  • LocalStack round-trip integration tests: presign PUT → upload → presign GET → download round-trips bytes, plus a response-content-disposition override check and a dot-segment key rejection. (Not run in the authoring environment — no Docker; runs in CI.)

Notes

  • The presigner currently signs the canonical URI with single URI-encoding (S3 style); double-encoding services are not yet supported (documented on the interface).

Add IRequestPresigner (query-string SigV4 signing, UNSIGNED-PAYLOAD) to
Goa.Clients.Core, and PresignGetObjectAsync / PresignPutObjectAsync to the
S3 client. This lets object bytes transfer directly to/from S3 via a
time-limited URL instead of being proxied through the caller (e.g. off the
6 MB Lambda invoke limit).

- GET presign supports response-content-type/-disposition overrides
- PUT presign can bind an exact content-length to cap upload size
- Session tokens are included and signed; expiry clamped to the 7-day max
- Reserved X-Amz-* query params and the host header are rejected from
  caller input; signed header values are whitespace-normalized per spec

Correctness is proven by a deterministic known-answer test reproducing the
AWS-documented example signature; LocalStack round-trip integration tests
cover end-to-end upload/download and response-header overrides.
@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e1b92e13-f20f-4e90-99db-c8e47ba704b6

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/s3-presigned-urls

Comment @coderabbitai help to get the list of available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant