fix: prevent local absolute paths from being treated as remote URLs (#2397)
Add filepath.IsAbs guard to IsRemote and Parse to prevent Windows drive letter paths (e.g., C:\path) from being misinterpreted as remote URLs by go-getter's url.Parse, which prepends file:// to drive letter paths. Fixes #2384 Signed-off-by: Aditya Menon <amenon@canarytechnologies.com>
This commit is contained in:
parent
3a0703425f
commit
2f8b9cbdfb
|
|
@ -102,6 +102,9 @@ type Source struct {
|
|||
}
|
||||
|
||||
func IsRemote(goGetterSrc string) bool {
|
||||
if filepath.IsAbs(goGetterSrc) {
|
||||
return false
|
||||
}
|
||||
if _, err := Parse(goGetterSrc); err != nil {
|
||||
return false
|
||||
}
|
||||
|
|
@ -122,6 +125,13 @@ func Parse(goGetterSrc string) (*Source, error) {
|
|||
}
|
||||
}
|
||||
|
||||
// Local absolute paths (e.g., C:\path on Windows, /path on Unix)
|
||||
// are not remote URLs. Reject them before go-getter's url.Parse
|
||||
// can misinterpret Windows drive letters as URL schemes.
|
||||
if filepath.IsAbs(goGetterSrc) {
|
||||
return nil, InvalidURLError{err: fmt.Sprintf("parse url: local absolute path is not a remote URL: %s", goGetterSrc)}
|
||||
}
|
||||
|
||||
u, err := url.Parse(goGetterSrc)
|
||||
if err != nil {
|
||||
return nil, InvalidURLError{err: fmt.Sprintf("parse url: %v", err)}
|
||||
|
|
|
|||
|
|
@ -356,6 +356,54 @@ func TestRemote_S3(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestIsRemote(t *testing.T) {
|
||||
testcases := []struct {
|
||||
name string
|
||||
input string
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
name: "git remote URL",
|
||||
input: "git::https://github.com/cloudposse/helmfiles.git@releases/kiam.yaml?ref=0.40.0",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "s3 remote URL",
|
||||
input: "s3://helm-s3-values-example/values.yaml",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "https remote URL",
|
||||
input: "https://example.com/values.yaml",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "relative path",
|
||||
input: "relative/path/to/file.yaml",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "parent-relative path",
|
||||
input: "../services/values.yaml",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "unix absolute path",
|
||||
input: "/absolute/path/to/file.yaml",
|
||||
expected: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range testcases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := IsRemote(tt.input)
|
||||
if result != tt.expected {
|
||||
t.Errorf("IsRemote(%q) = %v, want %v", tt.input, result, tt.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParse(t *testing.T) {
|
||||
testcases := []struct {
|
||||
name string
|
||||
|
|
@ -372,6 +420,11 @@ func TestParse(t *testing.T) {
|
|||
input: "raw/incubator",
|
||||
err: "parse url: missing scheme - probably this is a local file path? raw/incubator",
|
||||
},
|
||||
{
|
||||
name: "unix absolute path",
|
||||
input: "/absolute/path/to/file.yaml",
|
||||
err: "parse url: local absolute path is not a remote URL: /absolute/path/to/file.yaml",
|
||||
},
|
||||
{
|
||||
name: "git scheme",
|
||||
input: "git::https://github.com/stakater/Forecastle.git@deployments/kubernetes/chart/forecastle?ref=v1.0.54",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,69 @@
|
|||
//go:build windows
|
||||
|
||||
package remote
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestIsRemote_Windows(t *testing.T) {
|
||||
testcases := []struct {
|
||||
name string
|
||||
input string
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
name: "windows drive letter path",
|
||||
input: `C:\project\services\values.yaml`,
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "windows UNC path",
|
||||
input: `\\server\share\path\values.yaml`,
|
||||
expected: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range testcases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := IsRemote(tt.input)
|
||||
if result != tt.expected {
|
||||
t.Errorf("IsRemote(%q) = %v, want %v", tt.input, result, tt.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParse_Windows(t *testing.T) {
|
||||
testcases := []struct {
|
||||
name string
|
||||
input string
|
||||
err string
|
||||
}{
|
||||
{
|
||||
name: "windows drive letter path",
|
||||
input: `C:\project\services\values.yaml`,
|
||||
err: `parse url: local absolute path is not a remote URL: C:\project\services\values.yaml`,
|
||||
},
|
||||
{
|
||||
name: "windows UNC path",
|
||||
input: `\\server\share\path\values.yaml`,
|
||||
err: `parse url: local absolute path is not a remote URL: \\server\share\path\values.yaml`,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range testcases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
_, err := Parse(tt.input)
|
||||
if err == nil {
|
||||
t.Fatalf("Parse(%q) expected error, got nil", tt.input)
|
||||
}
|
||||
if _, ok := err.(InvalidURLError); !ok {
|
||||
t.Fatalf("Parse(%q) expected InvalidURLError, got %T: %v", tt.input, err, err)
|
||||
}
|
||||
if err.Error() != tt.err {
|
||||
t.Errorf("Parse(%q) error = %q, want %q", tt.input, err.Error(), tt.err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue