From 7dd9fde7ce59d23ebd19ee10b455e17c68ad6163 Mon Sep 17 00:00:00 2001 From: Sibasis Padhi Date: Tue, 13 Jan 2026 10:25:59 -0600 Subject: [PATCH] fix: normalize paths to prevent concatenation on Windows Fixes #5673 On Windows, when using absolute paths like C:\path\to\dir, the path could be incorrectly concatenated, resulting in: C:\working\dir\C:\path\to\dir\file This fix applies filepath.Abs() and filepath.Clean() to normalize the path before using it, ensuring absolute paths are handled correctly on all platforms. Changes: - Apply filepath.Abs() to convert relative paths to absolute - Apply filepath.Clean() to remove redundant separators and resolve .. - Add tests for absolute paths, complex paths with .., and paths with redundant separators to verify normalization works correctly The tests use actual 'flux build kustomization' commands with: 1. Absolute paths (prevents concatenation bugs) 2. Paths with parent directory (..) references 3. Paths with redundant separators (//) All tests verify the command produces correct output, ensuring the path normalization fix works as expected. Signed-off-by: Sibasis Padhi --- cmd/flux/build_kustomization.go | 8 ++++ cmd/flux/build_kustomization_test.go | 62 ++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) diff --git a/cmd/flux/build_kustomization.go b/cmd/flux/build_kustomization.go index 5d29c001..2000faac 100644 --- a/cmd/flux/build_kustomization.go +++ b/cmd/flux/build_kustomization.go @@ -20,6 +20,7 @@ import ( "fmt" "os" "os/signal" + "path/filepath" "github.com/spf13/cobra" @@ -97,6 +98,13 @@ func buildKsCmdRun(cmd *cobra.Command, args []string) (err error) { return fmt.Errorf("invalid resource path %q", buildKsArgs.path) } + // Normalize the path to handle Windows absolute and relative paths correctly + buildKsArgs.path, err = filepath.Abs(buildKsArgs.path) + if err != nil { + return fmt.Errorf("failed to resolve absolute path: %w", err) + } + buildKsArgs.path = filepath.Clean(buildKsArgs.path) + if fs, err := os.Stat(buildKsArgs.path); err != nil || !fs.IsDir() { return fmt.Errorf("invalid resource path %q", buildKsArgs.path) } diff --git a/cmd/flux/build_kustomization_test.go b/cmd/flux/build_kustomization_test.go index 2f8036bb..7b49506e 100644 --- a/cmd/flux/build_kustomization_test.go +++ b/cmd/flux/build_kustomization_test.go @@ -218,3 +218,65 @@ spec: }) } } + +// TestBuildKustomizationPathNormalization verifies that absolute and complex +// paths are normalized to prevent path concatenation bugs (issue #5673). +// Without normalization, paths could be duplicated like: /path/test/path/test/file +func TestBuildKustomizationPathNormalization(t *testing.T) { + // Get absolute path to testdata to test absolute path handling + absTestDataPath, err := filepath.Abs("testdata/build-kustomization/podinfo") + if err != nil { + t.Fatalf("failed to get absolute path: %v", err) + } + + tests := []struct { + name string + args string + resultFile string + assertFunc string + }{ + { + name: "build with absolute path", + args: "build kustomization podinfo --path " + absTestDataPath, + resultFile: "./testdata/build-kustomization/podinfo-result.yaml", + assertFunc: "assertGoldenTemplateFile", + }, + { + name: "build with complex relative path (parent dir)", + args: "build kustomization podinfo --path ./testdata/build-kustomization/../build-kustomization/podinfo", + resultFile: "./testdata/build-kustomization/podinfo-result.yaml", + assertFunc: "assertGoldenTemplateFile", + }, + { + name: "build with path containing redundant separators", + args: "build kustomization podinfo --path ./testdata//build-kustomization//podinfo", + resultFile: "./testdata/build-kustomization/podinfo-result.yaml", + assertFunc: "assertGoldenTemplateFile", + }, + } + + tmpl := map[string]string{ + "fluxns": allocateNamespace("flux-system"), + } + setup(t, tmpl) + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var assert assertFunc + + switch tt.assertFunc { + case "assertGoldenTemplateFile": + assert = assertGoldenTemplateFile(tt.resultFile, tmpl) + case "assertError": + assert = assertError(tt.resultFile) + } + + cmd := cmdTestCase{ + args: tt.args + " -n " + tmpl["fluxns"], + assert: assert, + } + + cmd.runTestCmd(t) + }) + } +}