From 05e508668addf216c8ddfb9339d64e0d010da0d1 Mon Sep 17 00:00:00 2001 From: Sohan Kunkerkar Date: Tue, 30 Jul 2024 14:28:24 -0400 Subject: [PATCH 1/8] internal/oci: improve container termination process in killContainer This change aims to reduce unnecessary kill attempts and error logs when terminating containers that have already stopped or don't exist. Signed-off-by: Sohan Kunkerkar --- internal/oci/runtime_oci.go | 42 +++++++++++++++++++++++++++---------- 1 file changed, 31 insertions(+), 11 deletions(-) diff --git a/internal/oci/runtime_oci.go b/internal/oci/runtime_oci.go index 8a7be53c3e4..017bfc3adbd 100644 --- a/internal/oci/runtime_oci.go +++ b/internal/oci/runtime_oci.go @@ -895,20 +895,24 @@ func (r *runtimeOCI) StopLoopForContainer(c *Container, bm kwait.BackoffManager) done := make(chan struct{}) go func() { + statusCheckTicker := time.NewTicker(stopProcessWatchSleep) + defer statusCheckTicker.Stop() for { - if err := c.Living(); err != nil { - // The initial container process either doesn't exist, or isn't ours. - if !errors.Is(err, ErrNotFound) { - log.Warnf(ctx, "Failed to find process for container %s: %v", c.ID(), err) - } - close(done) - return - } select { case <-ctx.Done(): return - case <-time.After(stopProcessWatchSleep): - // Continue watching + case <-statusCheckTicker.C: + // Periodically check if the container is still running. + // This avoids busy-waiting and reduces resource usage while + // ensuring timely detection of container termination. + if err := c.Living(); err != nil { + // The initial container process either doesn't exist, or isn't ours. + if !errors.Is(err, ErrNotFound) { + log.Warnf(ctx, "Failed to find process for container %s: %v", c.ID(), err) + } + close(done) + return + } } } }() @@ -957,11 +961,15 @@ killContainer: // We cannot use ExponentialBackoff() here as its stop conditions are not flexible enough. kwait.BackoffUntil(func() { if _, err := r.runtimeCmd("kill", c.ID(), "KILL"); err != nil { - log.Errorf(ctx, "Killing container %v failed: %v", c.ID(), err) + if !errors.Is(err, ErrNotFound) { + log.Errorf(ctx, "Killing container %v failed: %v", c.ID(), err) + } + log.Debugf(ctx, "Error while killing container %s: %v", c.ID(), err) } if err := c.Living(); err != nil { stop() + return } // Reschedule the timer so that the periodic reminder can continue. blockedTimer.Reset(stopProcessBlockedInterval) @@ -1495,6 +1503,18 @@ func (r *runtimeOCI) runtimeCmd(args ...string) (string, error) { err := cmd.Run() if err != nil { + stdErrStr := stderr.String() + switch { + // crun, for most of the commands. + case strings.Contains(stdErrStr, "no such process"): + fallthrough //nolint:gocritic + // runc, for most of the commands. + case strings.Contains(stdErrStr, "container not running"): + fallthrough //nolint:gocritic + // runc, on a rare occasion. + case strings.Contains(stdErrStr, "invalid process"): + err = ErrNotFound + } return "", fmt.Errorf("`%v %v` failed: %v %v: %w", r.handler.RuntimePath, strings.Join(runtimeArgs, " "), stderr.String(), stdout.String(), err) } From 999910e2fd52bed81d1e3bb556c05ba18ffc43e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Wilczy=C5=84ski?= Date: Mon, 4 Mar 2024 18:59:21 +0900 Subject: [PATCH 2/8] Change process metrics collector log levels MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Krzysztof Wilczyński --- internal/process/defunct_processes.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/process/defunct_processes.go b/internal/process/defunct_processes.go index 4a970190426..67668b990ac 100644 --- a/internal/process/defunct_processes.go +++ b/internal/process/defunct_processes.go @@ -50,11 +50,11 @@ func DefunctProcessesForPath(path string) (defunctCount uint, retErr error) { stat, err := processStats(path, name) if err != nil { - logrus.Debugf("Failed to get the status of process with PID %s: %v", name, err) + logrus.Warnf("Failed to get the status of process with PID %s: %v", name, err) continue } if stat.State == "Z" { - logrus.Warnf("Found defunct process with PID %s (%s)", name, stat.Comm) + logrus.Debugf("Found defunct process with PID %s (%s)", name, stat.Comm) defunctCount++ } } From bdc785bd512dd884ff14f63eefe10b5e46d4d37d Mon Sep 17 00:00:00 2001 From: Sascha Grunert Date: Fri, 15 Mar 2024 09:06:02 +0100 Subject: [PATCH 3/8] Remove Podman `lookup` dependency Signed-off-by: Sascha Grunert --- utils/utils.go | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/utils/utils.go b/utils/utils.go index f42dbcf0869..6331d14ab3c 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -10,7 +10,6 @@ import ( "runtime" "strconv" - "github.com/containers/podman/v4/pkg/lookup" securejoin "github.com/cyphar/filepath-securejoin" "github.com/opencontainers/runc/libcontainer/user" "github.com/sirupsen/logrus" @@ -199,7 +198,7 @@ func GetUserInfo(rootfs, userName string) (uid, gid uint32, additionalGids []uin func GeneratePasswd(username string, uid, gid uint32, homedir, rootfs, rundir string) (string, error) { // if UID exists inside of container rootfs /etc/passwd then // don't generate passwd - if _, err := lookup.GetUser(rootfs, strconv.Itoa(int(uid))); err == nil { + if _, err := GetUser(rootfs, strconv.Itoa(int(uid))); err == nil { return "", nil } passwdFile := filepath.Join(rundir, "passwd") @@ -249,6 +248,39 @@ func GeneratePasswd(username string, uid, gid uint32, homedir, rootfs, rundir st return passwdFile, nil } +// GetUser takes a containermount path and user name or ID and returns +// a matching User structure from /etc/passwd. If it cannot locate a user +// with the provided information, an ErrNoPasswdEntries is returned. +// When the provided user name was an ID, a User structure with Uid +// set is returned along with ErrNoPasswdEntries. +func GetUser(containerMount, userIDorName string) (*user.User, error) { + var inputIsName bool + uid, err := strconv.Atoi(userIDorName) + if err != nil { + inputIsName = true + } + passwdDest, err := securejoin.SecureJoin(containerMount, "/etc/passwd") + if err != nil { + return nil, err + } + users, err := user.ParsePasswdFileFilter(passwdDest, func(u user.User) bool { + if inputIsName { + return u.Name == userIDorName + } + return u.Uid == uid + }) + if err != nil && !os.IsNotExist(err) { + return nil, err + } + if len(users) > 0 { + return &users[0], nil + } + if !inputIsName { + return &user.User{Uid: uid}, user.ErrNoPasswdEntries + } + return nil, user.ErrNoPasswdEntries +} + // Int32Ptr is a utility function to assign to integer pointer variables func Int32Ptr(i int32) *int32 { return &i From c39cd001a3a9b1e52ba6b8d87de8563867740a3b Mon Sep 17 00:00:00 2001 From: PannagaRamamanohara Date: Mon, 3 Jun 2024 16:08:29 -0400 Subject: [PATCH 4/8] server/*: Fix bug to add gid in /etc/group When securityContext of runAsGroup is added the gid has to be added in /etc/group. This PR has changes to add gid value under /etc/group Test case to verify the addition of the same is also being added Signed-off-by: PannagaRamamanohara --- server/container_create.go | 36 +++++++++- test/pod.bats | 29 ++++++++ utils/utils.go | 144 ++++++++++++++++++++++++++++++------- utils/utils_test.go | 45 ++++++++++++ 4 files changed, 224 insertions(+), 30 deletions(-) diff --git a/server/container_create.go b/server/container_create.go index 222cd6dd8f6..9668ed04327 100644 --- a/server/container_create.go +++ b/server/container_create.go @@ -229,11 +229,19 @@ func setupContainerUser(ctx context.Context, specgen *generate.Generator, rootfs } genPasswd := true + genGroup := true for _, mount := range specgen.Config.Mounts { - if mount.Destination == "/etc" || - mount.Destination == "/etc/" || - mount.Destination == "/etc/passwd" { + switch mount.Destination { + case "/etc", "/etc/": genPasswd = false + genGroup = false + case "/etc/passwd": + genPasswd = false + case "/etc/group": + genGroup = false + } + + if !genPasswd && !genGroup { break } } @@ -257,6 +265,28 @@ func setupContainerUser(ctx context.Context, specgen *generate.Generator, rootfs specgen.AddMount(mnt) } } + if genGroup { + if sc.RunAsGroup != nil { + gid = uint32(sc.RunAsGroup.Value) + } + + // verify gid exists in containers /etc/group, else generate a group with the group entry + groupPath, err := utils.GenerateGroup(gid, rootfs, ctrRunDir) + if err != nil { + return err + } + if groupPath != "" { + if err := securityLabel(groupPath, mountLabel, false, false); err != nil { + return err + } + specgen.AddMount(rspec.Mount{ + Type: "bind", + Source: groupPath, + Destination: "/etc/group", + Options: []string{"rw", "bind", "nodev", "nosuid", "noexec"}, + }) + } + } specgen.SetProcessUID(uid) if sc.RunAsGroup != nil { diff --git a/test/pod.bats b/test/pod.bats index cfdd140aa10..eb2d934c497 100644 --- a/test/pod.bats +++ b/test/pod.bats @@ -337,3 +337,32 @@ function teardown() { output=$(crictl exec --sync "$ctr_id" ls -ld /etc) [[ "$output" == *"test test"* ]] } + +@test "verify RunAsGroup in container" { + start_crio + + jq ' + .linux.security_context.run_as_user = { value: 1000 } + | .linux.security_context.run_as_group = { value: 1001 } + ' "$TESTDATA"/sandbox_config.json > "$TESTDIR/modified_sandbox_config.json" + + jq ' + .linux.security_context.run_as_user = { value: 1000 } + | .linux.security_context.run_as_group = { value: 1002 } + ' "$TESTDATA"/container_sleep.json > "$TESTDIR/modified_container_sleep_config" + + # Create a new pod using the modified sandbox configuration + pod_id=$(crictl runp "$TESTDIR/modified_sandbox_config.json") + + # Create a new container within the pod using the modified container configuration + ctr_id=$(crictl create "$pod_id" "$TESTDIR/modified_container_sleep_config" "$TESTDIR/modified_sandbox_config.json") + crictl start "$ctr_id" + + # Verify that the gid is present in the /etc/group file + exec_output=$(crictl exec "$ctr_id" cat /etc/group) + echo "$exec_output" | grep "x:1002" || fail "RunAsGroup ID 1002 not found in /etc/group" + + # Clean up the pod and container + crictl stop "$ctr_id" + crictl stopp "$pod_id" +} diff --git a/utils/utils.go b/utils/utils.go index 6331d14ab3c..dbcfa06b0c1 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -196,56 +196,146 @@ func GetUserInfo(rootfs, userName string) (uid, gid uint32, additionalGids []uin // GeneratePasswd generates a container specific passwd file, // iff uid is not defined in the containers /etc/passwd func GeneratePasswd(username string, uid, gid uint32, homedir, rootfs, rundir string) (string, error) { - // if UID exists inside of container rootfs /etc/passwd then - // don't generate passwd if _, err := GetUser(rootfs, strconv.Itoa(int(uid))); err == nil { return "", nil } + + passwdFilePath, stat, err := secureFilePath(rootfs, "/etc/passwd") + if err != nil || stat.Size == 0 { + return "", err + } + + if checkFilePermissions(&stat, uid, stat.Uid) { + return "", nil + } + + origContent, err := readFileContent(passwdFilePath) + if err != nil || origContent == nil { + return "", err + } + + if username == "" { + username = "default" + } + if homedir == "" { + homedir = "/tmp" + } + + pwdContent := fmt.Sprintf("%s%s:x:%d:%d:%s user:%s:/sbin/nologin\n", string(origContent), username, uid, gid, username, homedir) passwdFile := filepath.Join(rundir, "passwd") - originPasswdFile, err := securejoin.SecureJoin(rootfs, "/etc/passwd") + + return createAndSecureFile(passwdFile, pwdContent, os.FileMode(stat.Mode), int(stat.Uid), int(stat.Gid)) +} + +// GenerateGroup generates a container specific group file, +// iff gid is not defined in the containers /etc/group +func GenerateGroup(gid uint32, rootfs, rundir string) (string, error) { + if _, err := GetGroup(rootfs, strconv.Itoa(int(gid))); err == nil { + return "", nil + } + + groupFilePath, stat, err := secureFilePath(rootfs, "/etc/group") + if err != nil { + return "", err + } + + if checkFilePermissions(&stat, gid, stat.Gid) { + return "", nil + } + + origContent, err := readFileContent(groupFilePath) + if err != nil || origContent == nil { + return "", err + } + + groupContent := fmt.Sprintf("%s%d:x:%d:\n", string(origContent), gid, gid) + groupFile := filepath.Join(rundir, "group") + + return createAndSecureFile(groupFile, groupContent, os.FileMode(stat.Mode), int(stat.Uid), int(stat.Gid)) +} + +func secureFilePath(rootfs, file string) (string, unix.Stat_t, error) { + path, err := securejoin.SecureJoin(rootfs, file) if err != nil { - return "", fmt.Errorf("unable to follow symlinks to passwd file: %w", err) + return "", unix.Stat_t{}, fmt.Errorf("unable to follow symlinks to %s file: %w", file, err) } + var st unix.Stat_t - err = unix.Stat(originPasswdFile, &st) + err = unix.Stat(path, &st) if err != nil { if os.IsNotExist(err) { - return "", nil + return "", unix.Stat_t{}, nil // File does not exist } - return "", fmt.Errorf("unable to stat passwd file %s: %w", originPasswdFile, err) + return "", unix.Stat_t{}, fmt.Errorf("unable to stat file %s: %w", path, err) } - // Check if passwd file is world writable. - if st.Mode&0o022 != 0 { - return "", nil + return path, st, nil +} + +// checkFilePermissions checks file permissions to decide whether to skip file modification. +func checkFilePermissions(stat *unix.Stat_t, id, statID uint32) bool { + if stat.Mode&0o022 != 0 { + return true } - if uid == st.Uid && st.Mode&0o200 != 0 { - return "", nil + // Check if the UID/GID matches and if the file is owner writable. + if id == statID && stat.Mode&0o200 != 0 { + return true } - orig, err := os.ReadFile(originPasswdFile) + return false +} + +func readFileContent(path string) ([]byte, error) { + content, err := os.ReadFile(path) if err != nil { - // If no /etc/passwd in container ignore and return if os.IsNotExist(err) { - return "", nil + return nil, nil // File does not exist } - return "", fmt.Errorf("read passwd file: %w", err) + return nil, fmt.Errorf("read file: %w", err) } - if username == "" { - username = "default" + return content, nil +} + +func createAndSecureFile(path, content string, mode os.FileMode, uid, gid int) (string, error) { + if err := os.WriteFile(path, []byte(content), mode&os.ModePerm); err != nil { + return "", fmt.Errorf("failed to create file: %w", err) } - if homedir == "" { - homedir = "/tmp" + if err := os.Chown(path, uid, gid); err != nil { + return "", fmt.Errorf("failed to chown file: %w", err) } - pwd := fmt.Sprintf("%s%s:x:%d:%d:%s user:%s:/sbin/nologin\n", orig, username, uid, gid, username, homedir) - if err := os.WriteFile(passwdFile, []byte(pwd), os.FileMode(st.Mode)&os.ModePerm); err != nil { - return "", fmt.Errorf("failed to create temporary passwd file: %w", err) + return path, nil +} + +// GetGroup searches for a group in the container's /etc/group file using the provided +// container mount path and group identifier (either name or ID). It returns a matching +// user.Group structure if found. If no matching group is located, it returns +// ErrNoGroupEntries. +func GetGroup(containerMount, groupIDorName string) (*user.Group, error) { + var inputIsName bool + gid, err := strconv.Atoi(groupIDorName) + if err != nil { + inputIsName = true } - if err := os.Chown(passwdFile, int(st.Uid), int(st.Gid)); err != nil { - return "", fmt.Errorf("failed to chown temporary passwd file: %w", err) + groupDest, err := securejoin.SecureJoin(containerMount, "/etc/group") + if err != nil { + return nil, err } - - return passwdFile, nil + groups, err := user.ParseGroupFileFilter(groupDest, func(g user.Group) bool { + if inputIsName { + return g.Name == groupIDorName + } + return g.Gid == gid + }) + if err != nil && !os.IsNotExist(err) { + return nil, err + } + if len(groups) > 0 { + return &groups[0], nil + } + if !inputIsName { + return &user.Group{Gid: gid}, user.ErrNoGroupEntries + } + return nil, user.ErrNoGroupEntries } // GetUser takes a containermount path and user name or ID and returns diff --git a/utils/utils_test.go b/utils/utils_test.go index da2002001f6..a9ed00eed8e 100644 --- a/utils/utils_test.go +++ b/utils/utils_test.go @@ -211,6 +211,11 @@ var _ = t.Describe("Utils", func() { Expect(err).To(BeNil()) Expect(passwdFile).To(BeEmpty()) + // groupPath should be empty because an updated /etc/group file isn't created. + groupPath, err := utils.GenerateGroup(gid, dir, dir) + Expect(err).ToNot(HaveOccurred()) + Expect(groupPath).To(BeEmpty()) + // Double check that the uid, gid, and additional gids didn't change. newuid, newgid, newaddgids, err := utils.GetUserInfo(dir, "root") Expect(err).To(BeNil()) @@ -230,6 +235,11 @@ var _ = t.Describe("Utils", func() { Expect(err).To(BeNil()) Expect(passwdFile).To(BeEmpty()) + // groupPath should be empty because an updated /etc/group file isn't created. + groupPath, err := utils.GenerateGroup(gid, dir, dir) + Expect(err).ToNot(HaveOccurred()) + Expect(groupPath).To(BeEmpty()) + // Double check that the uid, gid, and additional gids didn't change. newuid, newgid, newaddgids, err := utils.GetUserInfo(dir, "daemon") Expect(err).To(BeNil()) @@ -249,6 +259,11 @@ var _ = t.Describe("Utils", func() { Expect(err).To(BeNil()) Expect(passwdFile).To(BeEmpty()) + // groupPath should be empty because an updated /etc/group file isn't created. + groupPath, err := utils.GenerateGroup(gid, dir, dir) + Expect(err).ToNot(HaveOccurred()) + Expect(groupPath).To(BeEmpty()) + // Double check that the uid, gid, and additional gids didn't change. newuid, newgid, newaddgids, err := utils.GetUserInfo(dir, "25") Expect(err).To(BeNil()) @@ -276,6 +291,16 @@ var _ = t.Describe("Utils", func() { Expect(newaddgids).To(Equal(addgids)) }) + It("should succeed with gid that doesn't exist in /etc/group", func() { + dir := createEtcFiles() + defer os.RemoveAll(dir) + + // groupPath should not be empty because an updated /etc/group file is created. + groupPath, err := utils.GenerateGroup(6000, dir, dir) + Expect(err).ToNot(HaveOccurred()) + Expect(groupPath).ToNot(BeEmpty()) + }) + It("should fail with username that desn't exist in /etc/passwd", func() { dir := createEtcFiles() defer os.RemoveAll(dir) @@ -313,6 +338,11 @@ var _ = t.Describe("Utils", func() { Expect(err).To(BeNil()) Expect(passwdFile).To(BeEmpty()) + // groupPath should be empty because an updated /etc/group file isn't created. + groupPath, err := utils.GenerateGroup(gid, dir, dir) + Expect(err).ToNot(HaveOccurred()) + Expect(groupPath).To(BeEmpty()) + // Double check that the uid, gid, and additional gids didn't change. newuid, newgid, newaddgids, err := utils.GetUserInfo(dir, "2:22") Expect(err).To(BeNil()) @@ -332,6 +362,11 @@ var _ = t.Describe("Utils", func() { Expect(err).To(BeNil()) Expect(passwdFile).To(BeEmpty()) + // groupPath should not be empty because an updated /etc/group file is created. + groupPath, err := utils.GenerateGroup(6000, dir, dir) + Expect(err).ToNot(HaveOccurred()) + Expect(groupPath).ToNot(BeEmpty()) + // Double check that the uid, gid, and additional gids didn't change. newuid, newgid, newaddgids, err := utils.GetUserInfo(dir, "daemon:250") Expect(err).To(BeNil()) @@ -351,6 +386,11 @@ var _ = t.Describe("Utils", func() { Expect(err).To(BeNil()) Expect(passwdFile).ToNot(BeEmpty()) + // groupPath should not be empty because an updated /etc/group file is created. + groupPath, err := utils.GenerateGroup(6000, dir, dir) + Expect(err).ToNot(HaveOccurred()) + Expect(groupPath).ToNot(BeEmpty()) + // Double check that the uid, gid, and additional gids didn't change. newuid, newgid, newaddgids, err := utils.GetUserInfo(dir, "300:250") Expect(err).To(BeNil()) @@ -370,6 +410,11 @@ var _ = t.Describe("Utils", func() { Expect(err).To(BeNil()) Expect(passwdFile).ToNot(BeEmpty()) + // groupPath should be empty because an updated /etc/group file isn't created. + groupPath, err := utils.GenerateGroup(gid, dir, dir) + Expect(err).ToNot(HaveOccurred()) + Expect(groupPath).To(BeEmpty()) + // Double check that the uid, gid, and additional gids didn't change. newuid, newgid, newaddgids, err := utils.GetUserInfo(dir, "300:mail") Expect(err).To(BeNil()) From 8fa8414002ba955589a273cfd57e891a5bb13fcb Mon Sep 17 00:00:00 2001 From: Sascha Grunert Date: Mon, 3 Jun 2024 11:52:18 +0200 Subject: [PATCH 5/8] Fix container stats label filter We need to filter the labels for each container to be able to support the corresponding cri-tools feature. Fixes: https://github.com/kubernetes-sigs/cri-tools/issues/950 Signed-off-by: Sascha Grunert --- server/container_stats_list.go | 11 +++++++++-- test/stats.bats | 4 ++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/server/container_stats_list.go b/server/container_stats_list.go index 01fc19d3880..1e2ad3e24df 100644 --- a/server/container_stats_list.go +++ b/server/container_stats_list.go @@ -16,14 +16,21 @@ func (s *Server) ListContainerStats(ctx context.Context, req *types.ListContaine if err != nil { return nil, err } - filter := req.Filter - if filter != nil { + if req.Filter != nil { cFilter := &types.ContainerFilter{ Id: req.Filter.Id, PodSandboxId: req.Filter.PodSandboxId, LabelSelector: req.Filter.LabelSelector, } ctrList = s.filterContainerList(ctx, cFilter, ctrList) + + filteredCtrList := []*oci.Container{} + for _, ctr := range ctrList { + if filterContainer(ctr.CRIContainer(), cFilter) { + filteredCtrList = append(filteredCtrList, ctr) + } + } + ctrList = filteredCtrList } return &types.ListContainerStatsResponse{ diff --git a/test/stats.bats b/test/stats.bats index aa5e6df033b..ba14c774189 100644 --- a/test/stats.bats +++ b/test/stats.bats @@ -51,6 +51,10 @@ function teardown() { # Assuming the two containers can't have exactly same memory usage echo "checking $ctr1_mem != $ctr2_mem" [ "$ctr1_mem" != "$ctr2_mem" ] + + # Test if the label filtering works + [ "$(crictl stats | wc -l)" == 3 ] + [ "$(crictl stats --label tier=backend | wc -l)" == 2 ] } @test "pod stats" { From df0263b195c0765c268fe65726e0081605abf74b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Wilczy=C5=84ski?= Date: Sun, 8 Sep 2024 00:31:30 +0900 Subject: [PATCH 6/8] Pin govulncheck to specific version to match Go version requirements MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Krzysztof Wilczyński --- .github/workflows/test.yml | 4 ++-- dependencies.yaml | 6 ++++++ hack/govulncheck.sh | 34 +++++++++++++++++++--------------- 3 files changed, 27 insertions(+), 17 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4b4c569b0e8..baba3e0ba2c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -382,7 +382,7 @@ jobs: - uses: actions/setup-go@v4 with: go-version: ${{ env.GO_VERSION }} - - name: Run Govulncheck + - name: Run govulncheck run: make verify-govulncheck - - name: Run Gosec + - name: Run gosec run: make verify-gosec diff --git a/dependencies.yaml b/dependencies.yaml index d49ae735fa2..8f07012906f 100644 --- a/dependencies.yaml +++ b/dependencies.yaml @@ -111,6 +111,12 @@ dependencies: - path: Makefile match: GO_MOD_OUTDATED_VERSION + - name: govulncheck + version: v1.1.1 + refPaths: + - path: hack/govulncheck.sh + match: GOVULNCHECK_VERSION + - name: gosec version: 2.15.0 refPaths: diff --git a/hack/govulncheck.sh b/hack/govulncheck.sh index be13e836c8f..6dae8ad372a 100755 --- a/hack/govulncheck.sh +++ b/hack/govulncheck.sh @@ -1,35 +1,39 @@ -#!/bin/bash +#!/usr/bin/env bash set -euo pipefail -# Install dependencies +# The govulncheck version should match supported Go version. +GOVULNCHECK_VERSION="v1.1.1" + +# Install build time dependencies. sudo apt-get update -sudo apt-get install -y pkg-config libgpgme-dev libbtrfs-dev libseccomp-dev libdevmapper-dev btrfs-progs +sudo apt-get install -y pkg-config libgpgme-dev libbtrfs-dev libseccomp-dev btrfs-progs -# Set environment variables +# Set environment variables. +export GOGC=off export GO111MODULE=on -export GOSUMDB=sum.golang.org -export PKG_CONFIG_PATH=/usr/lib/x86_64-linux-gnu/pkgconfig -GOPATH_BIN=$(go env GOPATH)/bin -export PATH="$PATH:$GOPATH_BIN" +export GOSUMDB="sum.golang.org" +export PKG_CONFIG_PATH="/usr/lib/x86_64-linux-gnu/pkgconfig" +GOPATH_BIN="$(go env GOPATH)"/bin +export PATH="${PATH}:${GOPATH_BIN}" -# Install gosec -go install golang.org/x/vuln/cmd/govulncheck@latest +# Install govulncheck. +go install golang.org/x/vuln/cmd/govulncheck@${GOVULNCHECK_VERSION} -# Generate report +# Generate the report. report=$(mktemp) trap 'rm "$report"' EXIT -"$GOPATH_BIN"/govulncheck -json -tags=test ./... >"$report" +"$GOPATH_BIN"/govulncheck -json -tags=test,exclude_graphdriver_devicemapper ./... >"$report" -# Parse vulnerabilities from report +# Parse vulnerabilities from the report. modvulns=$(jq -Sr '.vulnerability.modules[]? | select(.path != "stdlib") | [.path, "affected package(s): \(.packages[].path)", "found version: \(.found_version)", "fixed version: \(.fixed_version)"]' <"$report") libvulns=$(jq -Sr '.vulnerability.modules[]? | select(.path == "stdlib") | [.path, "affected package(s): \(.packages[].path)", "found version: \(.found_version)", "fixed version: \(.fixed_version)"]' <"$report") -# Print vulnerabilities +# Print vulnerabilities information, if any. echo "$modvulns" echo "$libvulns" -# Exit with non-zero status if there are any vulnerabilities in module dependencies +# Exit with non-zero status if there were any vulnerabilities detected in module dependencies. if [[ -n "$modvulns" ]]; then exit 1 fi From b31a87cef60f8a15393e247914faa37afcae96aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Wilczy=C5=84ski?= Date: Sun, 8 Sep 2024 00:31:30 +0900 Subject: [PATCH 7/8] Pin govulncheck to specific version to match Go version requirements MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Krzysztof Wilczyński --- .github/workflows/test.yml | 4 ++-- dependencies.yaml | 6 ++++++ hack/govulncheck.sh | 30 +++++++++++++++++------------- 3 files changed, 25 insertions(+), 15 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4b4c569b0e8..baba3e0ba2c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -382,7 +382,7 @@ jobs: - uses: actions/setup-go@v4 with: go-version: ${{ env.GO_VERSION }} - - name: Run Govulncheck + - name: Run govulncheck run: make verify-govulncheck - - name: Run Gosec + - name: Run gosec run: make verify-gosec diff --git a/dependencies.yaml b/dependencies.yaml index d49ae735fa2..8f07012906f 100644 --- a/dependencies.yaml +++ b/dependencies.yaml @@ -111,6 +111,12 @@ dependencies: - path: Makefile match: GO_MOD_OUTDATED_VERSION + - name: govulncheck + version: v1.1.1 + refPaths: + - path: hack/govulncheck.sh + match: GOVULNCHECK_VERSION + - name: gosec version: 2.15.0 refPaths: diff --git a/hack/govulncheck.sh b/hack/govulncheck.sh index be13e836c8f..ba529dbec1d 100755 --- a/hack/govulncheck.sh +++ b/hack/govulncheck.sh @@ -1,35 +1,39 @@ -#!/bin/bash +#!/usr/bin/env bash set -euo pipefail -# Install dependencies +# The govulncheck version should match supported Go version. +GOVULNCHECK_VERSION="v1.1.1" + +# Install build time dependencies. sudo apt-get update sudo apt-get install -y pkg-config libgpgme-dev libbtrfs-dev libseccomp-dev libdevmapper-dev btrfs-progs -# Set environment variables +# Set environment variables. +export GOGC=off export GO111MODULE=on -export GOSUMDB=sum.golang.org -export PKG_CONFIG_PATH=/usr/lib/x86_64-linux-gnu/pkgconfig -GOPATH_BIN=$(go env GOPATH)/bin -export PATH="$PATH:$GOPATH_BIN" +export GOSUMDB="sum.golang.org" +export PKG_CONFIG_PATH="/usr/lib/x86_64-linux-gnu/pkgconfig" +GOPATH_BIN="$(go env GOPATH)"/bin +export PATH="${PATH}:${GOPATH_BIN}" -# Install gosec -go install golang.org/x/vuln/cmd/govulncheck@latest +# Install govulncheck. +go install golang.org/x/vuln/cmd/govulncheck@${GOVULNCHECK_VERSION} -# Generate report +# Generate the report. report=$(mktemp) trap 'rm "$report"' EXIT "$GOPATH_BIN"/govulncheck -json -tags=test ./... >"$report" -# Parse vulnerabilities from report +# Parse vulnerabilities from the report. modvulns=$(jq -Sr '.vulnerability.modules[]? | select(.path != "stdlib") | [.path, "affected package(s): \(.packages[].path)", "found version: \(.found_version)", "fixed version: \(.fixed_version)"]' <"$report") libvulns=$(jq -Sr '.vulnerability.modules[]? | select(.path == "stdlib") | [.path, "affected package(s): \(.packages[].path)", "found version: \(.found_version)", "fixed version: \(.fixed_version)"]' <"$report") -# Print vulnerabilities +# Print vulnerabilities information, if any. echo "$modvulns" echo "$libvulns" -# Exit with non-zero status if there are any vulnerabilities in module dependencies +# Exit with non-zero status if there were any vulnerabilities detected in module dependencies. if [[ -n "$modvulns" ]]; then exit 1 fi From 6058166be54f2094f2071da099fdf586bdd9da77 Mon Sep 17 00:00:00 2001 From: Kubernetes Release Robot Date: Tue, 1 Oct 2024 00:26:13 +0000 Subject: [PATCH 8/8] version: bump to 1.28.11 Signed-off-by: Kubernetes Release Robot --- internal/version/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/version/version.go b/internal/version/version.go index 18a9f9d4f16..95072910b3b 100644 --- a/internal/version/version.go +++ b/internal/version/version.go @@ -20,7 +20,7 @@ import ( ) // Version is the version of the build. -const Version = "1.28.10" +const Version = "1.28.11" // Variables injected during build-time var (