diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 11c2db2f523..68e32b07471 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -25,7 +25,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-24.04, ubuntu-24.04-arm] - go-version: [1.23.x, 1.24.x] + go-version: [1.24.x, 1.25.x] rootless: ["rootless", ""] race: ["-race", ""] criu: ["", "criu-dev"] @@ -33,12 +33,12 @@ jobs: # Disable most of criu-dev jobs, as they are expensive # (need to compile criu) and don't add much value/coverage. - criu: criu-dev - go-version: 1.23.x + go-version: 1.24.x - criu: criu-dev rootless: rootless # Do race detection only on latest Go. - race: -race - go-version: 1.23.x + go-version: 1.24.x runs-on: ${{ matrix.os }} diff --git a/Dockerfile b/Dockerfile index 5c3b933b38e..26f124ede8e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -ARG GO_VERSION=1.23 +ARG GO_VERSION=1.24 ARG BATS_VERSION=v1.11.0 ARG LIBSECCOMP_VERSION=2.5.6 diff --git a/README.md b/README.md index 70e64a18b64..2d0f13bd03d 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ A third party security audit was performed by Cure53, you can see the full repor ## Building -`runc` only supports Linux. See the header of [`go.mod`](./go.mod) for the required Go version. +`runc` only supports Linux. See the header of [`go.mod`](./go.mod) for the minimally required Go version. ### Pre-Requisites diff --git a/exec.go b/exec.go index ff8e8ee1582..cd5a9d17154 100644 --- a/exec.go +++ b/exec.go @@ -132,7 +132,7 @@ func getSubCgroupPaths(args []string) (map[string]string, error) { // Split into controller:path. if ctr, path, ok := strings.Cut(c, ":"); ok { // There may be a few comma-separated controllers. - for _, ctrl := range strings.Split(ctr, ",") { + for ctrl := range strings.SplitSeq(ctr, ",") { if ctrl == "" { return nil, fmt.Errorf("invalid --cgroup argument: %s (empty prefix)", c) } diff --git a/go.mod b/go.mod index 3c4eb535991..756837fbb9b 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/opencontainers/runc -go 1.23.0 +go 1.24.0 require ( github.com/checkpoint-restore/go-criu/v7 v7.2.0 diff --git a/libcontainer/configs/config.go b/libcontainer/configs/config.go index 07216cb81cd..a0cdaec6a19 100644 --- a/libcontainer/configs/config.go +++ b/libcontainer/configs/config.go @@ -325,7 +325,7 @@ func toCPUSet(str string) (*unix.CPUSet, error) { return int(ret), nil } - for _, r := range strings.Split(str, ",") { + for r := range strings.SplitSeq(str, ",") { // Allow extra spaces around. r = strings.TrimSpace(r) // Allow empty elements (extra commas). diff --git a/libcontainer/configs/config_test.go b/libcontainer/configs/config_test.go index 644129941ce..70dcb799531 100644 --- a/libcontainer/configs/config_test.go +++ b/libcontainer/configs/config_test.go @@ -30,7 +30,7 @@ func TestUnmarshalHooks(t *testing.T) { for _, hookName := range configs.HookNameList { hooks := configs.Hooks{} - err = hooks.UnmarshalJSON([]byte(fmt.Sprintf(`{"%s" :[%s]}`, hookName, hookJson))) + err = hooks.UnmarshalJSON(fmt.Appendf(nil, `{"%s" :[%s]}`, hookName, hookJson)) if err != nil { t.Fatal(err) } diff --git a/libcontainer/configs/tocpuset_test.go b/libcontainer/configs/tocpuset_test.go index 43fb11bf876..8af2ab57726 100644 --- a/libcontainer/configs/tocpuset_test.go +++ b/libcontainer/configs/tocpuset_test.go @@ -57,7 +57,6 @@ func TestToCPUSet(t *testing.T) { } for _, tc := range testCases { - tc := tc t.Run(tc.in, func(t *testing.T) { out, err := toCPUSet(tc.in) t.Logf("toCPUSet(%q) = %v (error: %v)", tc.in, out, err) diff --git a/libcontainer/configs/validate/rootless.go b/libcontainer/configs/validate/rootless.go index 88cf1cd60fc..ef9c8e6f948 100644 --- a/libcontainer/configs/validate/rootless.go +++ b/libcontainer/configs/validate/rootless.go @@ -60,7 +60,7 @@ func rootlessEUIDMount(config *configs.Config) error { if !strings.Contains(mount.Data, "id=") { continue } - for _, opt := range strings.Split(mount.Data, ",") { + for opt := range strings.SplitSeq(mount.Data, ",") { if str, ok := strings.CutPrefix(opt, "uid="); ok { uid, err := strconv.Atoi(str) if err != nil { diff --git a/libcontainer/configs/validate/rootless_test.go b/libcontainer/configs/validate/rootless_test.go index 7b088739910..f725b541f81 100644 --- a/libcontainer/configs/validate/rootless_test.go +++ b/libcontainer/configs/validate/rootless_test.go @@ -154,8 +154,7 @@ func BenchmarkRootlessEUIDMount(b *testing.B) { }, } - b.ResetTimer() - for i := 0; i < b.N; i++ { + for b.Loop() { err := rootlessEUIDMount(config) if err != nil { b.Fatal(err) diff --git a/libcontainer/configs/validate/validator_test.go b/libcontainer/configs/validate/validator_test.go index 99e189c6590..2dd47a198d3 100644 --- a/libcontainer/configs/validate/validator_test.go +++ b/libcontainer/configs/validate/validator_test.go @@ -774,7 +774,6 @@ func TestValidateIDMapMounts(t *testing.T) { } for _, tc := range testCases { - tc := tc t.Run(tc.name, func(t *testing.T) { config := tc.config config.Rootfs = "/var" diff --git a/libcontainer/integration/bench_test.go b/libcontainer/integration/bench_test.go index c10c57fda3c..0375ee7f7cc 100644 --- a/libcontainer/integration/bench_test.go +++ b/libcontainer/integration/bench_test.go @@ -34,8 +34,7 @@ func BenchmarkExecTrue(b *testing.B) { }() ok(b, err) - b.ResetTimer() - for i := 0; i < b.N; i++ { + for b.Loop() { exec := &libcontainer.Process{ Cwd: "/", Args: []string{"/bin/true"}, @@ -101,8 +100,7 @@ func BenchmarkExecInBigEnv(b *testing.B) { wantOut.WriteString(e + "\n") } - b.ResetTimer() - for i := 0; i < b.N; i++ { + for b.Loop() { buffers := newStdBuffers() exec := &libcontainer.Process{ Cwd: "/", diff --git a/libcontainer/integration/exec_test.go b/libcontainer/integration/exec_test.go index 17312563bfc..f5a24777edf 100644 --- a/libcontainer/integration/exec_test.go +++ b/libcontainer/integration/exec_test.go @@ -850,8 +850,8 @@ func TestMountCgroupRO(t *testing.T) { buffers := runContainerOk(t, config, "mount") mountInfo := buffers.Stdout.String() - lines := strings.Split(mountInfo, "\n") - for _, l := range lines { + lines := strings.SplitSeq(mountInfo, "\n") + for l := range lines { if strings.HasPrefix(l, "tmpfs on /sys/fs/cgroup") { if !strings.Contains(l, "ro") || !strings.Contains(l, "nosuid") || @@ -892,8 +892,8 @@ func TestMountCgroupRW(t *testing.T) { buffers := runContainerOk(t, config, "mount") mountInfo := buffers.Stdout.String() - lines := strings.Split(mountInfo, "\n") - for _, l := range lines { + lines := strings.SplitSeq(mountInfo, "\n") + for l := range lines { if strings.HasPrefix(l, "tmpfs on /sys/fs/cgroup") { if !strings.Contains(l, "rw") || !strings.Contains(l, "nosuid") || @@ -1206,8 +1206,8 @@ func TestRootfsPropagationSlaveMount(t *testing.T) { dir2cont = filepath.Join(dir1cont, filepath.Base(dir2host)) propagationInfo := stdout2.String() - lines := strings.Split(propagationInfo, "\n") - for _, l := range lines { + lines := strings.SplitSeq(propagationInfo, "\n") + for l := range lines { linefields := strings.Split(l, " ") if len(linefields) < 5 { continue diff --git a/libcontainer/internal/userns/usernsfd_linux_test.go b/libcontainer/internal/userns/usernsfd_linux_test.go index 23a3419fcae..0065b7f839d 100644 --- a/libcontainer/internal/userns/usernsfd_linux_test.go +++ b/libcontainer/internal/userns/usernsfd_linux_test.go @@ -42,7 +42,7 @@ func BenchmarkSpawnProc(b *testing.B) { } }) - for i := 0; i < b.N; i++ { + for b.Loop() { proc, err := spawnProc(mapping) if err != nil { b.Error(err) diff --git a/libcontainer/rootfs_linux.go b/libcontainer/rootfs_linux.go index fd9fdddcd05..a7a72b8bb19 100644 --- a/libcontainer/rootfs_linux.go +++ b/libcontainer/rootfs_linux.go @@ -354,7 +354,7 @@ func mountCgroupV1(m *configs.Mount, c *mountConfig) error { } } for _, mc := range merged { - for _, ss := range strings.Split(mc, ",") { + for ss := range strings.SplitSeq(mc, ",") { // symlink(2) is very dumb, it will just shove the path into // the link and doesn't do any checks or relative path // conversion. Also, don't error out if the cgroup already exists. diff --git a/libcontainer/specconv/spec_linux_test.go b/libcontainer/specconv/spec_linux_test.go index 77219496243..4c3c4769348 100644 --- a/libcontainer/specconv/spec_linux_test.go +++ b/libcontainer/specconv/spec_linux_test.go @@ -777,7 +777,6 @@ func TestInitSystemdProps(t *testing.T) { spec := &specs.Spec{} for _, tc := range testCases { - tc := tc spec.Annotations = map[string]string{tc.in.name: tc.in.value} outMap, err := initSystemdProps(spec) @@ -834,7 +833,7 @@ func TestCheckPropertyName(t *testing.T) { } func BenchmarkCheckPropertyName(b *testing.B) { - for i := 0; i < b.N; i++ { + for b.Loop() { for _, s := range []string{"", "xx", "xxx", "someValidName", "A name", "Кир", "მადლობა", "合い言葉"} { _ = checkPropertyName(s) } diff --git a/libcontainer/system/kernelversion/kernel_linux_test.go b/libcontainer/system/kernelversion/kernel_linux_test.go index a18f1f2226f..7a5df8421b1 100644 --- a/libcontainer/system/kernelversion/kernel_linux_test.go +++ b/libcontainer/system/kernelversion/kernel_linux_test.go @@ -67,7 +67,6 @@ func TestParseRelease(t *testing.T) { {in: "3.-8", expectedErr: fmt.Errorf(`failed to parse kernel version "3.-8": expected integer`)}, } for _, tc := range tests { - tc := tc t.Run(tc.in, func(t *testing.T) { version, err := parseRelease(tc.in) if tc.expectedErr != nil { @@ -126,7 +125,6 @@ func TestGreaterEqualThan(t *testing.T) { }, } for _, tc := range tests { - tc := tc t.Run(tc.doc+": "+tc.in.String(), func(t *testing.T) { ok, err := GreaterEqualThan(tc.in) if err != nil { diff --git a/libcontainer/system/rlimit_linux.go b/libcontainer/system/rlimit_linux.go index 4595fa82aa1..8add993c22e 100644 --- a/libcontainer/system/rlimit_linux.go +++ b/libcontainer/system/rlimit_linux.go @@ -1,5 +1,3 @@ -//go:build go1.23 - package system import ( diff --git a/notify_socket.go b/notify_socket.go index a3aa8d2b208..afebf4e77e4 100644 --- a/notify_socket.go +++ b/notify_socket.go @@ -128,7 +128,7 @@ func (s *notifySocket) run(pid1 int) error { got := buf[0:r] // systemd-ready sends a single datagram with the state string as payload, // so we don't need to worry about partial messages. - for _, line := range bytes.Split(got, []byte{'\n'}) { + for line := range bytes.SplitSeq(got, []byte{'\n'}) { if bytes.HasPrefix(got, []byte("READY=")) { fileChan <- line return diff --git a/types/events.go b/types/events.go index fc741d2d9e2..e9dc5443a8a 100644 --- a/types/events.go +++ b/types/events.go @@ -75,8 +75,8 @@ type CpuUsage struct { } type Cpu struct { - Usage CpuUsage `json:"usage,omitempty"` - Throttling Throttling `json:"throttling,omitempty"` + Usage CpuUsage `json:"usage,omitzero"` + Throttling Throttling `json:"throttling,omitzero"` PSI *PSIStats `json:"psi,omitempty"` } @@ -103,10 +103,10 @@ type MemoryEntry struct { type Memory struct { Cache uint64 `json:"cache,omitempty"` - Usage MemoryEntry `json:"usage,omitempty"` - Swap MemoryEntry `json:"swap,omitempty"` - Kernel MemoryEntry `json:"kernel,omitempty"` - KernelTCP MemoryEntry `json:"kernelTCP,omitempty"` + Usage MemoryEntry `json:"usage,omitzero"` + Swap MemoryEntry `json:"swap,omitzero"` + Kernel MemoryEntry `json:"kernel,omitzero"` + KernelTCP MemoryEntry `json:"kernelTCP,omitzero"` Raw map[string]uint64 `json:"raw,omitempty"` PSI *PSIStats `json:"psi,omitempty"` }