diff --git a/CHANGELOG.md b/CHANGELOG.md index a974e9c..730e29d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ - Custom `# syntax=` directives no longer cause validation errors. () - Upgrading docker-build no longer causes resource replacements. () - Fixed leaking the GitHub actions secret in diff logs. () +- Provider panics when using Image resource with exec set to true. () ## 0.0.7 (2024-10-16) diff --git a/provider/internal/cache.go b/provider/internal/cache.go index d6695db..5ce462c 100644 --- a/provider/internal/cache.go +++ b/provider/internal/cache.go @@ -468,9 +468,8 @@ func (c CacheFrom) validate(preview bool) (*controllerapi.CacheOptionsEntry, err return nil, err } if len(parsed) == 0 { - // This can happen for example if we have a GHA cache but no GitHub - // environment variables set. - // Shouldn't happen... + // This can happen for example if we have a GHA cache configuration but no GitHub + // environment variables set. Ignore the cacheFrom entry in this case. return nil, nil } return parsed[0], nil @@ -677,9 +676,8 @@ func (c CacheTo) validate(preview bool) (*controllerapi.CacheOptionsEntry, error return nil, err } if len(parsed) == 0 { - // This can happen for example if we have a GHA cache but no GitHub - // environment variables set. - // Shouldn't happen... + // This can happen for example if we have a GHA cache configuration but no GitHub + // environment variables set. Ignore the cacheTo entry in this case. return nil, nil } return parsed[0], nil diff --git a/provider/internal/image.go b/provider/internal/image.go index 7bcacb9..04e532e 100644 --- a/provider/internal/image.go +++ b/provider/internal/image.go @@ -576,7 +576,9 @@ func (ia *ImageArgs) validate(supportsMultipleExports, preview bool) (controller multierr = errors.Join(multierr, newCheckFailure(err, "exports[%d]", idx)) continue } - exports = append(exports, exp) + if exp != nil { + exports = append(exports, exp) + } } platforms := []string{} @@ -586,7 +588,9 @@ func (ia *ImageArgs) validate(supportsMultipleExports, preview bool) (controller multierr = errors.Join(multierr, newCheckFailure(err, "platforms[%d]", idx)) continue } - platforms = append(platforms, platform) + if platform != "" { + platforms = append(platforms, platform) + } } cacheFrom := []*controllerapi.CacheOptionsEntry{} @@ -599,7 +603,9 @@ func (ia *ImageArgs) validate(supportsMultipleExports, preview bool) (controller multierr = errors.Join(multierr, newCheckFailure(err, "cacheFrom[%d]", idx)) continue } - cacheFrom = append(cacheFrom, cache) + if cache != nil { + cacheFrom = append(cacheFrom, cache) + } } cacheTo := []*controllerapi.CacheOptionsEntry{} @@ -612,7 +618,9 @@ func (ia *ImageArgs) validate(supportsMultipleExports, preview bool) (controller multierr = errors.Join(multierr, newCheckFailure(err, "cacheTo[%d]", idx)) continue } - cacheTo = append(cacheTo, cache) + if cache != nil { + cacheTo = append(cacheTo, cache) + } } ssh := []*controllerapi.SSH{} @@ -622,7 +630,9 @@ func (ia *ImageArgs) validate(supportsMultipleExports, preview bool) (controller multierr = errors.Join(multierr, newCheckFailure(err, "ssh[%d]", idx)) continue } - ssh = append(ssh, ss) + if ss != nil { + ssh = append(ssh, ss) + } } for idx, t := range normalized.Tags { diff --git a/provider/internal/image_test.go b/provider/internal/image_test.go index 6620700..6bba7de 100644 --- a/provider/internal/image_test.go +++ b/provider/internal/image_test.go @@ -25,6 +25,7 @@ import ( _ "github.com/docker/buildx/driver/docker-container" "github.com/distribution/reference" + pb "github.com/docker/buildx/controller/pb" "github.com/moby/buildkit/client" "github.com/moby/buildkit/exporter/containerimage/exptypes" "github.com/regclient/regclient/types/descriptor" @@ -818,7 +819,6 @@ func TestImageDiff(t *testing.T) { } func TestValidateImageArgs(t *testing.T) { - t.Parallel() t.Run("invalid inputs", func(t *testing.T) { t.Parallel() args := ImageArgs{ @@ -917,6 +917,85 @@ func TestValidateImageArgs(t *testing.T) { assert.Len(t, opts.Exports, 0) }) + t.Run("environment variables", func(t *testing.T) { + tests := []struct { + name string + envs map[string]string + args ImageArgs + wantCacheFrom *pb.CacheOptionsEntry + wantCacheTo *pb.CacheOptionsEntry + }{ + { + name: "gha environment", + envs: map[string]string{ + "ACTIONS_CACHE_URL": "test-cache-url", + "ACTIONS_RUNTIME_TOKEN": "test-runtime-token", + }, + args: ImageArgs{ + Context: &BuildContext{Context: Context{Location: "testdata/noop"}}, + CacheFrom: []CacheFrom{{GHA: &CacheFromGitHubActions{}}}, + CacheTo: []CacheTo{{GHA: &CacheToGitHubActions{ + CacheFromGitHubActions: CacheFromGitHubActions{}, + }}}, + }, + wantCacheFrom: &pb.CacheOptionsEntry{ + Type: "gha", + Attrs: map[string]string{ + "token": "test-runtime-token", + "url": "test-cache-url", + }, + }, + wantCacheTo: &pb.CacheOptionsEntry{ + Type: "gha", + Attrs: map[string]string{ + "token": "test-runtime-token", + "url": "test-cache-url", + }, + }, + }, + { + name: "non-gha environment", + envs: map[string]string{ + "ACTIONS_CACHE_URL": "", + "ACTIONS_RUNTIME_TOKEN": "", + }, + args: ImageArgs{ + Context: &BuildContext{Context: Context{Location: "testdata/noop"}}, + CacheFrom: []CacheFrom{{GHA: &CacheFromGitHubActions{}}}, + CacheTo: []CacheTo{{GHA: &CacheToGitHubActions{ + CacheFromGitHubActions: CacheFromGitHubActions{}, + }}}, + }, + wantCacheFrom: nil, + wantCacheTo: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + for k, v := range tt.envs { + t.Setenv(k, v) + } + validate := func(preview bool) { + opts, err := tt.args.validate(true, preview) + require.NoError(t, err) + if tt.wantCacheFrom != nil { + assert.Equal(t, tt.wantCacheFrom, opts.CacheFrom[0]) + } else { + assert.Len(t, opts.CacheFrom, 0) + } + if tt.wantCacheTo != nil { + assert.Equal(t, tt.wantCacheTo, opts.CacheTo[0]) + } else { + assert.Len(t, opts.CacheTo, 0) + } + } + validate(true) + validate(false) + }) + } + }) + t.Run("multiple exports pre-0.13", func(t *testing.T) { t.Parallel() args := ImageArgs{