diff --git a/go.mod b/go.mod index bbbee0fabf9..99f3d09f9fb 100644 --- a/go.mod +++ b/go.mod @@ -71,7 +71,7 @@ require ( github.com/googleapis/gax-go/v2 v2.14.1 // @grafana/grafana-backend-group github.com/gorilla/mux v1.8.1 // @grafana/grafana-backend-group github.com/gorilla/websocket v1.5.3 // @grafana/grafana-app-platform-squad - github.com/grafana/alerting v0.0.0-20250219142948-d43046431703 // @grafana/alerting-backend + github.com/grafana/alerting v0.0.0-20250219153626-c475b1a572b0 // @grafana/alerting-backend github.com/grafana/authlib v0.0.0-20250219100139-6a3b1bbb50e7 // @grafana/identity-access-team github.com/grafana/authlib/types v0.0.0-20250219092154-21ce22b49f31 // @grafana/identity-access-team github.com/grafana/dataplane/examples v0.0.1 // @grafana/observability-metrics diff --git a/go.sum b/go.sum index 5bd68002377..839d2e19349 100644 --- a/go.sum +++ b/go.sum @@ -1511,8 +1511,8 @@ github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7Fsg github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/grafana/alerting v0.0.0-20250219142948-d43046431703 h1:Z53rmFhUeif1/cFjOQqxHyv+YfXac4vzyl9yzdjxOoY= -github.com/grafana/alerting v0.0.0-20250219142948-d43046431703/go.mod h1:hdGB3dSl8Ma9Rjo2YiAEAjMkZ5HiNJbNDqRKDefRZrM= +github.com/grafana/alerting v0.0.0-20250219153626-c475b1a572b0 h1:LGH+tVzHCDrR9hsltmkP4jmNRg5IreQw5CNFbJKlnts= +github.com/grafana/alerting v0.0.0-20250219153626-c475b1a572b0/go.mod h1:hdGB3dSl8Ma9Rjo2YiAEAjMkZ5HiNJbNDqRKDefRZrM= github.com/grafana/authlib v0.0.0-20250219100139-6a3b1bbb50e7 h1:NTMmow+74I3Jb033xhbRgWQS7A//5TDhiM4tl7bsVP4= github.com/grafana/authlib v0.0.0-20250219100139-6a3b1bbb50e7/go.mod h1:T3X4z0ejGfJOiOmZLFeKCRT/yxWJq/RtclAc/PHj/w4= github.com/grafana/authlib/types v0.0.0-20250219092154-21ce22b49f31 h1:EokLC5grHwLPs4tXW8T6E8187H1e5G9AP0QQ5B60HbA= diff --git a/pkg/services/ngalert/models/image.go b/pkg/services/ngalert/models/image.go index 07c8578cdd9..1a90090aa53 100644 --- a/pkg/services/ngalert/models/image.go +++ b/pkg/services/ngalert/models/image.go @@ -6,8 +6,11 @@ import ( ) var ( - // ErrImageNotFound is returned when the image does not exist. + // ErrImageNotFound is returned when the image does not exist or is expired. ErrImageNotFound = errors.New("image not found") + + // ErrImageDataUnavailable is returned when image data is unavailable. Usually because the image is missing a path. + ErrImageDataUnavailable = errors.New("image data is unavailable") ) type Image struct { diff --git a/pkg/services/ngalert/notifier/images.go b/pkg/services/ngalert/notifier/images.go index d8effb176ce..d25b20bce80 100644 --- a/pkg/services/ngalert/notifier/images.go +++ b/pkg/services/ngalert/notifier/images.go @@ -6,145 +6,61 @@ import ( "io" "os" "path/filepath" - "strings" alertingImages "github.com/grafana/alerting/images" - alertingModels "github.com/grafana/alerting/models" - alertingNotify "github.com/grafana/alerting/notify" "github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/services/ngalert/models" "github.com/grafana/grafana/pkg/services/ngalert/store" ) -type imageProvider struct { +type tokenStore struct { store store.ImageStore logger log.Logger } +var _ alertingImages.TokenStore = (*tokenStore)(nil) + func newImageProvider(store store.ImageStore, logger log.Logger) alertingImages.Provider { - return &imageProvider{ + return alertingImages.NewTokenProvider(&tokenStore{ store: store, logger: logger, - } + }, newLogWrapper(logger)) } -func (i imageProvider) GetImage(ctx context.Context, uri string) (*alertingImages.Image, error) { - image, err := i.getImageFromURI(ctx, uri) +func (t tokenStore) GetImage(ctx context.Context, token string) (*alertingImages.Image, error) { + image, err := t.store.GetImage(ctx, token) if err != nil { if errors.Is(err, models.ErrImageNotFound) { - i.logger.Info("Image not found in database", "uri", uri) return nil, alertingImages.ErrImageNotFound } return nil, err } return &alertingImages.Image{ - Token: image.Token, - Path: image.Path, - URL: image.URL, - CreatedAt: image.CreatedAt, + URL: image.URL, + RawData: func(_ context.Context) (alertingImages.ImageContent, error) { + if image.Path == "" { + return alertingImages.ImageContent{}, models.ErrImageDataUnavailable + } + b, err := readImage(image.Path, t.logger) + if err != nil { + return alertingImages.ImageContent{}, err + } + return alertingImages.ImageContent{ + Name: filepath.Base(image.Path), + Content: b, + }, nil + }, }, nil } -func (i imageProvider) GetImageURL(ctx context.Context, alert *alertingNotify.Alert) (string, error) { - uri, err := getImageURI(alert) - if err != nil { - return "", err - } - - // If the identifier is a URL, validate that it corresponds to a stored, non-expired image. - if strings.HasPrefix(uri, "http") { - i.logger.Debug("Received an image URL in annotations", "alert", alert) - exists, err := i.store.URLExists(ctx, uri) - if err != nil { - return "", err - } - if !exists { - i.logger.Info("Image URL not found in database", "alert", alert) - return "", alertingImages.ErrImageNotFound - } - return uri, nil - } - - // If the identifier is a token, remove the prefix, get the image and return the URL. - token := strings.TrimPrefix(uri, "token://") - i.logger.Debug("Received an image token in annotations", "alert", alert, "token", token) - return i.getImageURLFromToken(ctx, token) -} - -// getImageURLFromToken takes a token and returns the URL of the image that token belongs to. -func (i imageProvider) getImageURLFromToken(ctx context.Context, token string) (string, error) { - image, err := i.store.GetImage(ctx, token) - if err != nil { - if errors.Is(err, models.ErrImageNotFound) { - i.logger.Info("Image not found in database", "token", token) - return "", alertingImages.ErrImageNotFound - } - return "", err - } - - if !image.HasURL() { - return "", alertingImages.ErrImagesNoURL - } - return image.URL, nil -} - -func (i imageProvider) GetRawImage(ctx context.Context, alert *alertingNotify.Alert) (io.ReadCloser, string, error) { - uri, err := getImageURI(alert) - if err != nil { - return nil, "", err - } - - image, err := i.getImageFromURI(ctx, uri) - if err != nil { - if errors.Is(err, models.ErrImageNotFound) { - i.logger.Info("Image not found in database", "alert", alert) - return nil, "", alertingImages.ErrImageNotFound - } - return nil, "", err - } - if !image.HasPath() { - return nil, "", alertingImages.ErrImagesNoPath - } - - // Return image bytes and filename. - readCloser, err := openImage(image.Path) - if err != nil { - i.logger.Error("Error looking for image on disk", "alert", alert, "path", image.Path, "error", err) - return nil, "", err - } - filename := filepath.Base(image.Path) - return readCloser, filename, nil -} - -func (i imageProvider) getImageFromURI(ctx context.Context, uri string) (*models.Image, error) { - // Check whether the uri is a URL or a token to know how to query the DB. - if strings.HasPrefix(uri, "http") { - i.logger.Debug("Received an image URL in annotations") - return i.store.GetImageByURL(ctx, uri) - } - - token := strings.TrimPrefix(uri, "token://") - i.logger.Debug("Received an image token in annotations", "token", token) - return i.store.GetImage(ctx, token) -} - -// getImageURI is a helper function to retrieve the image URI from the alert annotations as a string. -func getImageURI(alert *alertingNotify.Alert) (string, error) { - uri, ok := alert.Annotations[alertingModels.ImageTokenAnnotation] - if !ok { - return "", alertingImages.ErrNoImageForAlert - } - return string(uri), nil -} - -// openImage returns an the io representation of an image from the given path. -func openImage(path string) (io.ReadCloser, error) { +// readImage returns an image from the given path. +func readImage(path string, logger log.Logger) ([]byte, error) { fp := filepath.Clean(path) _, err := os.Stat(fp) if os.IsNotExist(err) || os.IsPermission(err) { - return nil, alertingImages.ErrImageNotFound + return nil, models.ErrImageNotFound } f, err := os.Open(fp) @@ -152,5 +68,11 @@ func openImage(path string) (io.ReadCloser, error) { return nil, err } - return f, nil + defer func() { + if err := f.Close(); err != nil { + logger.Error("Failed to close image file", "error", err) + } + }() + + return io.ReadAll(f) } diff --git a/pkg/services/ngalert/notifier/images_test.go b/pkg/services/ngalert/notifier/images_test.go index b16bd0e6360..85ed780cb3b 100644 --- a/pkg/services/ngalert/notifier/images_test.go +++ b/pkg/services/ngalert/notifier/images_test.go @@ -2,7 +2,6 @@ package notifier import ( "context" - "io" "os" "path/filepath" "testing" @@ -11,177 +10,98 @@ import ( alertingImages "github.com/grafana/alerting/images" alertingModels "github.com/grafana/alerting/models" alertingNotify "github.com/grafana/alerting/notify" + "github.com/prometheus/common/model" + "github.com/stretchr/testify/require" + "github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/services/ngalert/models" "github.com/grafana/grafana/pkg/services/ngalert/store" - "github.com/prometheus/common/model" - "github.com/stretchr/testify/require" ) func TestGetImage(t *testing.T) { - fakeImageStore := store.NewFakeImageStore(t) - store := newImageProvider(fakeImageStore, log.NewNopLogger()) + testBytes := []byte("some test bytes") + testPath := generateTestFile(t, testBytes) - t.Run("queries by token when it gets a token", func(tt *testing.T) { - img := models.Image{ - Token: "test", - URL: "http://localhost:1234", - Path: "test.png", - } - err := fakeImageStore.SaveImage(context.Background(), &img) - require.NoError(tt, err) - - // nolint:staticcheck - savedImg, err := store.GetImage(context.Background(), "token://"+img.Token) - require.NoError(tt, err) - require.Equal(tt, savedImg.Token, img.Token) - require.Equal(tt, savedImg.URL, img.URL) - require.Equal(tt, savedImg.Path, img.Path) - }) - - t.Run("queries by URL when it gets a URL", func(tt *testing.T) { - img := models.Image{ - Token: "test", - Path: "test.png", - URL: "https://test.com/test.png", - } - err := fakeImageStore.SaveImage(context.Background(), &img) - require.NoError(tt, err) - - // nolint:staticcheck - savedImg, err := store.GetImage(context.Background(), img.URL) - require.NoError(tt, err) - require.Equal(tt, savedImg.Token, img.Token) - require.Equal(tt, savedImg.URL, img.URL) - require.Equal(tt, savedImg.Path, img.Path) - }) -} - -func TestGetImageURL(t *testing.T) { var ( - imageWithoutURL = models.Image{ - Token: "test-no-url", - CreatedAt: time.Now().UTC(), - ExpiresAt: time.Now().UTC().Add(24 * time.Hour), - } - testImage = models.Image{ - Token: "test", + imageWithoutPath = models.Image{ + Token: "test-token-no-path", URL: "https://test.com", CreatedAt: time.Now().UTC(), ExpiresAt: time.Now().UTC().Add(24 * time.Hour), } - ) - - fakeImageStore := store.NewFakeImageStore(t, &imageWithoutURL, &testImage) - store := newImageProvider(fakeImageStore, log.NewNopLogger()) - - tests := []struct { - name string - uri string - expURL string - expErr error - }{ - { - "URL does not exist", - "https://invalid.com/test", - "", - alertingImages.ErrImageNotFound, - }, { - "existing URL", - testImage.URL, - testImage.URL, - nil, - }, { - "token does not exist", - "token://invalid", - "", - alertingImages.ErrImageNotFound, - }, { - "existing token", - "token://" + testImage.Token, - testImage.URL, - nil, - }, { - "image has no URL", - "token://" + imageWithoutURL.Token, - "", - alertingImages.ErrImagesNoURL, - }, - } - - for _, test := range tests { - t.Run(test.name, func(tt *testing.T) { - alert := alertingNotify.Alert{ - Alert: model.Alert{ - Annotations: model.LabelSet{alertingModels.ImageTokenAnnotation: model.LabelValue(test.uri)}, - }, - } - url, err := store.GetImageURL(context.Background(), &alert) - require.ErrorIs(tt, err, test.expErr) - require.Equal(tt, test.expURL, url) - }) - } -} - -func TestGetRawImage(t *testing.T) { - var ( - testBytes = []byte("some test bytes") - testPath = generateTestFile(t, testBytes) - imageWithoutPath = models.Image{ - Token: "test-no-path", - URL: "https://test-no-path.com", - CreatedAt: time.Now().UTC(), - ExpiresAt: time.Now().UTC().Add(24 * time.Hour), - } testImage = models.Image{ - Token: "test", + Token: "test-token", URL: "https://test.com", Path: testPath, CreatedAt: time.Now().UTC(), ExpiresAt: time.Now().UTC().Add(24 * time.Hour), } + testImageMissingFile = models.Image{ + Token: "test-token-missing-file", + URL: "https://test.com", + Path: "/tmp/missing/1234asdf.png", + CreatedAt: time.Now().UTC(), + ExpiresAt: time.Now().UTC().Add(24 * time.Hour), + } ) - fakeImageStore := store.NewFakeImageStore(t, &imageWithoutPath, &testImage) + fakeImageStore := store.NewFakeImageStore(t, &imageWithoutPath, &testImage, &testImageMissingFile) store := newImageProvider(fakeImageStore, log.NewNopLogger()) tests := []struct { - name string - uri string - expFilename string - expBytes []byte - expErr error + name string + token string + url string + expImage *alertingImages.Image + expImageContent *alertingImages.ImageContent + expRawDataErr error }{ { - "URL does not exist", - "https://invalid.com/test", - "", - nil, - alertingImages.ErrImageNotFound, + name: "Given existing raw token, expect image", + token: testImage.Token, + expImage: &alertingImages.Image{ + URL: testImage.URL, + }, }, { - "existing URL", - testImage.URL, - filepath.Base(testPath), - testBytes, - nil, + name: "Given existing token and url, expect image", + token: testImage.Token, + url: testImage.URL, + expImage: &alertingImages.Image{ + URL: testImage.URL, + }, }, { - "token does not exist", - "token://invalid", - "", - nil, - alertingImages.ErrImageNotFound, + name: "Given existing with just url, expect nil", + token: "", + url: testImage.URL, + expImage: nil, }, { - "existing token", - "token://" + testImage.Token, - filepath.Base(testPath), - testBytes, - nil, + name: "Given missing raw token, expect nil", + token: "invalid", + expImage: nil, }, { - "image has no path", - "token://" + imageWithoutPath.Token, - "", - nil, - alertingImages.ErrImagesNoPath, + name: "Given image with Path, expect RawData", + token: testImage.Token, + expImage: &alertingImages.Image{ + URL: testImage.URL, + }, + expImageContent: &alertingImages.ImageContent{ + Name: filepath.Base(testImage.Path), + Content: testBytes, + }, + }, { + name: "Given image with Path but file doesn't exist, expect RawData error", + token: testImageMissingFile.Token, + expImage: &alertingImages.Image{ + URL: testImageMissingFile.URL, + }, + expRawDataErr: models.ErrImageNotFound, + }, { + name: "Given image without Path, expect RawData error", + token: imageWithoutPath.Token, + expImage: &alertingImages.Image{ + URL: imageWithoutPath.URL, + }, + expRawDataErr: models.ErrImageDataUnavailable, }, } @@ -189,18 +109,24 @@ func TestGetRawImage(t *testing.T) { t.Run(test.name, func(tt *testing.T) { alert := alertingNotify.Alert{ Alert: model.Alert{ - Annotations: model.LabelSet{alertingModels.ImageTokenAnnotation: model.LabelValue(test.uri)}, + Annotations: model.LabelSet{alertingModels.ImageTokenAnnotation: model.LabelValue(test.token)}, }, } - readCloser, filename, err := store.GetRawImage(context.Background(), &alert) - require.ErrorIs(tt, err, test.expErr) - require.Equal(tt, test.expFilename, filename) - - if test.expBytes != nil { - b, err := io.ReadAll(readCloser) + image, err := store.GetImage(context.Background(), alert) + require.NoError(tt, err) + if test.expImage == nil { + require.Nil(tt, image) + return + } + require.Equal(tt, test.expImage.URL, image.URL) + if test.expImageContent != nil { + ic, err := image.RawData(context.Background()) require.NoError(tt, err) - require.Equal(tt, test.expBytes, b) - require.NoError(t, readCloser.Close()) + require.Equal(tt, *test.expImageContent, ic) + } + if test.expRawDataErr != nil { + _, err := image.RawData(context.Background()) + require.ErrorIs(tt, err, test.expRawDataErr) } }) } diff --git a/pkg/services/ngalert/notifier/log.go b/pkg/services/ngalert/notifier/log.go index c9dc97ea413..4aef94c49ed 100644 --- a/pkg/services/ngalert/notifier/log.go +++ b/pkg/services/ngalert/notifier/log.go @@ -10,6 +10,10 @@ var LoggerFactory alertingLogging.LoggerFactory = func(logger string, ctx ...any return &logWrapper{log.New(append([]any{logger}, ctx...)...)} } +func newLogWrapper(logger log.Logger, ctx ...any) alertingLogging.Logger { + return &logWrapper{logger.New(ctx...)} +} + type logWrapper struct { *log.ConcreteLogger } diff --git a/pkg/services/ngalert/state/compat.go b/pkg/services/ngalert/state/compat.go index 55e1fdf76fe..7f4b5c41428 100644 --- a/pkg/services/ngalert/state/compat.go +++ b/pkg/services/ngalert/state/compat.go @@ -17,6 +17,7 @@ import ( apimodels "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions" "github.com/grafana/grafana/pkg/services/ngalert/eval" + ngModels "github.com/grafana/grafana/pkg/services/ngalert/models" ) const ( @@ -48,8 +49,8 @@ func StateToPostableAlert(transition StateTransition, appURL *url.URL) *models.P nA[alertingModels.ValueStringAnnotation] = alertState.LastEvaluationString } - if alertState.Image != nil && alertState.Image.Token != "" { - nA[alertingModels.ImageTokenAnnotation] = alertState.Image.Token + if alertState.Image != nil { + attachImageAnnotations(alertState.Image, nA) } if alertState.StateReason != "" { @@ -153,3 +154,13 @@ func FromAlertsStateToStoppedAlert(firingStates []StateTransition, appURL *url.U } return alerts } + +// attachImageAnnotations attaches image annotations to the alert. +func attachImageAnnotations(image *ngModels.Image, a data.Labels) { + if image.Token != "" { + a[alertingModels.ImageTokenAnnotation] = image.Token + } + if image.URL != "" { + a[alertingModels.ImageURLAnnotation] = image.URL + } +} diff --git a/pkg/services/ngalert/state/compat_test.go b/pkg/services/ngalert/state/compat_test.go index bd0189badb8..84d5ad8e6fa 100644 --- a/pkg/services/ngalert/state/compat_test.go +++ b/pkg/services/ngalert/state/compat_test.go @@ -120,10 +120,10 @@ func Test_StateToPostableAlert(t *testing.T) { require.Equal(t, expected, result.Annotations) }) - t.Run("add __alertImageToken__ if there is an image token", func(t *testing.T) { + t.Run("add both annotations if there is an image token and url", func(t *testing.T) { alertState := randomTransition(eval.Normal, tc.state) alertState.Annotations = randomMapOfStrings() - alertState.Image = &ngModels.Image{Token: "test_token"} + alertState.Image = &ngModels.Image{Token: "test_token", URL: "test_url"} result := StateToPostableAlert(alertState, appURL) @@ -131,12 +131,17 @@ func Test_StateToPostableAlert(t *testing.T) { for k, v := range alertState.Annotations { expected[k] = v } - expected["__alertImageToken__"] = alertState.Image.Token + expected[alertingModels.ImageTokenAnnotation] = alertState.Image.Token + expected[alertingModels.ImageURLAnnotation] = alertState.Image.URL + + // Sanity check that the annotation is correct. + require.Contains(t, result.Annotations[alertingModels.ImageTokenAnnotation], alertState.Image.Token) + require.Contains(t, result.Annotations[alertingModels.ImageURLAnnotation], alertState.Image.URL) require.Equal(t, expected, result.Annotations) }) - t.Run("don't add __alertImageToken__ if there's no image token", func(t *testing.T) { + t.Run("don't add annotations if there's no image token or url", func(t *testing.T) { alertState := randomTransition(eval.Normal, tc.state) alertState.Annotations = randomMapOfStrings() alertState.Image = &ngModels.Image{} diff --git a/pkg/storage/unified/apistore/go.mod b/pkg/storage/unified/apistore/go.mod index e758daa2d06..16b8b6442de 100644 --- a/pkg/storage/unified/apistore/go.mod +++ b/pkg/storage/unified/apistore/go.mod @@ -192,7 +192,7 @@ require ( github.com/googleapis/gax-go/v2 v2.14.1 // indirect github.com/gorilla/mux v1.8.1 // indirect github.com/gorilla/websocket v1.5.3 // indirect - github.com/grafana/alerting v0.0.0-20250219142948-d43046431703 // indirect + github.com/grafana/alerting v0.0.0-20250219153626-c475b1a572b0 // indirect github.com/grafana/authlib v0.0.0-20250219100139-6a3b1bbb50e7 // indirect github.com/grafana/dataplane/sdata v0.0.9 // indirect github.com/grafana/dskit v0.0.0-20241105154643-a6b453a88040 // indirect diff --git a/pkg/storage/unified/apistore/go.sum b/pkg/storage/unified/apistore/go.sum index fa94a7e92ec..faf5e7a9e0f 100644 --- a/pkg/storage/unified/apistore/go.sum +++ b/pkg/storage/unified/apistore/go.sum @@ -566,8 +566,8 @@ github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/grafana/alerting v0.0.0-20250219142948-d43046431703 h1:Z53rmFhUeif1/cFjOQqxHyv+YfXac4vzyl9yzdjxOoY= -github.com/grafana/alerting v0.0.0-20250219142948-d43046431703/go.mod h1:hdGB3dSl8Ma9Rjo2YiAEAjMkZ5HiNJbNDqRKDefRZrM= +github.com/grafana/alerting v0.0.0-20250219153626-c475b1a572b0 h1:LGH+tVzHCDrR9hsltmkP4jmNRg5IreQw5CNFbJKlnts= +github.com/grafana/alerting v0.0.0-20250219153626-c475b1a572b0/go.mod h1:hdGB3dSl8Ma9Rjo2YiAEAjMkZ5HiNJbNDqRKDefRZrM= github.com/grafana/authlib v0.0.0-20250219100139-6a3b1bbb50e7 h1:NTMmow+74I3Jb033xhbRgWQS7A//5TDhiM4tl7bsVP4= github.com/grafana/authlib v0.0.0-20250219100139-6a3b1bbb50e7/go.mod h1:T3X4z0ejGfJOiOmZLFeKCRT/yxWJq/RtclAc/PHj/w4= github.com/grafana/authlib/types v0.0.0-20250219092154-21ce22b49f31 h1:EokLC5grHwLPs4tXW8T6E8187H1e5G9AP0QQ5B60HbA= diff --git a/pkg/storage/unified/resource/go.mod b/pkg/storage/unified/resource/go.mod index 28745ab869d..a7d81ec25ca 100644 --- a/pkg/storage/unified/resource/go.mod +++ b/pkg/storage/unified/resource/go.mod @@ -117,7 +117,7 @@ require ( github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect github.com/googleapis/gax-go/v2 v2.14.1 // indirect github.com/gorilla/mux v1.8.1 // indirect - github.com/grafana/alerting v0.0.0-20250219142948-d43046431703 // indirect + github.com/grafana/alerting v0.0.0-20250219153626-c475b1a572b0 // indirect github.com/grafana/dataplane/sdata v0.0.9 // indirect github.com/grafana/grafana-app-sdk/logging v0.30.0 // indirect github.com/grafana/grafana-aws-sdk v0.31.5 // indirect diff --git a/pkg/storage/unified/resource/go.sum b/pkg/storage/unified/resource/go.sum index 09e3a20b8a6..9ee7f749839 100644 --- a/pkg/storage/unified/resource/go.sum +++ b/pkg/storage/unified/resource/go.sum @@ -397,8 +397,8 @@ github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2z github.com/gorilla/mux v1.7.1/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= -github.com/grafana/alerting v0.0.0-20250219142948-d43046431703 h1:Z53rmFhUeif1/cFjOQqxHyv+YfXac4vzyl9yzdjxOoY= -github.com/grafana/alerting v0.0.0-20250219142948-d43046431703/go.mod h1:hdGB3dSl8Ma9Rjo2YiAEAjMkZ5HiNJbNDqRKDefRZrM= +github.com/grafana/alerting v0.0.0-20250219153626-c475b1a572b0 h1:LGH+tVzHCDrR9hsltmkP4jmNRg5IreQw5CNFbJKlnts= +github.com/grafana/alerting v0.0.0-20250219153626-c475b1a572b0/go.mod h1:hdGB3dSl8Ma9Rjo2YiAEAjMkZ5HiNJbNDqRKDefRZrM= github.com/grafana/authlib v0.0.0-20250219100139-6a3b1bbb50e7 h1:NTMmow+74I3Jb033xhbRgWQS7A//5TDhiM4tl7bsVP4= github.com/grafana/authlib v0.0.0-20250219100139-6a3b1bbb50e7/go.mod h1:T3X4z0ejGfJOiOmZLFeKCRT/yxWJq/RtclAc/PHj/w4= github.com/grafana/authlib/types v0.0.0-20250219092154-21ce22b49f31 h1:EokLC5grHwLPs4tXW8T6E8187H1e5G9AP0QQ5B60HbA=