diff --git a/cmd/nvidia-container-runtime-hook/container_config.go b/cmd/nvidia-container-runtime-hook/container_config.go index 86288d8e6..9c61b1dc3 100644 --- a/cmd/nvidia-container-runtime-hook/container_config.go +++ b/cmd/nvidia-container-runtime-hook/container_config.go @@ -7,8 +7,8 @@ import ( "os" "path" + "github.com/Masterminds/semver/v3" "github.com/opencontainers/runtime-spec/specs-go" - "golang.org/x/mod/semver" "github.com/NVIDIA/nvidia-container-toolkit/internal/config/image" ) @@ -107,8 +107,12 @@ func (s *Spec) GetCapabilities() []string { var caps []string // If v1.0.0-rc1 <= OCI version < v1.0.0-rc5 parse s.Process.Capabilities as: // github.com/opencontainers/runtime-spec/blob/v1.0.0-rc1/specs-go/config.go#L30-L54 - rc1cmp := semver.Compare("v"+*s.Version, "v1.0.0-rc1") - rc5cmp := semver.Compare("v"+*s.Version, "v1.0.0-rc5") + sv, err := semver.NewVersion(*s.Version) + if err != nil { + sv = semver.MustParse("0.0.0") + } + rc1cmp := sv.Compare(semver.MustParse("v1.0.0-rc1")) + rc5cmp := sv.Compare(semver.MustParse("v1.0.0-rc5")) if (rc1cmp == 1 || rc1cmp == 0) && (rc5cmp == -1) { err := json.Unmarshal(*s.Process.Capabilities, &caps) if err != nil { @@ -120,7 +124,7 @@ func (s *Spec) GetCapabilities() []string { // Otherwise, parse s.Process.Capabilities as: // github.com/opencontainers/runtime-spec/blob/v1.0.0/specs-go/config.go#L30-L54 capabilities := specs.LinuxCapabilities{} - err := json.Unmarshal(*s.Process.Capabilities, &capabilities) + err = json.Unmarshal(*s.Process.Capabilities, &capabilities) if err != nil { log.Panicln("could not decode Process.Capabilities in OCI spec:", err) } diff --git a/go.mod b/go.mod index 11dbed2f6..d243166af 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,6 @@ require ( github.com/stretchr/testify v1.11.1 github.com/urfave/cli-altsrc/v3 v3.1.0 github.com/urfave/cli/v3 v3.10.1 - golang.org/x/mod v0.38.0 golang.org/x/sys v0.47.0 tags.cncf.io/container-device-interface v1.1.0 tags.cncf.io/container-device-interface/specs-go v1.1.0 @@ -42,6 +41,7 @@ require ( github.com/rogpeppe/go-internal v1.11.0 // indirect github.com/tetratelabs/wazero v1.11.0 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect + golang.org/x/mod v0.38.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478 // indirect google.golang.org/grpc v1.82.1 // indirect google.golang.org/protobuf v1.36.11 // indirect diff --git a/internal/config/image/cuda_image.go b/internal/config/image/cuda_image.go index e0343c089..a06a7bb31 100644 --- a/internal/config/image/cuda_image.go +++ b/internal/config/image/cuda_image.go @@ -23,8 +23,8 @@ import ( "strconv" "strings" + "github.com/Masterminds/semver/v3" "github.com/opencontainers/runtime-spec/specs-go" - "golang.org/x/mod/semver" "tags.cncf.io/container-device-interface/pkg/parser" "github.com/NVIDIA/nvidia-container-toolkit/internal/logger" @@ -201,16 +201,13 @@ func (i CUDA) legacyVersion() (string, error) { } func parseMajorMinorVersion(version string) (string, error) { - vVersion := "v" + strings.TrimPrefix(version, "v") - - if !semver.IsValid(vVersion) { - return "", fmt.Errorf("invalid version string") + sv, err := semver.NewVersion(version) + if err != nil { + return "", fmt.Errorf("invalid version string: %w", err) } - - majorMinor := strings.TrimPrefix(semver.MajorMinor(vVersion), "v") + majorMinor := fmt.Sprintf("%d.%d", sv.Major(), sv.Minor()) parts := strings.Split(majorMinor, ".") - var err error _, err = strconv.ParseUint(parts[0], 10, 32) if err != nil { return "", fmt.Errorf("invalid major version") @@ -219,6 +216,7 @@ func parseMajorMinorVersion(version string) (string, error) { if err != nil { return "", fmt.Errorf("invalid minor version") } + return majorMinor, nil } diff --git a/internal/requirements/constraints/property.go b/internal/requirements/constraints/property.go index c1a754ebd..d157705b1 100644 --- a/internal/requirements/constraints/property.go +++ b/internal/requirements/constraints/property.go @@ -18,9 +18,8 @@ package constraints import ( "fmt" - "strings" - "golang.org/x/mod/semver" + "github.com/Masterminds/semver/v3" ) // Property represents a property that is used to check requirements @@ -111,20 +110,23 @@ func (p versionProperty) CompareTo(other string) (int, error) { return 0, fmt.Errorf("invailid value for %v: %v", p.name, err) } - vValue := ensurePrefix(p.value, "v") - vOther := ensurePrefix(other, "v") - return semver.Compare(vValue, vOther), nil + value, err := semver.NewVersion(p.value) + if err != nil { + return 0, fmt.Errorf("invalid value for %v: %w", p.name, err) + } + otherVersion, err := semver.NewVersion(other) + if err != nil { + return 0, fmt.Errorf("invalid value for %v: %w", p.name, err) + } + return value.Compare(otherVersion), nil } // Validate checks whether the supplied value is a valid semantic version func (p versionProperty) Validate(value string) error { - if !semver.IsValid(ensurePrefix(value, "v")) { - return fmt.Errorf("invailid value %v; expected a valid version string", value) + _, err := semver.NewVersion(value) + if err != nil { + return fmt.Errorf("invalid version string: %w", err) } return nil } - -func ensurePrefix(s string, prefix string) string { - return prefix + strings.TrimPrefix(s, prefix) -} diff --git a/tests/e2e/nvidia-container-toolkit_test.go b/tests/e2e/nvidia-container-toolkit_test.go index 8ebd2af23..7bb265de8 100644 --- a/tests/e2e/nvidia-container-toolkit_test.go +++ b/tests/e2e/nvidia-container-toolkit_test.go @@ -25,7 +25,7 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" - "golang.org/x/mod/semver" + "github.com/Masterminds/semver/v3" ) // Integration tests for Docker runtime @@ -491,7 +491,7 @@ EOF`) It("should fail when using the nvidia-container-runtime-hook", Label("legacy"), func(ctx context.Context) { // Prior to Docker v29.2.0, the --gpus flag would inject the nvidia-container-runtime-hook. - if semver.Compare(dockerVersion, "v29.2.0") >= 0 { + if semver.MustParse(dockerVersion).Compare(semver.MustParse("v29.2.0")) >= 0 { Skip(fmt.Sprintf("This test requires Docker < v29.2.0. Found %s", dockerVersion)) } output, stderr, err := runner.Run("docker run --rm --runtime=runc --gpus=all firmware-test") @@ -503,7 +503,7 @@ EOF`) It("should not fail when the --gpus flag is handled as a CDI request", func(ctx context.Context) { // As of Docker v29.2.0, the --gpus flag is handled as a CDI // device request if CDI specs are available. - if semver.Compare(dockerVersion, "v29.2.0") < 0 { + if semver.MustParse(dockerVersion).Compare(semver.MustParse("v29.2.0")) < 0 { Skip(fmt.Sprintf("This test requires Docker >= v29.2.0. Found %s", dockerVersion)) } output, stderr, err := runner.Run("docker run --rm --runtime=runc --gpus=all firmware-test")