Skip to content

Commit 4c65be7

Browse files
authored
Return the file error instead of the URL error for a missing artifact path (#2872)
validateFileOrURL fell through to URL validation when the file path failed, so a nonexistent --artifact/--entry file returned only "'<v>' is not a valid url" and masked the real error (e.g. "no such file or directory"). Return the file validation error when the value is not an http(s) URL so the message is actionable, and add TestValidateFileOrURL. Addresses #2138 Signed-off-by: Nikhil Jathar <22786232+mailnike@users.noreply.github.com>
1 parent 2c9a403 commit 4c65be7

2 files changed

Lines changed: 47 additions & 4 deletions

File tree

cmd/rekor-cli/app/pflags.go

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -280,12 +280,23 @@ func validateSHAValue(v string) error {
280280

281281
// validateFileOrURL ensures the provided string is either a valid file path that can be opened or a valid URL
282282
func validateFileOrURL(v string) error {
283-
valGen := pflagValueFuncMap[fileFlag]
284-
if valGen().Set(v) == nil {
283+
fileErr := pflagValueFuncMap[fileFlag]().Set(v)
284+
if fileErr == nil {
285285
return nil
286286
}
287-
valGen = pflagValueFuncMap[urlFlag]
288-
return valGen().Set(v)
287+
urlErr := pflagValueFuncMap[urlFlag]().Set(v)
288+
if urlErr == nil {
289+
return nil
290+
}
291+
// Neither a readable file nor a valid URL. Return the error for whichever
292+
// the input was most likely intended to be, so the message is actionable:
293+
// a value with an http(s) scheme is treated as a URL, anything else as a
294+
// file path. Previously the file error (e.g. "no such file or directory")
295+
// was always masked by the "is not a valid url" error.
296+
if strings.HasPrefix(v, "http://") || strings.HasPrefix(v, "https://") {
297+
return urlErr
298+
}
299+
return fileErr
289300
}
290301

291302
// validateID ensures the ID is either an EntryID (TreeID + UUID) or a UUID

cmd/rekor-cli/app/pflags_test.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"net/http"
2222
"net/http/httptest"
2323
"os"
24+
"strings"
2425
"testing"
2526

2627
"github.com/spf13/cobra"
@@ -926,3 +927,34 @@ func TestParseTypeFlag(t *testing.T) {
926927
}
927928
}
928929
}
930+
931+
func TestValidateFileOrURL(t *testing.T) {
932+
tests := []struct {
933+
caseDesc string
934+
value string
935+
expectErr bool
936+
errSubstr string
937+
}{
938+
{caseDesc: "valid local file", value: "tests/test_file.txt", expectErr: false},
939+
{caseDesc: "valid https url", value: "https://example.com/artifact", expectErr: false},
940+
{caseDesc: "missing file reports the file error, not the url error", value: "tests/not_a_file", expectErr: true, errSubstr: "not_a_file"},
941+
{caseDesc: "malformed http url reports the url error", value: "http://", expectErr: true, errSubstr: "is not a valid url"},
942+
}
943+
for _, tc := range tests {
944+
err := validateFileOrURL(tc.value)
945+
if tc.expectErr {
946+
if err == nil {
947+
t.Errorf("%s: expected an error, got nil", tc.caseDesc)
948+
continue
949+
}
950+
if tc.errSubstr != "" && !strings.Contains(err.Error(), tc.errSubstr) {
951+
t.Errorf("%s: expected error containing %q, got %q", tc.caseDesc, tc.errSubstr, err.Error())
952+
}
953+
if !strings.HasPrefix(tc.value, "http") && strings.Contains(err.Error(), "is not a valid url") {
954+
t.Errorf("%s: file error was masked by the url error: %q", tc.caseDesc, err.Error())
955+
}
956+
} else if err != nil {
957+
t.Errorf("%s: expected no error, got %q", tc.caseDesc, err.Error())
958+
}
959+
}
960+
}

0 commit comments

Comments
 (0)