diff --git a/cmd/grype/cli/commands/root.go b/cmd/grype/cli/commands/root.go index a1417c2fa83..69a6cb45602 100644 --- a/cmd/grype/cli/commands/root.go +++ b/cmd/grype/cli/commands/root.go @@ -259,13 +259,12 @@ func checkForAppUpdate(id clio.Identification, opts *options.Grype) { return } - version := id.Version - isAvailable, newVersion, err := isUpdateAvailable(version) + isAvailable, newVersion, err := isUpdateAvailable(id) if err != nil { log.Errorf(err.Error()) } if isAvailable { - log.Infof("new version of %s is available: %s (currently running: %s)", id.Name, newVersion, version) + log.Infof("new version of %s is available: %s (currently running: %s)", id.Name, newVersion, id.Version) bus.Publish(partybus.Event{ Type: event.CLIAppUpdateAvailable, diff --git a/cmd/grype/cli/commands/update.go b/cmd/grype/cli/commands/update.go index 2916a588faf..cf95279ae8c 100644 --- a/cmd/grype/cli/commands/update.go +++ b/cmd/grype/cli/commands/update.go @@ -6,6 +6,7 @@ import ( "net/http" "strings" + "github.com/anchore/clio" hashiVersion "github.com/anchore/go-version" "github.com/anchore/grype/cmd/grype/internal" ) @@ -25,17 +26,17 @@ func isProductionBuild(version string) bool { return true } -func isUpdateAvailable(version string) (bool, string, error) { - if !isProductionBuild(version) { +func isUpdateAvailable(id clio.Identification) (bool, string, error) { + if !isProductionBuild(id.Version) { // don't allow for non-production builds to check for a version. return false, "", nil } - currentVersion, err := hashiVersion.NewVersion(version) + currentVersion, err := hashiVersion.NewVersion(id.Version) if err != nil { return false, "", fmt.Errorf("failed to parse current application version: %w", err) } - latestVersion, err := fetchLatestApplicationVersion() + latestVersion, err := fetchLatestApplicationVersion(id) if err != nil { return false, "", err } @@ -47,12 +48,14 @@ func isUpdateAvailable(version string) (bool, string, error) { return false, "", nil } -func fetchLatestApplicationVersion() (*hashiVersion.Version, error) { +func fetchLatestApplicationVersion(id clio.Identification) (*hashiVersion.Version, error) { req, err := http.NewRequest(http.MethodGet, latestAppVersionURL.host+latestAppVersionURL.path, nil) if err != nil { return nil, fmt.Errorf("failed to create request for latest version: %w", err) } + req.Header.Add("User-Agent", fmt.Sprintf("%v %v", id.Name, id.Version)) + client := http.Client{} resp, err := client.Do(req) if err != nil { diff --git a/cmd/grype/cli/commands/update_test.go b/cmd/grype/cli/commands/update_test.go index eb2dedb9fcc..e5b85e47ece 100644 --- a/cmd/grype/cli/commands/update_test.go +++ b/cmd/grype/cli/commands/update_test.go @@ -5,6 +5,7 @@ import ( "net/http/httptest" "testing" + "github.com/anchore/clio" hashiVersion "github.com/anchore/go-version" "github.com/anchore/grype/cmd/grype/internal" ) @@ -108,7 +109,7 @@ func TestIsUpdateAvailable(t *testing.T) { latestAppVersionURL.host = mockSrv.URL defer mockSrv.Close() - isAvailable, newVersion, err := isUpdateAvailable(version) + isAvailable, newVersion, err := isUpdateAvailable(clio.Identification{Version: version}) if err != nil && !test.err { t.Fatalf("got error but expected none: %+v", err) } else if err == nil && test.err { @@ -190,7 +191,7 @@ func TestFetchLatestApplicationVersion(t *testing.T) { latestAppVersionURL.host = mockSrv.URL defer mockSrv.Close() - actual, err := fetchLatestApplicationVersion() + actual, err := fetchLatestApplicationVersion(clio.Identification{}) if err != nil && !test.err { t.Fatalf("got error but expected none: %+v", err) } else if err == nil && test.err { @@ -208,3 +209,27 @@ func TestFetchLatestApplicationVersion(t *testing.T) { } } + +func Test_UserAgent(t *testing.T) { + got := "" + + // setup mock + handler := http.NewServeMux() + handler.HandleFunc(latestAppVersionURL.path, func(w http.ResponseWriter, r *http.Request) { + got = r.Header.Get("User-Agent") + w.WriteHeader(http.StatusOK) + _, _ = w.Write([]byte("1.0.0")) + }) + mockSrv := httptest.NewServer(handler) + latestAppVersionURL.host = mockSrv.URL + defer mockSrv.Close() + + fetchLatestApplicationVersion(clio.Identification{ + Name: "the-app", + Version: "v3.2.1", + }) + + if got != "the-app v3.2.1" { + t.Errorf("expected User-Agent header to match, got: %v", got) + } +}