From 73e2ead04ba812b13d5610c66f2539873dbcd48c Mon Sep 17 00:00:00 2001 From: beejeebus Date: Tue, 1 Jul 2025 12:02:54 -0400 Subject: [PATCH] Add checksums to SHA256 mismatch error message (#107461) This should make it easier to debug this issue if we see it again. --- pkg/plugins/repo/client.go | 11 ++++++----- pkg/plugins/repo/errors.go | 6 +++--- pkg/plugins/repo/errors_test.go | 6 ++++-- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/pkg/plugins/repo/client.go b/pkg/plugins/repo/client.go index 1c4c6496ece..698b61e186d 100644 --- a/pkg/plugins/repo/client.go +++ b/pkg/plugins/repo/client.go @@ -100,7 +100,7 @@ func (c *Client) SendReq(ctx context.Context, url *url.URL, compatOpts CompatOpt return io.ReadAll(bodyReader) } -func (c *Client) downloadFile(ctx context.Context, tmpFile *os.File, pluginURL, checksum string, compatOpts CompatOpts) (err error) { +func (c *Client) downloadFile(ctx context.Context, tmpFile *os.File, pluginURL, expectedChecksum string, compatOpts CompatOpts) (err error) { // Try handling URL as a local file path first if _, err := os.Stat(pluginURL); err == nil { // TODO re-verify @@ -136,7 +136,7 @@ func (c *Client) downloadFile(ctx context.Context, tmpFile *os.File, pluginURL, if err != nil { return } - err = c.downloadFile(ctx, tmpFile, pluginURL, checksum, compatOpts) + err = c.downloadFile(ctx, tmpFile, pluginURL, expectedChecksum, compatOpts) } else { c.retryCount = 0 failure := fmt.Sprintf("%v", r) @@ -169,7 +169,7 @@ func (c *Client) downloadFile(ctx context.Context, tmpFile *os.File, pluginURL, if c.retryCount < 3 { c.retryCount++ c.log.Debug("Failed downloading. Will retry.") - err = c.downloadFile(ctx, tmpFile, pluginURL, checksum, compatOpts) + err = c.downloadFile(ctx, tmpFile, pluginURL, expectedChecksum, compatOpts) } return err } @@ -187,8 +187,9 @@ func (c *Client) downloadFile(ctx context.Context, tmpFile *os.File, pluginURL, if err = w.Flush(); err != nil { return fmt.Errorf("failed to write to %q: %w", tmpFile.Name(), err) } - if len(checksum) > 0 && checksum != fmt.Sprintf("%x", h.Sum(nil)) { - return ErrChecksumMismatch(pluginURL) + computedChecksum := fmt.Sprintf("%x", h.Sum(nil)) + if len(expectedChecksum) > 0 && expectedChecksum != computedChecksum { + return ErrChecksumMismatch(pluginURL, expectedChecksum, computedChecksum) } c.retryCount = 0 diff --git a/pkg/plugins/repo/errors.go b/pkg/plugins/repo/errors.go index c275ce43afc..f25474345b1 100644 --- a/pkg/plugins/repo/errors.go +++ b/pkg/plugins/repo/errors.go @@ -60,7 +60,7 @@ var ( ErrArcNotFoundBase = errutil.NotFound("plugin.archNotFound"). MustTemplate(ErrArcNotFoundMsg, errutil.WithPublic(ErrArcNotFoundMsg)) - ErrChecksumMismatchMsg = "expected SHA256 checksum does not match the downloaded archive ({{.Public.ArchiveURL}}) - please contact security@grafana.com" + ErrChecksumMismatchMsg = "expected SHA256 checksum ({{.Public.ExpectedSHA256}}) does not match the downloaded archive ({{.Public.ArchiveURL}}) computed SHA256 checksum ({{.Public.ComputedSHA256}}) - please contact security@grafana.com" ErrChecksumMismatchBase = errutil.UnprocessableEntity("plugin.checksumMismatch"). MustTemplate(ErrChecksumMismatchMsg, errutil.WithPublic(ErrChecksumMismatchMsg)) @@ -85,8 +85,8 @@ func ErrArcNotFound(pluginID, systemInfo string) error { return ErrArcNotFoundBase.Build(errutil.TemplateData{Public: map[string]any{"PluginID": pluginID, "SysInfo": systemInfo}}) } -func ErrChecksumMismatch(archiveURL string) error { - return ErrChecksumMismatchBase.Build(errutil.TemplateData{Public: map[string]any{"ArchiveURL": archiveURL}}) +func ErrChecksumMismatch(archiveURL, expectedSHA256, computedSHA256 string) error { + return ErrChecksumMismatchBase.Build(errutil.TemplateData{Public: map[string]any{"ArchiveURL": archiveURL, "ExpectedSHA256": expectedSHA256, "ComputedSHA256": computedSHA256}}) } func ErrCorePlugin(pluginID string) error { diff --git a/pkg/plugins/repo/errors_test.go b/pkg/plugins/repo/errors_test.go index 7e10ed587b8..59f4b7446df 100644 --- a/pkg/plugins/repo/errors_test.go +++ b/pkg/plugins/repo/errors_test.go @@ -49,11 +49,13 @@ func TestErrorTemplates(t *testing.T) { require.Equal(t, "plugin.archNotFound", base.Public().MessageID) require.Equal(t, "grafana-test-app is not compatible with your system architecture: darwin-amd64", base.Public().Message) - err = ErrChecksumMismatch("http://localhost:6481/grafana-test-app/versions/1.0.0/download") + expectedChecksum := "abcdef1234567890" + computedChecksum := "abcdef0987654321" + err = ErrChecksumMismatch("http://localhost:6481/grafana-test-app/versions/1.0.0/download", expectedChecksum, computedChecksum) require.True(t, errors.As(err, base)) require.Equal(t, http.StatusUnprocessableEntity, base.Public().StatusCode) require.Equal(t, "plugin.checksumMismatch", base.Public().MessageID) - require.Equal(t, "expected SHA256 checksum does not match the downloaded archive (http://localhost:6481/grafana-test-app/versions/1.0.0/download) - please contact security@grafana.com", base.Public().Message) + require.Equal(t, "expected SHA256 checksum (abcdef1234567890) does not match the downloaded archive (http://localhost:6481/grafana-test-app/versions/1.0.0/download) computed SHA256 checksum (abcdef0987654321) - please contact security@grafana.com", base.Public().Message) err = ErrCorePlugin("grafana-test-app") require.True(t, errors.As(err, base))