github.com/argoproj/argo-cd/v3@v3.2.1/util/io/path/resolved_test.go (about) 1 package path 2 3 import ( 4 "os" 5 "path/filepath" 6 "testing" 7 8 "github.com/stretchr/testify/assert" 9 "github.com/stretchr/testify/require" 10 ) 11 12 func Test_resolveSymlinkRecursive(t *testing.T) { 13 testsDir, err := filepath.Abs("./testdata") 14 if err != nil { 15 panic(err) 16 } 17 t.Run("Resolve non-symlink", func(t *testing.T) { 18 r, err := resolveSymbolicLinkRecursive(testsDir+"/foo", 2) 19 require.NoError(t, err) 20 assert.Equal(t, testsDir+"/foo", r) 21 }) 22 t.Run("Successfully resolve symlink", func(t *testing.T) { 23 r, err := resolveSymbolicLinkRecursive(testsDir+"/bar", 2) 24 require.NoError(t, err) 25 assert.Equal(t, testsDir+"/foo", r) 26 }) 27 t.Run("Do not allow symlink at all", func(t *testing.T) { 28 r, err := resolveSymbolicLinkRecursive(testsDir+"/bar", 0) 29 require.Error(t, err) 30 assert.Empty(t, r) 31 }) 32 t.Run("Error because too nested symlink", func(t *testing.T) { 33 r, err := resolveSymbolicLinkRecursive(testsDir+"/bam", 2) 34 require.Error(t, err) 35 assert.Empty(t, r) 36 }) 37 t.Run("No such file or directory", func(t *testing.T) { 38 r, err := resolveSymbolicLinkRecursive(testsDir+"/foobar", 2) 39 require.NoError(t, err) 40 assert.Equal(t, testsDir+"/foobar", r) 41 }) 42 } 43 44 func Test_isURLSchemeAllowed(t *testing.T) { 45 type testdata struct { 46 name string 47 scheme string 48 allowed []string 49 expected bool 50 } 51 tts := []testdata{ 52 { 53 name: "Allowed scheme matches", 54 scheme: "http", 55 allowed: []string{"http", "https"}, 56 expected: true, 57 }, 58 { 59 name: "Allowed scheme matches only partially", 60 scheme: "http", 61 allowed: []string{"https"}, 62 expected: false, 63 }, 64 { 65 name: "Scheme is not allowed", 66 scheme: "file", 67 allowed: []string{"http", "https"}, 68 expected: false, 69 }, 70 { 71 name: "Empty scheme with valid allowances is forbidden", 72 scheme: "", 73 allowed: []string{"http", "https"}, 74 expected: false, 75 }, 76 { 77 name: "Empty scheme with empty allowances is forbidden", 78 scheme: "", 79 allowed: []string{}, 80 expected: false, 81 }, 82 { 83 name: "Some scheme with empty allowances is forbidden", 84 scheme: "file", 85 allowed: []string{}, 86 expected: false, 87 }, 88 } 89 for _, tt := range tts { 90 t.Run(tt.name, func(t *testing.T) { 91 r := isURLSchemeAllowed(tt.scheme, tt.allowed) 92 assert.Equal(t, tt.expected, r) 93 }) 94 } 95 } 96 97 var allowedRemoteProtocols = []string{"http", "https"} 98 99 func Test_resolveFilePath(t *testing.T) { 100 t.Run("Resolve normal relative path into absolute path", func(t *testing.T) { 101 p, remote, err := ResolveValueFilePathOrUrl("/foo/bar", "/foo", "baz/bim.yaml", allowedRemoteProtocols) 102 require.NoError(t, err) 103 assert.False(t, remote) 104 assert.Equal(t, "/foo/bar/baz/bim.yaml", string(p)) 105 }) 106 t.Run("Resolve normal relative path into absolute path", func(t *testing.T) { 107 p, remote, err := ResolveValueFilePathOrUrl("/foo/bar", "/foo", "baz/../../bim.yaml", allowedRemoteProtocols) 108 require.NoError(t, err) 109 assert.False(t, remote) 110 assert.Equal(t, "/foo/bim.yaml", string(p)) 111 }) 112 t.Run("Error on path resolving outside repository root", func(t *testing.T) { 113 p, remote, err := ResolveValueFilePathOrUrl("/foo/bar", "/foo", "baz/../../../bim.yaml", allowedRemoteProtocols) 114 require.ErrorContains(t, err, "outside repository root") 115 assert.False(t, remote) 116 assert.Empty(t, string(p)) 117 }) 118 t.Run("Return verbatim URL", func(t *testing.T) { 119 url := "https://some.where/foo,yaml" 120 p, remote, err := ResolveValueFilePathOrUrl("/foo/bar", "/foo", url, allowedRemoteProtocols) 121 require.NoError(t, err) 122 assert.True(t, remote) 123 assert.Equal(t, url, string(p)) 124 }) 125 t.Run("URL scheme not allowed", func(t *testing.T) { 126 url := "file:///some.where/foo,yaml" 127 p, remote, err := ResolveValueFilePathOrUrl("/foo/bar", "/foo", url, allowedRemoteProtocols) 128 require.Error(t, err) 129 assert.False(t, remote) 130 assert.Empty(t, string(p)) 131 }) 132 t.Run("Implicit URL by absolute path", func(t *testing.T) { 133 p, remote, err := ResolveValueFilePathOrUrl("/foo/bar", "/foo", "/baz.yaml", allowedRemoteProtocols) 134 require.NoError(t, err) 135 assert.False(t, remote) 136 assert.Equal(t, "/foo/baz.yaml", string(p)) 137 }) 138 t.Run("Relative app path", func(t *testing.T) { 139 p, remote, err := ResolveValueFilePathOrUrl(".", "/foo", "/baz.yaml", allowedRemoteProtocols) 140 require.NoError(t, err) 141 assert.False(t, remote) 142 assert.Equal(t, "/foo/baz.yaml", string(p)) 143 }) 144 t.Run("Relative repo path", func(t *testing.T) { 145 c, err := os.Getwd() 146 require.NoError(t, err) 147 p, remote, err := ResolveValueFilePathOrUrl(".", ".", "baz.yaml", allowedRemoteProtocols) 148 require.NoError(t, err) 149 assert.False(t, remote) 150 assert.Equal(t, c+"/baz.yaml", string(p)) 151 }) 152 t.Run("Overlapping root prefix without trailing slash", func(t *testing.T) { 153 p, remote, err := ResolveValueFilePathOrUrl(".", "/foo", "../foo2/baz.yaml", allowedRemoteProtocols) 154 require.ErrorContains(t, err, "outside repository root") 155 assert.False(t, remote) 156 assert.Empty(t, string(p)) 157 }) 158 t.Run("Overlapping root prefix with trailing slash", func(t *testing.T) { 159 p, remote, err := ResolveValueFilePathOrUrl(".", "/foo/", "../foo2/baz.yaml", allowedRemoteProtocols) 160 require.ErrorContains(t, err, "outside repository root") 161 assert.False(t, remote) 162 assert.Empty(t, string(p)) 163 }) 164 t.Run("Garbage input as values file", func(t *testing.T) { 165 p, remote, err := ResolveValueFilePathOrUrl(".", "/foo/", "kfdj\\ks&&&321209.,---e32908923%$ยง!\"", allowedRemoteProtocols) 166 require.ErrorContains(t, err, "outside repository root") 167 assert.False(t, remote) 168 assert.Empty(t, string(p)) 169 }) 170 t.Run("NUL-byte path input as values file", func(t *testing.T) { 171 p, remote, err := ResolveValueFilePathOrUrl(".", "/foo/", "\000", allowedRemoteProtocols) 172 require.ErrorContains(t, err, "outside repository root") 173 assert.False(t, remote) 174 assert.Empty(t, string(p)) 175 }) 176 t.Run("Resolve root path into absolute path - jsonnet library path", func(t *testing.T) { 177 p, err := ResolveFileOrDirectoryPath("/foo", "/foo", "./") 178 require.NoError(t, err) 179 assert.Equal(t, "/foo", string(p)) 180 }) 181 }