Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 14 additions & 7 deletions internal/pullbox/s3/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,23 +22,31 @@ const (
region = "us-east-2"
)

func assumeRole(ctx context.Context, c *devopt.Credentials) (*aws.Config, error) {
noPermsConfig, _ := config.LoadDefaultConfig(ctx)
func assumeRole(ctx context.Context, cred *devopt.Credentials) (*aws.Config, error) {
// STS needs an explicit region to resolve its endpoint. Without one,
// users who don't have an AWS region configured in their environment hit
// "Invalid Configuration: Missing Region" when running `devbox global
// push`. Pin it to the bucket's region, same as the config below.
noPermsConfig, err := config.LoadDefaultConfig(ctx, config.WithRegion(region))
if err != nil {
return nil, errors.WithStack(err)
}
stsClient := sts.NewFromConfig(noPermsConfig)
creds, err := stsClient.AssumeRoleWithWebIdentity(
ctx,
&sts.AssumeRoleWithWebIdentityInput{
RoleArn: aws.String(roleArn),
RoleSessionName: aws.String(c.Email),
WebIdentityToken: aws.String(c.IDToken),
RoleSessionName: aws.String(cred.Email),
WebIdentityToken: aws.String(cred.IDToken),
},
)
if err != nil {
return nil, err
}

config, err := config.LoadDefaultConfig(
cfg, err := config.LoadDefaultConfig(
ctx,
config.WithRegion(region),
config.WithCredentialsProvider(
credentials.NewStaticCredentialsProvider(
*creds.Credentials.AccessKeyId,
Expand All @@ -47,9 +55,8 @@ func assumeRole(ctx context.Context, c *devopt.Credentials) (*aws.Config, error)
),
),
)
config.Region = region
if err != nil {
return nil, errors.WithStack(err)
}
return &config, err
return &cfg, nil
}
53 changes: 53 additions & 0 deletions internal/pullbox/s3/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package s3

import (
"testing"

"github.com/aws/aws-sdk-go-v2/config"
)

// TestConfigPinsRegion guards against a regression of jetify-com/devbox#2591,
// where `devbox global push` failed with "Invalid Configuration: Missing
// Region" for users who had no AWS region configured in their environment.
//
// assumeRole builds AWS configs (for both the STS and S3 clients) that must
// explicitly pin the region, since neither STS nor S3 can resolve an endpoint
// without one. This test reproduces the reporter's environment (no region
// configured anywhere) and verifies that pinning the region via
// config.WithRegion(region) still yields a config with the expected region.
func TestConfigPinsRegion(t *testing.T) {
if region == "" {
t.Fatal("region constant must not be empty; STS/S3 endpoint resolution requires it")
}

// Simulate a user with no AWS region configured anywhere: clear the
// region environment variables and point the shared config/credentials
// files at nonexistent paths so no ambient region leaks in.
t.Setenv("AWS_REGION", "")
t.Setenv("AWS_DEFAULT_REGION", "")
t.Setenv("AWS_CONFIG_FILE", "/dev/null")
t.Setenv("AWS_SHARED_CREDENTIALS_FILE", "/dev/null")

ctx := t.Context()

// Without an explicit region, the loaded config has no region. This is the
// condition that produced the "Missing Region" error before the fix.
noRegion, err := config.LoadDefaultConfig(ctx)
if err != nil {
t.Fatalf("loading default config: %v", err)
}
if noRegion.Region != "" {
t.Skipf("test environment provides a default AWS region (%q); "+
"cannot exercise the missing-region case", noRegion.Region)
}

// With the region pinned (as assumeRole now does for both configs), the
// region is set regardless of the environment.
pinned, err := config.LoadDefaultConfig(ctx, config.WithRegion(region))
if err != nil {
t.Fatalf("loading config with pinned region: %v", err)
}
if pinned.Region != region {
t.Errorf("pinned region = %q, want %q", pinned.Region, region)
}
}
Loading