diff --git a/objects/middleware.go b/objects/middleware.go
index efdb4b5..b14330e 100644
--- a/objects/middleware.go
+++ b/objects/middleware.go
@@ -7,9 +7,11 @@ import (
"net/http"
"github.com/aws/aws-sdk-go-v2/aws"
+ v4 "github.com/aws/aws-sdk-go-v2/aws/signer/v4"
"github.com/aws/aws-sdk-go-v2/credentials"
"github.com/aws/aws-sdk-go-v2/service/s3"
"github.com/aws/smithy-go/endpoints"
+ smithymw "github.com/aws/smithy-go/middleware"
"github.com/vaughan0/go-ini"
"git.sr.ht/~sircmpwn/core-go/config"
@@ -87,7 +89,19 @@ func NewClient(conf ini.File) (*s3.Client, error) {
return s3.NewFromConfig(aws.Config{
Region: region,
Credentials: creds,
- }, func(opts *s3.Options) {
+ }, s3.WithSigV4SigningRegion(region), func(opts *s3.Options) {
+ // Patched (phoebe-lab): pages Publish + builds artifact upload pass
+ // non-seekable bodies (tar.Reader, io.LimitReader) to PutObject. The
+ // SDK's default dynamic-payload middleware only uses UnsignedPayload
+ // over HTTPS; over HTTP (s3-insecure=true to internal Garage) it
+ // falls through to ComputePayloadSHA256, which seeks the body and
+ // fails. Force UnsignedPayload unconditionally. The above
+ // WithSigV4SigningRegion pins the sigv4 region so the V1 endpoint
+ // resolver doesn't override it back to "default".
+ opts.APIOptions = append(opts.APIOptions, func(stack *smithymw.Stack) error {
+ _, err := stack.Finalize.Swap("ComputePayloadHash", &v4.UnsignedPayload{})
+ return err
+ })
opts.BaseEndpoint = aws.String(scheme + upstream)
opts.EndpointResolverV2 = &S3Resolver{
conf,