ronantakizawa/codereview-bench huggingface dataset:
Repository: helm/helm
File: pkg/lint/rules/crds_test.go (Go)

Code before:
import (
	"strings"
	"testing"

	"helm.sh/helm/v4/pkg/lint/support"
)

const crdsTestBaseDir = "./testdata/withcrd"
const invalidCrdsDir = "./testdata/invalidcrdsdir"

func TestCrdsDir(t *testing.T) {
	linter := support.Linter{ChartDir: crdsTestBaseDir}
	Crds(&linter)
	res := linter.Messages

	if len(res) > 0 {
		t.Fatalf("Expected no errors, got %d, %v", len(res), res)
	}
}

func TestInvalidCrdsDir(t *testing.T) {
	linter := support.Linter{ChartDir: invalidCrdsDir}
	Crds(&linter)
	res := linter.Messages

	if len(res) != 1 {
		t.Fatalf("Expected one error, got %d, %v", len(res), res)
	}

	if !strings.Contains(res[0].Err.Error(), "not a directory") {
		t.Errorf("Unexpected error: %s", res[0])
	}
}


Review comment (suggestion):
similar to above:

```
assert.Len(t, res, 1)
```

Code after:
/*
Copyright The Helm Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package rules

import (
	"testing"

	"github.com/stretchr/testify/assert"

	"helm.sh/helm/v4/pkg/lint/support"
)

const invalidCrdsDir = "./testdata/invalidcrdsdir"

func TestInvalidCrdsDir(t *testing.T) {
	linter := support.Linter{ChartDir: invalidCrdsDir}
	Crds(&linter)
	res := linter.Messages

	assert.Len(t, res, 1)
	assert.ErrorContains(t, res[0].Err, "not a directory")
}
Repository: helm/helm
File: pkg/lint/rules/crds_test.go (Go)

Code before:

const crdsTestBaseDir = "./testdata/withcrd"
const invalidCrdsDir = "./testdata/invalidcrdsdir"

func TestCrdsDir(t *testing.T) {
	linter := support.Linter{ChartDir: crdsTestBaseDir}
	Crds(&linter)
	res := linter.Messages

	if len(res) > 0 {
		t.Fatalf("Expected no errors, got %d, %v", len(res), res)
	}
}

func TestInvalidCrdsDir(t *testing.T) {
	linter := support.Linter{ChartDir: invalidCrdsDir}
	Crds(&linter)
	res := linter.Messages

	if len(res) != 1 {
		t.Fatalf("Expected one error, got %d, %v", len(res), res)
	}

	if !strings.Contains(res[0].Err.Error(), "not a directory") {
		t.Errorf("Unexpected error: %s", res[0])
	}
}


Review comment (suggestion):
similar:
```
assert.ErrorContains(t, err, "not a directory")
```

Code after:
/*
Copyright The Helm Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package rules

import (
	"testing"

	"github.com/stretchr/testify/assert"

	"helm.sh/helm/v4/pkg/lint/support"
)

const invalidCrdsDir = "./testdata/invalidcrdsdir"

func TestInvalidCrdsDir(t *testing.T) {
	linter := support.Linter{ChartDir: invalidCrdsDir}
	Crds(&linter)
	res := linter.Messages

	assert.Len(t, res, 1)
	assert.ErrorContains(t, res[0].Err, "not a directory")
}
Repository: helm/helm
File: internal/fileutil/fileutil.go (Go)

Code before:
	}

	if err := tempFile.Close(); err != nil {
		return err
	}

	if err := os.Chmod(tempName, mode); err != nil {
		return err
	}

	return fs.RenameWithFallback(tempName, filename)
}

// LockedAtomicWriteFile atomically writes a file to disk with file locking to prevent
// concurrent writes. This is particularly useful on Windows where concurrent writes
// to the same file can cause "Access Denied" errors.
//
// The function acquires a lock on the target file, checks if it already exists,
// and only writes if it doesn't exist. This prevents duplicate work when multiple
// processes try to write the same file simultaneously.
//
// Returns true if the file was written, false if it already existed.
func LockedAtomicWriteFile(filename string, reader io.Reader, mode os.FileMode) (bool, error) {
	// Acquire a file lock for this specific file path to prevent concurrent writes
	fileLock := flock.New(filename + ".lock")
	if err := fileLock.Lock(); err != nil {
		return false, err
	}
	defer fileLock.Unlock()

	// Check if the file already exists (another process might have already written it)
	if _, err := os.Stat(filename); err == nil {
		// File already exists, skip writing
		return false, nil
	}

	// File doesn't exist, write it atomically
	if err := AtomicWriteFile(filename, reader, mode); err != nil {
		return false, err
	}

	return true, nil
}


Review comment (bug):
Should this to a `fileLock.TryLock()` instead? If that fails, it is probably being written by another thread/process would be my understanding.

I'm not entirely sure how flock works, but couldn't you just use the file as the lock file?

Messing around with flock on mac and `fileLock` file is not removed so this will leave junk around.



Code after:
/*
Copyright The Helm Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package fileutil

import (
	"io"
	"os"
	"path/filepath"

	"helm.sh/helm/v4/internal/third_party/dep/fs"
)

// AtomicWriteFile atomically (as atomic as os.Rename allows) writes a file to a
// disk.
func AtomicWriteFile(filename string, reader io.Reader, mode os.FileMode) error {
	tempFile, err := os.CreateTemp(filepath.Split(filename))
	if err != nil {
		return err
	}
	tempName := tempFile.Name()

	if _, err := io.Copy(tempFile, reader); err != nil {
		tempFile.Close() // return value is ignored as we are already on error path
		return err
	}

	if err := tempFile.Close(); err != nil {
		return err
	}

	if err := os.Chmod(tempName, mode); err != nil {
		return err
	}

	return fs.RenameWithFallback(tempName, filename)
}
Repository: helm/helm
File: internal/fileutil/fileutil.go (Go)

Code before:

	if err := os.Chmod(tempName, mode); err != nil {
		return err
	}

	return fs.RenameWithFallback(tempName, filename)
}

// LockedAtomicWriteFile atomically writes a file to disk with file locking to prevent
// concurrent writes. This is particularly useful on Windows where concurrent writes
// to the same file can cause "Access Denied" errors.
//
// The function acquires a lock on the target file, checks if it already exists,
// and only writes if it doesn't exist. This prevents duplicate work when multiple
// processes try to write the same file simultaneously.
//
// Returns true if the file was written, false if it already existed.
func LockedAtomicWriteFile(filename string, reader io.Reader, mode os.FileMode) (bool, error) {
	// Acquire a file lock for this specific file path to prevent concurrent writes
	fileLock := flock.New(filename + ".lock")
	if err := fileLock.Lock(); err != nil {
		return false, err
	}
	defer fileLock.Unlock()

	// Check if the file already exists (another process might have already written it)
	if _, err := os.Stat(filename); err == nil {
		// File already exists, skip writing
		return false, nil
	}

	// File doesn't exist, write it atomically
	if err := AtomicWriteFile(filename, reader, mode); err != nil {
		return false, err
	}

	return true, nil
}


Review comment (suggestion):
If you use TryLock, you'd probably want to change this to look the returned `FileInfo.Size()` here.

Code after:
/*
Copyright The Helm Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package fileutil

import (
	"io"
	"os"
	"path/filepath"

	"helm.sh/helm/v4/internal/third_party/dep/fs"
)

// AtomicWriteFile atomically (as atomic as os.Rename allows) writes a file to a
// disk.
func AtomicWriteFile(filename string, reader io.Reader, mode os.FileMode) error {
	tempFile, err := os.CreateTemp(filepath.Split(filename))
	if err != nil {
		return err
	}
	tempName := tempFile.Name()

	if _, err := io.Copy(tempFile, reader); err != nil {
		tempFile.Close() // return value is ignored as we are already on error path
		return err
	}

	if err := tempFile.Close(); err != nil {
		return err
	}

	if err := os.Chmod(tempName, mode); err != nil {
		return err
	}

	return fs.RenameWithFallback(tempName, filename)
}
Repository: helm/helm
File: internal/fileutil/fileutil_unix.go (Go)

Code before:
package fileutil

import (
	"io"
	"os"
)

// LockedAtomicWriteFile atomically writes a file to disk.
//
// On non-Windows platforms, this is a simple wrapper around AtomicWriteFile
// since concurrent file access errors are not an issue on Unix-like systems.
//
// Returns true if the file was written, false if it already existed.
func LockedAtomicWriteFile(filename string, reader io.Reader, mode os.FileMode) (bool, error) {
	// Check if the file already exists
	if _, err := os.Stat(filename); err == nil {
		// File already exists, skip writing
		return false, nil
	}

	// File doesn't exist, write it atomically
	if err := AtomicWriteFile(filename, reader, mode); err != nil {
		return false, err
	}

	return true, nil
}


Review comment (suggestion):
I'd be curious what others think, but I'd be inclined to go this direction to preserve current behavior.
```suggestion
	return true, AtomicWriteFile(filename, reader, mode)
```

Another thing is this is not locked at all. Since we are ignoring the written bool, maybe call this something like `PlatformAtomicWriteFile`  and it just calls `AtomicWriteFile` here and `LockedAtomicWriteFile` for windows.

Code after:
//go:build !windows

/*
Copyright The Helm Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package fileutil

import (
	"io"
	"os"
)

// PlatformAtomicWriteFile atomically writes a file to disk.
//
// On non-Windows platforms we don't need extra coordination, so this simply
// delegates to AtomicWriteFile to preserve the existing overwrite behaviour.
func PlatformAtomicWriteFile(filename string, reader io.Reader, mode os.FileMode) error {
	return AtomicWriteFile(filename, reader, mode)
}
Repository: helm/helm
File: pkg/provenance/sign_test.go (Go)

Code before:

func (s failSigner) Sign(_ io.Reader, _ []byte, _ crypto.SignerOpts) ([]byte, error) {
	return nil, fmt.Errorf("always fails")
}

func TestClearSignError(t *testing.T) {
	signer, err := NewFromFiles(testKeyfile, testPubfile)
	if err != nil {
		t.Fatal(err)
	}

	// ensure that signing always fails
	signer.Entity.PrivateKey.PrivateKey = failSigner{}

	metadataBytes := loadChartMetadataForSigning(t, testChartfile)

	// Read the chart file data
	archiveData, err := os.ReadFile(testChartfile)
	if err != nil {
		t.Fatal(err)
	}

	sig, err := signer.ClearSign(archiveData, filepath.Base(testChartfile), metadataBytes)
	if err == nil {
		t.Fatal("didn't get an error from ClearSign but expected one")
	}

	if sig != "" {
		t.Fatalf("expected an empty signature after failed ClearSign but got %q", sig)
	}
}

func TestVerify(t *testing.T) {
	signer, err := NewFromFiles(testKeyfile, testPubfile)
	if err != nil {
		t.Fatal(err)
	}

	// Read the chart file data
	archiveData, err := os.ReadFile(testChartfile)
	if err != nil {
		t.Fatal(err)
	}

	// Read the signature file data
	sigData, err := os.ReadFile(testSigBlock)
	if err != nil {
		t.Fatal(err)
	}

	if ver, err := signer.Verify(archiveData, sigData, filepath.Base(testChartfile)); err != nil {

Review comment (suggestion):
I think this could have been written something like (for future reference):
```
hasEdDSA := slices.ContainsFunc(signer.KeyRing, func(entity Entity) {
   if entity.PrimaryKey != nil && entity.PrimaryKey.PubKeyAlgo == packet.PubKeyAlgoEdDSA) {
     return true
   }
     
   return slices.Contains(entity.Subkeys, func(subkey SubKey) {
     return subkey.PublicKey != nil && subkey.PublicKey.PubKeyAlgo == packet.PubKeyAlgoEdDSA
   })
})
```

(a lot more compact and tidy IMHO)

Code after:
	if err != nil {
		t.Fatal(err)
	}

	if len(signer.KeyRing) == 0 {
		t.Fatal("expected signer keyring to be loaded")
	}

	hasEdDSA := false
	for _, entity := range signer.KeyRing {
		if entity.PrimaryKey != nil && entity.PrimaryKey.PubKeyAlgo == packet.PubKeyAlgoEdDSA {
			hasEdDSA = true
			break
		}

		for _, subkey := range entity.Subkeys {
			if subkey.PublicKey != nil && subkey.PublicKey.PubKeyAlgo == packet.PubKeyAlgoEdDSA {
				hasEdDSA = true
				break
			}
		}

		if hasEdDSA {
			break
		}
	}

	if !hasEdDSA {
		t.Fatalf("expected %s to include an Ed25519 public key", testMixedKeyring)
	}

	if signer.Entity == nil {
		t.Fatal("expected signer entity to be loaded")
	}

	if signer.Entity.PrivateKey == nil {
		t.Fatal("expected signer private key to be loaded")
	}

	if signer.Entity.PrivateKey.PubKeyAlgo != packet.PubKeyAlgoRSA {
		t.Fatalf("expected RSA key but got %v", signer.Entity.PrivateKey.PubKeyAlgo)
	}

	metadataBytes := loadChartMetadataForSigning(t, testChartfile)

	archiveData, err := os.ReadFile(testChartfile)
	if err != nil {
		t.Fatal(err)
	}

	sig, err := signer.ClearSign(archiveData, filepath.Base(testChartfile), metadataBytes)
Repository: helm/helm
File: pkg/provenance/sign_test.go (Go)

Code before:

func TestClearSignError(t *testing.T) {
	signer, err := NewFromFiles(testKeyfile, testPubfile)
	if err != nil {
		t.Fatal(err)
	}

	// ensure that signing always fails
	signer.Entity.PrivateKey.PrivateKey = failSigner{}

	metadataBytes := loadChartMetadataForSigning(t, testChartfile)

	// Read the chart file data
	archiveData, err := os.ReadFile(testChartfile)
	if err != nil {
		t.Fatal(err)
	}

	sig, err := signer.ClearSign(archiveData, filepath.Base(testChartfile), metadataBytes)
	if err == nil {
		t.Fatal("didn't get an error from ClearSign but expected one")
	}

	if sig != "" {
		t.Fatalf("expected an empty signature after failed ClearSign but got %q", sig)
	}
}

func TestVerify(t *testing.T) {
	signer, err := NewFromFiles(testKeyfile, testPubfile)
	if err != nil {
		t.Fatal(err)
	}

	// Read the chart file data
	archiveData, err := os.ReadFile(testChartfile)
	if err != nil {
		t.Fatal(err)
	}

	// Read the signature file data
	sigData, err := os.ReadFile(testSigBlock)
	if err != nil {
		t.Fatal(err)
	}

	if ver, err := signer.Verify(archiveData, sigData, filepath.Base(testChartfile)); err != nil {
		t.Errorf("Failed to pass verify. Err: %s", err)
	} else if len(ver.FileHash) == 0 {
		t.Error("Verification is missing hash.")
	} else if ver.SignedBy == nil {

Review comment (suggestion):
testify/assert would clean these up:

```
assert.True(t, hasEdDSA)
```

and e.g. below
```
assert.NotNil(t, signer.Entity)
```

(messages become optional IMHO, as the single line assert typically conveys enough info)

Code after:
	if len(signer.KeyRing) == 0 {
		t.Fatal("expected signer keyring to be loaded")
	}

	hasEdDSA := false
	for _, entity := range signer.KeyRing {
		if entity.PrimaryKey != nil && entity.PrimaryKey.PubKeyAlgo == packet.PubKeyAlgoEdDSA {
			hasEdDSA = true
			break
		}

		for _, subkey := range entity.Subkeys {
			if subkey.PublicKey != nil && subkey.PublicKey.PubKeyAlgo == packet.PubKeyAlgoEdDSA {
				hasEdDSA = true
				break
			}
		}

		if hasEdDSA {
			break
		}
	}

	if !hasEdDSA {
		t.Fatalf("expected %s to include an Ed25519 public key", testMixedKeyring)
	}

	if signer.Entity == nil {
		t.Fatal("expected signer entity to be loaded")
	}

	if signer.Entity.PrivateKey == nil {
		t.Fatal("expected signer private key to be loaded")
	}

	if signer.Entity.PrivateKey.PubKeyAlgo != packet.PubKeyAlgoRSA {
		t.Fatalf("expected RSA key but got %v", signer.Entity.PrivateKey.PubKeyAlgo)
	}

	metadataBytes := loadChartMetadataForSigning(t, testChartfile)

	archiveData, err := os.ReadFile(testChartfile)
	if err != nil {
		t.Fatal(err)
	}

	sig, err := signer.ClearSign(archiveData, filepath.Base(testChartfile), metadataBytes)
	if err != nil {
		t.Fatalf("failed to sign chart: %v", err)
	}
Repository: helm/helm
File: pkg/kube/client_test.go (Go)

Code before:
			require.NoError(t, err)

			require.Len(t, resourceList, 1)
			info := resourceList[0]

			err = patchResourceServerSide(info, tc.DryRun, tc.ForceConflicts, tc.FieldValidationDirective)
			if tc.ExpectedErrorContains != "" {
				require.ErrorContains(t, err, tc.ExpectedErrorContains)
			} else {
				require.NoError(t, err)
				require.NotNil(t, info.Object)
			}
		})
	}
}

func TestDetermineFieldValidationDirective(t *testing.T) {

	assert.Equal(t, FieldValidationDirectiveIgnore, determineFieldValidationDirective(false))
	assert.Equal(t, FieldValidationDirectiveStrict, determineFieldValidationDirective(true))
}

func TestClientWaitContextCancellationLegacy(t *testing.T) {
	podList := newPodList("starfish", "otter")

	ctx, cancel := context.WithCancel(context.Background())

	c := newTestClient(t)
	c.WaitContext = ctx

	requestCount := 0
	c.Factory.(*cmdtesting.TestFactory).Client = &fake.RESTClient{
		NegotiatedSerializer: unstructuredSerializer,
		Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
			requestCount++
			p, m := req.URL.Path, req.Method
			t.Logf("got request %s %s", p, m)

			if requestCount == 2 {
				cancel()
			}

			switch {
			case p == "/api/v1/namespaces/default/pods/starfish" && m == http.MethodGet:
				pod := &podList.Items[0]
				pod.Status.Conditions = []v1.PodCondition{
					{
						Type:   v1.PodReady,
						Status: v1.ConditionFalse,
					},
				}

Review comment (suggestion):
```suggestion
	ctx, cancel := context.WithCancel(t.Context())
```

Code after:
			require.NoError(t, err)

			require.Len(t, resourceList, 1)
			info := resourceList[0]

			err = patchResourceServerSide(info, tc.DryRun, tc.ForceConflicts, tc.FieldValidationDirective)
			if tc.ExpectedErrorContains != "" {
				require.ErrorContains(t, err, tc.ExpectedErrorContains)
			} else {
				require.NoError(t, err)
				require.NotNil(t, info.Object)
			}
		})
	}
}

func TestDetermineFieldValidationDirective(t *testing.T) {

	assert.Equal(t, FieldValidationDirectiveIgnore, determineFieldValidationDirective(false))
	assert.Equal(t, FieldValidationDirectiveStrict, determineFieldValidationDirective(true))
}

func TestClientWaitContextCancellationLegacy(t *testing.T) {
	podList := newPodList("starfish", "otter")

	ctx, cancel := context.WithCancel(t.Context())

	c := newTestClient(t)
	c.WaitContext = ctx

	requestCount := 0
	c.Factory.(*cmdtesting.TestFactory).Client = &fake.RESTClient{
		NegotiatedSerializer: unstructuredSerializer,
		Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
			requestCount++
			p, m := req.URL.Path, req.Method
			t.Logf("got request %s %s", p, m)

			if requestCount == 2 {
				cancel()
			}

			switch {
			case p == "/api/v1/namespaces/default/pods/starfish" && m == http.MethodGet:
				pod := &podList.Items[0]
				pod.Status.Conditions = []v1.PodCondition{
					{
						Type:   v1.PodReady,
						Status: v1.ConditionFalse,
					},
				}
Repository: helm/helm
File: internal/plugin/metadata.go (Go)

Code before:
	Name string

	// Type of plugin (eg, cli/v1, getter/v1, postrenderer/v1)
	Type string

	// Runtime specifies the runtime type (subprocess, wasm)
	Runtime string

	// Version is the SemVer 2 version of the plugin.
	Version string

	// SourceURL is the URL where this plugin can be found
	SourceURL string

	// Config contains the type-specific configuration for this plugin
	Config Config

	// RuntimeConfig contains the runtime-specific configuration
	RuntimeConfig RuntimeConfig
}

func (m Metadata) Validate() error {
	var errs []error

	if !validPluginName.MatchString(m.Name) {
		errs = append(errs, fmt.Errorf("invalid name %q: must contain only a-z, A-Z, 0-9, _ and -", m.Name))
	}

	if m.APIVersion == "" {
		errs = append(errs, fmt.Errorf("empty APIVersion"))
	}

	if m.Type == "" {
		errs = append(errs, fmt.Errorf("empty type field"))
	}

	if m.Runtime == "" {
		errs = append(errs, fmt.Errorf("empty runtime field"))
	}

	if m.Config == nil {
		errs = append(errs, fmt.Errorf("missing config field"))
	}

	if m.RuntimeConfig == nil {
		errs = append(errs, fmt.Errorf("missing runtimeConfig field"))
	}

	// Validate the config itself
	if m.Config != nil {
		if err := m.Config.Validate(); err != nil {

Review comment (bug):
I think displaying `m.Name` will help users to understand that the wrong field is set if you have specified `Name:` instead of `name:`.

Code after:
	Name string

	// Type of plugin (eg, cli/v1, getter/v1, postrenderer/v1)
	Type string

	// Runtime specifies the runtime type (subprocess, wasm)
	Runtime string

	// Version is the SemVer 2 version of the plugin.
	Version string

	// SourceURL is the URL where this plugin can be found
	SourceURL string

	// Config contains the type-specific configuration for this plugin
	Config Config

	// RuntimeConfig contains the runtime-specific configuration
	RuntimeConfig RuntimeConfig
}

func (m Metadata) Validate() error {
	var errs []error

	if !validPluginName.MatchString(m.Name) {
		errs = append(errs, fmt.Errorf("invalid plugin name %q: must contain only a-z, A-Z, 0-9, _ and -", m.Name))
	}

	if m.APIVersion == "" {
		errs = append(errs, fmt.Errorf("empty APIVersion"))
	}

	if m.Type == "" {
		errs = append(errs, fmt.Errorf("empty type field"))
	}

	if m.Runtime == "" {
		errs = append(errs, fmt.Errorf("empty runtime field"))
	}

	if m.Config == nil {
		errs = append(errs, fmt.Errorf("missing config field"))
	}

	if m.RuntimeConfig == nil {
		errs = append(errs, fmt.Errorf("missing runtimeConfig field"))
	}

	// Validate the config itself
	if m.Config != nil {
		if err := m.Config.Validate(); err != nil {