From b1265637d21319805ef1ec6b379768cba774acfc Mon Sep 17 00:00:00 2001 From: Xavier Coulon Date: Mon, 3 Aug 2026 16:44:04 +0200 Subject: [PATCH 1/6] refactor: update toolchain-common with renamed ServerSideApplyClient type fix golangci-lint issues: in particular, use `os.Root` to avoid Time-of-Check-Time-of-Use (TOCTOU) race condition with symlinks in filepath.Walk/filepath.WalkDir callbacks also, update the golangci-lint-action settings Signed-off-by: Xavier Coulon --- .github/workflows/linters.yml | 4 +--- .govulncheck.yaml | 2 +- go.mod | 2 ++ go.sum | 4 ++-- pkg/cmd/add_space_users.go | 2 +- pkg/cmd/adm/install_operator.go | 6 +++--- pkg/cmd/adm/install_operator_test.go | 16 ++++++++-------- pkg/cmd/generate/assertion_test.go | 9 +++++++-- pkg/cmd/generate/nstemplatetiers.go | 9 +++++++-- pkg/cmd/generate/nstemplatetiers_test.go | 5 ++++- 10 files changed, 36 insertions(+), 23 deletions(-) diff --git a/.github/workflows/linters.yml b/.github/workflows/linters.yml index 267c5015..30311c39 100644 --- a/.github/workflows/linters.yml +++ b/.github/workflows/linters.yml @@ -26,9 +26,7 @@ jobs: - name: Lint uses: golangci/golangci-lint-action@v9 with: - version: v2.1.6 - skip-pkg-cache: true - skip-build-cache: true + version: v2.12.2 args: --config=./.golangci.yml --verbose yammlint: diff --git a/.govulncheck.yaml b/.govulncheck.yaml index 2bc6f3ee..b788c98c 100644 --- a/.govulncheck.yaml +++ b/.govulncheck.yaml @@ -76,4 +76,4 @@ ignored-vulnerabilities: # Fixed in: golang.org/x/text/unicode/norm@v0.39.0 - id: GO-2026-5970 silence-until: 2026-09-03 - info: https://pkg.go.dev/vuln/GO-2026-5970 + info: https://pkg.go.dev/vuln/GO-2026-5970 \ No newline at end of file diff --git a/go.mod b/go.mod index 84ee6f95..bd52bcad 100644 --- a/go.mod +++ b/go.mod @@ -28,6 +28,8 @@ require ( sigs.k8s.io/kustomize/api v0.19.0 ) +replace github.com/codeready-toolchain/toolchain-common => github.com/xcoulon/toolchain-common v0.0.0-20260803142641-2756b24ebace + require ( github.com/charmbracelet/bubbletea v1.1.0 github.com/charmbracelet/huh v0.6.0 diff --git a/go.sum b/go.sum index 4a1deb0f..fdd26513 100644 --- a/go.sum +++ b/go.sum @@ -44,8 +44,6 @@ github.com/charmbracelet/x/term v0.2.0 h1:cNB9Ot9q8I711MyZ7myUR5HFWL/lc3OpU8jZ4h github.com/charmbracelet/x/term v0.2.0/go.mod h1:GVxgxAbjUrmpvIINHIQnJJKpMlHiZ4cktEQCN6GWyF0= github.com/codeready-toolchain/api v0.0.0-20260731065234-734640c901d2 h1:i5izQYQWwi0Dbc2Mv/sDOJ5GIMH69O3n0jRwQaAWo9o= github.com/codeready-toolchain/api v0.0.0-20260731065234-734640c901d2/go.mod h1:PMg6kNHuCGNlu3MOdrCisqGkBpvzB0qS1+E6nrXxPAc= -github.com/codeready-toolchain/toolchain-common v0.0.0-20260731071123-c63091456f4a h1:3t4cvcI/6ZUxUSRZoGS/Q9jH9OFu6Sg26PMTtOPRok4= -github.com/codeready-toolchain/toolchain-common v0.0.0-20260731071123-c63091456f4a/go.mod h1:j4xJuhNtqEuZW7VR6BB5V6h/oDJ0dIwSh5iijUSwwdM= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= @@ -245,6 +243,8 @@ github.com/stretchr/testify v1.11.0 h1:ib4sjIrwZKxE5u/Japgo/7SJV3PvgjGiRNAvTVGqQ github.com/stretchr/testify v1.11.0/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= +github.com/xcoulon/toolchain-common v0.0.0-20260803142641-2756b24ebace h1:aW/k32FZO9wr4IcCR6adbdXdamiazxdEDV0VY16MU7w= +github.com/xcoulon/toolchain-common v0.0.0-20260803142641-2756b24ebace/go.mod h1:j4xJuhNtqEuZW7VR6BB5V6h/oDJ0dIwSh5iijUSwwdM= github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ= github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= diff --git a/pkg/cmd/add_space_users.go b/pkg/cmd/add_space_users.go index a3e5801f..fa8b37d5 100644 --- a/pkg/cmd/add_space_users.go +++ b/pkg/cmd/add_space_users.go @@ -72,7 +72,7 @@ func AddSpaceUsers(ctx *clicontext.CommandContext, spaceName, role string, users validRolesMsg.WriteString("the following are valid roles:\n") for actual := range nsTemplTier.Spec.SpaceRoles { - validRolesMsg.WriteString(fmt.Sprintf("%s\n", actual)) + fmt.Fprintf(&validRolesMsg, "%s\n", actual) if role == actual { isRoleValid = true } diff --git a/pkg/cmd/adm/install_operator.go b/pkg/cmd/adm/install_operator.go index 01ccf201..25f3f691 100644 --- a/pkg/cmd/adm/install_operator.go +++ b/pkg/cmd/adm/install_operator.go @@ -44,7 +44,7 @@ func NewInstallOperatorCmd() *cobra.Command { return err } - cl := commonclient.NewSSAApplyClient(kubeClient, utils.KsctlFieldManager) + cl := commonclient.NewServerSideApplyClient(kubeClient, utils.KsctlFieldManager) ctx := clicontext.NewTerminalContext(term) return installOperator(ctx, commandArgs, args[0], cl) }, @@ -57,7 +57,7 @@ func NewInstallOperatorCmd() *cobra.Command { return cmd } -func installOperator(ctx *clicontext.TerminalContext, args installArgs, operator string, applyClient *commonclient.SSAApplyClient) error { +func installOperator(ctx *clicontext.TerminalContext, args installArgs, operator string, applyClient *commonclient.ServerSideApplyClient) error { // validate cluster type if operator != string(configuration.Host) && operator != string(configuration.Member) { return fmt.Errorf("invalid operator type provided: %s. Valid ones are %s|%s", operator, configuration.Host, configuration.Member) @@ -136,7 +136,7 @@ func getOperatorName(operator string) string { return fmt.Sprintf("toolchain-%s-operator", operator) } -func createNamespaceIfNotFound(ctx *clicontext.TerminalContext, applyClient *commonclient.SSAApplyClient, namespace string) error { +func createNamespaceIfNotFound(ctx *clicontext.TerminalContext, applyClient *commonclient.ServerSideApplyClient, namespace string) error { ns := &v1.Namespace{ ObjectMeta: metav1.ObjectMeta{ Name: namespace, diff --git a/pkg/cmd/adm/install_operator_test.go b/pkg/cmd/adm/install_operator_test.go index 697a772e..eb328fb5 100644 --- a/pkg/cmd/adm/install_operator_test.go +++ b/pkg/cmd/adm/install_operator_test.go @@ -65,7 +65,7 @@ func TestInstallOperator(t *testing.T) { ctx := clicontext.NewTerminalContext(term) // when - err := installOperator(ctx, args, operator, commonclient.NewSSAApplyClient(fakeClient, utils.KsctlFieldManager)) + err := installOperator(ctx, args, operator, commonclient.NewServerSideApplyClient(fakeClient, utils.KsctlFieldManager)) // then require.NoError(t, err) @@ -100,7 +100,7 @@ func TestInstallOperator(t *testing.T) { ctx := clicontext.NewTerminalContext(term) // when - err := installOperator(ctx, args, operator, commonclient.NewSSAApplyClient(fakeClient, utils.KsctlFieldManager)) + err := installOperator(ctx, args, operator, commonclient.NewServerSideApplyClient(fakeClient, utils.KsctlFieldManager)) // then require.ErrorContains(t, err, "failed waiting for catalog source to be ready.") @@ -120,7 +120,7 @@ func TestInstallOperator(t *testing.T) { ctx := clicontext.NewTerminalContext(term) // when - err := installOperator(ctx, args, operator, commonclient.NewSSAApplyClient(fakeClient, utils.KsctlFieldManager)) + err := installOperator(ctx, args, operator, commonclient.NewServerSideApplyClient(fakeClient, utils.KsctlFieldManager)) // then require.ErrorContains(t, err, "failed waiting for install plan to be complete.") @@ -140,7 +140,7 @@ func TestInstallOperator(t *testing.T) { // when err := installOperator(ctx, installArgs{namespace: namespace, waitForReadyTimeout: 1 * time.Second}, operator, - commonclient.NewSSAApplyClient(fakeClient, utils.KsctlFieldManager), + commonclient.NewServerSideApplyClient(fakeClient, utils.KsctlFieldManager), ) // then @@ -158,7 +158,7 @@ func TestInstallOperator(t *testing.T) { ctx := clicontext.NewTerminalContext(term) // when - err := installOperator(ctx, args, operator, commonclient.NewSSAApplyClient(fakeClient, utils.KsctlFieldManager)) + err := installOperator(ctx, args, operator, commonclient.NewServerSideApplyClient(fakeClient, utils.KsctlFieldManager)) // then require.NoError(t, err) @@ -177,7 +177,7 @@ func TestInstallOperator(t *testing.T) { // when err := installOperator(ctx, installArgs{namespace: "", kubeConfig: kubeconfig, waitForReadyTimeout: timeout}, // we provide no namespace operator, - commonclient.NewSSAApplyClient(fakeClient, utils.KsctlFieldManager), + commonclient.NewServerSideApplyClient(fakeClient, utils.KsctlFieldManager), ) // then require.NoError(t, err) @@ -195,7 +195,7 @@ func TestInstallOperator(t *testing.T) { // when err := installOperator(ctx, installArgs{}, "INVALIDOPERATOR", - commonclient.NewSSAApplyClient(fakeClient, utils.KsctlFieldManager), + commonclient.NewServerSideApplyClient(fakeClient, utils.KsctlFieldManager), ) // then @@ -212,7 +212,7 @@ func TestInstallOperator(t *testing.T) { operator := "host" err := installOperator(ctx, installArgs{namespace: "toolchain-host-operator", waitForReadyTimeout: time.Second * 1}, operator, - commonclient.NewSSAApplyClient(fakeClient, utils.KsctlFieldManager), + commonclient.NewServerSideApplyClient(fakeClient, utils.KsctlFieldManager), ) // then diff --git a/pkg/cmd/generate/assertion_test.go b/pkg/cmd/generate/assertion_test.go index 5ef49e41..4c82bef0 100644 --- a/pkg/cmd/generate/assertion_test.go +++ b/pkg/cmd/generate/assertion_test.go @@ -133,13 +133,18 @@ func inKStructure(t *testing.T, out, rootDirName string) *kStructureAssertion { func (a *kStructureAssertion) listObjects(dirName, kind string, object runtimeclient.Object) ([]runtimeclient.Object, error) { var objects []runtimeclient.Object - err := filepath.WalkDir(filepath.Join(a.out, a.rootDirName), func(path string, dirEntry fs.DirEntry, err error) error { + root, err := os.OpenRoot(filepath.Join(a.out, a.rootDirName)) + if err != nil { + return nil, err + } + defer root.Close() + err = fs.WalkDir(root.FS(), ".", func(path string, dirEntry fs.DirEntry, err error) error { if err != nil { return err } if dirEntry != nil && !dirEntry.IsDir() && (filepath.Base(filepath.Dir(path)) == dirName || dirName == "") && dirEntry.Name() != "kustomization.yaml" { obj := object.DeepCopyObject() - objFile, err := os.ReadFile(path) + objFile, err := fs.ReadFile(root.FS(), path) require.NoError(a.t, err) assert.True(a.t, strings.HasPrefix(string(objFile), header), "every file generated by cli should container a header") assert.NotContains(a.t, string(objFile), "creationTimestamp") diff --git a/pkg/cmd/generate/nstemplatetiers.go b/pkg/cmd/generate/nstemplatetiers.go index c7ca9336..30667665 100644 --- a/pkg/cmd/generate/nstemplatetiers.go +++ b/pkg/cmd/generate/nstemplatetiers.go @@ -46,14 +46,19 @@ func NSTemplateTiers(term ioutils.Terminal, source, outDir, hostNs string) error metadata := map[string]string{} templates := map[string][]byte{} - err := filepath.Walk(source, func(path string, info fs.FileInfo, err error) error { + root, err := os.OpenRoot(source) + if err != nil { + return err + } + defer root.Close() + err = fs.WalkDir(root.FS(), ".", func(path string, info fs.DirEntry, err error) error { if err != nil { return err } if info.IsDir() { return nil } - file, err := os.ReadFile(path) + file, err := fs.ReadFile(root.FS(), path) if err != nil { return err } diff --git a/pkg/cmd/generate/nstemplatetiers_test.go b/pkg/cmd/generate/nstemplatetiers_test.go index d659a724..5e3cd7c2 100644 --- a/pkg/cmd/generate/nstemplatetiers_test.go +++ b/pkg/cmd/generate/nstemplatetiers_test.go @@ -212,6 +212,9 @@ func verifyTierFiles(t *testing.T, outTempDir, sourceDir, updatedTier string, ol func copyTemplates(t *testing.T, destination, tierToUpdate string) { sourceDir, err := filepath.Abs("../../../test-resources/nstemplatetiers/") require.NoError(t, err) + root, err := os.OpenRoot(sourceDir) + require.NoError(t, err) + defer root.Close() err = filepath.WalkDir(sourceDir, func(path string, dirEntry fs.DirEntry, err error) error { if err != nil { return err @@ -221,7 +224,7 @@ func copyTemplates(t *testing.T, destination, tierToUpdate string) { if dirEntry.IsDir() { return os.MkdirAll(newPath, 0744) } - file, err := os.ReadFile(path) + file, err := fs.ReadFile(root.FS(), path) if err != nil { return err } From 3dff418898c98f6c4a8adc292edf2e5c84b4fdea Mon Sep 17 00:00:00 2001 From: Xavier Coulon Date: Tue, 4 Aug 2026 11:40:01 +0200 Subject: [PATCH 2/6] update code Signed-off-by: Xavier Coulon --- pkg/cmd/generate/assertion_test.go | 16 +++++++++++----- pkg/cmd/generate/nstemplatetiers.go | 19 +++++++++++++------ pkg/cmd/generate/nstemplatetiers_test.go | 19 ++++++++++++------- 3 files changed, 36 insertions(+), 18 deletions(-) diff --git a/pkg/cmd/generate/assertion_test.go b/pkg/cmd/generate/assertion_test.go index 4c82bef0..9d716c60 100644 --- a/pkg/cmd/generate/assertion_test.go +++ b/pkg/cmd/generate/assertion_test.go @@ -3,6 +3,7 @@ package generate import ( "encoding/json" "fmt" + "io" "io/fs" "os" "path/filepath" @@ -133,18 +134,23 @@ func inKStructure(t *testing.T, out, rootDirName string) *kStructureAssertion { func (a *kStructureAssertion) listObjects(dirName, kind string, object runtimeclient.Object) ([]runtimeclient.Object, error) { var objects []runtimeclient.Object - root, err := os.OpenRoot(filepath.Join(a.out, a.rootDirName)) + rootDir := filepath.Join(a.out, a.rootDirName) + root, err := os.OpenRoot(rootDir) if err != nil { return nil, err } defer root.Close() - err = fs.WalkDir(root.FS(), ".", func(path string, dirEntry fs.DirEntry, err error) error { + + err = fs.WalkDir(root.FS(), ".", func(path string, d fs.DirEntry, err error) error { if err != nil { return err } - if dirEntry != nil && !dirEntry.IsDir() && (filepath.Base(filepath.Dir(path)) == dirName || dirName == "") && dirEntry.Name() != "kustomization.yaml" { + if d != nil && !d.IsDir() && (filepath.Base(filepath.Dir(path)) == dirName || dirName == "") && d.Name() != "kustomization.yaml" { obj := object.DeepCopyObject() - objFile, err := fs.ReadFile(root.FS(), path) + f, err := root.Open(path) + require.NoError(a.t, err) + objFile, err := io.ReadAll(f) + f.Close() require.NoError(a.t, err) assert.True(a.t, strings.HasPrefix(string(objFile), header), "every file generated by cli should container a header") assert.NotContains(a.t, string(objFile), "creationTimestamp") @@ -153,7 +159,7 @@ func (a *kStructureAssertion) listObjects(dirName, kind string, object runtimecl require.NoError(a.t, err) if obj.GetObjectKind().GroupVersionKind().Kind == kind { objects = append(objects, obj.(runtimeclient.Object)) - assertKustomizationFiles(a.t, a.out, a.rootDirName, path) + assertKustomizationFiles(a.t, a.out, a.rootDirName, filepath.Join(rootDir, path)) } } return nil diff --git a/pkg/cmd/generate/nstemplatetiers.go b/pkg/cmd/generate/nstemplatetiers.go index 30667665..c51e8367 100644 --- a/pkg/cmd/generate/nstemplatetiers.go +++ b/pkg/cmd/generate/nstemplatetiers.go @@ -3,6 +3,7 @@ package generate import ( "fmt" "hash/crc32" + "io" "io/fs" "os" "path/filepath" @@ -44,25 +45,31 @@ func NSTemplateTiers(term ioutils.Terminal, source, outDir, hostNs string) error return err } - metadata := map[string]string{} - templates := map[string][]byte{} root, err := os.OpenRoot(source) if err != nil { return err } defer root.Close() - err = fs.WalkDir(root.FS(), ".", func(path string, info fs.DirEntry, err error) error { + + metadata := map[string]string{} + templates := map[string][]byte{} + err = fs.WalkDir(root.FS(), ".", func(path string, d fs.DirEntry, err error) error { if err != nil { return err } - if info.IsDir() { + if d.IsDir() { return nil } - file, err := fs.ReadFile(root.FS(), path) + f, err := root.Open(path) + if err != nil { + return err + } + defer f.Close() + file, err := io.ReadAll(f) if err != nil { return err } - tmplPath := filepath.Join(filepath.Base(filepath.Dir(path)), info.Name()) + tmplPath := filepath.Join(filepath.Base(filepath.Dir(path)), d.Name()) templates[tmplPath] = file checksum := crc32.Checksum(file, crc32.IEEETable) metadata[strings.TrimSuffix(tmplPath, ".yaml")] = fmt.Sprint(checksum) diff --git a/pkg/cmd/generate/nstemplatetiers_test.go b/pkg/cmd/generate/nstemplatetiers_test.go index 5e3cd7c2..3624817e 100644 --- a/pkg/cmd/generate/nstemplatetiers_test.go +++ b/pkg/cmd/generate/nstemplatetiers_test.go @@ -2,6 +2,7 @@ package generate import ( "fmt" + "io" "io/fs" "os" "path/filepath" @@ -104,7 +105,7 @@ func TestGenerateNSTemplateTiers(t *testing.T) { // then require.Error(t, err) - assert.Equal(t, "lstat /does/not/exist: no such file or directory", err.Error()) // error occurred while creating TierTemplate resources + assert.Equal(t, "open /does/not/exist: no such file or directory", err.Error()) // error occurred while opening the root directory }) t.Run("failed to process wrong files", func(t *testing.T) { @@ -215,20 +216,24 @@ func copyTemplates(t *testing.T, destination, tierToUpdate string) { root, err := os.OpenRoot(sourceDir) require.NoError(t, err) defer root.Close() - err = filepath.WalkDir(sourceDir, func(path string, dirEntry fs.DirEntry, err error) error { + err = fs.WalkDir(root.FS(), ".", func(path string, d fs.DirEntry, err error) error { if err != nil { return err } - suffix, _ := strings.CutPrefix(path, sourceDir) - newPath := filepath.Join(destination, suffix) - if dirEntry.IsDir() { + newPath := filepath.Join(destination, path) + if d.IsDir() { return os.MkdirAll(newPath, 0744) } - file, err := fs.ReadFile(root.FS(), path) + f, err := root.Open(path) if err != nil { return err } - if tierToUpdate != "" && strings.Contains(path, tierToUpdate+string(filepath.Separator)) && filepath.Base(path) != "tier.yaml" { + defer f.Close() + file, err := io.ReadAll(f) + if err != nil { + return err + } + if tierToUpdate != "" && strings.Contains(path, tierToUpdate+"/") && filepath.Base(path) != "tier.yaml" { file = []byte(strings.Replace(string(file), "metadata:", `metadata: annotations: modified-by: "test"`, 1)) From 742eb8a7a4ec6447d74a66ea795656fdde5ae191 Mon Sep 17 00:00:00 2001 From: Xavier Coulon Date: Tue, 4 Aug 2026 13:12:14 +0200 Subject: [PATCH 3/6] update govulncheck exclusions Signed-off-by: Xavier Coulon --- .govulncheck.yaml | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/.govulncheck.yaml b/.govulncheck.yaml index b788c98c..b2018681 100644 --- a/.govulncheck.yaml +++ b/.govulncheck.yaml @@ -18,8 +18,8 @@ ignored-vulnerabilities: silence-until: 2026-09-03 info: https://pkg.go.dev/vuln/GO-2026-4870 # Infinite loop in HTTP/2 transport when given bad SETTINGS_MAX_FRAME_SIZE in net/http/internal/http2 in golang.org/x/net - # Found in: net/http@go1.24.13 - # Fixed in: net/http@go1.25.10 + # Found in: golang.org/x/net/http2@v0.47.0 + # Fixed in: golang.org/x/net/http2@v0.53.0 - id: GO-2026-4918 silence-until: 2026-09-03 info: https://pkg.go.dev/vuln/GO-2026-4918 @@ -35,6 +35,12 @@ ignored-vulnerabilities: - id: GO-2026-4947 silence-until: 2026-09-03 info: https://pkg.go.dev/vuln/GO-2026-4947 + # Root escape via symlink plus trailing slash in os + # Found in: os@go1.24.13 + # Fixed in: os@go1.25.12 + - id: GO-2026-4970 + silence-until: 2026-09-03 + info: https://pkg.go.dev/vuln/GO-2026-4970 # Panic in Dial and LookupPort when handling NUL byte on Windows in net # Found in: net@go1.24.13 # Fixed in: net@go1.25.10 @@ -76,4 +82,4 @@ ignored-vulnerabilities: # Fixed in: golang.org/x/text/unicode/norm@v0.39.0 - id: GO-2026-5970 silence-until: 2026-09-03 - info: https://pkg.go.dev/vuln/GO-2026-5970 \ No newline at end of file + info: https://pkg.go.dev/vuln/GO-2026-5970 From 315f9612786f8f2b561d0aa51a2c5d409fe15299 Mon Sep 17 00:00:00 2001 From: Xavier Coulon Date: Tue, 4 Aug 2026 15:00:09 +0200 Subject: [PATCH 4/6] revert changes related to filepath.Walk/filepath.WalkDir callbacks we're safe to use os.ReadFile/os.WriteFile in ksctl codebase This reverts commit 3dff418898c98f6c4a8adc292edf2e5c84b4fdea. --- pkg/cmd/generate/assertion_test.go | 19 ++++--------------- pkg/cmd/generate/nstemplatetiers.go | 20 ++++---------------- pkg/cmd/generate/nstemplatetiers_test.go | 24 ++++++++---------------- 3 files changed, 16 insertions(+), 47 deletions(-) diff --git a/pkg/cmd/generate/assertion_test.go b/pkg/cmd/generate/assertion_test.go index 9d716c60..a71f31c6 100644 --- a/pkg/cmd/generate/assertion_test.go +++ b/pkg/cmd/generate/assertion_test.go @@ -3,7 +3,6 @@ package generate import ( "encoding/json" "fmt" - "io" "io/fs" "os" "path/filepath" @@ -134,23 +133,13 @@ func inKStructure(t *testing.T, out, rootDirName string) *kStructureAssertion { func (a *kStructureAssertion) listObjects(dirName, kind string, object runtimeclient.Object) ([]runtimeclient.Object, error) { var objects []runtimeclient.Object - rootDir := filepath.Join(a.out, a.rootDirName) - root, err := os.OpenRoot(rootDir) - if err != nil { - return nil, err - } - defer root.Close() - - err = fs.WalkDir(root.FS(), ".", func(path string, d fs.DirEntry, err error) error { + err := filepath.WalkDir(filepath.Join(a.out, a.rootDirName), func(path string, dirEntry fs.DirEntry, err error) error { if err != nil { return err } - if d != nil && !d.IsDir() && (filepath.Base(filepath.Dir(path)) == dirName || dirName == "") && d.Name() != "kustomization.yaml" { + if dirEntry != nil && !dirEntry.IsDir() && (filepath.Base(filepath.Dir(path)) == dirName || dirName == "") && dirEntry.Name() != "kustomization.yaml" { obj := object.DeepCopyObject() - f, err := root.Open(path) - require.NoError(a.t, err) - objFile, err := io.ReadAll(f) - f.Close() + objFile, err := os.ReadFile(path) //nolint:gosec require.NoError(a.t, err) assert.True(a.t, strings.HasPrefix(string(objFile), header), "every file generated by cli should container a header") assert.NotContains(a.t, string(objFile), "creationTimestamp") @@ -159,7 +148,7 @@ func (a *kStructureAssertion) listObjects(dirName, kind string, object runtimecl require.NoError(a.t, err) if obj.GetObjectKind().GroupVersionKind().Kind == kind { objects = append(objects, obj.(runtimeclient.Object)) - assertKustomizationFiles(a.t, a.out, a.rootDirName, filepath.Join(rootDir, path)) + assertKustomizationFiles(a.t, a.out, a.rootDirName, path) } } return nil diff --git a/pkg/cmd/generate/nstemplatetiers.go b/pkg/cmd/generate/nstemplatetiers.go index c51e8367..b37ad08a 100644 --- a/pkg/cmd/generate/nstemplatetiers.go +++ b/pkg/cmd/generate/nstemplatetiers.go @@ -3,7 +3,6 @@ package generate import ( "fmt" "hash/crc32" - "io" "io/fs" "os" "path/filepath" @@ -45,31 +44,20 @@ func NSTemplateTiers(term ioutils.Terminal, source, outDir, hostNs string) error return err } - root, err := os.OpenRoot(source) - if err != nil { - return err - } - defer root.Close() - metadata := map[string]string{} templates := map[string][]byte{} - err = fs.WalkDir(root.FS(), ".", func(path string, d fs.DirEntry, err error) error { + err := filepath.Walk(source, func(path string, info fs.FileInfo, err error) error { if err != nil { return err } - if d.IsDir() { + if info.IsDir() { return nil } - f, err := root.Open(path) - if err != nil { - return err - } - defer f.Close() - file, err := io.ReadAll(f) + file, err := os.ReadFile(path) //nolint:gosec if err != nil { return err } - tmplPath := filepath.Join(filepath.Base(filepath.Dir(path)), d.Name()) + tmplPath := filepath.Join(filepath.Base(filepath.Dir(path)), info.Name()) templates[tmplPath] = file checksum := crc32.Checksum(file, crc32.IEEETable) metadata[strings.TrimSuffix(tmplPath, ".yaml")] = fmt.Sprint(checksum) diff --git a/pkg/cmd/generate/nstemplatetiers_test.go b/pkg/cmd/generate/nstemplatetiers_test.go index 3624817e..2db59a64 100644 --- a/pkg/cmd/generate/nstemplatetiers_test.go +++ b/pkg/cmd/generate/nstemplatetiers_test.go @@ -2,7 +2,6 @@ package generate import ( "fmt" - "io" "io/fs" "os" "path/filepath" @@ -105,7 +104,7 @@ func TestGenerateNSTemplateTiers(t *testing.T) { // then require.Error(t, err) - assert.Equal(t, "open /does/not/exist: no such file or directory", err.Error()) // error occurred while opening the root directory + assert.Equal(t, "lstat /does/not/exist: no such file or directory", err.Error()) // error occurred while creating TierTemplate resources }) t.Run("failed to process wrong files", func(t *testing.T) { @@ -213,32 +212,25 @@ func verifyTierFiles(t *testing.T, outTempDir, sourceDir, updatedTier string, ol func copyTemplates(t *testing.T, destination, tierToUpdate string) { sourceDir, err := filepath.Abs("../../../test-resources/nstemplatetiers/") require.NoError(t, err) - root, err := os.OpenRoot(sourceDir) - require.NoError(t, err) - defer root.Close() - err = fs.WalkDir(root.FS(), ".", func(path string, d fs.DirEntry, err error) error { + err = filepath.WalkDir(sourceDir, func(path string, dirEntry fs.DirEntry, err error) error { if err != nil { return err } - newPath := filepath.Join(destination, path) - if d.IsDir() { + suffix, _ := strings.CutPrefix(path, sourceDir) + newPath := filepath.Join(destination, suffix) + if dirEntry.IsDir() { return os.MkdirAll(newPath, 0744) } - f, err := root.Open(path) - if err != nil { - return err - } - defer f.Close() - file, err := io.ReadAll(f) + file, err := os.ReadFile(path) //nolint:gosec if err != nil { return err } - if tierToUpdate != "" && strings.Contains(path, tierToUpdate+"/") && filepath.Base(path) != "tier.yaml" { + if tierToUpdate != "" && strings.Contains(path, tierToUpdate+string(filepath.Separator)) && filepath.Base(path) != "tier.yaml" { file = []byte(strings.Replace(string(file), "metadata:", `metadata: annotations: modified-by: "test"`, 1)) } - return os.WriteFile(newPath, file, 0600) + return os.WriteFile(newPath, file, 0600) //nolint:gosec }) require.NoError(t, err) } From 0e8d7acad5b8b791aa3745d44b46c0dd049107e1 Mon Sep 17 00:00:00 2001 From: Xavier Coulon Date: Tue, 4 Aug 2026 15:06:59 +0200 Subject: [PATCH 5/6] update 'common' dep Signed-off-by: Xavier Coulon --- go.mod | 2 -- go.sum | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index bd52bcad..84ee6f95 100644 --- a/go.mod +++ b/go.mod @@ -28,8 +28,6 @@ require ( sigs.k8s.io/kustomize/api v0.19.0 ) -replace github.com/codeready-toolchain/toolchain-common => github.com/xcoulon/toolchain-common v0.0.0-20260803142641-2756b24ebace - require ( github.com/charmbracelet/bubbletea v1.1.0 github.com/charmbracelet/huh v0.6.0 diff --git a/go.sum b/go.sum index fdd26513..4a1deb0f 100644 --- a/go.sum +++ b/go.sum @@ -44,6 +44,8 @@ github.com/charmbracelet/x/term v0.2.0 h1:cNB9Ot9q8I711MyZ7myUR5HFWL/lc3OpU8jZ4h github.com/charmbracelet/x/term v0.2.0/go.mod h1:GVxgxAbjUrmpvIINHIQnJJKpMlHiZ4cktEQCN6GWyF0= github.com/codeready-toolchain/api v0.0.0-20260731065234-734640c901d2 h1:i5izQYQWwi0Dbc2Mv/sDOJ5GIMH69O3n0jRwQaAWo9o= github.com/codeready-toolchain/api v0.0.0-20260731065234-734640c901d2/go.mod h1:PMg6kNHuCGNlu3MOdrCisqGkBpvzB0qS1+E6nrXxPAc= +github.com/codeready-toolchain/toolchain-common v0.0.0-20260731071123-c63091456f4a h1:3t4cvcI/6ZUxUSRZoGS/Q9jH9OFu6Sg26PMTtOPRok4= +github.com/codeready-toolchain/toolchain-common v0.0.0-20260731071123-c63091456f4a/go.mod h1:j4xJuhNtqEuZW7VR6BB5V6h/oDJ0dIwSh5iijUSwwdM= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= @@ -243,8 +245,6 @@ github.com/stretchr/testify v1.11.0 h1:ib4sjIrwZKxE5u/Japgo/7SJV3PvgjGiRNAvTVGqQ github.com/stretchr/testify v1.11.0/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= -github.com/xcoulon/toolchain-common v0.0.0-20260803142641-2756b24ebace h1:aW/k32FZO9wr4IcCR6adbdXdamiazxdEDV0VY16MU7w= -github.com/xcoulon/toolchain-common v0.0.0-20260803142641-2756b24ebace/go.mod h1:j4xJuhNtqEuZW7VR6BB5V6h/oDJ0dIwSh5iijUSwwdM= github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ= github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= From e0d88ad57040742df38902c7e410cd800f6e6ccd Mon Sep 17 00:00:00 2001 From: Xavier Coulon Date: Tue, 4 Aug 2026 15:13:34 +0200 Subject: [PATCH 6/6] update 'common' dep Signed-off-by: Xavier Coulon --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 84ee6f95..72647710 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ toolchain go1.24.13 require ( github.com/codeready-toolchain/api v0.0.0-20260731065234-734640c901d2 - github.com/codeready-toolchain/toolchain-common v0.0.0-20260731071123-c63091456f4a + github.com/codeready-toolchain/toolchain-common v0.0.0-20260804130313-0d4161d82454 github.com/ghodss/yaml v1.0.0 github.com/mitchellh/go-homedir v1.1.0 // using latest commit from 'github.com/openshift/api branch release-4.20' diff --git a/go.sum b/go.sum index 4a1deb0f..26ef37a9 100644 --- a/go.sum +++ b/go.sum @@ -44,8 +44,8 @@ github.com/charmbracelet/x/term v0.2.0 h1:cNB9Ot9q8I711MyZ7myUR5HFWL/lc3OpU8jZ4h github.com/charmbracelet/x/term v0.2.0/go.mod h1:GVxgxAbjUrmpvIINHIQnJJKpMlHiZ4cktEQCN6GWyF0= github.com/codeready-toolchain/api v0.0.0-20260731065234-734640c901d2 h1:i5izQYQWwi0Dbc2Mv/sDOJ5GIMH69O3n0jRwQaAWo9o= github.com/codeready-toolchain/api v0.0.0-20260731065234-734640c901d2/go.mod h1:PMg6kNHuCGNlu3MOdrCisqGkBpvzB0qS1+E6nrXxPAc= -github.com/codeready-toolchain/toolchain-common v0.0.0-20260731071123-c63091456f4a h1:3t4cvcI/6ZUxUSRZoGS/Q9jH9OFu6Sg26PMTtOPRok4= -github.com/codeready-toolchain/toolchain-common v0.0.0-20260731071123-c63091456f4a/go.mod h1:j4xJuhNtqEuZW7VR6BB5V6h/oDJ0dIwSh5iijUSwwdM= +github.com/codeready-toolchain/toolchain-common v0.0.0-20260804130313-0d4161d82454 h1:D3+dc9mEmLrq0XiG6xXDVJoZ+YChF7eX1OTKZ62ydfU= +github.com/codeready-toolchain/toolchain-common v0.0.0-20260804130313-0d4161d82454/go.mod h1:j4xJuhNtqEuZW7VR6BB5V6h/oDJ0dIwSh5iijUSwwdM= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=