From 69743ed1a4d1dd0087cd78efe022e27d04991444 Mon Sep 17 00:00:00 2001 From: "lean.dev" <34773040+leandro-deveikis@users.noreply.github.com> Date: Fri, 25 Jul 2025 15:04:43 +0100 Subject: [PATCH 001/131] SecretsManager: remove unused metric (#108694) --- pkg/storage/secret/metadata/metrics/metrics.go | 9 --------- 1 file changed, 9 deletions(-) diff --git a/pkg/storage/secret/metadata/metrics/metrics.go b/pkg/storage/secret/metadata/metrics/metrics.go index bedaa03b4f8..aea3817f12c 100644 --- a/pkg/storage/secret/metadata/metrics/metrics.go +++ b/pkg/storage/secret/metadata/metrics/metrics.go @@ -35,7 +35,6 @@ type StorageMetrics struct { SecureValueMetadataGetCount prometheus.Counter SecureValueMetadataListDuration prometheus.Histogram SecureValueMetadataListCount prometheus.Counter - SecureValueGetForDecryptDuration prometheus.Histogram SecureValueSetExternalIDDuration prometheus.Histogram SecureValueSetStatusDuration prometheus.Histogram @@ -185,13 +184,6 @@ func newStorageMetrics() *StorageMetrics { Name: "secure_value_metadata_list_count", Help: "Count of secure value metadata list operations", }), - SecureValueGetForDecryptDuration: prometheus.NewHistogram(prometheus.HistogramOpts{ - Namespace: namespace, - Subsystem: subsystem, - Name: "secure_value_get_for_decrypt_duration_seconds", - Help: "Duration of secure value get for decrypt operations", - Buckets: prometheus.DefBuckets, - }), SecureValueSetExternalIDDuration: prometheus.NewHistogram(prometheus.HistogramOpts{ Namespace: namespace, Subsystem: subsystem, @@ -257,7 +249,6 @@ func NewStorageMetrics(reg prometheus.Registerer) *StorageMetrics { m.SecureValueMetadataGetCount, m.SecureValueMetadataListDuration, m.SecureValueMetadataListCount, - m.SecureValueGetForDecryptDuration, m.SecureValueSetExternalIDDuration, m.SecureValueSetStatusDuration, m.DecryptDuration, From b4e955ced75e4727fba768cdc83d77aa87a3b7cf Mon Sep 17 00:00:00 2001 From: Alex Khomenko Date: Fri, 25 Jul 2025 17:09:08 +0300 Subject: [PATCH 002/131] Provisioning: Use move API on dashboards settings page (#108671) * Provisioning: Use Move API to move dashboards in Dashboards Settings Page * i18n --- .../MoveProvisionedDashboardForm.test.tsx | 11 ------- .../settings/MoveProvisionedDashboardForm.tsx | 33 ++++--------------- public/locales/en-US/grafana.json | 1 - 3 files changed, 7 insertions(+), 38 deletions(-) diff --git a/public/app/features/dashboard-scene/settings/MoveProvisionedDashboardForm.test.tsx b/public/app/features/dashboard-scene/settings/MoveProvisionedDashboardForm.test.tsx index 30600a0e6df..cbcefb075a4 100644 --- a/public/app/features/dashboard-scene/settings/MoveProvisionedDashboardForm.test.tsx +++ b/public/app/features/dashboard-scene/settings/MoveProvisionedDashboardForm.test.tsx @@ -5,7 +5,6 @@ import { getAppEvents } from '@grafana/runtime'; import { useGetFolderQuery } from 'app/api/clients/folder/v1beta1'; import { useCreateRepositoryFilesWithPathMutation, - useDeleteRepositoryFilesWithPathMutation, useGetRepositoryFilesWithPathQuery, } from 'app/api/clients/provisioning/v0alpha1'; import { AnnoKeySourcePath } from 'app/features/apiserver/types'; @@ -26,7 +25,6 @@ jest.mock('@grafana/runtime', () => { jest.mock('app/api/clients/provisioning/v0alpha1', () => ({ useGetRepositoryFilesWithPathQuery: jest.fn(), useCreateRepositoryFilesWithPathMutation: jest.fn(), - useDeleteRepositoryFilesWithPathMutation: jest.fn(), provisioningAPIv0alpha1: { endpoints: { listRepository: { @@ -109,13 +107,6 @@ const mockCreateRequest = { error: null, }; -const mockDeleteRequest = { - isSuccess: false, - isError: false, - isLoading: false, - error: null, -}; - describe('MoveProvisionedDashboardForm', () => { beforeEach(() => { jest.clearAllMocks(); @@ -156,8 +147,6 @@ describe('MoveProvisionedDashboardForm', () => { (useCreateRepositoryFilesWithPathMutation as jest.Mock).mockReturnValue([jest.fn(), mockCreateRequest]); - (useDeleteRepositoryFilesWithPathMutation as jest.Mock).mockReturnValue([jest.fn(), mockDeleteRequest]); - (useProvisionedRequestHandler as jest.Mock).mockReturnValue(undefined); }); diff --git a/public/app/features/dashboard-scene/settings/MoveProvisionedDashboardForm.tsx b/public/app/features/dashboard-scene/settings/MoveProvisionedDashboardForm.tsx index a9e62edc3db..5a2a07cc478 100644 --- a/public/app/features/dashboard-scene/settings/MoveProvisionedDashboardForm.tsx +++ b/public/app/features/dashboard-scene/settings/MoveProvisionedDashboardForm.tsx @@ -10,7 +10,6 @@ import { useGetFolderQuery } from 'app/api/clients/folder/v1beta1'; import { RepositoryView, useCreateRepositoryFilesWithPathMutation, - useDeleteRepositoryFilesWithPathMutation, useGetRepositoryFilesWithPathQuery, } from 'app/api/clients/provisioning/v0alpha1'; import { AnnoKeySourcePath } from 'app/features/apiserver/types'; @@ -64,8 +63,7 @@ export function MoveProvisionedDashboardForm({ const { data: targetFolder } = useGetFolderQuery({ name: targetFolderUID! }, { skip: !targetFolderUID }); - const [createFile, createRequest] = useCreateRepositoryFilesWithPathMutation(); - const [deleteFile, deleteRequest] = useDeleteRepositoryFilesWithPathMutation(); + const [moveFile, moveRequest] = useCreateRepositoryFilesWithPathMutation(); const [targetPath, setTargetPath] = useState(''); const navigate = useNavigate(); @@ -103,32 +101,15 @@ export function MoveProvisionedDashboardForm({ const commitMessage = comment || `Move dashboard: ${dashboard.state.title}`; try { - await createFile({ + await moveFile({ name: repo, path: targetPath, ref: branchRef, message: commitMessage, body: currentFileData.resource.file, - }).unwrap(); - - await deleteFile({ - name: repo, - path: path, - ref: branchRef, - message: commitMessage, + originalPath: path, }).unwrap(); } catch (error) { - if (createRequest.isSuccess && !deleteRequest.isSuccess) { - appEvents.publish({ - type: AppEvents.alertWarning.name, - payload: [ - t( - 'dashboard-scene.move-provisioned-dashboard-form.partial-failure-warning', - 'Dashboard was created at new location but could not be deleted from original location. Please manually remove the old file.' - ), - ], - }); - } appEvents.publish({ type: AppEvents.alertError.name, payload: [t('dashboard-scene.move-provisioned-dashboard-form.api-error', 'Failed to move dashboard'), error], @@ -148,15 +129,15 @@ export function MoveProvisionedDashboardForm({ panelEditor?.onDiscard(); const url = buildResourceBranchRedirectUrl({ paramName: 'new_pull_request_url', - paramValue: createRequest?.data?.urls?.newPullRequestURL, - repoType: createRequest?.data?.repository?.type, + paramValue: moveRequest?.data?.urls?.newPullRequestURL, + repoType: moveRequest?.data?.repository?.type, }); navigate(url); }; useProvisionedRequestHandler({ dashboard, - request: createRequest, + request: moveRequest, workflow, handlers: { onBranchSuccess, @@ -164,7 +145,7 @@ export function MoveProvisionedDashboardForm({ }, }); - const isLoading = createRequest.isLoading || deleteRequest.isLoading; + const isLoading = moveRequest.isLoading; return ( Date: Fri, 25 Jul 2025 14:22:57 +0000 Subject: [PATCH 003/131] Alerting: Update alerting module to 615c8286e14b14347365db1b3db557d74d8952f1 (#108695) [create-pull-request] automated change Co-authored-by: yuri-tceretian <25988953+yuri-tceretian@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 023caf5199a..1ca1f6bb799 100644 --- a/go.mod +++ b/go.mod @@ -85,7 +85,7 @@ require ( github.com/googleapis/gax-go/v2 v2.14.2 // @grafana/grafana-backend-group github.com/gorilla/mux v1.8.1 // @grafana/grafana-backend-group github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // @grafana/grafana-app-platform-squad - github.com/grafana/alerting v0.0.0-20250716142237-8308539caa27 // @grafana/alerting-backend + github.com/grafana/alerting v0.0.0-20250725130805-615c8286e14b // @grafana/alerting-backend github.com/grafana/authlib v0.0.0-20250710201142-9542f2f28d43 // @grafana/identity-access-team github.com/grafana/authlib/types v0.0.0-20250710201142-9542f2f28d43 // @grafana/identity-access-team github.com/grafana/dataplane/examples v0.0.1 // @grafana/observability-metrics diff --git a/go.sum b/go.sum index 11e8025c482..7d457d8217c 100644 --- a/go.sum +++ b/go.sum @@ -1574,8 +1574,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.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo= github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA= -github.com/grafana/alerting v0.0.0-20250716142237-8308539caa27 h1:buoRKSKUO2QGJ16j2mY8T8S0KTjwB9uLtBrNvbYjkmM= -github.com/grafana/alerting v0.0.0-20250716142237-8308539caa27/go.mod h1:gtR7agmxVfJOmNKV/n2ZULgOYTYNL+PDKYB5N48tQ7Q= +github.com/grafana/alerting v0.0.0-20250725130805-615c8286e14b h1:mfUAq/N+mS82EcE35hDXWtfVY7UhTjzZxzssvFt9tvQ= +github.com/grafana/alerting v0.0.0-20250725130805-615c8286e14b/go.mod h1:VKxaR93Gff0ZlO2sPcdPVob1a/UzArFEW5zx3Bpyhls= github.com/grafana/authlib v0.0.0-20250710201142-9542f2f28d43 h1:vVPT0i5Y1vI6qzecYStV2yk7cHKrC3Pc7AgvwT5KydQ= github.com/grafana/authlib v0.0.0-20250710201142-9542f2f28d43/go.mod h1:1fWkOiL+m32NBgRHZtlZGz2ji868tPZACYbqP3nBRJI= github.com/grafana/authlib/types v0.0.0-20250710201142-9542f2f28d43 h1:NlkGMnVi/oUn6Cr90QbJYpQJ4FnjyAIG9Ex5GtTZIzw= From b1592b5e36d2dc477a4d6495a7343f31dccfc78a Mon Sep 17 00:00:00 2001 From: Bruno Date: Fri, 25 Jul 2025 11:41:21 -0300 Subject: [PATCH 004/131] Cloud migrations: store snapshots in the database (#108551) * Cloud migrations: store snapshots in the database * update github.com/grafana/grafana-cloud-migration-snapshot to v1.9.0 * make update-workspace * use new field name in test * return error after call to fmt.Errorf * create methods for readability / fix session deletiong not deleting snapshots * remove debugging changes * update sample.ini * update tests to include OrgID in ListSnapshotsQuery * lint * lint * Update pkg/services/cloudmigration/cloudmigrationimpl/snapshot_mgmt.go Co-authored-by: Matheus Macabu * remove TODO * Update pkg/services/cloudmigration/cloudmigrationimpl/snapshot_mgmt.go Co-authored-by: Matheus Macabu * remove one of the debug logs --------- Co-authored-by: Matheus Macabu --- conf/defaults.ini | 2 + conf/sample.ini | 2 + go.mod | 2 +- go.sum | 4 +- go.work.sum | 4 +- pkg/services/cloudmigration/cloudmigration.go | 5 + .../cloudmigrationimpl/cloudmigration.go | 32 ++-- .../cloudmigrationimpl/cloudmigration_test.go | 12 +- .../cloudmigrationimpl/snapshot_mgmt.go | 164 ++++++++++++++--- .../cloudmigrationimpl/store.go | 5 +- .../cloudmigrationimpl/xorm_store.go | 174 ++++++++++++++++-- .../cloudmigrationimpl/xorm_store_test.go | 79 ++++++-- .../gmsclient/gms_client_test.go | 2 +- .../gmsclient/inmemory_client.go | 2 +- pkg/services/cloudmigration/model.go | 43 +++-- .../sqlstore/migrations/cloud_migrations.go | 37 ++++ pkg/setting/setting_cloud_migration.go | 8 +- 17 files changed, 470 insertions(+), 107 deletions(-) diff --git a/conf/defaults.ini b/conf/defaults.ini index 9baa84e5760..65faaa76224 100644 --- a/conf/defaults.ini +++ b/conf/defaults.ini @@ -2171,6 +2171,8 @@ frontend_poll_interval = 2s # With "paused", all Alert Rules will be created in Paused state. This is helpful to avoid double notifications. # With "unchanged", all Alert Rules will be created with the pause state unchanged coming from the source instance. alert_rules_state = "paused" +# Either "db" to store snapshots in the database or "fs" to store in the file system. +resource_storage_type = "db" ###################################### Secrets Manager ###################################### [secrets_manager] diff --git a/conf/sample.ini b/conf/sample.ini index 238162d2590..30e5bb42f6a 100644 --- a/conf/sample.ini +++ b/conf/sample.ini @@ -2068,6 +2068,8 @@ default_datasource_uid = # With "paused", all Alert Rules will be created in Paused state. This is helpful to avoid double notifications. # With "unchanged", all Alert Rules will be created with the pause state unchanged coming from the source instance. ;alert_rules_state = "paused" +# Either "db" to store snapshots in the database or "fs" to store in the file system. +;resource_storage_type = "db" ###################################### Secrets Manager ###################################### [secrets_manager] diff --git a/go.mod b/go.mod index 1ca1f6bb799..05e5c77a5fc 100644 --- a/go.mod +++ b/go.mod @@ -99,7 +99,7 @@ require ( github.com/grafana/grafana-app-sdk/logging v0.39.3 // @grafana/grafana-app-platform-squad github.com/grafana/grafana-aws-sdk v1.0.4 // @grafana/aws-datasources github.com/grafana/grafana-azure-sdk-go/v2 v2.1.6 // @grafana/partner-datasources - github.com/grafana/grafana-cloud-migration-snapshot v1.6.0 // @grafana/grafana-operator-experience-squad + github.com/grafana/grafana-cloud-migration-snapshot v1.9.0 // @grafana/grafana-operator-experience-squad github.com/grafana/grafana-google-sdk-go v0.4.1 // @grafana/partner-datasources github.com/grafana/grafana-openapi-client-go v0.0.0-20231213163343-bd475d63fb79 // @grafana/grafana-backend-group github.com/grafana/grafana-plugin-sdk-go v0.278.0 // @grafana/plugins-platform-backend diff --git a/go.sum b/go.sum index 7d457d8217c..0f4910959d3 100644 --- a/go.sum +++ b/go.sum @@ -1602,8 +1602,8 @@ github.com/grafana/grafana-aws-sdk v1.0.4 h1:D14UAehsOqpjliHmHzveRQ1p43KCsMzdmb7 github.com/grafana/grafana-aws-sdk v1.0.4/go.mod h1:hO7q7yWV+t6dmiyJjMa3IbuYnYkBua+G/IAlOPVIYKE= github.com/grafana/grafana-azure-sdk-go/v2 v2.1.6 h1:OfCkitCuomzZKW1WYHrG8MxKwtMhALb7jqoj+487eTg= github.com/grafana/grafana-azure-sdk-go/v2 v2.1.6/go.mod h1:V7y2BmsWxS3A9Ohebwn4OiSfJJqi//4JQydQ8fHTduo= -github.com/grafana/grafana-cloud-migration-snapshot v1.6.0 h1:S4kHwr//AqhtL9xHBtz1gqVgZQeCRGTxjgsRBAkpjKY= -github.com/grafana/grafana-cloud-migration-snapshot v1.6.0/go.mod h1:rWNhyxYkgiXgV7xZ4yOQzMV08yikO8L8S8M5KNoQNpA= +github.com/grafana/grafana-cloud-migration-snapshot v1.9.0 h1:JOzchPgptwJdruYoed7x28lFDwhzs7kssResYsnC0iI= +github.com/grafana/grafana-cloud-migration-snapshot v1.9.0/go.mod h1:nOHgq4Oa829qmBKA5KIXw5Ipo3rhLs0d6A8UI9Nw8Zk= github.com/grafana/grafana-google-sdk-go v0.4.1 h1:QdHmgDzlV3RzBTvIxd+WuxER1+afnFzUmEivbwDo27E= github.com/grafana/grafana-google-sdk-go v0.4.1/go.mod h1:U73+w9DlbEtUonhQUzERwlXnzWTtfRoyrtKH8d3VY40= github.com/grafana/grafana-openapi-client-go v0.0.0-20231213163343-bd475d63fb79 h1:r+mU5bGMzcXCRVAuOrTn54S80qbfVkvTdUJZfSfTNbs= diff --git a/go.work.sum b/go.work.sum index aebd5f7c7d7..fd43ea298b9 100644 --- a/go.work.sum +++ b/go.work.sum @@ -628,8 +628,6 @@ github.com/aws/aws-msk-iam-sasl-signer-go v1.0.1 h1:nMp7diZObd4XEVUR0pEvn7/E13JI github.com/aws/aws-msk-iam-sasl-signer-go v1.0.1/go.mod h1:MVYeeOhILFFemC/XlYTClvBjYZrg/EPd3ts885KrNTI= github.com/aws/aws-sdk-go-v2/service/kms v1.35.3 h1:UPTdlTOwWUX49fVi7cymEN6hDqCwe3LNv1vi7TXUutk= github.com/aws/aws-sdk-go-v2/service/kms v1.35.3/go.mod h1:gjDP16zn+WWalyaUqwCCioQ8gU8lzttCCc9jYsiQI/8= -github.com/aws/aws-sdk-go-v2/service/kms v1.38.1 h1:tecq7+mAav5byF+Mr+iONJnCBf4B4gon8RSp4BrweSc= -github.com/aws/aws-sdk-go-v2/service/kms v1.38.1/go.mod h1:cQn6tAF77Di6m4huxovNM7NVAozWTZLsDRp9t8Z/WYk= github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.32.4 h1:NgRFYyFpiMD62y4VPXh4DosPFbZd4vdMVBWKk0VmWXc= github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.32.4/go.mod h1:TKKN7IQoM7uTnyuFm9bm9cw5P//ZYTl4m3htBWQ1G/c= github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.35.2 h1:vlYXbindmagyVA3RS2SPd47eKZ00GZZQcr+etTviHtc= @@ -951,6 +949,8 @@ github.com/grafana/grafana-aws-sdk v0.38.2 h1:TzQD0OpWsNjtldi5G5TLDlBRk8OyDf+B5u github.com/grafana/grafana-aws-sdk v0.38.2/go.mod h1:j3vi+cXYHEFqjhBGrI6/lw1TNM+dl0Y3f0cSnDOPy+s= github.com/grafana/grafana-aws-sdk v1.0.2 h1:98eBuHYFmgvH0xO9kKf4RBsEsgQRp8EOA/9yhDIpkss= github.com/grafana/grafana-aws-sdk v1.0.2/go.mod h1:hO7q7yWV+t6dmiyJjMa3IbuYnYkBua+G/IAlOPVIYKE= +github.com/grafana/grafana-cloud-migration-snapshot v1.9.0 h1:JOzchPgptwJdruYoed7x28lFDwhzs7kssResYsnC0iI= +github.com/grafana/grafana-cloud-migration-snapshot v1.9.0/go.mod h1:nOHgq4Oa829qmBKA5KIXw5Ipo3rhLs0d6A8UI9Nw8Zk= github.com/grafana/grafana-plugin-sdk-go v0.263.0/go.mod h1:U43Cnrj/9DNYyvFcNdeUWNjMXTKNB0jcTcQGpWKd2gw= github.com/grafana/grafana-plugin-sdk-go v0.267.0/go.mod h1:OuwS4c/JYgn0rr/w5zhJBpLo4gKm/vw15RsfpYAvK9Q= github.com/grafana/grafana-plugin-sdk-go v0.269.1/go.mod h1:yv2KbO4mlr9WuDK2f+2gHAMTwwLmLuqaEnrPXTRU+OI= diff --git a/pkg/services/cloudmigration/cloudmigration.go b/pkg/services/cloudmigration/cloudmigration.go index 7b90fb750d5..a325d736b0f 100644 --- a/pkg/services/cloudmigration/cloudmigration.go +++ b/pkg/services/cloudmigration/cloudmigration.go @@ -7,6 +7,11 @@ import ( "github.com/grafana/grafana/pkg/services/user" ) +const ( + ResourceStorageTypeFs = "fs" + ResourceStorageTypeDb = "db" +) + type Service interface { // GetToken Returns the cloud migration token if it exists. GetToken(ctx context.Context) (authapi.TokenView, error) diff --git a/pkg/services/cloudmigration/cloudmigrationimpl/cloudmigration.go b/pkg/services/cloudmigration/cloudmigrationimpl/cloudmigration.go index a2342c9338e..163fcfbcb1b 100644 --- a/pkg/services/cloudmigration/cloudmigrationimpl/cloudmigration.go +++ b/pkg/services/cloudmigration/cloudmigrationimpl/cloudmigration.go @@ -496,23 +496,24 @@ func (s *Service) CreateSnapshot(ctx context.Context, signedInUser *user.SignedI // save snapshot to the db snapshot := cloudmigration.CloudMigrationSnapshot{ - UID: util.GenerateShortUID(), - SessionUID: cmd.SessionUID, - Status: cloudmigration.SnapshotStatusCreating, - EncryptionKey: initResp.EncryptionKey, - GMSSnapshotUID: initResp.SnapshotID, - LocalDir: filepath.Join(s.cfg.CloudMigration.SnapshotFolder, "grafana", "snapshots", initResp.SnapshotID), + UID: util.GenerateShortUID(), + SessionUID: cmd.SessionUID, + Status: cloudmigration.SnapshotStatusCreating, + GMSPublicKey: initResp.GMSPublicKey, + GMSSnapshotUID: initResp.SnapshotID, + Metadata: initResp.Metadata, + EncryptionAlgo: initResp.Algo, + LocalDir: filepath.Join(s.cfg.CloudMigration.SnapshotFolder, "grafana", "snapshots", initResp.SnapshotID), + ResourceStorageType: s.cfg.CloudMigration.ResourceStorageType, } - uid, err := s.store.CreateSnapshot(ctx, snapshot) - if err != nil { + if err := s.store.CreateSnapshot(ctx, snapshot); err != nil { return nil, fmt.Errorf("saving snapshot: %w", err) } - snapshot.UID = uid // Update status to "creating" to ensure the frontend polls from now on if err := s.updateSnapshotWithRetries(ctx, cloudmigration.UpdateSnapshotCmd{ - UID: uid, + UID: snapshot.UID, SessionID: cmd.SessionUID, Status: cloudmigration.SnapshotStatusCreating, }); err != nil { @@ -538,6 +539,7 @@ func (s *Service) CreateSnapshot(ctx context.Context, signedInUser *user.SignedI s.report(asyncCtx, session, gmsclient.EventStartBuildingSnapshot, 0, nil, signedInUser.UserUID) start := time.Now() + err := s.buildSnapshot(asyncCtx, signedInUser, initResp.MaxItemsPerPartition, initResp.Metadata, snapshot, cmd.ResourceTypes) if err != nil { asyncSpan.SetStatus(codes.Error, "error building snapshot") @@ -896,10 +898,12 @@ func (s *Service) deleteLocalFiles(snapshots []cloudmigration.CloudMigrationSnap var err error for _, snapshot := range snapshots { - err = os.RemoveAll(snapshot.LocalDir) - if err != nil { - // in this case we only log the error, don't return it to continue with the process - s.log.Error("deleting migration snapshot files", "err", err) + if snapshot.LocalDir != "" { + err = os.RemoveAll(snapshot.LocalDir) + if err != nil { + // in this case we only log the error, don't return it to continue with the process + s.log.Error("deleting migration snapshot files", "err", err) + } } } return err diff --git a/pkg/services/cloudmigration/cloudmigrationimpl/cloudmigration_test.go b/pkg/services/cloudmigration/cloudmigrationimpl/cloudmigration_test.go index 90d9cc7ce78..3bf16b66ef9 100644 --- a/pkg/services/cloudmigration/cloudmigrationimpl/cloudmigration_test.go +++ b/pkg/services/cloudmigration/cloudmigrationimpl/cloudmigration_test.go @@ -103,14 +103,15 @@ func Test_GetSnapshotStatusFromGMS(t *testing.T) { }) require.NoError(t, err) - uid, err := s.store.CreateSnapshot(ctx, cloudmigration.CloudMigrationSnapshot{ - UID: "test uid", + uid := "test uid" + + err = s.store.CreateSnapshot(ctx, cloudmigration.CloudMigrationSnapshot{ + UID: uid, SessionUID: sess.UID, Status: cloudmigration.SnapshotStatusCreating, GMSSnapshotUID: "gms uid", }) require.NoError(t, err) - assert.Equal(t, "test uid", uid) // Make sure status is coming from the db only snapshot, err := s.GetSnapshot(ctx, cloudmigration.GetSnapshotsQuery{ @@ -381,8 +382,9 @@ func Test_OnlyQueriesStatusFromGMSWhenRequired(t *testing.T) { }) require.NoError(t, err) - uid, err := s.store.CreateSnapshot(context.Background(), cloudmigration.CloudMigrationSnapshot{ - UID: uuid.NewString(), + uid := uuid.NewString() + err = s.store.CreateSnapshot(context.Background(), cloudmigration.CloudMigrationSnapshot{ + UID: uid, SessionUID: sess.UID, Status: cloudmigration.SnapshotStatusCreating, GMSSnapshotUID: "gms uid", diff --git a/pkg/services/cloudmigration/cloudmigrationimpl/snapshot_mgmt.go b/pkg/services/cloudmigration/cloudmigrationimpl/snapshot_mgmt.go index 8f35242d66e..7d3cbb0161c 100644 --- a/pkg/services/cloudmigration/cloudmigrationimpl/snapshot_mgmt.go +++ b/pkg/services/cloudmigration/cloudmigrationimpl/snapshot_mgmt.go @@ -1,6 +1,7 @@ package cloudmigrationimpl import ( + "bytes" "context" cryptoRand "crypto/rand" "encoding/json" @@ -562,7 +563,7 @@ func (s *Service) buildSnapshot( // Use GMS public key + the grafana generated private key to encrypt snapshot files. snapshotWriter, err := snapshot.NewSnapshotWriter(contracts.AssymetricKeys{ - Public: snapshotMeta.EncryptionKey, + Public: snapshotMeta.GMSPublicKey, Private: privateKey[:], }, crypto.NewNacl(), @@ -605,6 +606,56 @@ func (s *Service) buildSnapshot( } } + switch s.cfg.CloudMigration.ResourceStorageType { + case cloudmigration.ResourceStorageTypeDb: + if err := s.buildSnapshotWithDBStorage(ctx, snapshotMeta.UID, snapshotWriter, resourcesGroupedByType, maxItemsPerPartition); err != nil { + return fmt.Errorf("building snapshot with database storage: %w", err) + } + s.log.Debug(fmt.Sprintf("buildSnapshot: wrote data partitions with database storage in %d ms", time.Since(start).Milliseconds())) + + case cloudmigration.ResourceStorageTypeFs: + if err := s.buildSnapshotWithFSStorage(publicKey[:], metadata, snapshotWriter, resourcesGroupedByType, maxItemsPerPartition); err != nil { + return fmt.Errorf("building snapshot with file system storage: %w", err) + } + s.log.Debug(fmt.Sprintf("buildSnapshot: wrote data partitions with file system storage in %d ms", time.Since(start).Milliseconds())) + + default: + return fmt.Errorf("unknown resource storage type, check your configuration and try again: %q", s.cfg.CloudMigration.ResourceStorageType) + } + + // update snapshot status to pending upload with retries + if err := s.updateSnapshotWithRetries(ctx, cloudmigration.UpdateSnapshotCmd{ + UID: snapshotMeta.UID, + SessionID: snapshotMeta.SessionUID, + Status: cloudmigration.SnapshotStatusPendingUpload, + LocalResourcesToCreate: localSnapshotResource, + PublicKey: publicKey[:], + }); err != nil { + return err + } + + return nil +} + +func (s *Service) buildSnapshotWithDBStorage(ctx context.Context, snapshotUID string, snapshotWriter *snapshot.SnapshotWriter, resourcesGroupedByType map[cloudmigration.MigrateDataType][]snapshot.MigrateDataRequestItemDTO, maxItemsPerPartition uint32) error { + for _, resourceType := range currentMigrationTypes { + i := 0 + for chunk := range slices.Chunk(resourcesGroupedByType[resourceType], int(maxItemsPerPartition)) { + encoded, err := snapshotWriter.EncodePartition(chunk) + if err != nil { + return fmt.Errorf("encoding snapshot partition: %w", err) + } + if err := s.store.StorePartition(ctx, snapshotUID, string(resourceType), i, encoded); err != nil { + return fmt.Errorf("storing partition into database: %w", err) + } + i += 1 + } + } + + return nil +} + +func (s *Service) buildSnapshotWithFSStorage(publicKey, metadata []byte, snapshotWriter *snapshot.SnapshotWriter, resourcesGroupedByType map[cloudmigration.MigrateDataType][]snapshot.MigrateDataRequestItemDTO, maxItemsPerPartition uint32) error { for _, resourceType := range currentMigrationTypes { for chunk := range slices.Chunk(resourcesGroupedByType[resourceType], int(maxItemsPerPartition)) { if err := snapshotWriter.Write(string(resourceType), chunk); err != nil { @@ -613,8 +664,6 @@ func (s *Service) buildSnapshot( } } - s.log.Debug(fmt.Sprintf("buildSnapshot: wrote data files in %d ms", time.Since(start).Milliseconds())) - // Add the grafana generated public key to the index file so gms can use it to decrypt the snapshot files later. // This works because the snapshot files are being encrypted with // the grafana generated private key + the gms public key. @@ -625,18 +674,6 @@ func (s *Service) buildSnapshot( return fmt.Errorf("finishing writing snapshot files and generating index file: %w", err) } - s.log.Debug(fmt.Sprintf("buildSnapshot: finished snapshot in %d ms", time.Since(start).Milliseconds())) - - // update snapshot status to pending upload with retries - if err := s.updateSnapshotWithRetries(ctx, cloudmigration.UpdateSnapshotCmd{ - UID: snapshotMeta.UID, - SessionID: snapshotMeta.SessionUID, - Status: cloudmigration.SnapshotStatusPendingUpload, - LocalResourcesToCreate: localSnapshotResource, - }); err != nil { - return err - } - return nil } @@ -654,13 +691,94 @@ func (s *Service) uploadSnapshot(ctx context.Context, session *cloudmigration.Cl s.log.Debug(fmt.Sprintf("uploadSnapshot: method completed in %d ms", time.Since(start).Milliseconds())) }() + switch s.cfg.CloudMigration.ResourceStorageType { + case cloudmigration.ResourceStorageTypeDb: + if err := s.uploadSnapshotWithDBStorage(ctx, session, snapshotMeta, uploadUrl); err != nil { + return fmt.Errorf("uploading snapshot with database storage: %w", err) + } + + case cloudmigration.ResourceStorageTypeFs: + if err := s.uploadSnapshotWithFSStorage(ctx, session, snapshotMeta, uploadUrl); err != nil { + return fmt.Errorf("uploading snapshot with file system storage: %w", err) + } + + default: + return fmt.Errorf("unknown resource storage type, check your configuration and try again: %q", s.cfg.CloudMigration.ResourceStorageType) + } + + s.log.Info("successfully uploaded snapshot", "snapshotUid", snapshotMeta.UID, "cloud_snapshotUid", snapshotMeta.GMSSnapshotUID) + + // update snapshot status to processing with retries + if err := s.updateSnapshotWithRetries(ctx, cloudmigration.UpdateSnapshotCmd{ + UID: snapshotMeta.UID, + SessionID: snapshotMeta.SessionUID, + Status: cloudmigration.SnapshotStatusProcessing, + }); err != nil { + return err + } + + return nil +} + +func (s *Service) uploadSnapshotWithDBStorage(ctx context.Context, session *cloudmigration.CloudMigrationSession, snapshotMeta *cloudmigration.CloudMigrationSnapshot, uploadUrl string) error { + index, err := s.store.GetIndex(ctx, session.OrgID, snapshotMeta.SessionUID, snapshotMeta.UID) + if err != nil { + return fmt.Errorf("fetching index from database: %w", err) + } + + snapshotIndex := snapshot.Index{ + Version: 1, + EncryptionAlgo: index.EncryptionAlgo, + PublicKey: index.PublicKey, + Metadata: index.Metadata, + Items: make(map[string][]string), + } + + var partitionToFileName = func(resourceType string, partitionNumber int) string { + return fmt.Sprintf("%+v_%+v", resourceType, partitionNumber) + } + + for resourceType, partitionsNumbers := range index.Items { + for _, partitionNumber := range partitionsNumbers { + fileName := partitionToFileName(resourceType, partitionNumber) + snapshotIndex.Items[resourceType] = append(snapshotIndex.Items[resourceType], fileName) + + key := fmt.Sprintf("%d/snapshots/%s/%+v", session.StackID, snapshotMeta.GMSSnapshotUID, fileName) + + partition, err := s.store.GetPartition(ctx, snapshotMeta.UID, resourceType, partitionNumber) + if err != nil { + return fmt.Errorf("fetching partition from database: %w", err) + } + if err = s.objectStorage.PresignedURLUpload(ctx, uploadUrl, key, bytes.NewReader(partition.Data)); err != nil { + return fmt.Errorf("uploading file using presigned url: %w", err) + } + } + } + + key := fmt.Sprintf("%d/snapshots/%s/%s", session.StackID, snapshotMeta.GMSSnapshotUID, "index.json") + + buffer, err := snapshot.EncodeIndex(snapshotIndex) + + if err != nil { + return fmt.Errorf("encoding snapshot index for upload: %w", err) + } + + if err = s.objectStorage.PresignedURLUpload(ctx, uploadUrl, key, bytes.NewReader(buffer)); err != nil { + return fmt.Errorf("uploading index file using presigned url: %w", err) + } + + return nil +} + +func (s *Service) uploadSnapshotWithFSStorage(ctx context.Context, session *cloudmigration.CloudMigrationSession, snapshotMeta *cloudmigration.CloudMigrationSnapshot, uploadUrl string) error { indexFilePath := filepath.Join(snapshotMeta.LocalDir, "index.json") + + start := time.Now() // LocalDir can be set in the configuration, therefore the file path can be set to any path. // nolint:gosec indexFile, err := os.Open(indexFilePath) if err != nil { - // TODO: Clean this notice once we've fixed the HA bug - return fmt.Errorf("opening index files: %w. If you are running Grafana in a highly-available setup, try scaling down to one replica to avoid a known bug: https://github.com/grafana/grafana/issues/107264", err) + return fmt.Errorf("opening index files: %w. If you are running Grafana in a highly-available setup, try setting cloud_migration.resource_storage_type to 'db' or scaling down to one replica", err) } defer func() { if closeErr := indexFile.Close(); closeErr != nil { @@ -679,8 +797,6 @@ func (s *Service) uploadSnapshot(ctx context.Context, session *cloudmigration.Cl } readIndexSpan.End() - s.log.Debug(fmt.Sprintf("uploadSnapshot: read index file in %d ms", time.Since(start).Milliseconds())) - uploadCtx, uploadSpan := s.tracer.Start(ctx, "CloudMigrationService.uploadSnapshot.uploadDataFiles") // Upload the data files. for _, fileNames := range index.Items { @@ -724,16 +840,6 @@ func (s *Service) uploadSnapshot(ctx context.Context, session *cloudmigration.Cl uploadSpan.End() s.log.Debug(fmt.Sprintf("uploadSnapshot: uploaded index file in %d ms", time.Since(start).Milliseconds())) - s.log.Info("successfully uploaded snapshot", "snapshotUid", snapshotMeta.UID, "cloud_snapshotUid", snapshotMeta.GMSSnapshotUID) - - // update snapshot status to processing with retries - if err := s.updateSnapshotWithRetries(ctx, cloudmigration.UpdateSnapshotCmd{ - UID: snapshotMeta.UID, - SessionID: snapshotMeta.SessionUID, - Status: cloudmigration.SnapshotStatusProcessing, - }); err != nil { - return err - } return nil } diff --git a/pkg/services/cloudmigration/cloudmigrationimpl/store.go b/pkg/services/cloudmigration/cloudmigrationimpl/store.go index 3d4d3703ed8..316fae7e9bd 100644 --- a/pkg/services/cloudmigration/cloudmigrationimpl/store.go +++ b/pkg/services/cloudmigration/cloudmigrationimpl/store.go @@ -12,8 +12,11 @@ type store interface { GetCloudMigrationSessionList(ctx context.Context, orgID int64) ([]*cloudmigration.CloudMigrationSession, error) DeleteMigrationSessionByUID(ctx context.Context, orgID int64, uid string) (*cloudmigration.CloudMigrationSession, []cloudmigration.CloudMigrationSnapshot, error) - CreateSnapshot(ctx context.Context, snapshot cloudmigration.CloudMigrationSnapshot) (string, error) + CreateSnapshot(ctx context.Context, snapshot cloudmigration.CloudMigrationSnapshot) error UpdateSnapshot(ctx context.Context, snapshot cloudmigration.UpdateSnapshotCmd) error + GetIndex(ctx context.Context, orgID int64, sessionUID string, snapshotUID string) (cloudmigration.CloudMigrationSnapshotIndex, error) + GetPartition(ctx context.Context, snapshotUID string, resourceType string, partitionNumber int) (cloudmigration.CloudMigrationSnapshotPartition, error) + StorePartition(ctx context.Context, snapshotUID string, resourceType string, partitionNumber int, data []byte) error GetSnapshotByUID(ctx context.Context, orgID int64, sessUid, id string, params cloudmigration.SnapshotResultQueryParams) (*cloudmigration.CloudMigrationSnapshot, error) GetSnapshotList(ctx context.Context, query cloudmigration.ListSnapshotsQuery) ([]cloudmigration.CloudMigrationSnapshot, error) } diff --git a/pkg/services/cloudmigration/cloudmigrationimpl/xorm_store.go b/pkg/services/cloudmigration/cloudmigrationimpl/xorm_store.go index 0dec65ae14f..20b401ff615 100644 --- a/pkg/services/cloudmigration/cloudmigrationimpl/xorm_store.go +++ b/pkg/services/cloudmigration/cloudmigrationimpl/xorm_store.go @@ -121,6 +121,7 @@ func (ss *sqlStore) DeleteMigrationSessionByUID(ctx context.Context, orgID int64 SessionUID: uid, Page: 1, Limit: GetAllSnapshots, + OrgID: orgID, } snapshots, err := ss.GetSnapshotList(ctx, q) if err != nil { @@ -129,12 +130,13 @@ func (ss *sqlStore) DeleteMigrationSessionByUID(ctx context.Context, orgID int64 err = ss.db.InTransaction(ctx, func(ctx context.Context) error { for _, snapshot := range snapshots { - err := ss.deleteSnapshotResources(ctx, snapshot.UID) - if err != nil { + if err := ss.deleteSnapshotResources(ctx, snapshot.UID); err != nil { return fmt.Errorf("deleting snapshot resource from db: %w", err) } - err = ss.deleteSnapshot(ctx, snapshot.UID) - if err != nil { + if err := ss.deleteSnapshotPartitions(ctx, snapshot.UID); err != nil { + return fmt.Errorf("deleting snapshot partitions: %w", err) + } + if err := ss.deleteSnapshot(ctx, snapshot.UID); err != nil { return fmt.Errorf("deleting snapshot from db: %w", err) } } @@ -166,33 +168,33 @@ func (ss *sqlStore) DeleteMigrationSessionByUID(ctx context.Context, orgID int64 return &c, snapshots, nil } -func (ss *sqlStore) CreateSnapshot(ctx context.Context, snapshot cloudmigration.CloudMigrationSnapshot) (string, error) { +func (ss *sqlStore) CreateSnapshot(ctx context.Context, snapshot cloudmigration.CloudMigrationSnapshot) error { if snapshot.SessionUID == "" { - return "", fmt.Errorf("sessionUID is required") + return fmt.Errorf("sessionUID is required") } - if snapshot.UID == "" { - snapshot.UID = util.GenerateShortUID() + return fmt.Errorf("snapshot uid is required") } - if err := ss.secretsStore.Set(ctx, secretskv.AllOrganizations, snapshot.UID, secretType, string(snapshot.EncryptionKey)); err != nil { - return "", err + if err := ss.secretsStore.Set(ctx, secretskv.AllOrganizations, snapshot.UID, secretType, string(snapshot.GMSPublicKey)); err != nil { + return err } err := ss.db.WithDbSession(ctx, func(sess *sqlstore.DBSession) error { snapshot.Created = time.Now() snapshot.Updated = time.Now() - _, err := sess.Insert(&snapshot) + _, err := sess.InsertOne(&snapshot) if err != nil { return err } + return nil }) if err != nil { - return "", err + return err } - return snapshot.UID, nil + return nil } // UpdateSnapshot takes a command containing a snapshot uid and any updates to apply to the snapshot. @@ -232,19 +234,133 @@ func (ss *sqlStore) UpdateSnapshot(ctx context.Context, update cloudmigration.Up return err } } + if update.PublicKey != nil { + if err := ss.db.WithDbSession(ctx, func(sess *sqlstore.DBSession) error { + rawSQL := "UPDATE cloud_migration_snapshot SET public_key=? WHERE session_uid=? AND uid=?" + if _, err := sess.Exec(rawSQL, update.PublicKey, update.SessionID, update.UID); err != nil { + return fmt.Errorf("updating snapshot public key for uid %s: %w", update.UID, err) + } + return nil + }); err != nil { + return err + } + } return nil } -func (ss *sqlStore) deleteSnapshot(ctx context.Context, snapshotUid string) error { - return ss.db.WithDbSession(ctx, func(sess *sqlstore.DBSession) error { - _, err := sess.Delete(cloudmigration.CloudMigrationSnapshot{ - UID: snapshotUid, +func (ss *sqlStore) StorePartition(ctx context.Context, snapshotUID string, resourceType string, partitionNumber int, data []byte) error { + return ss.db.InTransaction(ctx, func(ctx context.Context) error { + return ss.db.WithDbSession(ctx, func(sess *sqlstore.DBSession) error { + _, err := sess.Insert(cloudmigration.CloudMigrationSnapshotPartition{ + SnapshotUID: snapshotUID, + ResourceType: resourceType, + PartitionNumber: partitionNumber, + Data: data, + }) + if err != nil { + return fmt.Errorf("inserting snapshot partition into database: %w", err) + } + return nil }) - return err }) } +func (ss *sqlStore) GetIndex(ctx context.Context, orgID int64, sessionUID string, snapshotUID string) (cloudmigration.CloudMigrationSnapshotIndex, error) { + var snap *cloudmigration.CloudMigrationSnapshot + partitions := make([]cloudmigration.CloudMigrationSnapshotPartition, 0) + + if err := ss.db.InTransaction(ctx, func(ctx context.Context) error { + return ss.db.WithDbSession(ctx, func(sess *sqlstore.DBSession) error { + s, err := ss.getSnapshotByUID(ctx, orgID, sessionUID, snapshotUID) + if err != nil { + return fmt.Errorf("fetching snapshot from database: %w", err) + } + + snap = s + if err := sess.OrderBy("cloud_migration_snapshot_partition.resource_type,cloud_migration_snapshot_partition.partition_number ASC").Find(&partitions, &cloudmigration.CloudMigrationSnapshotPartition{SnapshotUID: snapshotUID}); err != nil { + return fmt.Errorf("fetching partition from database: %w", err) + } + if secret, found, err := ss.secretsStore.Get(ctx, secretskv.AllOrganizations, snap.UID, secretType); err != nil { + return err + } else if !found { + return fmt.Errorf("encryption key not found for snapshot with UID %s", snap.UID) + } else { + snap.GMSPublicKey = []byte(secret) + } + + return nil + }) + }); err != nil { + return cloudmigration.CloudMigrationSnapshotIndex{}, err + } + + partitionsByResourceType := make(map[string][]int) + for _, partition := range partitions { + partitionsByResourceType[partition.ResourceType] = append(partitionsByResourceType[partition.ResourceType], partition.PartitionNumber) + } + + return cloudmigration.CloudMigrationSnapshotIndex{ + EncryptionAlgo: snap.EncryptionAlgo, + PublicKey: snap.PublicKey, + Metadata: snap.Metadata, + Items: partitionsByResourceType, + }, nil +} + +func (ss *sqlStore) GetPartition(ctx context.Context, snapshotUID string, resourceType string, partitionNumber int) (cloudmigration.CloudMigrationSnapshotPartition, error) { + var partition cloudmigration.CloudMigrationSnapshotPartition + + err := ss.db.InTransaction(ctx, func(ctx context.Context) error { + return ss.db.WithDbSession(ctx, func(sess *sqlstore.DBSession) error { + if _, err := sess.Where("snapshot_uid = ? AND resource_type = ? AND partition_number = ?", snapshotUID, resourceType, partitionNumber).Get(&partition); err != nil { + return fmt.Errorf("fetching partition from database: %w", err) + } + return nil + }) + }) + + return partition, err +} + +func (ss *sqlStore) deleteSnapshot(ctx context.Context, snapshotUid string) error { + return ss.db.InTransaction(ctx, func(ctx context.Context) error { + return ss.db.WithDbSession(ctx, func(sess *sqlstore.DBSession) error { + if _, err := sess.Delete(cloudmigration.CloudMigrationSnapshot{ + UID: snapshotUid, + }); err != nil { + return fmt.Errorf("deleting snapshot: %w", err) + } + return nil + }) + }) +} + +func (ss *sqlStore) getSnapshotByUID(ctx context.Context, orgID int64, sessionUID string, snapshotUID string) (*cloudmigration.CloudMigrationSnapshot, error) { + session, err := ss.GetMigrationSessionByUID(ctx, orgID, sessionUID) + if err != nil || session == nil { + return nil, err + } + + // now we get the snapshot + var snapshot cloudmigration.CloudMigrationSnapshot + err = ss.db.WithDbSession(ctx, func(sess *db.Session) error { + exist, err := sess.Where("session_uid=? AND uid=?", sessionUID, snapshotUID).Get(&snapshot) + if err != nil { + return err + } + if !exist { + return cloudmigration.ErrSnapshotNotFound + } + return nil + }) + if err != nil { + return nil, err + } + + return &snapshot, nil +} + func (ss *sqlStore) GetSnapshotByUID(ctx context.Context, orgID int64, sessionUid, uid string, params cloudmigration.SnapshotResultQueryParams) (*cloudmigration.CloudMigrationSnapshot, error) { // first we check if the session exists, using orgId and sessionUid session, err := ss.GetMigrationSessionByUID(ctx, orgID, sessionUid) @@ -273,7 +389,7 @@ func (ss *sqlStore) GetSnapshotByUID(ctx context.Context, orgID int64, sessionUi } else if !found { return &snapshot, fmt.Errorf("encryption key not found for snapshot with UID %s", snapshot.UID) } else { - snapshot.EncryptionKey = []byte(secret) + snapshot.GMSPublicKey = []byte(secret) } resources, err := ss.getSnapshotResources(ctx, uid, params) @@ -291,6 +407,12 @@ func (ss *sqlStore) GetSnapshotByUID(ctx context.Context, orgID int64, sessionUi // GetSnapshotList returns snapshots without resources included. Use GetSnapshotByUID to get individual snapshot results. // passing GetAllSnapshots will return all the elements regardless of the page func (ss *sqlStore) GetSnapshotList(ctx context.Context, query cloudmigration.ListSnapshotsQuery) ([]cloudmigration.CloudMigrationSnapshot, error) { + if query.OrgID == 0 { + return nil, fmt.Errorf("org id is required") + } + if query.SessionUID == "" { + return nil, fmt.Errorf("session uid is required") + } var snapshots = make([]cloudmigration.CloudMigrationSnapshot, 0) err := ss.db.WithDbSession(ctx, func(sess *db.Session) error { sess.Join("INNER", "cloud_migration_session", @@ -310,13 +432,14 @@ func (ss *sqlStore) GetSnapshotList(ctx context.Context, query cloudmigration.Li if err != nil { return nil, err } + for i, snapshot := range snapshots { if secret, found, err := ss.secretsStore.Get(ctx, secretskv.AllOrganizations, snapshot.UID, secretType); err != nil { return nil, err } else if !found { return nil, fmt.Errorf("encryption key not found for snapshot with UID %s", snapshot.UID) } else { - snapshot.EncryptionKey = []byte(secret) + snapshot.GMSPublicKey = []byte(secret) } if stats, err := ss.getSnapshotResourceStats(ctx, snapshot.UID); err != nil { @@ -531,6 +654,17 @@ func (ss *sqlStore) deleteSnapshotResources(ctx context.Context, snapshotUid str }) } +func (ss *sqlStore) deleteSnapshotPartitions(ctx context.Context, snapshotUid string) error { + return ss.db.WithDbSession(ctx, func(sess *sqlstore.DBSession) error { + if _, err := sess.Delete(cloudmigration.CloudMigrationSnapshotPartition{ + SnapshotUID: snapshotUid, + }); err != nil { + return fmt.Errorf("deleting snapshot partitions: %w", err) + } + return nil + }) +} + func (ss *sqlStore) encryptToken(ctx context.Context, cm *cloudmigration.CloudMigrationSession) error { s, err := ss.secretsService.Encrypt(ctx, []byte(cm.AuthToken), secrets.WithoutScope()) if err != nil { diff --git a/pkg/services/cloudmigration/cloudmigrationimpl/xorm_store_test.go b/pkg/services/cloudmigration/cloudmigrationimpl/xorm_store_test.go index 1c96293e4b7..2d84b257a5a 100644 --- a/pkg/services/cloudmigration/cloudmigrationimpl/xorm_store_test.go +++ b/pkg/services/cloudmigration/cloudmigrationimpl/xorm_store_test.go @@ -1,13 +1,18 @@ package cloudmigrationimpl import ( + "bytes" "context" + cryptoRand "crypto/rand" "encoding/base64" "fmt" "strconv" "testing" "github.com/google/uuid" + snapshot "github.com/grafana/grafana-cloud-migration-snapshot/src" + "github.com/grafana/grafana-cloud-migration-snapshot/src/contracts" + "github.com/grafana/grafana-cloud-migration-snapshot/src/infra/crypto" "github.com/grafana/grafana/pkg/infra/db" "github.com/grafana/grafana/pkg/services/cloudmigration" fakeSecrets "github.com/grafana/grafana/pkg/services/secrets/fakes" @@ -15,6 +20,7 @@ import ( "github.com/grafana/grafana/pkg/services/sqlstore" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "golang.org/x/crypto/nacl/box" ) func Test_GetAllCloudMigrationSessions(t *testing.T) { @@ -112,17 +118,18 @@ func Test_SnapshotManagement(t *testing.T) { require.NoError(t, err) // create a snapshot + uid := uuid.NewString() cmr := cloudmigration.CloudMigrationSnapshot{ + UID: uid, SessionUID: session.UID, Status: cloudmigration.SnapshotStatusCreating, } - snapshotUid, err := s.CreateSnapshot(ctx, cmr) + err = s.CreateSnapshot(ctx, cmr) require.NoError(t, err) - require.NotEmpty(t, snapshotUid) //retrieve it from the db - snapshot, err := s.GetSnapshotByUID(ctx, 1, session.UID, snapshotUid, cloudmigration.SnapshotResultQueryParams{ + snapshot, err := s.GetSnapshotByUID(ctx, 1, session.UID, uid, cloudmigration.SnapshotResultQueryParams{ ResultPage: 1, ResultLimit: 100, SortColumn: cloudmigration.SortColumnID, @@ -132,11 +139,11 @@ func Test_SnapshotManagement(t *testing.T) { require.Equal(t, cloudmigration.SnapshotStatusCreating, snapshot.Status) // update its status - err = s.UpdateSnapshot(ctx, cloudmigration.UpdateSnapshotCmd{UID: snapshotUid, Status: cloudmigration.SnapshotStatusCreating, SessionID: session.UID}) + err = s.UpdateSnapshot(ctx, cloudmigration.UpdateSnapshotCmd{UID: uid, Status: cloudmigration.SnapshotStatusCreating, SessionID: session.UID}) require.NoError(t, err) //retrieve it again - snapshot, err = s.GetSnapshotByUID(ctx, 1, session.UID, snapshotUid, cloudmigration.SnapshotResultQueryParams{ + snapshot, err = s.GetSnapshotByUID(ctx, 1, session.UID, uid, cloudmigration.SnapshotResultQueryParams{ ResultPage: 1, ResultLimit: 100, SortColumn: cloudmigration.SortColumnID, @@ -152,11 +159,11 @@ func Test_SnapshotManagement(t *testing.T) { require.Equal(t, *snapshot, snapshots[0]) // delete snapshot - err = s.deleteSnapshot(ctx, snapshotUid) + err = s.deleteSnapshot(ctx, uid) require.NoError(t, err) // now we expect not to find the snapshot - snapshot, err = s.GetSnapshotByUID(ctx, 1, session.UID, snapshotUid, cloudmigration.SnapshotResultQueryParams{ + snapshot, err = s.GetSnapshotByUID(ctx, 1, session.UID, uid, cloudmigration.SnapshotResultQueryParams{ ResultPage: 1, ResultLimit: 100, SortColumn: cloudmigration.SortColumnID, @@ -174,12 +181,13 @@ func Test_SnapshotManagement(t *testing.T) { require.NoError(t, err) // create a snapshot - snapshotUid, err := s.CreateSnapshot(ctx, cloudmigration.CloudMigrationSnapshot{ + uid := uuid.NewString() + err = s.CreateSnapshot(ctx, cloudmigration.CloudMigrationSnapshot{ + UID: uid, SessionUID: session.UID, Status: cloudmigration.SnapshotStatusCreating, }) require.NoError(t, err) - require.NotEmpty(t, snapshotUid) // Generate 50,001 test resources in order to test both update conditions (reached the batch limit or reached the end) const numResources = 50001 @@ -196,7 +204,7 @@ func Test_SnapshotManagement(t *testing.T) { // Update the snapshot with the resources to create err = s.UpdateSnapshot(ctx, cloudmigration.UpdateSnapshotCmd{ - UID: snapshotUid, + UID: uid, Status: cloudmigration.SnapshotStatusPendingUpload, SessionID: session.UID, LocalResourcesToCreate: resources, @@ -204,7 +212,7 @@ func Test_SnapshotManagement(t *testing.T) { require.NoError(t, err) // Get the Snapshot and ensure it's in the right state - snapshot, err := s.GetSnapshotByUID(ctx, 1, session.UID, snapshotUid, cloudmigration.SnapshotResultQueryParams{ + snapshot, err := s.GetSnapshotByUID(ctx, 1, session.UID, uid, cloudmigration.SnapshotResultQueryParams{ ResultPage: 1, ResultLimit: numResources, SortColumn: cloudmigration.SortColumnID, @@ -226,7 +234,7 @@ func Test_SnapshotManagement(t *testing.T) { // Update the snapshot with the resources to update err = s.UpdateSnapshot(ctx, cloudmigration.UpdateSnapshotCmd{ - UID: snapshotUid, + UID: uid, Status: cloudmigration.SnapshotStatusFinished, SessionID: session.UID, CloudResourcesToUpdate: snapshot.Resources, @@ -234,7 +242,7 @@ func Test_SnapshotManagement(t *testing.T) { require.NoError(t, err) // Get the Snapshot and ensure it's in the right state - snapshot, err = s.GetSnapshotByUID(ctx, 1, session.UID, snapshotUid, cloudmigration.SnapshotResultQueryParams{ + snapshot, err = s.GetSnapshotByUID(ctx, 1, session.UID, uid, cloudmigration.SnapshotResultQueryParams{ ResultPage: 1, ResultLimit: numResources, SortColumn: cloudmigration.SortColumnID, @@ -637,7 +645,7 @@ func TestGetSnapshotList(t *testing.T) { }) t.Run("return no snapshots if limit is set to 0", func(t *testing.T) { - snapshots, err := s.GetSnapshotList(ctx, cloudmigration.ListSnapshotsQuery{SessionUID: sessionUID, Page: 1, Limit: 0}) + snapshots, err := s.GetSnapshotList(ctx, cloudmigration.ListSnapshotsQuery{SessionUID: sessionUID, OrgID: 1, Page: 1, Limit: 0}) require.NoError(t, err) assert.Empty(t, snapshots) }) @@ -669,7 +677,7 @@ func TestGetSnapshotList(t *testing.T) { }) t.Run("only the snapshots that belong to a specific session are returned", func(t *testing.T) { - snapshots, err := s.GetSnapshotList(ctx, cloudmigration.ListSnapshotsQuery{SessionUID: "session-uid-that-doesnt-exist", Page: 1, Limit: 100}) + snapshots, err := s.GetSnapshotList(ctx, cloudmigration.ListSnapshotsQuery{SessionUID: "session-uid-that-doesnt-exist", OrgID: 1, Page: 1, Limit: 100}) require.NoError(t, err) assert.Empty(t, snapshots) }) @@ -680,7 +688,7 @@ func TestGetSnapshotList(t *testing.T) { require.NoError(t, err) // Fetch the snapshots that belong to the deleted session. - snapshots, err := s.GetSnapshotList(ctx, cloudmigration.ListSnapshotsQuery{SessionUID: sessionUID, Page: 1, Limit: 100}) + snapshots, err := s.GetSnapshotList(ctx, cloudmigration.ListSnapshotsQuery{SessionUID: sessionUID, OrgID: 1, Page: 1, Limit: 100}) require.NoError(t, err) // No snapshots should be returned because the session that @@ -801,3 +809,42 @@ func setUpTest(t *testing.T) (*sqlstore.SQLStore, *sqlStore) { func encodeToken(t string) string { return base64.StdEncoding.EncodeToString([]byte(t)) } + +func TestEncodeDecode(t *testing.T) { + gmsPublicKey, gmsPrivateKey, err := box.GenerateKey(cryptoRand.Reader) + require.NoError(t, err) + + grafanaPublicKey, grafanaPrivateKey, err := box.GenerateKey(cryptoRand.Reader) + require.NoError(t, err) + + snapshotWriter, err := snapshot.NewSnapshotWriter(contracts.AssymetricKeys{ + Public: gmsPublicKey[:], + Private: grafanaPrivateKey[:], + }, + crypto.NewNacl(), + "", + ) + require.NoError(t, err) + + chunk := []snapshot.MigrateDataRequestItemDTO{{ + Type: snapshot.AlertRuleGroupType, + RefID: "foo", + Name: "name", + Data: map[string]any{"a": "b"}, + }} + encoded, err := snapshotWriter.EncodePartition(chunk) + require.NoError(t, err) + + require.NoError(t, snapshotWriter.Write("RESOURCE_TYPE", chunk)) + + reader := snapshot.NewSnapshotReader(contracts.AssymetricKeys{ + Public: grafanaPublicKey[:], + Private: gmsPrivateKey[:], + }, + crypto.NewNacl()) + + partition, err := reader.ReadFile(bytes.NewReader(encoded)) + require.NoError(t, err) + + require.Equal(t, chunk, partition.Items) +} diff --git a/pkg/services/cloudmigration/gmsclient/gms_client_test.go b/pkg/services/cloudmigration/gmsclient/gms_client_test.go index d8acbd0af10..092b9223214 100644 --- a/pkg/services/cloudmigration/gmsclient/gms_client_test.go +++ b/pkg/services/cloudmigration/gmsclient/gms_client_test.go @@ -228,7 +228,7 @@ func Test_StartSnapshot(t *testing.T) { SnapshotID: "uuid", MaxItemsPerPartition: 1024, Algo: "nacl", - EncryptionKey: []uint8{0x66, 0x6f, 0x6f, 0xa}, // foo + GMSPublicKey: []uint8{0x66, 0x6f, 0x6f, 0xa}, // foo Metadata: []uint8{0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xa}, // metadata } diff --git a/pkg/services/cloudmigration/gmsclient/inmemory_client.go b/pkg/services/cloudmigration/gmsclient/inmemory_client.go index 9a176619e87..9d72f187f91 100644 --- a/pkg/services/cloudmigration/gmsclient/inmemory_client.go +++ b/pkg/services/cloudmigration/gmsclient/inmemory_client.go @@ -57,7 +57,7 @@ func (c *memoryClientImpl) StartSnapshot(_ context.Context, sess cloudmigration. c.mx.Unlock() return &cloudmigration.StartSnapshotResponse{ - EncryptionKey: publicKey[:], + GMSPublicKey: publicKey[:], SnapshotID: snapshotUid, MaxItemsPerPartition: 10, Algo: "nacl", diff --git a/pkg/services/cloudmigration/model.go b/pkg/services/cloudmigration/model.go index a01a33c62d4..d2e4a689bc7 100644 --- a/pkg/services/cloudmigration/model.go +++ b/pkg/services/cloudmigration/model.go @@ -35,17 +35,21 @@ type CloudMigrationSession struct { // CloudMigrationSnapshot contains all of the metadata about a snapshot type CloudMigrationSnapshot struct { - ID int64 `xorm:"pk autoincr 'id'"` - UID string `xorm:"uid"` - SessionUID string `xorm:"session_uid"` - Status SnapshotStatus - EncryptionKey []byte `xorm:"-"` // stored in the unified secrets table - LocalDir string `xorm:"local_directory"` - GMSSnapshotUID string `xorm:"gms_snapshot_uid"` - ErrorString string `xorm:"error_string"` - Created time.Time - Updated time.Time - Finished time.Time + ID int64 `xorm:"pk autoincr 'id'"` + UID string `xorm:"uid"` + SessionUID string `xorm:"session_uid"` + Status SnapshotStatus + GMSPublicKey []byte `xorm:"-"` // stored in the unified secrets table + PublicKey []byte `xorm:"public_key"` + LocalDir string `xorm:"local_directory"` + GMSSnapshotUID string `xorm:"gms_snapshot_uid"` + ErrorString string `xorm:"error_string"` + ResourceStorageType string `xorm:"resource_storage_type"` + EncryptionAlgo string `xorm:"encryption_algo"` + Metadata []byte `xorm:"'metadata'"` + Created time.Time + Updated time.Time + Finished time.Time // Stored in the cloud_migration_resource table Resources []CloudMigrationResource `xorm:"-"` @@ -53,6 +57,20 @@ type CloudMigrationSnapshot struct { StatsRollup SnapshotResourceStats `xorm:"-"` } +type CloudMigrationSnapshotPartition struct { + SnapshotUID string `xorm:"snapshot_uid"` + ResourceType string `xorm:"resource_type"` + PartitionNumber int `xorm:"partition_number"` + Data []byte `xorm:"data"` +} + +type CloudMigrationSnapshotIndex struct { + EncryptionAlgo string + PublicKey []byte + Metadata []byte + Items map[string][]int +} + type SnapshotStatus string const ( @@ -226,6 +244,7 @@ type UpdateSnapshotCmd struct { UID string SessionID string Status SnapshotStatus + PublicKey []byte // LocalResourcesToCreate represents the local state of a resource before it has been uploaded to GMS LocalResourcesToCreate []CloudMigrationResource @@ -293,7 +312,7 @@ type StartSnapshotResponse struct { SnapshotID string `json:"snapshotID"` MaxItemsPerPartition uint32 `json:"maxItemsPerPartition"` Algo string `json:"algo"` - EncryptionKey []byte `json:"encryptionKey"` + GMSPublicKey []byte `json:"encryptionKey"` Metadata []byte `json:"metadata"` } diff --git a/pkg/services/sqlstore/migrations/cloud_migrations.go b/pkg/services/sqlstore/migrations/cloud_migrations.go index 18dc3590570..7a602bf7d42 100644 --- a/pkg/services/sqlstore/migrations/cloud_migrations.go +++ b/pkg/services/sqlstore/migrations/cloud_migrations.go @@ -98,6 +98,15 @@ func addCloudMigrationsMigrations(mg *Migrator) { {Cols: []string{"uid"}, Type: UniqueIndex}, }, } + migrationSnapshotPartitionTable := Table{ + Name: "cloud_migration_snapshot_partition", + Columns: []*Column{ + {Name: "snapshot_uid", Type: DB_NVarchar, Length: 40, Nullable: false}, + {Name: "partition_number", Type: DB_Int, Nullable: false}, + {Name: "resource_type", Type: DB_Varchar, Length: 255, Nullable: false}, + {Name: "data", Type: DB_LongBlob, Nullable: false}, + }, + } addTableReplaceMigrations(mg, migrationTable, migrationSessionTable, 2, map[string]string{ "id": "id", @@ -187,4 +196,32 @@ func addCloudMigrationsMigrations(mg *Migrator) { mg.AddMigration("increase resource_uid column length", NewRawSQLMigration(""). Mysql("ALTER TABLE cloud_migration_resource MODIFY resource_uid NVARCHAR(255);"). Postgres("ALTER TABLE cloud_migration_resource ALTER COLUMN resource_uid TYPE VARCHAR(255);")) + + mg.AddMigration("create cloud_migration_snapshot_partition table v1", NewAddTableMigration(migrationSnapshotPartitionTable)) + mg.AddMigration("add cloud_migration_snapshot_partition srp_unique index", NewAddIndexMigration(migrationSnapshotPartitionTable, &Index{ + Name: "srp_unique", + Cols: []string{"snapshot_uid", "resource_type", "partition_number"}, Type: UniqueIndex, + })) + mg.AddMigration("add resource_storage_type column to cloud_migration_snapshot table", NewAddColumnMigration(migrationSnapshotTable, &Column{ + Name: "resource_storage_type", + Type: DB_Varchar, + Length: 255, + Nullable: true, + })) + mg.AddMigration("add encryption_algo column to cloud_migration_snapshot table", NewAddColumnMigration(migrationSnapshotTable, &Column{ + Name: "encryption_algo", + Type: DB_Varchar, + Length: 255, + Nullable: true, + })) + mg.AddMigration("add metadata column to cloud_migration_snapshot table", NewAddColumnMigration(migrationSnapshotTable, &Column{ + Name: "metadata", + Type: DB_Blob, + Nullable: true, + })) + mg.AddMigration("add public_key column to cloud_migration_snapshot table", NewAddColumnMigration(migrationSnapshotTable, &Column{ + Name: "public_key", + Type: DB_Blob, + Nullable: true, + })) } diff --git a/pkg/setting/setting_cloud_migration.go b/pkg/setting/setting_cloud_migration.go index dce1ac5fa7c..87f549ca9cd 100644 --- a/pkg/setting/setting_cloud_migration.go +++ b/pkg/setting/setting_cloud_migration.go @@ -14,11 +14,12 @@ const ( ) type CloudMigrationSettings struct { - IsTarget bool GcomAPIToken string AuthAPIUrl string SnapshotFolder string GMSDomain string + AlertRulesState string + ResourceStorageType string GMSStartSnapshotTimeout time.Duration GMSGetSnapshotStatusTimeout time.Duration GMSCreateUploadUrlTimeout time.Duration @@ -33,8 +34,8 @@ type CloudMigrationSettings struct { DeleteTokenTimeout time.Duration TokenExpiresAfter time.Duration FrontendPollInterval time.Duration - AlertRulesState string + IsTarget bool IsDeveloperMode bool } @@ -45,6 +46,8 @@ func (cfg *Cfg) readCloudMigrationSettings() { cfg.CloudMigration.AuthAPIUrl = cloudMigration.Key("auth_api_url").MustString("") cfg.CloudMigration.SnapshotFolder = cloudMigration.Key("snapshot_folder").MustString("") cfg.CloudMigration.GMSDomain = cloudMigration.Key("domain").MustString("") + cfg.CloudMigration.AlertRulesState = cloudMigration.Key("alert_rules_state").In(GMSAlertRulesPaused, []string{GMSAlertRulesPaused, GMSAlertRulesUnchanged}) + cfg.CloudMigration.ResourceStorageType = cloudMigration.Key("resource_storage_type").In("db", []string{"db", "fs"}) cfg.CloudMigration.GMSValidateKeyTimeout = cloudMigration.Key("validate_key_timeout").MustDuration(5 * time.Second) cfg.CloudMigration.GMSStartSnapshotTimeout = cloudMigration.Key("start_snapshot_timeout").MustDuration(5 * time.Second) cfg.CloudMigration.GMSGetSnapshotStatusTimeout = cloudMigration.Key("get_snapshot_status_timeout").MustDuration(5 * time.Second) @@ -60,7 +63,6 @@ func (cfg *Cfg) readCloudMigrationSettings() { cfg.CloudMigration.TokenExpiresAfter = cloudMigration.Key("token_expires_after").MustDuration(7 * 24 * time.Hour) cfg.CloudMigration.IsDeveloperMode = cloudMigration.Key("developer_mode").MustBool(false) cfg.CloudMigration.FrontendPollInterval = cloudMigration.Key("frontend_poll_interval").MustDuration(2 * time.Second) - cfg.CloudMigration.AlertRulesState = cloudMigration.Key("alert_rules_state").In(GMSAlertRulesPaused, []string{GMSAlertRulesPaused, GMSAlertRulesUnchanged}) if cfg.CloudMigration.SnapshotFolder == "" { cfg.CloudMigration.SnapshotFolder = filepath.Join(cfg.DataPath, "cloud_migration") From 5f6fc38430494e3cb642a09e32415ae62a92ad56 Mon Sep 17 00:00:00 2001 From: Victor Cinaglia Date: Fri, 25 Jul 2025 12:05:32 -0300 Subject: [PATCH 005/131] iam/authn: Introduce feature flag for authz resource mutations (#108698) * iam/authz: introduce feature flag for authz resource mutations * lint: fix typo --- .../src/types/featureToggles.gen.ts | 4 ++++ pkg/registry/apis/iam/models.go | 3 +++ pkg/registry/apis/iam/register.go | 23 ++++++++++--------- pkg/registry/apis/iam/user/store.go | 19 +++++++++++---- pkg/services/featuremgmt/registry.go | 8 +++++++ pkg/services/featuremgmt/toggles_gen.csv | 1 + pkg/services/featuremgmt/toggles_gen.go | 4 ++++ pkg/services/featuremgmt/toggles_gen.json | 17 ++++++++++++++ pkg/tests/apis/iam/iam_test.go | 1 + 9 files changed, 64 insertions(+), 16 deletions(-) diff --git a/packages/grafana-data/src/types/featureToggles.gen.ts b/packages/grafana-data/src/types/featureToggles.gen.ts index 97f2ba25bcd..31c573480ad 100644 --- a/packages/grafana-data/src/types/featureToggles.gen.ts +++ b/packages/grafana-data/src/types/featureToggles.gen.ts @@ -995,6 +995,10 @@ export interface FeatureToggles { */ kubernetesAuthzApis?: boolean; /** + * Enables create, delete, and update mutations for resources owned by IAM identity + */ + kubernetesAuthnMutation?: boolean; + /** * Enables restore deleted dashboards feature * @default false */ diff --git a/pkg/registry/apis/iam/models.go b/pkg/registry/apis/iam/models.go index 63c74d6ed0e..d4c96edf03a 100644 --- a/pkg/registry/apis/iam/models.go +++ b/pkg/registry/apis/iam/models.go @@ -44,6 +44,9 @@ type IdentityAccessManagementAPIBuilder struct { // Toggle for enabling authz management apis enableAuthZApis bool + // Toggle for enabling authn mutation + enableAuthnMutation bool + // Toggle for enabling dual writer enableDualWriter bool } diff --git a/pkg/registry/apis/iam/register.go b/pkg/registry/apis/iam/register.go index eac9f6340c3..22d15d2e518 100644 --- a/pkg/registry/apis/iam/register.go +++ b/pkg/registry/apis/iam/register.go @@ -56,16 +56,17 @@ func RegisterAPIService( authorizer := newIAMAuthorizer(accessClient, legacyAccessClient) builder := &IdentityAccessManagementAPIBuilder{ - store: store, - coreRolesStorage: coreRolesStorage, - sso: ssoService, - authorizer: authorizer, - legacyAccessClient: legacyAccessClient, - accessClient: accessClient, - display: user.NewLegacyDisplayREST(store), - reg: reg, - enableAuthZApis: features.IsEnabledGlobally(featuremgmt.FlagKubernetesAuthzApis), - enableDualWriter: true, + store: store, + coreRolesStorage: coreRolesStorage, + sso: ssoService, + authorizer: authorizer, + legacyAccessClient: legacyAccessClient, + accessClient: accessClient, + display: user.NewLegacyDisplayREST(store), + reg: reg, + enableAuthZApis: features.IsEnabledGlobally(featuremgmt.FlagKubernetesAuthzApis), + enableAuthnMutation: features.IsEnabledGlobally(featuremgmt.FlagKubernetesAuthnMutation), + enableDualWriter: true, } apiregistration.RegisterAPI(builder) @@ -127,7 +128,7 @@ func (b *IdentityAccessManagementAPIBuilder) UpdateAPIGroupInfo(apiGroupInfo *ge storage[teamBindingResource.StoragePath()] = team.NewLegacyBindingStore(b.store) userResource := legacyiamv0.UserResourceInfo - legacyStore := user.NewLegacyStore(b.store, b.legacyAccessClient) + legacyStore := user.NewLegacyStore(b.store, b.legacyAccessClient, b.enableAuthnMutation) storage[userResource.StoragePath()] = legacyStore if b.enableDualWriter { diff --git a/pkg/registry/apis/iam/user/store.go b/pkg/registry/apis/iam/user/store.go index bb4f0458486..c211ece5001 100644 --- a/pkg/registry/apis/iam/user/store.go +++ b/pkg/registry/apis/iam/user/store.go @@ -37,18 +37,19 @@ var ( var resource = iamv0.UserResourceInfo -func NewLegacyStore(store legacy.LegacyIdentityStore, ac claims.AccessClient) *LegacyStore { - return &LegacyStore{store, ac} +func NewLegacyStore(store legacy.LegacyIdentityStore, ac claims.AccessClient, enableAuthnMutation bool) *LegacyStore { + return &LegacyStore{store, ac, enableAuthnMutation} } type LegacyStore struct { - store legacy.LegacyIdentityStore - ac claims.AccessClient + store legacy.LegacyIdentityStore + ac claims.AccessClient + enableAuthnMutation bool } // Update implements rest.Updater. func (s *LegacyStore) Update(ctx context.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc, forceAllowCreate bool, options *metav1.UpdateOptions) (runtime.Object, bool, error) { - return nil, false, fmt.Errorf("method not yet implemented") + return nil, false, apierrors.NewMethodNotSupported(resource.GroupResource(), "update") } // DeleteCollection implements rest.CollectionDeleter. @@ -58,6 +59,10 @@ func (s *LegacyStore) DeleteCollection(ctx context.Context, deleteValidation res // Delete implements rest.GracefulDeleter. func (s *LegacyStore) Delete(ctx context.Context, name string, deleteValidation rest.ValidateObjectFunc, options *metav1.DeleteOptions) (runtime.Object, bool, error) { + if !s.enableAuthnMutation { + return nil, false, apierrors.NewMethodNotSupported(resource.GroupResource(), "delete") + } + ns, err := request.NamespaceInfoFrom(ctx, true) if err != nil { return nil, false, err @@ -178,6 +183,10 @@ func (s *LegacyStore) Get(ctx context.Context, name string, options *metav1.GetO // Create implements rest.Creater. func (s *LegacyStore) Create(ctx context.Context, obj runtime.Object, createValidation rest.ValidateObjectFunc, options *metav1.CreateOptions) (runtime.Object, error) { + if !s.enableAuthnMutation { + return nil, apierrors.NewMethodNotSupported(resource.GroupResource(), "create") + } + ns, err := request.NamespaceInfoFrom(ctx, true) if err != nil { return nil, err diff --git a/pkg/services/featuremgmt/registry.go b/pkg/services/featuremgmt/registry.go index 8bce171f419..dd1687c386d 100644 --- a/pkg/services/featuremgmt/registry.go +++ b/pkg/services/featuremgmt/registry.go @@ -1715,6 +1715,14 @@ var ( HideFromAdminPage: true, HideFromDocs: true, }, + { + Name: "kubernetesAuthnMutation", + Description: "Enables create, delete, and update mutations for resources owned by IAM identity", + Stage: FeatureStageExperimental, + Owner: identityAccessTeam, + HideFromAdminPage: true, + HideFromDocs: true, + }, { Name: "restoreDashboards", Description: "Enables restore deleted dashboards feature", diff --git a/pkg/services/featuremgmt/toggles_gen.csv b/pkg/services/featuremgmt/toggles_gen.csv index 778164b525b..c851a0edb47 100644 --- a/pkg/services/featuremgmt/toggles_gen.csv +++ b/pkg/services/featuremgmt/toggles_gen.csv @@ -223,6 +223,7 @@ alertingListViewV2PreviewToggle,privatePreview,@grafana/alerting-squad,false,fal alertRuleUseFiredAtForStartsAt,experimental,@grafana/alerting-squad,false,false,false alertingBulkActionsInUI,GA,@grafana/alerting-squad,false,false,true kubernetesAuthzApis,experimental,@grafana/identity-access-team,false,false,false +kubernetesAuthnMutation,experimental,@grafana/identity-access-team,false,false,false restoreDashboards,experimental,@grafana/grafana-frontend-platform,false,false,false skipTokenRotationIfRecent,GA,@grafana/identity-access-team,false,false,false alertEnrichment,experimental,@grafana/alerting-squad,false,false,false diff --git a/pkg/services/featuremgmt/toggles_gen.go b/pkg/services/featuremgmt/toggles_gen.go index 810b1e641cb..43df1d31604 100644 --- a/pkg/services/featuremgmt/toggles_gen.go +++ b/pkg/services/featuremgmt/toggles_gen.go @@ -903,6 +903,10 @@ const ( // Registers AuthZ /apis endpoint FlagKubernetesAuthzApis = "kubernetesAuthzApis" + // FlagKubernetesAuthnMutation + // Enables create, delete, and update mutations for resources owned by IAM identity + FlagKubernetesAuthnMutation = "kubernetesAuthnMutation" + // FlagRestoreDashboards // Enables restore deleted dashboards feature FlagRestoreDashboards = "restoreDashboards" diff --git a/pkg/services/featuremgmt/toggles_gen.json b/pkg/services/featuremgmt/toggles_gen.json index 18fde824fc9..3510eae27df 100644 --- a/pkg/services/featuremgmt/toggles_gen.json +++ b/pkg/services/featuremgmt/toggles_gen.json @@ -1670,6 +1670,23 @@ "requiresRestart": true } }, + { + "metadata": { + "name": "kubernetesAuthnMutation", + "resourceVersion": "1753454405614", + "creationTimestamp": "2025-07-25T14:12:51Z", + "annotations": { + "grafana.app/updatedTimestamp": "2025-07-25 14:40:05.614358 +0000 UTC" + } + }, + "spec": { + "description": "Enables create, delete, and update mutations for resources owned by IAM identity", + "stage": "experimental", + "codeowner": "@grafana/identity-access-team", + "hideFromAdminPage": true, + "hideFromDocs": true + } + }, { "metadata": { "name": "kubernetesAuthzApis", diff --git a/pkg/tests/apis/iam/iam_test.go b/pkg/tests/apis/iam/iam_test.go index 65af0d8e75f..2deaf6a94fd 100644 --- a/pkg/tests/apis/iam/iam_test.go +++ b/pkg/tests/apis/iam/iam_test.go @@ -198,6 +198,7 @@ func TestIntegrationUsers(t *testing.T) { }, EnableFeatureToggles: []string{ featuremgmt.FlagGrafanaAPIServerWithExperimentalAPIs, + featuremgmt.FlagKubernetesAuthnMutation, }, }) doUserCRUDTestsUsingTheNewAPIs(t, helper) From dcb965b7dcf1ec47d0847968fa362d2b308328f8 Mon Sep 17 00:00:00 2001 From: Santiago Date: Fri, 25 Jul 2025 17:06:59 +0200 Subject: [PATCH 006/131] Remote Alertmanager: Optionally merge remote state before starting the internal Alertmanager (#107710) * Remote Alertmanager: Use the same struct for Grafana stat and Mimir full state * Alertmanager: Add methods to merge nflog and silences * update grafana/alerting version * make update-workspace * update mocks * remove unnecesary methods from the remote Alertmanager implementation, create separate StateMerger interface * (WIP) Remote Alertmanager: Optionally merge remote state before starting the internal Alertmanager * cleanup ngalert.go * restore defaults.ini * move state parsing logic to 'remote' package, clean up ngalert.go * remove GetBase, implement MegeNflog and MergeSilences * delete fmt.Println * FetchRemoteState -> GetRemoteState * UserGrafanaState -> UserState * remove duplicate clusterpb import * reorder MimirClient interface * use general getState() method for Grafana state and Mimir full state * remove unnecessary state merging methods from the Alertmanager interface * remove pullState field * reduce diff * add info log after merging * merge silences and nflog entries in the same method * merge the remote state in the forked AM * reduce diff * update remote AM mock * tests * make error more specific * typo --- .../src/types/featureToggles.gen.ts | 5 + pkg/services/featuremgmt/registry.go | 9 + pkg/services/featuremgmt/toggles_gen.csv | 1 + pkg/services/featuremgmt/toggles_gen.go | 4 + pkg/services/featuremgmt/toggles_gen.json | 550 +++++++++--------- pkg/services/ngalert/ngalert.go | 7 +- .../remote/forked_alertmanager_test.go | 74 +++ .../ngalert/remote/mock/remoteAlertmanager.go | 58 ++ .../remote_secondary_forked_alertmanager.go | 41 +- 9 files changed, 467 insertions(+), 282 deletions(-) diff --git a/packages/grafana-data/src/types/featureToggles.gen.ts b/packages/grafana-data/src/types/featureToggles.gen.ts index 31c573480ad..c82fffa8ea5 100644 --- a/packages/grafana-data/src/types/featureToggles.gen.ts +++ b/packages/grafana-data/src/types/featureToggles.gen.ts @@ -1074,4 +1074,9 @@ export interface FeatureToggles { * Enables adhoc filtering support for the dashboard datasource */ dashboardDsAdHocFiltering?: boolean; + /** + * Starts Grafana in remote secondary mode pulling the latest state from the remote Alertmanager to avoid duplicate notifications. + * @default false + */ + alertmanagerRemoteSecondaryWithRemoteState?: boolean; } diff --git a/pkg/services/featuremgmt/registry.go b/pkg/services/featuremgmt/registry.go index dd1687c386d..b7ee60b6e55 100644 --- a/pkg/services/featuremgmt/registry.go +++ b/pkg/services/featuremgmt/registry.go @@ -1859,6 +1859,15 @@ var ( Owner: grafanaDataProSquad, FrontendOnly: true, }, + { + Name: "alertmanagerRemoteSecondaryWithRemoteState", + Description: "Starts Grafana in remote secondary mode pulling the latest state from the remote Alertmanager to avoid duplicate notifications.", + Stage: FeatureStageExperimental, + Owner: grafanaAlertingSquad, + HideFromAdminPage: true, + HideFromDocs: true, + Expression: "false", + }, } ) diff --git a/pkg/services/featuremgmt/toggles_gen.csv b/pkg/services/featuremgmt/toggles_gen.csv index c851a0edb47..d22d7e5b728 100644 --- a/pkg/services/featuremgmt/toggles_gen.csv +++ b/pkg/services/featuremgmt/toggles_gen.csv @@ -240,3 +240,4 @@ alertingNotificationHistory,experimental,@grafana/alerting-squad,false,false,fal pluginAssetProvider,experimental,@grafana/plugins-platform-backend,false,true,false unifiedStorageSearchDualReaderEnabled,experimental,@grafana/search-and-storage,false,false,false dashboardDsAdHocFiltering,experimental,@grafana/datapro,false,false,true +alertmanagerRemoteSecondaryWithRemoteState,experimental,@grafana/alerting-squad,false,false,false diff --git a/pkg/services/featuremgmt/toggles_gen.go b/pkg/services/featuremgmt/toggles_gen.go index 43df1d31604..7def9808abb 100644 --- a/pkg/services/featuremgmt/toggles_gen.go +++ b/pkg/services/featuremgmt/toggles_gen.go @@ -970,4 +970,8 @@ const ( // FlagDashboardDsAdHocFiltering // Enables adhoc filtering support for the dashboard datasource FlagDashboardDsAdHocFiltering = "dashboardDsAdHocFiltering" + + // FlagAlertmanagerRemoteSecondaryWithRemoteState + // Starts Grafana in remote secondary mode pulling the latest state from the remote Alertmanager to avoid duplicate notifications. + FlagAlertmanagerRemoteSecondaryWithRemoteState = "alertmanagerRemoteSecondaryWithRemoteState" ) diff --git a/pkg/services/featuremgmt/toggles_gen.json b/pkg/services/featuremgmt/toggles_gen.json index 3510eae27df..6d738596653 100644 --- a/pkg/services/featuremgmt/toggles_gen.json +++ b/pkg/services/featuremgmt/toggles_gen.json @@ -6,7 +6,7 @@ { "metadata": { "name": "addFieldFromCalculationStatFunctions", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2023-11-03T14:39:58Z" }, "spec": { @@ -20,7 +20,7 @@ { "metadata": { "name": "aiGeneratedDashboardChanges", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-03-05T12:01:31Z" }, "spec": { @@ -33,7 +33,7 @@ { "metadata": { "name": "alertEnrichment", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2025-06-06T12:16:07Z" }, "spec": { @@ -48,7 +48,7 @@ { "metadata": { "name": "alertRuleRestore", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2025-03-05T14:15:26Z" }, "spec": { @@ -61,7 +61,7 @@ { "metadata": { "name": "alertRuleUseFiredAtForStartsAt", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2025-04-22T11:16:38Z" }, "spec": { @@ -74,8 +74,8 @@ { "metadata": { "name": "alertingAIAnalyzeCentralStateHistory", - "resourceVersion": "1753285129398", - "creationTimestamp": "2025-07-23T15:38:49Z" + "resourceVersion": "1753448760331", + "creationTimestamp": "2025-07-25T13:06:00Z" }, "spec": { "description": "Enable AI-analyze central state history.", @@ -89,8 +89,8 @@ { "metadata": { "name": "alertingAIFeedback", - "resourceVersion": "1753285129398", - "creationTimestamp": "2025-07-23T15:38:49Z" + "resourceVersion": "1753448760331", + "creationTimestamp": "2025-07-25T13:06:00Z" }, "spec": { "description": "Enable AI-generated feedback from the Grafana UI.", @@ -104,8 +104,8 @@ { "metadata": { "name": "alertingAIGenAlertRules", - "resourceVersion": "1753285129398", - "creationTimestamp": "2025-07-23T15:38:49Z" + "resourceVersion": "1753448760331", + "creationTimestamp": "2025-07-25T13:06:00Z" }, "spec": { "description": "Enable AI-generated alert rules.", @@ -119,8 +119,8 @@ { "metadata": { "name": "alertingAIGenTemplates", - "resourceVersion": "1753285129398", - "creationTimestamp": "2025-07-23T15:38:49Z" + "resourceVersion": "1753448760331", + "creationTimestamp": "2025-07-25T13:06:00Z" }, "spec": { "description": "Enable AI-generated alerting templates.", @@ -134,8 +134,8 @@ { "metadata": { "name": "alertingAIImproveAlertRules", - "resourceVersion": "1753285129398", - "creationTimestamp": "2025-07-23T15:38:49Z" + "resourceVersion": "1753448760331", + "creationTimestamp": "2025-07-25T13:06:00Z" }, "spec": { "description": "Enable AI-improve alert rules labels and annotations.", @@ -149,7 +149,7 @@ { "metadata": { "name": "alertingBacktesting", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2022-12-14T14:44:14Z" }, "spec": { @@ -161,7 +161,7 @@ { "metadata": { "name": "alertingBulkActionsInUI", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2025-04-24T14:49:59Z" }, "spec": { @@ -177,7 +177,7 @@ { "metadata": { "name": "alertingCentralAlertHistory", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-05-29T15:01:38Z" }, "spec": { @@ -190,7 +190,7 @@ { "metadata": { "name": "alertingDisableSendAlertsExternal", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-05-23T12:29:19Z" }, "spec": { @@ -204,7 +204,7 @@ { "metadata": { "name": "alertingFilterV2", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-09-11T11:29:26Z" }, "spec": { @@ -217,7 +217,7 @@ { "metadata": { "name": "alertingImportAlertmanagerAPI", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2025-06-10T08:32:50Z" }, "spec": { @@ -232,7 +232,7 @@ { "metadata": { "name": "alertingImportYAMLUI", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2025-05-21T15:59:41Z" }, "spec": { @@ -246,7 +246,7 @@ { "metadata": { "name": "alertingJiraIntegration", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2025-02-14T12:22:04Z" }, "spec": { @@ -260,7 +260,7 @@ { "metadata": { "name": "alertingListViewV2", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-05-24T14:40:49Z" }, "spec": { @@ -273,7 +273,7 @@ { "metadata": { "name": "alertingListViewV2PreviewToggle", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2025-04-22T08:50:34Z" }, "spec": { @@ -286,7 +286,7 @@ { "metadata": { "name": "alertingMigrationUI", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2025-03-14T16:40:05Z" }, "spec": { @@ -300,8 +300,8 @@ { "metadata": { "name": "alertingNotificationHistory", - "resourceVersion": "1753285129398", - "creationTimestamp": "2025-07-23T15:38:49Z" + "resourceVersion": "1753448760331", + "creationTimestamp": "2025-07-25T13:06:00Z" }, "spec": { "description": "Enables the notification history feature", @@ -315,7 +315,7 @@ { "metadata": { "name": "alertingNotificationsStepMode", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-11-22T11:07:45Z" }, "spec": { @@ -329,7 +329,7 @@ { "metadata": { "name": "alertingPrometheusRulesPrimary", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-09-27T12:27:16Z" }, "spec": { @@ -342,8 +342,8 @@ { "metadata": { "name": "alertingProvenanceLockWrites", - "resourceVersion": "1753284360846", - "creationTimestamp": "2025-07-23T15:26:00Z" + "resourceVersion": "1753448760331", + "creationTimestamp": "2025-07-25T13:06:00Z" }, "spec": { "description": "Enables a feature to avoid issues with concurrent writes to the alerting provenance table in MySQL", @@ -356,7 +356,7 @@ { "metadata": { "name": "alertingQueryAndExpressionsStepMode", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-09-26T06:33:14Z" }, "spec": { @@ -370,7 +370,7 @@ { "metadata": { "name": "alertingQueryOptimization", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-01-10T20:52:58Z" }, "spec": { @@ -383,7 +383,7 @@ { "metadata": { "name": "alertingRulePermanentlyDelete", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2025-04-03T11:18:25Z" }, "spec": { @@ -399,7 +399,7 @@ { "metadata": { "name": "alertingRuleRecoverDeleted", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2025-03-27T14:39:26Z" }, "spec": { @@ -415,7 +415,7 @@ { "metadata": { "name": "alertingRuleVersionHistoryRestore", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2025-02-17T12:25:32Z" }, "spec": { @@ -431,7 +431,7 @@ { "metadata": { "name": "alertingSaveStateCompressed", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2025-01-27T17:47:33Z" }, "spec": { @@ -444,7 +444,7 @@ { "metadata": { "name": "alertingSaveStatePeriodic", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-01-23T16:03:30Z" }, "spec": { @@ -456,7 +456,7 @@ { "metadata": { "name": "alertingUIOptimizeReducer", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-11-18T10:59:00Z" }, "spec": { @@ -470,7 +470,7 @@ { "metadata": { "name": "alertmanagerRemotePrimary", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2023-10-30T16:27:08Z" }, "spec": { @@ -482,7 +482,7 @@ { "metadata": { "name": "alertmanagerRemoteSecondary", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2023-10-30T16:27:08Z" }, "spec": { @@ -491,10 +491,25 @@ "codeowner": "@grafana/alerting-squad" } }, + { + "metadata": { + "name": "alertmanagerRemoteSecondaryWithRemoteState", + "resourceVersion": "1753448760331", + "creationTimestamp": "2025-07-25T13:06:00Z" + }, + "spec": { + "description": "Starts Grafana in remote secondary mode pulling the latest state from the remote Alertmanager to avoid duplicate notifications.", + "stage": "experimental", + "codeowner": "@grafana/alerting-squad", + "hideFromAdminPage": true, + "hideFromDocs": true, + "expression": "false" + } + }, { "metadata": { "name": "annotationPermissionUpdate", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2023-10-31T13:30:13Z" }, "spec": { @@ -507,7 +522,7 @@ { "metadata": { "name": "appPlatformGrpcClientAuth", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-10-14T10:47:18Z" }, "spec": { @@ -521,7 +536,7 @@ { "metadata": { "name": "assetSriChecks", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2025-03-04T10:56:35Z" }, "spec": { @@ -534,7 +549,7 @@ { "metadata": { "name": "authZGRPCServer", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-06-13T09:41:35Z" }, "spec": { @@ -548,7 +563,7 @@ { "metadata": { "name": "awsAsyncQueryCaching", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2023-07-21T15:34:07Z" }, "spec": { @@ -561,7 +576,7 @@ { "metadata": { "name": "awsDatasourcesTempCredentials", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2023-07-06T15:06:11Z" }, "spec": { @@ -574,7 +589,7 @@ { "metadata": { "name": "azureMonitorDisableLogLimit", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-10-24T13:32:09Z" }, "spec": { @@ -587,7 +602,7 @@ { "metadata": { "name": "azureMonitorEnableUserAuth", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-11-27T14:01:54Z" }, "spec": { @@ -600,7 +615,7 @@ { "metadata": { "name": "azureMonitorLogsBuilderEditor", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2025-04-02T14:15:25Z" }, "spec": { @@ -613,7 +628,7 @@ { "metadata": { "name": "azureMonitorPrometheusExemplars", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-06-06T16:53:17Z" }, "spec": { @@ -626,7 +641,7 @@ { "metadata": { "name": "cachingOptimizeSerializationMemoryUsage", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2023-10-12T16:56:49Z" }, "spec": { @@ -638,7 +653,7 @@ { "metadata": { "name": "canvasPanelNesting", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2022-05-31T19:03:34Z" }, "spec": { @@ -652,7 +667,7 @@ { "metadata": { "name": "canvasPanelPanZoom", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-01-02T19:52:21Z" }, "spec": { @@ -665,7 +680,7 @@ { "metadata": { "name": "cloudRBACRoles", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-01-10T13:19:01Z" }, "spec": { @@ -681,7 +696,7 @@ { "metadata": { "name": "cloudWatchBatchQueries", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2023-10-20T19:09:41Z" }, "spec": { @@ -693,7 +708,7 @@ { "metadata": { "name": "cloudWatchCrossAccountQuerying", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2022-11-28T11:39:12Z" }, "spec": { @@ -707,7 +722,7 @@ { "metadata": { "name": "cloudWatchNewLabelParsing", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-04-05T15:57:56Z" }, "spec": { @@ -720,7 +735,7 @@ { "metadata": { "name": "cloudWatchRoundUpEndTime", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-06-27T15:10:28Z" }, "spec": { @@ -733,7 +748,7 @@ { "metadata": { "name": "configurableSchedulerTick", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2023-07-26T16:44:12Z" }, "spec": { @@ -747,7 +762,7 @@ { "metadata": { "name": "correlations", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2022-09-16T13:14:27Z" }, "spec": { @@ -761,7 +776,7 @@ { "metadata": { "name": "crashDetection", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-11-12T15:07:27Z" }, "spec": { @@ -774,7 +789,7 @@ { "metadata": { "name": "dashboardDisableSchemaValidationV1", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2025-04-11T16:52:46Z" }, "spec": { @@ -786,7 +801,7 @@ { "metadata": { "name": "dashboardDisableSchemaValidationV2", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2025-04-11T16:52:46Z" }, "spec": { @@ -798,8 +813,8 @@ { "metadata": { "name": "dashboardDsAdHocFiltering", - "resourceVersion": "1753285129398", - "creationTimestamp": "2025-07-23T15:38:49Z" + "resourceVersion": "1753448760331", + "creationTimestamp": "2025-07-25T13:06:00Z" }, "spec": { "description": "Enables adhoc filtering support for the dashboard datasource", @@ -811,7 +826,7 @@ { "metadata": { "name": "dashboardNewLayouts", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-10-23T08:55:45Z" }, "spec": { @@ -824,7 +839,7 @@ { "metadata": { "name": "dashboardScene", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2023-11-13T08:51:21Z" }, "spec": { @@ -838,7 +853,7 @@ { "metadata": { "name": "dashboardSceneForViewers", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2023-11-02T19:02:25Z" }, "spec": { @@ -852,7 +867,7 @@ { "metadata": { "name": "dashboardSceneSolo", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-02-11T08:08:47Z" }, "spec": { @@ -866,7 +881,7 @@ { "metadata": { "name": "dashboardSchemaValidationLogging", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2025-04-11T16:52:46Z" }, "spec": { @@ -878,7 +893,7 @@ { "metadata": { "name": "dashgpt", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2023-08-30T20:22:05Z" }, "spec": { @@ -892,7 +907,7 @@ { "metadata": { "name": "dataplaneAggregator", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-08-09T08:41:07Z" }, "spec": { @@ -905,7 +920,7 @@ { "metadata": { "name": "dataplaneFrontendFallback", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2023-04-07T21:13:19Z" }, "spec": { @@ -920,7 +935,7 @@ { "metadata": { "name": "datasourceAPIServers", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-09-19T08:28:27Z" }, "spec": { @@ -933,7 +948,7 @@ { "metadata": { "name": "datasourceConnectionsTab", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2025-01-21T17:39:48Z" }, "spec": { @@ -946,7 +961,7 @@ { "metadata": { "name": "datasourceQueryTypes", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-05-23T16:46:28Z" }, "spec": { @@ -959,7 +974,7 @@ { "metadata": { "name": "disableClassicHTTPHistogram", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-06-18T19:37:44Z" }, "spec": { @@ -973,7 +988,7 @@ { "metadata": { "name": "disableEnvelopeEncryption", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2022-05-24T08:34:47Z" }, "spec": { @@ -987,7 +1002,7 @@ { "metadata": { "name": "disableNumericMetricsSortingInExpressions", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-04-16T14:52:47Z" }, "spec": { @@ -1000,7 +1015,7 @@ { "metadata": { "name": "disableSSEDataplane", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2023-04-12T16:24:34Z" }, "spec": { @@ -1012,7 +1027,7 @@ { "metadata": { "name": "editPanelCSVDragAndDrop", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2023-01-24T09:43:44Z" }, "spec": { @@ -1025,7 +1040,7 @@ { "metadata": { "name": "elasticsearchCrossClusterSearch", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-12-12T22:20:04Z" }, "spec": { @@ -1037,7 +1052,7 @@ { "metadata": { "name": "elasticsearchImprovedParsing", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2025-01-15T17:05:54Z" }, "spec": { @@ -1049,8 +1064,8 @@ { "metadata": { "name": "enableAppChromeExtensions", - "resourceVersion": "1753285129398", - "creationTimestamp": "2025-07-23T15:38:49Z" + "resourceVersion": "1753448760331", + "creationTimestamp": "2025-07-25T13:06:00Z" }, "spec": { "description": "Set this to true to enable all app chrome extensions registered by plugins.", @@ -1065,7 +1080,7 @@ { "metadata": { "name": "enableDatagridEditing", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2023-04-24T14:46:31Z" }, "spec": { @@ -1078,7 +1093,7 @@ { "metadata": { "name": "enableExtensionsAdminPage", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-11-05T15:55:10Z" }, "spec": { @@ -1091,7 +1106,7 @@ { "metadata": { "name": "enableNativeHTTPHistogram", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2023-10-03T18:23:55Z" }, "spec": { @@ -1105,8 +1120,8 @@ { "metadata": { "name": "enablePluginImporter", - "resourceVersion": "1753285129398", - "creationTimestamp": "2025-07-23T15:38:49Z" + "resourceVersion": "1753448760331", + "creationTimestamp": "2025-07-25T13:06:00Z" }, "spec": { "description": "Set this to true to use the new PluginImporter functionality", @@ -1121,7 +1136,7 @@ { "metadata": { "name": "enableSCIM", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-11-07T14:38:46Z" }, "spec": { @@ -1133,7 +1148,7 @@ { "metadata": { "name": "enableScopesInMetricsExplore", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-11-06T13:11:33Z" }, "spec": { @@ -1147,7 +1162,7 @@ { "metadata": { "name": "exploreLogsAggregatedMetrics", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-08-29T13:55:59Z" }, "spec": { @@ -1160,7 +1175,7 @@ { "metadata": { "name": "exploreLogsLimitedTimeRange", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-08-29T13:55:59Z" }, "spec": { @@ -1173,7 +1188,7 @@ { "metadata": { "name": "exploreLogsShardSplitting", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-08-29T13:55:59Z" }, "spec": { @@ -1186,7 +1201,7 @@ { "metadata": { "name": "exploreMetricsRelatedLogs", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-11-05T16:28:43Z" }, "spec": { @@ -1199,7 +1214,7 @@ { "metadata": { "name": "expressionParser", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-02-17T00:59:11Z" }, "spec": { @@ -1212,7 +1227,7 @@ { "metadata": { "name": "extensionSidebar", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2025-04-03T10:16:35Z" }, "spec": { @@ -1225,7 +1240,7 @@ { "metadata": { "name": "externalServiceAccounts", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2023-09-28T07:26:37Z" }, "spec": { @@ -1238,7 +1253,7 @@ { "metadata": { "name": "extraThemes", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2023-05-10T13:37:04Z", "deletionTimestamp": "2025-05-20T08:18:08Z" }, @@ -1252,7 +1267,7 @@ { "metadata": { "name": "extractFieldsNameDeduplication", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2023-11-02T15:47:42Z" }, "spec": { @@ -1265,7 +1280,7 @@ { "metadata": { "name": "faroDatasourceSelector", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2023-05-05T00:35:10Z" }, "spec": { @@ -1278,7 +1293,7 @@ { "metadata": { "name": "featureHighlights", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2022-02-03T11:53:23Z" }, "spec": { @@ -1292,7 +1307,7 @@ { "metadata": { "name": "featureToggleAdminPage", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2023-07-18T20:43:32Z" }, "spec": { @@ -1306,7 +1321,7 @@ { "metadata": { "name": "feedbackButton", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-12-02T17:08:15Z" }, "spec": { @@ -1319,7 +1334,7 @@ { "metadata": { "name": "fetchRulesUsingPost", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2025-01-29T12:17:44Z" }, "spec": { @@ -1333,8 +1348,8 @@ { "metadata": { "name": "foldersAppPlatformAPI", - "resourceVersion": "1753285129398", - "creationTimestamp": "2025-07-23T15:38:49Z" + "resourceVersion": "1753448760331", + "creationTimestamp": "2025-07-25T13:06:00Z" }, "spec": { "description": "Enables use of app platform API for folders", @@ -1349,7 +1364,7 @@ { "metadata": { "name": "formatString", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2023-10-13T18:17:12Z" }, "spec": { @@ -1363,7 +1378,7 @@ { "metadata": { "name": "grafanaAPIServerEnsureKubectlAccess", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2023-12-06T20:21:21Z" }, "spec": { @@ -1377,7 +1392,7 @@ { "metadata": { "name": "grafanaAPIServerWithExperimentalAPIs", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2023-10-06T18:55:22Z" }, "spec": { @@ -1391,7 +1406,7 @@ { "metadata": { "name": "grafanaAdvisor", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2025-01-20T10:08:00Z" }, "spec": { @@ -1403,7 +1418,7 @@ { "metadata": { "name": "grafanaManagedRecordingRules", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-04-22T17:53:16Z", "deletionTimestamp": "2025-05-19T10:15:49Z" }, @@ -1418,7 +1433,7 @@ { "metadata": { "name": "grafanaconThemes", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2025-02-06T11:08:04Z" }, "spec": { @@ -1434,7 +1449,7 @@ { "metadata": { "name": "groupAttributeSync", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-09-09T15:29:43Z" }, "spec": { @@ -1447,7 +1462,7 @@ { "metadata": { "name": "groupByVariable", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-02-14T17:18:04Z" }, "spec": { @@ -1461,7 +1476,7 @@ { "metadata": { "name": "groupToNestedTableTransformation", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-02-07T14:28:26Z" }, "spec": { @@ -1475,7 +1490,7 @@ { "metadata": { "name": "grpcServer", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2022-09-26T20:25:34Z" }, "spec": { @@ -1488,7 +1503,7 @@ { "metadata": { "name": "improvedExternalSessionHandling", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-09-17T10:54:39Z" }, "spec": { @@ -1502,7 +1517,7 @@ { "metadata": { "name": "improvedExternalSessionHandlingSAML", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2025-01-09T17:02:49Z" }, "spec": { @@ -1516,7 +1531,7 @@ { "metadata": { "name": "individualCookiePreferences", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2023-02-21T10:19:07Z" }, "spec": { @@ -1528,7 +1543,7 @@ { "metadata": { "name": "infinityRunQueriesInParallel", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2025-03-14T12:54:04Z" }, "spec": { @@ -1540,7 +1555,7 @@ { "metadata": { "name": "influxdbBackendMigration", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2022-02-09T18:26:16Z", "deletionTimestamp": "2023-01-17T14:11:26Z" }, @@ -1555,7 +1570,7 @@ { "metadata": { "name": "influxdbRunQueriesInParallel", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-02-01T10:58:24Z" }, "spec": { @@ -1567,7 +1582,7 @@ { "metadata": { "name": "influxqlStreamingParser", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2023-11-29T17:29:35Z" }, "spec": { @@ -1579,7 +1594,7 @@ { "metadata": { "name": "investigationsBackend", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-12-18T08:31:03Z" }, "spec": { @@ -1592,7 +1607,7 @@ { "metadata": { "name": "inviteUserExperimental", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2025-03-07T19:09:59Z" }, "spec": { @@ -1607,7 +1622,7 @@ { "metadata": { "name": "jitterAlertRulesWithinGroups", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-01-18T18:48:11Z" }, "spec": { @@ -1621,7 +1636,7 @@ { "metadata": { "name": "k8SFolderCounts", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-12-27T17:10:44Z" }, "spec": { @@ -1634,7 +1649,7 @@ { "metadata": { "name": "k8SFolderMove", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-12-27T17:10:44Z" }, "spec": { @@ -1647,7 +1662,7 @@ { "metadata": { "name": "kubernetesAggregator", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-02-12T20:59:35Z" }, "spec": { @@ -1660,7 +1675,7 @@ { "metadata": { "name": "kubernetesAggregatorCapTokenAuth", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2025-05-15T18:14:23Z" }, "spec": { @@ -1690,7 +1705,7 @@ { "metadata": { "name": "kubernetesAuthzApis", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2025-06-18T07:43:01Z" }, "spec": { @@ -1704,7 +1719,7 @@ { "metadata": { "name": "kubernetesClientDashboardsFolders", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2025-02-18T23:11:26Z" }, "spec": { @@ -1717,7 +1732,7 @@ { "metadata": { "name": "kubernetesDashboards", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-06-05T14:34:23Z" }, "spec": { @@ -1730,7 +1745,7 @@ { "metadata": { "name": "kubernetesFeatureToggles", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-01-18T05:32:44Z" }, "spec": { @@ -1744,8 +1759,8 @@ { "metadata": { "name": "kubernetesLibraryPanelConnections", - "resourceVersion": "1753285129398", - "creationTimestamp": "2025-07-23T15:38:49Z" + "resourceVersion": "1753448760331", + "creationTimestamp": "2025-07-25T13:06:00Z" }, "spec": { "description": "Routes library panel connections requests from /api to using search", @@ -1757,7 +1772,7 @@ { "metadata": { "name": "kubernetesLibraryPanels", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2025-06-25T22:21:56Z" }, "spec": { @@ -1770,7 +1785,7 @@ { "metadata": { "name": "kubernetesSnapshots", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2023-12-05T22:31:49Z" }, "spec": { @@ -1783,7 +1798,7 @@ { "metadata": { "name": "localeFormatPreference", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2025-03-31T13:59:07Z" }, "spec": { @@ -1795,7 +1810,7 @@ { "metadata": { "name": "localizationForPlugins", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2025-03-31T04:38:38Z" }, "spec": { @@ -1807,7 +1822,7 @@ { "metadata": { "name": "logQLScope", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-11-11T11:53:24Z" }, "spec": { @@ -1822,7 +1837,7 @@ { "metadata": { "name": "logRequestsInstrumentedAsUnknown", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2022-06-10T08:56:55Z" }, "spec": { @@ -1834,7 +1849,7 @@ { "metadata": { "name": "logRowsPopoverMenu", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2023-11-16T09:48:10Z" }, "spec": { @@ -1848,7 +1863,7 @@ { "metadata": { "name": "logsContextDatasourceUi", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2023-01-27T14:12:01Z" }, "spec": { @@ -1863,7 +1878,7 @@ { "metadata": { "name": "logsExploreTableDefaultVisualization", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-05-02T15:28:15Z" }, "spec": { @@ -1876,7 +1891,7 @@ { "metadata": { "name": "logsExploreTableVisualisation", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2023-07-12T13:52:42Z" }, "spec": { @@ -1890,7 +1905,7 @@ { "metadata": { "name": "logsInfiniteScrolling", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2023-11-09T10:54:03Z" }, "spec": { @@ -1904,7 +1919,7 @@ { "metadata": { "name": "logsPanelControls", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2025-04-07T14:38:55Z" }, "spec": { @@ -1918,7 +1933,7 @@ { "metadata": { "name": "lokiExperimentalStreaming", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2023-06-19T10:03:51Z" }, "spec": { @@ -1930,7 +1945,7 @@ { "metadata": { "name": "lokiLabelNamesQueryApi", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-12-13T14:31:41Z" }, "spec": { @@ -1943,7 +1958,7 @@ { "metadata": { "name": "lokiLogsDataplane", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2023-07-13T07:58:00Z" }, "spec": { @@ -1955,7 +1970,7 @@ { "metadata": { "name": "lokiQuerySplitting", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2023-02-09T17:27:02Z" }, "spec": { @@ -1970,7 +1985,7 @@ { "metadata": { "name": "lokiRunQueriesInParallel", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2023-09-19T09:34:01Z" }, "spec": { @@ -1982,7 +1997,7 @@ { "metadata": { "name": "lokiShardSplitting", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-10-23T11:21:03Z" }, "spec": { @@ -1995,7 +2010,7 @@ { "metadata": { "name": "managedDualWriter", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2025-02-19T14:50:39Z" }, "spec": { @@ -2009,7 +2024,7 @@ { "metadata": { "name": "metricsFromProfiles", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2025-04-09T10:55:28Z" }, "spec": { @@ -2022,7 +2037,7 @@ { "metadata": { "name": "mlExpressions", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2023-07-13T17:37:50Z" }, "spec": { @@ -2034,7 +2049,7 @@ { "metadata": { "name": "multiTenantFrontend", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2025-04-25T09:24:25Z" }, "spec": { @@ -2046,7 +2061,7 @@ { "metadata": { "name": "multiTenantTempCredentials", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2025-04-02T20:25:50Z" }, "spec": { @@ -2059,7 +2074,7 @@ { "metadata": { "name": "mysqlAnsiQuotes", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2022-10-12T11:43:35Z" }, "spec": { @@ -2071,7 +2086,7 @@ { "metadata": { "name": "nestedFolders", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2022-10-26T14:15:14Z" }, "spec": { @@ -2084,7 +2099,7 @@ { "metadata": { "name": "newDashboardSharingComponent", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-05-03T15:02:18Z" }, "spec": { @@ -2098,7 +2113,7 @@ { "metadata": { "name": "newDashboardWithFiltersAndGroupBy", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-04-04T11:25:21Z" }, "spec": { @@ -2112,7 +2127,7 @@ { "metadata": { "name": "newFiltersUI", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-08-30T12:48:13Z" }, "spec": { @@ -2125,7 +2140,7 @@ { "metadata": { "name": "newInfluxDSConfigPageDesign", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2025-06-25T16:39:54Z" }, "spec": { @@ -2138,7 +2153,7 @@ { "metadata": { "name": "newLogsPanel", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2025-02-04T17:40:17Z" }, "spec": { @@ -2151,7 +2166,7 @@ { "metadata": { "name": "newPDFRendering", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-02-08T12:09:34Z" }, "spec": { @@ -2164,7 +2179,7 @@ { "metadata": { "name": "newShareReportDrawer", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2025-02-17T19:05:46Z" }, "spec": { @@ -2178,7 +2193,7 @@ { "metadata": { "name": "oauthRequireSubClaim", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-03-25T13:22:24Z" }, "spec": { @@ -2192,7 +2207,7 @@ { "metadata": { "name": "onPremToCloudMigrations", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-01-22T16:09:08Z" }, "spec": { @@ -2205,8 +2220,8 @@ { "metadata": { "name": "otelLogsFormatting", - "resourceVersion": "1753285129398", - "creationTimestamp": "2025-07-23T15:38:49Z" + "resourceVersion": "1753448760331", + "creationTimestamp": "2025-07-25T13:06:00Z" }, "spec": { "description": "Applies OTel formatting templates to displayed logs", @@ -2218,7 +2233,7 @@ { "metadata": { "name": "panelFilterVariable", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2023-11-03T12:15:54Z" }, "spec": { @@ -2232,7 +2247,7 @@ { "metadata": { "name": "panelMonitoring", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2023-10-09T05:19:08Z" }, "spec": { @@ -2246,7 +2261,7 @@ { "metadata": { "name": "panelTitleSearch", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2022-02-15T18:26:03Z" }, "spec": { @@ -2259,7 +2274,7 @@ { "metadata": { "name": "passwordlessMagicLinkAuthentication", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-11-14T13:50:55Z" }, "spec": { @@ -2273,7 +2288,7 @@ { "metadata": { "name": "pdfTables", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2023-11-06T13:39:22Z" }, "spec": { @@ -2285,7 +2300,7 @@ { "metadata": { "name": "permissionsFilterRemoveSubquery", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2023-08-02T07:39:25Z" }, "spec": { @@ -2297,7 +2312,7 @@ { "metadata": { "name": "pinNavItems", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-06-10T11:40:03Z" }, "spec": { @@ -2310,7 +2325,7 @@ { "metadata": { "name": "playlistsReconciler", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-12-20T03:09:31Z" }, "spec": { @@ -2323,8 +2338,8 @@ { "metadata": { "name": "pluginAssetProvider", - "resourceVersion": "1753285129398", - "creationTimestamp": "2025-07-23T15:38:49Z" + "resourceVersion": "1753448760331", + "creationTimestamp": "2025-07-25T13:06:00Z" }, "spec": { "description": "Allows decoupled core plugins to load from the Grafana CDN", @@ -2339,7 +2354,7 @@ { "metadata": { "name": "pluginProxyPreserveTrailingSlash", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-06-05T11:36:14Z" }, "spec": { @@ -2352,7 +2367,7 @@ { "metadata": { "name": "pluginsAutoUpdate", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2025-04-16T11:44:39Z" }, "spec": { @@ -2361,25 +2376,10 @@ "codeowner": "@grafana/plugins-platform-backend" } }, - { - "metadata": { - "name": "pluginsDetailsRightPanel", - "resourceVersion": "1753285129398", - "creationTimestamp": "2024-08-13T09:55:30Z", - "deletionTimestamp": "2025-07-25T08:56:36Z" - }, - "spec": { - "description": "Enables right panel for the plugins details page", - "stage": "GA", - "codeowner": "@grafana/plugins-platform-backend", - "frontend": true, - "expression": "true" - } - }, { "metadata": { "name": "pluginsFrontendSandbox", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2023-06-05T08:51:36Z" }, "spec": { @@ -2391,7 +2391,7 @@ { "metadata": { "name": "pluginsSkipHostEnvVars", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2023-11-15T17:09:14Z" }, "spec": { @@ -2403,7 +2403,7 @@ { "metadata": { "name": "pluginsSriChecks", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-10-04T12:55:09Z" }, "spec": { @@ -2416,7 +2416,7 @@ { "metadata": { "name": "preferLibraryPanelTitle", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2025-06-17T11:21:21Z" }, "spec": { @@ -2429,7 +2429,7 @@ { "metadata": { "name": "preinstallAutoUpdate", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-11-07T12:14:25Z" }, "spec": { @@ -2442,7 +2442,7 @@ { "metadata": { "name": "preserveDashboardStateWhenNavigating", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-05-27T12:28:06Z" }, "spec": { @@ -2456,7 +2456,7 @@ { "metadata": { "name": "promQLScope", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-01-29T20:22:17Z" }, "spec": { @@ -2471,7 +2471,7 @@ { "metadata": { "name": "prometheusAzureOverrideAudience", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2022-05-30T15:43:32Z", "deletionTimestamp": "2023-07-16T21:30:14Z" }, @@ -2485,7 +2485,7 @@ { "metadata": { "name": "prometheusCodeModeMetricNamesSearch", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-04-04T20:38:23Z" }, "spec": { @@ -2498,7 +2498,7 @@ { "metadata": { "name": "prometheusSpecialCharsInLabelValues", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-12-18T21:31:08Z" }, "spec": { @@ -2511,7 +2511,7 @@ { "metadata": { "name": "provisioning", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-11-22T09:03:50Z" }, "spec": { @@ -2524,8 +2524,8 @@ { "metadata": { "name": "provisioningSecretsService", - "resourceVersion": "1753285129398", - "creationTimestamp": "2025-07-23T15:38:49Z" + "resourceVersion": "1753448760331", + "creationTimestamp": "2025-07-25T13:06:00Z" }, "spec": { "description": "Experimental feature to use the secrets service for provisioning instead of the legacy secrets", @@ -2537,7 +2537,7 @@ { "metadata": { "name": "publicDashboardsEmailSharing", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2023-01-03T19:45:15Z" }, "spec": { @@ -2551,7 +2551,7 @@ { "metadata": { "name": "publicDashboardsScene", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-03-22T14:48:21Z" }, "spec": { @@ -2565,7 +2565,7 @@ { "metadata": { "name": "queryLibrary", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2022-10-07T18:31:45Z", "deletionTimestamp": "2023-03-20T16:00:14Z" }, @@ -2578,7 +2578,7 @@ { "metadata": { "name": "queryService", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-04-19T09:26:21Z" }, "spec": { @@ -2591,7 +2591,7 @@ { "metadata": { "name": "queryServiceFromExplore", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2025-04-02T10:00:33Z" }, "spec": { @@ -2604,7 +2604,7 @@ { "metadata": { "name": "queryServiceFromUI", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-04-19T09:26:21Z" }, "spec": { @@ -2617,7 +2617,7 @@ { "metadata": { "name": "queryServiceRewrite", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-04-19T09:26:21Z" }, "spec": { @@ -2630,7 +2630,7 @@ { "metadata": { "name": "recordedQueriesMulti", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2023-06-14T12:34:22Z" }, "spec": { @@ -2643,7 +2643,7 @@ { "metadata": { "name": "refactorVariablesTimeRange", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2023-06-06T13:12:09Z" }, "spec": { @@ -2656,7 +2656,7 @@ { "metadata": { "name": "regressionTransformation", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2023-11-24T14:49:16Z" }, "spec": { @@ -2669,7 +2669,7 @@ { "metadata": { "name": "reloadDashboardsOnParamsChange", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-10-25T12:56:54Z" }, "spec": { @@ -2683,7 +2683,7 @@ { "metadata": { "name": "renderAuthJWT", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2023-04-03T16:53:38Z" }, "spec": { @@ -2696,7 +2696,7 @@ { "metadata": { "name": "rendererDisableAppPluginsPreload", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2025-02-24T14:43:06Z" }, "spec": { @@ -2711,7 +2711,7 @@ { "metadata": { "name": "reportingRetries", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2023-08-31T07:47:47Z" }, "spec": { @@ -2724,7 +2724,7 @@ { "metadata": { "name": "restoreDashboards", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2025-05-23T14:35:54Z" }, "spec": { @@ -2738,7 +2738,7 @@ { "metadata": { "name": "rolePickerDrawer", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-09-26T12:51:38Z" }, "spec": { @@ -2750,7 +2750,7 @@ { "metadata": { "name": "scopeApi", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-11-27T07:58:25Z" }, "spec": { @@ -2764,7 +2764,7 @@ { "metadata": { "name": "scopeFilters", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-03-05T15:41:19Z" }, "spec": { @@ -2778,7 +2778,7 @@ { "metadata": { "name": "scopeSearchAllLevels", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2025-04-14T07:42:16Z" }, "spec": { @@ -2792,7 +2792,7 @@ { "metadata": { "name": "secretsManagementAppPlatform", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2025-03-19T09:25:14Z" }, "spec": { @@ -2804,8 +2804,8 @@ { "metadata": { "name": "sharingDashboardImage", - "resourceVersion": "1753285129398", - "creationTimestamp": "2025-07-23T15:38:49Z" + "resourceVersion": "1753448760331", + "creationTimestamp": "2025-07-25T13:06:00Z" }, "spec": { "description": "Enables image sharing functionality for dashboards", @@ -2818,7 +2818,7 @@ { "metadata": { "name": "showDashboardValidationWarnings", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2022-10-14T13:51:05Z" }, "spec": { @@ -2830,7 +2830,7 @@ { "metadata": { "name": "skipTokenRotationIfRecent", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2025-06-03T06:59:40Z" }, "spec": { @@ -2845,7 +2845,7 @@ { "metadata": { "name": "sqlDatasourceDatabaseSelection", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2023-06-06T16:28:52Z" }, "spec": { @@ -2859,7 +2859,7 @@ { "metadata": { "name": "sqlExpressions", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-02-27T21:16:00Z" }, "spec": { @@ -2871,8 +2871,8 @@ { "metadata": { "name": "sqlExpressionsColumnAutoComplete", - "resourceVersion": "1751471729972", - "creationTimestamp": "2025-07-02T15:55:29Z" + "resourceVersion": "1753448760331", + "creationTimestamp": "2025-07-25T13:06:00Z" }, "spec": { "description": "Enables column autocomplete for SQL Expressions", @@ -2884,7 +2884,7 @@ { "metadata": { "name": "sseGroupByDatasource", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2023-09-07T20:02:07Z" }, "spec": { @@ -2896,7 +2896,7 @@ { "metadata": { "name": "ssoSettingsLDAP", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-06-18T11:31:27Z" }, "spec": { @@ -2911,7 +2911,7 @@ { "metadata": { "name": "storage", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2022-03-17T17:19:23Z" }, "spec": { @@ -2923,7 +2923,7 @@ { "metadata": { "name": "tableNextGen", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2025-03-26T03:57:57Z" }, "spec": { @@ -2936,7 +2936,7 @@ { "metadata": { "name": "tableSharedCrosshair", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2023-12-13T09:33:14Z" }, "spec": { @@ -2949,7 +2949,7 @@ { "metadata": { "name": "tabularNumbers", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2025-06-24T11:52:03Z" }, "spec": { @@ -2962,7 +2962,7 @@ { "metadata": { "name": "teamHttpHeadersMimir", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2025-01-13T10:42:47Z" }, "spec": { @@ -2976,7 +2976,7 @@ { "metadata": { "name": "teamHttpHeadersTempo", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2025-05-22T19:13:31Z" }, "spec": { @@ -2988,7 +2988,7 @@ { "metadata": { "name": "templateVariablesUsesCombobox", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2025-01-31T09:53:13Z" }, "spec": { @@ -3001,8 +3001,8 @@ { "metadata": { "name": "tempoAlerting", - "resourceVersion": "1753285129398", - "creationTimestamp": "2025-07-23T15:38:49Z" + "resourceVersion": "1753448760331", + "creationTimestamp": "2025-07-25T13:06:00Z" }, "spec": { "description": "Enables creating alerts from Tempo data source", @@ -3014,8 +3014,8 @@ { "metadata": { "name": "timeComparison", - "resourceVersion": "1753285129398", - "creationTimestamp": "2025-07-23T15:38:49Z" + "resourceVersion": "1753448760331", + "creationTimestamp": "2025-07-25T13:06:00Z" }, "spec": { "description": "Enables time comparison option in supported panels", @@ -3027,7 +3027,7 @@ { "metadata": { "name": "timeRangeProvider", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-10-22T10:52:33Z" }, "spec": { @@ -3039,7 +3039,7 @@ { "metadata": { "name": "tlsMemcached", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-05-09T19:12:08Z" }, "spec": { @@ -3052,7 +3052,7 @@ { "metadata": { "name": "transformationsRedesign", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2023-07-12T16:35:49Z" }, "spec": { @@ -3067,7 +3067,7 @@ { "metadata": { "name": "unifiedHistory", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-12-13T10:41:18Z" }, "spec": { @@ -3080,7 +3080,7 @@ { "metadata": { "name": "unifiedNavbars", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2025-04-09T12:51:22Z" }, "spec": { @@ -3094,7 +3094,7 @@ { "metadata": { "name": "unifiedRequestLog", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2023-03-31T13:38:09Z" }, "spec": { @@ -3108,7 +3108,7 @@ { "metadata": { "name": "unifiedStorageBigObjectsSupport", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-10-17T10:18:29Z" }, "spec": { @@ -3120,7 +3120,7 @@ { "metadata": { "name": "unifiedStorageGrpcConnectionPool", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2025-03-21T13:24:54Z" }, "spec": { @@ -3134,7 +3134,7 @@ { "metadata": { "name": "unifiedStorageHistoryPruner", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2025-03-17T10:36:38Z" }, "spec": { @@ -3149,7 +3149,7 @@ { "metadata": { "name": "unifiedStorageSearch", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-09-30T19:46:14Z" }, "spec": { @@ -3163,8 +3163,8 @@ { "metadata": { "name": "unifiedStorageSearchDualReaderEnabled", - "resourceVersion": "1753285129398", - "creationTimestamp": "2025-07-23T15:38:49Z" + "resourceVersion": "1753448760331", + "creationTimestamp": "2025-07-25T13:06:00Z" }, "spec": { "description": "Enable dual reader for unified storage search", @@ -3177,7 +3177,7 @@ { "metadata": { "name": "unifiedStorageSearchPermissionFiltering", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2025-01-22T11:38:37Z" }, "spec": { @@ -3192,7 +3192,7 @@ { "metadata": { "name": "unifiedStorageSearchSprinkles", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-12-18T17:00:54Z" }, "spec": { @@ -3206,7 +3206,7 @@ { "metadata": { "name": "unifiedStorageSearchUI", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-12-19T18:21:48Z" }, "spec": { @@ -3220,7 +3220,7 @@ { "metadata": { "name": "useScopesNavigationEndpoint", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2025-03-31T15:20:00Z" }, "spec": { @@ -3235,7 +3235,7 @@ { "metadata": { "name": "useSessionStorageForRedirection", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-09-23T09:31:23Z" }, "spec": { @@ -3248,7 +3248,7 @@ { "metadata": { "name": "zanzana", - "resourceVersion": "1753285129398", + "resourceVersion": "1753448760331", "creationTimestamp": "2024-06-19T13:59:47Z" }, "spec": { diff --git a/pkg/services/ngalert/ngalert.go b/pkg/services/ngalert/ngalert.go index 0c2a0274867..c4f3d19ba24 100644 --- a/pkg/services/ngalert/ngalert.go +++ b/pkg/services/ngalert/ngalert.go @@ -193,7 +193,8 @@ func (ng *AlertNG) init() error { crypto := notifier.NewCrypto(ng.SecretsService, ng.store, moaLogger) remotePrimary := ng.FeatureToggles.IsEnabled(initCtx, featuremgmt.FlagAlertmanagerRemotePrimary) remoteSecondary := ng.FeatureToggles.IsEnabled(initCtx, featuremgmt.FlagAlertmanagerRemoteSecondary) - if remotePrimary || remoteSecondary { + remoteSecondaryWithRemoteState := ng.FeatureToggles.IsEnabled(initCtx, featuremgmt.FlagAlertmanagerRemoteSecondaryWithRemoteState) + if remotePrimary || remoteSecondary || remoteSecondaryWithRemoteState { m := ng.Metrics.GetRemoteAlertmanagerMetrics() smtpCfg := remoteClient.SmtpConfig{ FromAddress: ng.Cfg.Smtp.FromAddress, @@ -268,6 +269,10 @@ func (ng *AlertNG) init() error { cfg.OrgID = orgID remoteAM, err := createRemoteAlertmanager(ctx, cfg, ng.KVStore, crypto, autogenFn, m, ng.tracer) if err != nil { + if remoteSecondaryWithRemoteState { + // We can't start the internal Alertmanager without the remote state. + return nil, fmt.Errorf("failed to create remote Alertmanager, can't start the internal Alertmanager without the remote state: %w", err) + } moaLogger.Error("Failed to create remote Alertmanager, falling back to using only the internal one", "err", err) return internalAM, nil } diff --git a/pkg/services/ngalert/remote/forked_alertmanager_test.go b/pkg/services/ngalert/remote/forked_alertmanager_test.go index 565de4320f4..af8769a2e88 100644 --- a/pkg/services/ngalert/remote/forked_alertmanager_test.go +++ b/pkg/services/ngalert/remote/forked_alertmanager_test.go @@ -84,6 +84,75 @@ func TestForkedAlertmanager_ModeRemoteSecondary(t *testing.T) { } }) + t.Run("ApplyConfig - with remote state", func(tt *testing.T) { + { + // During the first ApplyConfig call, we should: + // 1. Apply the configuration to the remote Alertmanager + // 2. Merge the remote state + // 3. Apply the configuration to the internal Alertmanager + internal, remote, forked := genTestAlertmanagers(tt, modeRemoteSecondary, withRemoteState) + readyCall := remote.EXPECT().Ready().Return(false).Once() + remote.EXPECT().ApplyConfig(ctx, mock.Anything).Return(nil).Once().NotBefore(readyCall) + remote.EXPECT().Ready().Return(true).Once() + remoteStateCall := remote.EXPECT().GetRemoteState(mock.Anything).Return(notifier.ExternalState{}, nil).Once() + internal.EXPECT().ApplyConfig(ctx, mock.Anything).Return(nil).Once().NotBefore(remoteStateCall) + require.NoError(tt, forked.ApplyConfig(ctx, &models.AlertConfiguration{})) + require.True(tt, internal.mergeStateCalled) + + // We shouldn't attempt to merge the remote state again on the next sync loop iteration. + internal.mergeStateCalled = false + remote.EXPECT().Ready().Return(true).Once() + internal.EXPECT().ApplyConfig(ctx, mock.Anything).Return(nil).Once() + remote.EXPECT().CompareAndSendConfiguration(ctx, mock.Anything).Return(nil).Once() + require.NoError(tt, forked.ApplyConfig(ctx, &models.AlertConfiguration{})) + require.False(tt, internal.mergeStateCalled) + } + + { + // If we fail to apply the configuration in the remote Alertmanager, we should get an error and not start the internal Alertmanager. + internal, remote, forked := genTestAlertmanagers(tt, modeRemoteSecondary, withSyncInterval(10*time.Minute), withRemoteState) + readyCall := remote.EXPECT().Ready().Return(false).Once() + remote.EXPECT().ApplyConfig(ctx, mock.Anything).Return(expErr).Once().NotBefore(readyCall) + remote.EXPECT().Ready().Return(false).Once() + err := forked.ApplyConfig(ctx, &models.AlertConfiguration{}) + require.Equal(tt, "remote Alertmanager not ready, can't fetch remote state", err.Error()) + require.False(tt, internal.mergeStateCalled) + + // Calling ApplyConfig again should result in the forked Alertmanager calling ApplyConfig on both + // Alertmanagers and merging the remote state, even if the sync interval has not elapsed. + remote.EXPECT().Ready().Return(true).Twice() + remote.EXPECT().CompareAndSendConfiguration(ctx, mock.Anything).Return(nil).Once() + remoteStateCall := remote.EXPECT().GetRemoteState(mock.Anything).Return(notifier.ExternalState{}, nil).Once() + internal.EXPECT().ApplyConfig(ctx, mock.Anything).Return(nil).Once().NotBefore(remoteStateCall) + require.NoError(tt, forked.ApplyConfig(ctx, &models.AlertConfiguration{})) + require.True(tt, internal.mergeStateCalled) + } + + { + // An error in the remote Alertmanager should be returned. + // The internal Alertmanager shouldn't be started. + internal, remote, forked := genTestAlertmanagers(tt, modeRemotePrimary) + remote.EXPECT().ApplyConfig(ctx, mock.Anything).Return(expErr).Once() + require.ErrorIs(tt, forked.ApplyConfig(ctx, &models.AlertConfiguration{}), expErr) + require.False(t, internal.mergeStateCalled) + } + + { + // An error in the internal Alertmanager should be returned. + internal, remote, forked := genTestAlertmanagers(tt, modeRemoteSecondary, withRemoteState) + internal.EXPECT().ApplyConfig(ctx, mock.Anything).Return(expErr).Once() + + // Simulate starting the remote Alertmanager and merging the remote state. + readyCall := remote.EXPECT().Ready().Return(false).Once() + remote.EXPECT().ApplyConfig(ctx, mock.Anything).Return(nil).Once().NotBefore(readyCall) + remote.EXPECT().Ready().Return(true).Once() + remote.EXPECT().GetRemoteState(mock.Anything).Return(notifier.ExternalState{}, nil).Once() + + require.ErrorIs(tt, forked.ApplyConfig(ctx, &models.AlertConfiguration{}), expErr) + require.True(t, internal.mergeStateCalled) + } + }) + t.Run("SaveAndApplyConfig", func(tt *testing.T) { // SaveAndApplyConfig should only be called on the remote Alertmanager. // State and configuration are updated on an interval. @@ -707,6 +776,11 @@ func (m *internalAlertmanagerMock) MergeState(notifier.ExternalState) error { return nil } +func withRemoteState(rsc RemoteSecondaryConfig) RemoteSecondaryConfig { + rsc.WithRemoteState = true + return rsc +} + func withSyncInterval(syncInterval time.Duration) func(RemoteSecondaryConfig) RemoteSecondaryConfig { return func(rsc RemoteSecondaryConfig) RemoteSecondaryConfig { rsc.SyncInterval = syncInterval diff --git a/pkg/services/ngalert/remote/mock/remoteAlertmanager.go b/pkg/services/ngalert/remote/mock/remoteAlertmanager.go index 33a77c10f1c..1199b65ae9c 100644 --- a/pkg/services/ngalert/remote/mock/remoteAlertmanager.go +++ b/pkg/services/ngalert/remote/mock/remoteAlertmanager.go @@ -13,6 +13,8 @@ import ( models "github.com/grafana/grafana/pkg/services/ngalert/models" + notifier "github.com/grafana/grafana/pkg/services/ngalert/notifier" + notify "github.com/grafana/alerting/notify" v2models "github.com/prometheus/alertmanager/api/v2/models" @@ -413,6 +415,62 @@ func (_c *RemoteAlertmanagerMock_GetReceivers_Call) RunAndReturn(run func(contex return _c } +// GetRemoteState provides a mock function with given fields: _a0 +func (_m *RemoteAlertmanagerMock) GetRemoteState(_a0 context.Context) (notifier.ExternalState, error) { + ret := _m.Called(_a0) + + if len(ret) == 0 { + panic("no return value specified for GetRemoteState") + } + + var r0 notifier.ExternalState + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) (notifier.ExternalState, error)); ok { + return rf(_a0) + } + if rf, ok := ret.Get(0).(func(context.Context) notifier.ExternalState); ok { + r0 = rf(_a0) + } else { + r0 = ret.Get(0).(notifier.ExternalState) + } + + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(_a0) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// RemoteAlertmanagerMock_GetRemoteState_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetRemoteState' +type RemoteAlertmanagerMock_GetRemoteState_Call struct { + *mock.Call +} + +// GetRemoteState is a helper method to define mock.On call +// - _a0 context.Context +func (_e *RemoteAlertmanagerMock_Expecter) GetRemoteState(_a0 interface{}) *RemoteAlertmanagerMock_GetRemoteState_Call { + return &RemoteAlertmanagerMock_GetRemoteState_Call{Call: _e.mock.On("GetRemoteState", _a0)} +} + +func (_c *RemoteAlertmanagerMock_GetRemoteState_Call) Run(run func(_a0 context.Context)) *RemoteAlertmanagerMock_GetRemoteState_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context)) + }) + return _c +} + +func (_c *RemoteAlertmanagerMock_GetRemoteState_Call) Return(_a0 notifier.ExternalState, _a1 error) *RemoteAlertmanagerMock_GetRemoteState_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *RemoteAlertmanagerMock_GetRemoteState_Call) RunAndReturn(run func(context.Context) (notifier.ExternalState, error)) *RemoteAlertmanagerMock_GetRemoteState_Call { + _c.Call.Return(run) + return _c +} + // GetSilence provides a mock function with given fields: _a0, _a1 func (_m *RemoteAlertmanagerMock) GetSilence(_a0 context.Context, _a1 string) (v2models.GettableSilence, error) { ret := _m.Called(_a0, _a1) diff --git a/pkg/services/ngalert/remote/remote_secondary_forked_alertmanager.go b/pkg/services/ngalert/remote/remote_secondary_forked_alertmanager.go index fa018672ee7..45a24ee1dca 100644 --- a/pkg/services/ngalert/remote/remote_secondary_forked_alertmanager.go +++ b/pkg/services/ngalert/remote/remote_secondary_forked_alertmanager.go @@ -22,6 +22,7 @@ type configStore interface { type remoteAlertmanager interface { notifier.Alertmanager CompareAndSendConfiguration(context.Context, *models.AlertConfiguration) error + GetRemoteState(context.Context) (notifier.ExternalState, error) SendState(context.Context) error } @@ -35,6 +36,8 @@ type RemoteSecondaryForkedAlertmanager struct { lastSync time.Time syncInterval time.Duration + + shouldFetchRemoteState bool } type RemoteSecondaryConfig struct { @@ -45,6 +48,9 @@ type RemoteSecondaryConfig struct { // SyncInterval determines how often we should attempt to synchronize // the configuration on the remote Alertmanager. SyncInterval time.Duration + + // WithRemoteState is used to fetch and merge the state from the remote Alertmanager before starting the internal one. + WithRemoteState bool } func (c *RemoteSecondaryConfig) Validate() error { @@ -59,12 +65,13 @@ func NewRemoteSecondaryForkedAlertmanager(cfg RemoteSecondaryConfig, internal no return nil, err } return &RemoteSecondaryForkedAlertmanager{ - log: cfg.Logger, - orgID: cfg.OrgID, - store: cfg.Store, - internal: internal, - remote: remote, - syncInterval: cfg.SyncInterval, + log: cfg.Logger, + orgID: cfg.OrgID, + store: cfg.Store, + internal: internal, + remote: remote, + syncInterval: cfg.SyncInterval, + shouldFetchRemoteState: cfg.WithRemoteState, }, nil } @@ -99,6 +106,28 @@ func (fam *RemoteSecondaryForkedAlertmanager) ApplyConfig(ctx context.Context, c } }() + if fam.shouldFetchRemoteState { + wg.Wait() + if !fam.remote.Ready() { + return fmt.Errorf("remote Alertmanager not ready, can't fetch remote state") + } + // Pull and merge the remote Alertmanager state. + rs, err := fam.remote.GetRemoteState(ctx) + if err != nil { + return fmt.Errorf("failed to fetch remote state: %w", err) + } + + // The internal Alertmanager should implement the StateMerger interface. + sm := fam.internal.(notifier.StateMerger) + if err := sm.MergeState(rs); err != nil { + return fmt.Errorf("failed to merge remote state: %w", err) + } + fam.log.Info("Successfully merged remote silences and nflog entries") + + // This operation should only be performed at startup. + fam.shouldFetchRemoteState = false + } + // Call ApplyConfig on the internal Alertmanager - we only care about errors for this one. err := fam.internal.ApplyConfig(ctx, config) wg.Wait() From 69d3b9023cec95264d32c254a9a2b1f1c18227e8 Mon Sep 17 00:00:00 2001 From: Mihai Doarna Date: Fri, 25 Jul 2025 18:27:15 +0300 Subject: [PATCH 007/131] SCIM Docs: Add mapping in AzureAD for the active attribute (#108669) add mapping in AzureAD for the active attribute --- .../configure-scim-with-azuread/_index.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/docs/sources/setup-grafana/configure-security/configure-scim-provisioning/configure-scim-with-azuread/_index.md b/docs/sources/setup-grafana/configure-security/configure-scim-provisioning/configure-scim-with-azuread/_index.md index fb031c15c10..1554484f45b 100644 --- a/docs/sources/setup-grafana/configure-security/configure-scim-provisioning/configure-scim-with-azuread/_index.md +++ b/docs/sources/setup-grafana/configure-security/configure-scim-provisioning/configure-scim-with-azuread/_index.md @@ -112,12 +112,13 @@ After setting the Tenant URL and Secret Token, navigate to the **Mappings** sect Configure the following required attributes: -| Azure AD Attribute | Grafana Attribute | -| ------------------- | ------------------------------ | -| `userPrincipalName` | `userName` | -| `mail` | `emails[type eq "work"].value` | -| `displayName` | `displayName` | -| `objectId` | `externalId` | +| Azure AD Attribute | Grafana Attribute | +| ------------------------------------------------------------- | ------------------------------ | +| `userPrincipalName` | `userName` | +| `mail` | `emails[type eq "work"].value` | +| `displayName` | `displayName` | +| `objectId` | `externalId` | +| `Switch([IsSoftDeleted], , "False", "True", "True", "False")` | `active` | ### Enable provisioning From f69f25be5d6b132751c742375562cab1134bc267 Mon Sep 17 00:00:00 2001 From: Michael Mandrus <41969079+mmandrus@users.noreply.github.com> Date: Fri, 25 Jul 2025 11:55:10 -0400 Subject: [PATCH 008/131] Chore: Don't show a "Not found" for public-dashboard fetches if the service is disabled via config (#108650) don't show 404 toast if pubdash is completely disabled --- public/app/features/dashboard/api/publicDashboardApi.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/app/features/dashboard/api/publicDashboardApi.ts b/public/app/features/dashboard/api/publicDashboardApi.ts index f7b19ace849..99fa565a453 100644 --- a/public/app/features/dashboard/api/publicDashboardApi.ts +++ b/public/app/features/dashboard/api/publicDashboardApi.ts @@ -43,7 +43,7 @@ export const publicDashboardApi = createApi({ try { await queryFulfilled; } catch (e) { - if (isFetchBaseQueryError(e) && isFetchError(e.error)) { + if (isFetchBaseQueryError(e) && isFetchError(e.error) && config.publicDashboardsEnabled) { dispatch(notifyApp(createErrorNotification(e.error.data.message))); } } From b1b9cc43a83a2a55b71afaf0ebc0dba1d8fc7701 Mon Sep 17 00:00:00 2001 From: Dana Axinte <53751979+dana-axinte@users.noreply.github.com> Date: Fri, 25 Jul 2025 17:11:17 +0100 Subject: [PATCH 009/131] SecretsManager: Adding ability to disable all DEKs (#108444) * Adding dek deactivation and rename list dek * disable data keys from manager * separate interface and don't use in encryption manager --- .../apis/secret/contracts/data_key.go | 7 +- .../secret/encryption/manager/manager_test.go | 8 +-- .../encryption/data/data_key_disable_all.sql | 7 ++ .../secret/encryption/data_key_store.go | 68 +++++++++++++++++-- .../secret/encryption/data_key_store_test.go | 15 +++- pkg/storage/secret/encryption/metrics.go | 41 +++++++++-- pkg/storage/secret/encryption/query.go | 8 +++ pkg/storage/secret/encryption/query_test.go | 9 +++ .../mysql--data_key_disable_all-disable.sql | 7 ++ ...postgres--data_key_disable_all-disable.sql | 7 ++ .../sqlite--data_key_disable_all-disable.sql | 7 ++ 11 files changed, 167 insertions(+), 17 deletions(-) create mode 100644 pkg/storage/secret/encryption/data/data_key_disable_all.sql create mode 100755 pkg/storage/secret/encryption/testdata/mysql--data_key_disable_all-disable.sql create mode 100755 pkg/storage/secret/encryption/testdata/postgres--data_key_disable_all-disable.sql create mode 100755 pkg/storage/secret/encryption/testdata/sqlite--data_key_disable_all-disable.sql diff --git a/pkg/registry/apis/secret/contracts/data_key.go b/pkg/registry/apis/secret/contracts/data_key.go index bac21460d18..5ee4bead843 100644 --- a/pkg/registry/apis/secret/contracts/data_key.go +++ b/pkg/registry/apis/secret/contracts/data_key.go @@ -29,7 +29,12 @@ type DataKeyStorage interface { CreateDataKey(ctx context.Context, dataKey *SecretDataKey) error GetDataKey(ctx context.Context, namespace, uid string) (*SecretDataKey, error) GetCurrentDataKey(ctx context.Context, namespace, label string) (*SecretDataKey, error) - GetAllDataKeys(ctx context.Context, namespace string) ([]*SecretDataKey, error) + ListDataKeys(ctx context.Context, namespace string) ([]*SecretDataKey, error) DisableDataKeys(ctx context.Context, namespace string) error DeleteDataKey(ctx context.Context, namespace, uid string) error } + +// GlobalDataKeyStorage is an interface for namespace unbounded operations. +type GlobalDataKeyStorage interface { + DisableAllDataKeys(ctx context.Context) error +} diff --git a/pkg/registry/apis/secret/encryption/manager/manager_test.go b/pkg/registry/apis/secret/encryption/manager/manager_test.go index 97166c52267..ede903c06d6 100644 --- a/pkg/registry/apis/secret/encryption/manager/manager_test.go +++ b/pkg/registry/apis/secret/encryption/manager/manager_test.go @@ -45,7 +45,7 @@ func TestEncryptionService_EnvelopeEncryption(t *testing.T) { require.NoError(t, err) assert.Equal(t, plaintext, decrypted) - keys, err := svc.store.GetAllDataKeys(ctx, namespace) + keys, err := svc.store.ListDataKeys(ctx, namespace) require.NoError(t, err) assert.Equal(t, len(keys), 1) }) @@ -60,7 +60,7 @@ func TestEncryptionService_EnvelopeEncryption(t *testing.T) { require.NoError(t, err) assert.Equal(t, plaintext, decrypted) - keys, err := svc.store.GetAllDataKeys(ctx, namespace) + keys, err := svc.store.ListDataKeys(ctx, namespace) require.NoError(t, err) assert.Equal(t, len(keys), 1) }) @@ -139,12 +139,12 @@ func TestEncryptionService_DataKeys(t *testing.T) { }) t.Run("deleting DEK when no id provided must fail", func(t *testing.T) { - beforeDelete, err := store.GetAllDataKeys(ctx, namespace) + beforeDelete, err := store.ListDataKeys(ctx, namespace) require.NoError(t, err) err = store.DeleteDataKey(ctx, namespace, "") require.Error(t, err) - afterDelete, err := store.GetAllDataKeys(ctx, namespace) + afterDelete, err := store.ListDataKeys(ctx, namespace) require.NoError(t, err) assert.Equal(t, beforeDelete, afterDelete) }) diff --git a/pkg/storage/secret/encryption/data/data_key_disable_all.sql b/pkg/storage/secret/encryption/data/data_key_disable_all.sql new file mode 100644 index 00000000000..92a2bd6a5c6 --- /dev/null +++ b/pkg/storage/secret/encryption/data/data_key_disable_all.sql @@ -0,0 +1,7 @@ +UPDATE + {{ .Ident "secret_data_key" }} +SET + {{ .Ident "active" }} = false, + {{ .Ident "updated" }} = {{ .Arg .Updated }} +WHERE {{ .Ident "active" }} = true +; diff --git a/pkg/storage/secret/encryption/data_key_store.go b/pkg/storage/secret/encryption/data_key_store.go index b80da516acd..6d38d117901 100644 --- a/pkg/storage/secret/encryption/data_key_store.go +++ b/pkg/storage/secret/encryption/data_key_store.go @@ -9,6 +9,7 @@ import ( "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/trace" + "github.com/grafana/grafana-app-sdk/logging" "github.com/grafana/grafana/pkg/registry/apis/secret/contracts" "github.com/grafana/grafana/pkg/storage/unified/sql/sqltemplate" ) @@ -161,14 +162,14 @@ func (ss *encryptionStoreImpl) GetCurrentDataKey(ctx context.Context, namespace, }, nil } -func (ss *encryptionStoreImpl) GetAllDataKeys(ctx context.Context, namespace string) ([]*contracts.SecretDataKey, error) { +func (ss *encryptionStoreImpl) ListDataKeys(ctx context.Context, namespace string) ([]*contracts.SecretDataKey, error) { start := time.Now() - ctx, span := ss.tracer.Start(ctx, "DataKeyStorage.GetAllDataKeys", trace.WithAttributes( + ctx, span := ss.tracer.Start(ctx, "DataKeyStorage.ListDataKeys", trace.WithAttributes( attribute.String("namespace", namespace), )) defer func() { span.End() - ss.metrics.GetAllDataKeysDuration.Observe(float64(time.Since(start))) + ss.metrics.ListDataKeysDuration.Observe(float64(time.Since(start))) }() req := listDataKeys{ @@ -299,8 +300,8 @@ func (ss *encryptionStoreImpl) DisableDataKeys(ctx context.Context, namespace st return fmt.Errorf("getting rows affected: %w", err) } - if rowsAffected != 1 { - return fmt.Errorf("expected 1 row affected, but affected %d", rowsAffected) + if rowsAffected == 0 { + logging.FromContext(ctx).Info("Disable all data keys: no keys were disabled for namespace", "namespace", namespace) } return nil @@ -348,3 +349,60 @@ func (ss *encryptionStoreImpl) DeleteDataKey(ctx context.Context, namespace, uid return nil } + +type globalEncryptionStoreImpl struct { + db contracts.Database + dialect sqltemplate.Dialect + tracer trace.Tracer + metrics *GlobalDataKeyMetrics +} + +func ProvideGlobalDataKeyStorage( + db contracts.Database, + tracer trace.Tracer, + registerer prometheus.Registerer, +) (contracts.GlobalDataKeyStorage, error) { + store := &globalEncryptionStoreImpl{ + db: db, + dialect: sqltemplate.DialectForDriver(db.DriverName()), + tracer: tracer, + metrics: NewGlobalDataKeyMetrics(registerer), + } + + return store, nil +} + +func (ss *globalEncryptionStoreImpl) DisableAllDataKeys(ctx context.Context) error { + start := time.Now() + ctx, span := ss.tracer.Start(ctx, "GlobalDataKeyStorage.DisableAllDataKeys") + defer func() { + span.End() + ss.metrics.DisableAllDataKeysDuration.Observe(float64(time.Since(start))) + }() + + req := disableAllDataKeys{ + SQLTemplate: sqltemplate.New(ss.dialect), + Updated: time.Now(), + } + + query, err := sqltemplate.Execute(sqlDataKeyDisableAll, req) + if err != nil { + return fmt.Errorf("execute template %q: %w", sqlDataKeyDisableAll.Name(), err) + } + + result, err := ss.db.ExecContext(ctx, query, req.GetArgs()...) + if err != nil { + return fmt.Errorf("updating data keys: %w", err) + } + + rowsAffected, err := result.RowsAffected() + if err != nil { + return fmt.Errorf("getting rows affected: %w", err) + } + + if rowsAffected == 0 { + logging.FromContext(ctx).Info("Disable all data keys: no keys were disabled") + } + + return nil +} diff --git a/pkg/storage/secret/encryption/data_key_store_test.go b/pkg/storage/secret/encryption/data_key_store_test.go index 134be881231..18081997ad5 100644 --- a/pkg/storage/secret/encryption/data_key_store_test.go +++ b/pkg/storage/secret/encryption/data_key_store_test.go @@ -31,6 +31,8 @@ func TestEncryptionStoreImpl_DataKeyLifecycle(t *testing.T) { tracer := noop.NewTracerProvider().Tracer("test") store, err := ProvideDataKeyStorage(database.ProvideDatabase(testDB, tracer), tracer, nil) require.NoError(t, err) + globalStore, err := ProvideGlobalDataKeyStorage(database.ProvideDatabase(testDB, tracer), tracer, nil) + require.NoError(t, err) ctx := context.Background() @@ -71,8 +73,8 @@ func TestEncryptionStoreImpl_DataKeyLifecycle(t *testing.T) { require.Equal(t, dataKey.UID, currentKey.UID) require.Equal(t, dataKey.Namespace, currentKey.Namespace) - // Test GetAllDataKeys - allKeys, err := store.GetAllDataKeys(ctx, "test-namespace") + // Test ListDataKeys + allKeys, err := store.ListDataKeys(ctx, "test-namespace") require.NoError(t, err) require.Len(t, allKeys, 1) require.Equal(t, dataKey.UID, allKeys[0].UID) @@ -101,6 +103,15 @@ func TestEncryptionStoreImpl_DataKeyLifecycle(t *testing.T) { require.Equal(t, unchangingDataKey.UID, staticKey.UID) require.Equal(t, unchangingDataKey.Namespace, staticKey.Namespace) require.True(t, staticKey.Active) + + // Test DisableAllDataKeys + err = globalStore.DisableAllDataKeys(ctx) + require.NoError(t, err) + + // Verify that remaining data keys are disabled + disabledKey, err = store.GetDataKey(ctx, "static-namespace", "static-uid") + require.NoError(t, err) + require.False(t, disabledKey.Active) } type PassThroughEncryptionProvider struct{} diff --git a/pkg/storage/secret/encryption/metrics.go b/pkg/storage/secret/encryption/metrics.go index 5a18d400764..5262139cdd5 100644 --- a/pkg/storage/secret/encryption/metrics.go +++ b/pkg/storage/secret/encryption/metrics.go @@ -14,7 +14,7 @@ type DataKeyMetrics struct { CreateDataKeyDuration prometheus.Histogram GetDataKeyDuration prometheus.Histogram GetCurrentDataKeyDuration prometheus.Histogram - GetAllDataKeysDuration prometheus.Histogram + ListDataKeysDuration prometheus.Histogram DisableDataKeysDuration prometheus.Histogram DeleteDataKeyDuration prometheus.Histogram } @@ -42,11 +42,11 @@ func newDataKeyMetrics() *DataKeyMetrics { Help: "Duration of get current data key operations", Buckets: prometheus.DefBuckets, }), - GetAllDataKeysDuration: prometheus.NewHistogram(prometheus.HistogramOpts{ + ListDataKeysDuration: prometheus.NewHistogram(prometheus.HistogramOpts{ Namespace: namespace, Subsystem: subsystem, - Name: "get_all_data_keys_duration_seconds", - Help: "Duration of get all data keys operations", + Name: "list_data_keys_duration_seconds", + Help: "Duration of list data keys operations", Buckets: prometheus.DefBuckets, }), DisableDataKeysDuration: prometheus.NewHistogram(prometheus.HistogramOpts{ @@ -76,7 +76,7 @@ func NewDataKeyMetrics(reg prometheus.Registerer) *DataKeyMetrics { m.CreateDataKeyDuration, m.GetDataKeyDuration, m.GetCurrentDataKeyDuration, - m.GetAllDataKeysDuration, + m.ListDataKeysDuration, m.DisableDataKeysDuration, m.DeleteDataKeyDuration, ) @@ -84,3 +84,34 @@ func NewDataKeyMetrics(reg prometheus.Registerer) *DataKeyMetrics { return m } + +type GlobalDataKeyMetrics struct { + DisableAllDataKeysDuration prometheus.Histogram +} + +func newGlobalDataKeyMetrics() *GlobalDataKeyMetrics { + return &GlobalDataKeyMetrics{ + + DisableAllDataKeysDuration: prometheus.NewHistogram(prometheus.HistogramOpts{ + Namespace: namespace, + Subsystem: subsystem, + Name: "disable_all_data_keys_duration_seconds", + Help: "Duration of disable all data keys operations", + Buckets: prometheus.DefBuckets, + }), + } +} + +// NewGlobalDataKeyMetrics returns an instance of the GlobalDataKeyMetrics +// struct containing registered metrics if [reg] is not nil. +func NewGlobalDataKeyMetrics(reg prometheus.Registerer) *GlobalDataKeyMetrics { + m := newGlobalDataKeyMetrics() + + if reg != nil { + reg.MustRegister( + m.DisableAllDataKeysDuration, + ) + } + + return m +} diff --git a/pkg/storage/secret/encryption/query.go b/pkg/storage/secret/encryption/query.go index 25f21cb77ba..573e295dcaa 100644 --- a/pkg/storage/secret/encryption/query.go +++ b/pkg/storage/secret/encryption/query.go @@ -28,6 +28,7 @@ var ( sqlDataKeyList = mustTemplate("data_key_list.sql") sqlDataKeyDisable = mustTemplate("data_key_disable.sql") sqlDataKeyDelete = mustTemplate("data_key_delete.sql") + sqlDataKeyDisableAll = mustTemplate("data_key_disable_all.sql") ) // TODO: Move this to a common place so that all stores can use @@ -140,3 +141,10 @@ type deleteDataKey struct { } func (r deleteDataKey) Validate() error { return nil } + +type disableAllDataKeys struct { + sqltemplate.SQLTemplate + Updated time.Time +} + +func (r disableAllDataKeys) Validate() error { return nil } diff --git a/pkg/storage/secret/encryption/query_test.go b/pkg/storage/secret/encryption/query_test.go index 51e078d8e25..c2ebf7a9635 100644 --- a/pkg/storage/secret/encryption/query_test.go +++ b/pkg/storage/secret/encryption/query_test.go @@ -159,6 +159,15 @@ func TestDataKeyQueries(t *testing.T) { }, }, }, + sqlDataKeyDisableAll: { + { + Name: "disable", + Data: &disableAllDataKeys{ + SQLTemplate: mocks.NewTestingSQLTemplate(), + Updated: time.Unix(1735689600, 0).UTC(), + }, + }, + }, }, }) } diff --git a/pkg/storage/secret/encryption/testdata/mysql--data_key_disable_all-disable.sql b/pkg/storage/secret/encryption/testdata/mysql--data_key_disable_all-disable.sql new file mode 100755 index 00000000000..49972ef5026 --- /dev/null +++ b/pkg/storage/secret/encryption/testdata/mysql--data_key_disable_all-disable.sql @@ -0,0 +1,7 @@ +UPDATE + `secret_data_key` +SET + `active` = false, + `updated` = '2025-01-01 00:00:00 +0000 UTC' +WHERE `active` = true +; diff --git a/pkg/storage/secret/encryption/testdata/postgres--data_key_disable_all-disable.sql b/pkg/storage/secret/encryption/testdata/postgres--data_key_disable_all-disable.sql new file mode 100755 index 00000000000..8b72ac271fc --- /dev/null +++ b/pkg/storage/secret/encryption/testdata/postgres--data_key_disable_all-disable.sql @@ -0,0 +1,7 @@ +UPDATE + "secret_data_key" +SET + "active" = false, + "updated" = '2025-01-01 00:00:00 +0000 UTC' +WHERE "active" = true +; diff --git a/pkg/storage/secret/encryption/testdata/sqlite--data_key_disable_all-disable.sql b/pkg/storage/secret/encryption/testdata/sqlite--data_key_disable_all-disable.sql new file mode 100755 index 00000000000..8b72ac271fc --- /dev/null +++ b/pkg/storage/secret/encryption/testdata/sqlite--data_key_disable_all-disable.sql @@ -0,0 +1,7 @@ +UPDATE + "secret_data_key" +SET + "active" = false, + "updated" = '2025-01-01 00:00:00 +0000 UTC' +WHERE "active" = true +; From c1c5c2db8b09235f3a9890844d29c09bc03cee78 Mon Sep 17 00:00:00 2001 From: Josh Hunt Date: Fri, 25 Jul 2025 17:21:48 +0100 Subject: [PATCH 010/131] FS: Handle unavailable backend (#108544) * add dev mechanism for making backend unavailable * handle unavailable backend in html * fix ordering of /-/ routes * Add new loader to index.html * tweak light colours * fix readme * add error handling and error state * use setTimeout for the retry loop * easier on the comments: --- devenv/frontend-service/README.md | 10 + devenv/frontend-service/backend.dockerfile | 2 +- devenv/frontend-service/build-grafana.sh | 2 +- devenv/frontend-service/nginx.conf | 29 +++ pkg/services/frontend/index.html | 285 +++++++++++++++++---- 5 files changed, 278 insertions(+), 50 deletions(-) diff --git a/devenv/frontend-service/README.md b/devenv/frontend-service/README.md index c81008cb3b0..60acc1e134e 100644 --- a/devenv/frontend-service/README.md +++ b/devenv/frontend-service/README.md @@ -16,3 +16,13 @@ On top of the main Grafana development dependencies, you will need installed: To start the stack, from the root of the Grafana project run `make frontend-service-up`. Tilt will orchestrate the webpack and docker builds, and then run the services with Docker compose. You can monitor it's progress and see logs with the URL to the Tilt console. Once done, you can access Grafana at `http://localhost:3000`. Quitting the process will not stop the service from running. Run `make frontend-service-down` when done to shut down the docker containers. + +### Bootdata unavailable + +To simulate the `/bootdata` endpoint being available, there are special control URLs you can visit that use cookies to control behaviour: + + - `/-/down` - Simulates the endpoint being unavailable for 60 seconds. + - `/-/down/:seconds` - Simulates the endpoint being unavailable for a custom number of seconds. + - `/-/up` - Restores the endpoint to being available. + +When unavailable, the API will return `HTTP 503 Service Unavailable` with a JSON payload. \ No newline at end of file diff --git a/devenv/frontend-service/backend.dockerfile b/devenv/frontend-service/backend.dockerfile index bfc89735d1a..7326802d3a6 100644 --- a/devenv/frontend-service/backend.dockerfile +++ b/devenv/frontend-service/backend.dockerfile @@ -1,5 +1,5 @@ ARG BASE_IMAGE=alpine:3.21 -ARG GO_IMAGE=golang:1.24.4-alpine +ARG GO_IMAGE=golang:1.24.5-alpine # ----- Go build stage FROM ${GO_IMAGE} AS go-dev-builder diff --git a/devenv/frontend-service/build-grafana.sh b/devenv/frontend-service/build-grafana.sh index 8b1ac338889..b3adbe16e1a 100644 --- a/devenv/frontend-service/build-grafana.sh +++ b/devenv/frontend-service/build-grafana.sh @@ -6,7 +6,7 @@ echo "Go build cache: $(go env GOCACHE), $(ls -1 $(go env GOCACHE) | wc -l) item # Need to build version into the binary so plugin compatibility works correctly VERSION=$(jq -r .version package.json) -go build \ +go build -v \ -ldflags "-X main.version=${VERSION}" \ -gcflags "all=-N -l" \ -o ./bin/grafana ./pkg/cmd/grafana diff --git a/devenv/frontend-service/nginx.conf b/devenv/frontend-service/nginx.conf index 5927c492e53..26d6c1f9968 100644 --- a/devenv/frontend-service/nginx.conf +++ b/devenv/frontend-service/nginx.conf @@ -9,10 +9,29 @@ upstream frontend { server frontend-service:3000; } +map "$request_method:$cookie_fs_unavailable" $reject_login { + default 0; + "POST:1" 1; +} + server { listen 80; server_name _; + location ~ ^/-/down/?$ { + add_header Set-Cookie "fs_unavailable=true; Max-Age=60; Path=/; HttpOnly" always; + return 302 $scheme://$http_host/; + } + + location ~ ^/-/down/(?\d+)/?$ { + add_header Set-Cookie "fs_unavailable=true; Max-Age=$age; Path=/; HttpOnly" always; + return 302 $scheme://$http_host/; + } + + location ~ ^/-/up/?$ { + return 302 $scheme://$http_host/-/down/0; + } + # Special‐case POST /login to backend, GET to frontend location = /login { proxy_set_header Host $host; @@ -20,6 +39,11 @@ server { proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; + if ($reject_login) { + add_header Content-Type application/json always; + return 503 '{"code":"Loading", "message": "Soon!"}'; + } + if ($request_method = POST) { proxy_pass http://backend; break; @@ -37,6 +61,11 @@ server { # Cheat with app plugin paths and route them to the backend. These should come from # the Plugin CDN location ~ ^/(api|apis|bootdata|logout|public\/plugins\/grafana\-\w+\-app) { + if ($cookie_fs_unavailable) { + add_header Content-Type application/json always; + return 503 '{"code":"Loading", "message": "Soon!"}'; + } + proxy_pass http://backend; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; diff --git a/pkg/services/frontend/index.html b/pkg/services/frontend/index.html index f735f2daa81..2ece6114fa5 100644 --- a/pkg/services/frontend/index.html +++ b/pkg/services/frontend/index.html @@ -1,5 +1,5 @@ - + [[ if and .CSPEnabled .IsDevelopmentEnv ]] @@ -24,28 +24,133 @@ performance.mark('frontend_boot_css_time_seconds'); - + -
+
+ + +
+ + + + + +

Grafana is starting up...

+
+ +
+ + + + +

Error loading Grafana

+
+
+
- window.__grafana_load_failed = function(...args) { - console.error('Failed to load Grafana', ...args); - }; + [[range $asset := .Assets.JSFiles]] From c16117df4ecf86ad53bb3b3d7a8d359dd3e97f25 Mon Sep 17 00:00:00 2001 From: Zoe C <38118634+zoesyc@users.noreply.github.com> Date: Fri, 25 Jul 2025 12:25:55 -0400 Subject: [PATCH 011/131] Update Influx Config Options Section in Docs (#108264) --- .../configure-influxdb-data-source/_index.md | 176 ++++++++++-------- 1 file changed, 99 insertions(+), 77 deletions(-) diff --git a/docs/sources/datasources/influxdb/configure-influxdb-data-source/_index.md b/docs/sources/datasources/influxdb/configure-influxdb-data-source/_index.md index d50db2e9d43..0c958283f0e 100644 --- a/docs/sources/datasources/influxdb/configure-influxdb-data-source/_index.md +++ b/docs/sources/datasources/influxdb/configure-influxdb-data-source/_index.md @@ -34,15 +34,11 @@ This document provides instructions for configuring the InfluxDB data source and To configure the InfluxDB data source you must have the `Administrator` role. -{{< admonition type="note" >}} -Select the query language you want to use with InfluxDB before adding the InfluxDB data source. Configuration options differ based on query language type. -{{< /admonition >}} - InfluxData provides three query languages. Some key points to consider: -- SQL is only available for InfluxDB v3.x. - Flux is a functional data scripting language for InfluxDB 2.x. Refer to [Query InfluxDB with Flux](https://docs.influxdata.com/influxdb/cloud/query-data/get-started/query-influxdb/) for a basic guide on working with Flux. - InfluxQL is SQL-like query language developed by InfluxData. It doesn't support more advanced functions such as JOINs. +- SQL is only available for InfluxDB v3.x. To help choose the best language for your needs, refer to a [comparison of Flux vs InfluxQL](https://docs.influxdata.com/influxdb/v1.8/flux/flux-vs-influxql/) @@ -60,97 +56,123 @@ Complete the following steps to set up a new InfluxDB data source: You are taken to the **Settings** tab where you will configure the data source. -## InfluxDB common configuration options +## Configuration Options -The following configuration options apply to **all three query language options**. +The following is a list of configuration options for InfluxDB. + +![Name and Default settings for InfluxDB configuration](https://grafana.com/media/docs/influxdb/InfluxDB-ConfigV2-Name.png) + +The first option is to configure the name of your connection. - **Name** - Sets the name you use to refer to the data source in panels and queries. Examples: `InfluxDB-InfluxQL`, `InfluxDB_SQL`. - **Default** - Toggle to set as the default data source. -- **Query language** - Select the query language for your InfluxDB instance. The three options are: - - **InfluxQL** - SQL-like language for querying InfluxDB, with statements such as SELECT, FROM, WHERE, and GROUP BY that are familiar to SQL users. - - **SQL** - Native SQL language starting with InfluxDB v.3.0. Refer to InfluxData's [SQL reference documentation](https://docs.influxdata.com/influxdb/cloud-serverless/reference/sql/) for a list of supported statements, operators, and functions. - - **Flux** - Flux is a data scripting language developed by InfluxData that allows you to query, analyze, and act on data. Refer to [Get started with Flux](https://docs.influxdata.com/influxdb/cloud/query-data/get-started/) for guidance on using Flux. -**HTTP section:** +### URL and Authentication + +![URL and Authentication for InfluxDB configuration](https://grafana.com/media/docs/influxdb/InfluxDB-ConfigV2-URLAuth-Section.png) + +These settings identify the Influx instance and schema the data source is connecting to. - **URL** - The HTTP protocol, IP address, and port of your InfluxDB API. InfluxDB’s default API port is `8086`. +- **Product** - Select the product version of your Influx instance. +- **Query language** - Select the query language for your InfluxDB instance. This will determine the connection details needed in **Database Settings**. The three options are: + - **Flux** - Flux is a data scripting language developed by InfluxData that allows you to query, analyze, and act on data. Refer to [Get started with Flux](https://docs.influxdata.com/influxdb/cloud/query-data/get-started/) for guidance on using Flux. + - **InfluxQL** - SQL-like language for querying InfluxDB, with statements such as SELECT, FROM, WHERE, and GROUP BY that are familiar to SQL users. + - **SQL** - Native SQL language starting with **InfluxDB v.3.0**. Refer to InfluxData's [SQL reference documentation](https://docs.influxdata.com/influxdb/cloud-serverless/reference/sql/) for a list of supported statements, operators, and functions. + +{{< admonition type="note" >}} +_For InfluxQL only._ **Database + Retention Policy (DBRP) Mapping** must be configured before data can be queried for the following product versions: _Influx OSS 1.x_, _Influx OSS 2.x_, _Influx Enterprise 1.x_, _Influx Cloud (TSM)_, _Influx Cloud Serverless_ + +Refer to [Manage DBRP Mappings](https://docs.influxdata.com/influxdb/cloud/query-data/influxql/dbrp/) for guidance on setting this up via the CLI or API +{{< /admonition >}} + +#### Advanced HTTP Settings (Optional) + +Advanced HTTP Settings are optional settings that can be configured for more control over your data source. + - **Allowed cookies** - Defines which cookies are forwarded to the data source. All other cookies are deleted by default. - **Timeout** - Set an HTTP request timeout in seconds. -**Auth section:** +**Custom HTTP Headers** -- **Basic auth** - The most common authentication method. Use your InfluxData user name and password to authenticate. Toggling requires you to add the user and password under **Basic auth details**. -- **With credentials** - Toggle to enable credentials such as cookies or auth headers to be sent with cross-site requests. -- **TLS client auth** - Toggle to use client authentication. When enabled, add the `Server name`, `Client cert` and `Client key` under the **TLS/SSL auth details** section. The client provides a certificate that the server validates to establish the client’s trusted identity. The client key encrypts the data between client and server. -- **With CA cert** - Authenticate with a CA certificate. Follow the instructions of your CA (Certificate Authority) to download the certificate file. -- **Skip TLS verify** - Toggle to bypass TLS certificate validation. -- **Forward OAuth identity** - Forward the OAuth access token (and also the OIDC ID token if available) of the user querying the data source. - -**Basic auth details:** - -If you enable **Basic auth** under the Auth section you need to configure the following: - -- **User** - Add the username used to sign in to InfluxDB. -- **Password** - Defines the token you use to query the bucket defined in **Database**. Retrieve this from the [Tokens page](https://docs.influxdata.com/influxdb/v2.0/security/tokens/view-tokens/) in the InfluxDB UI. - -**TLS/SSL auth details:** - -TLS/SSL certificates are encrypted and stored in the Grafana database. - -- **CA cert** - If you toggle **With CA cert** add your self-signed cert here. -- **Server name** - Name of the server. Example: server1.domain.com -- **Client cert** - Add the client certificate. -- **Client key** - Add the client key. - -**Custom HTTP headers:** +Click **+ Add header** to add one or more HTTP headers. HTTP headers pass additional context and metadata about the request/response. - **Header** - Add a custom HTTP header. Select an option from the drop-down. Allows custom headers to be passed based on the needs of your InfluxDB instance. - **Value** - The value for the header. -**Private data source connect:** +#### Auth and TSL/SSL Settings (Optional) -- **Private data source connect** - _Only for Grafana Cloud users._ Private data source connect, or PDC, allows you to establish a private, secured connection between a Grafana Cloud instance, or stack, and data sources secured within a private network. Click the drop-down to locate the URL for PDC. For more information regarding Grafana PDC refer to [Private data source connect (PDC)](https://grafana.com/docs/grafana-cloud/connect-externally-hosted/private-data-source-connect/). +There are several authentication methods you can choose in the Authentication section. + +- **No Authentication** - Make the data source available without authentication. Grafana recommends using some type of authentication method. +- **Basic auth** - The most common authentication method. Use your Influx instance username and password to authenticate. +- **Forward OAuth identity** - Forward the OAuth access token (and also the OIDC ID token if available) of the user querying the data source. +- **With credentials** - Toggle to enable credentials such as cookies or auth headers to be sent with cross-site requests. + +TLS/SSL Certificates are encrypted and stored in the Grafana database. + +- **TLS client auth** - When enabled, add the `Server name`, `Client cert` and `Client key`. The client provides a certificate that the server validates to establish the client’s trusted identity. The client key encrypts the data between client and server. + - **Server name** - Name of the server. Example: `server1.domain.com` + - **Client cert** - Add the client certificate. + - **Client key** - Add the client key. +- **CA cert** - Authenticate with a CA certificate. When enabled, follow the instructions of your CA (Certificate Authority) to download the certificate file. +- **Skip TLS verify** - Toggle to bypass TLS certificate validation. + +### Database Settings + +![Database Settings for InfluxDB configuration](https://grafana.com/media/docs/influxdb/InfluxDB-ConfigV2-DBSettings.png) + +{{< admonition type="note" >}} +Setting the database for this data source **does not deny access to other databases**. The InfluxDB query syntax allows switching the database in the query. For example: `SHOW MEASUREMENTS ON _internal` or `SELECT * FROM "_internal".."database" LIMIT 10` + +To support data isolation and security, make sure appropriate permissions are configured in InfluxDB. +{{< /admonition >}} + +These settings identify the Influx database your data source will connect to. The required information will vary by the query language selected in **URL and Authentication**. Each query language uses a different set of connection details. + +The table below illustrates the details needed for each query language: + +| **Setting** | **Flux** | **InfluxQL** | **SQL** | +| -------------------------- | -------- | ------------ | -------- | +| **Bucket** or **Database** | ✓ | ✓ | ✓ | +| **Organization** | ✓ | | | +| **Password** or **Token** | ✓ | ✓ | ✓ | +| **User** | | ✓ | | + +- **Bucket** or **Database** - Sets the ID of the bucket to query. Refer to [View buckets](https://docs.influxdata.com/influxdb/v2.0/organizations/buckets/view-buckets/) in InfluxData's documentation on how to locate the list of available buckets and their corresponding IDs. +- **Organization** - Sets the [Influx organization](https://v2.docs.influxdata.com/v2.0/organizations/) used for Flux queries. Also used for the `v.organization` query macro. +- **Password** or **Token** - Specify the token used to query the bucket defined in **Database**. Retrieve this from the [Tokens page](https://docs.influxdata.com/influxdb/v2.0/security/tokens/view-tokens/) in the InfluxDB UI. +- **User** - Add the username used to sign in to InfluxDB. + +**For Flux** + +- **Default bucket** is optional. The [Influx bucket](https://v2.docs.influxdata.com/v2.0/organizations/buckets/) used for the `v.defaultBucket` macro in Flux queries. +- With Influx 2.0 products, use the [influx authentication token to function](https://v2.docs.influxdata.com/v2.0/security/tokens/create-token/). Token must be set as `Authorization` header with the value `Token `. +- For Influx 1.8, the token is `username:password`. + +#### Advanced Database Settings (Optional) + +Advanced Database Settings are optional settings that give you more control over the query experience. + +- **Min time interval** - Sets the minimum time interval for auto group-by. Grafana recommends setting this to match the data write frequency. For example, if your data is written every minute, it’s recommended to set this interval to 1 minute, so that each group contains data from each new write. The default is `10s`. Refer to [Min time interval](#min-time-interval) for format examples. +- **Max series** - Sets a limit on the maximum number of series or tables that Grafana processes. Set a lower limit to prevent system overload, or increase it if you have many small time series and need to display more of them. The default is `1000`. + +**For InfluxQL** + +- **HTTP method** - Sets the HTTP method used to query your data source. The POST method allows for larger queries that would return an error using the GET method. The default method is `POST`. +- **Autocomplete range** - Sets a time range limit for the query editor's autocomplete to reduce the execution time of tag filter queries. As a result, any tags not present within the defined time range will be filtered out. For example, setting the value to 12h will include only tag keys/values from the past 12 hours. This feature is recommended for use with very large databases, where significant performance improvements can be observed. + +**For SQL** + +- **Insecure Connection** - Toggle to disable gRPC TLS security. + +### Private Data Source Connect + +_For Grafana Cloud only._ Private data source connect (PDC) allows you to establish a private, secured connection between a Grafana Cloud instance, or stack, and data sources secured within a private network. Click the drop-down to locate the URL for PDC. For more information regarding Grafana PDC refer to [Private data source connect (PDC)](https://grafana.com/docs/grafana-cloud/connect-externally-hosted/private-data-source-connect/). Click **Manage private data source connect** to be taken to your PDC connection page, where you'll find your PDC configuration details. -Once you have added your connection settings, click **Save & test** to test the data source connection. - -### InfluxQL-specific configuration section - -The following settings are specific to the InfluxQL query language option. - -**InfluxQL InfluxDB details section:** - -- **Database** - Sets the ID of the bucket to query. Refer to [View buckets](https://docs.influxdata.com/influxdb/v2.0/organizations/buckets/view-buckets/) in InfluxData's documentation on how to locate the list of available buckets and their corresponding IDs. -- **User** - The user name used to sign in to InfluxDB. -- **Password** - Defines the token used to query the bucket defined in **Database**. Retrieve the password from the [Tokens page](https://docs.influxdata.com/influxdb/v2.0/security/tokens/view-tokens/) of the InfluxDB UI. -- **HTTP method** - Sets the HTTP method used to query your data source. The POST method allows for larger queries that would return an error using the GET method. The default method is `POST`. -- **Min time interval** - _(Optional)_ Sets the minimum time interval for auto group-by. Grafana recommends setting this to match the data write frequency. For example, if your data is written every minute, it’s recommended to set this interval to 1 minute, so that each group contains data from each new write. The default is `10s`. Refer to [Min time interval](#min-time-interval) for format examples. -- **Autocomplete range** - _(Optional)_ Sets a time range limit for the query editor's autocomplete to reduce the execution time of tag filter queries. As a result, any tags not present within the defined time range will be filtered out. For example, setting the value to 12h will include only tag keys/values from the past 12 hours. This feature is recommended for use with very large databases, where significant performance improvements can be observed. -- **Max series** - _(Optional)_ Sets a limit on the maximum number of series or tables that Grafana processes. Set a lower limit to prevent system overload, or increase it if you have many small time series and need to display more of them. The default is `1000`. - -### SQL-specific configuration section - -The following settings are specific to the SQL query language option. - -**SQL InfluxDB details section:** - -- **Database** - Specify the **bucket ID**. Refer to the **Buckets page** in the InfluxDB UI to locate the ID. -- **Token** The API token used for SQL queries. Generated on InfluxDB Cloud dashboard under [Load Data > API Tokens](https://docs.influxdata.com/influxdb/cloud-serverless/get-started/setup/#create-an-all-access-api-token) menu. -- **Insecure Connection** - Toggle to disable gRPC TLS security. -- **Max series** - _(Optional)_ Sets a limit on the maximum number of series or tables that Grafana processes. Set a lower limit to prevent system overload, or increase it if you have many small time series and need to display more of them. The default is `1000`. - -### Flux-specific configuration section - -The following settings are specific to the Flux query language option. - -**Flux InfluxDB details section:** - -- **Organization** - The [Influx organization](https://v2.docs.influxdata.com/v2.0/organizations/) used for Flux queries. Also used for the `v.organization` query macro. -- **Token** - The authentication token used for Flux queries. With Influx 2.0, use the [influx authentication token to function](https://v2.docs.influxdata.com/v2.0/security/tokens/create-token/). Token must be set as `Authorization` header with the value `Token `. For Influx 1.8, the token is `username:password`. -- **Default bucket** - _(Optional)_ The [Influx bucket](https://v2.docs.influxdata.com/v2.0/organizations/buckets/) used for the `v.defaultBucket` macro in Flux queries. -- **Min time interval** - Sets the minimum time interval for auto group-by. Grafana recommends aligning this setting with the data write frequency. For example, if data is written every minute, set the interval to 1 minute to ensure each group includes data from every new write. The default is `10s`. -- **Max series** - Sets a limit on the maximum number of series or tables that Grafana processes. Set a lower limit to prevent system overload, or increase it if you have many small time series and need to display more of them. The default is `1000`. +After you have added your connection settings, click **Save & test** to test the data source connection. ### Min time interval From a82a7f13407ce74313d5ff8bd849c74bb381cf19 Mon Sep 17 00:00:00 2001 From: Dave Henderson Date: Fri, 25 Jul 2025 12:27:57 -0400 Subject: [PATCH 012/131] deps(go): Tidying advisor and investigations go modules (#108703) deps(go): Tidying apps/advisor go module Signed-off-by: Dave Henderson --- apps/advisor/go.mod | 233 ++++- apps/advisor/go.sum | 1956 ++++++++++++++++++++++++++++++++---- apps/investigations/go.mod | 155 ++- apps/investigations/go.sum | 932 ++++++++++++++--- go.mod | 2 +- go.sum | 4 +- go.work.sum | 54 +- pkg/build/go.mod | 2 +- pkg/build/go.sum | 4 +- 9 files changed, 2966 insertions(+), 376 deletions(-) diff --git a/apps/advisor/go.mod b/apps/advisor/go.mod index 5d6563ec367..853c9850196 100644 --- a/apps/advisor/go.mod +++ b/apps/advisor/go.mod @@ -3,60 +3,239 @@ module github.com/grafana/grafana/apps/advisor go 1.24.5 require ( + github.com/Masterminds/semver/v3 v3.4.0 + github.com/google/go-github/v70 v70.0.0 + github.com/grafana/authlib/types v0.0.0-20250710201142-9542f2f28d43 + github.com/grafana/grafana v0.0.0-00010101000000-000000000000 github.com/grafana/grafana-app-sdk v0.40.0 - k8s.io/apimachinery v0.33.2 - k8s.io/klog/v2 v2.130.1 + github.com/grafana/grafana-app-sdk/logging v0.39.3 + github.com/grafana/grafana-plugin-sdk-go v0.278.0 + github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250725144121-b1592b5e36d2 + github.com/stretchr/testify v1.10.0 + k8s.io/apimachinery v0.33.3 + k8s.io/apiserver v0.33.3 k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff ) +// transitive dependencies that need replaced +// TODO: stop depending on grafana core +replace github.com/grafana/grafana => ../.. + +replace github.com/prometheus/alertmanager => github.com/grafana/prometheus-alertmanager v0.25.1-0.20250620093340-be61a673dee6 + require ( + cloud.google.com/go/compute/metadata v0.7.0 // indirect + dario.cat/mergo v1.0.1 // indirect + filippo.io/edwards25519 v1.1.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.9.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1 // indirect + github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e // indirect + github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 // indirect + github.com/BurntSushi/toml v1.5.0 // indirect + github.com/Masterminds/goutils v1.1.1 // indirect + github.com/Masterminds/semver v1.5.0 // indirect + github.com/Masterminds/sprig/v3 v3.3.0 // indirect + github.com/ProtonMail/go-crypto v1.1.6 // indirect + github.com/VividCortex/mysqlerr v0.0.0-20170204212430-6c6b55f8796f // indirect + github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b // indirect + github.com/apache/arrow-go/v18 v18.3.0 // indirect + github.com/armon/go-metrics v0.4.1 // indirect + github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect + github.com/at-wat/mqtt-go v0.19.4 // indirect + github.com/aws/aws-sdk-go v1.55.7 // indirect + github.com/aws/aws-sdk-go-v2 v1.36.5 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.17.70 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.36 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.36 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.17 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.34.0 // indirect + github.com/aws/smithy-go v1.22.4 // indirect + github.com/benbjohnson/clock v1.3.5 // indirect github.com/beorn7/perks v1.0.1 // indirect + github.com/blang/semver/v4 v4.0.0 // indirect + github.com/bluele/gcache v0.0.2 // indirect github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 // indirect + github.com/bwmarrin/snowflake v0.3.0 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect + github.com/cenkalti/backoff/v5 v5.0.2 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/cheekybits/genny v1.0.0 // indirect + github.com/chromedp/cdproto v0.0.0-20250429231605-6ed5b53462d4 // indirect + github.com/cloudflare/circl v1.6.1 // indirect + github.com/coreos/go-systemd/v22 v22.5.0 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect - github.com/emicklei/go-restful/v3 v3.11.0 // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect + github.com/dlmiddlecote/sqlstats v1.0.2 // indirect + github.com/docker/go-units v0.5.0 // indirect + github.com/dolthub/flatbuffers/v23 v23.3.3-dh.2 // indirect + github.com/dolthub/go-icu-regex v0.0.0-20250327004329-6799764f2dad // indirect + github.com/dolthub/go-mysql-server v0.19.1-0.20250410182021-5632d67cd46e // indirect + github.com/dolthub/jsonpath v0.0.2-0.20240227200619-19675ab05c71 // indirect + github.com/dolthub/vitess v0.0.0-20250410090211-143e6b272ad4 // indirect + github.com/elazarl/goproxy v1.7.2 // indirect + github.com/emicklei/go-restful/v3 v3.12.1 // indirect github.com/evanphx/json-patch v5.6.0+incompatible // indirect + github.com/fatih/color v1.18.0 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect + github.com/gchaincl/sqlhooks v1.3.0 // indirect github.com/getkin/kin-openapi v0.132.0 // indirect + github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect + github.com/go-jose/go-jose/v3 v3.0.4 // indirect + github.com/go-kit/log v0.2.1 // indirect + github.com/go-ldap/ldap/v3 v3.4.4 // indirect + github.com/go-logfmt/logfmt v0.6.0 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-openapi/analysis v0.23.0 // indirect + github.com/go-openapi/errors v0.22.0 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/jsonreference v0.21.0 // indirect + github.com/go-openapi/loads v0.22.0 // indirect + github.com/go-openapi/runtime v0.28.0 // indirect + github.com/go-openapi/spec v0.21.0 // indirect + github.com/go-openapi/strfmt v0.23.0 // indirect github.com/go-openapi/swag v0.23.0 // indirect - github.com/go-viper/mapstructure/v2 v2.3.0 // indirect + github.com/go-openapi/validate v0.24.0 // indirect + github.com/go-redis/redis/v8 v8.11.5 // indirect + github.com/go-sql-driver/mysql v1.9.2 // indirect + github.com/go-stack/stack v1.8.1 // indirect + github.com/gobwas/glob v0.2.3 // indirect + github.com/goccy/go-json v0.10.5 // indirect + github.com/gofrs/uuid v4.4.0+incompatible // indirect + github.com/gogo/googleapis v1.4.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang-jwt/jwt/v4 v4.5.2 // indirect + github.com/golang-jwt/jwt/v5 v5.2.2 // indirect + github.com/golang-migrate/migrate/v4 v4.7.0 // indirect + github.com/golang/mock v1.7.0-rc.1 // indirect github.com/golang/protobuf v1.5.4 // indirect + github.com/google/btree v1.1.3 // indirect + github.com/google/flatbuffers v25.2.10+incompatible // indirect github.com/google/gnostic-models v0.6.9 // indirect github.com/google/go-cmp v0.7.0 // indirect - github.com/google/gofuzz v1.2.0 // indirect - github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad // indirect + github.com/google/go-querystring v1.1.0 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/grafana/authlib v0.0.0-20250515162837-2f4a8263eabb // indirect - github.com/grafana/grafana-app-sdk/logging v0.39.3 // indirect + github.com/google/wire v0.6.0 // indirect + github.com/gorilla/mux v1.8.1 // indirect + github.com/grafana/alerting v0.0.0-20250725130805-615c8286e14b // indirect + github.com/grafana/authlib v0.0.0-20250710201142-9542f2f28d43 // indirect + github.com/grafana/dataplane/sdata v0.0.9 // indirect + github.com/grafana/dskit v0.0.0-20250611075409-46f51e1ce914 // indirect + github.com/grafana/grafana-aws-sdk v1.0.4 // indirect + github.com/grafana/grafana-azure-sdk-go/v2 v2.1.6 // indirect + github.com/grafana/grafana/pkg/apiserver v0.0.0-20250627191313-2f1a6ae1712b // indirect + github.com/grafana/otel-profiling-go v0.5.1 // indirect + github.com/grafana/pyroscope-go/godeltaprof v0.1.8 // indirect + github.com/grafana/sqlds/v4 v4.2.3 // indirect + github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0 // indirect + github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.2 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-hclog v1.6.3 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-metrics v0.5.4 // indirect + github.com/hashicorp/go-msgpack/v2 v2.1.2 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect - github.com/invopop/yaml v0.3.1 // indirect + github.com/hashicorp/go-plugin v1.6.3 // indirect + github.com/hashicorp/go-sockaddr v1.0.7 // indirect + github.com/hashicorp/golang-lru v1.0.2 // indirect + github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect + github.com/hashicorp/memberlist v0.5.2 // indirect + github.com/hashicorp/yamux v0.1.1 // indirect + github.com/huandu/xstrings v1.5.0 // indirect + github.com/jaegertracing/jaeger-idl v0.5.0 // indirect + github.com/jessevdk/go-flags v1.5.0 // indirect + github.com/jmespath-community/go-jmespath v1.1.1 // indirect + github.com/jmespath/go-jmespath v0.4.0 // indirect + github.com/jmoiron/sqlx v1.3.5 // indirect github.com/josharian/intern v1.0.0 // indirect + github.com/jpillora/backoff v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect + github.com/jszwedko/go-datemath v0.1.1-0.20230526204004-640a500621d6 // indirect github.com/klauspost/compress v1.18.0 // indirect - github.com/mailru/easyjson v0.7.7 // indirect + github.com/klauspost/cpuid/v2 v2.2.10 // indirect + github.com/kylelemons/godebug v1.1.0 // indirect + github.com/lestrrat-go/strftime v1.0.4 // indirect + github.com/lib/pq v1.10.9 // indirect + github.com/magefile/mage v1.15.0 // indirect + github.com/mailru/easyjson v0.9.0 // indirect + github.com/mattetti/filebuffer v1.0.1 // indirect + github.com/mattn/go-colorable v0.1.14 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-runewidth v0.0.16 // indirect + github.com/mattn/go-sqlite3 v1.14.22 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect + github.com/mdlayher/socket v0.4.1 // indirect + github.com/mdlayher/vsock v1.2.1 // indirect + github.com/miekg/dns v1.1.63 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/mitchellh/mapstructure v1.5.1-0.20231216201459-8508981c8b6c // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/mithrandie/csvq v1.18.1 // indirect + github.com/mithrandie/csvq-driver v1.7.0 // indirect + github.com/mithrandie/go-file/v2 v2.1.0 // indirect + github.com/mithrandie/go-text v1.6.0 // indirect + github.com/mithrandie/ternary v1.1.1 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/openfga/openfga v1.8.13 // indirect + github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect + github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect + github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/oklog/ulid v1.3.1 // indirect + github.com/olekukonko/tablewriter v0.0.5 // indirect + github.com/open-feature/go-sdk v1.14.1 // indirect + github.com/open-feature/go-sdk-contrib/providers/go-feature-flag v0.2.3 // indirect + github.com/open-feature/go-sdk-contrib/providers/ofrep v0.1.5 // indirect + github.com/patrickmn/go-cache v2.1.0+incompatible // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect + github.com/pierrec/lz4/v4 v4.1.22 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/prometheus/alertmanager v0.28.0 // indirect github.com/prometheus/client_golang v1.22.0 // indirect github.com/prometheus/client_model v0.6.2 // indirect - github.com/prometheus/common v0.64.0 // indirect + github.com/prometheus/common v0.65.0 // indirect + github.com/prometheus/common/sigv4 v0.1.0 // indirect + github.com/prometheus/exporter-toolkit v0.14.0 // indirect github.com/prometheus/procfs v0.16.1 // indirect github.com/puzpuzpuz/xsync/v2 v2.5.1 // indirect + github.com/rivo/uniseg v0.4.7 // indirect + github.com/rs/cors v1.11.1 // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 // indirect + github.com/shopspring/decimal v1.4.0 // indirect + github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c // indirect + github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546 // indirect + github.com/sirupsen/logrus v1.9.3 // indirect + github.com/spf13/cast v1.7.1 // indirect github.com/spf13/pflag v1.0.6 // indirect + github.com/stretchr/objx v0.5.2 // indirect + github.com/tetratelabs/wazero v1.8.2 // indirect + github.com/tjhop/slog-gokit v0.1.3 // indirect + github.com/unknwon/bra v0.0.0-20200517080246-1e3013ecaff8 // indirect + github.com/unknwon/com v1.0.1 // indirect + github.com/unknwon/log v0.0.0-20200308114134-929b1006e34a // indirect + github.com/urfave/cli v1.22.16 // indirect github.com/x448/float16 v0.8.4 // indirect + github.com/zeebo/xxh3 v1.0.2 // indirect + go.mongodb.org/mongo-driver v1.16.1 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.61.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 // indirect + go.opentelemetry.io/contrib/propagators/jaeger v1.36.0 // indirect + go.opentelemetry.io/contrib/samplers/jaegerremote v0.30.0 // indirect go.opentelemetry.io/otel v1.37.0 // indirect + go.opentelemetry.io/otel/exporters/jaeger v1.17.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.37.0 // indirect @@ -64,26 +243,44 @@ require ( go.opentelemetry.io/otel/sdk v1.37.0 // indirect go.opentelemetry.io/otel/trace v1.37.0 // indirect go.opentelemetry.io/proto/otlp v1.7.0 // indirect + go.uber.org/atomic v1.11.0 // indirect + go.yaml.in/yaml/v2 v2.4.2 // indirect golang.org/x/crypto v0.39.0 // indirect + golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 // indirect + golang.org/x/mod v0.25.0 // indirect golang.org/x/net v0.41.0 // indirect golang.org/x/oauth2 v0.30.0 // indirect golang.org/x/sync v0.16.0 // indirect golang.org/x/sys v0.33.0 // indirect golang.org/x/term v0.32.0 // indirect golang.org/x/text v0.26.0 // indirect - golang.org/x/time v0.9.0 // indirect + golang.org/x/time v0.11.0 // indirect + golang.org/x/tools v0.34.0 // indirect + golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect + gonum.org/v1/gonum v0.16.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect google.golang.org/grpc v1.73.0 // indirect google.golang.org/protobuf v1.36.6 // indirect + gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect + gopkg.in/fsnotify/fsnotify.v1 v1.4.7 // indirect gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect + gopkg.in/mail.v2 v2.3.1 // indirect + gopkg.in/src-d/go-errors.v1 v1.0.0 // indirect + gopkg.in/telebot.v3 v3.2.1 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/api v0.33.2 // indirect + k8s.io/api v0.33.3 // indirect k8s.io/apiextensions-apiserver v0.33.2 // indirect - k8s.io/client-go v0.33.2 // indirect - k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect - sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect + k8s.io/client-go v0.33.3 // indirect + k8s.io/component-base v0.33.3 // indirect + k8s.io/klog/v2 v2.130.1 // indirect + k8s.io/utils v0.0.0-20241210054802-24370beab758 // indirect + sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect + sigs.k8s.io/randfill v1.0.0 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect - sigs.k8s.io/yaml v1.4.0 // indirect + sigs.k8s.io/yaml v1.5.0 // indirect + xorm.io/builder v0.3.6 // indirect ) diff --git a/apps/advisor/go.sum b/apps/advisor/go.sum index 6019928ed89..2613bb8c90c 100644 --- a/apps/advisor/go.sum +++ b/apps/advisor/go.sum @@ -1,364 +1,1918 @@ +cel.dev/expr v0.23.1 h1:K4KOtPCJQjVggkARsjG9RWXP6O4R73aHeJMa/dmCQQg= +cel.dev/expr v0.23.1/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw= +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= +cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= +cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= +cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= +cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= +cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= +cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= +cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= +cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= +cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= +cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= +cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= +cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= +cloud.google.com/go v0.121.1 h1:S3kTQSydxmu1JfLRLpKtxRPA7rSrYPRPEUmL/PavVUw= +cloud.google.com/go v0.121.1/go.mod h1:nRFlrHq39MNVWu+zESP2PosMWA0ryJw8KUBZ2iZpxbw= +cloud.google.com/go/auth v0.16.1 h1:XrXauHMd30LhQYVRHLGvJiYeczweKQXZxsTbV9TiguU= +cloud.google.com/go/auth v0.16.1/go.mod h1:1howDHJ5IETh/LwYs3ZxvlkXF48aSqqJUM+5o02dNOI= +cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc= +cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= +cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= +cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= +cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= +cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= +cloud.google.com/go/compute/metadata v0.7.0 h1:PBWF+iiAerVNe8UCHxdOt6eHLVc3ydFeOCw78U8ytSU= +cloud.google.com/go/compute/metadata v0.7.0/go.mod h1:j5MvL9PprKL39t166CoB1uVHfQMs4tFQZZcKwksXUjo= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/firestore v1.6.1/go.mod h1:asNXNOzBdyVQmEU+ggO8UPodTkEVFW5Qx+rwHnAz+EY= +cloud.google.com/go/iam v1.5.2 h1:qgFRAGEmd8z6dJ/qyEchAuL9jpswyODjA2lS+w234g8= +cloud.google.com/go/iam v1.5.2/go.mod h1:SE1vg0N81zQqLzQEwxL2WI6yhetBdbNQuTvIKCSkUHE= +cloud.google.com/go/monitoring v1.24.2 h1:5OTsoJ1dXYIiMiuL+sYscLc9BumrL3CarVLL7dd7lHM= +cloud.google.com/go/monitoring v1.24.2/go.mod h1:x7yzPWcgDRnPEv3sI+jJGBkwl5qINf+6qY4eq0I9B4U= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= +cloud.google.com/go/storage v1.55.0 h1:NESjdAToN9u1tmhVqhXCaCwYBuvEhZLLv0gBr+2znf0= +cloud.google.com/go/storage v1.55.0/go.mod h1:ztSmTTwzsdXe5syLVS0YsbFxXuvEmEyZj7v7zChEmuY= +cuelang.org/go v0.11.1 h1:pV+49MX1mmvDm8Qh3Za3M786cty8VKPWzQ1Ho4gZRP0= +cuelang.org/go v0.11.1/go.mod h1:PBY6XvPUswPPJ2inpvUozP9mebDVTXaeehQikhZPBz0= +dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= +dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0 h1:Gt0j3wceWMwPmiazCa8MzMA0MfhmPIz0Qp0FJ6qcM0U= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0/go.mod h1:Ot/6aikWnKWi4l9QB7qVSwa8iMphQNqkWALMoNT3rzM= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.9.0 h1:OVoM452qUFBrX+URdH3VpR299ma4kfom0yB0URYky9g= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.9.0/go.mod h1:kUjrAo8bgEwLeZ/CmHqNl3Z/kPm7y6FKfxxK0izYUg4= +github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2 h1:yz1bePFlP5Vws5+8ez6T3HWXPmwOK7Yvq8QxDBD3SKY= +github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2/go.mod h1:Pa9ZNPuoNu/GztvBSKk9J1cDJW6vk/n0zLtV4mgd8N8= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1 h1:FPKJS1T+clwv+OLGt13a8UjqeRuh0O4SJ3lUriThc+4= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1/go.mod h1:j2chePtV91HrC22tGoRX3sGY42uF13WzmmV80/OdVAA= +github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.1 h1:lhZdRq7TIx0GJQvSyX2Si406vrYsov2FXGp/RnSEtcs= +github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.1/go.mod h1:8cl44BDmi+effbARHMQjgOKA2AYvcohNm7KEt42mSV8= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= +github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest/autorest v0.11.29 h1:I4+HL/JDvErx2LjyzaVxllw2lRDB5/BT2Bm4g20iqYw= +github.com/Azure/go-autorest/autorest/to v0.4.1 h1:CxNHBqdzTr7rLtdrtb5CMjJcDut+WNGCVv7OmS5+lTc= +github.com/Azure/go-autorest/autorest/to v0.4.1/go.mod h1:EtaofgU4zmtvn1zT2ARsjRFdq9vXx0YWtmElwL+GZ9M= +github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e h1:NeAW1fUYUEWhft7pkxDf6WoUvEZJ/uOKsvtpjLnn8MU= +github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= +github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 h1:WJTmL004Abzc5wDB5VtZG2PJk5ndYDgVacGqfirKxjM= +github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mod h1:tCcJZ0uHAmvjsVYzEFivsRTN00oz5BEsRgQHu5JZ9WE= +github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 h1:oygO0locgZJe7PpYPXT5A29ZkwJaPqcva7BVeemZOZs= +github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= +github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg= +github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.27.0 h1:ErKg/3iS1AKcTkf3yixlZ54f9U1rljCkQyEXWUnIUxc= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.27.0/go.mod h1:yAZHSGnqScoU556rBOVkwLze6WP5N+U11RHuWaGVxwY= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.51.0 h1:fYE9p3esPxA/C0rQ0AHhP0drtPXDRhaWiwg1DPqO7IU= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.51.0/go.mod h1:BnBReJLvVYx2CS/UHOgVz2BXKXD9wsQPxZug20nZhd0= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.51.0 h1:6/0iUd0xrnX7qt+mLNRwg5c0PGv8wpE8K90ryANQwMI= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.51.0/go.mod h1:otE2jQekW/PqXk1Awf5lmfokJx4uwuqcj1ab5SpGeW0= +github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= +github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= +github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= +github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= +github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0= +github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= +github.com/Masterminds/sprig/v3 v3.3.0 h1:mQh0Yrg1XPo6vjYXgtf5OtijNAKJRNcTdOOGZe3tPhs= +github.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSCzdgBfDb35Lz0= +github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= +github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I= +github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= +github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/ProtonMail/go-crypto v1.1.6 h1:ZcV+Ropw6Qn0AX9brlQLAUXfqLBc7Bl+f/DmNxpLfdw= +github.com/ProtonMail/go-crypto v1.1.6/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE= +github.com/RoaringBitmap/roaring v1.9.3 h1:t4EbC5qQwnisr5PrP9nt0IRhRTb9gMUgQF4t4S2OByM= +github.com/RoaringBitmap/roaring v1.9.3/go.mod h1:6AXUsoIEzDTFFQCe1RbGA6uFONMhvejWj5rqITANK90= +github.com/RoaringBitmap/roaring/v2 v2.4.5 h1:uGrrMreGjvAtTBobc0g5IrW1D5ldxDQYe2JW2gggRdg= +github.com/RoaringBitmap/roaring/v2 v2.4.5/go.mod h1:FiJcsfkGje/nZBZgCu0ZxCPOKD/hVXDS2dXi7/eUFE0= +github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= +github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= +github.com/VividCortex/mysqlerr v0.0.0-20170204212430-6c6b55f8796f h1:HR5nRmUQgXrwqZOwZ2DAc/aCi3Bu3xENpspW935vxu0= +github.com/VividCortex/mysqlerr v0.0.0-20170204212430-6c6b55f8796f/go.mod h1:f3HiCrHjHBdcm6E83vGaXh1KomZMA2P6aeo3hKx/wg0= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b h1:mimo19zliBX/vSQ6PWWSL9lK8qwHozUj03+zLoEB8O0= +github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b/go.mod h1:fvzegU4vN3H1qMT+8wDmzjAcDONcgo2/SZ/TyfdUOFs= +github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA= +github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ= +github.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw= +github.com/apache/arrow-go/v18 v18.3.0 h1:Xq4A6dZj9Nu33sqZibzn012LNnewkTUlfKVUFD/RX/I= +github.com/apache/arrow-go/v18 v18.3.0/go.mod h1:eEM1DnUTHhgGAjf/ChvOAQbUQ+EPohtDrArffvUjPg8= +github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/apache/thrift v0.21.0 h1:tdPmh/ptjE1IJnhbhrcl2++TauVjy242rkV/UzJChnE= +github.com/apache/thrift v0.21.0/go.mod h1:W1H8aR/QRtYNvrPeFXBtobyRkd0/YVhTc6i07XIAgDw= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= +github.com/at-wat/mqtt-go v0.19.4 h1:R2cbCU7O5PHQ38unbe1Y51ncG3KsFEJV6QeipDoqdLQ= +github.com/at-wat/mqtt-go v0.19.4/go.mod h1:AsiWc9kqVOhqq7LzUeWT/AkKUBfx3Sw5cEe8lc06fqA= +github.com/aws/aws-sdk-go v1.17.7/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.38.35/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/aws/aws-sdk-go v1.55.7 h1:UJrkFq7es5CShfBwlWAC8DA077vp8PyVbQd3lqLiztE= +github.com/aws/aws-sdk-go v1.55.7/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU= +github.com/aws/aws-sdk-go-v2 v1.36.5 h1:0OF9RiEMEdDdZEMqF9MRjevyxAQcf6gY+E7vwBILFj0= +github.com/aws/aws-sdk-go-v2 v1.36.5/go.mod h1:EYrzvCCN9CMUTa5+6lf6MM4tq3Zjp8UhSGR/cBsjai0= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.11 h1:12SpdwU8Djs+YGklkinSSlcrPyj3H4VifVsKf78KbwA= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.11/go.mod h1:dd+Lkp6YmMryke+qxW/VnKyhMBDTYP41Q2Bb+6gNZgY= +github.com/aws/aws-sdk-go-v2/config v1.29.17 h1:jSuiQ5jEe4SAMH6lLRMY9OVC+TqJLP5655pBGjmnjr0= +github.com/aws/aws-sdk-go-v2/config v1.29.17/go.mod h1:9P4wwACpbeXs9Pm9w1QTh6BwWwJjwYvJ1iCt5QbCXh8= +github.com/aws/aws-sdk-go-v2/credentials v1.17.70 h1:ONnH5CM16RTXRkS8Z1qg7/s2eDOhHhaXVd72mmyv4/0= +github.com/aws/aws-sdk-go-v2/credentials v1.17.70/go.mod h1:M+lWhhmomVGgtuPOhO85u4pEa3SmssPTdcYpP/5J/xc= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.32 h1:KAXP9JSHO1vKGCr5f4O6WmlVKLFFXgWYAGoJosorxzU= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.32/go.mod h1:h4Sg6FQdexC1yYG9RDnOvLbW1a/P986++/Y/a+GyEM8= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.69 h1:6VFPH/Zi9xYFMJKPQOX5URYkQoXRWeJ7V/7Y6ZDYoms= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.69/go.mod h1:GJj8mmO6YT6EqgduWocwhMoxTLFitkhIrK+owzrYL2I= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.36 h1:SsytQyTMHMDPspp+spo7XwXTP44aJZZAC7fBV2C5+5s= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.36/go.mod h1:Q1lnJArKRXkenyog6+Y+zr7WDpk4e6XlR6gs20bbeNo= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.36 h1:i2vNHQiXUvKhs3quBR6aqlgJaiaexz/aNvdCktW/kAM= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.36/go.mod h1:UdyGa7Q91id/sdyHPwth+043HhmP6yP9MBHgbZM0xo8= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 h1:bIqFDwgGXXN1Kpp99pDOdKMTTb5d2KyU5X/BZxjOkRo= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3/go.mod h1:H5O/EsxDWyU+LP/V8i5sm8cxoZgc2fdNR9bxlOFrQTo= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.34 h1:ZNTqv4nIdE/DiBfUUfXcLZ/Spcuz+RjeziUtNJackkM= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.34/go.mod h1:zf7Vcd1ViW7cPqYWEHLHJkS50X0JS2IKz9Cgaj6ugrs= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4 h1:CXV68E2dNqhuynZJPB80bhPQwAKqBWVer887figW6Jc= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4/go.mod h1:/xFi9KtvBXP97ppCz1TAEvU1Uf66qvid89rbem3wCzQ= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.0 h1:lguz0bmOoGzozP9XfRJR1QIayEYo+2vP/No3OfLF0pU= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.0/go.mod h1:iu6FSzgt+M2/x3Dk8zhycdIcHjEFb36IS8HVUVFoMg0= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.17 h1:t0E6FzREdtCsiLIoLCWsYliNsRBgyGD/MCK571qk4MI= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.17/go.mod h1:ygpklyoaypuyDvOM5ujWGrYWpAK3h7ugnmKCU/76Ys4= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.15 h1:moLQUoVq91LiqT1nbvzDukyqAlCv89ZmwaHw/ZFlFZg= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.15/go.mod h1:ZH34PJUc8ApjBIfgQCFvkWcUDBtl/WTD+uiYHjd8igA= +github.com/aws/aws-sdk-go-v2/service/s3 v1.78.2 h1:jIiopHEV22b4yQP2q36Y0OmwLbsxNWdWwfZRR5QRRO4= +github.com/aws/aws-sdk-go-v2/service/s3 v1.78.2/go.mod h1:U5SNqwhXB3Xe6F47kXvWihPl/ilGaEDe8HD/50Z9wxc= +github.com/aws/aws-sdk-go-v2/service/sso v1.25.5 h1:AIRJ3lfb2w/1/8wOOSqYb9fUKGwQbtysJ2H1MofRUPg= +github.com/aws/aws-sdk-go-v2/service/sso v1.25.5/go.mod h1:b7SiVprpU+iGazDUqvRSLf5XmCdn+JtT1on7uNL6Ipc= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.3 h1:BpOxT3yhLwSJ77qIY3DoHAQjZsc4HEGfMCE4NGy3uFg= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.3/go.mod h1:vq/GQR1gOFLquZMSrxUK/cpvKCNVYibNyJ1m7JrU88E= +github.com/aws/aws-sdk-go-v2/service/sts v1.34.0 h1:NFOJ/NXEGV4Rq//71Hs1jC/NvPs1ezajK+yQmkwnPV0= +github.com/aws/aws-sdk-go-v2/service/sts v1.34.0/go.mod h1:7ph2tGpfQvwzgistp2+zga9f+bCjlQJPkPUmMgDSD7w= +github.com/aws/smithy-go v1.22.4 h1:uqXzVZNuNexwc/xrh6Tb56u89WDlJY6HS+KC0S4QSjw= +github.com/aws/smithy-go v1.22.4/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI= +github.com/axiomhq/hyperloglog v0.0.0-20240507144631-af9851f82b27 h1:60m4tnanN1ctzIu4V3bfCNJ39BiOPSm1gHFlFjTkRE0= +github.com/axiomhq/hyperloglog v0.0.0-20240507144631-af9851f82b27/go.mod h1:k08r+Yj1PRAmuayFiRK6MYuR5Ve4IuZtTfxErMIh0+c= +github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= +github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= +github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o= +github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k= +github.com/bits-and-blooms/bitset v1.22.0 h1:Tquv9S8+SGaS3EhyA+up3FXzmkhxPGjQQCkcs2uw7w4= +github.com/bits-and-blooms/bitset v1.22.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= +github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= +github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= +github.com/blevesearch/bleve/v2 v2.5.0 h1:HzYqBy/5/M9Ul9ESEmXzN/3Jl7YpmWBdHM/+zzv/3k4= +github.com/blevesearch/bleve/v2 v2.5.0/go.mod h1:PcJzTPnEynO15dCf9isxOga7YFRa/cMSsbnRwnszXUk= +github.com/blevesearch/bleve_index_api v1.2.7 h1:c8r9vmbaYQroAMSGag7zq5gEVPiuXrUQDqfnj7uYZSY= +github.com/blevesearch/bleve_index_api v1.2.7/go.mod h1:rKQDl4u51uwafZxFrPD1R7xFOwKnzZW7s/LSeK4lgo0= +github.com/blevesearch/geo v0.1.20 h1:paaSpu2Ewh/tn5DKn/FB5SzvH0EWupxHEIwbCk/QPqM= +github.com/blevesearch/geo v0.1.20/go.mod h1:DVG2QjwHNMFmjo+ZgzrIq2sfCh6rIHzy9d9d0B59I6w= +github.com/blevesearch/go-faiss v1.0.25 h1:lel1rkOUGbT1CJ0YgzKwC7k+XH0XVBHnCVWahdCXk4U= +github.com/blevesearch/go-faiss v1.0.25/go.mod h1:OMGQwOaRRYxrmeNdMrXJPvVx8gBnvE5RYrr0BahNnkk= +github.com/blevesearch/go-porterstemmer v1.0.3 h1:GtmsqID0aZdCSNiY8SkuPJ12pD4jI+DdXTAn4YRcHCo= +github.com/blevesearch/go-porterstemmer v1.0.3/go.mod h1:angGc5Ht+k2xhJdZi511LtmxuEf0OVpvUUNrwmM1P7M= +github.com/blevesearch/gtreap v0.1.1 h1:2JWigFrzDMR+42WGIN/V2p0cUvn4UP3C4Q5nmaZGW8Y= +github.com/blevesearch/gtreap v0.1.1/go.mod h1:QaQyDRAT51sotthUWAH4Sj08awFSSWzgYICSZ3w0tYk= +github.com/blevesearch/mmap-go v1.0.4 h1:OVhDhT5B/M1HNPpYPBKIEJaD0F3Si+CrEKULGCDPWmc= +github.com/blevesearch/mmap-go v1.0.4/go.mod h1:EWmEAOmdAS9z/pi/+Toxu99DnsbhG1TIxUoRmJw/pSs= +github.com/blevesearch/scorch_segment_api/v2 v2.3.9 h1:X6nJXnNHl7nasXW+U6y2Ns2Aw8F9STszkYkyBfQ+p0o= +github.com/blevesearch/scorch_segment_api/v2 v2.3.9/go.mod h1:IrzspZlVjhf4X29oJiEhBxEteTqOY9RlYlk1lCmYHr4= +github.com/blevesearch/segment v0.9.1 h1:+dThDy+Lvgj5JMxhmOVlgFfkUtZV2kw49xax4+jTfSU= +github.com/blevesearch/segment v0.9.1/go.mod h1:zN21iLm7+GnBHWTao9I+Au/7MBiL8pPFtJBJTsk6kQw= +github.com/blevesearch/snowballstem v0.9.0 h1:lMQ189YspGP6sXvZQ4WZ+MLawfV8wOmPoD/iWeNXm8s= +github.com/blevesearch/snowballstem v0.9.0/go.mod h1:PivSj3JMc8WuaFkTSRDW2SlrulNWPl4ABg1tC/hlgLs= +github.com/blevesearch/upsidedown_store_api v1.0.2 h1:U53Q6YoWEARVLd1OYNc9kvhBMGZzVrdmaozG2MfoB+A= +github.com/blevesearch/upsidedown_store_api v1.0.2/go.mod h1:M01mh3Gpfy56Ps/UXHjEO/knbqyQ1Oamg8If49gRwrQ= +github.com/blevesearch/vellum v1.1.0 h1:CinkGyIsgVlYf8Y2LUQHvdelgXr6PYuvoDIajq6yR9w= +github.com/blevesearch/vellum v1.1.0/go.mod h1:QgwWryE8ThtNPxtgWJof5ndPfx0/YMBh+W2weHKPw8Y= +github.com/blevesearch/zapx/v11 v11.4.1 h1:qFCPlFbsEdwbbckJkysptSQOsHn4s6ZOHL5GMAIAVHA= +github.com/blevesearch/zapx/v11 v11.4.1/go.mod h1:qNOGxIqdPC1MXauJCD9HBG487PxviTUUbmChFOAosGs= +github.com/blevesearch/zapx/v12 v12.4.1 h1:K77bhypII60a4v8mwvav7r4IxWA8qxhNjgF9xGdb9eQ= +github.com/blevesearch/zapx/v12 v12.4.1/go.mod h1:QRPrlPOzAxBNMI0MkgdD+xsTqx65zbuPr3Ko4Re49II= +github.com/blevesearch/zapx/v13 v13.4.1 h1:EnkEMZFUK0lsW/jOJJF2xOcp+W8TjEsyeN5BeAZEYYE= +github.com/blevesearch/zapx/v13 v13.4.1/go.mod h1:e6duBMlCvgbH9rkzNMnUa9hRI9F7ri2BRcHfphcmGn8= +github.com/blevesearch/zapx/v14 v14.4.1 h1:G47kGCshknBZzZAtjcnIAMn3oNx8XBLxp8DMq18ogyE= +github.com/blevesearch/zapx/v14 v14.4.1/go.mod h1:O7sDxiaL2r2PnCXbhh1Bvm7b4sP+jp4unE9DDPWGoms= +github.com/blevesearch/zapx/v15 v15.4.1 h1:B5IoTMUCEzFdc9FSQbhVOxAY+BO17c05866fNruiI7g= +github.com/blevesearch/zapx/v15 v15.4.1/go.mod h1:b/MreHjYeQoLjyY2+UaM0hGZZUajEbE0xhnr1A2/Q6Y= +github.com/blevesearch/zapx/v16 v16.2.2 h1:MifKJVRTEhMTgSlle2bDRTb39BGc9jXFRLPZc6r0Rzk= +github.com/blevesearch/zapx/v16 v16.2.2/go.mod h1:B9Pk4G1CqtErgQV9DyCSA9Lb7WZe4olYfGw7fVDZ4sk= +github.com/bluele/gcache v0.0.2 h1:WcbfdXICg7G/DGBh1PFfcirkWOQV+v077yF1pSy3DGw= +github.com/bluele/gcache v0.0.2/go.mod h1:m15KV+ECjptwSPxKhOhQoAFQVtUFjTVkc3H8o0t/fp0= +github.com/blugelabs/bluge v0.2.2 h1:gat8CqE6P6tOgeX30XGLOVNTC26cpM2RWVcreXWtYcM= +github.com/blugelabs/bluge v0.2.2/go.mod h1:am1LU9jS8dZgWkRzkGLQN3757EgMs3upWrU2fdN9foE= +github.com/blugelabs/bluge_segment_api v0.2.0 h1:cCX1Y2y8v0LZ7+EEJ6gH7dW6TtVTW4RhG0vp3R+N2Lo= +github.com/blugelabs/bluge_segment_api v0.2.0/go.mod h1:95XA+ZXfRj/IXADm7gZ+iTcWOJPg5jQTY1EReIzl3LA= +github.com/blugelabs/ice v1.0.0 h1:um7wf9e6jbkTVCrOyQq3tKK43fBMOvLUYxbj3Qtc4eo= +github.com/blugelabs/ice v1.0.0/go.mod h1:gNfFPk5zM+yxJROhthxhVQYjpBO9amuxWXJQ2Lo+IbQ= +github.com/blugelabs/ice/v2 v2.0.1 h1:mzHbntLjk2v7eDRgoXCgzOsPKN1Tenu9Svo6l9cTLS4= +github.com/blugelabs/ice/v2 v2.0.1/go.mod h1:QxAWSPNwZwsIqS25c3lbIPFQrVvT1sphf5x5DfMLH5M= +github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 h1:N7oVaKyGp8bttX0bfZGmcGkjz7DLQXhAn3DNd3T0ous= github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874/go.mod h1:r5xuitiExdLAJ09PR7vBVENGvp4ZuTBeWTGtxuX3K+c= +github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA= +github.com/bufbuild/protocompile v0.4.0/go.mod h1:3v93+mbWn/v3xzN+31nwkJfrEpAUwp+BagBSZWx+TP8= +github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= +github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= +github.com/bwmarrin/snowflake v0.3.0 h1:xm67bEhkKh6ij1790JB83OujPR5CzNe8QuQqAgISZN0= +github.com/bwmarrin/snowflake v0.3.0/go.mod h1:NdZxfVWX+oR6y2K0o6qAYv6gIOP9rjG0/E9WsDpxqwE= +github.com/caio/go-tdigest v3.1.0+incompatible h1:uoVMJ3Q5lXmVLCCqaMGHLBWnbGoN6Lpu7OAUPR60cds= +github.com/caio/go-tdigest v3.1.0+incompatible/go.mod h1:sHQM/ubZStBUmF1WbB8FAm8q9GjDajLC5T7ydxE3JHI= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/cenkalti/backoff/v5 v5.0.2 h1:rIfFVxEf1QsI7E1ZHfp/B4DF/6QBAUhmgkxc0H7Zss8= +github.com/cenkalti/backoff/v5 v5.0.2/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE= +github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ= +github.com/chromedp/cdproto v0.0.0-20250429231605-6ed5b53462d4 h1:UZdrvid2JFwnvPlUSEFlE794XZL4Jmrj8fuxfcLECJE= +github.com/chromedp/cdproto v0.0.0-20250429231605-6ed5b53462d4/go.mod h1:NItd7aLkcfOA/dcMXvl8p1u+lQqioRMq/SqDp71Pb/k= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0= +github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20250326154945-ae57f3c0d45f h1:C5bqEmzEPLsHm9Mv73lSE9e9bKV23aB1vxOsmZrkl3k= +github.com/cncf/xds/go v0.0.0-20250326154945-ae57f3c0d45f/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= +github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= +github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= +github.com/cockroachdb/apd/v3 v3.2.1 h1:U+8j7t0axsIgvQUqthuNm82HIrYXodOV2iWLWtEaIwg= +github.com/cockroachdb/apd/v3 v3.2.1/go.mod h1:klXJcjp+FffLTHlhIG69tezTDvdP065naDsHzKhYSqc= +github.com/cockroachdb/cockroach-go v0.0.0-20181001143604-e0a95dfd547c/go.mod h1:XGLbWH/ujMcbPbhZq52Nv6UrCghb1yGn//133kEsvDk= +github.com/containerd/containerd v1.2.7/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4= +github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec= +github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.6 h1:XJtiaUW6dEEqVuZiMTn1ldk455QWwEIsMIJlo5vtkx0= +github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/cznic/b v0.0.0-20180115125044-35e9bbe41f07/go.mod h1:URriBxXwVq5ijiJ12C7iIZqlA69nTlI+LgI6/pwftG8= +github.com/cznic/fileutil v0.0.0-20180108211300-6a051e75936f/go.mod h1:8S58EK26zhXSxzv7NQFpnliaOQsmDUxvoQO3rt154Vg= +github.com/cznic/golex v0.0.0-20170803123110-4ab7c5e190e4/go.mod h1:+bmmJDNmKlhWNG+gwWCkaBoTy39Fs+bzRxVBzoTQbIc= +github.com/cznic/internal v0.0.0-20180608152220-f44710a21d00/go.mod h1:olo7eAdKwJdXxb55TKGLiJ6xt1H0/tiiRCWKVLmtjY4= +github.com/cznic/lldb v1.1.0/go.mod h1:FIZVUmYUVhPwRiPzL8nD/mpFcJ/G7SSXjjXYG4uRI3A= +github.com/cznic/mathutil v0.0.0-20180504122225-ca4c9f2c1369/go.mod h1:e6NPNENfs9mPDVNRekM7lKScauxd5kXTr1Mfyig6TDM= +github.com/cznic/ql v1.2.0/go.mod h1:FbpzhyZrqr0PVlK6ury+PoW3T0ODUV22OeWIxcaOrSE= +github.com/cznic/sortutil v0.0.0-20150617083342-4c7342852e65/go.mod h1:q2w6Bg5jeox1B+QkJ6Wp/+Vn0G/bo3f1uY7Fn3vivIQ= +github.com/cznic/strutil v0.0.0-20171016134553-529a34b1c186/go.mod h1:AHHPPPXTw0h6pVabbcbyGRK1DckRn7r/STdZEeIDzZc= +github.com/cznic/zappy v0.0.0-20160723133515-2533cb5b45cc/go.mod h1:Y1SNZ4dRUOKXshKUbwUapqNncRrho4mkjQebgEHZLj8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= -github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/denisenkom/go-mssqldb v0.0.0-20190515213511-eb9f6a1743f3/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM= +github.com/dennwc/varint v1.0.0 h1:kGNFFSSw8ToIy3obO/kKr8U9GZYUAxQEVuix4zfDWzE= +github.com/dennwc/varint v1.0.0/go.mod h1:hnItb35rvZvJrbTALZtY/iQfDs48JKRG1RPpgziApxA= +github.com/dgraph-io/badger/v4 v4.7.0 h1:Q+J8HApYAY7UMpL8d9owqiB+odzEc0zn/aqOD9jhc6Y= +github.com/dgraph-io/badger/v4 v4.7.0/go.mod h1:He7TzG3YBy3j4f5baj5B7Zl2XyfNe5bl4Udl0aPemVA= +github.com/dgraph-io/ristretto/v2 v2.2.0 h1:bkY3XzJcXoMuELV8F+vS8kzNgicwQFAaGINAEJdWGOM= +github.com/dgraph-io/ristretto/v2 v2.2.0/go.mod h1:RZrm63UmcBAaYWC1DotLYBmTvgkrs0+XhBd7Npn7/zI= +github.com/dgryski/go-metro v0.0.0-20180109044635-280f6062b5bc h1:8WFBn63wegobsYAX0YjD+8suexZDga5CctH4CCTx2+8= +github.com/dgryski/go-metro v0.0.0-20180109044635-280f6062b5bc/go.mod h1:c9O8+fpSOX1DM8cPNSkX/qsBWdkD4yd2dpciOWQjpBw= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= +github.com/dhui/dktest v0.3.0/go.mod h1:cyzIUfGsBEbZ6BT7tnXqAShHSXCZhSNmFl70sZ7c1yc= +github.com/dlmiddlecote/sqlstats v1.0.2 h1:gSU11YN23D/iY50A2zVYwgXgy072khatTsIW6UPjUtI= +github.com/dlmiddlecote/sqlstats v1.0.2/go.mod h1:0CWaIh/Th+z2aI6Q9Jpfg/o21zmGxWhbByHgQSCUQvY= +github.com/docker/distribution v2.7.0+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v0.7.3-0.20190103212154-2b7e084dc98b/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v0.7.3-0.20190817195342-4760db040282/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/dolthub/flatbuffers/v23 v23.3.3-dh.2 h1:u3PMzfF8RkKd3lB9pZ2bfn0qEG+1Gms9599cr0REMww= +github.com/dolthub/flatbuffers/v23 v23.3.3-dh.2/go.mod h1:mIEZOHnFx4ZMQeawhw9rhsj+0zwQj7adVsnBX7t+eKY= +github.com/dolthub/go-icu-regex v0.0.0-20250327004329-6799764f2dad h1:66ZPawHszNu37VPQckdhX1BPPVzREsGgNxQeefnlm3g= +github.com/dolthub/go-icu-regex v0.0.0-20250327004329-6799764f2dad/go.mod h1:ylU4XjUpsMcvl/BKeRRMXSH7e7WBrPXdSLvnRJYrxEA= +github.com/dolthub/go-mysql-server v0.19.1-0.20250410182021-5632d67cd46e h1:7pAttAqWaudUAsM9iHASi/4eFBK+qn4qeaNto7g8bK4= +github.com/dolthub/go-mysql-server v0.19.1-0.20250410182021-5632d67cd46e/go.mod h1:KZyoO3jngyZCLyCf100FEQTrwAHj33AIMj4Zv4u3MNE= +github.com/dolthub/jsonpath v0.0.2-0.20240227200619-19675ab05c71 h1:bMGS25NWAGTEtT5tOBsCuCrlYnLRKpbJVJkDbrTRhwQ= +github.com/dolthub/jsonpath v0.0.2-0.20240227200619-19675ab05c71/go.mod h1:2/2zjLQ/JOOSbbSboojeg+cAwcRV0fDLzIiWch/lhqI= +github.com/dolthub/vitess v0.0.0-20250410090211-143e6b272ad4 h1:LGTt2LtYX8vaai32d+c9L0sMcP+Dg9w1kO6+lbsxxYg= +github.com/dolthub/vitess v0.0.0-20250410090211-143e6b272ad4/go.mod h1:1gQZs/byeHLMSul3Lvl3MzioMtOW1je79QYGyi2fd70= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= +github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= +github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +github.com/elazarl/goproxy v1.7.2 h1:Y2o6urb7Eule09PjlhQRGNsqRfPmYI3KKQLFpCAV3+o= +github.com/elazarl/goproxy v1.7.2/go.mod h1:82vkLNir0ALaW14Rc399OTTjyNREgmdL2cVoIbS6XaE= +github.com/emicklei/go-restful/v3 v3.12.1 h1:PJMDIM/ak7btuL8Ex0iYET9hxM3CI2sjZtzpL63nKAU= +github.com/emicklei/go-restful/v3 v3.12.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= +github.com/envoyproxy/go-control-plane v0.13.4 h1:zEqyPVyku6IvWCFwux4x9RxkLOMUL+1vC9xUFv5l2/M= +github.com/envoyproxy/go-control-plane/envoy v1.32.4 h1:jb83lalDRZSpPWW2Z7Mck/8kXZ5CQAFYVjQcdVIr83A= +github.com/envoyproxy/go-control-plane/envoy v1.32.4/go.mod h1:Gzjc5k8JcJswLjAx1Zm+wSYE20UrLtt7JZMWiWQXQEw= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/envoyproxy/protoc-gen-validate v1.2.1 h1:DEo3O99U8j4hBFwbJfrz9VtgcDfUKS7KJ7spH3d86P8= +github.com/envoyproxy/protoc-gen-validate v1.2.1/go.mod h1:d/C80l/jxXLdfEIhX1W2TmLfsJ31lvEjwamM4DxlWXU= github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= +github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= +github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= +github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= +github.com/fsouza/fake-gcs-server v1.7.0/go.mod h1:5XIRs4YvwNbNoz+1JF8j6KLAyDh7RHGAyAK3EP2EsNk= +github.com/fullstorydev/grpchan v1.1.1 h1:heQqIJlAv5Cnks9a70GRL2EJke6QQoUB25VGR6TZQas= +github.com/fullstorydev/grpchan v1.1.1/go.mod h1:f4HpiV8V6htfY/K44GWV1ESQzHBTq7DinhzqQ95lpgc= github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= -github.com/getkin/kin-openapi v0.128.0 h1:jqq3D9vC9pPq1dGcOCv7yOp1DaEe7c/T1vzcLbITSp4= -github.com/getkin/kin-openapi v0.128.0/go.mod h1:OZrfXzUfGrNbsKj+xmFBx6E5c6yH3At/tAKSc2UszXM= -github.com/getkin/kin-openapi v0.131.0/go.mod h1:3OlG51PCYNsPByuiMB0t4fjnNlIDnaEDsjiKUV8nL58= +github.com/gchaincl/sqlhooks v1.3.0 h1:yKPXxW9a5CjXaVf2HkQn6wn7TZARvbAOAelr3H8vK2Y= +github.com/gchaincl/sqlhooks v1.3.0/go.mod h1:9BypXnereMT0+Ys8WGWHqzgkkOfHIhyeUCqXC24ra34= github.com/getkin/kin-openapi v0.132.0 h1:3ISeLMsQzcb5v26yeJrBcdTCEQTag36ZjaGk7MIRUwk= github.com/getkin/kin-openapi v0.132.0/go.mod h1:3OlG51PCYNsPByuiMB0t4fjnNlIDnaEDsjiKUV8nL58= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-asn1-ber/asn1-ber v1.5.4 h1:vXT6d/FNDiELJnLb6hGNa309LMsrCoYFvpwHDF0+Y1A= +github.com/go-asn1-ber/asn1-ber v1.5.4/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-jose/go-jose/v3 v3.0.4 h1:Wp5HA7bLQcKnf6YYao/4kpRpVMp/yf6+pJKV8WFSaNY= +github.com/go-jose/go-jose/v3 v3.0.4/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ= +github.com/go-jose/go-jose/v4 v4.1.0 h1:cYSYxd3pw5zd2FSXk2vGdn9igQU2PS8MuxrCOCl0FdY= +github.com/go-jose/go-jose/v4 v4.1.0/go.mod h1:GG/vqmYm3Von2nYiB2vGTXzdoNKE5tix5tuc6iAd+sw= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= +github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= +github.com/go-ldap/ldap/v3 v3.4.4 h1:qPjipEpt+qDa6SI/h1fzuGWoRUY+qqQ9sOZq67/PYUs= +github.com/go-ldap/ldap/v3 v3.4.4/go.mod h1:fe1MsuN5eJJ1FeLT/LEBVdWfNWKh459R7aXgXtJC+aI= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4= +github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= -github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-openapi/analysis v0.23.0 h1:aGday7OWupfMs+LbmLZG4k0MYXIANxcuBTYUC03zFCU= +github.com/go-openapi/analysis v0.23.0/go.mod h1:9mz9ZWaSlV8TvjQHLl2mUW2PbZtemkE8yA5v22ohupo= +github.com/go-openapi/errors v0.22.0 h1:c4xY/OLxUBSTiepAg3j/MHuAv5mJhnf53LLMWFB+u/w= +github.com/go-openapi/errors v0.22.0/go.mod h1:J3DmZScxCDufmIMsdOuDHxJbdOGC0xtUynjIx092vXE= github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= +github.com/go-openapi/loads v0.22.0 h1:ECPGd4jX1U6NApCGG1We+uEozOAvXvJSF4nnwHZ8Aco= +github.com/go-openapi/loads v0.22.0/go.mod h1:yLsaTCS92mnSAZX5WWoxszLj0u+Ojl+Zs5Stn1oF+rs= +github.com/go-openapi/runtime v0.28.0 h1:gpPPmWSNGo214l6n8hzdXYhPuJcGtziTOgUpvsFWGIQ= +github.com/go-openapi/runtime v0.28.0/go.mod h1:QN7OzcS+XuYmkQLw05akXk0jRH/eZ3kb18+1KwW9gyc= +github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY= +github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk= +github.com/go-openapi/strfmt v0.23.0 h1:nlUS6BCqcnAk0pyhi9Y+kdDVZdZMHfEKQiS4HaMgO/c= +github.com/go-openapi/strfmt v0.23.0/go.mod h1:NrtIpfKtWIygRkKVsxh7XQMDQW5HKQl6S5ik2elW+K4= github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= +github.com/go-openapi/validate v0.24.0 h1:LdfDKwNbpB6Vn40xhTdNZAnfLECL81w+VX3BumrGD58= +github.com/go-openapi/validate v0.24.0/go.mod h1:iyeX1sEufmv3nPbBdX3ieNviWnOZaJ1+zquzJEf2BAQ= +github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= +github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= +github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= +github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= +github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= +github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-sql-driver/mysql v1.9.2 h1:4cNKDYQ1I84SXslGddlsrMhc8k4LeDVj6Ad6WRjiHuU= +github.com/go-sql-driver/mysql v1.9.2/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= +github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= -github.com/go-viper/mapstructure/v2 v2.3.0 h1:27XbWsHIqhbdR5TIC911OfYvgSaW93HM+dX7970Q7jk= -github.com/go-viper/mapstructure/v2 v2.3.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:9wScpmSP5A3Bk8V3XHWUcJmYTh+ZnlHVyc+A4oZYS3Y= +github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:56xuuqnHyryaerycW3BfssRdxQstACi0Epw/yC5E2xM= +github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= +github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= +github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= +github.com/goccy/go-yaml v1.9.5/go.mod h1:U/jl18uSupI5rdI2jmuCswEA2htH9eXfferR3KfscvA= +github.com/gocql/gocql v0.0.0-20190301043612-f6df8288f9b4/go.mod h1:4Fw1eo5iaEhDUs8XyuhSVCVy52Jq3L+/3GJgYkwc+/0= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA= +github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gogo/googleapis v1.4.1 h1:1Yx4Myt7BxzvUr5ldGSbwYiZG6t9wGBZ+8/fX3Wvtq0= +github.com/gogo/googleapis v1.4.1/go.mod h1:2lpHqI5OcWCtVElxXnPt+s8oJvMpySlOyM6xDCrzib4= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/gogo/status v1.1.1 h1:DuHXlSFHNKqTQ+/ACf5Vs6r4X/dH2EgIzR9Vr+H65kg= +github.com/gogo/status v1.1.1/go.mod h1:jpG3dM5QPcqu19Hg8lkUhBFBa3TcLs1DG7+2Jqci7oU= +github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI= +github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8= +github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang-migrate/migrate/v4 v4.7.0 h1:gONcHxHApDTKXDyLH/H97gEHmpu1zcnnbAaq2zgrPrs= +github.com/golang-migrate/migrate/v4 v4.7.0/go.mod h1:Qvut3N4xKWjoH3sokBccML6WyHSnggXm/DvMMnTsQIc= +github.com/golang/geo v0.0.0-20210211234256-740aa86cb551 h1:gtexQ/VGyN+VVFRXSFiguSNcXmS6rkKT+X7FdIrTtfo= +github.com/golang/geo v0.0.0-20210211234256-740aa86cb551/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ= +github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +github.com/golang/mock v1.7.0-rc.1 h1:YojYx61/OLFsiv6Rw1Z96LpldJIy31o+UHmwAUMJ6/U= +github.com/golang/mock v1.7.0-rc.1/go.mod h1:s42URUywIqd+OcERslBJvOjepvNymP31m3q8d/GkuRs= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= -github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= -github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= +github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs= +github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= +github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= +github.com/google/cel-go v0.25.0 h1:jsFw9Fhn+3y2kBbltZR4VEz5xKkcIFRPDnuEzAGv5GY= +github.com/google/cel-go v0.25.0/go.mod h1:hjEb6r5SuOSlhCHmFoLzu8HGCERvIsDAbxDAyNU/MmI= +github.com/google/flatbuffers v25.2.10+incompatible h1:F3vclr7C3HpB1k9mxCGRMXq6FdUalZ6H/pNX4FP1v0Q= +github.com/google/flatbuffers v25.2.10+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= +github.com/google/gnostic-models v0.6.9 h1:MU/8wDLif2qCXZmzncUQ/BOfxWfthHi63KqpoNbWqVw= github.com/google/gnostic-models v0.6.9/go.mod h1:CiWsm0s6BSQd1hRn8/QmxqB6BesYcbSZxsz9b0KuDBw= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= +github.com/google/go-github/v70 v70.0.0 h1:/tqCp5KPrcvqCc7vIvYyFYTiCGrYvaWoYMGHSQbo55o= +github.com/google/go-github/v70 v70.0.0/go.mod h1:xBUZgo8MI3lUL/hwxl3hlceJW1U8MVnXP3zUyI+rhQY= +github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= +github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= -github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg= -github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J0b1vyeLSOYI8bm5wbJM/8yDe8= +github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0= +github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM= +github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/grafana/authlib v0.0.0-20250515162837-2f4a8263eabb h1:oTl2j6/4miQUYmXANp2pBuYCWA5f8NVYFfCWpczpFso= -github.com/grafana/authlib v0.0.0-20250515162837-2f4a8263eabb/go.mod h1:PBtQaXwkFu4BAt2aXsR7w8p8NVpdjV5aJYhqRDei9Us= -github.com/grafana/grafana-app-sdk v0.30.0 h1:Hqn2pETu2mQ4RpWkZYEQfu01P7xd1Z1Gj+HX/8aB0tw= -github.com/grafana/grafana-app-sdk v0.30.0/go.mod h1:jhfqNIovb+Mes2vdMf9iMCWQkp1GTNtyNuExONtiNuk= -github.com/grafana/grafana-app-sdk v0.31.0/go.mod h1:Xw00NL7qpRLo5r3Gn48Bl1Xn2n4eUDI5pYf/wMufKWs= -github.com/grafana/grafana-app-sdk v0.35.1/go.mod h1:Zx5MkVppYK+ElSDUAR6+fjzOVo6I/cIgk+ty+LmNOxI= -github.com/grafana/grafana-app-sdk v0.38.3-0.20250708143121-df8ec27cecb5 h1:5EvbpsK3MMoLj4X8831DZ+k/uXwQrwwM65pE0W9knfg= -github.com/grafana/grafana-app-sdk v0.38.3-0.20250708143121-df8ec27cecb5/go.mod h1:3BP1layBA+/vm6niDfw66HwNnDyUCX99tUcX0p5/ErA= -github.com/grafana/grafana-app-sdk v0.38.3-0.20250709183049-aef07c9d3145 h1:4VpspqAe3zz3GniPkdFvwXhNwWhQKQmKWc7R80VbkyQ= -github.com/grafana/grafana-app-sdk v0.38.3-0.20250709183049-aef07c9d3145/go.mod h1:3BP1layBA+/vm6niDfw66HwNnDyUCX99tUcX0p5/ErA= -github.com/grafana/grafana-app-sdk v0.39.0/go.mod h1:xRyBQOttgWTc3tGe9pI0upnpEPVhzALf7Mh/61O4zyY= -github.com/grafana/grafana-app-sdk v0.39.2 h1:ymfr+1318t+JC9U2OYrzVpGmNG/aJONUmFFu/G98Xh8= -github.com/grafana/grafana-app-sdk v0.39.2/go.mod h1:t0m6q561lpoHQCixS9LUHFUhUzDClzNtm7BH60gHVSY= +github.com/google/wire v0.6.0 h1:HBkoIh4BdSxoyo9PveV8giw7ZsaBOvzWKfcg/6MrVwI= +github.com/google/wire v0.6.0/go.mod h1:F4QhpQ9EDIdJ1Mbop/NZBRB+5yrR6qg3BnctaoUk6NA= +github.com/googleapis/enterprise-certificate-proxy v0.3.6 h1:GW/XbdyBFQ8Qe+YAmFU9uHLo7OnF5tL52HFAgMmyrf4= +github.com/googleapis/enterprise-certificate-proxy v0.3.6/go.mod h1:MkHOF77EYAE7qfSuSS9PU6g4Nt4e11cnsDUowfwewLA= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= +github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= +github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= +github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= +github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= +github.com/googleapis/gax-go/v2 v2.14.2 h1:eBLnkZ9635krYIPD+ag1USrOAI0Nr0QYF3+/3GqO0k0= +github.com/googleapis/gax-go/v2 v2.14.2/go.mod h1:ON64QhlJkhVtSqp4v1uaK92VyZ2gmvDQsweuyLV+8+w= +github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= +github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e h1:JKmoR8x90Iww1ks85zJ1lfDGgIiMDuIptTOhJq+zKyg= +github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= +github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +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-20250725130805-615c8286e14b h1:mfUAq/N+mS82EcE35hDXWtfVY7UhTjzZxzssvFt9tvQ= +github.com/grafana/alerting v0.0.0-20250725130805-615c8286e14b/go.mod h1:VKxaR93Gff0ZlO2sPcdPVob1a/UzArFEW5zx3Bpyhls= +github.com/grafana/authlib v0.0.0-20250710201142-9542f2f28d43 h1:vVPT0i5Y1vI6qzecYStV2yk7cHKrC3Pc7AgvwT5KydQ= +github.com/grafana/authlib v0.0.0-20250710201142-9542f2f28d43/go.mod h1:1fWkOiL+m32NBgRHZtlZGz2ji868tPZACYbqP3nBRJI= +github.com/grafana/authlib/types v0.0.0-20250710201142-9542f2f28d43 h1:NlkGMnVi/oUn6Cr90QbJYpQJ4FnjyAIG9Ex5GtTZIzw= +github.com/grafana/authlib/types v0.0.0-20250710201142-9542f2f28d43/go.mod h1:qeWYbnWzaYGl88JlL9+DsP1GT2Cudm58rLtx13fKZdw= +github.com/grafana/dataplane/examples v0.0.1 h1:K9M5glueWyLoL4//H+EtTQq16lXuHLmOhb6DjSCahzA= +github.com/grafana/dataplane/examples v0.0.1/go.mod h1:h5YwY8s407/17XF5/dS8XrUtsTVV2RnuW8+m1Mp46mg= +github.com/grafana/dataplane/sdata v0.0.9 h1:AGL1LZnCUG4MnQtnWpBPbQ8ZpptaZs14w6kE/MWfg7s= +github.com/grafana/dataplane/sdata v0.0.9/go.mod h1:Jvs5ddpGmn6vcxT7tCTWAZ1mgi4sbcdFt9utQx5uMAU= +github.com/grafana/dskit v0.0.0-20250611075409-46f51e1ce914 h1:qcSGhr691f1mmPHwg2svGyO40Ex92G02aOyHzP6XHCE= +github.com/grafana/dskit v0.0.0-20250611075409-46f51e1ce914/go.mod h1:OiN4P4aC6LwLzLbEupH3Ue83VfQoNMfG48rsna8jI/E= github.com/grafana/grafana-app-sdk v0.40.0 h1:KilbCFMYox2cnIi1W6ql7W+n9kms/NvWlBPM1m4Q4mg= github.com/grafana/grafana-app-sdk v0.40.0/go.mod h1:fn943JEM0CR3mY/Gd3816MUcpob5xnKc8MoojnbMjYY= -github.com/grafana/grafana-app-sdk/logging v0.29.0 h1:mgbXaAf33aFwqwGVeaX30l8rkeAJH0iACgX5Rn6YkN4= -github.com/grafana/grafana-app-sdk/logging v0.29.0/go.mod h1:xy6ZyVXl50Z3DBDLybvBPphbykPhuVNed/VNmen9DQM= -github.com/grafana/grafana-app-sdk/logging v0.30.0/go.mod h1:xy6ZyVXl50Z3DBDLybvBPphbykPhuVNed/VNmen9DQM= -github.com/grafana/grafana-app-sdk/logging v0.35.0/go.mod h1:Y/bvbDhBiV/tkIle9RW49pgfSPIPSON8Q4qjx3pyqDk= -github.com/grafana/grafana-app-sdk/logging v0.38.2/go.mod h1:Y/bvbDhBiV/tkIle9RW49pgfSPIPSON8Q4qjx3pyqDk= -github.com/grafana/grafana-app-sdk/logging v0.39.2/go.mod h1:WhDENSnaGHtyVVwZGVnAR7YLvh2xlLDYR3D7E6h7XVk= +github.com/grafana/grafana-app-sdk/logging v0.39.3 h1:mMrcYahnoRu7blKyL/ZVcgv7WCiI2CqxODYh8tBFUgY= github.com/grafana/grafana-app-sdk/logging v0.39.3/go.mod h1:otUD9XpJD7A5sCLb8mcs9hIXGdeV6lnhzVwe747g4RU= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 h1:VNqngBF40hVlDloBruUehVYC3ArSgIyScOAyMRqBxRg= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1/go.mod h1:RBRO7fro65R6tjKzYgLAFo0t1QEXY1Dp+i/bvpRiqiQ= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1/go.mod h1:tIxuGz/9mpox++sgp9fJjHO0+q1X9/UOWd798aAm22M= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI= +github.com/grafana/grafana-aws-sdk v1.0.4 h1:D14UAehsOqpjliHmHzveRQ1p43KCsMzdmb7GovWj+SY= +github.com/grafana/grafana-aws-sdk v1.0.4/go.mod h1:hO7q7yWV+t6dmiyJjMa3IbuYnYkBua+G/IAlOPVIYKE= +github.com/grafana/grafana-azure-sdk-go/v2 v2.1.6 h1:OfCkitCuomzZKW1WYHrG8MxKwtMhALb7jqoj+487eTg= +github.com/grafana/grafana-azure-sdk-go/v2 v2.1.6/go.mod h1:V7y2BmsWxS3A9Ohebwn4OiSfJJqi//4JQydQ8fHTduo= +github.com/grafana/grafana-plugin-sdk-go v0.278.0 h1:5/rIYparLi02pofdaag8wnjspMMVNCi8cZhC4cdC3Ho= +github.com/grafana/grafana-plugin-sdk-go v0.278.0/go.mod h1:+8NXT/XUJ/89GV6FxGQ366NZ3nU+cAXDMd0OUESF9H4= +github.com/grafana/grafana/apps/dashboard v0.0.0-20250716132114-6fd75ebc5441 h1:+TSbaxCXBZrKkdROWBzdWna8uStE1f9LYd7GiqjVfz8= +github.com/grafana/grafana/apps/dashboard v0.0.0-20250716132114-6fd75ebc5441/go.mod h1:1XWiRSVuDQiayapHhQiDc4S4e9GzEZgg/3GeNCuDgn4= +github.com/grafana/grafana/apps/folder v0.0.0-20250627191313-2f1a6ae1712b h1:31MwoIKKT9Ay0ZjbT4lkfcPijiWogUWzXs2EjrCgodI= +github.com/grafana/grafana/apps/folder v0.0.0-20250627191313-2f1a6ae1712b/go.mod h1:dLtYBp1pza5HYalezNvzlP8JDeKrZ5BKTonDgEOE0NY= +github.com/grafana/grafana/apps/secret v0.0.0-20250711114246-c9b2126c4ad5 h1:+fMhUoqwGdY8ntH0GL2icJa3uk+bTiIMicawDG2r9Uc= +github.com/grafana/grafana/apps/secret v0.0.0-20250711114246-c9b2126c4ad5/go.mod h1:TIrKvhgo2j6lvVeOZ3TUmXbI4I48d6v7QcadL/f6SKQ= +github.com/grafana/grafana/pkg/aggregator v0.0.0-20250627191313-2f1a6ae1712b h1:ei01IFqmnXkOrrVvsT3CYe+i5xYra3SCX7Wsu3PMsDU= +github.com/grafana/grafana/pkg/aggregator v0.0.0-20250627191313-2f1a6ae1712b/go.mod h1:+H4Va9jDJlGQJjAN+OFD/hLx2I/yEzDRMQLaKecvgAc= +github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250725144121-b1592b5e36d2 h1:lvmcK9XOJUJiYhl2kH4nwAKOUdq+ug+ueIGqfKlip3E= +github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250725144121-b1592b5e36d2/go.mod h1:3ZgUe0E3rIhI026xF4DKFptOst/jpDHJ/Sn+bRODzI4= +github.com/grafana/grafana/pkg/apiserver v0.0.0-20250627191313-2f1a6ae1712b h1:QyJLJn3xwFTIXu9KPZujsrIUN0X8DdiR9b2h75L0AfI= +github.com/grafana/grafana/pkg/apiserver v0.0.0-20250627191313-2f1a6ae1712b/go.mod h1:6OKkPWDB8PetDXqMVMOWL35iTCEUdpATwwpuew0k8+o= +github.com/grafana/grafana/pkg/promlib v0.0.8 h1:VUWsqttdf0wMI4j9OX9oNrykguQpZcruudDAFpJJVw0= +github.com/grafana/grafana/pkg/promlib v0.0.8/go.mod h1:U1ezG/MGaEPoThqsr3lymMPN5yIPdVTJnDZ+wcXT+ao= +github.com/grafana/grafana/pkg/semconv v0.0.0-20250627191313-2f1a6ae1712b h1:m78RNSvTseSpvwQYe5HcdsiADSw4vj6+QUppuCL63gw= +github.com/grafana/grafana/pkg/semconv v0.0.0-20250627191313-2f1a6ae1712b/go.mod h1:mu3yl0GxB0eQZV1q7Kka0pkF3Th9x7W04WrjR9wqBlc= +github.com/grafana/otel-profiling-go v0.5.1 h1:stVPKAFZSa7eGiqbYuG25VcqYksR6iWvF3YH66t4qL8= +github.com/grafana/otel-profiling-go v0.5.1/go.mod h1:ftN/t5A/4gQI19/8MoWurBEtC6gFw8Dns1sJZ9W4Tls= +github.com/grafana/prometheus-alertmanager v0.25.1-0.20250620093340-be61a673dee6 h1:oJnbhG6ZNy10AjsgNeAtAKeGHogIGOMfAsBH6fYYa5M= +github.com/grafana/prometheus-alertmanager v0.25.1-0.20250620093340-be61a673dee6/go.mod h1:O/QP1BCm0HHIzbKvgMzqb5sSyH88rzkFk84F4TfJjBU= +github.com/grafana/pyroscope-go/godeltaprof v0.1.8 h1:iwOtYXeeVSAeYefJNaxDytgjKtUuKQbJqgAIjlnicKg= +github.com/grafana/pyroscope-go/godeltaprof v0.1.8/go.mod h1:2+l7K7twW49Ct4wFluZD3tZ6e0SjanjcUUBPVD/UuGU= +github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc h1:GN2Lv3MGO7AS6PrRoT6yV5+wkrOpcszoIsO4+4ds248= +github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc/go.mod h1:+JKpmjMGhpgPL+rXZ5nsZieVzvarn86asRlBg4uNGnk= +github.com/grafana/sqlds/v4 v4.2.3 h1:9ibD1c5O5u9fifEkBSig+jAc41TUEz+M+bWQqDsofP4= +github.com/grafana/sqlds/v4 v4.2.3/go.mod h1:bv+XHabfUF4xkgg4y+nYFCK8rpMHZsMaQk56qNaJcAM= +github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0 h1:QGLs/O40yoNK9vmy4rhUGBVyMf1lISBGtXRpsu/Qu/o= +github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0/go.mod h1:hM2alZsMUni80N33RBe6J0e423LB+odMj7d3EMP9l20= +github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.2 h1:sGm2vDRFUrQJO/Veii4h4zG2vvqG6uWNkBHSTqXOZk0= +github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.2/go.mod h1:wd1YpapPLivG6nQgbf7ZkG1hhSOXDhhn4MLTknx2aAc= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20191002090509-6af20e3a5340 h1:uGoIog/wiQHI9GAxXO5TJbT0wWKH3O9HhOJW1F9c3fY= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20191002090509-6af20e3a5340/go.mod h1:3bDW6wMZJB7tiONtC/1Xpicra6Wp5GgbTbQWCbI5fkc= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1 h1:X5VWvz21y3gzm9Nw/kaUeku/1+uBhcekkmy4IkffJww= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1/go.mod h1:Zanoh4+gvIgluNqcfMVTJueD4wSS5hT7zTt4Mrutd90= +github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4= +github.com/hashicorp/consul/api v1.12.0/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= +github.com/hashicorp/consul/api v1.31.2 h1:NicObVJHcCmyOIl7Z9iHPvvFrocgTYo9cITSGg0/7pw= +github.com/hashicorp/consul/api v1.31.2/go.mod h1:Z8YgY0eVPukT/17ejW+l+C7zJmKwgPHtjU1q16v/Y40= +github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v1.2.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= +github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-metrics v0.5.4 h1:8mmPiIJkTPPEbAiV97IxdAGNdRdaWwVap1BU6elejKY= +github.com/hashicorp/go-metrics v0.5.4/go.mod h1:CG5yz4NZ/AI/aQt9Ucm/vdBnbh7fvmv4lxZ350i+QQI= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-msgpack/v2 v2.1.2 h1:4Ee8FTp834e+ewB71RDrQ0VKpyFdrKOjvYtnQ/ltVj0= +github.com/hashicorp/go-msgpack/v2 v2.1.2/go.mod h1:upybraOAblm4S7rx0+jeNy+CWWhzywQsSRV5033mMu4= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= -github.com/invopop/yaml v0.3.1 h1:f0+ZpmhfBSS4MhG+4HYseMdJhoeeopbSKbq5Rpeelso= -github.com/invopop/yaml v0.3.1/go.mod h1:PMOp3nn4/12yEZUFfmOuNHJsZToEEOwoWsT+D81KkeA= +github.com/hashicorp/go-plugin v1.6.3 h1:xgHB+ZUSYeuJi96WtxEjzi23uh7YQpznjGh0U0UUrwg= +github.com/hashicorp/go-plugin v1.6.3/go.mod h1:MRobyh+Wc/nYy1V4KAXUiYfzxoYhs7V1mlH1Z7iY2h0= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-sockaddr v1.0.7 h1:G+pTkSO01HpR5qCxg7lxfsFEZaG+C0VssTy/9dbT+Fw= +github.com/hashicorp/go-sockaddr v1.0.7/go.mod h1:FZQbEYa1pxkQ7WLpyXJ6cbjpT8q0YgQaK/JakXqGyWw= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= +github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= +github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= +github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= +github.com/hashicorp/memberlist v0.5.2 h1:rJoNPWZ0juJBgqn48gjy59K5H4rNgvUoM1kUD7bXiuI= +github.com/hashicorp/memberlist v0.5.2/go.mod h1:Ri9p/tRShbjYnpNf4FFPXG7wxEGY4Nrcn6E7jrVa//4= +github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= +github.com/hashicorp/serf v0.9.7/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= +github.com/hashicorp/serf v0.10.2 h1:m5IORhuNSjaxeljg5DeQVDlQyVkhRIjJDimbkCa8aAc= +github.com/hashicorp/serf v0.10.2/go.mod h1:T1CmSGfSeGfnfNy/w0odXQUR1rfECGd2Qdsp84DjOiY= +github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE= +github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI= +github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/invopop/jsonschema v0.13.0 h1:KvpoAJWEjR3uD9Kbm2HWJmqsEaHt8lBUpd0qHcIi21E= +github.com/invopop/jsonschema v0.13.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0= +github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ= +github.com/jackc/pgx v3.2.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= +github.com/jaegertracing/jaeger-idl v0.5.0 h1:zFXR5NL3Utu7MhPg8ZorxtCBjHrL3ReM1VoB65FOFGE= +github.com/jaegertracing/jaeger-idl v0.5.0/go.mod h1:ON90zFo9eoyXrt9F/KN8YeF3zxcnujaisMweFY/rg5k= +github.com/jessevdk/go-flags v1.5.0 h1:1jKYvbxEjfUl0fmqTCOfonvskHHXMjBySTLW4y9LFvc= +github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= +github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c= +github.com/jhump/protoreflect v1.15.1/go.mod h1:jD/2GMKKE6OqX8qTjhADU1e6DShO+gavG9e0Q693nKo= +github.com/jmespath-community/go-jmespath v1.1.1 h1:bFikPhsi/FdmlZhVgSCd2jj1e7G/rw+zyQfyg5UF+L4= +github.com/jmespath-community/go-jmespath v1.1.1/go.mod h1:4gOyFJsR/Gk+05RgTKYrifT7tBPWD8Lubtb5jRrfy9I= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g= +github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/jszwedko/go-datemath v0.1.1-0.20230526204004-640a500621d6 h1:SwcnSwBR7X/5EHJQlXBockkJVIMRVt5yKaesBPMtyZQ= +github.com/jszwedko/go-datemath v0.1.1-0.20230526204004-640a500621d6/go.mod h1:WrYiIuiXUMIvTDAQw97C+9l0CnBmCcvosPjN3XDqS/o= +github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8= +github.com/keybase/go-keychain v0.0.1 h1:way+bWYa6lDppZoZcgMbYsvC7GxljxrskdNInRtuthU= +github.com/keybase/go-keychain v0.0.1/go.mod h1:PdEILRW3i9D8JcdM+FmY6RwkHGnhHxXwkPPMeUgOK1k= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= -github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= +github.com/klauspost/asmfmt v1.3.2 h1:4Ri7ox3EwapiOjCki+hw14RyKk201CN4rzyCJRFLpK4= +github.com/klauspost/asmfmt v1.3.2/go.mod h1:AG8TuvYojzulgDAMCnYn50l/5QV3Bs/tp6j0HLHbNSE= +github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= +github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE= +github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kshvakov/clickhouse v1.3.5/go.mod h1:DMzX7FxRymoNkVgizH0DWAL8Cur7wHLgx3MUnGwJqpE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= +github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc h1:RKf14vYWi2ttpEmkA4aQ3j4u9dStX2t4M8UM6qqNsG8= +github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc/go.mod h1:kopuH9ugFRkIXf3YoqHKyrJ9YfUFsckUU9S7B+XP+is= +github.com/lestrrat-go/strftime v1.0.4 h1:T1Rb9EPkAhgxKqbcMIPguPq8glqXTA1koF8n9BHElA8= +github.com/lestrrat-go/strftime v1.0.4/go.mod h1:E1nN3pCbtMSu1yjSVeyuRFVm/U0xoR76fd03sz+Qz4g= +github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= +github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/magefile/mage v1.15.0 h1:BvGheCMAsG3bWUDbZ8AyXXpCNwU9u5CB6sM+HNb9HYg= +github.com/magefile/mage v1.15.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= +github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= +github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= +github.com/mattbaird/jsonpatch v0.0.0-20240118010651-0ba75a80ca38 h1:hQWBtNqRYrI7CWIaUSXXtNKR90KzcUA5uiuxFVWw7sU= +github.com/mattbaird/jsonpatch v0.0.0-20240118010651-0ba75a80ca38/go.mod h1:M1qoD/MqPgTZIk0EWKB38wE28ACRfVcn+cU08jyArI0= +github.com/mattetti/filebuffer v1.0.1 h1:gG7pyfnSIZCxdoKq+cPa8T0hhYtD9NxCdI4D7PTjRLM= +github.com/mattetti/filebuffer v1.0.1/go.mod h1:YdMURNDOttIiruleeVr6f56OrMc+MydEnTcXwtkxNVs= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= +github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= +github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= +github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= +github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U= +github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA= +github.com/mdlayher/vsock v1.2.1 h1:pC1mTJTvjo1r9n9fbm7S1j04rCgCzhCOS5DY0zqHlnQ= +github.com/mdlayher/vsock v1.2.1/go.mod h1:NRfCibel++DgeMD8z/hP+PPTjlNJsdPOmxcnENvE+SE= +github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= +github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= +github.com/miekg/dns v1.1.63 h1:8M5aAw6OMZfFXTT7K5V0Eu5YiiL8l7nUAkyN6C9YwaY= +github.com/miekg/dns v1.1.63/go.mod h1:6NGHfjhpmr5lt3XPLuyfDJi5AXbNIPM9PY6H6sF1Nfs= +github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8 h1:AMFGa4R4MiIpspGNG7Z948v4n35fFGB3RR3G/ry4FWs= +github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcsrzbxHt8iiaC+zU4b1ylILSosueou12R++wfY= +github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3 h1:+n/aFZefKZp7spd8DFdX7uMikMLXX4oubIzJF4kv/wI= +github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3/go.mod h1:RagcQ7I8IeTMnF8JTXieKnO4Z6JCsikNEzj0DwauVzE= +github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.1-0.20231216201459-8508981c8b6c h1:cqn374mizHuIWj+OSJCajGr/phAmuMug9qIX3l9CflE= +github.com/mitchellh/mapstructure v1.5.1-0.20231216201459-8508981c8b6c/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/mithrandie/csvq v1.18.1 h1:f7NB2scbb7xx2ffPduJ2VtZ85RpWXfvanYskAkGlCBU= +github.com/mithrandie/csvq v1.18.1/go.mod h1:MRJj7AtcXfk7jhNGxLuJGP3LORmh4lpiPWxQ7VyCRn8= +github.com/mithrandie/csvq-driver v1.7.0 h1:ejiavXNWwTPMyr3fJFnhcqd1L1cYudA0foQy9cZrqhw= +github.com/mithrandie/csvq-driver v1.7.0/go.mod h1:HcN3xL9UCJnBYA/AIQOOB/KlyfXAiYr5yxDmiwrGk5o= +github.com/mithrandie/go-file/v2 v2.1.0 h1:XA5Tl+73GXMDvgwSE3Sg0uC5FkLr3hnXs8SpUas0hyg= +github.com/mithrandie/go-file/v2 v2.1.0/go.mod h1:9YtTF3Xo59GqC1Pxw6KyGVcM/qubAMlxVsqI/u9r++c= +github.com/mithrandie/go-text v1.6.0 h1:8gOXTMPbMY8DJbKMTv8kHhADcJlDWXqS/YQH4SyWO6s= +github.com/mithrandie/go-text v1.6.0/go.mod h1:xCgj1xiNbI/d4xA9sLVvXkjh5B2tNx2ZT2/3rpmh8to= +github.com/mithrandie/ternary v1.1.1 h1:k/joD6UGVYxHixYmSR8EGgDFNONBMqyD373xT4QRdC4= +github.com/mithrandie/ternary v1.1.1/go.mod h1:0D9Ba3+09K2TdSZO7/bFCC0GjSXetCvYuYq0u8FY/1g= +github.com/mocktools/go-smtp-mock/v2 v2.3.1 h1:wq75NDSsOy5oHo/gEQQT0fRRaYKRqr1IdkjhIPXxagM= +github.com/mocktools/go-smtp-mock/v2 v2.3.1/go.mod h1:h9AOf/IXLSU2m/1u4zsjtOM/WddPwdOUBz56dV9f81M= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= +github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/mschoch/smat v0.2.0 h1:8imxQsjDm8yFEAVBe7azKmKSgzSkZXDuKkSq9374khM= +github.com/mschoch/smat v0.2.0/go.mod h1:kc9mz7DoBKqDyiRL7VZN8KvXQMWeTaVnttLRXOlotKw= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/onsi/ginkgo/v2 v2.21.0 h1:7rg/4f3rB88pb5obDgNZrNHrQ4e6WpjonchcpuBRnZM= -github.com/onsi/ginkgo/v2 v2.21.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo= -github.com/onsi/gomega v1.35.1 h1:Cwbd75ZBPxFSuZ6T+rN/WCb/gOc6YgFBXLlZLhC7Ds4= -github.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog= -github.com/openfga/openfga v1.8.12 h1:xEirA6tFwaJfjBDtbHWCK0/Tw+B8XleRyhg9dcEpzHo= -github.com/openfga/openfga v1.8.12/go.mod h1:fIZyekdNB+tWQ6zIiglZonAc5ErZiDGMeHue/BzRYRM= -github.com/openfga/openfga v1.8.13 h1:ROURkotKhbmtyBX3188+cNElN8AOZmTl0CMkxUqwawo= -github.com/openfga/openfga v1.8.13/go.mod h1:h1VGcVW81eY1YyDtFx5+gxxAIEhIiOGR9SRGgs/X/k8= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/nakagami/firebirdsql v0.0.0-20190310045651-3c02a58cfed8/go.mod h1:86wM1zFnC6/uDBfZGNwB65O+pR2OFi5q/YQaEUid1qA= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 h1:G7ERwszslrBzRxj//JalHPu/3yz+De2J+4aLtSRlHiY= +github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037/go.mod h1:2bpvgLBZEtENV5scfDFEtB/5+1M4hkQhDQrccEJ/qGw= +github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 h1:bQx3WeLcUWy+RletIKwUIt4x3t8n2SxavmoclizMb8c= +github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90/go.mod h1:y5+oSEHCPT/DGrS++Wc/479ERge0zTFxaF8PbGKcg2o= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= +github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= +github.com/onsi/ginkgo/v2 v2.22.2 h1:/3X8Panh8/WwhU/3Ssa6rCKqPLuAkVY2I0RoyDLySlU= +github.com/onsi/ginkgo/v2 v2.22.2/go.mod h1:oeMosUL+8LtarXBHu/c0bx2D/K9zyQ6uX3cTyztHwsk= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8= +github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY= +github.com/open-feature/go-sdk v1.14.1 h1:jcxjCIG5Up3XkgYwWN5Y/WWfc6XobOhqrIwjyDBsoQo= +github.com/open-feature/go-sdk v1.14.1/go.mod h1:t337k0VB/t/YxJ9S0prT30ISUHwYmUd/jhUZgFcOvGg= +github.com/open-feature/go-sdk-contrib/providers/go-feature-flag v0.2.3 h1:6jpO63NCEZv4xunJj+aNlDuFVuRkVBPMcIuxvFPYRWQ= +github.com/open-feature/go-sdk-contrib/providers/go-feature-flag v0.2.3/go.mod h1:dPUHjAIFzg+ci/wt6XxlNiiMkOh5Yw4SGyeRY0AFT0g= +github.com/open-feature/go-sdk-contrib/providers/ofrep v0.1.5 h1:ZdqlGnNwhWf3luhBQlIpbglvcCzjkcuEgOEhYhr5Emc= +github.com/open-feature/go-sdk-contrib/providers/ofrep v0.1.5/go.mod h1:jrD4UG3ZCzuwImKHlyuIN2iWeYjlOX5+zJ/sX45efuE= +github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opentracing-contrib/go-stdlib v1.0.0 h1:TBS7YuVotp8myLon4Pv7BtCBzOTo1DeZCld0Z63mW2w= +github.com/opentracing-contrib/go-stdlib v1.0.0/go.mod h1:qtI1ogk+2JhVPIXVc6q+NHziSmy2W5GbdQZFUHADCBU= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= +github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= +github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= +github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= +github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= +github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas= +github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= +github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s= github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw= +github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU= +github.com/pierrec/lz4/v4 v4.1.22/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= +github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= +github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo= +github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y= -github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= -github.com/prometheus/client_golang v1.21.1/go.mod h1:U9NM32ykUErtVBxdvD3zfi+EuFkkaBvMb09mIfe0Zgg= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q= github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0= -github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= -github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= -github.com/prometheus/common v0.61.0 h1:3gv/GThfX0cV2lpO7gkTUwZru38mxevy90Bj8YFSRQQ= -github.com/prometheus/common v0.61.0/go.mod h1:zr29OCN/2BsJRaFwG8QOBr41D6kkchKbpeNH7pAjb/s= -github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I= -github.com/prometheus/common v0.63.0/go.mod h1:VVFF/fBIoToEnWRVkYoXEkq3R3paCoxG9PXP74SnV18= -github.com/prometheus/common v0.64.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8= -github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= -github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= -github.com/prometheus/procfs v0.16.0/go.mod h1:8veyXUu3nGP7oaCxhX6yeaM5u4stL2FeMXnCqhDthZg= +github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/common v0.29.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/common v0.65.0 h1:QDwzd+G1twt//Kwj/Ww6E9FQq1iVMmODnILtW1t2VzE= +github.com/prometheus/common v0.65.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8= +github.com/prometheus/common/sigv4 v0.1.0 h1:qoVebwtwwEhS85Czm2dSROY5fTo2PAPEVdDeppTwGX4= +github.com/prometheus/common/sigv4 v0.1.0/go.mod h1:2Jkxxk9yYvCkE5G1sQT7GuEXm57JrvHu9k5YwTjsNtI= +github.com/prometheus/exporter-toolkit v0.14.0 h1:NMlswfibpcZZ+H0sZBiTjrA3/aBFHkNZqE+iCj5EmRg= +github.com/prometheus/exporter-toolkit v0.14.0/go.mod h1:Gu5LnVvt7Nr/oqTBUC23WILZepW0nffNo10XdhQcwWA= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= +github.com/prometheus/prometheus v0.303.1 h1:He/2jRE6sB23Ew38AIoR1WRR3fCMgPlJA2E0obD2WSY= +github.com/prometheus/prometheus v0.303.1/go.mod h1:WEq2ogBPZoLjj9x5K67VEk7ECR0nRD9XCjaOt1lsYck= github.com/puzpuzpuz/xsync/v2 v2.5.1 h1:mVGYAvzDSu52+zaGyNjC+24Xw2bQi3kTr4QJ6N9pIIU= github.com/puzpuzpuz/xsync/v2 v2.5.1/go.mod h1:gD2H2krq/w52MfPLE+Uy64TzJDVY7lP2znR9qmR35kU= -github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= -github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= -github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/redis/go-redis/v9 v9.7.3 h1:YpPyAayJV+XErNsatSElgRZZVCwXX9QzkKYNvO7x0wM= +github.com/redis/go-redis/v9 v9.7.3/go.mod h1:bGUrSggJ9X9GUmZpZNEOQKaANxSGgOEBRltRTZHSvrA= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= +github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= +github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= +github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA= +github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/sagikazarmark/crypt v0.6.0/go.mod h1:U8+INwJo3nBv1m6A/8OBXAq7Jnpspk5AxSgDyEQcea8= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= +github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= +github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= +github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c h1:aqg5Vm5dwtvL+YgDpBcK1ITf3o96N/K7/wsRXQnUTEs= +github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c/go.mod h1:owqhoLW1qZoYLZzLnBw+QkPP9WZnjlSWihhxAJC1+/M= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546 h1:pXY9qYc/MP5zdvqWEUH6SjNiu7VhSjuVFTFiTcphaLU= +github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304 h1:Jpy1PXuP99tXNrhbq2BaPz9B+jNAvH1JPQQpG/9GCXY= +github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c h1:Ho+uVpkel/udgjbwB5Lktg9BtvJSh2DT0Hi6LPSyI2w= +github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo= +github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= +github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y= +github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= +github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= +github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.13.0/go.mod h1:Icm2xNL3/8uyh/wFuB1jI7TiTNKp8632Nwegu+zgdYw= +github.com/spiffe/go-spiffe/v2 v2.5.0 h1:N2I01KCUkv1FAjZXJMwh95KK1ZIQLYbPfhaxw8WS0hE= +github.com/spiffe/go-spiffe/v2 v2.5.0/go.mod h1:P+NxobPc6wXhVtINNtFjNWGBTreew1GBUCwT2wPmb7g= +github.com/stoewer/go-strcase v1.3.0 h1:g0eASXYtp+yvN9fK8sH94oCIk0fau9uV1/ZdJ0AVEzs= +github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.7.5/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= +github.com/teris-io/shortid v0.0.0-20171029131806-771a37caa5cf h1:Z2X3Os7oRzpdJ75iPqWZc0HeJWFYNCvKsfpQwFpRNTA= +github.com/teris-io/shortid v0.0.0-20171029131806-771a37caa5cf/go.mod h1:M8agBzgqHIhgj7wEn9/0hJUZcrvt9VY+Ln+S1I5Mha0= +github.com/tetratelabs/wazero v1.8.2 h1:yIgLR/b2bN31bjxwXHD8a3d+BogigR952csSDdLYEv4= +github.com/tetratelabs/wazero v1.8.2/go.mod h1:yAI0XTsMBhREkM/YDAK/zNou3GoiAce1P6+rp/wQhjs= +github.com/tidwall/pretty v0.0.0-20180105212114-65a9db5fad51/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/tjhop/slog-gokit v0.1.3 h1:6SdexP3UIeg93KLFeiM1Wp1caRwdTLgsD/THxBUy1+o= +github.com/tjhop/slog-gokit v0.1.3/go.mod h1:Bbu5v2748qpAWH7k6gse/kw3076IJf6owJmh7yArmJs= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +github.com/uber/jaeger-client-go v2.30.0+incompatible h1:D6wyKGCecFaSRUpo8lCVbaOOb6ThwMmTEbhRwtKR97o= +github.com/uber/jaeger-client-go v2.30.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= +github.com/uber/jaeger-lib v2.4.1+incompatible h1:td4jdvLcExb4cBISKIpHuGoVXh+dVKhn2Um6rjCsSsg= +github.com/uber/jaeger-lib v2.4.1+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/unknwon/bra v0.0.0-20200517080246-1e3013ecaff8 h1:aVGB3YnaS/JNfOW3tiHIlmNmTDg618va+eT0mVomgyI= +github.com/unknwon/bra v0.0.0-20200517080246-1e3013ecaff8/go.mod h1:fVle4kNr08ydeohzYafr20oZzbAkhQT39gKK/pFQ5M4= +github.com/unknwon/com v1.0.1 h1:3d1LTxD+Lnf3soQiD4Cp/0BRB+Rsa/+RTvz8GMMzIXs= +github.com/unknwon/com v1.0.1/go.mod h1:tOOxU81rwgoCLoOVVPHb6T/wt8HZygqH5id+GNnlCXM= +github.com/unknwon/log v0.0.0-20150304194804-e617c87089d3/go.mod h1:1xEUf2abjfP92w2GZTV+GgaRxXErwRXcClbUwrNJffU= +github.com/unknwon/log v0.0.0-20200308114134-929b1006e34a h1:vcrhXnj9g9PIE+cmZgaPSwOyJ8MAQTRmsgGrB0x5rF4= +github.com/unknwon/log v0.0.0-20200308114134-929b1006e34a/go.mod h1:1xEUf2abjfP92w2GZTV+GgaRxXErwRXcClbUwrNJffU= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli v1.22.16 h1:MH0k6uJxdwdeWQTwhSO42Pwr4YLrNLwBtg1MRgTqPdQ= +github.com/urfave/cli v1.22.16/go.mod h1:EeJR6BKodywf4zciqrdw6hpCPk68JO9z5LazXZMn5Po= +github.com/wk8/go-ordered-map v1.0.0 h1:BV7z+2PaK8LTSd/mWgY12HyMAo5CEgkHqbkVq2thqr8= +github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc= +github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= +github.com/xanzy/go-gitlab v0.15.0/go.mod h1:8zdQa/ri1dfn8eS3Ir1SyfvOKlw7WBJ8DVThkpGiXrs= +github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= +github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ= +github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= +github.com/zeebo/errs v1.4.0 h1:XNdoD/RRMKP7HD0UhJnIzUy74ISdGGxURlYG8HSWSfM= +github.com/zeebo/errs v1.4.0/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4= +github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0= +github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= +gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b/go.mod h1:T3BPAOm2cqquPa0MKWeNkmOM5RQsRhkrwMWonFMN7fE= +go.etcd.io/bbolt v1.4.0 h1:TU77id3TnN/zKr7CO/uk+fBCwF2jGcMuw2B/FMAzYIk= +go.etcd.io/bbolt v1.4.0/go.mod h1:AsD+OCi/qPN1giOX1aiLAha3o1U8rAz65bvN4j0sRuk= +go.etcd.io/etcd/api/v3 v3.5.4/go.mod h1:5GB2vv4A4AOn3yk7MftYGHkUfGtDHnEraIjym4dYz5A= +go.etcd.io/etcd/api/v3 v3.5.21 h1:A6O2/JDb3tvHhiIz3xf9nJ7REHvtEFJJ3veW3FbCnS8= +go.etcd.io/etcd/api/v3 v3.5.21/go.mod h1:c3aH5wcvXv/9dqIw2Y810LDXJfhSYdHQ0vxmP3CCHVY= +go.etcd.io/etcd/client/pkg/v3 v3.5.4/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= +go.etcd.io/etcd/client/pkg/v3 v3.5.21 h1:lPBu71Y7osQmzlflM9OfeIV2JlmpBjqBNlLtcoBqUTc= +go.etcd.io/etcd/client/pkg/v3 v3.5.21/go.mod h1:BgqT/IXPjK9NkeSDjbzwsHySX3yIle2+ndz28nVsjUs= +go.etcd.io/etcd/client/v2 v2.305.4/go.mod h1:Ud+VUwIi9/uQHOMA+4ekToJ12lTxlv0zB/+DHwTGEbU= +go.etcd.io/etcd/client/v3 v3.5.4/go.mod h1:ZaRkVgBZC+L+dLCjTcF1hRXpgZXQPOvnA/Ak/gq3kiY= +go.etcd.io/etcd/client/v3 v3.5.21 h1:T6b1Ow6fNjOLOtM0xSoKNQt1ASPCLWrF9XMHcH9pEyY= +go.etcd.io/etcd/client/v3 v3.5.21/go.mod h1:mFYy67IOqmbRf/kRUvsHixzo3iG+1OF2W2+jVIQRAnU= +go.mongodb.org/mongo-driver v1.1.0/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= +go.mongodb.org/mongo-driver v1.16.1 h1:rIVLL3q0IHM39dvE+z2ulZLp9ENZKThVfuvN/IiN4l8= +go.mongodb.org/mongo-driver v1.16.1/go.mod h1:oB6AhJQvFQL4LEHyXi6aJzQJtBiTQHiAd83l0GdFaiw= +go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= +go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= -go.opentelemetry.io/otel v1.33.0 h1:/FerN9bax5LoK51X/sI0SVYrjSE0/yUL7DpxW4K3FWw= -go.opentelemetry.io/otel v1.33.0/go.mod h1:SUUkR6csvUQl+yjReHu5uM3EtVV7MBm5FHKRlNx4I8I= -go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI= -go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y= -go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E= +go.opentelemetry.io/contrib/bridges/prometheus v0.61.0 h1:RyrtJzu5MAmIcbRrwg75b+w3RlZCP0vJByDVzcpAe3M= +go.opentelemetry.io/contrib/bridges/prometheus v0.61.0/go.mod h1:tirr4p9NXbzjlbruiRGp53IzlYrDk5CO2fdHj0sSSaY= +go.opentelemetry.io/contrib/detectors/gcp v1.36.0 h1:F7q2tNlCaHY9nMKHR6XH9/qkp8FktLnIcy6jJNyOCQw= +go.opentelemetry.io/contrib/detectors/gcp v1.36.0/go.mod h1:IbBN8uAIIx734PTonTPxAxnjc2pQTxWNkwfstZ+6H2k= +go.opentelemetry.io/contrib/exporters/autoexport v0.61.0 h1:XfzKtKSrbtYk9TNCF8dkO0Y9M7IOfb4idCwBOTwGBiI= +go.opentelemetry.io/contrib/exporters/autoexport v0.61.0/go.mod h1:N6otC+qXTD5bAnbK2O1f/1SXq3cX+3KYSWrkBUqG0cw= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0 h1:x7wzEgXfnzJcHDwStJT+mxOz4etr2EcexjqhBvmoakw= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0/go.mod h1:rg+RlpR5dKwaS95IyyZqj5Wd4E13lk/msnTS0Xl9lJM= +go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.61.0 h1:lREC4C0ilyP4WibDhQ7Gg2ygAQFP8oR07Fst/5cafwI= +go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.61.0/go.mod h1:HfvuU0kW9HewH14VCOLImqKvUgONodURG7Alj/IrnGI= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 h1:Hf9xI/XLML9ElpiHVDNwvqI0hIFlzV8dgIr35kV1kRU= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0/go.mod h1:NfchwuyNoMcZ5MLHwPrODwUF1HWCXWrL31s8gSAdIKY= +go.opentelemetry.io/contrib/propagators/jaeger v1.36.0 h1:SoCgXYF4ISDtNyfLUzsGDaaudZVTx2yJhOyBO0+/GYk= +go.opentelemetry.io/contrib/propagators/jaeger v1.36.0/go.mod h1:VHu48l0YTRKSObdPQ+Sb8xMZvdnJlN7yhHuHoPgNqHM= +go.opentelemetry.io/contrib/samplers/jaegerremote v0.30.0 h1:bQ1Gvah4Sp8z7epSkgJaNTuZm7sutfA6Fji2/7cKFMc= +go.opentelemetry.io/contrib/samplers/jaegerremote v0.30.0/go.mod h1:9b8Q9rH52NgYH3ShiTFB5wf18Vt3RTH/VMB7LDcC1ug= +go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= +go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ= go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.33.0 h1:Vh5HayB/0HHfOQA7Ctx69E/Y/DcQSMPpKANYVMQ7fBA= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.33.0/go.mod h1:cpgtDBaqD/6ok/UG0jT15/uKjAY8mRA53diogHBg3UI= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0/go.mod h1:7Bept48yIeqxP2OZ9/AqIpYS94h2or0aB4FypJTc8ZM= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0/go.mod h1:zjPK58DtkqQFn+YUMbx0M2XV3QgKU0gS9LeGohREyK4= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.36.0/go.mod h1:90PoxvaEB5n6AOdZvi+yWJQoE95U8Dhhw2bSyRqnTD0= +go.opentelemetry.io/otel/exporters/jaeger v1.17.0 h1:D7UpUy2Xc2wsi1Ras6V40q806WM07rqoCWzXu7Sqy+4= +go.opentelemetry.io/otel/exporters/jaeger v1.17.0/go.mod h1:nPCqOnEH9rNLKqH/+rrUjiMzHJdV1BlpKcTwRTyKkKI= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.12.2 h1:06ZeJRe5BnYXceSM9Vya83XXVaNGe3H1QqsvqRANQq8= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.12.2/go.mod h1:DvPtKE63knkDVP88qpatBj81JxN+w1bqfVbsbCbj1WY= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.12.2 h1:tPLwQlXbJ8NSOfZc4OkgU5h2A38M4c9kfHSVc4PFQGs= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.12.2/go.mod h1:QTnxBwT/1rBIgAG1goq6xMydfYOBKU6KTiYF4fp5zL8= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.37.0 h1:zG8GlgXCJQd5BU98C0hZnBbElszTmUgCNCfYneaDL0A= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.37.0/go.mod h1:hOfBCz8kv/wuq73Mx2H2QnWokh/kHZxkh6SNF2bdKtw= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.37.0 h1:9PgnL3QNlj10uGxExowIDIZu66aVBwWhXmbOp1pa6RA= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.37.0/go.mod h1:0ineDcLELf6JmKfuo0wvvhAVMuxWFYvkTin2iV4ydPQ= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0 h1:Ahq7pZmv87yiyn3jeFz/LekZmPLLdKejuO3NcK9MssM= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0/go.mod h1:MJTqhM0im3mRLw1i8uGHnCvUEeS7VwRyxlLC78PA18M= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.33.0 h1:5pojmb1U1AogINhN3SurB+zm/nIcusopeBNp42f45QM= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.33.0/go.mod h1:57gTHJSE5S1tqg+EKsLPlTWhpHMsWlVmer+LA926XiA= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.34.0/go.mod h1:U7HYyW0zt/a9x5J1Kjs+r1f/d4ZHnYFclhYY2+YbeoE= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0/go.mod h1:LjReUci/F4BUyv+y4dwnq3h/26iNOeC3wAIqgvTIZVo= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.36.0/go.mod h1:179AK5aar5R3eS9FucPy6rggvU0g52cvKId8pv4+v0c= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0 h1:EtFWSnwW9hGObjkIdmlnWSydO+Qs8OwzfzXLUPg4xOc= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0/go.mod h1:QjUEoiGCPkvFZ/MjK6ZZfNOS6mfVEVKYE99dFhuN2LI= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.33.0 h1:wpMfgF8E1rkrT1Z6meFh1NDtownE9Ii3n3X2GJYjsaU= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.33.0/go.mod h1:wAy0T/dUbs468uOlkT31xjvqQgEVXv58BRFWEgn5v/0= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.34.0/go.mod h1:9cKLGBDzI/F3NoHLQGm4ZrYdIHsvGt6ej6hUowxY0J4= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0/go.mod h1:u5BF1xyjstDowA1R5QAO9JHzqK+ublenEW/dyqTjBVk= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.36.0/go.mod h1:r49hO7CgrxY9Voaj3Xe8pANWtr0Oq916d0XAmOoCZAQ= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.37.0 h1:bDMKF3RUSxshZ5OjOTi8rsHGaPKsAt76FaqgvIUySLc= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.37.0/go.mod h1:dDT67G/IkA46Mr2l9Uj7HsQVwsjASyV9SjGofsiUZDA= -go.opentelemetry.io/otel/metric v1.33.0 h1:r+JOocAyeRVXD8lZpjdQjzMadVZp2M4WmQ+5WtEnklQ= -go.opentelemetry.io/otel/metric v1.33.0/go.mod h1:L9+Fyctbp6HFTddIxClbQkjtubW6O9QS3Ann/M82u6M= -go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE= -go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE= -go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs= +go.opentelemetry.io/otel/exporters/prometheus v0.59.0 h1:HHf+wKS6o5++XZhS98wvILrLVgHxjA/AMjqHKes+uzo= +go.opentelemetry.io/otel/exporters/prometheus v0.59.0/go.mod h1:R8GpRXTZrqvXHDEGVH5bF6+JqAZcK8PjJcZ5nGhEWiE= +go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.12.2 h1:12vMqzLLNZtXuXbJhSENRg+Vvx+ynNilV8twBLBsXMY= +go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.12.2/go.mod h1:ZccPZoPOoq8x3Trik/fCsba7DEYDUnN6yX79pgp2BUQ= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.36.0 h1:rixTyDGXFxRy1xzhKrotaHy3/KXdPhlWARrCgK+eqUY= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.36.0/go.mod h1:dowW6UsM9MKbJq5JTz2AMVp3/5iW5I/TStsk8S+CfHw= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.37.0 h1:SNhVp/9q4Go/XHBkQ1/d5u9P/U+L1yaGPoi0x+mStaI= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.37.0/go.mod h1:tx8OOlGH6R4kLV67YaYO44GFXloEjGPZuMjEkaaqIp4= +go.opentelemetry.io/otel/log v0.12.2 h1:yob9JVHn2ZY24byZeaXpTVoPS6l+UrrxmxmPKohXTwc= +go.opentelemetry.io/otel/log v0.12.2/go.mod h1:ShIItIxSYxufUMt+1H5a2wbckGli3/iCfuEbVZi/98E= +go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM= +go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE= go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E= -go.opentelemetry.io/otel/sdk v1.33.0 h1:iax7M131HuAm9QkZotNHEfstof92xM+N8sr3uHXc2IM= -go.opentelemetry.io/otel/sdk v1.33.0/go.mod h1:A1Q5oi7/9XaMlIWzPSxLRWOI8nG3FnzHJNbiENQuihM= -go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU= -go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg= -go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY= +go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E= +go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI= go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg= -go.opentelemetry.io/otel/sdk/metric v1.31.0 h1:i9hxxLJF/9kkvfHppyLL55aW7iIJz4JjxTeYusH7zMc= -go.opentelemetry.io/otel/sdk/metric v1.31.0/go.mod h1:CRInTMVvNhUKgSAMbKyTMxqOBC0zgyxzW55lZzX43Y8= -go.opentelemetry.io/otel/trace v1.33.0 h1:cCJuF7LRjUFso9LPnEAHJDB2pqzp+hbO8eu1qqW2d/s= -go.opentelemetry.io/otel/trace v1.33.0/go.mod h1:uIcdVUZMpTAmz0tI1z04GoVSezK37CbGV4fr1f2nBck= -go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE= -go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc= -go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA= +go.opentelemetry.io/otel/sdk/log v0.12.2 h1:yNoETvTByVKi7wHvYS6HMcZrN5hFLD7I++1xIZ/k6W0= +go.opentelemetry.io/otel/sdk/log v0.12.2/go.mod h1:DcpdmUXHJgSqN/dh+XMWa7Vf89u9ap0/AAk/XGLnEzY= +go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFhbjxHHspCPc= +go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps= +go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= +go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4= go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0= -go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4= -go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4= -go.opentelemetry.io/proto/otlp v1.6.0/go.mod h1:cicgGehlFuNdgZkcALOCh3VE6K/u2tAjzlRhDwmVpZc= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.opentelemetry.io/proto/otlp v1.7.0 h1:jX1VolD6nHuFzOYso2E73H85i92Mv8JQYk0K9vz09os= go.opentelemetry.io/proto/otlp v1.7.0/go.mod h1:fSKjH6YJ7HDlwzltzyMj036AJ3ejJLCgCSHGj4efDDo= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= +go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI= +go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU= +go.yaml.in/yaml/v3 v3.0.3 h1:bXOww4E/J3f66rav3pX3m8w6jDE4knZjGOw8b5Y6iNE= +go.yaml.in/yaml/v3 v3.0.3/go.mod h1:tBHosrYAkRZjRAOREWbDnBXUf08JOwYq++0QNwQiWzI= +gocloud.dev v0.42.0 h1:qzG+9ItUL3RPB62/Amugws28n+4vGZXEoJEAMfjutzw= +gocloud.dev v0.42.0/go.mod h1:zkaYAapZfQisXOA4bzhsbA4ckiStGQ3Psvs9/OQ5dPM= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8= -golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 h1:y5zboxd6LQAqYIhHnB48p0ByQ/GnQx2BE33L8BOHQkI= +golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6/go.mod h1:U6Lno4MTRCDY+Ba7aCcauB9T60gsv5s4ralQzP72ZoQ= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w= +golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181108082009-03003ca0c849/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190424112056-4829fb13d2c6/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0= -golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= -golang.org/x/net v0.36.0 h1:vWF2fRbw4qslQsQzgFqZff+BItCvGFQqKzKIzx1rmoA= -golang.org/x/net v0.36.0/go.mod h1:bFmbeoIPfrw4sMHNhb4J9f6+tPziuGjq7Jk/38fxi1I= -golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY= -golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E= -golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY= -golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= +golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= +golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= +golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= -golang.org/x/oauth2 v0.25.0 h1:CY4y7XT9v0cRI9oupztF8AgiIu99L/ksR/Xp/6jrZ70= -golang.org/x/oauth2 v0.25.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= -golang.org/x/oauth2 v0.27.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= -golang.org/x/oauth2 v0.29.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= -golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= -golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= -golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220513210516-0976fa681c29/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190102155601-82a175fd1598/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190426135247-a129542de9ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191020152052-9984515f0562/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= -golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg= -golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek= -golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s= -golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= +golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg= golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= -golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= -golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= -golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU= -golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= -golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY= -golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0= +golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190425222832-ad9eeb80039a/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.29.0 h1:Xx0h3TtM9rzQpQuR4dKLrdglAmCEN5Oi+P74JdhdzXE= -golang.org/x/tools v0.29.0/go.mod h1:KMQVMRsVxU6nHCFXrBPhDB8XncLNLM0lIy/F14RP588= +golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= +golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo= +golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= -gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= +golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da h1:noIWHXmPHxILtqtCOPIhSt0ABwskkZKjD3bXGnZGpNY= +golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= +gomodules.xyz/jsonpatch/v2 v2.5.0 h1:JELs8RLM12qJGXU4u/TO3V25KW8GreMKl9pdkk14RM0= gomodules.xyz/jsonpatch/v2 v2.5.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= -google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d h1:H8tOf8XM88HvKqLTxe755haY6r1fqqzLbEnfrmLXlSA= -google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d/go.mod h1:2v7Z7gP2ZUOGsaFyxATQSRoBnKygqVq2Cwnvom7QiqY= -google.golang.org/genproto/googleapis/api v0.0.0-20250115164207-1a7da9e5054f/go.mod h1:Ic02D47M+zbarjYYUlK57y316f2MoN0gjAwI3f2S95o= -google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a/go.mod h1:3kWAYMk1I75K4vykHtKt2ycnOgpA6974V7bREqbsenU= -google.golang.org/genproto/googleapis/api v0.0.0-20250428153025-10db94c68c34/go.mod h1:0awUlEkap+Pb1UMeJwJQQAdJQrt3moU7J2moTy69irI= -google.golang.org/genproto/googleapis/api v0.0.0-20250519155744-55703ea1f237/go.mod h1:ezi0AVyMKDWy5xAncvjLWH7UcLBB5n7y2fQ8MzjJcto= +gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= +gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= +google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= +google.golang.org/api v0.3.2/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= +google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= +google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= +google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= +google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= +google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= +google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= +google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= +google.golang.org/api v0.59.0/go.mod h1:sT2boj7M9YJxZzgeZqXogmhfmRWDtPzT31xkieUbuZU= +google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= +google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= +google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= +google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= +google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8= +google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs= +google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= +google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw= +google.golang.org/api v0.81.0/go.mod h1:FA6Mb/bZxj706H2j+j2d6mHEEaHBmbbWnkfvmorOCko= +google.golang.org/api v0.235.0 h1:C3MkpQSRxS1Jy6AkzTGKKrpSCOd2WOGrezZ+icKSkKo= +google.golang.org/api v0.235.0/go.mod h1:QpeJkemzkFKe5VCE/PMv7GsUfn9ZF+u+q1Q7w6ckxTg= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= +google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= +google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211008145708-270636b82663/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211028162531-8db9c33dc351/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= +google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20250603155806-513f23925822 h1:rHWScKit0gvAPuOnu87KpaYtjK5zBMLcULh7gxkCXu4= +google.golang.org/genproto v0.0.0-20250603155806-513f23925822/go.mod h1:HubltRL7rMh0LfnQPkMH4NPDFEWp0jw3vixw7jEM53s= +google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 h1:oWVWY3NzT7KJppx2UKhKmzPq4SRe0LdCijVRwvGeikY= google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822/go.mod h1:h3c4v36UTKzUiuaOKQ6gr3S+0hovBtUrXzTG/i3+XEc= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d h1:xJJRGY7TJcvIlpSrN3K6LAWgNFUILlO+OMAqtg9aqnw= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d/go.mod h1:3ENsm/5D1mzDyhpzeRi1NR784I0BcofWBoSc5QqqMK4= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f/go.mod h1:+2Yz8+CLJbIfL9z73EW45avw8Lmge3xVElCP9zEKi50= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a/go.mod h1:uRxBH1mhmO8PGhU89cMcHaXKZqO+OfakD8QQO0oYwlQ= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250428153025-10db94c68c34/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250519155744-55703ea1f237/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 h1:fc6jSaCT0vBduLYZHYrBBNY4dsWuvgyff9noRNDdBeE= google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= -google.golang.org/grpc v1.69.4 h1:MF5TftSMkd8GLw/m0KM6V8CMOCY6NZ1NQDPGFgbTt4A= -google.golang.org/grpc v1.69.4/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4= -google.golang.org/grpc v1.71.0/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec= -google.golang.org/grpc v1.72.0/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= -google.golang.org/grpc v1.72.1/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= +google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= +google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok= google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc= -google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk= -google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= -google.golang.org/protobuf v1.36.3/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= -google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk= +gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4= gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/fsnotify/fsnotify.v1 v1.4.7 h1:XNNYLJHt73EyYiCZi6+xjupS9CpvmiDgjPTAjrBlQbo= +gopkg.in/fsnotify/fsnotify.v1 v1.4.7/go.mod h1:Fyux9zXlo4rWoMSIzpn9fDAYjalPqJ/K1qJ27s+7ltE= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/mail.v2 v2.3.1 h1:WYFn/oANrAGP2C0dcV6/pbkPzv8yGzqTjPmTeO7qoXk= +gopkg.in/mail.v2 v2.3.1/go.mod h1:htwXN1Qh09vZJ1NVKxQqHPBaCBbzKhp5GzuJEA4VJWw= +gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= +gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= +gopkg.in/src-d/go-errors.v1 v1.0.0 h1:cooGdZnCjYbeS1zb1s6pVAAimTdKceRrpn7aKOnNIfc= +gopkg.in/src-d/go-errors.v1 v1.0.0/go.mod h1:q1cBlomlw2FnDBDNGlnh6X0jPihy+QxZfMMNxPCbdYg= +gopkg.in/telebot.v3 v3.2.1 h1:3I4LohaAyJBiivGmkfB+CiVu7QFOWkuZ4+KHgO/G3rs= +gopkg.in/telebot.v3 v3.2.1/go.mod h1:GJKwwWqp9nSkIVN51eRKU78aB5f5OnQuWdwiIZfPbko= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -k8s.io/api v0.32.0 h1:OL9JpbvAU5ny9ga2fb24X8H6xQlVp+aJMFlgtQjR9CE= -k8s.io/api v0.32.0/go.mod h1:4LEwHZEf6Q/cG96F3dqR965sYOfmPM7rq81BLgsE0p0= -k8s.io/api v0.32.1/go.mod h1:/Yi/BqkuueW1BgpoePYBRdDYfjPF5sgTr5+YqDZra5k= -k8s.io/api v0.32.3/go.mod h1:2wEDTXADtm/HA7CCMD8D8bK4yuBUptzaRhYcYEEYA3k= -k8s.io/api v0.33.1/go.mod h1:87esjTn9DRSRTD4fWMXamiXxJhpOIREjWOSjsW1kEHw= -k8s.io/api v0.33.2/go.mod h1:fhrbphQJSM2cXzCWgqU29xLDuks4mu7ti9vveEnpSXs= -k8s.io/apiextensions-apiserver v0.32.0 h1:S0Xlqt51qzzqjKPxfgX1xh4HBZE+p8KKBq+k2SWNOE0= -k8s.io/apiextensions-apiserver v0.32.0/go.mod h1:86hblMvN5yxMvZrZFX2OhIHAuFIMJIZ19bTvzkP+Fmw= -k8s.io/apiextensions-apiserver v0.32.1/go.mod h1:sxWIGuGiYov7Io1fAS2X06NjMIk5CbRHc2StSmbaQto= -k8s.io/apiextensions-apiserver v0.32.3/go.mod h1:8YwcvVRMVzw0r1Stc7XfGAzB/SIVLunqApySV5V7Dss= -k8s.io/apiextensions-apiserver v0.33.1/go.mod h1:uNQ52z1A1Gu75QSa+pFK5bcXc4hq7lpOXbweZgi4dqA= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +k8s.io/api v0.33.3 h1:SRd5t//hhkI1buzxb288fy2xvjubstenEKL9K51KBI8= +k8s.io/api v0.33.3/go.mod h1:01Y/iLUjNBM3TAvypct7DIj0M0NIZc+PzAHCIo0CYGE= +k8s.io/apiextensions-apiserver v0.33.2 h1:6gnkIbngnaUflR3XwE1mCefN3YS8yTD631JXQhsU6M8= k8s.io/apiextensions-apiserver v0.33.2/go.mod h1:IvVanieYsEHJImTKXGP6XCOjTwv2LUMos0YWc9O+QP8= -k8s.io/apimachinery v0.32.0 h1:cFSE7N3rmEEtv4ei5X6DaJPHHX0C+upp+v5lVPiEwpg= -k8s.io/apimachinery v0.32.0/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE= -k8s.io/apimachinery v0.32.1/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE= -k8s.io/apimachinery v0.32.3/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE= -k8s.io/apimachinery v0.33.1/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM= -k8s.io/apimachinery v0.33.2/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM= -k8s.io/client-go v0.32.0 h1:DimtMcnN/JIKZcrSrstiwvvZvLjG0aSxy8PxN8IChp8= -k8s.io/client-go v0.32.0/go.mod h1:boDWvdM1Drk4NJj/VddSLnx59X3OPgwrOo0vGbtq9+8= -k8s.io/client-go v0.32.1/go.mod h1:aTTKZY7MdxUaJ/KiUs8D+GssR9zJZi77ZqtzcGXIiDg= -k8s.io/client-go v0.32.3/go.mod h1:3v0+3k4IcT9bXTc4V2rt+d2ZPPG700Xy6Oi0Gdl2PaY= -k8s.io/client-go v0.33.1/go.mod h1:JAsUrl1ArO7uRVFWfcj6kOomSlCv+JpvIsp6usAGefA= -k8s.io/client-go v0.33.2/go.mod h1:9mCgT4wROvL948w6f6ArJNb7yQd7QsvqavDeZHvNmHo= +k8s.io/apimachinery v0.33.3 h1:4ZSrmNa0c/ZpZJhAgRdcsFcZOw1PQU1bALVQ0B3I5LA= +k8s.io/apimachinery v0.33.3/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM= +k8s.io/apiserver v0.33.3 h1:Wv0hGc+QFdMJB4ZSiHrCgN3zL3QRatu56+rpccKC3J4= +k8s.io/apiserver v0.33.3/go.mod h1:05632ifFEe6TxwjdAIrwINHWE2hLwyADFk5mBsQa15E= +k8s.io/client-go v0.33.3 h1:M5AfDnKfYmVJif92ngN532gFqakcGi6RvaOF16efrpA= +k8s.io/client-go v0.33.3/go.mod h1:luqKBQggEf3shbxHY4uVENAxrDISLOarxpTKMiUuujg= +k8s.io/component-base v0.33.3 h1:mlAuyJqyPlKZM7FyaoM/LcunZaaY353RXiOd2+B5tGA= +k8s.io/component-base v0.33.3/go.mod h1:ktBVsBzkI3imDuxYXmVxZ2zxJnYTZ4HAsVj9iF09qp4= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= -k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f h1:GA7//TjRY9yWGy1poLzYYJJ4JRdzg3+O6e8I+e+8T5Y= -k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f/go.mod h1:R/HEjbvWI0qdfb8viZUeVZm0X6IZnxAydC7YU42CMw4= +k8s.io/kms v0.33.3 h1:7cQWC+GSH211NgY8LRKjBXNtkzra5SkpYzeZrOt5D+8= +k8s.io/kms v0.33.3/go.mod h1:C1I8mjFFBNzfUZXYt9FZVJ8MJl7ynFbGgZFbBzkBJ3E= +k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff h1:/usPimJzUKKu+m+TE36gUyGcf03XZEP0ZIKgKj35LS4= k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff/go.mod h1:5jIi+8yX4RIb8wk3XwBo5Pq2ccx4FP10ohkbSKCZoK8= -k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 h1:M3sRQVHv7vB20Xc2ybTt7ODCeFj6JSWYFzOFnYeS6Ro= -k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8= -sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo= +k8s.io/utils v0.0.0-20241210054802-24370beab758 h1:sdbE21q2nlQtFh65saZY+rRM6x6aJJI8IUa1AmH/qa0= +k8s.io/utils v0.0.0-20241210054802-24370beab758/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 h1:jpcvIRr3GLoUoEKRkHKSmGjxb6lWwrBlJsXc+eUYQHM= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw= +sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE= +sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= -sigs.k8s.io/structured-merge-diff/v4 v4.5.0 h1:nbCitCK2hfnhyiKo6uf2HxUPTCodY6Qaf85SbDIaMBk= -sigs.k8s.io/structured-merge-diff/v4 v4.5.0/go.mod h1:N8f93tFZh9U6vpxwRArLiikrE5/2tiu1w1AGfACIGE4= +sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= +sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= +sigs.k8s.io/structured-merge-diff/v4 v4.6.0 h1:IUA9nvMmnKWcj5jl84xn+T5MnlZKThmUW1TdblaLVAc= sigs.k8s.io/structured-merge-diff/v4 v4.6.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps= -sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= +sigs.k8s.io/yaml v1.5.0 h1:M10b2U7aEUY6hRtU870n2VTPgR5RZiL/I6Lcc2F4NUQ= +sigs.k8s.io/yaml v1.5.0/go.mod h1:wZs27Rbxoai4C0f8/9urLZtZtF3avA3gKvGyPdDqTO4= +xorm.io/builder v0.3.6 h1:ha28mQ2M+TFx96Hxo+iq6tQgnkC9IZkM6D8w9sKHHF8= +xorm.io/builder v0.3.6/go.mod h1:LEFAPISnRzG+zxaxj2vPicRwz67BdhFreKg8yv8/TgU= diff --git a/apps/investigations/go.mod b/apps/investigations/go.mod index 961be07bde6..ec8c3d01dae 100644 --- a/apps/investigations/go.mod +++ b/apps/investigations/go.mod @@ -3,63 +3,174 @@ module github.com/grafana/grafana/apps/investigations go 1.24.5 require ( + github.com/grafana/grafana v0.0.0-00010101000000-000000000000 github.com/grafana/grafana-app-sdk v0.40.0 - k8s.io/apimachinery v0.33.2 + github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250725152715-69d3b9023cec + github.com/stretchr/testify v1.10.0 + k8s.io/apimachinery v0.33.3 + k8s.io/apiserver v0.33.3 k8s.io/klog/v2 v2.130.1 k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff ) +// transitive dependencies that need replaced +// TODO: stop depending on grafana core +replace github.com/grafana/grafana => ../.. + +replace github.com/prometheus/alertmanager => github.com/grafana/prometheus-alertmanager v0.25.1-0.20250620093340-be61a673dee6 + require ( + filippo.io/edwards25519 v1.1.0 // indirect + github.com/BurntSushi/toml v1.5.0 // indirect + github.com/VividCortex/mysqlerr v0.0.0-20170204212430-6c6b55f8796f // indirect + github.com/apache/arrow-go/v18 v18.3.0 // indirect + github.com/armon/go-metrics v0.4.1 // indirect + github.com/aws/aws-sdk-go-v2 v1.36.5 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.17.70 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.36 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.36 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.17 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.34.0 // indirect + github.com/aws/smithy-go v1.22.4 // indirect github.com/beorn7/perks v1.0.1 // indirect + github.com/blang/semver/v4 v4.0.0 // indirect + github.com/bluele/gcache v0.0.2 // indirect github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 // indirect - github.com/cenkalti/backoff/v4 v4.3.0 // indirect + github.com/bwmarrin/snowflake v0.3.0 // indirect + github.com/cenkalti/backoff/v5 v5.0.2 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/cheekybits/genny v1.0.0 // indirect + github.com/chromedp/cdproto v0.0.0-20250429231605-6ed5b53462d4 // indirect + github.com/coreos/go-systemd/v22 v22.5.0 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect - github.com/emicklei/go-restful/v3 v3.11.0 // indirect + github.com/elazarl/goproxy v1.7.2 // indirect + github.com/emicklei/go-restful/v3 v3.12.1 // indirect github.com/evanphx/json-patch v5.6.0+incompatible // indirect + github.com/fatih/color v1.18.0 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/getkin/kin-openapi v0.132.0 // indirect + github.com/go-jose/go-jose/v3 v3.0.4 // indirect + github.com/go-kit/log v0.2.1 // indirect + github.com/go-logfmt/logfmt v0.6.0 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/jsonreference v0.21.0 // indirect github.com/go-openapi/swag v0.23.0 // indirect - github.com/go-viper/mapstructure/v2 v2.3.0 // indirect + github.com/go-sql-driver/mysql v1.9.2 // indirect + github.com/go-stack/stack v1.8.1 // indirect + github.com/gobwas/glob v0.2.3 // indirect + github.com/goccy/go-json v0.10.5 // indirect + github.com/gogo/googleapis v1.4.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang-migrate/migrate/v4 v4.7.0 // indirect github.com/golang/protobuf v1.5.4 // indirect + github.com/google/btree v1.1.3 // indirect + github.com/google/flatbuffers v25.2.10+incompatible // indirect github.com/google/gnostic-models v0.6.9 // indirect github.com/google/go-cmp v0.7.0 // indirect - github.com/google/gofuzz v1.2.0 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/grafana/authlib v0.0.0-20250515162837-2f4a8263eabb // indirect + github.com/gorilla/mux v1.8.1 // indirect + github.com/grafana/alerting v0.0.0-20250725130805-615c8286e14b // indirect + github.com/grafana/authlib v0.0.0-20250710201142-9542f2f28d43 // indirect + github.com/grafana/authlib/types v0.0.0-20250710201142-9542f2f28d43 // indirect + github.com/grafana/dataplane/sdata v0.0.9 // indirect + github.com/grafana/dskit v0.0.0-20250611075409-46f51e1ce914 // indirect github.com/grafana/grafana-app-sdk/logging v0.39.3 // indirect + github.com/grafana/grafana-aws-sdk v1.0.4 // indirect + github.com/grafana/grafana-azure-sdk-go/v2 v2.1.6 // indirect + github.com/grafana/grafana-plugin-sdk-go v0.278.0 // indirect + github.com/grafana/grafana/pkg/apiserver v0.0.0-20250627191313-2f1a6ae1712b // indirect + github.com/grafana/otel-profiling-go v0.5.1 // indirect + github.com/grafana/pyroscope-go/godeltaprof v0.1.8 // indirect + github.com/grafana/sqlds/v4 v4.2.3 // indirect + github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0 // indirect + github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.2 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-hclog v1.6.3 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-metrics v0.5.4 // indirect + github.com/hashicorp/go-msgpack/v2 v2.1.2 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.6.3 // indirect + github.com/hashicorp/go-sockaddr v1.0.7 // indirect + github.com/hashicorp/golang-lru v1.0.2 // indirect + github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect + github.com/hashicorp/memberlist v0.5.2 // indirect + github.com/hashicorp/yamux v0.1.1 // indirect + github.com/jaegertracing/jaeger-idl v0.5.0 // indirect + github.com/jmespath-community/go-jmespath v1.1.1 // indirect + github.com/jmoiron/sqlx v1.3.5 // indirect github.com/josharian/intern v1.0.0 // indirect + github.com/jpillora/backoff v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect + github.com/jszwedko/go-datemath v0.1.1-0.20230526204004-640a500621d6 // indirect github.com/klauspost/compress v1.18.0 // indirect - github.com/mailru/easyjson v0.7.7 // indirect + github.com/klauspost/cpuid/v2 v2.2.10 // indirect + github.com/lib/pq v1.10.9 // indirect + github.com/magefile/mage v1.15.0 // indirect + github.com/mailru/easyjson v0.9.0 // indirect + github.com/mattetti/filebuffer v1.0.1 // indirect + github.com/mattn/go-colorable v0.1.14 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-runewidth v0.0.16 // indirect + github.com/mattn/go-sqlite3 v1.14.22 // indirect + github.com/mdlayher/socket v0.4.1 // indirect + github.com/mdlayher/vsock v1.2.1 // indirect + github.com/miekg/dns v1.1.63 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/mithrandie/csvq v1.18.1 // indirect + github.com/mithrandie/csvq-driver v1.7.0 // indirect + github.com/mithrandie/go-file/v2 v2.1.0 // indirect + github.com/mithrandie/go-text v1.6.0 // indirect + github.com/mithrandie/ternary v1.1.1 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // indirect - github.com/onsi/ginkgo/v2 v2.22.2 // indirect - github.com/onsi/gomega v1.36.2 // indirect - github.com/openfga/openfga v1.8.13 // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/oklog/ulid v1.3.1 // indirect + github.com/olekukonko/tablewriter v0.0.5 // indirect + github.com/open-feature/go-sdk v1.14.1 // indirect + github.com/open-feature/go-sdk-contrib/providers/go-feature-flag v0.2.3 // indirect + github.com/open-feature/go-sdk-contrib/providers/ofrep v0.1.5 // indirect + github.com/patrickmn/go-cache v2.1.0+incompatible // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect + github.com/pierrec/lz4/v4 v4.1.22 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/prometheus/alertmanager v0.28.0 // indirect github.com/prometheus/client_golang v1.22.0 // indirect github.com/prometheus/client_model v0.6.2 // indirect - github.com/prometheus/common v0.64.0 // indirect + github.com/prometheus/common v0.65.0 // indirect + github.com/prometheus/exporter-toolkit v0.14.0 // indirect github.com/prometheus/procfs v0.16.1 // indirect github.com/puzpuzpuz/xsync/v2 v2.5.1 // indirect - github.com/rogpeppe/go-internal v1.14.1 // indirect + github.com/rivo/uniseg v0.4.7 // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 // indirect github.com/spf13/pflag v1.0.6 // indirect + github.com/stretchr/objx v0.5.2 // indirect + github.com/tjhop/slog-gokit v0.1.3 // indirect + github.com/unknwon/bra v0.0.0-20200517080246-1e3013ecaff8 // indirect + github.com/unknwon/com v1.0.1 // indirect + github.com/unknwon/log v0.0.0-20200308114134-929b1006e34a // indirect + github.com/urfave/cli v1.22.16 // indirect github.com/x448/float16 v0.8.4 // indirect + github.com/zeebo/xxh3 v1.0.2 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.61.0 // indirect + go.opentelemetry.io/contrib/propagators/jaeger v1.36.0 // indirect + go.opentelemetry.io/contrib/samplers/jaegerremote v0.30.0 // indirect go.opentelemetry.io/otel v1.37.0 // indirect + go.opentelemetry.io/otel/exporters/jaeger v1.17.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.37.0 // indirect @@ -67,7 +178,11 @@ require ( go.opentelemetry.io/otel/sdk v1.37.0 // indirect go.opentelemetry.io/otel/trace v1.37.0 // indirect go.opentelemetry.io/proto/otlp v1.7.0 // indirect + go.uber.org/atomic v1.11.0 // indirect + go.yaml.in/yaml/v2 v2.4.2 // indirect golang.org/x/crypto v0.39.0 // indirect + golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 // indirect + golang.org/x/mod v0.25.0 // indirect golang.org/x/net v0.41.0 // indirect golang.org/x/oauth2 v0.30.0 // indirect golang.org/x/sync v0.16.0 // indirect @@ -76,19 +191,25 @@ require ( golang.org/x/text v0.26.0 // indirect golang.org/x/time v0.11.0 // indirect golang.org/x/tools v0.34.0 // indirect + golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect google.golang.org/grpc v1.73.0 // indirect google.golang.org/protobuf v1.36.6 // indirect + gopkg.in/fsnotify/fsnotify.v1 v1.4.7 // indirect gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/api v0.33.2 // indirect + k8s.io/api v0.33.3 // indirect k8s.io/apiextensions-apiserver v0.33.2 // indirect - k8s.io/client-go v0.33.2 // indirect - k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect - sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect + k8s.io/client-go v0.33.3 // indirect + k8s.io/component-base v0.33.3 // indirect + k8s.io/utils v0.0.0-20241210054802-24370beab758 // indirect + sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect sigs.k8s.io/randfill v1.0.0 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect - sigs.k8s.io/yaml v1.4.0 // indirect + sigs.k8s.io/yaml v1.5.0 // indirect + xorm.io/builder v0.3.6 // indirect ) diff --git a/apps/investigations/go.sum b/apps/investigations/go.sum index e1e8867933c..903c4ae9e07 100644 --- a/apps/investigations/go.sum +++ b/apps/investigations/go.sum @@ -1,307 +1,993 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw= +cuelang.org/go v0.11.1 h1:pV+49MX1mmvDm8Qh3Za3M786cty8VKPWzQ1Ho4gZRP0= +cuelang.org/go v0.11.1/go.mod h1:PBY6XvPUswPPJ2inpvUozP9mebDVTXaeehQikhZPBz0= +dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= +dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0 h1:Gt0j3wceWMwPmiazCa8MzMA0MfhmPIz0Qp0FJ6qcM0U= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0/go.mod h1:Ot/6aikWnKWi4l9QB7qVSwa8iMphQNqkWALMoNT3rzM= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.9.0 h1:OVoM452qUFBrX+URdH3VpR299ma4kfom0yB0URYky9g= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.9.0/go.mod h1:kUjrAo8bgEwLeZ/CmHqNl3Z/kPm7y6FKfxxK0izYUg4= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1 h1:FPKJS1T+clwv+OLGt13a8UjqeRuh0O4SJ3lUriThc+4= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1/go.mod h1:j2chePtV91HrC22tGoRX3sGY42uF13WzmmV80/OdVAA= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e h1:NeAW1fUYUEWhft7pkxDf6WoUvEZJ/uOKsvtpjLnn8MU= +github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= +github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 h1:oygO0locgZJe7PpYPXT5A29ZkwJaPqcva7BVeemZOZs= +github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= +github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg= +github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= +github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= +github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= +github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= +github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0= +github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= +github.com/Masterminds/sprig/v3 v3.3.0 h1:mQh0Yrg1XPo6vjYXgtf5OtijNAKJRNcTdOOGZe3tPhs= +github.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSCzdgBfDb35Lz0= +github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= +github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= +github.com/ProtonMail/go-crypto v1.1.6 h1:ZcV+Ropw6Qn0AX9brlQLAUXfqLBc7Bl+f/DmNxpLfdw= +github.com/ProtonMail/go-crypto v1.1.6/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE= +github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= +github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= +github.com/VividCortex/mysqlerr v0.0.0-20170204212430-6c6b55f8796f h1:HR5nRmUQgXrwqZOwZ2DAc/aCi3Bu3xENpspW935vxu0= +github.com/VividCortex/mysqlerr v0.0.0-20170204212430-6c6b55f8796f/go.mod h1:f3HiCrHjHBdcm6E83vGaXh1KomZMA2P6aeo3hKx/wg0= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b h1:mimo19zliBX/vSQ6PWWSL9lK8qwHozUj03+zLoEB8O0= +github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b/go.mod h1:fvzegU4vN3H1qMT+8wDmzjAcDONcgo2/SZ/TyfdUOFs= +github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA= +github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA= +github.com/apache/arrow-go/v18 v18.3.0 h1:Xq4A6dZj9Nu33sqZibzn012LNnewkTUlfKVUFD/RX/I= +github.com/apache/arrow-go/v18 v18.3.0/go.mod h1:eEM1DnUTHhgGAjf/ChvOAQbUQ+EPohtDrArffvUjPg8= +github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/apache/thrift v0.21.0 h1:tdPmh/ptjE1IJnhbhrcl2++TauVjy242rkV/UzJChnE= +github.com/apache/thrift v0.21.0/go.mod h1:W1H8aR/QRtYNvrPeFXBtobyRkd0/YVhTc6i07XIAgDw= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= +github.com/at-wat/mqtt-go v0.19.4 h1:R2cbCU7O5PHQ38unbe1Y51ncG3KsFEJV6QeipDoqdLQ= +github.com/at-wat/mqtt-go v0.19.4/go.mod h1:AsiWc9kqVOhqq7LzUeWT/AkKUBfx3Sw5cEe8lc06fqA= +github.com/aws/aws-sdk-go v1.17.7/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.55.7 h1:UJrkFq7es5CShfBwlWAC8DA077vp8PyVbQd3lqLiztE= +github.com/aws/aws-sdk-go v1.55.7/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU= +github.com/aws/aws-sdk-go-v2 v1.36.5 h1:0OF9RiEMEdDdZEMqF9MRjevyxAQcf6gY+E7vwBILFj0= +github.com/aws/aws-sdk-go-v2 v1.36.5/go.mod h1:EYrzvCCN9CMUTa5+6lf6MM4tq3Zjp8UhSGR/cBsjai0= +github.com/aws/aws-sdk-go-v2/credentials v1.17.70 h1:ONnH5CM16RTXRkS8Z1qg7/s2eDOhHhaXVd72mmyv4/0= +github.com/aws/aws-sdk-go-v2/credentials v1.17.70/go.mod h1:M+lWhhmomVGgtuPOhO85u4pEa3SmssPTdcYpP/5J/xc= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.36 h1:SsytQyTMHMDPspp+spo7XwXTP44aJZZAC7fBV2C5+5s= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.36/go.mod h1:Q1lnJArKRXkenyog6+Y+zr7WDpk4e6XlR6gs20bbeNo= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.36 h1:i2vNHQiXUvKhs3quBR6aqlgJaiaexz/aNvdCktW/kAM= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.36/go.mod h1:UdyGa7Q91id/sdyHPwth+043HhmP6yP9MBHgbZM0xo8= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4 h1:CXV68E2dNqhuynZJPB80bhPQwAKqBWVer887figW6Jc= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4/go.mod h1:/xFi9KtvBXP97ppCz1TAEvU1Uf66qvid89rbem3wCzQ= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.17 h1:t0E6FzREdtCsiLIoLCWsYliNsRBgyGD/MCK571qk4MI= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.17/go.mod h1:ygpklyoaypuyDvOM5ujWGrYWpAK3h7ugnmKCU/76Ys4= +github.com/aws/aws-sdk-go-v2/service/sts v1.34.0 h1:NFOJ/NXEGV4Rq//71Hs1jC/NvPs1ezajK+yQmkwnPV0= +github.com/aws/aws-sdk-go-v2/service/sts v1.34.0/go.mod h1:7ph2tGpfQvwzgistp2+zga9f+bCjlQJPkPUmMgDSD7w= +github.com/aws/smithy-go v1.22.4 h1:uqXzVZNuNexwc/xrh6Tb56u89WDlJY6HS+KC0S4QSjw= +github.com/aws/smithy-go v1.22.4/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI= +github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o= +github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k= +github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= +github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= +github.com/bluele/gcache v0.0.2 h1:WcbfdXICg7G/DGBh1PFfcirkWOQV+v077yF1pSy3DGw= +github.com/bluele/gcache v0.0.2/go.mod h1:m15KV+ECjptwSPxKhOhQoAFQVtUFjTVkc3H8o0t/fp0= +github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 h1:N7oVaKyGp8bttX0bfZGmcGkjz7DLQXhAn3DNd3T0ous= github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874/go.mod h1:r5xuitiExdLAJ09PR7vBVENGvp4ZuTBeWTGtxuX3K+c= +github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA= +github.com/bufbuild/protocompile v0.4.0/go.mod h1:3v93+mbWn/v3xzN+31nwkJfrEpAUwp+BagBSZWx+TP8= +github.com/bwmarrin/snowflake v0.3.0 h1:xm67bEhkKh6ij1790JB83OujPR5CzNe8QuQqAgISZN0= +github.com/bwmarrin/snowflake v0.3.0/go.mod h1:NdZxfVWX+oR6y2K0o6qAYv6gIOP9rjG0/E9WsDpxqwE= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/cenkalti/backoff/v5 v5.0.2 h1:rIfFVxEf1QsI7E1ZHfp/B4DF/6QBAUhmgkxc0H7Zss8= +github.com/cenkalti/backoff/v5 v5.0.2/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE= +github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ= +github.com/chromedp/cdproto v0.0.0-20250429231605-6ed5b53462d4 h1:UZdrvid2JFwnvPlUSEFlE794XZL4Jmrj8fuxfcLECJE= +github.com/chromedp/cdproto v0.0.0-20250429231605-6ed5b53462d4/go.mod h1:NItd7aLkcfOA/dcMXvl8p1u+lQqioRMq/SqDp71Pb/k= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0= +github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs= +github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= +github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= +github.com/cockroachdb/apd/v3 v3.2.1 h1:U+8j7t0axsIgvQUqthuNm82HIrYXodOV2iWLWtEaIwg= +github.com/cockroachdb/apd/v3 v3.2.1/go.mod h1:klXJcjp+FffLTHlhIG69tezTDvdP065naDsHzKhYSqc= +github.com/cockroachdb/cockroach-go v0.0.0-20181001143604-e0a95dfd547c/go.mod h1:XGLbWH/ujMcbPbhZq52Nv6UrCghb1yGn//133kEsvDk= +github.com/containerd/containerd v1.2.7/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.6 h1:XJtiaUW6dEEqVuZiMTn1ldk455QWwEIsMIJlo5vtkx0= +github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= +github.com/cznic/b v0.0.0-20180115125044-35e9bbe41f07/go.mod h1:URriBxXwVq5ijiJ12C7iIZqlA69nTlI+LgI6/pwftG8= +github.com/cznic/fileutil v0.0.0-20180108211300-6a051e75936f/go.mod h1:8S58EK26zhXSxzv7NQFpnliaOQsmDUxvoQO3rt154Vg= +github.com/cznic/golex v0.0.0-20170803123110-4ab7c5e190e4/go.mod h1:+bmmJDNmKlhWNG+gwWCkaBoTy39Fs+bzRxVBzoTQbIc= +github.com/cznic/internal v0.0.0-20180608152220-f44710a21d00/go.mod h1:olo7eAdKwJdXxb55TKGLiJ6xt1H0/tiiRCWKVLmtjY4= +github.com/cznic/lldb v1.1.0/go.mod h1:FIZVUmYUVhPwRiPzL8nD/mpFcJ/G7SSXjjXYG4uRI3A= +github.com/cznic/mathutil v0.0.0-20180504122225-ca4c9f2c1369/go.mod h1:e6NPNENfs9mPDVNRekM7lKScauxd5kXTr1Mfyig6TDM= +github.com/cznic/ql v1.2.0/go.mod h1:FbpzhyZrqr0PVlK6ury+PoW3T0ODUV22OeWIxcaOrSE= +github.com/cznic/sortutil v0.0.0-20150617083342-4c7342852e65/go.mod h1:q2w6Bg5jeox1B+QkJ6Wp/+Vn0G/bo3f1uY7Fn3vivIQ= +github.com/cznic/strutil v0.0.0-20171016134553-529a34b1c186/go.mod h1:AHHPPPXTw0h6pVabbcbyGRK1DckRn7r/STdZEeIDzZc= +github.com/cznic/zappy v0.0.0-20160723133515-2533cb5b45cc/go.mod h1:Y1SNZ4dRUOKXshKUbwUapqNncRrho4mkjQebgEHZLj8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= -github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/denisenkom/go-mssqldb v0.0.0-20190515213511-eb9f6a1743f3/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= +github.com/dhui/dktest v0.3.0/go.mod h1:cyzIUfGsBEbZ6BT7tnXqAShHSXCZhSNmFl70sZ7c1yc= +github.com/dlmiddlecote/sqlstats v1.0.2 h1:gSU11YN23D/iY50A2zVYwgXgy072khatTsIW6UPjUtI= +github.com/dlmiddlecote/sqlstats v1.0.2/go.mod h1:0CWaIh/Th+z2aI6Q9Jpfg/o21zmGxWhbByHgQSCUQvY= +github.com/docker/distribution v2.7.0+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v0.7.3-0.20190103212154-2b7e084dc98b/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v0.7.3-0.20190817195342-4760db040282/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/dolthub/flatbuffers/v23 v23.3.3-dh.2 h1:u3PMzfF8RkKd3lB9pZ2bfn0qEG+1Gms9599cr0REMww= +github.com/dolthub/flatbuffers/v23 v23.3.3-dh.2/go.mod h1:mIEZOHnFx4ZMQeawhw9rhsj+0zwQj7adVsnBX7t+eKY= +github.com/dolthub/go-icu-regex v0.0.0-20250327004329-6799764f2dad h1:66ZPawHszNu37VPQckdhX1BPPVzREsGgNxQeefnlm3g= +github.com/dolthub/go-icu-regex v0.0.0-20250327004329-6799764f2dad/go.mod h1:ylU4XjUpsMcvl/BKeRRMXSH7e7WBrPXdSLvnRJYrxEA= +github.com/dolthub/go-mysql-server v0.19.1-0.20250410182021-5632d67cd46e h1:7pAttAqWaudUAsM9iHASi/4eFBK+qn4qeaNto7g8bK4= +github.com/dolthub/go-mysql-server v0.19.1-0.20250410182021-5632d67cd46e/go.mod h1:KZyoO3jngyZCLyCf100FEQTrwAHj33AIMj4Zv4u3MNE= +github.com/dolthub/jsonpath v0.0.2-0.20240227200619-19675ab05c71 h1:bMGS25NWAGTEtT5tOBsCuCrlYnLRKpbJVJkDbrTRhwQ= +github.com/dolthub/jsonpath v0.0.2-0.20240227200619-19675ab05c71/go.mod h1:2/2zjLQ/JOOSbbSboojeg+cAwcRV0fDLzIiWch/lhqI= +github.com/dolthub/vitess v0.0.0-20250410090211-143e6b272ad4 h1:LGTt2LtYX8vaai32d+c9L0sMcP+Dg9w1kO6+lbsxxYg= +github.com/dolthub/vitess v0.0.0-20250410090211-143e6b272ad4/go.mod h1:1gQZs/byeHLMSul3Lvl3MzioMtOW1je79QYGyi2fd70= +github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= +github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= +github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +github.com/elazarl/goproxy v1.7.2 h1:Y2o6urb7Eule09PjlhQRGNsqRfPmYI3KKQLFpCAV3+o= +github.com/elazarl/goproxy v1.7.2/go.mod h1:82vkLNir0ALaW14Rc399OTTjyNREgmdL2cVoIbS6XaE= +github.com/emicklei/go-restful/v3 v3.12.1 h1:PJMDIM/ak7btuL8Ex0iYET9hxM3CI2sjZtzpL63nKAU= +github.com/emicklei/go-restful/v3 v3.12.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= +github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= +github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= +github.com/fsouza/fake-gcs-server v1.7.0/go.mod h1:5XIRs4YvwNbNoz+1JF8j6KLAyDh7RHGAyAK3EP2EsNk= github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= -github.com/getkin/kin-openapi v0.131.0 h1:NO2UeHnFKRYhZ8wg6Nyh5Cq7dHk4suQQr72a4pMrDxE= -github.com/getkin/kin-openapi v0.131.0/go.mod h1:3OlG51PCYNsPByuiMB0t4fjnNlIDnaEDsjiKUV8nL58= +github.com/gchaincl/sqlhooks v1.3.0 h1:yKPXxW9a5CjXaVf2HkQn6wn7TZARvbAOAelr3H8vK2Y= +github.com/gchaincl/sqlhooks v1.3.0/go.mod h1:9BypXnereMT0+Ys8WGWHqzgkkOfHIhyeUCqXC24ra34= github.com/getkin/kin-openapi v0.132.0 h1:3ISeLMsQzcb5v26yeJrBcdTCEQTag36ZjaGk7MIRUwk= github.com/getkin/kin-openapi v0.132.0/go.mod h1:3OlG51PCYNsPByuiMB0t4fjnNlIDnaEDsjiKUV8nL58= +github.com/go-asn1-ber/asn1-ber v1.5.4 h1:vXT6d/FNDiELJnLb6hGNa309LMsrCoYFvpwHDF0+Y1A= +github.com/go-asn1-ber/asn1-ber v1.5.4/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= +github.com/go-jose/go-jose/v3 v3.0.4 h1:Wp5HA7bLQcKnf6YYao/4kpRpVMp/yf6+pJKV8WFSaNY= +github.com/go-jose/go-jose/v3 v3.0.4/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= +github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= +github.com/go-ldap/ldap/v3 v3.4.4 h1:qPjipEpt+qDa6SI/h1fzuGWoRUY+qqQ9sOZq67/PYUs= +github.com/go-ldap/ldap/v3 v3.4.4/go.mod h1:fe1MsuN5eJJ1FeLT/LEBVdWfNWKh459R7aXgXtJC+aI= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4= +github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= -github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-openapi/analysis v0.23.0 h1:aGday7OWupfMs+LbmLZG4k0MYXIANxcuBTYUC03zFCU= +github.com/go-openapi/analysis v0.23.0/go.mod h1:9mz9ZWaSlV8TvjQHLl2mUW2PbZtemkE8yA5v22ohupo= +github.com/go-openapi/errors v0.22.0 h1:c4xY/OLxUBSTiepAg3j/MHuAv5mJhnf53LLMWFB+u/w= +github.com/go-openapi/errors v0.22.0/go.mod h1:J3DmZScxCDufmIMsdOuDHxJbdOGC0xtUynjIx092vXE= github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= +github.com/go-openapi/loads v0.22.0 h1:ECPGd4jX1U6NApCGG1We+uEozOAvXvJSF4nnwHZ8Aco= +github.com/go-openapi/loads v0.22.0/go.mod h1:yLsaTCS92mnSAZX5WWoxszLj0u+Ojl+Zs5Stn1oF+rs= +github.com/go-openapi/runtime v0.28.0 h1:gpPPmWSNGo214l6n8hzdXYhPuJcGtziTOgUpvsFWGIQ= +github.com/go-openapi/runtime v0.28.0/go.mod h1:QN7OzcS+XuYmkQLw05akXk0jRH/eZ3kb18+1KwW9gyc= +github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY= +github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk= +github.com/go-openapi/strfmt v0.23.0 h1:nlUS6BCqcnAk0pyhi9Y+kdDVZdZMHfEKQiS4HaMgO/c= +github.com/go-openapi/strfmt v0.23.0/go.mod h1:NrtIpfKtWIygRkKVsxh7XQMDQW5HKQl6S5ik2elW+K4= github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= +github.com/go-openapi/validate v0.24.0 h1:LdfDKwNbpB6Vn40xhTdNZAnfLECL81w+VX3BumrGD58= +github.com/go-openapi/validate v0.24.0/go.mod h1:iyeX1sEufmv3nPbBdX3ieNviWnOZaJ1+zquzJEf2BAQ= +github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= +github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= +github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-sql-driver/mysql v1.9.2 h1:4cNKDYQ1I84SXslGddlsrMhc8k4LeDVj6Ad6WRjiHuU= +github.com/go-sql-driver/mysql v1.9.2/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= +github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= -github.com/go-viper/mapstructure/v2 v2.3.0 h1:27XbWsHIqhbdR5TIC911OfYvgSaW93HM+dX7970Q7jk= -github.com/go-viper/mapstructure/v2 v2.3.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:9wScpmSP5A3Bk8V3XHWUcJmYTh+ZnlHVyc+A4oZYS3Y= +github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:56xuuqnHyryaerycW3BfssRdxQstACi0Epw/yC5E2xM= +github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= +github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= +github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= +github.com/gocql/gocql v0.0.0-20190301043612-f6df8288f9b4/go.mod h1:4Fw1eo5iaEhDUs8XyuhSVCVy52Jq3L+/3GJgYkwc+/0= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA= +github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gogo/googleapis v1.4.1 h1:1Yx4Myt7BxzvUr5ldGSbwYiZG6t9wGBZ+8/fX3Wvtq0= +github.com/gogo/googleapis v1.4.1/go.mod h1:2lpHqI5OcWCtVElxXnPt+s8oJvMpySlOyM6xDCrzib4= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI= +github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8= +github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang-migrate/migrate/v4 v4.7.0 h1:gONcHxHApDTKXDyLH/H97gEHmpu1zcnnbAaq2zgrPrs= +github.com/golang-migrate/migrate/v4 v4.7.0/go.mod h1:Qvut3N4xKWjoH3sokBccML6WyHSnggXm/DvMMnTsQIc= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.7.0-rc.1 h1:YojYx61/OLFsiv6Rw1Z96LpldJIy31o+UHmwAUMJ6/U= +github.com/golang/mock v1.7.0-rc.1/go.mod h1:s42URUywIqd+OcERslBJvOjepvNymP31m3q8d/GkuRs= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs= +github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= +github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= +github.com/google/flatbuffers v25.2.10+incompatible h1:F3vclr7C3HpB1k9mxCGRMXq6FdUalZ6H/pNX4FP1v0Q= +github.com/google/flatbuffers v25.2.10+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/gnostic-models v0.6.9 h1:MU/8wDLif2qCXZmzncUQ/BOfxWfthHi63KqpoNbWqVw= github.com/google/gnostic-models v0.6.9/go.mod h1:CiWsm0s6BSQd1hRn8/QmxqB6BesYcbSZxsz9b0KuDBw= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= +github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= -github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg= -github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J0b1vyeLSOYI8bm5wbJM/8yDe8= +github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/grafana/authlib v0.0.0-20250515162837-2f4a8263eabb h1:oTl2j6/4miQUYmXANp2pBuYCWA5f8NVYFfCWpczpFso= -github.com/grafana/authlib v0.0.0-20250515162837-2f4a8263eabb/go.mod h1:PBtQaXwkFu4BAt2aXsR7w8p8NVpdjV5aJYhqRDei9Us= -github.com/grafana/grafana-app-sdk v0.35.1 h1:zEXubzsQrxGBOzXJJMBwhEClC/tvPi0sfK7NGmlX3RI= -github.com/grafana/grafana-app-sdk v0.35.1/go.mod h1:Zx5MkVppYK+ElSDUAR6+fjzOVo6I/cIgk+ty+LmNOxI= -github.com/grafana/grafana-app-sdk v0.38.3-0.20250708143121-df8ec27cecb5 h1:5EvbpsK3MMoLj4X8831DZ+k/uXwQrwwM65pE0W9knfg= -github.com/grafana/grafana-app-sdk v0.38.3-0.20250708143121-df8ec27cecb5/go.mod h1:3BP1layBA+/vm6niDfw66HwNnDyUCX99tUcX0p5/ErA= -github.com/grafana/grafana-app-sdk v0.38.3-0.20250709183049-aef07c9d3145 h1:4VpspqAe3zz3GniPkdFvwXhNwWhQKQmKWc7R80VbkyQ= -github.com/grafana/grafana-app-sdk v0.38.3-0.20250709183049-aef07c9d3145/go.mod h1:3BP1layBA+/vm6niDfw66HwNnDyUCX99tUcX0p5/ErA= -github.com/grafana/grafana-app-sdk v0.39.0/go.mod h1:xRyBQOttgWTc3tGe9pI0upnpEPVhzALf7Mh/61O4zyY= +github.com/google/wire v0.6.0 h1:HBkoIh4BdSxoyo9PveV8giw7ZsaBOvzWKfcg/6MrVwI= +github.com/google/wire v0.6.0/go.mod h1:F4QhpQ9EDIdJ1Mbop/NZBRB+5yrR6qg3BnctaoUk6NA= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e h1:JKmoR8x90Iww1ks85zJ1lfDGgIiMDuIptTOhJq+zKyg= +github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= +github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +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-20250725130805-615c8286e14b h1:mfUAq/N+mS82EcE35hDXWtfVY7UhTjzZxzssvFt9tvQ= +github.com/grafana/alerting v0.0.0-20250725130805-615c8286e14b/go.mod h1:VKxaR93Gff0ZlO2sPcdPVob1a/UzArFEW5zx3Bpyhls= +github.com/grafana/authlib v0.0.0-20250710201142-9542f2f28d43 h1:vVPT0i5Y1vI6qzecYStV2yk7cHKrC3Pc7AgvwT5KydQ= +github.com/grafana/authlib v0.0.0-20250710201142-9542f2f28d43/go.mod h1:1fWkOiL+m32NBgRHZtlZGz2ji868tPZACYbqP3nBRJI= +github.com/grafana/authlib/types v0.0.0-20250710201142-9542f2f28d43 h1:NlkGMnVi/oUn6Cr90QbJYpQJ4FnjyAIG9Ex5GtTZIzw= +github.com/grafana/authlib/types v0.0.0-20250710201142-9542f2f28d43/go.mod h1:qeWYbnWzaYGl88JlL9+DsP1GT2Cudm58rLtx13fKZdw= +github.com/grafana/dataplane/sdata v0.0.9 h1:AGL1LZnCUG4MnQtnWpBPbQ8ZpptaZs14w6kE/MWfg7s= +github.com/grafana/dataplane/sdata v0.0.9/go.mod h1:Jvs5ddpGmn6vcxT7tCTWAZ1mgi4sbcdFt9utQx5uMAU= +github.com/grafana/dskit v0.0.0-20250611075409-46f51e1ce914 h1:qcSGhr691f1mmPHwg2svGyO40Ex92G02aOyHzP6XHCE= +github.com/grafana/dskit v0.0.0-20250611075409-46f51e1ce914/go.mod h1:OiN4P4aC6LwLzLbEupH3Ue83VfQoNMfG48rsna8jI/E= github.com/grafana/grafana-app-sdk v0.40.0 h1:KilbCFMYox2cnIi1W6ql7W+n9kms/NvWlBPM1m4Q4mg= github.com/grafana/grafana-app-sdk v0.40.0/go.mod h1:fn943JEM0CR3mY/Gd3816MUcpob5xnKc8MoojnbMjYY= -github.com/grafana/grafana-app-sdk/logging v0.35.1 h1:taVpl+RoixTYl0JBJGhH+fPVmwA9wvdwdzJTZsv9buM= -github.com/grafana/grafana-app-sdk/logging v0.35.1/go.mod h1:Y/bvbDhBiV/tkIle9RW49pgfSPIPSON8Q4qjx3pyqDk= -github.com/grafana/grafana-app-sdk/logging v0.38.2/go.mod h1:Y/bvbDhBiV/tkIle9RW49pgfSPIPSON8Q4qjx3pyqDk= -github.com/grafana/grafana-app-sdk/logging v0.39.2/go.mod h1:WhDENSnaGHtyVVwZGVnAR7YLvh2xlLDYR3D7E6h7XVk= +github.com/grafana/grafana-app-sdk/logging v0.39.3 h1:mMrcYahnoRu7blKyL/ZVcgv7WCiI2CqxODYh8tBFUgY= github.com/grafana/grafana-app-sdk/logging v0.39.3/go.mod h1:otUD9XpJD7A5sCLb8mcs9hIXGdeV6lnhzVwe747g4RU= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 h1:5ZPtiqj0JL5oKWmcsq4VMaAW5ukBEgSGXEN89zeH1Jo= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI= +github.com/grafana/grafana-aws-sdk v1.0.4 h1:D14UAehsOqpjliHmHzveRQ1p43KCsMzdmb7GovWj+SY= +github.com/grafana/grafana-aws-sdk v1.0.4/go.mod h1:hO7q7yWV+t6dmiyJjMa3IbuYnYkBua+G/IAlOPVIYKE= +github.com/grafana/grafana-azure-sdk-go/v2 v2.1.6 h1:OfCkitCuomzZKW1WYHrG8MxKwtMhALb7jqoj+487eTg= +github.com/grafana/grafana-azure-sdk-go/v2 v2.1.6/go.mod h1:V7y2BmsWxS3A9Ohebwn4OiSfJJqi//4JQydQ8fHTduo= +github.com/grafana/grafana-plugin-sdk-go v0.278.0 h1:5/rIYparLi02pofdaag8wnjspMMVNCi8cZhC4cdC3Ho= +github.com/grafana/grafana-plugin-sdk-go v0.278.0/go.mod h1:+8NXT/XUJ/89GV6FxGQ366NZ3nU+cAXDMd0OUESF9H4= +github.com/grafana/grafana/apps/dashboard v0.0.0-20250716132114-6fd75ebc5441 h1:+TSbaxCXBZrKkdROWBzdWna8uStE1f9LYd7GiqjVfz8= +github.com/grafana/grafana/apps/dashboard v0.0.0-20250716132114-6fd75ebc5441/go.mod h1:1XWiRSVuDQiayapHhQiDc4S4e9GzEZgg/3GeNCuDgn4= +github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250725152715-69d3b9023cec h1:cg1GbDVZ7goqDrqoMzqeN4AeAcD271MGYjOvdVTDwfw= +github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250725152715-69d3b9023cec/go.mod h1:3ZgUe0E3rIhI026xF4DKFptOst/jpDHJ/Sn+bRODzI4= +github.com/grafana/grafana/pkg/apiserver v0.0.0-20250627191313-2f1a6ae1712b h1:QyJLJn3xwFTIXu9KPZujsrIUN0X8DdiR9b2h75L0AfI= +github.com/grafana/grafana/pkg/apiserver v0.0.0-20250627191313-2f1a6ae1712b/go.mod h1:6OKkPWDB8PetDXqMVMOWL35iTCEUdpATwwpuew0k8+o= +github.com/grafana/otel-profiling-go v0.5.1 h1:stVPKAFZSa7eGiqbYuG25VcqYksR6iWvF3YH66t4qL8= +github.com/grafana/otel-profiling-go v0.5.1/go.mod h1:ftN/t5A/4gQI19/8MoWurBEtC6gFw8Dns1sJZ9W4Tls= +github.com/grafana/prometheus-alertmanager v0.25.1-0.20250620093340-be61a673dee6 h1:oJnbhG6ZNy10AjsgNeAtAKeGHogIGOMfAsBH6fYYa5M= +github.com/grafana/prometheus-alertmanager v0.25.1-0.20250620093340-be61a673dee6/go.mod h1:O/QP1BCm0HHIzbKvgMzqb5sSyH88rzkFk84F4TfJjBU= +github.com/grafana/pyroscope-go/godeltaprof v0.1.8 h1:iwOtYXeeVSAeYefJNaxDytgjKtUuKQbJqgAIjlnicKg= +github.com/grafana/pyroscope-go/godeltaprof v0.1.8/go.mod h1:2+l7K7twW49Ct4wFluZD3tZ6e0SjanjcUUBPVD/UuGU= +github.com/grafana/sqlds/v4 v4.2.3 h1:9ibD1c5O5u9fifEkBSig+jAc41TUEz+M+bWQqDsofP4= +github.com/grafana/sqlds/v4 v4.2.3/go.mod h1:bv+XHabfUF4xkgg4y+nYFCK8rpMHZsMaQk56qNaJcAM= +github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0 h1:QGLs/O40yoNK9vmy4rhUGBVyMf1lISBGtXRpsu/Qu/o= +github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0/go.mod h1:hM2alZsMUni80N33RBe6J0e423LB+odMj7d3EMP9l20= +github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.2 h1:sGm2vDRFUrQJO/Veii4h4zG2vvqG6uWNkBHSTqXOZk0= +github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.2/go.mod h1:wd1YpapPLivG6nQgbf7ZkG1hhSOXDhhn4MLTknx2aAc= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1 h1:X5VWvz21y3gzm9Nw/kaUeku/1+uBhcekkmy4IkffJww= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1/go.mod h1:Zanoh4+gvIgluNqcfMVTJueD4wSS5hT7zTt4Mrutd90= +github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= +github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-metrics v0.5.4 h1:8mmPiIJkTPPEbAiV97IxdAGNdRdaWwVap1BU6elejKY= +github.com/hashicorp/go-metrics v0.5.4/go.mod h1:CG5yz4NZ/AI/aQt9Ucm/vdBnbh7fvmv4lxZ350i+QQI= +github.com/hashicorp/go-msgpack/v2 v2.1.2 h1:4Ee8FTp834e+ewB71RDrQ0VKpyFdrKOjvYtnQ/ltVj0= +github.com/hashicorp/go-msgpack/v2 v2.1.2/go.mod h1:upybraOAblm4S7rx0+jeNy+CWWhzywQsSRV5033mMu4= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.6.3 h1:xgHB+ZUSYeuJi96WtxEjzi23uh7YQpznjGh0U0UUrwg= +github.com/hashicorp/go-plugin v1.6.3/go.mod h1:MRobyh+Wc/nYy1V4KAXUiYfzxoYhs7V1mlH1Z7iY2h0= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-sockaddr v1.0.7 h1:G+pTkSO01HpR5qCxg7lxfsFEZaG+C0VssTy/9dbT+Fw= +github.com/hashicorp/go-sockaddr v1.0.7/go.mod h1:FZQbEYa1pxkQ7WLpyXJ6cbjpT8q0YgQaK/JakXqGyWw= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= +github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= +github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= +github.com/hashicorp/memberlist v0.5.2 h1:rJoNPWZ0juJBgqn48gjy59K5H4rNgvUoM1kUD7bXiuI= +github.com/hashicorp/memberlist v0.5.2/go.mod h1:Ri9p/tRShbjYnpNf4FFPXG7wxEGY4Nrcn6E7jrVa//4= +github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE= +github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI= +github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ= +github.com/jackc/pgx v3.2.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= +github.com/jaegertracing/jaeger-idl v0.5.0 h1:zFXR5NL3Utu7MhPg8ZorxtCBjHrL3ReM1VoB65FOFGE= +github.com/jaegertracing/jaeger-idl v0.5.0/go.mod h1:ON90zFo9eoyXrt9F/KN8YeF3zxcnujaisMweFY/rg5k= +github.com/jessevdk/go-flags v1.5.0 h1:1jKYvbxEjfUl0fmqTCOfonvskHHXMjBySTLW4y9LFvc= +github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= +github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c= +github.com/jhump/protoreflect v1.15.1/go.mod h1:jD/2GMKKE6OqX8qTjhADU1e6DShO+gavG9e0Q693nKo= +github.com/jmespath-community/go-jmespath v1.1.1 h1:bFikPhsi/FdmlZhVgSCd2jj1e7G/rw+zyQfyg5UF+L4= +github.com/jmespath-community/go-jmespath v1.1.1/go.mod h1:4gOyFJsR/Gk+05RgTKYrifT7tBPWD8Lubtb5jRrfy9I= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g= +github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jszwedko/go-datemath v0.1.1-0.20230526204004-640a500621d6 h1:SwcnSwBR7X/5EHJQlXBockkJVIMRVt5yKaesBPMtyZQ= +github.com/jszwedko/go-datemath v0.1.1-0.20230526204004-640a500621d6/go.mod h1:WrYiIuiXUMIvTDAQw97C+9l0CnBmCcvosPjN3XDqS/o= +github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/asmfmt v1.3.2 h1:4Ri7ox3EwapiOjCki+hw14RyKk201CN4rzyCJRFLpK4= +github.com/klauspost/asmfmt v1.3.2/go.mod h1:AG8TuvYojzulgDAMCnYn50l/5QV3Bs/tp6j0HLHbNSE= github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= +github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE= +github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kshvakov/clickhouse v1.3.5/go.mod h1:DMzX7FxRymoNkVgizH0DWAL8Cur7wHLgx3MUnGwJqpE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/lestrrat-go/strftime v1.0.4 h1:T1Rb9EPkAhgxKqbcMIPguPq8glqXTA1koF8n9BHElA8= +github.com/lestrrat-go/strftime v1.0.4/go.mod h1:E1nN3pCbtMSu1yjSVeyuRFVm/U0xoR76fd03sz+Qz4g= +github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= +github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/magefile/mage v1.15.0 h1:BvGheCMAsG3bWUDbZ8AyXXpCNwU9u5CB6sM+HNb9HYg= +github.com/magefile/mage v1.15.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= +github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= +github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= +github.com/mattetti/filebuffer v1.0.1 h1:gG7pyfnSIZCxdoKq+cPa8T0hhYtD9NxCdI4D7PTjRLM= +github.com/mattetti/filebuffer v1.0.1/go.mod h1:YdMURNDOttIiruleeVr6f56OrMc+MydEnTcXwtkxNVs= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= +github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= +github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= +github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U= +github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA= +github.com/mdlayher/vsock v1.2.1 h1:pC1mTJTvjo1r9n9fbm7S1j04rCgCzhCOS5DY0zqHlnQ= +github.com/mdlayher/vsock v1.2.1/go.mod h1:NRfCibel++DgeMD8z/hP+PPTjlNJsdPOmxcnENvE+SE= +github.com/miekg/dns v1.1.63 h1:8M5aAw6OMZfFXTT7K5V0Eu5YiiL8l7nUAkyN6C9YwaY= +github.com/miekg/dns v1.1.63/go.mod h1:6NGHfjhpmr5lt3XPLuyfDJi5AXbNIPM9PY6H6sF1Nfs= +github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8 h1:AMFGa4R4MiIpspGNG7Z948v4n35fFGB3RR3G/ry4FWs= +github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcsrzbxHt8iiaC+zU4b1ylILSosueou12R++wfY= +github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3 h1:+n/aFZefKZp7spd8DFdX7uMikMLXX4oubIzJF4kv/wI= +github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3/go.mod h1:RagcQ7I8IeTMnF8JTXieKnO4Z6JCsikNEzj0DwauVzE= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/mapstructure v1.5.1-0.20231216201459-8508981c8b6c h1:cqn374mizHuIWj+OSJCajGr/phAmuMug9qIX3l9CflE= +github.com/mitchellh/mapstructure v1.5.1-0.20231216201459-8508981c8b6c/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/mithrandie/csvq v1.18.1 h1:f7NB2scbb7xx2ffPduJ2VtZ85RpWXfvanYskAkGlCBU= +github.com/mithrandie/csvq v1.18.1/go.mod h1:MRJj7AtcXfk7jhNGxLuJGP3LORmh4lpiPWxQ7VyCRn8= +github.com/mithrandie/csvq-driver v1.7.0 h1:ejiavXNWwTPMyr3fJFnhcqd1L1cYudA0foQy9cZrqhw= +github.com/mithrandie/csvq-driver v1.7.0/go.mod h1:HcN3xL9UCJnBYA/AIQOOB/KlyfXAiYr5yxDmiwrGk5o= +github.com/mithrandie/go-file/v2 v2.1.0 h1:XA5Tl+73GXMDvgwSE3Sg0uC5FkLr3hnXs8SpUas0hyg= +github.com/mithrandie/go-file/v2 v2.1.0/go.mod h1:9YtTF3Xo59GqC1Pxw6KyGVcM/qubAMlxVsqI/u9r++c= +github.com/mithrandie/go-text v1.6.0 h1:8gOXTMPbMY8DJbKMTv8kHhADcJlDWXqS/YQH4SyWO6s= +github.com/mithrandie/go-text v1.6.0/go.mod h1:xCgj1xiNbI/d4xA9sLVvXkjh5B2tNx2ZT2/3rpmh8to= +github.com/mithrandie/ternary v1.1.1 h1:k/joD6UGVYxHixYmSR8EGgDFNONBMqyD373xT4QRdC4= +github.com/mithrandie/ternary v1.1.1/go.mod h1:0D9Ba3+09K2TdSZO7/bFCC0GjSXetCvYuYq0u8FY/1g= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= +github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/nakagami/firebirdsql v0.0.0-20190310045651-3c02a58cfed8/go.mod h1:86wM1zFnC6/uDBfZGNwB65O+pR2OFi5q/YQaEUid1qA= github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 h1:G7ERwszslrBzRxj//JalHPu/3yz+De2J+4aLtSRlHiY= github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037/go.mod h1:2bpvgLBZEtENV5scfDFEtB/5+1M4hkQhDQrccEJ/qGw= github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 h1:bQx3WeLcUWy+RletIKwUIt4x3t8n2SxavmoclizMb8c= github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90/go.mod h1:y5+oSEHCPT/DGrS++Wc/479ERge0zTFxaF8PbGKcg2o= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= +github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo/v2 v2.22.2 h1:/3X8Panh8/WwhU/3Ssa6rCKqPLuAkVY2I0RoyDLySlU= github.com/onsi/ginkgo/v2 v2.22.2/go.mod h1:oeMosUL+8LtarXBHu/c0bx2D/K9zyQ6uX3cTyztHwsk= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8= github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY= -github.com/openfga/openfga v1.8.12 h1:xEirA6tFwaJfjBDtbHWCK0/Tw+B8XleRyhg9dcEpzHo= -github.com/openfga/openfga v1.8.12/go.mod h1:fIZyekdNB+tWQ6zIiglZonAc5ErZiDGMeHue/BzRYRM= -github.com/openfga/openfga v1.8.13 h1:ROURkotKhbmtyBX3188+cNElN8AOZmTl0CMkxUqwawo= -github.com/openfga/openfga v1.8.13/go.mod h1:h1VGcVW81eY1YyDtFx5+gxxAIEhIiOGR9SRGgs/X/k8= +github.com/open-feature/go-sdk v1.14.1 h1:jcxjCIG5Up3XkgYwWN5Y/WWfc6XobOhqrIwjyDBsoQo= +github.com/open-feature/go-sdk v1.14.1/go.mod h1:t337k0VB/t/YxJ9S0prT30ISUHwYmUd/jhUZgFcOvGg= +github.com/open-feature/go-sdk-contrib/providers/go-feature-flag v0.2.3 h1:6jpO63NCEZv4xunJj+aNlDuFVuRkVBPMcIuxvFPYRWQ= +github.com/open-feature/go-sdk-contrib/providers/go-feature-flag v0.2.3/go.mod h1:dPUHjAIFzg+ci/wt6XxlNiiMkOh5Yw4SGyeRY0AFT0g= +github.com/open-feature/go-sdk-contrib/providers/ofrep v0.1.5 h1:ZdqlGnNwhWf3luhBQlIpbglvcCzjkcuEgOEhYhr5Emc= +github.com/open-feature/go-sdk-contrib/providers/ofrep v0.1.5/go.mod h1:jrD4UG3ZCzuwImKHlyuIN2iWeYjlOX5+zJ/sX45efuE= +github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= +github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= +github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= +github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s= github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw= +github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU= +github.com/pierrec/lz4/v4 v4.1.22/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= +github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v1.21.1 h1:DOvXXTqVzvkIewV/CDPFdejpMCGeMcbGCQ8YOmu+Ibk= -github.com/prometheus/client_golang v1.21.1/go.mod h1:U9NM32ykUErtVBxdvD3zfi+EuFkkaBvMb09mIfe0Zgg= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q= github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0= -github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= -github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= -github.com/prometheus/common v0.63.0 h1:YR/EIY1o3mEFP/kZCD7iDMnLPlGyuU2Gb3HIcXnA98k= -github.com/prometheus/common v0.63.0/go.mod h1:VVFF/fBIoToEnWRVkYoXEkq3R3paCoxG9PXP74SnV18= -github.com/prometheus/common v0.64.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8= -github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= -github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= -github.com/prometheus/procfs v0.16.0/go.mod h1:8veyXUu3nGP7oaCxhX6yeaM5u4stL2FeMXnCqhDthZg= +github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/common v0.65.0 h1:QDwzd+G1twt//Kwj/Ww6E9FQq1iVMmODnILtW1t2VzE= +github.com/prometheus/common v0.65.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8= +github.com/prometheus/common/sigv4 v0.1.0 h1:qoVebwtwwEhS85Czm2dSROY5fTo2PAPEVdDeppTwGX4= +github.com/prometheus/common/sigv4 v0.1.0/go.mod h1:2Jkxxk9yYvCkE5G1sQT7GuEXm57JrvHu9k5YwTjsNtI= +github.com/prometheus/exporter-toolkit v0.14.0 h1:NMlswfibpcZZ+H0sZBiTjrA3/aBFHkNZqE+iCj5EmRg= +github.com/prometheus/exporter-toolkit v0.14.0/go.mod h1:Gu5LnVvt7Nr/oqTBUC23WILZepW0nffNo10XdhQcwWA= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= github.com/puzpuzpuz/xsync/v2 v2.5.1 h1:mVGYAvzDSu52+zaGyNjC+24Xw2bQi3kTr4QJ6N9pIIU= github.com/puzpuzpuz/xsync/v2 v2.5.1/go.mod h1:gD2H2krq/w52MfPLE+Uy64TzJDVY7lP2znR9qmR35kU= +github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= +github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= +github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA= +github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= +github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= +github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= +github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c h1:aqg5Vm5dwtvL+YgDpBcK1ITf3o96N/K7/wsRXQnUTEs= +github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c/go.mod h1:owqhoLW1qZoYLZzLnBw+QkPP9WZnjlSWihhxAJC1+/M= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546 h1:pXY9qYc/MP5zdvqWEUH6SjNiu7VhSjuVFTFiTcphaLU= +github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304 h1:Jpy1PXuP99tXNrhbq2BaPz9B+jNAvH1JPQQpG/9GCXY= +github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c h1:Ho+uVpkel/udgjbwB5Lktg9BtvJSh2DT0Hi6LPSyI2w= +github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= +github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y= +github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/teris-io/shortid v0.0.0-20171029131806-771a37caa5cf h1:Z2X3Os7oRzpdJ75iPqWZc0HeJWFYNCvKsfpQwFpRNTA= +github.com/teris-io/shortid v0.0.0-20171029131806-771a37caa5cf/go.mod h1:M8agBzgqHIhgj7wEn9/0hJUZcrvt9VY+Ln+S1I5Mha0= +github.com/tetratelabs/wazero v1.8.2 h1:yIgLR/b2bN31bjxwXHD8a3d+BogigR952csSDdLYEv4= +github.com/tetratelabs/wazero v1.8.2/go.mod h1:yAI0XTsMBhREkM/YDAK/zNou3GoiAce1P6+rp/wQhjs= +github.com/tidwall/pretty v0.0.0-20180105212114-65a9db5fad51/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/tjhop/slog-gokit v0.1.3 h1:6SdexP3UIeg93KLFeiM1Wp1caRwdTLgsD/THxBUy1+o= +github.com/tjhop/slog-gokit v0.1.3/go.mod h1:Bbu5v2748qpAWH7k6gse/kw3076IJf6owJmh7yArmJs= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/unknwon/bra v0.0.0-20200517080246-1e3013ecaff8 h1:aVGB3YnaS/JNfOW3tiHIlmNmTDg618va+eT0mVomgyI= +github.com/unknwon/bra v0.0.0-20200517080246-1e3013ecaff8/go.mod h1:fVle4kNr08ydeohzYafr20oZzbAkhQT39gKK/pFQ5M4= +github.com/unknwon/com v1.0.1 h1:3d1LTxD+Lnf3soQiD4Cp/0BRB+Rsa/+RTvz8GMMzIXs= +github.com/unknwon/com v1.0.1/go.mod h1:tOOxU81rwgoCLoOVVPHb6T/wt8HZygqH5id+GNnlCXM= +github.com/unknwon/log v0.0.0-20150304194804-e617c87089d3/go.mod h1:1xEUf2abjfP92w2GZTV+GgaRxXErwRXcClbUwrNJffU= +github.com/unknwon/log v0.0.0-20200308114134-929b1006e34a h1:vcrhXnj9g9PIE+cmZgaPSwOyJ8MAQTRmsgGrB0x5rF4= +github.com/unknwon/log v0.0.0-20200308114134-929b1006e34a/go.mod h1:1xEUf2abjfP92w2GZTV+GgaRxXErwRXcClbUwrNJffU= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli v1.22.16 h1:MH0k6uJxdwdeWQTwhSO42Pwr4YLrNLwBtg1MRgTqPdQ= +github.com/urfave/cli v1.22.16/go.mod h1:EeJR6BKodywf4zciqrdw6hpCPk68JO9z5LazXZMn5Po= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= +github.com/xanzy/go-gitlab v0.15.0/go.mod h1:8zdQa/ri1dfn8eS3Ir1SyfvOKlw7WBJ8DVThkpGiXrs= +github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= +github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ= +github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= +github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0= +github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= +gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b/go.mod h1:T3BPAOm2cqquPa0MKWeNkmOM5RQsRhkrwMWonFMN7fE= +go.mongodb.org/mongo-driver v1.1.0/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= +go.mongodb.org/mongo-driver v1.16.1 h1:rIVLL3q0IHM39dvE+z2ulZLp9ENZKThVfuvN/IiN4l8= +go.mongodb.org/mongo-driver v1.16.1/go.mod h1:oB6AhJQvFQL4LEHyXi6aJzQJtBiTQHiAd83l0GdFaiw= +go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= -go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ= -go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y= -go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0 h1:x7wzEgXfnzJcHDwStJT+mxOz4etr2EcexjqhBvmoakw= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0/go.mod h1:rg+RlpR5dKwaS95IyyZqj5Wd4E13lk/msnTS0Xl9lJM= +go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.61.0 h1:lREC4C0ilyP4WibDhQ7Gg2ygAQFP8oR07Fst/5cafwI= +go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.61.0/go.mod h1:HfvuU0kW9HewH14VCOLImqKvUgONodURG7Alj/IrnGI= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 h1:Hf9xI/XLML9ElpiHVDNwvqI0hIFlzV8dgIr35kV1kRU= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0/go.mod h1:NfchwuyNoMcZ5MLHwPrODwUF1HWCXWrL31s8gSAdIKY= +go.opentelemetry.io/contrib/propagators/jaeger v1.36.0 h1:SoCgXYF4ISDtNyfLUzsGDaaudZVTx2yJhOyBO0+/GYk= +go.opentelemetry.io/contrib/propagators/jaeger v1.36.0/go.mod h1:VHu48l0YTRKSObdPQ+Sb8xMZvdnJlN7yhHuHoPgNqHM= +go.opentelemetry.io/contrib/samplers/jaegerremote v0.30.0 h1:bQ1Gvah4Sp8z7epSkgJaNTuZm7sutfA6Fji2/7cKFMc= +go.opentelemetry.io/contrib/samplers/jaegerremote v0.30.0/go.mod h1:9b8Q9rH52NgYH3ShiTFB5wf18Vt3RTH/VMB7LDcC1ug= +go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= +go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ= go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0 h1:1fTNlAIJZGWLP5FVu0fikVry1IsiUnXjf7QFvoNN3Xw= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0/go.mod h1:zjPK58DtkqQFn+YUMbx0M2XV3QgKU0gS9LeGohREyK4= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.36.0/go.mod h1:90PoxvaEB5n6AOdZvi+yWJQoE95U8Dhhw2bSyRqnTD0= +go.opentelemetry.io/otel/exporters/jaeger v1.17.0 h1:D7UpUy2Xc2wsi1Ras6V40q806WM07rqoCWzXu7Sqy+4= +go.opentelemetry.io/otel/exporters/jaeger v1.17.0/go.mod h1:nPCqOnEH9rNLKqH/+rrUjiMzHJdV1BlpKcTwRTyKkKI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0 h1:Ahq7pZmv87yiyn3jeFz/LekZmPLLdKejuO3NcK9MssM= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0/go.mod h1:MJTqhM0im3mRLw1i8uGHnCvUEeS7VwRyxlLC78PA18M= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0 h1:m639+BofXTvcY1q8CGs4ItwQarYtJPOWmVobfM1HpVI= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0/go.mod h1:LjReUci/F4BUyv+y4dwnq3h/26iNOeC3wAIqgvTIZVo= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.36.0/go.mod h1:179AK5aar5R3eS9FucPy6rggvU0g52cvKId8pv4+v0c= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0 h1:EtFWSnwW9hGObjkIdmlnWSydO+Qs8OwzfzXLUPg4xOc= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0/go.mod h1:QjUEoiGCPkvFZ/MjK6ZZfNOS6mfVEVKYE99dFhuN2LI= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0 h1:xJ2qHD0C1BeYVTLLR9sX12+Qb95kfeD/byKj6Ky1pXg= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0/go.mod h1:u5BF1xyjstDowA1R5QAO9JHzqK+ublenEW/dyqTjBVk= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.36.0/go.mod h1:r49hO7CgrxY9Voaj3Xe8pANWtr0Oq916d0XAmOoCZAQ= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.37.0 h1:bDMKF3RUSxshZ5OjOTi8rsHGaPKsAt76FaqgvIUySLc= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.37.0/go.mod h1:dDT67G/IkA46Mr2l9Uj7HsQVwsjASyV9SjGofsiUZDA= -go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M= -go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE= -go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs= +go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM= +go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE= go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E= -go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY= -go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg= -go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY= +go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E= +go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI= go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg= -go.opentelemetry.io/otel/sdk/metric v1.35.0 h1:1RriWBmCKgkeHEhM7a2uMjMUfP7MsOF5JpUCaEqEI9o= -go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w= -go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs= -go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc= -go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA= +go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFhbjxHHspCPc= +go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps= +go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= +go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4= go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0= -go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4= -go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4= -go.opentelemetry.io/proto/otlp v1.6.0/go.mod h1:cicgGehlFuNdgZkcALOCh3VE6K/u2tAjzlRhDwmVpZc= +go.opentelemetry.io/proto/otlp v1.7.0 h1:jX1VolD6nHuFzOYso2E73H85i92Mv8JQYk0K9vz09os= go.opentelemetry.io/proto/otlp v1.7.0/go.mod h1:fSKjH6YJ7HDlwzltzyMj036AJ3ejJLCgCSHGj4efDDo= +go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= +go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI= +go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU= +go.yaml.in/yaml/v3 v3.0.3 h1:bXOww4E/J3f66rav3pX3m8w6jDE4knZjGOw8b5Y6iNE= +go.yaml.in/yaml/v3 v3.0.3/go.mod h1:tBHosrYAkRZjRAOREWbDnBXUf08JOwYq++0QNwQiWzI= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8= -golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 h1:y5zboxd6LQAqYIhHnB48p0ByQ/GnQx2BE33L8BOHQkI= +golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6/go.mod h1:U6Lno4MTRCDY+Ba7aCcauB9T60gsv5s4ralQzP72ZoQ= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w= +golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181108082009-03003ca0c849/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190424112056-4829fb13d2c6/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY= -golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E= -golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY= -golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= -golang.org/x/oauth2 v0.29.0 h1:WdYw2tdTK1S8olAzWHdgeqfy+Mtm9XNhv/xJsY65d98= -golang.org/x/oauth2 v0.29.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610= -golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= -golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= -golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190102155601-82a175fd1598/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190426135247-a129542de9ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191020152052-9984515f0562/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20= -golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/term v0.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o= -golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg= golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0= -golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU= -golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0= golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425222832-ad9eeb80039a/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.32.0 h1:Q7N1vhpkQv7ybVzLFtTjvQya2ewbwNDZzUgfXGqtMWU= -golang.org/x/tools v0.32.0/go.mod h1:ZxrU41P/wAbZD8EDa6dDCa6XfpkhJ7HFMjHJXfBDu8s= -golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo= golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da h1:noIWHXmPHxILtqtCOPIhSt0ABwskkZKjD3bXGnZGpNY= +golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= gomodules.xyz/jsonpatch/v2 v2.5.0 h1:JELs8RLM12qJGXU4u/TO3V25KW8GreMKl9pdkk14RM0= gomodules.xyz/jsonpatch/v2 v2.5.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= -google.golang.org/genproto/googleapis/api v0.0.0-20250324211829-b45e905df463 h1:hE3bRWtU6uceqlh4fhrSnUyjKHMKB9KrTLLG+bc0ddM= -google.golang.org/genproto/googleapis/api v0.0.0-20250324211829-b45e905df463/go.mod h1:U90ffi8eUL9MwPcrJylN5+Mk2v3vuPDptd5yyNUiRR8= -google.golang.org/genproto/googleapis/api v0.0.0-20250428153025-10db94c68c34/go.mod h1:0awUlEkap+Pb1UMeJwJQQAdJQrt3moU7J2moTy69irI= -google.golang.org/genproto/googleapis/api v0.0.0-20250519155744-55703ea1f237/go.mod h1:ezi0AVyMKDWy5xAncvjLWH7UcLBB5n7y2fQ8MzjJcto= +gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= +gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= +google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= +google.golang.org/api v0.3.2/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 h1:oWVWY3NzT7KJppx2UKhKmzPq4SRe0LdCijVRwvGeikY= google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822/go.mod h1:h3c4v36UTKzUiuaOKQ6gr3S+0hovBtUrXzTG/i3+XEc= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463 h1:e0AIkUUhxyBKh6ssZNrAMeqhA7RKUj42346d1y02i2g= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250428153025-10db94c68c34/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250519155744-55703ea1f237/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 h1:fc6jSaCT0vBduLYZHYrBBNY4dsWuvgyff9noRNDdBeE= google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= -google.golang.org/grpc v1.71.1 h1:ffsFWr7ygTUscGPI0KKK6TLrGz0476KUvvsbqWK0rPI= -google.golang.org/grpc v1.71.1/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec= -google.golang.org/grpc v1.72.0/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= -google.golang.org/grpc v1.72.1/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= +google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok= google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk= +gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4= gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/fsnotify/fsnotify.v1 v1.4.7 h1:XNNYLJHt73EyYiCZi6+xjupS9CpvmiDgjPTAjrBlQbo= +gopkg.in/fsnotify/fsnotify.v1 v1.4.7/go.mod h1:Fyux9zXlo4rWoMSIzpn9fDAYjalPqJ/K1qJ27s+7ltE= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/mail.v2 v2.3.1 h1:WYFn/oANrAGP2C0dcV6/pbkPzv8yGzqTjPmTeO7qoXk= +gopkg.in/mail.v2 v2.3.1/go.mod h1:htwXN1Qh09vZJ1NVKxQqHPBaCBbzKhp5GzuJEA4VJWw= +gopkg.in/src-d/go-errors.v1 v1.0.0 h1:cooGdZnCjYbeS1zb1s6pVAAimTdKceRrpn7aKOnNIfc= +gopkg.in/src-d/go-errors.v1 v1.0.0/go.mod h1:q1cBlomlw2FnDBDNGlnh6X0jPihy+QxZfMMNxPCbdYg= +gopkg.in/telebot.v3 v3.2.1 h1:3I4LohaAyJBiivGmkfB+CiVu7QFOWkuZ4+KHgO/G3rs= +gopkg.in/telebot.v3 v3.2.1/go.mod h1:GJKwwWqp9nSkIVN51eRKU78aB5f5OnQuWdwiIZfPbko= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -k8s.io/api v0.32.3 h1:Hw7KqxRusq+6QSplE3NYG4MBxZw1BZnq4aP4cJVINls= -k8s.io/api v0.32.3/go.mod h1:2wEDTXADtm/HA7CCMD8D8bK4yuBUptzaRhYcYEEYA3k= -k8s.io/api v0.33.1/go.mod h1:87esjTn9DRSRTD4fWMXamiXxJhpOIREjWOSjsW1kEHw= -k8s.io/api v0.33.2/go.mod h1:fhrbphQJSM2cXzCWgqU29xLDuks4mu7ti9vveEnpSXs= -k8s.io/apiextensions-apiserver v0.32.3 h1:4D8vy+9GWerlErCwVIbcQjsWunF9SUGNu7O7hiQTyPY= -k8s.io/apiextensions-apiserver v0.32.3/go.mod h1:8YwcvVRMVzw0r1Stc7XfGAzB/SIVLunqApySV5V7Dss= -k8s.io/apiextensions-apiserver v0.33.1/go.mod h1:uNQ52z1A1Gu75QSa+pFK5bcXc4hq7lpOXbweZgi4dqA= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +k8s.io/api v0.33.3 h1:SRd5t//hhkI1buzxb288fy2xvjubstenEKL9K51KBI8= +k8s.io/api v0.33.3/go.mod h1:01Y/iLUjNBM3TAvypct7DIj0M0NIZc+PzAHCIo0CYGE= +k8s.io/apiextensions-apiserver v0.33.2 h1:6gnkIbngnaUflR3XwE1mCefN3YS8yTD631JXQhsU6M8= k8s.io/apiextensions-apiserver v0.33.2/go.mod h1:IvVanieYsEHJImTKXGP6XCOjTwv2LUMos0YWc9O+QP8= -k8s.io/apimachinery v0.32.3 h1:JmDuDarhDmA/Li7j3aPrwhpNBA94Nvk5zLeOge9HH1U= -k8s.io/apimachinery v0.32.3/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE= -k8s.io/apimachinery v0.33.1/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM= -k8s.io/apimachinery v0.33.2/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM= -k8s.io/client-go v0.32.3 h1:RKPVltzopkSgHS7aS98QdscAgtgah/+zmpAogooIqVU= -k8s.io/client-go v0.32.3/go.mod h1:3v0+3k4IcT9bXTc4V2rt+d2ZPPG700Xy6Oi0Gdl2PaY= -k8s.io/client-go v0.33.1/go.mod h1:JAsUrl1ArO7uRVFWfcj6kOomSlCv+JpvIsp6usAGefA= -k8s.io/client-go v0.33.2/go.mod h1:9mCgT4wROvL948w6f6ArJNb7yQd7QsvqavDeZHvNmHo= +k8s.io/apimachinery v0.33.3 h1:4ZSrmNa0c/ZpZJhAgRdcsFcZOw1PQU1bALVQ0B3I5LA= +k8s.io/apimachinery v0.33.3/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM= +k8s.io/apiserver v0.33.3 h1:Wv0hGc+QFdMJB4ZSiHrCgN3zL3QRatu56+rpccKC3J4= +k8s.io/apiserver v0.33.3/go.mod h1:05632ifFEe6TxwjdAIrwINHWE2hLwyADFk5mBsQa15E= +k8s.io/client-go v0.33.3 h1:M5AfDnKfYmVJif92ngN532gFqakcGi6RvaOF16efrpA= +k8s.io/client-go v0.33.3/go.mod h1:luqKBQggEf3shbxHY4uVENAxrDISLOarxpTKMiUuujg= +k8s.io/component-base v0.33.3 h1:mlAuyJqyPlKZM7FyaoM/LcunZaaY353RXiOd2+B5tGA= +k8s.io/component-base v0.33.3/go.mod h1:ktBVsBzkI3imDuxYXmVxZ2zxJnYTZ4HAsVj9iF09qp4= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff h1:/usPimJzUKKu+m+TE36gUyGcf03XZEP0ZIKgKj35LS4= k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff/go.mod h1:5jIi+8yX4RIb8wk3XwBo5Pq2ccx4FP10ohkbSKCZoK8= -k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 h1:M3sRQVHv7vB20Xc2ybTt7ODCeFj6JSWYFzOFnYeS6Ro= -k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8= -sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo= +k8s.io/utils v0.0.0-20241210054802-24370beab758 h1:sdbE21q2nlQtFh65saZY+rRM6x6aJJI8IUa1AmH/qa0= +k8s.io/utils v0.0.0-20241210054802-24370beab758/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE= +sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= sigs.k8s.io/structured-merge-diff/v4 v4.6.0 h1:IUA9nvMmnKWcj5jl84xn+T5MnlZKThmUW1TdblaLVAc= sigs.k8s.io/structured-merge-diff/v4 v4.6.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps= -sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= +sigs.k8s.io/yaml v1.5.0 h1:M10b2U7aEUY6hRtU870n2VTPgR5RZiL/I6Lcc2F4NUQ= +sigs.k8s.io/yaml v1.5.0/go.mod h1:wZs27Rbxoai4C0f8/9urLZtZtF3avA3gKvGyPdDqTO4= +xorm.io/builder v0.3.6 h1:ha28mQ2M+TFx96Hxo+iq6tQgnkC9IZkM6D8w9sKHHF8= +xorm.io/builder v0.3.6/go.mod h1:LEFAPISnRzG+zxaxj2vPicRwz67BdhFreKg8yv8/TgU= diff --git a/go.mod b/go.mod index 05e5c77a5fc..46c47ef1f6e 100644 --- a/go.mod +++ b/go.mod @@ -22,7 +22,7 @@ require ( github.com/BurntSushi/toml v1.5.0 // @grafana/identity-access-team github.com/DATA-DOG/go-sqlmock v1.5.2 // @grafana/grafana-search-and-storage github.com/Masterminds/semver v1.5.0 // @grafana/grafana-backend-group - github.com/Masterminds/semver/v3 v3.3.1 // @grafana/grafana-developer-enablement-squad + github.com/Masterminds/semver/v3 v3.4.0 // @grafana/grafana-developer-enablement-squad github.com/Masterminds/sprig/v3 v3.3.0 // @grafana/grafana-backend-group github.com/ProtonMail/go-crypto v1.1.6 // @grafana/plugins-platform-backend github.com/VividCortex/mysqlerr v0.0.0-20170204212430-6c6b55f8796f // @grafana/grafana-backend-group diff --git a/go.sum b/go.sum index 0f4910959d3..65c00e3ac6b 100644 --- a/go.sum +++ b/go.sum @@ -736,8 +736,8 @@ github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy86 github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= -github.com/Masterminds/semver/v3 v3.3.1 h1:QtNSWtVZ3nBfk8mAOu/B6v7FMJ+NHTIgUPi7rj+4nv4= -github.com/Masterminds/semver/v3 v3.3.1/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= +github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0= +github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= github.com/Masterminds/sprig/v3 v3.2.1/go.mod h1:UoaO7Yp8KlPnJIYWTFkMaqPUYKTfGFPhxNuwnnxkKlk= github.com/Masterminds/sprig/v3 v3.3.0 h1:mQh0Yrg1XPo6vjYXgtf5OtijNAKJRNcTdOOGZe3tPhs= github.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSCzdgBfDb35Lz0= diff --git a/go.work.sum b/go.work.sum index fd43ea298b9..4c6414c6e58 100644 --- a/go.work.sum +++ b/go.work.sum @@ -506,8 +506,6 @@ contrib.go.opencensus.io/exporter/zipkin v0.1.2/go.mod h1:mP5xM3rrgOjpn79MM8fZbj contrib.go.opencensus.io/integrations/ocsql v0.1.7 h1:G3k7C0/W44zcqkpRSFyjU9f6HZkbwIrL//qqnlqWZ60= contrib.go.opencensus.io/integrations/ocsql v0.1.7/go.mod h1:8DsSdjz3F+APR+0z0WkU1aRorQCFfRxvqjUUPMbF3fE= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9 h1:VpgP7xuJadIUuKccphEpTJnWhS2jkQyMt6Y7pJCD7fY= -filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= -filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= gioui.org v0.0.0-20210308172011-57750fc8a0a6 h1:K72hopUosKG3ntOPNG4OzzbuhxGuVf06fa2la1/H/Ho= git.sr.ht/~sbinet/gg v0.6.0 h1:RIzgkizAk+9r7uPzf/VfbJHBMKUr0F5hRFxTUGMnt38= git.sr.ht/~sbinet/gg v0.6.0/go.mod h1:uucygbfC9wVPQIfrmwM2et0imr8L7KQWywX0xpFMm94= @@ -565,6 +563,7 @@ github.com/Joker/jade v1.1.3 h1:Qbeh12Vq6BxURXT1qZBRHsDxeURB8ztcL6f3EXSGeHk= github.com/Joker/jade v1.1.3/go.mod h1:T+2WLyt7VH6Lp0TRxQrUYEs64nRc83wkMQrfeIQKduM= github.com/KimMachineGun/automemlimit v0.7.1 h1:QcG/0iCOLChjfUweIMC3YL5Xy9C3VBeNmCZHrZfJMBw= github.com/KimMachineGun/automemlimit v0.7.1/go.mod h1:QZxpHaGOQoYvFhv/r4u3U0JTC2ZcOwbSr11UZF46UBM= +github.com/Masterminds/semver/v3 v3.3.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= github.com/MicahParks/keyfunc/v2 v2.1.0 h1:6ZXKb9Rp6qp1bDbJefnG7cTH8yMN1IC/4nf+GVjO99k= github.com/MicahParks/keyfunc/v2 v2.1.0/go.mod h1:rW42fi+xgLJ2FRRXAfNx9ZA8WpD4OeE/yHVMteCkw9k= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= @@ -622,8 +621,6 @@ github.com/apparentlymart/go-dump v0.0.0-20180507223929-23540a00eaa3 h1:ZSTrOEhi github.com/apparentlymart/go-dump v0.0.0-20180507223929-23540a00eaa3/go.mod h1:oL81AME2rN47vu18xqj1S1jPIPuN7afo62yKTNn3XMM= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e h1:QEF07wC0T1rKkctt1RINW/+RMTVmiwxETico2l3gxJA= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6 h1:G1bPvciwNyF7IUmKXNt9Ak3m6u9DE1rF+RmtIkBpVdA= -github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= -github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/aws/aws-msk-iam-sasl-signer-go v1.0.1 h1:nMp7diZObd4XEVUR0pEvn7/E13JIgManMX79Q6quV6E= github.com/aws/aws-msk-iam-sasl-signer-go v1.0.1/go.mod h1:MVYeeOhILFFemC/XlYTClvBjYZrg/EPd3ts885KrNTI= github.com/aws/aws-sdk-go-v2/service/kms v1.35.3 h1:UPTdlTOwWUX49fVi7cymEN6hDqCwe3LNv1vi7TXUutk= @@ -681,10 +678,12 @@ github.com/chenzhuoyu/iasm v0.9.0 h1:9fhXjVzq5hUy2gkhhgHl95zG2cEAhw9OSGs8toWWAwo github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog= github.com/chromedp/sysutil v1.1.0 h1:PUFNv5EcprjqXZD9nJb9b/c9ibAbxiYo4exNWZyipwM= github.com/chromedp/sysutil v1.1.0/go.mod h1:WiThHUdltqCNKGc4gaU50XgYjwjYIhKWoHGPTUfWTJ8= +github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE= github.com/chzyer/logex v1.2.1 h1:XHDu3E6q+gdHgsdTPH6ImJMIp436vR6MPtH8gP05QzM= github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ= github.com/chzyer/readline v1.5.1 h1:upd/6fQk4src78LMRzh5vItIt361/o4uq553V8B5sGI= github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8= github.com/chzyer/test v1.0.0 h1:p3BQDXSxOhOG0P9z6/hGnII4LGiEPOYBhs8asl/fC04= github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8= github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible h1:C29Ae4G5GtYyYMm1aztcyj/J5ckgJm2zwdDajFbx1NY= @@ -694,7 +693,6 @@ github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe h1:QQ3GSy+MqSHxm/d8nC github.com/cncf/xds/go v0.0.0-20240723142845-024c85f92f20/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= github.com/cncf/xds/go v0.0.0-20250121191232-2f005788dc42/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= -github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= github.com/cockroachdb/cockroach-go v0.0.0-20181001143604-e0a95dfd547c h1:2zRrJWIt/f9c9HhNHAgrRgq0San5gRRUJTBXLkchal0= github.com/cockroachdb/datadriven v1.0.2 h1:H9MtNqVoVhvd9nCBwOyDjUEdZCREqbIdCJD93PBm/jA= github.com/cockroachdb/datadriven v1.0.2/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= @@ -758,9 +756,11 @@ github.com/d4l3k/messagediff v1.2.1 h1:ZcAIMYsUg0EAp9X+tt8/enBE/Q8Yd5kzPynLyKptt github.com/d4l3k/messagediff v1.2.1/go.mod h1:Oozbb1TVXFac9FtSIxHBMnBCq2qeH/2KkEQxENCrlLo= github.com/davecgh/go-xdr v0.0.0-20161123171359-e6a2ba005892 h1:qg9VbHo1TlL0KDM0vYvBG9EY0X0Yku5WYIPoFWt8f6o= github.com/davecgh/go-xdr v0.0.0-20161123171359-e6a2ba005892/go.mod h1:CTDl0pzVzE5DEzZhPfvhY/9sPFMQIxaJ9VAMs9AagrE= +github.com/dchest/siphash v1.2.3/go.mod h1:0NvQU092bT0ipiFN++/rXm69QG9tVxLAlQHIXMPAkHc= github.com/dchest/uniuri v1.2.0 h1:koIcOUdrTIivZgSLhHQvKgqdWZq5d7KdMEWF1Ud6+5g= github.com/dchest/uniuri v1.2.0/go.mod h1:fSzm4SLHzNZvWLvWJew423PhAzkpNQYq+uNLq4kxhkY= github.com/denisenkom/go-mssqldb v0.0.0-20190515213511-eb9f6a1743f3 h1:tkum0XDgfR0jcVVXuTsYv/erY2NnEDqwRojbxR1rBYA= +github.com/dgryski/go-ddmin v0.0.0-20210904190556-96a6d69f1034/go.mod h1:zz4KxBkcXUWKjIcrc+uphJ1gPh/t18ymGm3PmQ+VGTk= github.com/dgryski/go-sip13 v0.0.0-20190329191031-25c5027a8c7b h1:Yqiad0+sloMPdd/0Fg22actpFx0dekpzt1xJmVNVkU0= github.com/dhui/dktest v0.3.0 h1:kwX5a7EkLcjo7VpsPQSYJcKGbXBXdjI9FGjuUj1jn6I= github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U= @@ -813,6 +813,7 @@ github.com/evanphx/json-patch/v5 v5.9.11 h1:/8HVnzMq13/3x9TPvjG08wUGqBTmZBsCWzjT github.com/evanphx/json-patch/v5 v5.9.11/go.mod h1:3j+LviiESTElxA4p3EMKAB9HXj3/XEtnUf6OZxqIQTM= github.com/expr-lang/expr v1.16.9/go.mod h1:8/vRC7+7HBzESEqt5kKpYXxrxkr31SaO8r40VO/1IT4= github.com/expr-lang/expr v1.17.0/go.mod h1:8/vRC7+7HBzESEqt5kKpYXxrxkr31SaO8r40VO/1IT4= +github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/felixge/fgprof v0.9.4 h1:ocDNwMFlnA0NU0zSB3I52xkO4sFXk80VK9lXjLClu88= @@ -885,12 +886,15 @@ github.com/golang-jwt/jwt v3.2.1+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzq github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= github.com/gomarkdown/markdown v0.0.0-20230716120725-531d2d74bc12 h1:uK3X/2mt4tbSGoHvbLBHUny7CKiuwUip3MArtukol4E= github.com/gomarkdown/markdown v0.0.0-20230716120725-531d2d74bc12/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA= +github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/cel-go v0.23.2/go.mod h1:52Pb6QsDbC5kvgxvZhiL9QX1oZEkcUF/ZqaPx1J5Wwo= github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY= github.com/google/go-jsonnet v0.18.0 h1:/6pTy6g+Jh1a1I2UMoAODkqELFiVIdOxbNwv0DDzoOg= github.com/google/go-jsonnet v0.18.0/go.mod h1:C3fTzyVJDslXdiTqw/bTFk7vSGyCtH3MGRbDfvEwGd0= github.com/google/go-pkcs11 v0.3.0 h1:PVRnTgtArZ3QQqTGtbtjtnIkzl2iY2kt24yqbrf7td8= github.com/google/go-pkcs11 v0.3.0/go.mod h1:6eQoGcuNJpa7jnd5pMGdkSaQpNDYvPlXWMcjXXThLlY= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= github.com/google/renameio v0.1.0 h1:GOZbcHa3HfsPKPlmyPyN2KEohoMXOhdMbHrvbpl2QaA= @@ -949,8 +953,6 @@ github.com/grafana/grafana-aws-sdk v0.38.2 h1:TzQD0OpWsNjtldi5G5TLDlBRk8OyDf+B5u github.com/grafana/grafana-aws-sdk v0.38.2/go.mod h1:j3vi+cXYHEFqjhBGrI6/lw1TNM+dl0Y3f0cSnDOPy+s= github.com/grafana/grafana-aws-sdk v1.0.2 h1:98eBuHYFmgvH0xO9kKf4RBsEsgQRp8EOA/9yhDIpkss= github.com/grafana/grafana-aws-sdk v1.0.2/go.mod h1:hO7q7yWV+t6dmiyJjMa3IbuYnYkBua+G/IAlOPVIYKE= -github.com/grafana/grafana-cloud-migration-snapshot v1.9.0 h1:JOzchPgptwJdruYoed7x28lFDwhzs7kssResYsnC0iI= -github.com/grafana/grafana-cloud-migration-snapshot v1.9.0/go.mod h1:nOHgq4Oa829qmBKA5KIXw5Ipo3rhLs0d6A8UI9Nw8Zk= github.com/grafana/grafana-plugin-sdk-go v0.263.0/go.mod h1:U43Cnrj/9DNYyvFcNdeUWNjMXTKNB0jcTcQGpWKd2gw= github.com/grafana/grafana-plugin-sdk-go v0.267.0/go.mod h1:OuwS4c/JYgn0rr/w5zhJBpLo4gKm/vw15RsfpYAvK9Q= github.com/grafana/grafana-plugin-sdk-go v0.269.1/go.mod h1:yv2KbO4mlr9WuDK2f+2gHAMTwwLmLuqaEnrPXTRU+OI= @@ -995,6 +997,7 @@ github.com/hashicorp/go-memdb v1.3.4 h1:XSL3NR682X/cVk2IeV0d70N4DZ9ljI885xAEU8Io github.com/hashicorp/go-memdb v1.3.4/go.mod h1:uBTr1oQbtuMgd1SSGoR8YV27eT3sBHbYiNm53bMpgSg= github.com/hashicorp/go-msgpack v1.1.5 h1:9byZdVjKTe5mce63pRVNP1L7UAmdHOTEMGehn6KvJWs= github.com/hashicorp/go-msgpack v1.1.5/go.mod h1:gWVc3sv/wbDmR3rQsj1CAktEZzoz1YNK9NfGLXJ69/4= +github.com/hashicorp/go-msgpack/v2 v2.1.1/go.mod h1:upybraOAblm4S7rx0+jeNy+CWWhzywQsSRV5033mMu4= github.com/hashicorp/go-syslog v1.0.0 h1:KaodqZuhUoZereWVIYmpUgZysurB1kBLX2j0MwMrUAE= github.com/hashicorp/go.net v0.0.1 h1:sNCoNyDEvN1xa+X0baata4RdcpKwcMS6DH+xwfqPgjw= github.com/hashicorp/logutils v1.0.0 h1:dLEQVugN8vlakKOUE3ihGLTZJRB4j+M2cdTm/ORI65Y= @@ -1018,6 +1021,8 @@ github.com/influxdata/tdigest v0.0.2-0.20210216194612-fc98d27c9e8b h1:i44CesU68Z github.com/influxdata/tdigest v0.0.2-0.20210216194612-fc98d27c9e8b/go.mod h1:Z0kXnxzbTC2qrx4NaIzYkE1k66+6oEDQTvL95hQFh5Y= github.com/influxdata/telegraf v1.16.3 h1:x0qeuSGGMg5y+YqP/5ZHwXZu3bcBrO8AAQOTNlYEb1c= github.com/influxdata/telegraf v1.16.3/go.mod h1:fX/6k7qpIqzVPWyeIamb0wN5hbwc0ANUaTS80lPYFB8= +github.com/invopop/yaml v0.3.1 h1:f0+ZpmhfBSS4MhG+4HYseMdJhoeeopbSKbq5Rpeelso= +github.com/invopop/yaml v0.3.1/go.mod h1:PMOp3nn4/12yEZUFfmOuNHJsZToEEOwoWsT+D81KkeA= github.com/iris-contrib/schema v0.0.6 h1:CPSBLyx2e91H2yJzPuhGuifVRnZBBJ3pCOMbOvPZaTw= github.com/iris-contrib/schema v0.0.6/go.mod h1:iYszG0IOsuIsfzjymw1kMzTL8YQcCWlm65f3wX8J5iA= github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 h1:vr3AYkKovP8uR8AvSGGUK1IDqRa5lAAvEkZG1LKaCRc= @@ -1105,6 +1110,7 @@ github.com/mailgun/raymond/v2 v2.0.48 h1:5dmlB680ZkFG2RN/0lvTAghrSxIESeu9/2aeDqA github.com/mailgun/raymond/v2 v2.0.48/go.mod h1:lsgvL50kgt1ylcFJYZiULi5fjPBkkhNfj4KA0W54Z18= github.com/matryer/moq v0.5.2 h1:b2bsanSaO6IdraaIvPBzHnqcrkkQmk1/310HdT2nNQs= github.com/matryer/moq v0.5.2/go.mod h1:W/k5PLfou4f+bzke9VPXTbfJljxoeR1tLHigsmbshmU= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= github.com/maxbrunsfeld/counterfeiter/v6 v6.11.2 h1:yVCLo4+ACVroOEr4iFU1iH46Ldlzz2rTuu18Ra7M8sU= github.com/maxbrunsfeld/counterfeiter/v6 v6.11.2/go.mod h1:VzB2VoMh1Y32/QqDfg9ZJYHj99oM4LiGtqPZydTiQSQ= @@ -1112,6 +1118,7 @@ github.com/mfridman/xflag v0.1.0 h1:TWZrZwG1QklFX5S4j1vxfF1sZbZeZSGofMwPMLAF29M= github.com/mfridman/xflag v0.1.0/go.mod h1:/483ywM5ZO5SuMVjrIGquYNE5CzLrj5Ux/LxWWnjRaE= github.com/microcosm-cc/bluemonday v1.0.25 h1:4NEwSfiJ+Wva0VxN5B8OwMicaJvD8r9tlJWm9rtloEg= github.com/microcosm-cc/bluemonday v1.0.25/go.mod h1:ZIOjCQp1OrzBBPIJmfX4qDYFuhU02nx4bn030ixfHLE= +github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU= github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= github.com/mitchellh/cli v1.1.5 h1:OxRIeJXpAMztws/XHlN2vu6imG5Dpq+j61AzAX5fLng= @@ -1124,8 +1131,6 @@ github.com/mithrandie/readline-csvq v1.3.0 h1:VTJEOGouJ8j27jJCD4kBBbNTxM0OdBvE1a github.com/mithrandie/readline-csvq v1.3.0/go.mod h1:FKyYqDgf/G4SNov7SMFXRWO6LQLXIOeTog/NB97FZl0= github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= -github.com/moby/spdystream v0.5.0 h1:7r0J1Si3QO/kjRitvSLVVFUjxMEb/YLj6S9FF62JBCU= -github.com/moby/spdystream v0.5.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI= github.com/moby/sys/atomicwriter v0.1.0 h1:kw5D/EqkBwsBFi0ss9v1VG3wIkVhzGvLklJ+w3A14Sw= github.com/moby/sys/atomicwriter v0.1.0/go.mod h1:Ul8oqv2ZMNHOceF643P6FKPXeCmYtlQMvpizfsSoaWs= github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc= @@ -1138,7 +1143,6 @@ github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8 github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= github.com/mostynb/go-grpc-compression v1.2.3 h1:42/BKWMy0KEJGSdWvzqIyOZ95YcR9mLPqKctH7Uo//I= github.com/mostynb/go-grpc-compression v1.2.3/go.mod h1:AghIxF3P57umzqM9yz795+y1Vjs47Km/Y2FE6ouQ7Lg= -github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= github.com/nakagami/firebirdsql v0.0.0-20190310045651-3c02a58cfed8 h1:P48LjvUQpTReR3TQRbxSeSBsMXzfK0uol7eRcr7VBYQ= github.com/natefinch/atomic v1.0.1 h1:ZPYKxkqQOx3KZ+RsbnP/YsgvxWQPGxjC0oBt2AhwV0A= github.com/natefinch/atomic v1.0.1/go.mod h1:N/D/ELrljoqDyT3rZrsUmtsuzvHkeB/wWjHV22AZRbM= @@ -1151,8 +1155,10 @@ github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWb github.com/nsf/jsondiff v0.0.0-20230430225905-43f6cf3098c1 h1:dOYG7LS/WK00RWZc8XGgcUTlTxpp3mKhdR2Q9z9HbXM= github.com/nsf/jsondiff v0.0.0-20230430225905-43f6cf3098c1/go.mod h1:mpRZBD8SJ55OIICQ3iWH0Yz3cjzA61JdqMLoWXeB2+8= github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= +github.com/onsi/ginkgo/v2 v2.21.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo= github.com/onsi/ginkgo/v2 v2.22.1/go.mod h1:S6aTpoRsSq2cZOd+pssHAlKW/Q/jZt6cPrPlnj4a1xM= github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= +github.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog= github.com/open-telemetry/opentelemetry-collector-contrib/exporter/zipkinexporter v0.124.1 h1:+aiMrDR6xiaDM7xN4ByrBYI0Craqt68nZicmpYpt0co= github.com/open-telemetry/opentelemetry-collector-contrib/exporter/zipkinexporter v0.124.1/go.mod h1:H/TEWN4jgExt0McrtrBK2VFK6r9LRsWtqhEZrH690rs= github.com/open-telemetry/opentelemetry-collector-contrib/internal/coreinternal v0.124.1 h1:NrjsoVPxI6lmV8jPImDcMeqYh+97Y71f/HB5Sfpfe3I= @@ -1203,7 +1209,6 @@ github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2D github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30 h1:BHT1/DKsYDGkUgQ2jmMaozVcdk+sVfz0+1ZJq4zkWgw= github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g= -github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/philhofer/fwd v1.1.2 h1:bnDivRJ1EWPjUIRXV5KfORO897HTbpFAQddBdE8t7Gw= @@ -1220,6 +1225,7 @@ github.com/pquerna/cachecontrol v0.1.0 h1:yJMy84ti9h/+OEWa752kBTKv4XC30OtVVHYv/8 github.com/pquerna/cachecontrol v0.1.0/go.mod h1:NrUG3Z7Rdu85UNR3vm7SOsl1nFIeSiQnrHV5K9mBcUI= github.com/pquerna/ffjson v0.0.0-20190930134022-aa0246cd15f7 h1:xoIK0ctDddBMnc74udxJYBqlo9Ylnsp1waqjLsnef20= github.com/pquerna/ffjson v0.0.0-20190930134022-aa0246cd15f7/go.mod h1:YARuvh7BUWHNhzDq2OM5tzR2RiCcN2D7sapiKyCel/M= +github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I= github.com/prometheus/common/assets v0.2.0 h1:0P5OrzoHrYBOSM1OigWL3mY8ZvV2N4zIE/5AahrSrfM= github.com/prometheus/statsd_exporter v0.26.1 h1:ucbIAdPmwAUcA+dU+Opok8Qt81Aw8HanlO+2N/Wjv7w= github.com/prometheus/statsd_exporter v0.26.1/go.mod h1:XlDdjAmRmx3JVvPPYuFNUg+Ynyb5kR69iPPkQjxXFMk= @@ -1235,6 +1241,7 @@ github.com/richardartoul/molecule v1.0.0 h1:+LFA9cT7fn8KF39zy4dhOnwcOwRoqKiBkPqK github.com/richardartoul/molecule v1.0.0/go.mod h1:uvX/8buq8uVeiZiFht+0lqSLBHF+uGV8BrTv8W/SIwk= github.com/rogpeppe/fastuuid v1.2.0 h1:Ppwyp6VYCF1nvBTXL3trRso7mXMlRrw9ooo375wvi2s= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/rs/dnscache v0.0.0-20230804202142-fc85eb664529 h1:18kd+8ZUlt/ARXhljq+14TwAoKa61q6dX8jtwOf6DH8= github.com/rs/dnscache v0.0.0-20230804202142-fc85eb664529/go.mod h1:qe5TWALJ8/a1Lqznoc5BDHpYX/8HU60Hm2AwRmqzxqA= github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww= @@ -1261,6 +1268,7 @@ github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/spf13/afero v1.10.0/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= +github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g= github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= @@ -1364,6 +1372,7 @@ go.einride.tech/aip v0.68.1/go.mod h1:XaFtaj4HuA3Zwk9xoBtTWgNubZ0ZZXv9BZJCkuKuWb go.etcd.io/bbolt v1.3.11/go.mod h1:dksAq7YMXoljX0xu6VF5DMZGbhYYoLUalEiSySYAS4I= go.etcd.io/gofail v0.2.0 h1:p19drv16FKK345a09a1iubchlw/vmRuksmRzgBIGjcA= go.etcd.io/gofail v0.2.0/go.mod h1:nL3ILMGfkXTekKI3clMBNazKnjUZjYLKmBHzsVAnC1o= +go.mongodb.org/mongo-driver v1.14.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c= go.opentelemetry.io/collector v0.124.0 h1:g/dfdGFhBcQI0ggGxTmGlJnJ6Yl6T2gVxQoIj4UfXCc= go.opentelemetry.io/collector v0.124.0/go.mod h1:QzERYfmHUedawjr8Ph/CBEEkVqWS8IlxRLAZt+KHlCg= go.opentelemetry.io/collector/client v1.30.0 h1:QbvOrvwUGcnVjnIBn2zyLLubisOjgh7kMgkzDAiYpHg= @@ -1514,6 +1523,7 @@ go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.36.0/go.mod h1:PD57idA/ go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= go.opentelemetry.io/otel/metric v1.29.0/go.mod h1:auu/QWieFVWx+DmQOUMgj0F8LHWdgalxXqvp7BII/W8= go.opentelemetry.io/otel/metric v1.31.0/go.mod h1:C3dEloVbLuYoX41KpmAhOqNriGbA+qqH6PQ5E5mUfnY= +go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg= go.opentelemetry.io/otel/sdk v1.29.0/go.mod h1:pM8Dx5WKnvxLCb+8lG1PRNIDxu9g9b9g59Qr7hfAAok= go.opentelemetry.io/otel/sdk v1.31.0/go.mod h1:TfRbMdhvxIIr/B2N2LQW2S5v9m3gOQ/08KsbbO5BPT0= go.opentelemetry.io/otel/sdk/metric v1.29.0/go.mod h1:6zZLdCl2fkauYoZIOn/soQIDSWFmNSRcICarHfuhNJQ= @@ -1529,6 +1539,8 @@ go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwE go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= golang.org/x/arch v0.4.0 h1:A8WCeEWhLwPBKNbFi5Wv5UTCBx5zzubnXDlMOFAzFMc= golang.org/x/arch v0.4.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= +golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ= @@ -1545,13 +1557,19 @@ golang.org/x/image v0.25.0/go.mod h1:tCAmOEGthTtkalusGp1g3xa2gke8J6c2N565dTyl9Rs golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028 h1:4+4C/Iv2U4fMZBiMCc98MG1In4gJY5YRhtpDNeDeHWs= golang.org/x/mod v0.6.0-dev.0.20220818022119-ed83ed61efb9/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211123203042-d83791d6bcd9/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= +golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= +golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM= golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= @@ -1559,22 +1577,33 @@ golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= golang.org/x/oauth2 v0.19.0/go.mod h1:vYi7skDa1x015PmRRYZ7+s1cWyPgrPiSYRe4rnsexc8= golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/oauth2 v0.28.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= +golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/telemetry v0.0.0-20240521205824-bda55230c457 h1:zf5N6UOrA487eEFacMePxjXAJctxKmyjKUsjA11Uzuk= golang.org/x/telemetry v0.0.0-20240521205824-bda55230c457/go.mod h1:pRgIJT+bRLFKnoM1ldnzKoxTIn14Yxz928LQRYYgIN0= golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g= golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/time v0.10.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/tools v0.0.0-20190424220101-1e8e1cfdf96b/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= +golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0= +golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c= golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0= golang.org/x/tools v0.28.0/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw= @@ -1643,14 +1672,17 @@ google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFN google.golang.org/grpc v1.67.3/go.mod h1:YGaHCc6Oap+FzBJTZLBzkGSYt/cvGPFTPxkn7QfSU8s= google.golang.org/grpc v1.68.1/go.mod h1:+q1XYFJjShcqn0QZHvCyeR4CXPA+llXIeUIfIe00waw= google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw= +google.golang.org/grpc v1.71.0/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec= google.golang.org/grpc v1.72.2/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0 h1:M1YKkFIboKNieVO5DLUEVzQfGwJD30Nv2jfUgzb5UcE= google.golang.org/grpc/examples v0.0.0-20230224211313-3775f633ce20 h1:MLBCGN1O7GzIx+cBiwfYPwtmZ41U3Mn/cotLJciaArI= google.golang.org/grpc/examples v0.0.0-20230224211313-3775f633ce20/go.mod h1:Nr5H8+MlGWr5+xX/STzdoEqJrO+YteqFbMyCsrb6mH0= google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= google.golang.org/protobuf v1.36.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= google.golang.org/protobuf v1.36.4/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= gopkg.in/errgo.v2 v2.1.0 h1:0vLT13EuvQ0hNvakwLuFZ/jYrLp5F3kcWHXdRggjCE8= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= diff --git a/pkg/build/go.mod b/pkg/build/go.mod index 292e25afbf4..14dd91a5033 100644 --- a/pkg/build/go.mod +++ b/pkg/build/go.mod @@ -9,7 +9,7 @@ replace github.com/docker/docker => github.com/moby/moby v27.5.1+incompatible require ( cloud.google.com/go/storage v1.55.0 // @grafana/grafana-backend-group - github.com/Masterminds/semver/v3 v3.3.1 // @grafana/grafana-developer-enablement-squad + github.com/Masterminds/semver/v3 v3.4.0 // @grafana/grafana-developer-enablement-squad github.com/aws/aws-sdk-go v1.55.7 // @grafana/aws-datasources github.com/docker/docker v28.1.1+incompatible // @grafana/grafana-developer-enablement-squad github.com/drone/drone-cli v1.8.0 // @grafana/grafana-developer-enablement-squad diff --git a/pkg/build/go.sum b/pkg/build/go.sum index 2fafffb86ae..9392a9616ff 100644 --- a/pkg/build/go.sum +++ b/pkg/build/go.sum @@ -44,8 +44,8 @@ github.com/Khan/genqlient v0.8.1 h1:wtOCc8N9rNynRLXN3k3CnfzheCUNKBcvXmVv5zt6WCs= github.com/Khan/genqlient v0.8.1/go.mod h1:R2G6DzjBvCbhjsEajfRjbWdVglSH/73kSivC9TLWVjU= github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= -github.com/Masterminds/semver/v3 v3.3.1 h1:QtNSWtVZ3nBfk8mAOu/B6v7FMJ+NHTIgUPi7rj+4nv4= -github.com/Masterminds/semver/v3 v3.3.1/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= +github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0= +github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= From 20cea80795c1e86a867a3e5a5937f237ef5f3c68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roberto=20Jim=C3=A9nez=20S=C3=A1nchez?= Date: Fri, 25 Jul 2025 18:38:10 +0200 Subject: [PATCH 013/131] Provisioning: Add bulk delete job (#108580) * Add delete job type * Regenerate spec * Add first implementation of worker * Move interface and mock to repository package * Add unit tests * Add integration tests * Fix linting and spec * Regenerate client * Format file * go fmt * fix --------- Co-authored-by: Stephanie Hingtgen --- pkg/apis/provisioning/v0alpha1/jobs.go | 19 + .../v0alpha1/zz_generated.deepcopy.go | 26 ++ .../v0alpha1/zz_generated.openapi.go | 51 ++- ...enerated.openapi_violation_exceptions.list | 1 + .../apis/provisioning/jobs/delete/worker.go | 96 +++++ .../provisioning/jobs/delete/worker_test.go | 373 ++++++++++++++++++ pkg/registry/apis/provisioning/register.go | 9 +- .../repository/mock_wrap_with_stage_fn.go | 85 ++++ .../apis/provisioning/repository/staged.go | 3 + .../provisioning.grafana.app-v0alpha1.json | 32 +- .../apis/provisioning/provisioning_test.go | 154 +++++++- .../provisioning/v0alpha1/endpoints.gen.ts | 14 +- 12 files changed, 851 insertions(+), 12 deletions(-) create mode 100644 pkg/registry/apis/provisioning/jobs/delete/worker.go create mode 100644 pkg/registry/apis/provisioning/jobs/delete/worker_test.go create mode 100644 pkg/registry/apis/provisioning/repository/mock_wrap_with_stage_fn.go diff --git a/pkg/apis/provisioning/v0alpha1/jobs.go b/pkg/apis/provisioning/v0alpha1/jobs.go index 5d0348864a7..ceea231400b 100644 --- a/pkg/apis/provisioning/v0alpha1/jobs.go +++ b/pkg/apis/provisioning/v0alpha1/jobs.go @@ -37,6 +37,9 @@ const ( // JobActionMigrate acts like JobActionExport, then JobActionPull. It also tries to preserve the history. JobActionMigrate JobAction = "migrate" + + // JobActionDelete deletes files in the remote repository + JobActionDelete JobAction = "delete" ) // +enum @@ -81,6 +84,9 @@ type JobSpec struct { // Required when the action is `migrate` Migrate *MigrateJobOptions `json:"migrate,omitempty"` + + // Delete when the action is `delete` + Delete *DeleteJobOptions `json:"delete,omitempty"` } type PullRequestJobOptions struct { @@ -109,9 +115,11 @@ type ExportJobOptions struct { // The source folder (or empty) to export Folder string `json:"folder,omitempty"` + // FIXME: we should validate this in admission hooks // Target branch for export (only git) Branch string `json:"branch,omitempty"` + // FIXME: we should validate this in admission hooks // Prefix in target file system Path string `json:"path,omitempty"` } @@ -124,6 +132,17 @@ type MigrateJobOptions struct { Message string `json:"message,omitempty"` } +type DeleteJobOptions struct { + // Ref to the branch or commit hash to delete from + Ref string `json:"ref,omitempty"` + // Paths to be deleted. Examples: + // - dashboard.json (for a file) + // - a/b/c/other-dashboard.json (for a file) + // - nested/deep/ (for a directory) + // FIXME: we should validate this in admission hooks + Paths []string `json:"paths,omitempty"` +} + // The job status type JobStatus struct { State JobState `json:"state,omitempty"` diff --git a/pkg/apis/provisioning/v0alpha1/zz_generated.deepcopy.go b/pkg/apis/provisioning/v0alpha1/zz_generated.deepcopy.go index 30fd560a597..bed49953b63 100644 --- a/pkg/apis/provisioning/v0alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/provisioning/v0alpha1/zz_generated.deepcopy.go @@ -48,6 +48,27 @@ func (in *BitbucketRepositoryConfig) DeepCopy() *BitbucketRepositoryConfig { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DeleteJobOptions) DeepCopyInto(out *DeleteJobOptions) { + *out = *in + if in.Paths != nil { + in, out := &in.Paths, &out.Paths + *out = make([]string, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DeleteJobOptions. +func (in *DeleteJobOptions) DeepCopy() *DeleteJobOptions { + if in == nil { + return nil + } + out := new(DeleteJobOptions) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ErrorDetails) DeepCopyInto(out *ErrorDetails) { *out = *in @@ -370,6 +391,11 @@ func (in *JobSpec) DeepCopyInto(out *JobSpec) { *out = new(MigrateJobOptions) **out = **in } + if in.Delete != nil { + in, out := &in.Delete, &out.Delete + *out = new(DeleteJobOptions) + (*in).DeepCopyInto(*out) + } return } diff --git a/pkg/apis/provisioning/v0alpha1/zz_generated.openapi.go b/pkg/apis/provisioning/v0alpha1/zz_generated.openapi.go index 37db6def7d7..b81342c30c3 100644 --- a/pkg/apis/provisioning/v0alpha1/zz_generated.openapi.go +++ b/pkg/apis/provisioning/v0alpha1/zz_generated.openapi.go @@ -16,6 +16,7 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA return map[string]common.OpenAPIDefinition{ "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.Author": schema_pkg_apis_provisioning_v0alpha1_Author(ref), "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.BitbucketRepositoryConfig": schema_pkg_apis_provisioning_v0alpha1_BitbucketRepositoryConfig(ref), + "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.DeleteJobOptions": schema_pkg_apis_provisioning_v0alpha1_DeleteJobOptions(ref), "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.ErrorDetails": schema_pkg_apis_provisioning_v0alpha1_ErrorDetails(ref), "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.ExportJobOptions": schema_pkg_apis_provisioning_v0alpha1_ExportJobOptions(ref), "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.FileItem": schema_pkg_apis_provisioning_v0alpha1_FileItem(ref), @@ -155,6 +156,40 @@ func schema_pkg_apis_provisioning_v0alpha1_BitbucketRepositoryConfig(ref common. } } +func schema_pkg_apis_provisioning_v0alpha1_DeleteJobOptions(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "ref": { + SchemaProps: spec.SchemaProps{ + Description: "Ref to the branch or commit hash to delete from", + Type: []string{"string"}, + Format: "", + }, + }, + "paths": { + SchemaProps: spec.SchemaProps{ + Description: "Paths to be deleted. Examples: - dashboard.json (for a file) - a/b/c/other-dashboard.json (for a file) - nested/deep/ (for a directory) FIXME: we should validate this in admission hooks", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + }, + }, + }, + } +} + func schema_pkg_apis_provisioning_v0alpha1_ErrorDetails(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -209,14 +244,14 @@ func schema_pkg_apis_provisioning_v0alpha1_ExportJobOptions(ref common.Reference }, "branch": { SchemaProps: spec.SchemaProps{ - Description: "Target branch for export (only git)", + Description: "FIXME: we should validate this in admission hooks Target branch for export (only git)", Type: []string{"string"}, Format: "", }, }, "path": { SchemaProps: spec.SchemaProps{ - Description: "Prefix in target file system", + Description: "FIXME: we should validate this in admission hooks Prefix in target file system", Type: []string{"string"}, Format: "", }, @@ -843,10 +878,10 @@ func schema_pkg_apis_provisioning_v0alpha1_JobSpec(ref common.ReferenceCallback) Properties: map[string]spec.Schema{ "action": { SchemaProps: spec.SchemaProps{ - Description: "Possible enum values:\n - `\"migrate\"` acts like JobActionExport, then JobActionPull. It also tries to preserve the history.\n - `\"pr\"` adds additional useful information to a PR, such as comments with preview links and rendered images.\n - `\"pull\"` replicates the remote branch in the local copy of the repository.\n - `\"push\"` replicates the local copy of the repository in the remote branch.", + Description: "Possible enum values:\n - `\"delete\"` deletes files in the remote repository\n - `\"migrate\"` acts like JobActionExport, then JobActionPull. It also tries to preserve the history.\n - `\"pr\"` adds additional useful information to a PR, such as comments with preview links and rendered images.\n - `\"pull\"` replicates the remote branch in the local copy of the repository.\n - `\"push\"` replicates the local copy of the repository in the remote branch.", Type: []string{"string"}, Format: "", - Enum: []interface{}{"migrate", "pr", "pull", "push"}, + Enum: []interface{}{"delete", "migrate", "pr", "pull", "push"}, }, }, "repository": { @@ -880,11 +915,17 @@ func schema_pkg_apis_provisioning_v0alpha1_JobSpec(ref common.ReferenceCallback) Ref: ref("github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.MigrateJobOptions"), }, }, + "delete": { + SchemaProps: spec.SchemaProps{ + Description: "Delete when the action is `delete`", + Ref: ref("github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.DeleteJobOptions"), + }, + }, }, }, }, Dependencies: []string{ - "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.ExportJobOptions", "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.MigrateJobOptions", "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.PullRequestJobOptions", "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.SyncJobOptions"}, + "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.DeleteJobOptions", "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.ExportJobOptions", "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.MigrateJobOptions", "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.PullRequestJobOptions", "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1.SyncJobOptions"}, } } diff --git a/pkg/apis/provisioning/v0alpha1/zz_generated.openapi_violation_exceptions.list b/pkg/apis/provisioning/v0alpha1/zz_generated.openapi_violation_exceptions.list index 6c41753b403..fc982653184 100644 --- a/pkg/apis/provisioning/v0alpha1/zz_generated.openapi_violation_exceptions.list +++ b/pkg/apis/provisioning/v0alpha1/zz_generated.openapi_violation_exceptions.list @@ -1,3 +1,4 @@ +API rule violation: list_type_missing,github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1,DeleteJobOptions,Paths API rule violation: list_type_missing,github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1,FileList,Items API rule violation: list_type_missing,github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1,HistoryList,Items API rule violation: list_type_missing,github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1,JobResourceSummary,Errors diff --git a/pkg/registry/apis/provisioning/jobs/delete/worker.go b/pkg/registry/apis/provisioning/jobs/delete/worker.go new file mode 100644 index 00000000000..5489445d216 --- /dev/null +++ b/pkg/registry/apis/provisioning/jobs/delete/worker.go @@ -0,0 +1,96 @@ +package delete + +import ( + "context" + "errors" + "fmt" + "time" + + provisioning "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1" + "github.com/grafana/grafana/pkg/registry/apis/provisioning/jobs" + "github.com/grafana/grafana/pkg/registry/apis/provisioning/repository" +) + +type Worker struct { + syncWorker jobs.Worker + wrapFn repository.WrapWithStageFn +} + +func NewWorker(syncWorker jobs.Worker, wrapFn repository.WrapWithStageFn) *Worker { + return &Worker{ + syncWorker: syncWorker, + wrapFn: wrapFn, + } +} + +func (w *Worker) IsSupported(ctx context.Context, job provisioning.Job) bool { + return job.Spec.Action == provisioning.JobActionDelete +} + +func (w *Worker) Process(ctx context.Context, repo repository.Repository, job provisioning.Job, progress jobs.JobProgressRecorder) error { + if job.Spec.Delete == nil { + return errors.New("missing delete settings") + } + opts := *job.Spec.Delete + + paths := opts.Paths + progress.SetTotal(ctx, len(paths)) + progress.StrictMaxErrors(1) // Fail fast on any error during deletion + + fn := func(repo repository.Repository, _ bool) error { + rw, ok := repo.(repository.ReaderWriter) + if !ok { + return errors.New("delete job submitted targeting repository that is not a ReaderWriter") + } + + return w.deleteFiles(ctx, rw, progress, opts, paths...) + } + + stageOptions := repository.StageOptions{ + PushOnWrites: false, + Timeout: 10 * time.Minute, + } + + err := w.wrapFn(ctx, repo, stageOptions, fn) + if err != nil { + return fmt.Errorf("delete files from repository: %w", err) + } + + if opts.Ref == "" { + progress.ResetResults() + progress.SetMessage(ctx, "pull resources") + + syncJob := provisioning.Job{ + Spec: provisioning.JobSpec{ + Pull: &provisioning.SyncJobOptions{ + // Full sync because it's the only one that supports empty folder deletion + Incremental: false, + }, + }, + } + + if err := w.syncWorker.Process(ctx, repo, syncJob, progress); err != nil { + return fmt.Errorf("pull resources: %w", err) + } + } + + return nil +} + +func (w *Worker) deleteFiles(ctx context.Context, rw repository.ReaderWriter, progress jobs.JobProgressRecorder, opts provisioning.DeleteJobOptions, paths ...string) error { + for _, path := range paths { + result := jobs.JobResourceResult{ + Path: path, + Action: repository.FileActionDeleted, + } + + progress.SetMessage(ctx, "Deleting "+path) + result.Error = rw.Delete(ctx, path, opts.Ref, "Delete "+path) + progress.Record(ctx, result) + if err := progress.TooManyErrors(); err != nil { + return err + } + } + + return nil +} diff --git a/pkg/registry/apis/provisioning/jobs/delete/worker_test.go b/pkg/registry/apis/provisioning/jobs/delete/worker_test.go new file mode 100644 index 00000000000..d2ba09ba85d --- /dev/null +++ b/pkg/registry/apis/provisioning/jobs/delete/worker_test.go @@ -0,0 +1,373 @@ +package delete + +import ( + "context" + "errors" + "testing" + "time" + + provisioning "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1" + "github.com/grafana/grafana/pkg/registry/apis/provisioning/jobs" + "github.com/grafana/grafana/pkg/registry/apis/provisioning/repository" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" +) + +type mockReaderWriter struct { + *repository.MockRepository +} + +func (m *mockReaderWriter) Delete(ctx context.Context, path, ref, message string) error { + args := m.Called(ctx, path, ref, message) + return args.Error(0) +} + +func TestDeleteWorker_IsSupported(t *testing.T) { + tests := []struct { + name string + job provisioning.Job + expected bool + }{ + { + name: "delete action is supported", + job: provisioning.Job{ + Spec: provisioning.JobSpec{ + Action: provisioning.JobActionDelete, + }, + }, + expected: true, + }, + { + name: "pull action is not supported", + job: provisioning.Job{ + Spec: provisioning.JobSpec{ + Action: provisioning.JobActionPull, + }, + }, + expected: false, + }, + { + name: "push action is not supported", + job: provisioning.Job{ + Spec: provisioning.JobSpec{ + Action: provisioning.JobActionPush, + }, + }, + expected: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + worker := NewWorker(nil, nil) + result := worker.IsSupported(context.Background(), tt.job) + require.Equal(t, tt.expected, result) + }) + } +} + +func TestDeleteWorker_ProcessMissingDeleteSettings(t *testing.T) { + job := provisioning.Job{ + Spec: provisioning.JobSpec{ + Action: provisioning.JobActionDelete, + }, + } + + worker := NewWorker(nil, nil) + err := worker.Process(context.Background(), nil, job, nil) + require.EqualError(t, err, "missing delete settings") +} + +func TestDeleteWorker_ProcessNotReaderWriter(t *testing.T) { + job := provisioning.Job{ + Spec: provisioning.JobSpec{ + Action: provisioning.JobActionDelete, + Delete: &provisioning.DeleteJobOptions{ + Paths: []string{"test/path"}, + }, + }, + } + + mockRepo := repository.NewMockRepository(t) + mockProgress := jobs.NewMockJobProgressRecorder(t) + mockWrapFn := repository.NewMockWrapWithStageFn(t) + + mockWrapFn.On("Execute", mock.Anything, mockRepo, mock.MatchedBy(func(opts repository.StageOptions) bool { + return !opts.PushOnWrites && opts.Timeout == 10*time.Minute + }), mock.Anything).Return(errors.New("delete job submitted targeting repository that is not a ReaderWriter")) + + mockProgress.On("SetTotal", mock.Anything, 1).Return() + mockProgress.On("StrictMaxErrors", 1).Return() + + worker := NewWorker(nil, mockWrapFn.Execute) + err := worker.Process(context.Background(), mockRepo, job, mockProgress) + require.EqualError(t, err, "delete files from repository: delete job submitted targeting repository that is not a ReaderWriter") +} + +func TestDeleteWorker_ProcessWrapFnError(t *testing.T) { + job := provisioning.Job{ + Spec: provisioning.JobSpec{ + Action: provisioning.JobActionDelete, + Delete: &provisioning.DeleteJobOptions{ + Paths: []string{"test/path"}, + }, + }, + } + + mockRepo := repository.NewMockRepository(t) + mockProgress := jobs.NewMockJobProgressRecorder(t) + mockWrapFn := repository.NewMockWrapWithStageFn(t) + + mockWrapFn.On("Execute", mock.Anything, mockRepo, mock.Anything, mock.Anything).Return(errors.New("stage failed")) + mockProgress.On("SetTotal", mock.Anything, 1).Return() + mockProgress.On("StrictMaxErrors", 1).Return() + + worker := NewWorker(nil, mockWrapFn.Execute) + err := worker.Process(context.Background(), mockRepo, job, mockProgress) + require.EqualError(t, err, "delete files from repository: stage failed") +} + +func TestDeleteWorker_ProcessDeleteFilesSuccess(t *testing.T) { + job := provisioning.Job{ + Spec: provisioning.JobSpec{ + Action: provisioning.JobActionDelete, + Delete: &provisioning.DeleteJobOptions{ + Paths: []string{"test/path1", "test/path2"}, + Ref: "main", + }, + }, + } + + mockRepo := &mockReaderWriter{ + MockRepository: repository.NewMockRepository(t), + } + mockProgress := jobs.NewMockJobProgressRecorder(t) + mockWrapFn := repository.NewMockWrapWithStageFn(t) + + mockWrapFn.On("Execute", mock.Anything, mockRepo, mock.MatchedBy(func(opts repository.StageOptions) bool { + return !opts.PushOnWrites && opts.Timeout == 10*time.Minute + }), mock.Anything).Return(func(ctx context.Context, repo repository.Repository, stageOptions repository.StageOptions, fn func(repository.Repository, bool) error) error { + return fn(mockRepo, false) + }) + + mockProgress.On("SetTotal", mock.Anything, 2).Return() + mockProgress.On("StrictMaxErrors", 1).Return() + mockProgress.On("SetMessage", mock.Anything, "Deleting test/path1").Return() + mockProgress.On("SetMessage", mock.Anything, "Deleting test/path2").Return() + mockProgress.On("TooManyErrors").Return(nil).Twice() + + mockRepo.On("Delete", mock.Anything, "test/path1", "main", "Delete test/path1").Return(nil) + mockRepo.On("Delete", mock.Anything, "test/path2", "main", "Delete test/path2").Return(nil) + + mockProgress.On("Record", mock.Anything, mock.MatchedBy(func(result jobs.JobResourceResult) bool { + return result.Path == "test/path1" && result.Action == repository.FileActionDeleted && result.Error == nil + })).Return() + mockProgress.On("Record", mock.Anything, mock.MatchedBy(func(result jobs.JobResourceResult) bool { + return result.Path == "test/path2" && result.Action == repository.FileActionDeleted && result.Error == nil + })).Return() + + worker := NewWorker(nil, mockWrapFn.Execute) + err := worker.Process(context.Background(), mockRepo, job, mockProgress) + require.NoError(t, err) +} + +func TestDeleteWorker_ProcessDeleteFilesWithError(t *testing.T) { + job := provisioning.Job{ + Spec: provisioning.JobSpec{ + Action: provisioning.JobActionDelete, + Delete: &provisioning.DeleteJobOptions{ + Paths: []string{"test/path1", "test/path2"}, + Ref: "main", + }, + }, + } + + mockRepo := &mockReaderWriter{ + MockRepository: repository.NewMockRepository(t), + } + mockProgress := jobs.NewMockJobProgressRecorder(t) + mockWrapFn := repository.NewMockWrapWithStageFn(t) + + mockWrapFn.On("Execute", mock.Anything, mockRepo, mock.Anything, mock.Anything).Return(func(ctx context.Context, repo repository.Repository, stageOptions repository.StageOptions, fn func(repository.Repository, bool) error) error { + return fn(mockRepo, false) + }) + + mockProgress.On("SetTotal", mock.Anything, 2).Return() + mockProgress.On("StrictMaxErrors", 1).Return() + mockProgress.On("SetMessage", mock.Anything, "Deleting test/path1").Return() + + deleteError := errors.New("delete failed") + mockRepo.On("Delete", mock.Anything, "test/path1", "main", "Delete test/path1").Return(deleteError) + + mockProgress.On("Record", mock.Anything, mock.MatchedBy(func(result jobs.JobResourceResult) bool { + return result.Path == "test/path1" && result.Action == repository.FileActionDeleted && errors.Is(result.Error, deleteError) + })).Return() + mockProgress.On("TooManyErrors").Return(errors.New("too many errors")) + + worker := NewWorker(nil, mockWrapFn.Execute) + err := worker.Process(context.Background(), mockRepo, job, mockProgress) + require.EqualError(t, err, "delete files from repository: too many errors") +} + +func TestDeleteWorker_ProcessWithSyncWorker(t *testing.T) { + job := provisioning.Job{ + Spec: provisioning.JobSpec{ + Action: provisioning.JobActionDelete, + Delete: &provisioning.DeleteJobOptions{ + Paths: []string{"test/path"}, + }, + }, + } + + mockRepo := &mockReaderWriter{ + MockRepository: repository.NewMockRepository(t), + } + mockProgress := jobs.NewMockJobProgressRecorder(t) + mockSyncWorker := jobs.NewMockWorker(t) + mockWrapFn := repository.NewMockWrapWithStageFn(t) + + mockWrapFn.On("Execute", mock.Anything, mockRepo, mock.Anything, mock.Anything).Return(func(ctx context.Context, repo repository.Repository, stageOptions repository.StageOptions, fn func(repository.Repository, bool) error) error { + return fn(mockRepo, false) + }) + + mockProgress.On("SetTotal", mock.Anything, 1).Return() + mockProgress.On("StrictMaxErrors", 1).Return() + mockProgress.On("SetMessage", mock.Anything, "Deleting test/path").Return() + mockProgress.On("TooManyErrors").Return(nil) + + mockRepo.On("Delete", mock.Anything, "test/path", "", "Delete test/path").Return(nil) + + mockProgress.On("Record", mock.Anything, mock.MatchedBy(func(result jobs.JobResourceResult) bool { + return result.Path == "test/path" && result.Action == repository.FileActionDeleted && result.Error == nil + })).Return() + + mockProgress.On("ResetResults").Return() + mockProgress.On("SetMessage", mock.Anything, "pull resources").Return() + + mockSyncWorker.On("Process", mock.Anything, mockRepo, mock.MatchedBy(func(syncJob provisioning.Job) bool { + return syncJob.Spec.Pull != nil && !syncJob.Spec.Pull.Incremental + }), mockProgress).Return(nil) + + worker := NewWorker(mockSyncWorker, mockWrapFn.Execute) + err := worker.Process(context.Background(), mockRepo, job, mockProgress) + require.NoError(t, err) +} + +func TestDeleteWorker_ProcessSyncWorkerError(t *testing.T) { + job := provisioning.Job{ + Spec: provisioning.JobSpec{ + Action: provisioning.JobActionDelete, + Delete: &provisioning.DeleteJobOptions{ + Paths: []string{"test/path"}, + }, + }, + } + + mockRepo := &mockReaderWriter{ + MockRepository: repository.NewMockRepository(t), + } + mockProgress := jobs.NewMockJobProgressRecorder(t) + mockSyncWorker := jobs.NewMockWorker(t) + mockWrapFn := repository.NewMockWrapWithStageFn(t) + + mockWrapFn.On("Execute", mock.Anything, mockRepo, mock.Anything, mock.Anything).Return(func(ctx context.Context, repo repository.Repository, stageOptions repository.StageOptions, fn func(repository.Repository, bool) error) error { + return fn(mockRepo, false) + }) + + mockProgress.On("SetTotal", mock.Anything, 1).Return() + mockProgress.On("StrictMaxErrors", 1).Return() + mockProgress.On("SetMessage", mock.Anything, "Deleting test/path").Return() + mockProgress.On("TooManyErrors").Return(nil) + + mockRepo.On("Delete", mock.Anything, "test/path", "", "Delete test/path").Return(nil) + + mockProgress.On("Record", mock.Anything, mock.Anything).Return() + mockProgress.On("ResetResults").Return() + mockProgress.On("SetMessage", mock.Anything, "pull resources").Return() + + syncError := errors.New("sync failed") + mockSyncWorker.On("Process", mock.Anything, mockRepo, mock.Anything, mockProgress).Return(syncError) + + worker := NewWorker(mockSyncWorker, mockWrapFn.Execute) + err := worker.Process(context.Background(), mockRepo, job, mockProgress) + require.EqualError(t, err, "pull resources: sync failed") +} + +func TestDeleteWorker_deleteFiles(t *testing.T) { + tests := []struct { + name string + paths []string + deleteResults []error + tooManyErrors error + expectedError string + expectedCalls int + }{ + { + name: "single file success", + paths: []string{"test/file1.yaml"}, + deleteResults: []error{nil}, + expectedCalls: 1, + }, + { + name: "multiple files success", + paths: []string{"test/file1.yaml", "test/file2.yaml", "test/file3.yaml"}, + deleteResults: []error{nil, nil, nil}, + expectedCalls: 3, + }, + { + name: "single file with error continues", + paths: []string{"test/file1.yaml", "test/file2.yaml"}, + deleteResults: []error{errors.New("delete failed"), nil}, + expectedCalls: 2, + }, + { + name: "too many errors stops processing", + paths: []string{"test/file1.yaml", "test/file2.yaml", "test/file3.yaml"}, + deleteResults: []error{errors.New("delete failed")}, + tooManyErrors: errors.New("too many errors"), + expectedError: "too many errors", + expectedCalls: 1, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + mockRepo := &mockReaderWriter{ + MockRepository: repository.NewMockRepository(t), + } + mockProgress := jobs.NewMockJobProgressRecorder(t) + + opts := provisioning.DeleteJobOptions{ + Ref: "main", + } + + for i, path := range tt.paths { + if i < len(tt.deleteResults) { + mockRepo.On("Delete", mock.Anything, path, "main", "Delete "+path).Return(tt.deleteResults[i]).Once() + mockProgress.On("SetMessage", mock.Anything, "Deleting "+path).Return().Once() + mockProgress.On("Record", mock.Anything, mock.MatchedBy(func(result jobs.JobResourceResult) bool { + return result.Path == path && result.Action == repository.FileActionDeleted + })).Return().Once() + + if tt.tooManyErrors != nil && i == 0 { + mockProgress.On("TooManyErrors").Return(tt.tooManyErrors).Once() + } else { + mockProgress.On("TooManyErrors").Return(nil).Once() + } + } + } + + worker := NewWorker(nil, nil) + err := worker.deleteFiles(context.Background(), mockRepo, mockProgress, opts, tt.paths...) + + if tt.expectedError != "" { + require.EqualError(t, err, tt.expectedError) + } else { + require.NoError(t, err) + } + + mockRepo.AssertExpectations(t) + mockProgress.AssertExpectations(t) + }) + } +} diff --git a/pkg/registry/apis/provisioning/register.go b/pkg/registry/apis/provisioning/register.go index 9b60c22df44..be4cf583824 100644 --- a/pkg/registry/apis/provisioning/register.go +++ b/pkg/registry/apis/provisioning/register.go @@ -43,6 +43,7 @@ import ( "github.com/grafana/grafana/pkg/registry/apis/dashboard/legacy" "github.com/grafana/grafana/pkg/registry/apis/provisioning/controller" "github.com/grafana/grafana/pkg/registry/apis/provisioning/jobs" + deletepkg "github.com/grafana/grafana/pkg/registry/apis/provisioning/jobs/delete" "github.com/grafana/grafana/pkg/registry/apis/provisioning/jobs/export" "github.com/grafana/grafana/pkg/registry/apis/provisioning/jobs/migrate" "github.com/grafana/grafana/pkg/registry/apis/provisioning/jobs/sync" @@ -616,7 +617,13 @@ func (b *APIBuilder) GetPostStartHooks() (map[string]genericapiserver.PostStartH b.storageStatus, ) - workers := []jobs.Worker{migrationWorker, syncWorker, exportWorker} + deleteWorker := deletepkg.NewWorker(syncWorker, stageIfPossible) + workers := []jobs.Worker{ + deleteWorker, + exportWorker, + migrationWorker, + syncWorker, + } // Add any extra workers for _, extra := range b.extras { diff --git a/pkg/registry/apis/provisioning/repository/mock_wrap_with_stage_fn.go b/pkg/registry/apis/provisioning/repository/mock_wrap_with_stage_fn.go new file mode 100644 index 00000000000..e4c6108e83c --- /dev/null +++ b/pkg/registry/apis/provisioning/repository/mock_wrap_with_stage_fn.go @@ -0,0 +1,85 @@ +// Code generated by mockery v2.52.4. DO NOT EDIT. + +package repository + +import ( + context "context" + + mock "github.com/stretchr/testify/mock" +) + +// MockWrapWithStageFn is an autogenerated mock type for the WrapWithStageFn type +type MockWrapWithStageFn struct { + mock.Mock +} + +type MockWrapWithStageFn_Expecter struct { + mock *mock.Mock +} + +func (_m *MockWrapWithStageFn) EXPECT() *MockWrapWithStageFn_Expecter { + return &MockWrapWithStageFn_Expecter{mock: &_m.Mock} +} + +// Execute provides a mock function with given fields: ctx, repo, stageOptions, fn +func (_m *MockWrapWithStageFn) Execute(ctx context.Context, repo Repository, stageOptions StageOptions, fn func(Repository, bool) error) error { + ret := _m.Called(ctx, repo, stageOptions, fn) + + if len(ret) == 0 { + panic("no return value specified for Execute") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, Repository, StageOptions, func(Repository, bool) error) error); ok { + r0 = rf(ctx, repo, stageOptions, fn) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockWrapWithStageFn_Execute_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Execute' +type MockWrapWithStageFn_Execute_Call struct { + *mock.Call +} + +// Execute is a helper method to define mock.On call +// - ctx context.Context +// - repo Repository +// - stageOptions StageOptions +// - fn func(Repository , bool) error +func (_e *MockWrapWithStageFn_Expecter) Execute(ctx interface{}, repo interface{}, stageOptions interface{}, fn interface{}) *MockWrapWithStageFn_Execute_Call { + return &MockWrapWithStageFn_Execute_Call{Call: _e.mock.On("Execute", ctx, repo, stageOptions, fn)} +} + +func (_c *MockWrapWithStageFn_Execute_Call) Run(run func(ctx context.Context, repo Repository, stageOptions StageOptions, fn func(Repository, bool) error)) *MockWrapWithStageFn_Execute_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(Repository), args[2].(StageOptions), args[3].(func(Repository, bool) error)) + }) + return _c +} + +func (_c *MockWrapWithStageFn_Execute_Call) Return(_a0 error) *MockWrapWithStageFn_Execute_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockWrapWithStageFn_Execute_Call) RunAndReturn(run func(context.Context, Repository, StageOptions, func(Repository, bool) error) error) *MockWrapWithStageFn_Execute_Call { + _c.Call.Return(run) + return _c +} + +// NewMockWrapWithStageFn creates a new instance of MockWrapWithStageFn. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockWrapWithStageFn(t interface { + mock.TestingT + Cleanup(func()) +}) *MockWrapWithStageFn { + mock := &MockWrapWithStageFn{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/registry/apis/provisioning/repository/staged.go b/pkg/registry/apis/provisioning/repository/staged.go index bdcae0ab039..ca5b59c72c9 100644 --- a/pkg/registry/apis/provisioning/repository/staged.go +++ b/pkg/registry/apis/provisioning/repository/staged.go @@ -10,6 +10,9 @@ import ( "github.com/grafana/nanogit" ) +//go:generate mockery --name WrapWithStageFn --structname MockWrapWithStageFn --inpackage --filename mock_wrap_with_stage_fn.go --with-expecter +type WrapWithStageFn func(ctx context.Context, repo Repository, stageOptions StageOptions, fn func(repo Repository, staged bool) error) error + // StageMode defines the staging and commit behavior type StageMode int diff --git a/pkg/tests/apis/openapi_snapshots/provisioning.grafana.app-v0alpha1.json b/pkg/tests/apis/openapi_snapshots/provisioning.grafana.app-v0alpha1.json index 0faaab04b78..bd54e67e82a 100644 --- a/pkg/tests/apis/openapi_snapshots/provisioning.grafana.app-v0alpha1.json +++ b/pkg/tests/apis/openapi_snapshots/provisioning.grafana.app-v0alpha1.json @@ -2631,6 +2631,23 @@ } } }, + "com.github.grafana.grafana.pkg.apis.provisioning.v0alpha1.DeleteJobOptions": { + "type": "object", + "properties": { + "paths": { + "description": "Paths to be deleted. Examples: - dashboard.json (for a file) - a/b/c/other-dashboard.json (for a file) - nested/deep/ (for a directory) FIXME: we should validate this in admission hooks", + "type": "array", + "items": { + "type": "string", + "default": "" + } + }, + "ref": { + "description": "Ref to the branch or commit hash to delete from", + "type": "string" + } + } + }, "com.github.grafana.grafana.pkg.apis.provisioning.v0alpha1.ErrorDetails": { "type": "object", "required": [ @@ -2653,7 +2670,7 @@ "type": "object", "properties": { "branch": { - "description": "Target branch for export (only git)", + "description": "FIXME: we should validate this in admission hooks Target branch for export (only git)", "type": "string" }, "folder": { @@ -2665,7 +2682,7 @@ "type": "string" }, "path": { - "description": "Prefix in target file system", + "description": "FIXME: we should validate this in admission hooks Prefix in target file system", "type": "string" } } @@ -3049,15 +3066,24 @@ "type": "object", "properties": { "action": { - "description": "Possible enum values:\n - `\"migrate\"` acts like JobActionExport, then JobActionPull. It also tries to preserve the history.\n - `\"pr\"` adds additional useful information to a PR, such as comments with preview links and rendered images.\n - `\"pull\"` replicates the remote branch in the local copy of the repository.\n - `\"push\"` replicates the local copy of the repository in the remote branch.", + "description": "Possible enum values:\n - `\"delete\"` deletes files in the remote repository\n - `\"migrate\"` acts like JobActionExport, then JobActionPull. It also tries to preserve the history.\n - `\"pr\"` adds additional useful information to a PR, such as comments with preview links and rendered images.\n - `\"pull\"` replicates the remote branch in the local copy of the repository.\n - `\"push\"` replicates the local copy of the repository in the remote branch.", "type": "string", "enum": [ + "delete", "migrate", "pr", "pull", "push" ] }, + "delete": { + "description": "Delete when the action is `delete`", + "allOf": [ + { + "$ref": "#/components/schemas/com.github.grafana.grafana.pkg.apis.provisioning.v0alpha1.DeleteJobOptions" + } + ] + }, "migrate": { "description": "Required when the action is `migrate`", "allOf": [ diff --git a/pkg/tests/apis/provisioning/provisioning_test.go b/pkg/tests/apis/provisioning/provisioning_test.go index a5edc751fbe..15049df999d 100644 --- a/pkg/tests/apis/provisioning/provisioning_test.go +++ b/pkg/tests/apis/provisioning/provisioning_test.go @@ -822,7 +822,7 @@ func TestIntegrationProvisioning_DeleteResources(t *testing.T) { }) } -func TestIntegrationProvisioning_MoveResources(t *testing.T) { +func TestIntegrationProvisioning_DeleteJob(t *testing.T) { if testing.Short() { t.Skip("skipping integration test") } @@ -830,6 +830,158 @@ func TestIntegrationProvisioning_MoveResources(t *testing.T) { helper := runGrafana(t) ctx := context.Background() + const repo = "delete-job-test-repo" + localTmp := helper.RenderObject(t, "testdata/local-write.json.tmpl", map[string]any{ + "Name": repo, + "SyncEnabled": true, + "SyncTarget": "instance", + }) + _, err := helper.Repositories.Resource.Create(ctx, localTmp, metav1.CreateOptions{}) + require.NoError(t, err) + // Copy multiple test files to the repository + helper.CopyToProvisioningPath(t, "testdata/all-panels.json", "dashboard1.json") + helper.CopyToProvisioningPath(t, "testdata/text-options.json", "dashboard2.json") + helper.CopyToProvisioningPath(t, "testdata/timeline-demo.json", "folder/dashboard3.json") + + // Trigger and wait for initial sync to populate resources + helper.SyncAndWait(t, repo, nil) + + // Verify initial state - should have 3 dashboards and 1 folder + dashboards, err := helper.DashboardsV1.Resource.List(ctx, metav1.ListOptions{}) + require.NoError(t, err) + require.Equal(t, 3, len(dashboards.Items), "should have 3 dashboards after sync") + + folders, err := helper.Folders.Resource.List(ctx, metav1.ListOptions{}) + require.NoError(t, err) + require.Equal(t, 1, len(folders.Items), "should have 1 folder after sync") + + t.Run("delete single file", func(t *testing.T) { + // Create delete job for single file + result := helper.AdminREST.Post(). + Namespace("default"). + Resource("repositories"). + Name(repo). + SubResource("jobs"). + Body(asJSON(&provisioning.JobSpec{ + Action: provisioning.JobActionDelete, + Delete: &provisioning.DeleteJobOptions{ + Paths: []string{"dashboard1.json"}, + }, + })). + SetHeader("Content-Type", "application/json"). + Do(ctx) + require.NoError(t, result.Error(), "should be able to create delete job") + + // Wait for job to complete + helper.AwaitJobs(t, repo) + + // Verify file is deleted from repository + _, err = helper.Repositories.Resource.Get(ctx, repo, metav1.GetOptions{}, "files", "dashboard1.json") + require.Error(t, err, "file should be deleted from repository") + require.True(t, apierrors.IsNotFound(err), "should be not found error") + + // Verify dashboard is removed from Grafana after sync + dashboards, err = helper.DashboardsV1.Resource.List(ctx, metav1.ListOptions{}) + require.NoError(t, err) + require.Equal(t, 2, len(dashboards.Items), "should have 2 dashboards after delete") + + // Verify other files still exist + _, err = helper.Repositories.Resource.Get(ctx, repo, metav1.GetOptions{}, "files", "dashboard2.json") + require.NoError(t, err, "other files should still exist") + _, err = helper.Repositories.Resource.Get(ctx, repo, metav1.GetOptions{}, "files", "folder", "dashboard3.json") + require.NoError(t, err, "nested files should still exist") + }) + + t.Run("delete multiple files", func(t *testing.T) { + // Create delete job for multiple files + result := helper.AdminREST.Post(). + Namespace("default"). + Resource("repositories"). + Name(repo). + SubResource("jobs"). + Body(asJSON(&provisioning.JobSpec{ + Action: provisioning.JobActionDelete, + Delete: &provisioning.DeleteJobOptions{ + Paths: []string{"dashboard2.json", "folder/dashboard3.json"}, + }, + })). + SetHeader("Content-Type", "application/json"). + Do(ctx) + require.NoError(t, result.Error(), "should be able to create delete job") + + // Wait for job to complete + helper.AwaitJobs(t, repo) + + // Verify files are deleted from repository + _, err = helper.Repositories.Resource.Get(ctx, repo, metav1.GetOptions{}, "files", "dashboard2.json") + require.Error(t, err, "dashboard2.json should be deleted") + require.True(t, apierrors.IsNotFound(err)) + + _, err = helper.Repositories.Resource.Get(ctx, repo, metav1.GetOptions{}, "files", "folder", "dashboard3.json") + require.Error(t, err, "folder/dashboard3.json should be deleted") + require.True(t, apierrors.IsNotFound(err)) + + // Verify all dashboards are removed from Grafana after sync + dashboards, err = helper.DashboardsV1.Resource.List(ctx, metav1.ListOptions{}) + require.NoError(t, err) + require.Equal(t, 0, len(dashboards.Items), "should have 0 dashboards after deleting all") + }) + + t.Run("delete non-existent file", func(t *testing.T) { + // Create delete job for non-existent file + result := helper.AdminREST.Post(). + Namespace("default"). + Resource("repositories"). + Name(repo). + SubResource("jobs"). + Body(asJSON(&provisioning.JobSpec{ + Action: provisioning.JobActionDelete, + Delete: &provisioning.DeleteJobOptions{ + Paths: []string{"non-existent.json"}, + }, + })). + SetHeader("Content-Type", "application/json"). + Do(ctx) + require.NoError(t, result.Error(), "should be able to create delete job") + + // Wait for job to complete - should fail due to strict error handling + require.EventuallyWithT(t, func(collect *assert.CollectT) { + list := &unstructured.UnstructuredList{} + err := helper.AdminREST.Get(). + Namespace("default"). + Resource("repositories"). + Name(repo). + SubResource("jobs"). + Do(ctx).Into(list) + assert.NoError(collect, err, "should be able to list jobs") + assert.NotEmpty(collect, list.Items, "expect at least one job") + + // Find the delete job specifically + var deleteJob *unstructured.Unstructured + for _, elem := range list.Items { + assert.Equal(collect, repo, elem.GetLabels()["provisioning.grafana.app/repository"], "should have repo label") + + action := mustNestedString(elem.Object, "spec", "action") + if action == "delete" { + deleteJob = &elem + break + } + } + assert.NotNil(collect, deleteJob, "should find a delete job") + + state := mustNestedString(deleteJob.Object, "status", "state") + assert.Equal(collect, "error", state, "delete job should have failed due to non-existent file") + }, time.Second*10, time.Millisecond*100, "Expected delete job to fail with error state") + }) +} + +func TestIntegrationProvisioning_MoveResources(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test") + } + + helper := runGrafana(t) + ctx := context.Background() const repo = "move-test-repo" localTmp := helper.RenderObject(t, "testdata/local-write.json.tmpl", map[string]any{ "Name": repo, diff --git a/public/app/api/clients/provisioning/v0alpha1/endpoints.gen.ts b/public/app/api/clients/provisioning/v0alpha1/endpoints.gen.ts index ecd79c6c52e..20a6c603f32 100644 --- a/public/app/api/clients/provisioning/v0alpha1/endpoints.gen.ts +++ b/public/app/api/clients/provisioning/v0alpha1/endpoints.gen.ts @@ -758,6 +758,12 @@ export type ObjectMeta = { Populated by the system. Read-only. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#uids */ uid?: string; }; +export type DeleteJobOptions = { + /** Paths to be deleted. Examples: - dashboard.json (for a file) - a/b/c/other-dashboard.json (for a file) - nested/deep/ (for a directory) FIXME: we should validate this in admission hooks */ + paths?: string[]; + /** Ref to the branch or commit hash to delete from */ + ref?: string; +}; export type MigrateJobOptions = { /** Preserve history (if possible) */ history?: boolean; @@ -779,22 +785,26 @@ export type SyncJobOptions = { incremental: boolean; }; export type ExportJobOptions = { - /** Target branch for export (only git) */ + /** FIXME: we should validate this in admission hooks Target branch for export (only git) */ branch?: string; /** The source folder (or empty) to export */ folder?: string; /** Message to use when committing the changes in a single commit */ message?: string; + /** FIXME: we should validate this in admission hooks Prefix in target file system */ /** Prefix in target file system */ path?: string; }; export type JobSpec = { /** Possible enum values: + - `"delete"` deletes files in the remote repository - `"migrate"` acts like JobActionExport, then JobActionPull. It also tries to preserve the history. - `"pr"` adds additional useful information to a PR, such as comments with preview links and rendered images. - `"pull"` replicates the remote branch in the local copy of the repository. - `"push"` replicates the local copy of the repository in the remote branch. */ - action?: 'migrate' | 'pr' | 'pull' | 'push'; + action?: 'delete' | 'migrate' | 'pr' | 'pull' | 'push'; + /** Delete when the action is `delete` */ + delete?: DeleteJobOptions; /** Required when the action is `migrate` */ migrate?: MigrateJobOptions; /** Pull request options */ From c94f930950e026e79424f9621f8b6f01a8e3e254 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 25 Jul 2025 17:47:44 +0100 Subject: [PATCH 014/131] Update dependency prettier to v3.6.2 (#108689) * Update dependency prettier to v3.6.2 * run prettier --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Ashley Harrison --- .changelog-archive/CHANGELOG.02.md | 1 - GOVERNANCE.md | 1 - apps/advisor/README.md | 1 - contribute/ISSUE_TRIAGE.md | 1 - .../architecture/k8s-inspired-backend-arch.md | 4 ---- .../index.md | 1 - .../activate-license-on-ecs/index.md | 1 - .../activate-license-on-eks/index.md | 2 -- .../index.md | 2 -- .../cloud-migration-assistant.md | 1 - .../manually-migrate-to-grafana-cloud.md | 3 --- .../plugin-management/_index.md | 1 - .../alerting-rules/alerting-migration.md | 1 - .../create-grafana-managed-rule.md | 3 --- ...ate-data-source-managed-recording-rules.md | 1 - .../alerting/best-practices/dynamic-labels.md | 2 -- .../best-practices/dynamic-thresholds.md | 3 --- .../multi-dimensional-alerts.md | 1 - .../integrations/configure-amazon-sns.md | 5 ----- .../integrations/configure-email.md | 1 - .../integrations/configure-irm.md | 1 - .../template-notifications/examples.md | 1 - .../manage-notification-templates.md | 1 - .../alerting/fundamentals/templates.md | 2 -- .../provision-alerting-resources/_index.md | 1 - .../terraform-provisioning/index.md | 6 ------ .../annotate-visualizations/index.md | 1 - .../create-dashboard/index.md | 2 -- .../create-dynamic-dashboard/index.md | 9 --------- .../import-dashboards/index.md | 1 - .../manage-dashboard-links/index.md | 3 --- .../modify-dashboard-settings/index.md | 1 - .../create-manage-playlists/index.md | 2 -- .../dashboards/create-reports/_index.md | 6 ------ .../dashboards/manage-dashboards/index.md | 1 - .../share-dashboards-panels/_index.md | 1 - .../dashboards/use-dashboards/index.md | 1 - .../variables/add-template-variables/index.md | 9 --------- .../configure-elasticsearch-data-source.md | 1 - .../elasticsearch/query-editor/index.md | 2 -- .../google-cloud-monitoring/_index.md | 1 - .../datasources/mysql/query-editor/_index.md | 4 ---- .../prometheus/configure/_index.md | 1 - .../prometheus/query-editor/_index.md | 3 --- .../tempo/configure-tempo-data-source.md | 1 - .../traces-in-grafana/trace-correlations.md | 6 ------ .../explore/get-started-with-explore.md | 1 - docs/sources/fundamentals/exemplars/index.md | 1 - .../observability-as-code/get-started.md | 3 --- .../provision-resources/git-sync-setup.md | 1 - .../provisioned-dashboards.md | 1 - .../configure-panel-options/index.md | 1 - .../configure-standard-options/index.md | 1 - .../configure-value-mappings/index.md | 1 - .../panel-inspector/index.md | 1 - .../sql-expressions/index.md | 3 --- .../visualizations/bar-chart/index.md | 1 - .../visualizations/canvas/index.md | 1 - .../visualizations/table/index.md | 1 - .../visualizations/traces/index.md | 1 - .../auth-proxy/index.md | 2 -- .../configure-authentication/azuread/index.md | 11 ----------- .../generic-oauth/index.md | 4 ---- .../configure-authentication/gitlab/index.md | 1 - .../ldap-ui/_index.md | 1 - .../configure-authentication/okta/index.md | 2 -- .../configure-authentication/saml/_index.md | 3 --- .../saml/configure-saml-with-okta/_index.md | 1 - .../saml/saml-ui/_index.md | 1 - .../encrypt-secrets-using-aws-kms/index.md | 1 - .../index.md | 1 - .../index.md | 1 - .../index.md | 1 - .../configure-scim-provisioning/_index.md | 2 -- .../manage-users-teams/_index.md | 8 -------- .../configure-security/configure-team-sync.md | 1 - .../setup-grafana/installation/helm/index.md | 2 -- .../installation/kubernetes/index.md | 3 --- .../setup-grafana/installation/mac/index.md | 1 - docs/sources/setup-grafana/set-up-https.md | 1 - .../datasources/datasouce-authentication.md | 1 - .../shared/upgrade/upgrade-common-tasks.md | 1 - .../alerting-get-started-pt2/index.md | 4 ---- .../alerting-get-started-pt3/index.md | 19 ------------------- .../alerting-get-started-pt4/index.md | 10 ---------- .../alerting-get-started-pt5/index.md | 7 ------- .../alerting-get-started-pt6/index.md | 6 ------ .../tutorials/alerting-get-started/index.md | 4 ---- .../create-alerts-with-logs/index.md | 3 --- .../tutorials/grafana-fundamentals/index.md | 1 - .../upgrade-guide/when-to-upgrade/index.md | 2 -- docs/sources/whatsnew/whats-new-in-v11-3.md | 1 - package.json | 4 ++-- packages/README.md | 1 - .../services/pluginExtensions/utils.test.tsx | 18 +++++++++++++++--- .../ScrollContainer/ScrollContainer.mdx | 1 - .../components/RolePicker/RolePickerInput.tsx | 4 +++- public/app/features/admin/Users/OrgUnits.tsx | 8 +++++++- .../features/auth-config/ErrorContainer.tsx | 8 ++++++-- .../scene/layout-rows/RowItemRepeater.tsx | 4 +++- .../TransformationPicker.tsx | 3 ++- .../features/profile/UserProfileEditTabs.tsx | 4 +++- .../annotations2/AnnotationTooltip2.tsx | 4 +++- yarn.lock | 12 ++++++------ 104 files changed, 50 insertions(+), 250 deletions(-) diff --git a/.changelog-archive/CHANGELOG.02.md b/.changelog-archive/CHANGELOG.02.md index 7fc14a683dc..34945530c68 100644 --- a/.changelog-archive/CHANGELOG.02.md +++ b/.changelog-archive/CHANGELOG.02.md @@ -234,7 +234,6 @@ Grunt & Watch tasks: - binary to `/usr/sbin/grafana-server` - init.d script improvements, renamed to `/etc/init.d/grafana-server` - added default file with environment variables, - - `/etc/default/grafana-server` (deb/ubuntu) - `/etc/sysconfig/grafana-server` (centos/redhat) diff --git a/GOVERNANCE.md b/GOVERNANCE.md index ff129a87557..f246ca03386 100644 --- a/GOVERNANCE.md +++ b/GOVERNANCE.md @@ -7,7 +7,6 @@ This document describes the rules and governance of the project. It is meant to - **Maintainers**: Maintainers lead an individual project or parts thereof ([`MAINTAINERS.md`][maintainers]). - **Projects**: A single repository in the Grafana GitHub organization and listed below is referred to as a project: - - clock-panel - devtools - gel-app diff --git a/apps/advisor/README.md b/apps/advisor/README.md index 27c44711f43..c7929d9db62 100644 --- a/apps/advisor/README.md +++ b/apps/advisor/README.md @@ -142,7 +142,6 @@ Check [`security_config_step.go`](./pkg/app/checks/configchecks/security_config_ 2. **Type Safety**: Use type assertions to ensure you're working with the correct type of item. 3. **Severity Levels**: Use appropriate severity levels: - - `CheckReportFailureSeverityHigh`: For critical issues that need immediate attention - `CheckReportFailureSeverityLow`: For non-critical issues that can be addressed later diff --git a/contribute/ISSUE_TRIAGE.md b/contribute/ISSUE_TRIAGE.md index b856798fb5c..b8b669b27b5 100644 --- a/contribute/ISSUE_TRIAGE.md +++ b/contribute/ISSUE_TRIAGE.md @@ -234,7 +234,6 @@ In case there is an uncertainty around the prioritization of an issue, please as **Critical bugs** 1. If a bug has been categorized and any of the following criteria apply, the bug should be labeled as critical and must be actively worked on as someone's top priority right now: - - Results in any data loss - Critical security or performance issues - Problem that makes a feature unusable diff --git a/contribute/architecture/k8s-inspired-backend-arch.md b/contribute/architecture/k8s-inspired-backend-arch.md index 520ebcfc559..84197d93d85 100644 --- a/contribute/architecture/k8s-inspired-backend-arch.md +++ b/contribute/architecture/k8s-inspired-backend-arch.md @@ -14,22 +14,18 @@ The end goal is for the Resource APIs to become the only interface for managing ## 1. Key Differences from Legacy API Endpoints - **URL structure & versioning:** - - **Resource APIs:** Follow Kubernetes conventions (`/apis///namespaces///`). Includes explicit API versions (e.g., `v0alpha1`, `v1`, `v2beta1`) in the path, allowing for controlled evolution and multiple versions of a resource API to co-exist. - **Legacy APIs:** Variable path structures (e.g., `/api/dashboards/uid/:uid`, `/api/ruler/grafana/api/v1/rules/:uid/:uid`). Less explicit versioning. - **Resource schemas:** - - **Resource APIs:** Each resource has a well-defined schema (`spec`) and is wrapped with an envelope with common metadata, all APIs come with an always-in-sync OpenAPI spec. - **Legacy APIs:** Structures vary - **Namespacing / org context:** - - **Resource APIs:** Uses explicit namespaces in the path (`/namespaces//...`) mapping to Grafana Organization IDs in OSS/Enterprise and Grafana Cloud Stack IDs in Grafana Cloud for scoping. - **Legacy APIs:** Org context determined implicitly (session, API key), not usually part of the URL structure. - **Consistency of convenience features:** - - **Resource APIs:** Convenience features such as resource history, restore and observability-as-code tooling come out of the box; a single implementation of convenience features works across all resources because of the standardization - **Legacy APIs:** Different APIs support different convenience features; implementations are feature-specific diff --git a/docs/sources/administration/correlations/use-variables-and-transformations/index.md b/docs/sources/administration/correlations/use-variables-and-transformations/index.md index 6251d537352..8ba408e5b94 100644 --- a/docs/sources/administration/correlations/use-variables-and-transformations/index.md +++ b/docs/sources/administration/correlations/use-variables-and-transformations/index.md @@ -66,7 +66,6 @@ Instructions below show how to set up a link that can run metrics query for the ``` Two data sources are created: Source (emulating logs data source) and Target (emulating metrics data source): - - A correlation called “App metrics” is created targeting the Target data source with its UID. - The label and description are provided as text - Each correlation contains the following configuration: diff --git a/docs/sources/administration/enterprise-licensing/activate-aws-marketplace-license/activate-license-on-ecs/index.md b/docs/sources/administration/enterprise-licensing/activate-aws-marketplace-license/activate-license-on-ecs/index.md index c9192e585e6..1f37fa513eb 100644 --- a/docs/sources/administration/enterprise-licensing/activate-aws-marketplace-license/activate-license-on-ecs/index.md +++ b/docs/sources/administration/enterprise-licensing/activate-aws-marketplace-license/activate-license-on-ecs/index.md @@ -79,7 +79,6 @@ To configure Grafana for high availability: In this task you configure Grafana Enterprise to validate the license with AWS instead of Grafana Labs. 1. In AWS IAM, create an access policy with the following permissions: - - `"license-manager:CheckoutLicense"` - `"license-manager:ListReceivedLicenses"` - `"license-manager:GetLicenseUsage"` diff --git a/docs/sources/administration/enterprise-licensing/activate-aws-marketplace-license/activate-license-on-eks/index.md b/docs/sources/administration/enterprise-licensing/activate-aws-marketplace-license/activate-license-on-eks/index.md index 5199690faa3..1d57566cd61 100644 --- a/docs/sources/administration/enterprise-licensing/activate-aws-marketplace-license/activate-license-on-eks/index.md +++ b/docs/sources/administration/enterprise-licensing/activate-aws-marketplace-license/activate-license-on-eks/index.md @@ -89,7 +89,6 @@ For more information on Grafana High Availability setup, refer to [Set up Grafan In this task, you configure Grafana Enterprise to validate the license with AWS instead of Grafana Labs. 1. In AWS IAM, assign the following permissions to the Node IAM role (if you are using a Node Group), or the Pod Execution role (if you are using a Fargate profile): - - `"license-manager:CheckoutLicense"` - `"license-manager:ListReceivedLicenses"` - `"license-manager:GetLicenseUsage"` @@ -100,7 +99,6 @@ In this task, you configure Grafana Enterprise to validate the license with AWS For more information about AWS license permissions, refer to [Actions, resources, and condition keys for AWS License Manager](https://docs.aws.amazon.com/service-authorization/latest/reference/list_awslicensemanager.html). 1. Choose **one** of the following options to update the [license_validation_type](../../../../setup-grafana/configure-grafana/enterprise-configuration/#license_validation_type) configuration to `aws`: - - **Option 1:** Use `kubectl edit configmap grafana` to edit `grafana.ini` add the following section to the configuration: ``` diff --git a/docs/sources/administration/enterprise-licensing/activate-aws-marketplace-license/activate-license-on-instance-outside-aws/index.md b/docs/sources/administration/enterprise-licensing/activate-aws-marketplace-license/activate-license-on-instance-outside-aws/index.md index 9d1741d94a4..1399cde35f6 100644 --- a/docs/sources/administration/enterprise-licensing/activate-aws-marketplace-license/activate-license-on-instance-outside-aws/index.md +++ b/docs/sources/administration/enterprise-licensing/activate-aws-marketplace-license/activate-license-on-instance-outside-aws/index.md @@ -44,7 +44,6 @@ To install Grafana, refer to the documentation specific to your implementation. To retrieve your license, Grafana Enterprise requires access to your AWS account and license information. To grant access, create an IAM user in AWS with access to the license, and pass its credentials as environment variables on the host or container where Grafana is running. These environment variables allow Grafana to retrieve license details from AWS. 1. In the AWS License Manager service, create an IAM policy with the following permissions: - - `"license-manager:CheckoutLicense"` - `"license-manager:ListReceivedLicenses"` - `"license-manager:GetLicenseUsage"` @@ -93,7 +92,6 @@ To retrieve your license, Grafana Enterprise requires access to your AWS account 1. Attach the policy you created to the IAM user. 1. Add the following values as environment variables to the host or container running Grafana: - - AWS region - IAM user's access key ID - IAM user's secret access key diff --git a/docs/sources/administration/migration-guide/cloud-migration-assistant.md b/docs/sources/administration/migration-guide/cloud-migration-assistant.md index f6d349fb9a6..16bb16a93c4 100644 --- a/docs/sources/administration/migration-guide/cloud-migration-assistant.md +++ b/docs/sources/administration/migration-guide/cloud-migration-assistant.md @@ -136,7 +136,6 @@ After a snapshot is created, a list of resources appears with resource Type and 1. Use the assistant's real-time progress tracking to monitor the migration. The status changes to 'Uploaded to cloud' for resources successfully copied to the cloud. From Grafana v12.0, you can group and sort resources during and after the migration: - - Click **Name** to sort resources alphabetically. - Click **Type** to group and sort by resource type. - Click **Status** to group and sort by upload status (pending upload, uploaded successfully, or experienced errors). diff --git a/docs/sources/administration/migration-guide/manually-migrate-to-grafana-cloud.md b/docs/sources/administration/migration-guide/manually-migrate-to-grafana-cloud.md index de111d5abb8..e68083eb4a0 100644 --- a/docs/sources/administration/migration-guide/manually-migrate-to-grafana-cloud.md +++ b/docs/sources/administration/migration-guide/manually-migrate-to-grafana-cloud.md @@ -84,7 +84,6 @@ Migration of plugins is the first step when transitioning from Grafana OSS/Enter ``` The command provided above will carry out an HTTP request to this endpoint and accomplish several tasks: - - It issues a GET request to the `/api/plugins` endpoint of your Grafana OSS/Enterprise instance to retrieve a list of installed plugins. - It filters out the list to only include community plugins and those signed by external parties. - It extracts the plugin ID and version before storing them in a `plugins.json` file. @@ -111,7 +110,6 @@ Migration of plugins is the first step when transitioning from Grafana OSS/Enter Replace `` with your Grafana Cloud Access Policy Token. To create a new one, refer to Grafana Cloud [access policies documentation](https://grafana.com/docs/grafana-cloud/account-management/authentication-and-permissions/access-policies/) This script iterates through each plugin listed in the `plugins.json` file: - - It constructs a POST request for each plugin to add it to the specified Grafana Cloud instance. - It reports back the response for each POST request to give you confirmation or information about any issues that occurred. @@ -260,7 +258,6 @@ Grizzly does not currently support Reports and Playlists as a resource, so you c ``` The command provided above will carry out an HTTP request to this endpoint and accomplish several tasks: - - It fetches an array of all the playlists available in the Grafana OSS/Enterprise instance. - It then iterates through each playlist to obtain the complete set of details. - Finally, it stores each playlist's specification as separate JSON files within a directory named `playlists` diff --git a/docs/sources/administration/plugin-management/_index.md b/docs/sources/administration/plugin-management/_index.md index d396fc0825a..b7c674b4b18 100644 --- a/docs/sources/administration/plugin-management/_index.md +++ b/docs/sources/administration/plugin-management/_index.md @@ -249,7 +249,6 @@ To enable backend communication between plugins: ``` This is a comma-separated list that uses glob matching. - - To allow access to all plugins that have a backend: ``` diff --git a/docs/sources/alerting/alerting-rules/alerting-migration.md b/docs/sources/alerting/alerting-rules/alerting-migration.md index d00ad4f003d..f07c874902d 100644 --- a/docs/sources/alerting/alerting-rules/alerting-migration.md +++ b/docs/sources/alerting/alerting-rules/alerting-migration.md @@ -111,7 +111,6 @@ To convert data source-managed alert rules to Grafana managed alerts: 2. Navigate to the Data source-managed alert rules section and click **Import to Grafana-managed rules**. 3. Choose the **Import source** from which you want to import rules: - - Select **Existing data source-managed rules** to import rules from connected Mimir or Loki data sources with the ruler API enabled. - Select **Prometheus YAML file** to import rules by uploading a Prometheus YAML rule file. diff --git a/docs/sources/alerting/alerting-rules/create-grafana-managed-rule.md b/docs/sources/alerting/alerting-rules/create-grafana-managed-rule.md index 13709c0545d..df7abac34b0 100644 --- a/docs/sources/alerting/alerting-rules/create-grafana-managed-rule.md +++ b/docs/sources/alerting/alerting-rules/create-grafana-managed-rule.md @@ -276,7 +276,6 @@ To do this, you need to make sure that your alert rule is in the right evaluatio This is different to [mute timings](ref:mute-timings), which stop notifications from being delivered, but still allows for alert rule evaluation and the creation of alert instances. 1. In **Configure no data and error handling**, you can define the alerting behavior and alerting state for two scenarios: - - When the evaluation returns **No data** or all values are null. - When the evaluation returns **Error** or timeout. @@ -297,7 +296,6 @@ Complete the following steps to set up notifications. 1. Configure who receives a notification when an alert rule fires by either choosing **Select contact point** or **Use notification policy**. **Select contact point** - 1. Choose this option to select an existing [contact point](ref:contact-points). All notifications for this alert rule are sent to this contact point automatically and notification policies aren't used. @@ -305,7 +303,6 @@ Complete the following steps to set up notifications. 1. You can also optionally select a mute or active timing as well as groupings and timings to define when not to send notifications. **Use notification policy** - 1. Choose this option to use the [notification policy tree](ref:notification-policies) to handle alert notifications. All notifications for this alert rule are managed by the notification policy tree, which routes alerts based on their labels. diff --git a/docs/sources/alerting/alerting-rules/create-recording-rules/create-data-source-managed-recording-rules.md b/docs/sources/alerting/alerting-rules/create-recording-rules/create-data-source-managed-recording-rules.md index 375268e520c..ba16e57c14a 100644 --- a/docs/sources/alerting/alerting-rules/create-recording-rules/create-data-source-managed-recording-rules.md +++ b/docs/sources/alerting/alerting-rules/create-recording-rules/create-data-source-managed-recording-rules.md @@ -38,7 +38,6 @@ Note that in data source-managed groups, the alert rules and recording rules wit - Verify that you have write permission to the Prometheus or Loki data source. Otherwise, you will not be able to create or update Grafana Mimir managed alerting rules. - For Grafana Mimir and Loki data sources, enable the ruler API by configuring their respective services. - - **Loki** - The `local` rule storage type, default for the Loki data source, supports only viewing of rules. To edit rules, configure one of the other rule storage types. - **Mimir** - use the `/prometheus` prefix. The Prometheus data source supports both Grafana Mimir and Prometheus, and Grafana expects that both the [Query API](/docs/mimir/latest/operators-guide/reference-http-api/#querier--query-frontend) and [Ruler API](/docs/mimir/latest/operators-guide/reference-http-api/#ruler) are under the same URL. You cannot provide a separate URL for the Ruler API. diff --git a/docs/sources/alerting/best-practices/dynamic-labels.md b/docs/sources/alerting/best-practices/dynamic-labels.md index 155b496d00a..7a9586ea6d9 100644 --- a/docs/sources/alerting/best-practices/dynamic-labels.md +++ b/docs/sources/alerting/best-practices/dynamic-labels.md @@ -233,7 +233,6 @@ This setup reproduces label flapping and shows how dynamic label values affect a 1. Simulate a query (`$A`) that returns a noisy signal. Select **TestData** as the data source and configure the scenario. - - Scenario: Random Walk - Series count: 1 - Start value: 51 @@ -241,7 +240,6 @@ This setup reproduces label flapping and shows how dynamic label values affect a - Spread: 100 (ensures large changes between consecutive data points) 1. Add an expression. - - Type: Reduce - Input: A - Function: Last (to get the most recent value) diff --git a/docs/sources/alerting/best-practices/dynamic-thresholds.md b/docs/sources/alerting/best-practices/dynamic-thresholds.md index 56371657d7b..8cbc3ada2b0 100644 --- a/docs/sources/alerting/best-practices/dynamic-thresholds.md +++ b/docs/sources/alerting/best-practices/dynamic-thresholds.md @@ -146,7 +146,6 @@ You can use the [TestData data source](ref:testdata-data-source) to replicate th 1. Simulate a query (`$A`) that returns latencies for each service. Select **TestData** as the data source and configure the scenario. - - Scenario: Random Walk - Alias: latency - Labels: service=api-$seriesIndex @@ -179,7 +178,6 @@ You can use the [TestData data source](ref:testdata-data-source) to replicate th For details on CSV format requirements, see [table data examples](ref:table-data-example). 1. Add a new **Reduce** expression (`$C`). - - Type: Reduce - Input: A - Function: Mean @@ -188,7 +186,6 @@ You can use the [TestData data source](ref:testdata-data-source) to replicate th This calculates the average latency for each service: `api-0`, `api-1`, etc. 1. Add a new **Math** expression. - - Type: Math - Expression: `$C > $B` - Set this expression as the **alert condition**. diff --git a/docs/sources/alerting/best-practices/multi-dimensional-alerts.md b/docs/sources/alerting/best-practices/multi-dimensional-alerts.md index 4523140248c..f612df6aa37 100644 --- a/docs/sources/alerting/best-practices/multi-dimensional-alerts.md +++ b/docs/sources/alerting/best-practices/multi-dimensional-alerts.md @@ -116,7 +116,6 @@ You can quickly experiment with multi-dimensional alerts using the [**TestData** 1. Go to **Alerting** and create an alert rule 1. Select **TestData** as the data source. 1. Configure the TestData scenario - - Scenario: **Random Walk** - Labels: `cpu=cpu-$seriesIndex` - Series count: 3 diff --git a/docs/sources/alerting/configure-notifications/manage-contact-points/integrations/configure-amazon-sns.md b/docs/sources/alerting/configure-notifications/manage-contact-points/integrations/configure-amazon-sns.md index e36a87f08fe..09ac3ee6bee 100644 --- a/docs/sources/alerting/configure-notifications/manage-contact-points/integrations/configure-amazon-sns.md +++ b/docs/sources/alerting/configure-notifications/manage-contact-points/integrations/configure-amazon-sns.md @@ -89,11 +89,9 @@ This section outlines a minimal setup to configure Amazon SNS with Alerting. ### 1. Create an SNS Topic and Email Subscriber 1. **Navigate to SNS in AWS Console**: - - Go to the [Amazon SNS Console](https://console.aws.amazon.com/sns/v3/home). 2. **Create a new topic**: - - On the **Topics** page, choose **"Create topic"**. - Select **"Standard"** as the type. - Enter a **Name** for your topic, e.g., `My-Topic`. @@ -110,11 +108,9 @@ This section outlines a minimal setup to configure Amazon SNS with Alerting. ### 2. Create an IAM Policy, User, and Access Key 1. **Navigate to IAM in AWS Console**: - - Go to the [IAM Console](https://console.aws.amazon.com/iam/home). 2. **Create a new policy**: - - On the **Policies** page, choose **"Create policy"**. - Switch to the **"JSON"** tab and paste the following policy, replacing `Resource` with your SNS topic ARN: @@ -134,7 +130,6 @@ This section outlines a minimal setup to configure Amazon SNS with Alerting. - Click **"Next"**, name it (e.g., `SNSPublishPolicy`), and click **"Create policy"**. 3. **Create a new IAM user and assign the policy** - - In the IAM Console, on the **Users** page, choose **"Create user"**. - Enter a **User name**, e.g., `alerting-sns-user`. - Click **"Next"**. diff --git a/docs/sources/alerting/configure-notifications/manage-contact-points/integrations/configure-email.md b/docs/sources/alerting/configure-notifications/manage-contact-points/integrations/configure-email.md index 02db8cf0172..b7226283d1b 100644 --- a/docs/sources/alerting/configure-notifications/manage-contact-points/integrations/configure-email.md +++ b/docs/sources/alerting/configure-notifications/manage-contact-points/integrations/configure-email.md @@ -53,7 +53,6 @@ For Grafana OSS, you enable email notifications by first configuring [SMTP setti 1. Configure SMTP settings. Within the `[smtp]` settings section, specify the following parameters: - - `enabled = true`: Enables SMTP. - `host`: The hostname or IP address of your SMTP server, and the port number of your SMTP server (commonly 25, 465, or 587). Default is `localhost:25`. - `user`: Your SMTP username (if authentication is required). diff --git a/docs/sources/alerting/configure-notifications/manage-contact-points/integrations/configure-irm.md b/docs/sources/alerting/configure-notifications/manage-contact-points/integrations/configure-irm.md index 510d4e9a4f2..6c18f9064c9 100644 --- a/docs/sources/alerting/configure-notifications/manage-contact-points/integrations/configure-irm.md +++ b/docs/sources/alerting/configure-notifications/manage-contact-points/integrations/configure-irm.md @@ -94,7 +94,6 @@ To create the integration, follow the same steps as described in [Configure an O 1. Navigate to **Alerts & IRM** -> **IRM** -> **Integrations**. 1. Click **+ New integration**. 1. Select either **Alertmanager** or **Webhook** integration from the list. - - **Alertmanager** integration – Includes preconfigured IRM templates for processing Grafana and Prometheus alerts. - **Webhook** integration – Uses default IRM templates for general alert processing. diff --git a/docs/sources/alerting/configure-notifications/template-notifications/examples.md b/docs/sources/alerting/configure-notifications/template-notifications/examples.md index 23b69a9ce21..7927d367c94 100644 --- a/docs/sources/alerting/configure-notifications/template-notifications/examples.md +++ b/docs/sources/alerting/configure-notifications/template-notifications/examples.md @@ -444,7 +444,6 @@ Use one of the following methods to include a dashboard link with the correct ti ``` These URLs include a time range based on the alert’s timing: - - `from`: One hour before the alert started. - `to`: The current time if the alert is firing, or the alert’s end time if resolved. diff --git a/docs/sources/alerting/configure-notifications/template-notifications/manage-notification-templates.md b/docs/sources/alerting/configure-notifications/template-notifications/manage-notification-templates.md index 3ebb73d6907..e449bb6ecff 100644 --- a/docs/sources/alerting/configure-notifications/template-notifications/manage-notification-templates.md +++ b/docs/sources/alerting/configure-notifications/template-notifications/manage-notification-templates.md @@ -57,7 +57,6 @@ To add an existing notification template to your contact point, complete the fol 1. Click **Edit**. A dialog box opens where you can select notification templates. 1. Click **Select notification template** or **Enter custom message** to customize a template or message - - You can select an existing notification template and [preview](#preview-a-notification-template) it using the default payload. - You can also copy the notification template and use it in the **Enter custom message** tab. diff --git a/docs/sources/alerting/fundamentals/templates.md b/docs/sources/alerting/fundamentals/templates.md index efed6ad7cac..62674000b45 100644 --- a/docs/sources/alerting/fundamentals/templates.md +++ b/docs/sources/alerting/fundamentals/templates.md @@ -55,12 +55,10 @@ Use templating to customize, format, and reuse alert notification messages. Crea In Grafana, you have various options to template your alert notification messages: 1. [Alert rule annotations](#template-annotations) - - Annotations add extra information, like `summary` and `description`, to alert instances for notification messages. - Template annotations to display query values that are meaningful to the alert, for example, the server name or the threshold query value. 1. [Alert rule labels](#template-labels) - - Labels are used to differentiate an alert instance from all other alert instances. - Template labels to add an additional label based on a query value, or when the labels from the query are incomplete or not descriptive enough. - Avoid displaying query values in labels as this can create numerous alert instances—use annotations instead. diff --git a/docs/sources/alerting/set-up/provision-alerting-resources/_index.md b/docs/sources/alerting/set-up/provision-alerting-resources/_index.md index 23d5f06691f..90467ce5d6b 100644 --- a/docs/sources/alerting/set-up/provision-alerting-resources/_index.md +++ b/docs/sources/alerting/set-up/provision-alerting-resources/_index.md @@ -58,7 +58,6 @@ Choose from the options below to import (or provision) your Grafana Alerting res 1. [Use configuration files to provision your alerting resources](ref:alerting_file_provisioning), such as alert rules and contact points, through files on disk. {{< admonition type="note" >}} - - You cannot edit provisioned resources from files in the Grafana UI. - Provisioning with configuration files is not available in Grafana Cloud. {{< /admonition >}} diff --git a/docs/sources/alerting/set-up/provision-alerting-resources/terraform-provisioning/index.md b/docs/sources/alerting/set-up/provision-alerting-resources/terraform-provisioning/index.md index 2a5f5d97211..e595928e91a 100644 --- a/docs/sources/alerting/set-up/provision-alerting-resources/terraform-provisioning/index.md +++ b/docs/sources/alerting/set-up/provision-alerting-resources/terraform-provisioning/index.md @@ -159,7 +159,6 @@ In this section, we'll create Terraform configurations for each alerting resourc ``` Replace the following field values: - - `` with the terraform name of the data source. - `` with the terraform name of the folder. @@ -233,13 +232,11 @@ In this section, we'll create Terraform configurations for each alerting resourc ``` Replace the following field values: - - `` with the name of the alert rule group. Note that the distinct Grafana resources are connected through `uid` values in their Terraform configurations. The `uid` value will be randomly generated when provisioning. To link the alert rule group with its respective data source and folder in this example, replace the following field values: - - `` with the terraform name of the previously defined data source. - `` with the terraform name of the previously defined folder. @@ -266,7 +263,6 @@ In this section, we'll create Terraform configurations for each alerting resourc ``` Replace the following field values: - - `` with the terraform name of the contact point. It will be used to reference the contact point in other Terraform resources. - `` with the email to receive alert notifications. @@ -332,7 +328,6 @@ In this section, we'll create Terraform configurations for each alerting resourc ``` Replace the following field values: - - `` with the name of the Terraform resource. It will be used to reference the mute timing in the Terraform notification policy tree. 1. Continue to add more Grafana resources or [use the Terraform CLI for provisioning](#provision-grafana-resources-with-terraform). @@ -363,7 +358,6 @@ In this section, we'll create Terraform configurations for each alerting resourc ``` To configure the mute timing and contact point previously created in the notification policy tree, replace the following field values: - - `` with the terraform name of the previously defined contact point. - `` with the terraform name of the previously defined mute timing. diff --git a/docs/sources/dashboards/build-dashboards/annotate-visualizations/index.md b/docs/sources/dashboards/build-dashboards/annotate-visualizations/index.md index 7b7f90c097d..bd44477db06 100644 --- a/docs/sources/dashboards/build-dashboards/annotate-visualizations/index.md +++ b/docs/sources/dashboards/build-dashboards/annotate-visualizations/index.md @@ -140,7 +140,6 @@ To add a new annotation query to a dashboard, follow these steps: 1. If you don't want the annotation query toggle to be displayed in the dashboard, select the **Hidden** checkbox. 1. Select a color for the event markers. 1. In the **Show in** drop-down, choose one of the following options: - - **All panels** - The annotations are displayed on all panels that support annotations. - **Selected panels** - The annotations are displayed on all the panels you select. - **All panels except** - The annotations are displayed on all panels except the ones you select. diff --git a/docs/sources/dashboards/build-dashboards/create-dashboard/index.md b/docs/sources/dashboards/build-dashboards/create-dashboard/index.md index 033972b0b12..b62595986a2 100644 --- a/docs/sources/dashboards/build-dashboards/create-dashboard/index.md +++ b/docs/sources/dashboards/build-dashboards/create-dashboard/index.md @@ -101,7 +101,6 @@ Dashboards and panels allow you to show your data in visual form. Each panel nee {{< /shared >}} 1. In the dialog box that opens, do one of the following: - - Select one of your existing data sources. - Select one of the Grafana [built-in special data sources](ref:built-in-special-data-sources). - Click **Configure a new data source** to set up a new one (Admins only). @@ -127,7 +126,6 @@ Dashboards and panels allow you to show your data in visual form. Each panel nee 1. Refer to the following documentation for ways you can adjust panel settings. While not required, most visualizations need some adjustment before they properly display the information that you need. - - [Configure value mappings](ref:configure-value-mappings) - [Visualization-specific options](ref:visualization-specific-options) - [Override field values](ref:override-field-values) diff --git a/docs/sources/dashboards/build-dashboards/create-dynamic-dashboard/index.md b/docs/sources/dashboards/build-dashboards/create-dynamic-dashboard/index.md index 65a72a97d16..638ed32d79e 100644 --- a/docs/sources/dashboards/build-dashboards/create-dynamic-dashboard/index.md +++ b/docs/sources/dashboards/build-dashboards/create-dynamic-dashboard/index.md @@ -105,13 +105,11 @@ To create a dashboard, follow these steps: {{< figure src="/media/docs/grafana/dashboards/screenshot-new-dashboard-v12.png" max-width="750px" alt="New dashboard" >}} 1. Under **Panel layout**, choose one of the following options: - - **Custom** - Position and size panels manually. The default selection. - **Auto grid** - Panels are automatically resized to create a uniform grid based on the column and row settings. 1. Click **+ Add visualization**. 1. In the dialog box that opens, do one of the following: - - Select one of your existing data sources. - Select one of the Grafana [built-in special data sources](ref:built-in-special-data-sources). - Click **Configure a new data source** to set up a new one (Admins only). @@ -137,7 +135,6 @@ To create a dashboard, follow these steps: 1. Refer to the following documentation for ways you can adjust panel settings. While not required, most visualizations need some adjustment before they properly display the information that you need. - - [Configure value mappings](ref:configure-value-mappings) - [Visualization-specific options](ref:visualization-specific-options) - [Override field values](ref:override-field-values) @@ -227,9 +224,7 @@ To configure repeats, follow these steps: 1. Expand the **Repeat options** section. 1. Select the **Repeat by variable**. 1. For panels only, set the following options: - - Under **Repeat direction**, choose one of the following: - - **Horizontal** - Arrange panels side-by-side. Grafana adjusts the width of a repeated panel. You can’t mix other panels on a row with a repeated panel. - **Vertical** - Arrange panels in a column. The width of repeated panels is the same as the original, repeated panel. @@ -276,14 +271,12 @@ To configure show/hide rules, follow these steps: 1. Select **Show** or **Hide** to set whether the panel, row, or tab is shown or hidden based on the rules outcome. 1. Click **+ Add rule**. 1. Select a rule type: - - **Query result** - Show or hide a panel based on query results. Choose from **Has data** and **No data**. For panels only. - **Template variable** - Show or hide the panel, row, or tab dynamically based on the variable value. Select a variable and operator and enter a value. - **Time range less than** - Show or hide the panel, row, or tab if the dashboard time range is shorter than the selected time frame. Select or enter a time range. 1. Configure the rule. 1. Under **Match rules**, select one of the following: - - **Match all** - The panel, row, or tab is shown or hidden only if _all_ the rules are matched. - **Match any** - The panel, row, or tab is shown or hidden if _any_ of the rules are matched. @@ -315,7 +308,6 @@ To edit dashboards, follow these steps: 1. Click in the area you want to work with to bring it into focus and display the associated options in the edit pane. 1. Do one of the following: - - For rows or tabs, make the required changes using the edit pane. - For panels, update the panel title, description, repeat options or show/hide rules in the edit pane. For more changes, click **Configure** and continue in **Edit panel** view. - For dashboards, update the dashboard title, description, grouping or panel layout. For more changes, click the settings (gear) icon in the top-right corner. @@ -355,7 +347,6 @@ To move or resize, follow these steps: 1. Navigate to the dashboard you want to update. 1. Toggle on the edit mode switch. 1. Do one of the following: - - Click the panel title and drag the panel to the new location. - Click and drag the lower-right corner of the panel to change the size of the panel. diff --git a/docs/sources/dashboards/build-dashboards/import-dashboards/index.md b/docs/sources/dashboards/build-dashboards/import-dashboards/index.md index 6378fe4288a..df660d1b351 100644 --- a/docs/sources/dashboards/build-dashboards/import-dashboards/index.md +++ b/docs/sources/dashboards/build-dashboards/import-dashboards/index.md @@ -40,7 +40,6 @@ To import a dashboard, follow these steps: 1. Click **Dashboards** in the primary menu. 1. Click **New** and select **Import** in the drop-down menu. 1. Perform one of the following steps: - - Upload a dashboard JSON file. - Paste a [Grafana.com dashboard](#discover-dashboards-on-grafanacom) URL or ID into the field provided. - Paste dashboard JSON text directly into the text area. diff --git a/docs/sources/dashboards/build-dashboards/manage-dashboard-links/index.md b/docs/sources/dashboards/build-dashboards/manage-dashboard-links/index.md index 3dd373f4c31..99f4cf3bf32 100644 --- a/docs/sources/dashboards/build-dashboards/manage-dashboard-links/index.md +++ b/docs/sources/dashboards/build-dashboards/manage-dashboard-links/index.md @@ -94,7 +94,6 @@ Add links to other dashboards at the top of your current dashboard. If you don't add any tags, Grafana includes links to all other dashboards. 1. Set link options: - - **Show as dropdown** – If you are linking to lots of dashboards, then you probably want to select this option and add an optional title to the dropdown. Otherwise, Grafana displays the dashboard links side by side across the top of your dashboard. - **Include current time range** – Select this option to include the dashboard time range in the link. When the user clicks the link, the linked dashboard opens with the indicated time range already set. **Example:** https://play.grafana.org/d/000000010/annotations?orgId=1&from=now-3h&to=now - **Include current template variable values** – Select this option to include template variables currently used as query parameters in the link. When the user clicks the link, any matching templates in the linked dashboard are set to the values from the link. For more information, see [Dashboard URL variables](ref:dashboard-url-variables). @@ -118,7 +117,6 @@ Add a link to a URL at the top of your current dashboard. You can link to any av 1. In the **Tooltip** field, enter the tooltip you want the link to display when the user hovers their mouse over it. 1. In the **Icon** drop-down, choose the icon you want displayed with the link. 1. Set link options; by default, these options are enabled for URL links: - - **Include current time range** – Select this option to include the dashboard time range in the link. When the user clicks the link, the linked dashboard opens with the indicated time range already set. **Example:** https://play.grafana.org/d/000000010/annotations?orgId=1&from=now-3h&to=now - **Include current template variable values** – Select this option to include template variables currently used as query parameters in the link. When the user clicks the link, any matching templates in the linked dashboard are set to the values from the link. - **Open link in new tab** – Select this option if you want the dashboard link to open in a new tab or window. @@ -134,7 +132,6 @@ To edit, duplicate, or delete dashboard link, follow these steps: 1. Click **Settings**. 1. Go to the **Links** tab. 1. Do one of the following: - - **Edit** - Click the name of the link and update the link settings. - **Duplicate** - Click the copy link icon next to the link that you want to duplicate. - **Delete** - Click the red **X** next to the link that you want to delete, and then **Delete**. diff --git a/docs/sources/dashboards/build-dashboards/modify-dashboard-settings/index.md b/docs/sources/dashboards/build-dashboards/modify-dashboard-settings/index.md index a58f0332e50..ea79a3686c6 100644 --- a/docs/sources/dashboards/build-dashboards/modify-dashboard-settings/index.md +++ b/docs/sources/dashboards/build-dashboards/modify-dashboard-settings/index.md @@ -58,7 +58,6 @@ Adjust dashboard time settings when you want to change the dashboard timezone, t 1. On the **Settings** page, scroll down to the **Time Options** section of the **General** tab. 1. Specify time settings as follows. - - **Time zone:** Specify the local time zone of the service or system that you are monitoring. This can be helpful when monitoring a system or service that operates across several time zones. - **Default:** Grafana uses the default selected time zone for the user profile, team, or organization. If no time zone is specified for the user profile, a team the user is a member of, or the organization, then Grafana uses the local browser time. - **Browser time:** The time zone configured for the viewing user browser is used. This is usually the same time zone as set on the computer. diff --git a/docs/sources/dashboards/create-manage-playlists/index.md b/docs/sources/dashboards/create-manage-playlists/index.md index 20dba1c7cc6..4f2d7831350 100644 --- a/docs/sources/dashboards/create-manage-playlists/index.md +++ b/docs/sources/dashboards/create-manage-playlists/index.md @@ -48,7 +48,6 @@ You can start a playlist in four different view modes. View modes determine how 1. Find the desired playlist and click **Start playlist**. 1. In the dialog box that opens, select one of the [four playlist modes](#playlist-modes) available. 1. Disable any dashboard controls that you don't want displayed while the list plays; these controls are enabled and visible by default. Select from: - - **Time and refresh** - **Variables** - **Dashboard links** @@ -100,7 +99,6 @@ You can edit a playlist including adding, removing, and rearranging the order of 1. Click **Dashboards** in the main menu. 1. Click **Playlists**. 1. Find the playlist you want to update and click **Edit playlist**. Do one or more of the following: - - Edit - Update the name and time interval. - Add dashboards - Search for dashboards by title or tag to add them to the playlist. - Rearrange dashboards - Click and drag the dashboards into your desired order. diff --git a/docs/sources/dashboards/create-reports/_index.md b/docs/sources/dashboards/create-reports/_index.md index 645efcfbb95..0e9650f35ca 100644 --- a/docs/sources/dashboards/create-reports/_index.md +++ b/docs/sources/dashboards/create-reports/_index.md @@ -147,7 +147,6 @@ To create a report, follow these steps: - [Recipients](#4-recipients) - [Attachments](#5-attachments) 1. Click one of the following buttons at the bottom of the **Schedule report** drawer: - - The menu icon to access the following options: - **Download CSV** - **Preview PDF** @@ -179,7 +178,6 @@ To create a report, follow these steps: - [Recipients](#4-recipients) - [Attachments](#5-attachments) 1. Click one of the following buttons at the bottom of the **Schedule report** drawer: - - The menu icon to access the following options: - **Download CSV** - **Preview PDF** @@ -358,7 +356,6 @@ You can also navigate to the list of all reports from the dashboard-specific lis To edit a report, follow these steps: 1. Do one of the following: - - In the main menu, click **Dashboards > Reporting**. - Navigate to the dashboard from which the report was generated and click **Share > Schedule report**. @@ -373,12 +370,10 @@ You can pause and resume sending reports from the report list view. To do this, follow these steps: 1. Do one of the following: - - In the main menu, click **Dashboards > Reporting**. - Navigate to the dashboard from which the report was generated and click **Share > Schedule report**. 1. On the row of the report you want to update, do one of the following: - - Click the pause icon - The report won't be sent according to its schedule until it's resumed. - Click the resume icon - The report resumes on its previous schedule. @@ -389,7 +384,6 @@ You can also pause or resume a report from **Update report** drawer. To delete a report, follow these steps: 1. Do one of the following: - - In the main menu, click **Dashboards > Reporting**. - Navigate to the dashboard from which the report was generated and click **Share > Schedule report**. diff --git a/docs/sources/dashboards/manage-dashboards/index.md b/docs/sources/dashboards/manage-dashboards/index.md index 67ec9e71044..e09f2837eaa 100644 --- a/docs/sources/dashboards/manage-dashboards/index.md +++ b/docs/sources/dashboards/manage-dashboards/index.md @@ -76,7 +76,6 @@ Folders help you organize and group dashboards, which is useful when you have ma 1. Click **Dashboards** in the primary menu. 1. Do one of the following: - - On the **Dashboards** page, click **New** and select **New folder** in the drop-down. - Click an existing folder and on the folder’s page, click **New** and select **New folder** in the drop-down. diff --git a/docs/sources/dashboards/share-dashboards-panels/_index.md b/docs/sources/dashboards/share-dashboards-panels/_index.md index 00966e787e1..1b606ed8d0d 100644 --- a/docs/sources/dashboards/share-dashboards-panels/_index.md +++ b/docs/sources/dashboards/share-dashboards-panels/_index.md @@ -259,7 +259,6 @@ To share a personalized, direct link to your panel within your organization, fol 1. Click **Copy link**. 1. Send the copied link to a Grafana user with authorization to view it. 1. (Optional) To [generate an image of the panel as a PNG file](ref:image-rendering), customize the image settings: - - **Width** - In pixels. The default is 1000. - **Height** - In pixels. The default is 500. - **Scale factor** - The default is 1. diff --git a/docs/sources/dashboards/use-dashboards/index.md b/docs/sources/dashboards/use-dashboards/index.md index c5bba9e9e6d..5d956b4c380 100644 --- a/docs/sources/dashboards/use-dashboards/index.md +++ b/docs/sources/dashboards/use-dashboards/index.md @@ -304,7 +304,6 @@ To edit or delete filters, follow these steps: 1. On the dashboard, click anywhere on the filter you want to change. 1. Do one of the following: - - To edit the operator or value of a filter, click anywhere on the filter and update it. ![Editing an ad hoc filter](/media/docs/grafana/dashboards/screenshot-edit-filters-v11.3.png) diff --git a/docs/sources/dashboards/variables/add-template-variables/index.md b/docs/sources/dashboards/variables/add-template-variables/index.md index 54dc20e2d47..2e6181432df 100644 --- a/docs/sources/dashboards/variables/add-template-variables/index.md +++ b/docs/sources/dashboards/variables/add-template-variables/index.md @@ -121,13 +121,11 @@ To create a variable, follow these steps: If you don't enter a display name, then the drop-down list label is the variable name. 1. Choose a **Show on dashboard** option: - - **Label and value** - The variable drop-down list displays the variable **Name** or **Label** value. This is the default. - **Value:** The variable drop-down list only displays the selected variable value and a down arrow. - **Nothing:** No variable drop-down list is displayed on the dashboard. 1. Click one of the following links to complete the steps for adding your selected variable type: - - [Query](#add-a-query-variable) - [Custom](#add-a-custom-variable) - [Textbox](#add-a-text-box-variable) @@ -157,7 +155,6 @@ Query expressions are different for each data source. For more information, refe For more information about data sources, refer to [Add a data source](ref:add-a-data-source). 1. In the **Query type** drop-down list, select one of the following options: - - **Label names** - **Label values** - **Metrics** @@ -166,7 +163,6 @@ Query expressions are different for each data source. For more information, refe - **Classic query** 1. In the **Query** field, enter a query. - - The query field varies according to your data source. Some data sources have custom query editors. - Each data source defines how the variable values are extracted. The typical implementation uses every string value returned from the data source response as a variable value. Make sure to double-check the documentation for the data source. - Some data sources let you provide custom "display names" for the values. For instance, the PostgreSQL, MySQL, and Microsoft SQL Server plugins handle this by looking for fields named `__text` and `__value` in the result. Other data sources may look for `text` and `value` or use a different approach. Always remember to double-check the documentation for the data source. @@ -175,12 +171,10 @@ Query expressions are different for each data source. For more information, refe 1. (Optional) In the **Regex** field, type a regular expression to filter or capture specific parts of the names returned by your data source query. To see examples, refer to [Filter variables with a regular expression](#filter-variables-with-regex). 1. In the **Sort** drop-down list, select the sort order for values to be displayed in the dropdown list. The default option, **Disabled**, means that the order of options returned by your data source query is used. 1. Under **Refresh**, select when the variable should update options: - - **On dashboard load** - Queries the data source every time the dashboard loads. This slows down dashboard loading, because the variable query needs to be completed before dashboard can be initialized. - **On time range change** - Queries the data source every time the dashboard loads and when the dashboard time range changes. Use this option if your variable options query contains a time range filter or is dependent on the dashboard time range. 1. (Optional) Configure the settings in the [Selection Options](#configure-variable-selection-options) section: - - **Multi-value** - Enables multiple values to be selected at the same time. - **Include All option** - Enables an option to include all variables. @@ -200,7 +194,6 @@ For example, if you have server names or region names that never change, then yo You can include numbers, strings, or key/value pairs separated by a space and a colon. For example, `key1 : value1,key2 : value2`. 1. (Optional) Configure the settings in the [Selection Options](#configure-variable-selection-options) section: - - **Multi-value** - Enables multiple values to be selected at the same time. - **Include All option** - Enables an option to include all variables. @@ -249,7 +242,6 @@ _Data source_ variables enable you to quickly change the data source for an enti Leave this field empty to display all instances. 1. (Optional) Configure the settings in the [Selection Options](#configure-variable-selection-options) section: - - **Multi-value** - Enables multiple values to be selected at the same time. - **Include All option** - Enables an option to include all variables. @@ -271,7 +263,6 @@ You can use an interval variable as a parameter to group by time (for InfluxDB), 1. (Optional) Select on the **Auto option** checkbox if you want to add the `auto` option to the list. This option allows you to specify how many times the current time range should be divided to calculate the current `auto` time span. If you turn it on, then two more options appear: - - **Step count** - Select the number of times the current time range is divided to calculate the value, similar to the **Max data points** query option. For example, if the current visible time range is 30 minutes, then the `auto` interval groups the data into 30 one-minute increments. The default value is 30 steps. - **Min interval** - The minimum threshold below which the step count intervals does not divide the time. To continue the 30 minute example, if the minimum interval is set to 2m, then Grafana would group the data into 15 two-minute increments. diff --git a/docs/sources/datasources/elasticsearch/configure-elasticsearch-data-source.md b/docs/sources/datasources/elasticsearch/configure-elasticsearch-data-source.md index 6880eae661c..feb170a5c16 100644 --- a/docs/sources/datasources/elasticsearch/configure-elasticsearch-data-source.md +++ b/docs/sources/datasources/elasticsearch/configure-elasticsearch-data-source.md @@ -130,7 +130,6 @@ The following settings are specific to the Elasticsearch data source. - **Index name** - Use the index settings to specify a default for the `time field` and your Elasticsearch index's name. You can use a time pattern, for example `[logstash-]YYYY.MM.DD`, or a wildcard for the index name. When specifying a time pattern, the fixed part(s) of the pattern should be wrapped in square brackets. - **Pattern** - Select the matching pattern if using one in your index name. Options include: - - no pattern - hourly - daily diff --git a/docs/sources/datasources/elasticsearch/query-editor/index.md b/docs/sources/datasources/elasticsearch/query-editor/index.md index c6e56ed963d..fa20353a395 100644 --- a/docs/sources/datasources/elasticsearch/query-editor/index.md +++ b/docs/sources/datasources/elasticsearch/query-editor/index.md @@ -61,7 +61,6 @@ Metrics queries aggregate data and produce a variety of calculations such as cou - **Alias** - Aliasing only applies to **time series queries**, where the last group is `date histogram`. This is ignored for any other type of query. - **Metric** - Metrics aggregations include: - - count - see [Value count aggregation](https://www.elastic.co/guide/en/elasticsearch/reference/8.9/search-aggregations-metrics-valuecount-aggregation.html) - average - see [Avg aggregation](https://www.elastic.co/guide/en/elasticsearch/reference/8.9/search-aggregations-metrics-rate-aggregation.html) - sum - see [Sum aggregation](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-sum-aggregation.html) @@ -78,7 +77,6 @@ You can select multiple metrics and group by multiple terms or filters when usin Use the **+ sign** to the right to add multiple metrics to your query. Click on the **eye icon** next to **Metric** to hide metrics, and the **garbage can icon** to remove metrics. - **Group by options** - Create multiple group by options when constructing your Elasticsearch query. Date histogram is the default option. Below is a list of options in the dropdown menu. - - terms - see [Terms aggregation](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-terms-aggregation.html). - filter - see [Filter aggregation](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-filter-aggregation.html). - geo hash grid - see [Geohash grid aggregation](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-geohashgrid-aggregation.html). diff --git a/docs/sources/datasources/google-cloud-monitoring/_index.md b/docs/sources/datasources/google-cloud-monitoring/_index.md index 61b37b747fd..27bc7b390cd 100644 --- a/docs/sources/datasources/google-cloud-monitoring/_index.md +++ b/docs/sources/datasources/google-cloud-monitoring/_index.md @@ -83,7 +83,6 @@ If Grafana is running on a Google Compute Engine (GCE) virtual machine, when you Before you can request data from Google Cloud Monitoring, you must first enable necessary APIs on the Google end. 1. Open the Monitoring and Cloud Resource Manager API pages: - - [Monitoring API](https://console.cloud.google.com/apis/library/monitoring.googleapis.com) - [Cloud Resource Manager API](https://console.cloud.google.com/apis/library/cloudresourcemanager.googleapis.com) diff --git a/docs/sources/datasources/mysql/query-editor/_index.md b/docs/sources/datasources/mysql/query-editor/_index.md index 04a6cdc5e4e..8ec12f2789e 100644 --- a/docs/sources/datasources/mysql/query-editor/_index.md +++ b/docs/sources/datasources/mysql/query-editor/_index.md @@ -89,7 +89,6 @@ The following components will help you build a MySQL query: - **Format** - Select a format response from the drop-down for the MySQL query. The default is **Table**. If you use the **Time series** format option, one of the columns must be `time`. - **Dataset** - Select a database to query from the drop-down. - - **Table** - Select a table from the drop-down. Tables correspond to the chosen database. - **Data operations** - _Optional_ Select an aggregation from the drop-down. You can add multiple data operations by clicking the **+ sign**. Click the **X** to remove a data operation. Click the **garbage can icon** to remove the entire column. @@ -99,15 +98,12 @@ The following components will help you build a MySQL query: - **Alias** - _Optional_ Add an alias from the drop-down. You can also add your own alias by typing it in the box and clicking **Enter**. Remove an alias by clicking the **X**. - **Filter** - Toggle to add filters. - - **Filter by column value** - _Optional_ If you toggle **Filter** you can add a column to filter by from the drop-down. To filter on more columns, click the **+ sign** to the right of the condition drop-down. You can choose a variety of operators from the drop-down next to the condition. When multiple filters are added you can add an `AND` operator to display all true conditions or an `OR` operator to display any true conditions. Use the second drop-down to choose a filter. To remove a filter, click the `X` button next to that filter's drop-down. After selecting a date type column, you can choose **Macros** from the operators list and select `timeFilter` which will add the `$\_\_timeFilter` macro to the query with the selected date column. - **Group** - Toggle to add **Group by column**. - - **Group by column** - Select a column to filter by from the drop-down. Click the **+ sign** to filter by multiple columns. Click the **X** to remove a filter. - **Order** - Toggle to add an ORDER BY statement. - - **Order by** - Select a column to order by from the drop-down. Select ascending (`ASC`) or descending (`DESC`) order. - **Limit** - You can add an optional limit on the number of retrieved results. Default is 50. diff --git a/docs/sources/datasources/prometheus/configure/_index.md b/docs/sources/datasources/prometheus/configure/_index.md index d312245e658..b68219e3866 100644 --- a/docs/sources/datasources/prometheus/configure/_index.md +++ b/docs/sources/datasources/prometheus/configure/_index.md @@ -148,7 +148,6 @@ Use the IP address of the Prometheus container, or the hostname if you are using There are three authentication options for the Prometheus data source. - **Basic authentication** - The most common authentication method. - - **User** - The username you use to connect to the data source. - **Password** - The password you use to connect to the data source. diff --git a/docs/sources/datasources/prometheus/query-editor/_index.md b/docs/sources/datasources/prometheus/query-editor/_index.md index 31919d45e05..5be3b7cc180 100644 --- a/docs/sources/datasources/prometheus/query-editor/_index.md +++ b/docs/sources/datasources/prometheus/query-editor/_index.md @@ -78,7 +78,6 @@ The following video demonstrates how to use the visual Prometheus query builder: Builder mode contains the following components: - **Kick start your query** - Click to view a list of predefined operation patterns that help you quickly build queries with multiple operations. These include: - - Rate query starters - Histogram query starters - Binary query starters @@ -104,7 +103,6 @@ Click **+ Operations** to select from a list of operations including Aggregation **Options:** - **Legend**- Lets you customize the name for the time series. You can use a predefined or custom format. - - **Auto** - Displays unique labels. Also displays all overlapping labels if a series has multiple labels. - **Verbose** - Displays all label names. - **Custom** - Lets you customize the legend using label templates. For example, `{{hostname}}` is replaced with the value of the `hostname` label. To switch to a different legend mode, clear the input and click outside the field. @@ -112,7 +110,6 @@ Click **+ Operations** to select from a list of operations including Aggregation - **Min step** - Sets the minimum interval between data points returned by the query. For example, setting this to `1h` suggests that data is collected or displayed at hourly intervals. This setting supports the `$__interval` and `$__rate_interval` macros. Note that the time range of the query is aligned to this step size, which may adjust the actual start and end times of the returned data. - **Format** - Determines how the data from your Prometheus query is interpreted and visualized in a panel. Choose from the following format options: - - **Time series** - The default format. Refer to [Time series kind formats](https://grafana.com/developers/dataplane/timeseries/) for information on time series data frames and how time and value fields are structured. - **Table** - Displays data in table format. This format works only in a [Table panel](ref:table). - **Heatmap** - Displays Histogram-type metrics in a [Heatmap panel](ref:heatmap) by converting cumulative histograms to regular ones and sorting the series by the bucket bound. Converts cumulative histogram data into regular histogram format and sorts the series by bucket boundaries for proper display. diff --git a/docs/sources/datasources/tempo/configure-tempo-data-source.md b/docs/sources/datasources/tempo/configure-tempo-data-source.md index e737d1810a8..620459d765b 100644 --- a/docs/sources/datasources/tempo/configure-tempo-data-source.md +++ b/docs/sources/datasources/tempo/configure-tempo-data-source.md @@ -235,7 +235,6 @@ To use custom queries with the configuration, follow these steps: 1. Specify a custom query to be used to query metrics data. Each linked query consists of: - - **Link Label:** _(Optional)_ Descriptive label for the linked query. - **Query:** The query ran when navigating from a trace to the metrics data source. Interpolate tags using the `$__tags` keyword. diff --git a/docs/sources/datasources/tempo/traces-in-grafana/trace-correlations.md b/docs/sources/datasources/tempo/traces-in-grafana/trace-correlations.md index 7b28419d2d5..c8f4bc4b150 100644 --- a/docs/sources/datasources/tempo/traces-in-grafana/trace-correlations.md +++ b/docs/sources/datasources/tempo/traces-in-grafana/trace-correlations.md @@ -45,7 +45,6 @@ To use trace correlations, you need: 1. On step 1, provide a **label** for the correlation, and an optional **description**. 1. On step 2, configure the correlation **target**. - - Select the **Type** drop-down list and choose **Query** to link to another data source or choose **External** for a custom URL. - For a query **Target**, select the target drop-down list and select the data source that should be queried when the link is clicked. Define the target query. @@ -68,7 +67,6 @@ To use trace correlations, you need: {{< figure src="/media/docs/tempo/screenshot-grafana-trace-correlations-loki-step-2.png" max-width="900px" class="docs-image--no-shadow" alt="Setting up a correlation for a Loki target using trace variables" >}} 1. On step 3, configure the correlation data source: - - Select your Tempo data source in the **Source** drop-down list. - Enter the trace data variable you use for the correlation in the **Results field**. @@ -104,7 +102,6 @@ In this example, you configure trace to logs by service name and a trace identif {{< figure src="/media/docs/tempo/screenshot-grafana-trace-view-correlations-example-1-step-1.png" max-width="900px" class="docs-image--no-shadow" alt="Using correlations for a trace" >}} 1. On step 2, configure the correlation target: - - Select the target type **Query** and select your Loki data source as **Target**. - Define the Loki query, using `serviceName` and `traceID` as variables derived from the span data: @@ -116,7 +113,6 @@ In this example, you configure trace to logs by service name and a trace identif {{< figure src="/media/docs/tempo/screenshot-grafana-trace-view-correlations-example-1-step-2.png" max-width="900px" class="docs-image--no-shadow" alt="Using correlations for a trace" >}} 1. On step 3, configure the correlation source: - - Select your Tempo data source as **Source**. - Use `traceID` as **Results field**. @@ -138,7 +134,6 @@ In this example, you configure trace corrections with a custom URL. 1. On step 1, add a new correlation with the label **Open custom URL** and an optional description. 1. On step 2, configure the correlation target: - - Select the target type **External**. - Define your target URL, using variables derived from the span data. In this example, we are using `serviceName` and `traceID`. @@ -148,7 +143,6 @@ In this example, you configure trace corrections with a custom URL. ``` 1. On step 3, configure the correlation source: - - Select your Tempo data source as **Source**. - Use `traceID` as **Results field**. diff --git a/docs/sources/explore/get-started-with-explore.md b/docs/sources/explore/get-started-with-explore.md index fbffb4bb769..c4a64bc9196 100644 --- a/docs/sources/explore/get-started-with-explore.md +++ b/docs/sources/explore/get-started-with-explore.md @@ -53,7 +53,6 @@ Explore consists of a toolbar, outline, query editor, the ability to add multipl - **Outline** - Keeps track of the queries and visualization panels created in Explore. Refer to [Content outline](#content-outline) for more detail. - **Toolbar** - Provides quick access to frequently used tools and settings. - - **Data source picker** - Select a data source from the dropdown menu, or use absolute time. - **Split** - Click to compare visualizations side by side. Refer to [Split and compare](#split-and-compare) for additional detail. - **Add** - Click to add your exploration to a dashboard. You can also use this to declare an incident,create a forecast, detect outliers and to run an investigation. diff --git a/docs/sources/fundamentals/exemplars/index.md b/docs/sources/fundamentals/exemplars/index.md index 4181c50cac5..8b556d928d6 100644 --- a/docs/sources/fundamentals/exemplars/index.md +++ b/docs/sources/fundamentals/exemplars/index.md @@ -101,7 +101,6 @@ This panel shows the details of the trace in different segments. - The next segment shows the entire span for the specific trace as a narrow strip. All levels of the trace from the client all the way down to database query is displayed, which provides a bird's eye view of the time distribution across all layers over which the HTTP request was processed. - 1. You can click within this strip view to display a magnified view of a smaller time segment within the span. This magnified view shows up in the bottom segment of the panel. 1. In the magnified view, you can expand or collapse the various levels of the trace to drill down to the specific span of interest. diff --git a/docs/sources/observability-as-code/get-started.md b/docs/sources/observability-as-code/get-started.md index 00b48501f95..ef9822aae5c 100644 --- a/docs/sources/observability-as-code/get-started.md +++ b/docs/sources/observability-as-code/get-started.md @@ -68,17 +68,14 @@ Refer to the [Foundation SDK](../foundation-sdk) documentation for more informat If you're already using established Infrastructure as Code or other configuration management tools, Grafana offers integrations to manage resources within your existing workflows. - [Terraform](https://grafana.com/docs/grafana-cloud/developer-resources/infrastructure-as-code/terraform/) - - Use the Grafana Terraform provider to manage dashboards, alerts, and more. - Understand how to define and deploy resources using HCL/JSON configurations. - [Ansible](https://grafana.com/docs/grafana-cloud/developer-resources/infrastructure-as-code/ansible/) - - Learn to use the Grafana Ansible collection to manage Grafana Cloud resources, including folders and cloud stacks. - Write playbooks to automate resource provisioning through the Grafana API. - [Grafana Operator](https://grafana.com/docs/grafana-cloud/developer-resources/infrastructure-as-code/grafana-operator/) - - Utilize Kubernetes-native management with the Grafana Operator. - Manage dashboards, folders, and data sources via Kubernetes Custom Resources. - Integrate with GitOps workflows for seamless version control and deployment. diff --git a/docs/sources/observability-as-code/provision-resources/git-sync-setup.md b/docs/sources/observability-as-code/provision-resources/git-sync-setup.md index 4a81b71a197..b0c44727ffd 100644 --- a/docs/sources/observability-as-code/provision-resources/git-sync-setup.md +++ b/docs/sources/observability-as-code/provision-resources/git-sync-setup.md @@ -87,7 +87,6 @@ This token needs to be added to your Git Sync configuration to enable read and w 1. Create a new token using [Create new fine-grained personal access token](https://github.com/settings/personal-access-tokens/new). Refer to [Managing your personal access tokens](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens) for instructions. 1. Under **Permissions**, expand **Repository permissions**. 1. Set these permissions for Git Sync: - - **Contents**: Read and write permission - **Metadata**: Read-only permission - **Pull requests**: Read and write permission diff --git a/docs/sources/observability-as-code/provision-resources/provisioned-dashboards.md b/docs/sources/observability-as-code/provision-resources/provisioned-dashboards.md index 8ab3afa9c03..e92bb0800dc 100644 --- a/docs/sources/observability-as-code/provision-resources/provisioned-dashboards.md +++ b/docs/sources/observability-as-code/provision-resources/provisioned-dashboards.md @@ -97,7 +97,6 @@ Saving changes requires opening a pull request in your GitHub repository. 1. Click **Save dashboard**. 1. On the **Provisioned dashboard** panel, choose the options you want to use: - - **Update default refresh value**: Check this box to make the current refresh the new default. - **Update default variable values**: Check this box to make the current values the new default. - **Path**: Provide the path for your repository, ending in a JSON or YAML file. diff --git a/docs/sources/panels-visualizations/configure-panel-options/index.md b/docs/sources/panels-visualizations/configure-panel-options/index.md index 59c466a20fb..dc7c8601c11 100644 --- a/docs/sources/panels-visualizations/configure-panel-options/index.md +++ b/docs/sources/panels-visualizations/configure-panel-options/index.md @@ -90,7 +90,6 @@ To configure repeating panels, follow these steps: 1. Open the **Panel options** section of the panel editor pane. 1. Under **Repeat options**, select a variable in the **Repeat by variable** drop-down list. 1. Under **Repeat direction**, choose one of the following: - - **Horizontal** - Arrange panels side-by-side. Grafana adjusts the width of a repeated panel. You can't mix other panels on a row with a repeated panel. - **Vertical** - Arrange panels in a column. The width of repeated panels is the same as the original, repeated panel. diff --git a/docs/sources/panels-visualizations/configure-standard-options/index.md b/docs/sources/panels-visualizations/configure-standard-options/index.md index a27bd238a4f..2e737ed7de2 100644 --- a/docs/sources/panels-visualizations/configure-standard-options/index.md +++ b/docs/sources/panels-visualizations/configure-standard-options/index.md @@ -198,7 +198,6 @@ To display timestamps that are in seconds since epoch, multiply your timestamp v 1. Click **Add transformation**. 1. Select the **Add field from calculation** transformation. 1. Set the following options: - - **Mode** - **Binary operation** - **Operation** - Select your timestamp field diff --git a/docs/sources/panels-visualizations/configure-value-mappings/index.md b/docs/sources/panels-visualizations/configure-value-mappings/index.md index 82231549084..11223d3870b 100644 --- a/docs/sources/panels-visualizations/configure-value-mappings/index.md +++ b/docs/sources/panels-visualizations/configure-value-mappings/index.md @@ -184,7 +184,6 @@ The following image shows a table visualization with value mappings. If you want 1. Scroll to the **Value mappings** section and expand it. 1. Click **Add value mappings**. 1. Click **Add a new mapping** and then select one of the following: - - **Value** - Enter a single value to match. - **Range** - Enter the beginning and ending values of a range to match. - **Regex** - Enter a regular expression pattern to match. diff --git a/docs/sources/panels-visualizations/panel-inspector/index.md b/docs/sources/panels-visualizations/panel-inspector/index.md index a8086224d08..d751957a171 100644 --- a/docs/sources/panels-visualizations/panel-inspector/index.md +++ b/docs/sources/panels-visualizations/panel-inspector/index.md @@ -43,7 +43,6 @@ Grafana generates a CSV file that contains your data, including any transformati 1. Click **Data**. If your panel contains multiple queries or queries multiple nodes, then you have additional options. - - **Select result**: Choose which result set data you want to view. - **Transform data** - **Join by time**: View raw data from all your queries at once, one result set per column. Click a column heading to reorder the data. diff --git a/docs/sources/panels-visualizations/query-transform-data/sql-expressions/index.md b/docs/sources/panels-visualizations/query-transform-data/sql-expressions/index.md index 629eaece47f..54fd4f8f6cc 100644 --- a/docs/sources/panels-visualizations/query-transform-data/sql-expressions/index.md +++ b/docs/sources/panels-visualizations/query-transform-data/sql-expressions/index.md @@ -32,7 +32,6 @@ For general information on Grafana expressions, refer to [Write expression queri ## Before you begin - Enable SQL expressions under the feature toggle `sqlExpressions`. - - If you self-host Grafana, you can find feature toggles in the configuration file `grafana.ini`. ``` @@ -158,12 +157,10 @@ Grafana supports three types of data source response formats: 1. **Single Table-like Frame**: This refers to data returned in a standard tabular structure, where all values are organized into rows and columns, similar to what you'd get from a SQL query. - - **Example**: Any query against a SQL data source (e.g., PostgreSQL, MySQL) with the format set to Table. 2. **Dataplane: Time Series Format**: This format represents time series data with timestamps and associated values. It is typically returned from monitoring data sources. - - **Example**: Prometheus or Loki Range Queries (queries that return a set of values over time). 3. **Dataplane: Numeric Long Format**: diff --git a/docs/sources/panels-visualizations/visualizations/bar-chart/index.md b/docs/sources/panels-visualizations/visualizations/bar-chart/index.md index 44d0922b454..33b2bce6bfc 100644 --- a/docs/sources/panels-visualizations/visualizations/bar-chart/index.md +++ b/docs/sources/panels-visualizations/visualizations/bar-chart/index.md @@ -130,7 +130,6 @@ Set the mode of the gradient fill. Fill gradient is based on the line color. To - **Opacity** - Transparency of the gradient is calculated based on the values on the y-axis. Opacity of the fill is increasing with the values on the Y-axis. - **Hue** - Gradient color is generated based on the hue of the line color. - **Scheme** - The bar receives a gradient color defined by the **Standard options > Color scheme** selection. - - **From thresholds** - If the **Color scheme** selection is **From thresholds (by value)**, then each bar is the color of the defined threshold. {{< figure src="/media/docs/grafana/panels-visualizations/screenshot-colors-by-thresholds-v11.3.png" alt="Color scheme From thresholds" caption="Color scheme: From thresholds" >}} diff --git a/docs/sources/panels-visualizations/visualizations/canvas/index.md b/docs/sources/panels-visualizations/visualizations/canvas/index.md index cef103b2424..4be10911af6 100644 --- a/docs/sources/panels-visualizations/visualizations/canvas/index.md +++ b/docs/sources/panels-visualizations/visualizations/canvas/index.md @@ -470,7 +470,6 @@ You can style the selected connection using the following options: - **Size** - Control the size of the connection by entering a number in the **Value** field. - **Radius** - Add curve to the connection by entering a value to represent the degree. - **Arrow Direction** - Control the appearance of the arrow head. Choose from: - - **Forward** - The arrow head points in the direction in which the connection was drawn. - **Reverse** - The arrow head points in the opposite direction of which the connection was drawn. - **Both** - Adds arrow heads to both ends of the connection. diff --git a/docs/sources/panels-visualizations/visualizations/table/index.md b/docs/sources/panels-visualizations/visualizations/table/index.md index 9a7f97b13e4..707acfababc 100644 --- a/docs/sources/panels-visualizations/visualizations/table/index.md +++ b/docs/sources/panels-visualizations/visualizations/table/index.md @@ -160,7 +160,6 @@ To filter column values, follow these steps: 1. Click the checkbox next to the values that you want to display or click **Select all**. 1. Enter text in the search field at the top to show those values in the display so that you can select them rather than scroll to find them. 1. Choose from several operators to display column values: - - **Contains** - Matches a regex pattern (operator by default). - **Expression** - Evaluates a boolean expression. The character `$` represents the column value in the expression (for example, "$ >= 10 && $ <= 12"). - The typical comparison operators: `=`, `!=`, `<`, `<=`, `>`, `>=`. diff --git a/docs/sources/panels-visualizations/visualizations/traces/index.md b/docs/sources/panels-visualizations/visualizations/traces/index.md index a82d0be2662..abf7fc1ddc3 100644 --- a/docs/sources/panels-visualizations/visualizations/traces/index.md +++ b/docs/sources/panels-visualizations/visualizations/traces/index.md @@ -91,7 +91,6 @@ This procedure uses dashboard variables and templates to allow you to enter trac 1. From your Grafana stack, create a new dashboard or go to an existing dashboard where you'd like to add traces visualizations. 1. Do one of the following: - - New dashboard - Click **+ Add visualization**. - Existing dashboard - Click **Edit** in the top-right corner and then select **Visualization** in the **Add** drop-down. diff --git a/docs/sources/setup-grafana/configure-security/configure-authentication/auth-proxy/index.md b/docs/sources/setup-grafana/configure-security/configure-authentication/auth-proxy/index.md index f381c212abb..3d1c4a48a6b 100644 --- a/docs/sources/setup-grafana/configure-security/configure-authentication/auth-proxy/index.md +++ b/docs/sources/setup-grafana/configure-security/configure-authentication/auth-proxy/index.md @@ -120,9 +120,7 @@ In this example we use Apache as a reverse proxy in front of Grafana. Apache han - The first four lines of the virtualhost configuration are standard, so we won’t go into detail on what they do. - We use a **\** configuration block for applying our authentication rules to every proxied request. These rules include requiring basic authentication where user:password credentials are stored in the **/etc/apache2/grafana_htpasswd** file. This file can be created with the `htpasswd` command. - - The next part of the configuration is the tricky part. We use Apache’s rewrite engine to create our **X-WEBAUTH-USER header**, populated with the authenticated user. - - **RewriteRule .\* - [E=PROXY_USER:%{LA-U:REMOTE_USER}, NS]**: This line is a little bit of magic. What it does, is for every request use the rewriteEngines look-ahead (LA-U) feature to determine what the REMOTE_USER variable would be set to after processing the request. Then assign the result to the variable PROXY_USER. This is necessary as the REMOTE_USER variable is not available to the RequestHeader function. - **RequestHeader set X-WEBAUTH-USER “%{PROXY_USER}e”**: With the authenticated username now stored in the PROXY_USER variable, we create a new HTTP request header that will be sent to our backend Grafana containing the username. diff --git a/docs/sources/setup-grafana/configure-security/configure-authentication/azuread/index.md b/docs/sources/setup-grafana/configure-security/configure-authentication/azuread/index.md index 92be8f1f25a..69e6e1415f0 100644 --- a/docs/sources/setup-grafana/configure-security/configure-authentication/azuread/index.md +++ b/docs/sources/setup-grafana/configure-security/configure-authentication/azuread/index.md @@ -42,16 +42,12 @@ To enable the Azure AD/Entra ID OAuth, register your application with Entra ID. 1. Note the **Application ID**. This is the OAuth client ID. 1. Click **Endpoints** from the top menu. - - Note the **OAuth 2.0 authorization endpoint (v2)** URL. This is the authorization URL. - Note the **OAuth 2.0 token endpoint (v2)**. This is the token URL. 1. Click **Certificates & secrets** in the side menu, then add a new entry under the supported client authentication option you want to use. The following are the supported client authentication options with their respective configuration steps. - - **Client secrets** - 1. Add a new entry under **Client secrets** with the following configuration. - - Description: Grafana OAuth 2.0 - Expires: Select an expiration period @@ -60,16 +56,12 @@ To enable the Azure AD/Entra ID OAuth, register your application with Entra ID. {{< admonition type="note" >}} Make sure that you copy the string in the **Value** field, rather than the one in the **Secret ID** field. {{< /admonition >}} - 1. You must have set `client_authentication` under `[auth.azuread]` to `client_secret_post` in the Grafana server configuration for this to work. - **Federated credentials** - - **_Managed Identity_** - 1. Refer to [Configure an application to trust a managed identity (preview)](https://learn.microsoft.com/en-us/entra/workload-id/workload-identity-federation-config-app-trust-managed-identity?tabs=microsoft-entra-admin-center) for a complete guide on setting up a managed identity as a federated credential. Add a new entry under Federated credentials with the following configuration. - - Federated credential scenario: Select **Other issuer**. - Issuer: The OAuth 2.0 / OIDC issuer URL of the Microsoft Entra ID authority. For example: `https://login.microsoftonline.com/{tenantID}/v2.0`. - Subject identifier: The Object (Principal) ID GUID of the Managed Identity. @@ -88,10 +80,8 @@ To enable the Azure AD/Entra ID OAuth, register your application with Entra ID. {{< /admonition >}} - **_Workload Identity (K8s/AKS)_** - 1. Refer to [Federated identity credential for an Azure AD application](https://azure.github.io/azure-workload-identity/docs/topics/federated-identity-credential.html#azure-portal-ui) for a complete guide on setting up a federated credential for workload identity. Add a new entry under Federated credentials with the following configuration. - - Federated credential scenario: Select **Kubernetes accessing Azure resources**. - [Cluster issuer URL](https://learn.microsoft.com/en-us/azure/aks/use-oidc-issuer#get-the-oidc-issuer-url): The OIDC issuer URL that your cluster is integrated with. For example: `https://{region}.oic.prod-aks.azure.com/{tenant_id}/{uuid}`. - Namespace: Namespace of your Grafana deployment. For example: `grafana`. @@ -141,7 +131,6 @@ This section describes setting up basic application roles for Grafana within the 1. Click **App roles** and then **Create app role**. 1. Define a role corresponding to each Grafana role: Viewer, Editor, and Admin. - 1. Choose a **Display name** for the role. For example, "Grafana Editor". 1. Set the **Allowed member types** to **Users/Groups**. diff --git a/docs/sources/setup-grafana/configure-security/configure-authentication/generic-oauth/index.md b/docs/sources/setup-grafana/configure-security/configure-authentication/generic-oauth/index.md index 9e10faee645..9ebe70e6e55 100644 --- a/docs/sources/setup-grafana/configure-security/configure-authentication/generic-oauth/index.md +++ b/docs/sources/setup-grafana/configure-security/configure-authentication/generic-oauth/index.md @@ -450,7 +450,6 @@ Support for the Auth0 "audience" feature is not currently available in Grafana. To set up Generic OAuth authentication with Auth0, follow these steps: 1. Create an Auth0 application using the following parameters: - - Name: Grafana - Type: Regular Web Application @@ -485,7 +484,6 @@ To set up Generic OAuth authentication with Bitbucket, follow these steps: 1. Navigate to **Settings > Workspace setting > OAuth consumers** in BitBucket. 1. Create an application by selecting **Add consumer** and using the following parameters: - - Allowed Callback URLs: `https:///login/generic_oauth` 1. Click **Save**. @@ -518,7 +516,6 @@ By default, a refresh token is included in the response for the **Authorization To set up Generic OAuth authentication with OneLogin, follow these steps: 1. Create a new Custom Connector in OneLogin with the following settings: - - Name: Grafana - Sign On Method: OpenID Connect - Redirect URI: `https:///login/generic_oauth` @@ -526,7 +523,6 @@ To set up Generic OAuth authentication with OneLogin, follow these steps: - Login URL: `https:///login/generic_oauth` 1. Add an app to the Grafana Connector: - - Display Name: Grafana 1. Update the `[auth.generic_oauth]` section of the Grafana configuration file using the client ID and client secret from the **SSO** tab of the app details page: diff --git a/docs/sources/setup-grafana/configure-security/configure-authentication/gitlab/index.md b/docs/sources/setup-grafana/configure-security/configure-authentication/gitlab/index.md index 3ab7695554c..22363e59b54 100644 --- a/docs/sources/setup-grafana/configure-security/configure-authentication/gitlab/index.md +++ b/docs/sources/setup-grafana/configure-security/configure-authentication/gitlab/index.md @@ -88,7 +88,6 @@ Ensure that you have access to the [Grafana configuration file](../../../configu To configure GitLab authentication with Grafana, follow these steps: 1. Create an OAuth application in GitLab. - 1. Set the redirect URI to `http://:/login/gitlab`. Ensure that the Redirect URI is the complete HTTP address that you use to access Grafana via your browser, but with the appended path of `/login/gitlab`. diff --git a/docs/sources/setup-grafana/configure-security/configure-authentication/ldap-ui/_index.md b/docs/sources/setup-grafana/configure-security/configure-authentication/ldap-ui/_index.md index 7deaab7f849..ea8ec60d0f5 100644 --- a/docs/sources/setup-grafana/configure-security/configure-authentication/ldap-ui/_index.md +++ b/docs/sources/setup-grafana/configure-security/configure-authentication/ldap-ui/_index.md @@ -87,7 +87,6 @@ Map LDAP groups to Grafana roles. 1. **Manage group mappings**: When managing group mappings, the following fields are available. To add a new group mapping, click the **Add group mapping** button. - 1. **Add a group DN mapping**: The name of the key used to extract the ID token. 1. **Add an organization role mapping**: Select the Basic Role mapped to this group. 1. **Add the organization ID membership mapping**: Map the group to an organization ID. diff --git a/docs/sources/setup-grafana/configure-security/configure-authentication/okta/index.md b/docs/sources/setup-grafana/configure-security/configure-authentication/okta/index.md index 3a90f19b371..8166760890f 100644 --- a/docs/sources/setup-grafana/configure-security/configure-authentication/okta/index.md +++ b/docs/sources/setup-grafana/configure-security/configure-authentication/okta/index.md @@ -30,7 +30,6 @@ To follow this guide, ensure you have permissions in your Okta workspace to crea 1. For **Sign-in method**, select **OIDC - OpenID Connect**. 1. For **Application type**, select **Web Application** and click **Next**. 1. Configure **New Web App Integration Operations**: - - **App integration name**: Choose a name for the app. - **Logo (optional)**: Add a logo. - **Grant type**: Select **Authorization Code** and **Refresh Token**. @@ -54,7 +53,6 @@ To follow this guide, ensure you have permissions in your Okta workspace to crea 1. In the **Okta Admin Console**, select **Directory > Profile Editor**. 1. Select the Okta Application Profile you created previously (the default name for this is ` User`). 1. Select **Add Attribute** and fill in the following fields: - - **Data Type**: string - **Display Name**: Meaningful name. For example, `Grafana Role`. - **Variable Name**: Meaningful name. For example, `grafana_role`. diff --git a/docs/sources/setup-grafana/configure-security/configure-authentication/saml/_index.md b/docs/sources/setup-grafana/configure-security/configure-authentication/saml/_index.md index 6dd7f45042d..40cfc2441d8 100644 --- a/docs/sources/setup-grafana/configure-security/configure-authentication/saml/_index.md +++ b/docs/sources/setup-grafana/configure-security/configure-authentication/saml/_index.md @@ -50,7 +50,6 @@ Configuration in the API takes precedence over the configuration in the Grafana Grafana supports the following SAML 2.0 bindings: - From the Service Provider (SP) to the Identity Provider (IdP): - - `HTTP-POST` binding - `HTTP-Redirect` binding @@ -181,12 +180,10 @@ By default, new Grafana users using SAML authentication will have an account cre If you are also using SCIM provisioning for this Grafana application in Azure AD, it's crucial to align the user identifiers between SAML and SCIM for seamless operation. The unique identifier that links the SAML user to the SCIM provisioned user is determined by the `assertion_attribute_external_uid` setting in the Grafana SAML configuration. This `assertion_attribute_external_uid` should correspond to the `externalId` used in SCIM provisioning (typically set to the Azure AD `user.objectid`). 1. **Ensure Consistent Identifier in SAML Assertion:** - - The unique identifier from Azure AD (typically `user.objectid`) that you mapped to the `externalId` attribute in Grafana in your SCIM provisioning setup **must also be sent as a claim in the SAML assertion.** For more details on SCIM, refer to the [SCIM provisioning documentation](/docs/grafana//setup-grafana/configure-security/configure-scim-provisioning/). - In the Azure AD Enterprise Application, under **Single sign-on** > **Attributes & Claims**, ensure you add a claim that provides this identifier. For example, you might add a claim named `UserID` (or similar, like `externalId`) that sources its value from `user.objectid`. 2. **Configure Grafana SAML Settings for SCIM:** - - In the `[auth.saml]` section of your Grafana configuration, set `assertion_attribute_external_uid` to the name of the SAML claim you configured in the previous step (e.g., `userUID` or the full URI like `http://schemas.microsoft.com/identity/claims/objectidentifier` if that's how Azure AD sends it). - The `assertion_attribute_login` setting should still be configured to map to the attribute your users will log in with (e.g., `userPrincipalName`, `mail`). diff --git a/docs/sources/setup-grafana/configure-security/configure-authentication/saml/configure-saml-with-okta/_index.md b/docs/sources/setup-grafana/configure-security/configure-authentication/saml/configure-saml-with-okta/_index.md index 123a1298385..bb16de2b0ee 100644 --- a/docs/sources/setup-grafana/configure-security/configure-authentication/saml/configure-saml-with-okta/_index.md +++ b/docs/sources/setup-grafana/configure-security/configure-authentication/saml/configure-saml-with-okta/_index.md @@ -28,7 +28,6 @@ Grafana supports user authentication through Okta, which is useful when you want 1. Click **Create**. 1. On the **General Settings** tab, enter a name for your Grafana integration. You can also upload a logo. 1. On the **Configure SAML** tab, enter the SAML information related to your Grafana instance: - - In the **Single sign on URL** field, use the `/saml/acs` endpoint URL of your Grafana instance, for example, `https://grafana.example.com/saml/acs`. - In the **Audience URI (SP Entity ID)** field, use the `/saml/metadata` endpoint URL, by default it is the `/saml/metadata` endpoint of your Grafana instance (for example `https://example.grafana.com/saml/metadata`). This could be configured differently, but the value here must match the `entity_id` setting of the SAML settings of Grafana. - Leave the default values for **Name ID format** and **Application username**. diff --git a/docs/sources/setup-grafana/configure-security/configure-authentication/saml/saml-ui/_index.md b/docs/sources/setup-grafana/configure-security/configure-authentication/saml/saml-ui/_index.md index 7836a46df9f..52d2c84fbfd 100644 --- a/docs/sources/setup-grafana/configure-security/configure-authentication/saml/saml-ui/_index.md +++ b/docs/sources/setup-grafana/configure-security/configure-authentication/saml/saml-ui/_index.md @@ -64,7 +64,6 @@ Sign in to Grafana and navigate to **Administration > Authentication > Configure ### 2. Sign Requests Section 1. In the **Sign requests** field, specify whether you want the outgoing requests to be signed, and, if so, then: - 1. Provide a certificate and a private key that will be used by the service provider (Grafana) and the SAML IdP. Use the [PKCS #8](https://en.wikipedia.org/wiki/PKCS_8) format to issue the private key. diff --git a/docs/sources/setup-grafana/configure-security/configure-database-encryption/encrypt-secrets-using-aws-kms/index.md b/docs/sources/setup-grafana/configure-security/configure-database-encryption/encrypt-secrets-using-aws-kms/index.md index d081a085cb6..3b83e927616 100644 --- a/docs/sources/setup-grafana/configure-security/configure-database-encryption/encrypt-secrets-using-aws-kms/index.md +++ b/docs/sources/setup-grafana/configure-security/configure-database-encryption/encrypt-secrets-using-aws-kms/index.md @@ -33,7 +33,6 @@ You can use an encryption key from AWS Key Management Service to encrypt secrets

a. Add a new section to the configuration file, with a name in the format of `[security.encryption.awskms.]`, where `` is any name that uniquely identifies this key among other provider keys.

b. Fill in the section with the following values:
- - `key_id`: a reference to a key stored in the KMS. This can be a key ID, a key Amazon Resource Name (ARN), an alias name, or an alias ARN. If you are using an alias, use the prefix `alias/`. To specify a KMS key in a different AWS account, use its ARN or alias. For more information about how to retrieve a key ID from AWS, refer to [Finding the key ID and key ARN](https://docs.aws.amazon.com/kms/latest/developerguide/find-cmk-id-arn.html).
| `key_id` option | Example value | | --- | --- | diff --git a/docs/sources/setup-grafana/configure-security/configure-database-encryption/encrypt-secrets-using-azure-key-vault/index.md b/docs/sources/setup-grafana/configure-security/configure-database-encryption/encrypt-secrets-using-azure-key-vault/index.md index a13d6f7b41e..2b1a959c75b 100644 --- a/docs/sources/setup-grafana/configure-security/configure-database-encryption/encrypt-secrets-using-azure-key-vault/index.md +++ b/docs/sources/setup-grafana/configure-security/configure-database-encryption/encrypt-secrets-using-azure-key-vault/index.md @@ -35,7 +35,6 @@ You can use an encryption key from Azure Key Vault to encrypt secrets in the Gra

a. Add a new section to the configuration file, with a name in the format of `[security.encryption.azurekv.]`, where `` is any name that uniquely identifies this key among other provider keys.

b. Fill in the section with the following values:
- - `tenant_id`: the **Directory ID** (tenant) from the application that you registered. - `client_id`: the **Application ID** (client) from the application that you registered. - `client_secret`: the VALUE of the secret that you generated in your app. (Don't use the Secret ID). diff --git a/docs/sources/setup-grafana/configure-security/configure-database-encryption/encrypt-secrets-using-google-cloud-kms/index.md b/docs/sources/setup-grafana/configure-security/configure-database-encryption/encrypt-secrets-using-google-cloud-kms/index.md index 3d90697e310..4691ab90674 100644 --- a/docs/sources/setup-grafana/configure-security/configure-database-encryption/encrypt-secrets-using-google-cloud-kms/index.md +++ b/docs/sources/setup-grafana/configure-security/configure-database-encryption/encrypt-secrets-using-google-cloud-kms/index.md @@ -33,7 +33,6 @@ You can use an encryption key from Google Cloud Key Management Service to encryp

a. Add a new section to the configuration file, with a name in the format of `[security.encryption.azurekv.]`, where `` is any name that uniquely identifies this key among other provider keys.

b. Fill in the section with the following values:
- - `key_id`: encryption key ID, refer to [Getting the ID for a Key](https://cloud.google.com/kms/docs/getting-resource-ids#getting_the_id_for_a_key_and_version). - `credentials_file`: full path to service account key JSON file on your computer. diff --git a/docs/sources/setup-grafana/configure-security/configure-database-encryption/encrypt-secrets-using-hashicorp-key-vault/index.md b/docs/sources/setup-grafana/configure-security/configure-database-encryption/encrypt-secrets-using-hashicorp-key-vault/index.md index e15a46679b0..feee0cda4fb 100644 --- a/docs/sources/setup-grafana/configure-security/configure-database-encryption/encrypt-secrets-using-hashicorp-key-vault/index.md +++ b/docs/sources/setup-grafana/configure-security/configure-database-encryption/encrypt-secrets-using-hashicorp-key-vault/index.md @@ -31,7 +31,6 @@ You can use an encryption key from Hashicorp Vault to encrypt secrets in the Gra

a. Add a new section to the configuration file, with a name in the format of `[security.encryption.hashicorpvault.]`, where `` is any name that uniquely identifies this key among other provider keys.

b. Fill in the section with the following values:
- - `token`: a periodic service token used to authenticate within Hashicorp Vault. - `url`: URL of the Hashicorp Vault server. - `transit_engine_path`: mount point of the transit engine. diff --git a/docs/sources/setup-grafana/configure-security/configure-scim-provisioning/_index.md b/docs/sources/setup-grafana/configure-security/configure-scim-provisioning/_index.md index afc7cb26c40..2782bdab0fd 100644 --- a/docs/sources/setup-grafana/configure-security/configure-scim-provisioning/_index.md +++ b/docs/sources/setup-grafana/configure-security/configure-scim-provisioning/_index.md @@ -68,12 +68,10 @@ When you enable SCIM in Grafana, the following requirements and restrictions app 1. **Use the same identity provider for user provisioning and for authentication flow**: You must use the same identity provider for both authentication and user provisioning. 2. **Authentication restrictions**: - - Users attempting to log in through other methods (LDAP, OAuth) will be blocked - By default, users who are not provisioned through SCIM cannot access Grafana 3. **Security restriction**: When using SAML, the login authentication flow requires the SAML assertion exchange between the Identity Provider and Grafana to include the `userUID` SAML assertion with the user's unique identifier at the Identity Provider. - - Configure `userUID` SAML assertion in [Azure AD](/docs/grafana//setup-grafana/configure-security/configure-authentication/saml/configure-saml-with-azuread/#configure-saml-assertions-when-using-scim-provisioning) - Configure `userUID` SAML assertion in [Okta](/docs/grafana//setup-grafana/configure-security/configure-authentication/saml/configure-saml-with-okta/#configure-saml-assertions-when-using-scim-provisioning) diff --git a/docs/sources/setup-grafana/configure-security/configure-scim-provisioning/manage-users-teams/_index.md b/docs/sources/setup-grafana/configure-security/configure-scim-provisioning/manage-users-teams/_index.md index 5fb60103ad6..24f7cf1af0e 100644 --- a/docs/sources/setup-grafana/configure-security/configure-scim-provisioning/manage-users-teams/_index.md +++ b/docs/sources/setup-grafana/configure-security/configure-scim-provisioning/manage-users-teams/_index.md @@ -57,13 +57,11 @@ For detailed configuration steps specific to the identity provider, see: SCIM uses a specific process to establish and maintain user identity between the identity provider and Grafana: 1. **Initial user lookup:** - - The administrator configures SCIM at the Identity Provider, defining the **Unique identifier field** - The identity provider looks up each user in Grafana using this unique identifier field as a filter - The identity provider expects a single result from Grafana for each user 2. **Identity linking based on lookup results:** - - **If there's a single matching result:** The identity provider retrieves the user's unique ID at Grafana, saves it, confirms it can fetch the user's information, and updates the user's information in Grafana - **If there are no matching results:** The identity provider attempts to create the user in Grafana. If successful, it retrieves and saves the user's unique ID for future operations. If there's a conflict with an existing user, the identity provider flags the error and Grafana logs the error message - The identity provider learns the relationship between the found Grafana user and the Grafana internal ID @@ -97,12 +95,10 @@ For users who already exist in the Grafana instance: To prevent conflicts and maintain consistent user management, disable or restrict other provisioning methods when implementing SCIM. This ensures that all new users are created through SCIM and prevents duplicate or conflicting user records. - SAML Just-in-Time (JIT) provisioning: - - Disable `allow_sign_up` in SAML settings to prevent automatic user creation - Existing JIT-provisioned users will continue to work but should be migrated to SCIM - Terraform or API provisioning: - - Stop creating new users through these methods - Existing users will continue to work but should be migrated to SCIM - Consider removing or archiving Terraform user creation resources @@ -141,13 +137,11 @@ The migration process uses the same [user identification mechanism](#how-scim-id ### Migration steps 1. **Prepare the identity provider:** - - Ensure all existing Grafana users have corresponding accounts in your IDP - Verify that the unique identifier field (e.g., email, username, or object ID) matches between systems - Configure SCIM application in your IDP but don't assign users yet 2. **Configure SCIM in Grafana:** - - Set up SCIM endpoint and authentication as described in [Configure SCIM in Grafana](../../configure-scim-provisioning#configure-scim-in-grafana) - Enable `user_sync_enabled = true` - Configure the unique identifier field to match your IDP setup @@ -165,7 +159,6 @@ allow_non_provisioned_users = true {{< /admonition >}} 3. **Test the matching mechanism:** - - Use the SCIM API to verify that existing users can be found using the unique identifier: ```bash @@ -176,7 +169,6 @@ allow_non_provisioned_users = true - This should return exactly one user record for each existing user 4. **Assign users in the IDP:** - - Begin assigning existing users to the Grafana application in your IDP - The SCIM identification process will automatically link existing Grafana users with their IDP identities - Monitor the process for any conflicts or errors diff --git a/docs/sources/setup-grafana/configure-security/configure-team-sync.md b/docs/sources/setup-grafana/configure-security/configure-team-sync.md index f99de6a6189..268e907908f 100644 --- a/docs/sources/setup-grafana/configure-security/configure-team-sync.md +++ b/docs/sources/setup-grafana/configure-security/configure-team-sync.md @@ -51,7 +51,6 @@ If you have already grouped some users into a team, then you can synchronize tha 1. Insert the value of the group you want to sync with. This becomes the Grafana `GroupID`. Examples: - - For LDAP, this is the LDAP distinguished name (DN) of LDAP group you want to synchronize with the team. - For Auth Proxy, this is the value we receive as part of the custom `Groups` header. diff --git a/docs/sources/setup-grafana/installation/helm/index.md b/docs/sources/setup-grafana/installation/helm/index.md index 9551abe3a44..a77677b4f9b 100644 --- a/docs/sources/setup-grafana/installation/helm/index.md +++ b/docs/sources/setup-grafana/installation/helm/index.md @@ -109,7 +109,6 @@ When you create a new namespace in Kubernetes, you can better organize, allocate ``` Where: - - `helm install`: Installs the chart by deploying it on the Kubernetes cluster - `my-grafana`: The logical chart name that you provided - `grafana/grafana`: The repository and package name to install @@ -147,7 +146,6 @@ This section describes the steps you must complete to access Grafana via web bro ``` This command will print out the chart notes. You will the output `NOTES` that provide the complete instructions about: - - How to decode the login password for the Grafana admin account - Access Grafana service to the web browser diff --git a/docs/sources/setup-grafana/installation/kubernetes/index.md b/docs/sources/setup-grafana/installation/kubernetes/index.md index 7a9cf7fb9a7..0085a670896 100644 --- a/docs/sources/setup-grafana/installation/kubernetes/index.md +++ b/docs/sources/setup-grafana/installation/kubernetes/index.md @@ -391,9 +391,7 @@ Instead of using the `annotate` flag, you can still use the `--record` flag. How 1. In the editor, change the container image under the `kind: Deployment` section. For example: - - From - - `yaml image: grafana/grafana-oss:10.0.1` - To @@ -573,7 +571,6 @@ This section outlines general instructions for provisioning Grafana resources wi ``` You can follow the same process to provision additional Grafana resources by supplying the following folders: - - `provisioning/dashboards` - `provisioning/datasources` - `provisioning/plugins` diff --git a/docs/sources/setup-grafana/installation/mac/index.md b/docs/sources/setup-grafana/installation/mac/index.md index f4c3f5d7342..16a064ab063 100644 --- a/docs/sources/setup-grafana/installation/mac/index.md +++ b/docs/sources/setup-grafana/installation/mac/index.md @@ -35,7 +35,6 @@ To install Grafana on macOS using Homebrew, complete the following steps: ``` The brew page downloads and untars the files into: - - `/usr/local/Cellar/grafana/[version]` (Intel Silicon) - `/opt/homebrew/Cellar/grafana/[version]` (Apple Silicon) diff --git a/docs/sources/setup-grafana/set-up-https.md b/docs/sources/setup-grafana/set-up-https.md index b9823b47f2a..00c8838be94 100644 --- a/docs/sources/setup-grafana/set-up-https.md +++ b/docs/sources/setup-grafana/set-up-https.md @@ -131,7 +131,6 @@ The instructions provided in this section are for a Debian-based Linux system. F ``` These commands: - - Uninstall `certbot` from your system if it has been installed using a package manager - Install `certbot` using `snapd` diff --git a/docs/sources/shared/datasources/datasouce-authentication.md b/docs/sources/shared/datasources/datasouce-authentication.md index 4582eb48593..cb51a39774a 100644 --- a/docs/sources/shared/datasources/datasouce-authentication.md +++ b/docs/sources/shared/datasources/datasouce-authentication.md @@ -18,7 +18,6 @@ labels: To set up authentication: 1. Select an authentication method from the drop-down list: - - **Basic authentication**: Authenticates your data source using a username and password - **Forward OAuth identity**: Forwards the OAuth access token and the OIDC ID token, if available, of the user querying to the data source - **No authentication**: No authentication is required to access the data source diff --git a/docs/sources/shared/upgrade/upgrade-common-tasks.md b/docs/sources/shared/upgrade/upgrade-common-tasks.md index e6a252d43e4..0667dca09e6 100644 --- a/docs/sources/shared/upgrade/upgrade-common-tasks.md +++ b/docs/sources/shared/upgrade/upgrade-common-tasks.md @@ -66,7 +66,6 @@ To upgrade Grafana installed using RPM or YUM complete the following steps: This enables you to upgrade Grafana without the risk of losing your configuration changes. 1. Perform one of the following steps based on your installation. - - If you [downloaded an RPM package](https://grafana.com/grafana/download) to install Grafana, then complete the steps documented in [Install Grafana on Red Hat, RHEL, or Fedora](https://grafana.com/docs/grafana//setup-grafana/installation/redhat-rhel-fedora/) or [Install Grafana on SUSE or openSUSE](https://grafana.com/docs/grafana///setup-grafana/installation/suse-opensuse/) to upgrade Grafana. - If you used the Grafana YUM repository, run the following command: diff --git a/docs/sources/tutorials/alerting-get-started-pt2/index.md b/docs/sources/tutorials/alerting-get-started-pt2/index.md index f08cd09f901..ff2b8ab2487 100644 --- a/docs/sources/tutorials/alerting-get-started-pt2/index.md +++ b/docs/sources/tutorials/alerting-get-started-pt2/index.md @@ -51,17 +51,14 @@ Learning about alert instances and notification policies is useful if you have m There are different ways you can follow along with this tutorial. - **Grafana Cloud** - - As a Grafana Cloud user, you don't have to install anything. [Create your free account](http://www.grafana.com/auth/sign-up/create-user). Continue to [Alert instances](#alert-instances). - **Interactive learning environment** - - Alternatively, you can try out this example in our interactive learning environment: [Get started with Grafana Alerting - Alert routing](https://killercoda.com/grafana-labs/course/grafana/alerting-get-started-pt2/). It's a fully configured environment with all the dependencies already installed. - **Grafana OSS** - - If you opt to run a Grafana stack locally, ensure you have the following applications installed: - [Docker Compose](https://docs.docker.com/get-docker/) (included in Docker for Desktop for macOS and Windows) @@ -252,7 +249,6 @@ Grafana includes a [test data source](https://grafana.com/docs/grafana/latest/da The above CSV data simulates a data source returning multiple time series, each leading to the creation of an alert instance for that specific time series. Note that the data returned matches the example in the [Alert instance](#alert-instances) section. 1. In the **Alert condition** section: - - Keep `Last` as the value for the reducer function (`WHEN`), and `IS ABOVE 1000` as the threshold value. This is the value above which the alert rule should trigger. 1. Click **Preview alert rule condition** to run the queries. diff --git a/docs/sources/tutorials/alerting-get-started-pt3/index.md b/docs/sources/tutorials/alerting-get-started-pt3/index.md index fa7aa1c55d7..caed6c606f0 100644 --- a/docs/sources/tutorials/alerting-get-started-pt3/index.md +++ b/docs/sources/tutorials/alerting-get-started-pt3/index.md @@ -68,17 +68,14 @@ In this tutorial, you will: There are different ways you can follow along with this tutorial. - **Grafana Cloud** - - As a Grafana Cloud user, you don't have to install anything. [Create your free account](http://www.grafana.com/auth/sign-up/create-user). Continue to [How alert rule grouping works](#how-alert-rule-grouping-works). - **Interactive learning environment** - - Alternatively, you can try out this example in our interactive learning environment: [Get started with Grafana Alerting - Grouping](https://killercoda.com/grafana-labs/course/grafana/alerting-get-started-pt3/). It's a fully configured environment with all the dependencies already installed. - **Grafana OSS** - - If you opt to run a Grafana stack locally, ensure you have the following applications installed: - [Docker Compose](https://docs.docker.com/get-docker/) (included in Docker for Desktop for macOS and Windows) @@ -227,16 +224,13 @@ Following the above example, [notification policies](ref:notification-policies) 1. Sign in to Grafana: - - **Grafana Cloud** users: Log in via Grafana Cloud. - **OSS users**: Go to [http://localhost:3000](http://localhost:3000). 1. Navigate to **Notification Policies**: - - Go to **Alerts & IRM > Alerting > Notification Policies**. 1. Add a child policy: - - In the Default policy, click **+ New child policy**. - **Label**: `region` - **Operator**: `=` @@ -245,31 +239,26 @@ Following the above example, [notification policies](ref:notification-policies) This label matches alert rules where the region label is us-west. 1. Choose a **Contact point**: - - Select **Webhook**. If you don’t have any contact points, add a [Contact point](https://grafana.com/docs/grafana/latest/alerting/configure-notifications/manage-contact-points/#add-a-contact-point). 1. Enable Continue matching: - - Turn on **Continue matching subsequent sibling nodes** so the evaluation continues even after one or more labels (i.e. region label) match. 1. Override grouping settings: - - Toggle **Override grouping**. - **Group by**: Add `region` as label. Remove any existing labels. **Group by** consolidates alerts that share the same grouping label into a single notification. For example, all alerts with `region=us-west` will be combined into one notification, making it easier to manage and reducing alert fatigue. 1. Set custom timing: - - Toggle **Override general timings**. - **Group interval**: `2m`. This ensures follow-up notifications for the same alert group will be sent at intervals of 2 minutes. While the default is 5 minutes, we chose 2 minutes here to provide faster feedback for demonstration purposes. **Timing options** control how often notifications are sent and can help balance timely alerting with minimizing noise. 1. Save and repeat: - - Repeat the steps above for `region = us-east` but without overriding grouping and timing options. Use a different webhook endpoint as the contact point. {{< figure src="/media/docs/alerting/notificaiton-policies-region.png" max-width="750px" alt="Two nested notification policies to route and group alert notifications" >}} @@ -290,7 +279,6 @@ Following the above example, [notification policies](ref:notification-policies) 1. Visit [http://localhost:3000](http://localhost:3000), where Grafana should be running 1. Navigate to **Alerts & IRM > Alerting > Notification policies**. 1. In the Default policy, click **+ New child policy**. - - In the Default policy, click **+ New child policy**. - **Label**: `region` - **Operator**: `=` @@ -299,31 +287,26 @@ Following the above example, [notification policies](ref:notification-policies) This label matches alert rules where the region label is us-west 1. Choose a **Contact point**: - - Select **Webhook**. If you don’t have any contact points, add a Contact point. 1. Enable Continue matching: - - Turn on **Continue matching subsequent sibling nodes** so the evaluation continues even after one or more labels (i.e. region label) match. 1. Override grouping settings: - - Toggle **Override grouping**. - **Group by**: `region`. **Group by** consolidates alerts that share the same grouping label into a single notification. For example, all alerts with `region=us-west` will be combined into one notification, making it easier to manage and reducing alert fatigue. 1. Set custom timing: - - Toggle **Override general timings**. - **Group interval**: `2m`. This ensures follow-up notifications for the same alert group will be sent at intervals of 2 minutes. While the default is 5 minutes, we chose 2 minutes here to provide faster feedback for demonstration purposes. **Timing options** control how often notifications are sent and can help balance timely alerting with minimizing noise. 1. Save and repeat: - - Repeat for `region = us-east` with a different webhook or a different contact point. **Note**: Label matchers are combined using the `AND` logical operator. This means that all matchers must be satisfied for a rule to be linked to a policy. If you attempt to use the same label key (e.g., region) with different values (e.g., us-west and us-east), the condition will not match, because it is logically impossible for a single key to have multiple values simultaneously. @@ -355,7 +338,6 @@ Grafana includes a [test data source](https://grafana.com/docs/grafana/latest/da 1. From the drop-down menu, select **TestData** data source. 1. From **Scenario** select **CSV Content**. 1. Copy in the following CSV data: - - Select **TestData** as the data source. - Set **Scenario** to **CSV Content**. - Use the following CSV data: @@ -375,7 +357,6 @@ Grafana includes a [test data source](https://grafana.com/docs/grafana/latest/da The returned data simulates a data source returning multiple time series, each leading to the creation of an alert instance for that specific time series. 1. In the **Alert condition** section: - - Keep `Last` as the value for the reducer function (`WHEN`), and `IS ABOVE 75` as the threshold value. This is the value above which the alert rule should trigger. 1. Click **Preview alert rule condition** to run the queries. diff --git a/docs/sources/tutorials/alerting-get-started-pt4/index.md b/docs/sources/tutorials/alerting-get-started-pt4/index.md index ce34258da51..5fe4d1afbff 100644 --- a/docs/sources/tutorials/alerting-get-started-pt4/index.md +++ b/docs/sources/tutorials/alerting-get-started-pt4/index.md @@ -100,17 +100,14 @@ There are different ways you can follow along with this tutorial. > Note: Some of the templating features in Grafana Alerting discussed in this tutorial are currently available in Grafana Cloud but have not yet been released to the Open Source (OSS) version. - **Grafana Cloud** - - As a Grafana Cloud user, you don't have to install anything. [Create your free account](http://www.grafana.com/auth/sign-up/create-user). Continue to [how templating works](#how-templating-works). - **Interactive learning environment** - - Alternatively, you can try out this example in our interactive learning environment: [Get started with Grafana Alerting - Templating](https://killercoda.com/grafana-labs/course/grafana/alerting-get-started-pt4/). It's a fully configured environment with all the dependencies already installed. - **Grafana OSS** - - If you opt to run a Grafana stack locally, ensure you have the following applications installed: - [Docker Compose](https://docs.docker.com/get-docker/) (included in Docker for Desktop for macOS and Windows) @@ -215,7 +212,6 @@ Now that we've introduced how templating works, let’s move on to the next step ### Create an alert rule 1. Sign in to Grafana: - - **Grafana Cloud** users: Log in via Grafana Cloud. - **OSS users**: Go to [http://localhost:3000](http://localhost:3000). @@ -224,7 +220,6 @@ Now that we've introduced how templating works, let’s move on to the next step - Click **+ New alert rule**. - Enter an **alert rule name**. Name it `High CPU usage` 1. **Define query an alert condition** section: - - Select TestData data source from the drop-down menu. [TestData](https://grafana.com/docs/grafana/latest/datasources/testdata/) is included in the demo environment. If you’re working in Grafana Cloud or your own local Grafana instance, you can add the data source through the Connections menu. @@ -243,7 +238,6 @@ Now that we've introduced how templating works, let’s move on to the next step This dataset simulates a data source returning multiple time series, with each time series generating a separate alert instance. 1. **Alert condition** section: - - Keep Last as the value for the reducer function (`WHEN`), and `IS ABOVE 75` as the threshold value, representing CPU usage above 75% .This is the value above which the alert rule should trigger. - Click **Preview alert rule condition** to run the queries. @@ -252,7 +246,6 @@ Now that we've introduced how templating works, let’s move on to the next step {{< figure src="/media/docs/alerting/part-4-firing-instances-preview.png" max-width="1200px" caption="Preview of a query returning alert instances" >}} 1. Add folders and labels section: - - In **Folder**, click **+ New folder** and enter a name. For example: `System metrics` . This folder contains our alert rules. Note: while it's possible to template labels here, in this tutorial, we focus on templating the summary and annotations fields instead. @@ -265,13 +258,11 @@ Now that we've introduced how templating works, let’s move on to the next step 1. **Configure notifications** section: Select who should receive a notification when an alert rule fires. - - Select a **Contact point**. If you don’t have any contact points, click _View or create contact points_. 1. **Configure notification message** section: In this step, you’ll configure the **summary** and **description** annotations to make your alert notifications informative and easy to understand. These annotations use templates to dynamically include key information about the alert. - - **Summary** annotation: Enter the following code as the value for the annotation.: ```go @@ -412,7 +403,6 @@ In this tutorial, we learned how to use templating in Grafana Alerting to create To deepen your understanding of Grafana’s templating, explore the following resources: - **Overview of the functions and operators used in templates**: - - [Notification template language](https://grafana.com/docs/grafana/latest/alerting/configure-notifications/template-notifications/language/) - [Alert rule template language](https://grafana.com/docs/grafana/latest/alerting/alerting-rules/templates/language/) diff --git a/docs/sources/tutorials/alerting-get-started-pt5/index.md b/docs/sources/tutorials/alerting-get-started-pt5/index.md index 91a1c1e4141..fe89a2a3b18 100644 --- a/docs/sources/tutorials/alerting-get-started-pt5/index.md +++ b/docs/sources/tutorials/alerting-get-started-pt5/index.md @@ -37,7 +37,6 @@ In this tutorial you will learn how to: ## Before you begin - **Interactive learning environment** - - Alternatively, you can [try out this example in our interactive learning environment](https://killercoda.com/grafana-labs/course/grafana/alerting-get-started-pt5/). It’s a fully configured environment with all the dependencies already installed. - **Grafana OSS** @@ -174,14 +173,12 @@ Notification policies route alert instances to contact points via label matchers Although our application doesn't explicitly include an `environment` label, we can rely on other labels like `instance` or `deployment`, which may contain keywords (like prod or staging) that indicate the environment. 1. Sign in to Grafana: - - **Grafana Cloud** users: Log in via Grafana Cloud. - **OSS users**: Go to [http://localhost:3000](http://localhost:3000). 1. Navigate to **Alerts & IRM > Alerting > Notification Policies**. 1. Add a child policy: - - In the **Default policy**, click **+ New child policy**. - **Label**: `environment`. - **Operator**: `=`. @@ -189,17 +186,14 @@ Although our application doesn't explicitly include an `environment` label, we c - This label matches alert rules where the environment label is `prod`. 1. Choose a **contact point**: - - If you don’t have any contact points, add a [Contact point](https://grafana.com/docs/grafana/latest/alerting/configure-notifications/manage-contact-points/#add-a-contact-point). For a quick test, you can use a public webhook from [webhook.site](https://webhook.site/) to capture and inspect alert notifications. If you choose this method, select **Webhook** from the drop-down menu in contact points. 1. Enable continue matching: - - Turn on **Continue matching subsequent sibling nodes** so the evaluation continues even after one or more labels (i.e., _environment_ labels) match. 1. Save and repeat - - Create another child policy by following the same steps. - Use `environment = staging` as the label/value pair. - Feel free to use a different contact point. @@ -234,7 +228,6 @@ Make it short and descriptive, as this will appear in your alert notification. F ``` 1. **Alert condition** section: - - Enter `75` as the value for **WHEN QUERY IS ABOVE** to set the threshold for the alert. - Click **Preview alert rule condition** to run the queries. diff --git a/docs/sources/tutorials/alerting-get-started-pt6/index.md b/docs/sources/tutorials/alerting-get-started-pt6/index.md index 8f4b3eeff83..470330237e2 100644 --- a/docs/sources/tutorials/alerting-get-started-pt6/index.md +++ b/docs/sources/tutorials/alerting-get-started-pt6/index.md @@ -39,7 +39,6 @@ In this tutorial you will learn how to: ## Before you begin - **Interactive learning environment** - - Alternatively, you can [try out this example in our interactive learning environment](https://killercoda.com/grafana-labs/course/grafana/alerting-get-started-pt6/). It’s a fully configured environment with all the dependencies already installed. - **Grafana OSS** @@ -150,12 +149,10 @@ To keep track of these metrics you can set up a visualization for CPU usage and The time-series visualization supports alert rules to provide more context in the form of annotations and alert rule state. Follow these steps to create a visualization to monitor the application’s metrics. 1. Log in to Grafana: - - Navigate to [http://localhost:3000](http://localhost:3000), where Grafana should be running. - Username and password: `admin` 1. Create a time series panel: - - Navigate to **Dashboards**. - Click **+ Create dashboard**. - Click **+ Add visualization**. @@ -163,7 +160,6 @@ The time-series visualization supports alert rules to provide more context in th - Enter a title for your panel, e.g., **CPU and Memory Usage**. 1. Add queries for metrics: - - In the query area, copy and paste the following PromQL query: ** switch to **Code** mode if not already selected ** @@ -177,7 +173,6 @@ The time-series visualization supports alert rules to provide more context in th This query should display the simulated CPU usage data for the **prod** environment. 1. Add memory usage query: - - Click **+ Add query**. - In the query area, paste the following PromQL query: @@ -219,7 +214,6 @@ Make it short and descriptive, as this will appear in your alert notification. F ``` 1. **Alert condition** - - Enter 75 as the value for **WHEN QUERY IS ABOVE** to set the threshold for the alert. - Click **Preview alert rule condition** to run the queries. diff --git a/docs/sources/tutorials/alerting-get-started/index.md b/docs/sources/tutorials/alerting-get-started/index.md index 542190188f1..69107963b35 100644 --- a/docs/sources/tutorials/alerting-get-started/index.md +++ b/docs/sources/tutorials/alerting-get-started/index.md @@ -57,17 +57,14 @@ After you have completed Part 1, don’t forget to explore the advanced but esse There are different ways you can follow along with this tutorial. - **Grafana Cloud** - - As a Grafana Cloud user, you don't have to install anything. [Create your free account](http://www.grafana.com/auth/sign-up/create-user). Continue to [Create a contact point](#create-a-contact-point). - **Interactive learning environment** - - Alternatively, you can [try out this example in our interactive learning environment](https://killercoda.com/grafana-labs/course/grafana/alerting-get-started/). It's a fully configured environment with all the dependencies already installed. - **Grafana OSS** - - If you opt to run a Grafana stack locally, ensure you have the following applications installed: - [Docker Compose](https://docs.docker.com/get-docker/) (included in Docker for Desktop for macOS and Windows) @@ -194,7 +191,6 @@ Grafana includes a [test data source](https://grafana.com/docs/grafana/latest/da 1. Select the **TestData** data source from the drop-down menu. 1. In the **Alert condition** section: - - Keep **Random Walk** as the _Scenario_. - Keep `Last` as the value for the reducer function (`WHEN`), and `IS ABOVE 0` as the threshold value. This is the value above which the alert rule should trigger. diff --git a/docs/sources/tutorials/create-alerts-with-logs/index.md b/docs/sources/tutorials/create-alerts-with-logs/index.md index 873a2e7094f..aa5ee2eaade 100644 --- a/docs/sources/tutorials/create-alerts-with-logs/index.md +++ b/docs/sources/tutorials/create-alerts-with-logs/index.md @@ -65,12 +65,10 @@ There are different ways you can follow along with this tutorial. - **Grafana OSS** To run a Grafana stack locally, ensure you have the following applications installed: - - [Docker Compose](https://docs.docker.com/get-docker/) (included in Docker for Desktop for macOS and Windows) - [Git](https://git-scm.com/) - **Interactive learning environment** - - Alternatively, you can [try out this example in our interactive learning environment](https://killercoda.com/grafana-labs/course/grafana/alerting-loki-logs). It's a fully configured environment with all the dependencies already installed. ## Set up the Grafana stack @@ -227,7 +225,6 @@ In this section, we use the default options for Grafana-managed alert rule creat {{< /docs/ignore >}} 1. In the **Alert condition** section: - - Keep `Last` as the value for the reducer function (`WHEN`), and `0` as the threshold value. This is the value above which the alert rule should trigger. 1. Click **Preview alert rule condition** to run the query. diff --git a/docs/sources/tutorials/grafana-fundamentals/index.md b/docs/sources/tutorials/grafana-fundamentals/index.md index 20f9616fea8..0b8ef024707 100644 --- a/docs/sources/tutorials/grafana-fundamentals/index.md +++ b/docs/sources/tutorials/grafana-fundamentals/index.md @@ -375,7 +375,6 @@ The most basic alert rule consists of two parts: > {{< /docs/ignore >}} Some popular channels include: - - [Email](https://grafana.com/docs/grafana/latest/alerting/configure-notifications/manage-contact-points/integrations/configure-email/) - [Webhooks](https://grafana.com/docs/grafana/latest/alerting/configure-notifications/manage-contact-points/integrations/webhook-notifier/) - [Telegram](https://grafana.com/docs/grafana/latest/alerting/configure-notifications/manage-contact-points/integrations/configure-telegram/) diff --git a/docs/sources/upgrade-guide/when-to-upgrade/index.md b/docs/sources/upgrade-guide/when-to-upgrade/index.md index f759b26cbb8..b92f019c0b4 100644 --- a/docs/sources/upgrade-guide/when-to-upgrade/index.md +++ b/docs/sources/upgrade-guide/when-to-upgrade/index.md @@ -124,14 +124,12 @@ Here is an overview of version support through 2026: The level of support changes as new versions of Grafana are released. Here are the key details: - **Full Support**: - - All new features - All bug fixes - Security patches - Regular updates - **Security & Critical Bugs Only**: - - Security vulnerability patches - Critical bug fixes that cause feature degradation - No new features diff --git a/docs/sources/whatsnew/whats-new-in-v11-3.md b/docs/sources/whatsnew/whats-new-in-v11-3.md index aafe83f2695..5eb55341a04 100644 --- a/docs/sources/whatsnew/whats-new-in-v11-3.md +++ b/docs/sources/whatsnew/whats-new-in-v11-3.md @@ -62,7 +62,6 @@ For configuring controls outside of playlist playback, you can use the following - The [variable usage check](https://grafana.com/docs/grafana//dashboards/variables/inspect-variable/) is not yet available. - Editing a panel: - - The **Library panels** tab is not available anymore. You can replace a library panel from the panel menu. - The **Overrides** tab is not in panel options (coming in Grafana v11.3.0). Overrides are shown at the bottom of the option list. - The drop-down menu to collapse the visualization picker is missing (coming in Grafana v11.3.0). diff --git a/package.json b/package.json index 91440a05642..8f66957123b 100644 --- a/package.json +++ b/package.json @@ -233,7 +233,7 @@ "postcss-loader": "8.1.1", "postcss-reporter": "7.1.0", "postcss-scss": "4.0.9", - "prettier": "3.4.2", + "prettier": "3.6.2", "publint": "^0.3.12", "react-refresh": "0.14.0", "react-select-event": "5.5.1", @@ -463,7 +463,7 @@ }, "packageManager": "yarn@4.9.2", "dependenciesMeta": { - "prettier@3.4.2": { + "prettier@3.6.2": { "unplugged": true } }, diff --git a/packages/README.md b/packages/README.md index b3797e69514..525d77097fb 100644 --- a/packages/README.md +++ b/packages/README.md @@ -53,7 +53,6 @@ Every commit to main that has changes within the `packages` directory is a subje 3. Run `yarn packages:build` script that compiles distribution code in `packages/grafana-*/dist`. 4. Run `yarn packages:pack` script to compress each package into `npm-artifacts/*.tgz` files. This is required for yarn to replace properties in the package.json files declared in the `publishConfig` property. 5. Depending on whether or not it's a prerelease: - - When releasing a prerelease run `./scripts/publish-npm-packages.sh --dist-tag 'next' --registry 'https://registry.npmjs.org/'` to publish new versions. - When releasing a stable version run `./scripts/publish-npm-packages.sh --dist-tag 'latest' --registry 'https://registry.npmjs.org/'` to publish new versions. - When releasing a test version run `./scripts/publish-npm-packages.sh --dist-tag 'test' --registry 'https://registry.npmjs.org/'` to publish test versions. diff --git a/packages/grafana-runtime/src/services/pluginExtensions/utils.test.tsx b/packages/grafana-runtime/src/services/pluginExtensions/utils.test.tsx index e235aace668..14f1a9082be 100644 --- a/packages/grafana-runtime/src/services/pluginExtensions/utils.test.tsx +++ b/packages/grafana-runtime/src/services/pluginExtensions/utils.test.tsx @@ -92,7 +92,11 @@ describe('Plugin Extensions / Utils', () => { // Check if the right components are selected const limitedComponents = getLimitedComponentsToRender({ props, components, limit: 3 }); const rendered = render( - <>{limitedComponents?.map((Component, index) => )} + <> + {limitedComponents?.map((Component, index) => ( + + ))} + ); expect(rendered.getByText('Test 1')).toBeInTheDocument(); @@ -127,7 +131,11 @@ describe('Plugin Extensions / Utils', () => { // Check if the right components are selected const limitedComponents = getLimitedComponentsToRender({ props, components, limit: 1 }); const rendered = render( - <>{limitedComponents?.map((Component, index) => )} + <> + {limitedComponents?.map((Component, index) => ( + + ))} + ); expect(rendered.getByText('Test 1')).toBeInTheDocument(); @@ -158,7 +166,11 @@ describe('Plugin Extensions / Utils', () => { pluginId: ['plugin-id-2', 'plugin-id-3'], }); const rendered = render( - <>{limitedComponents?.map((Component, index) => )} + <> + {limitedComponents?.map((Component, index) => ( + + ))} + ); expect(rendered.getByText('Test 2')).toBeInTheDocument(); diff --git a/packages/grafana-ui/src/components/ScrollContainer/ScrollContainer.mdx b/packages/grafana-ui/src/components/ScrollContainer/ScrollContainer.mdx index a9b0213ea5e..67ced9d65fe 100644 --- a/packages/grafana-ui/src/components/ScrollContainer/ScrollContainer.mdx +++ b/packages/grafana-ui/src/components/ScrollContainer/ScrollContainer.mdx @@ -30,7 +30,6 @@ If you were using additional props, there are roughly 3 categories of changes: - `hideHorizontalTrack` and `hideVerticalTrack` have been removed. - You can achieve the same behavior by setting either `overflowX` or `overflowY` to `hidden`. These names more closely match the CSS properties they represent. - `scrollTop` and `setScrollTop`. - - You can achieve the same behavior by using the `ref` prop to get a reference to the `ScrollContainer` component, and then calling `scrollTo` on that reference. - Before: diff --git a/public/app/core/components/RolePicker/RolePickerInput.tsx b/public/app/core/components/RolePicker/RolePickerInput.tsx index 9aaa4b447f5..3f8158020c3 100644 --- a/public/app/core/components/RolePicker/RolePickerInput.tsx +++ b/public/app/core/components/RolePicker/RolePickerInput.tsx @@ -116,7 +116,9 @@ export const RolesLabel = ({ showBuiltInRole, numberOfRoles, appliedRoles }: Rol - {appliedRoles?.map((role) =>

{role.group + ':' + (role.displayName || role.name)}

)} + {appliedRoles?.map((role) => ( +

{role.group + ':' + (role.displayName || role.name)}

+ ))} } > diff --git a/public/app/features/admin/Users/OrgUnits.tsx b/public/app/features/admin/Users/OrgUnits.tsx index b029df9e19e..f91c54f79d8 100644 --- a/public/app/features/admin/Users/OrgUnits.tsx +++ b/public/app/features/admin/Users/OrgUnits.tsx @@ -14,7 +14,13 @@ export const OrgUnits = ({ units, icon }: OrgUnitProps) => { return units.length > 1 ? ( {units?.map((unit) => {unit.name})}} + content={ + + {units?.map((unit) => ( + {unit.name} + ))} + + } > {units.length} diff --git a/public/app/features/auth-config/ErrorContainer.tsx b/public/app/features/auth-config/ErrorContainer.tsx index 336dde9716a..1a51263a364 100644 --- a/public/app/features/auth-config/ErrorContainer.tsx +++ b/public/app/features/auth-config/ErrorContainer.tsx @@ -25,12 +25,16 @@ export const ErrorContainerUnconnected = ({ error, warning, resetError, resetWar
{error && ( resetError()}> - {error.errors?.map((e, i) =>
{e}
)} + {error.errors?.map((e, i) => ( +
{e}
+ ))}
)} {warning && ( resetWarning()} severity="warning"> - {warning.errors?.map((e, i) =>
{e}
)} + {warning.errors?.map((e, i) => ( +
{e}
+ ))}
)}
diff --git a/public/app/features/dashboard-scene/scene/layout-rows/RowItemRepeater.tsx b/public/app/features/dashboard-scene/scene/layout-rows/RowItemRepeater.tsx index a8e473e7a6b..9d1a602fce4 100644 --- a/public/app/features/dashboard-scene/scene/layout-rows/RowItemRepeater.tsx +++ b/public/app/features/dashboard-scene/scene/layout-rows/RowItemRepeater.tsx @@ -61,7 +61,9 @@ export function RowItemRepeater({ return ( <> - {repeatedRows?.map((rowClone) => )} + {repeatedRows?.map((rowClone) => ( + + ))} ); } diff --git a/public/app/features/dashboard/components/TransformationsEditor/TransformationPicker.tsx b/public/app/features/dashboard/components/TransformationsEditor/TransformationPicker.tsx index a05b51053eb..23a94ffe8cb 100644 --- a/public/app/features/dashboard/components/TransformationsEditor/TransformationPicker.tsx +++ b/public/app/features/dashboard/components/TransformationsEditor/TransformationPicker.tsx @@ -54,7 +54,8 @@ export function TransformationPicker(props: TransformationPickerProps) {
- It can help to switch to the Table visualization to understand what a transformation is doing.{' '} + It can help to switch to the Table visualization to understand what a transformation is + doing.{' '}

{Boolean(activeTab) && ( - {activeTab?.components.map((Component, index) => )} + {activeTab?.components.map((Component, index) => ( + + ))} )} diff --git a/public/app/plugins/panel/timeseries/plugins/annotations2/AnnotationTooltip2.tsx b/public/app/plugins/panel/timeseries/plugins/annotations2/AnnotationTooltip2.tsx index 89e5c8f7c08..33d6eb0e013 100644 --- a/public/app/plugins/panel/timeseries/plugins/annotations2/AnnotationTooltip2.tsx +++ b/public/app/plugins/panel/timeseries/plugins/annotations2/AnnotationTooltip2.tsx @@ -101,7 +101,9 @@ export const AnnotationTooltip2 = ({ annoVals, annoIdx, timeZone, onEdit }: Prop {alertText}
- {annoVals.tags?.[annoIdx]?.map((t: string, i: number) => )} + {annoVals.tags?.[annoIdx]?.map((t: string, i: number) => ( + + ))}
diff --git a/yarn.lock b/yarn.lock index d256bcfcd6e..8aae2c14159 100644 --- a/yarn.lock +++ b/yarn.lock @@ -18405,7 +18405,7 @@ __metadata: postcss-loader: "npm:8.1.1" postcss-reporter: "npm:7.1.0" postcss-scss: "npm:4.0.9" - prettier: "npm:3.4.2" + prettier: "npm:3.6.2" prismjs: "npm:1.30.0" publint: "npm:^0.3.12" rc-slider: "npm:11.1.8" @@ -18490,7 +18490,7 @@ __metadata: yargs: "npm:^17.5.1" zod: "npm:^3.25.55" dependenciesMeta: - prettier@3.4.2: + prettier@3.6.2: unplugged: true languageName: unknown linkType: soft @@ -25844,12 +25844,12 @@ __metadata: languageName: node linkType: hard -"prettier@npm:3.4.2, prettier@npm:^3.1.1, prettier@npm:^3.2.5": - version: 3.4.2 - resolution: "prettier@npm:3.4.2" +"prettier@npm:3.6.2, prettier@npm:^3.1.1, prettier@npm:^3.2.5": + version: 3.6.2 + resolution: "prettier@npm:3.6.2" bin: prettier: bin/prettier.cjs - checksum: 10/a3e806fb0b635818964d472d35d27e21a4e17150c679047f5501e1f23bd4aa806adf660f0c0d35214a210d5d440da6896c2e86156da55f221a57938278dc326e + checksum: 10/1213691706bcef1371d16ef72773c8111106c3533b660b1cc8ec158bd109cdf1462804125f87f981f23c4a3dba053b6efafda30ab0114cc5b4a725606bb9ff26 languageName: node linkType: hard From 87464efb16fdb8edf265492cf352ccdce2b86a54 Mon Sep 17 00:00:00 2001 From: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> Date: Fri, 25 Jul 2025 14:48:10 -0400 Subject: [PATCH 015/131] Docs: Refactor Variables page and improve content (#108346) --- docs/sources/dashboards/variables/_index.md | 122 +++++++++++------- .../variables/add-template-variables/index.md | 8 ++ .../influxdb/template-variables/index.md | 4 +- 3 files changed, 83 insertions(+), 51 deletions(-) diff --git a/docs/sources/dashboards/variables/_index.md b/docs/sources/dashboards/variables/_index.md index 6ec5d4916ed..da7451271d2 100644 --- a/docs/sources/dashboards/variables/_index.md +++ b/docs/sources/dashboards/variables/_index.md @@ -15,57 +15,81 @@ weight: 800 # Variables +A variable is a placeholder for a value. +When you change the value, the element using the variable will change to reflect the new value. + +Variables are displayed as drop-down lists (or in some cases text fields) at the top of the dashboard. +These drop-down lists make it easy to update the variable value and thus change the data being displayed in your dashboard. + +For example, if you needed to monitor several servers, you _could_ make a dashboard for each server. +Or you could create one dashboard and use panels with variables like this one, where you can change the server using the variable selector: + +{{< figure src="/media/docs/grafana/dashboards/screenshot-selected-variables-v12.png" max-width="750px" alt="Variable drop-down open and two values selected" >}} + +Variables allow you to create more interactive dashboards. +Instead of hard-coding things like server, application, and sensor names in your metric queries, you can use variables in their place. +They're useful for administrators who want to allow Grafana viewers to adjust visualizations without giving them full editing permissions. + +Using variables also allows you to single-source dashboards. +If you have multiple identical data sources or servers, you can make one dashboard and use variables to change what you are viewing. +This simplifies maintenance and upkeep enormously. + {{< youtube id="mMUJ3iwIYwc" >}} +You can use variables in: + +- Data source queries +- [Panel repeating options](https://grafana.com/docs/grafana//panels-visualizations/configure-panel-options/#configure-repeating-panels) +- [Dashboard and panel links](https://grafana.com/docs/grafana//dashboards/build-dashboards/manage-dashboard-links/) +- Titles +- Descriptions +- [Transformations](https://grafana.com/docs/grafana//panels-visualizations/query-transform-data/transform-data/) + +To see variable settings, navigate to **Dashboard Settings > Variables**. +Click a variable in the list to see its settings. + +{{< docs/play title="Templating - Interactive dashboard" url="https://play.grafana.org/goto/B9Xog68Hg?orgId=1" >}} + +## Template variables {#templates} + +A _template_ is any query that contains a variable. +Queries with text that starts with `$` are templates. + +{{< admonition type="note">}} +In our documentation and in the application, we typically simply refer to a _template query_ as a _query_, but we often use the terms _variable_ and _template variable_ interchangeably. +{{< /admonition >}} + +For example, if you were administering a dashboard to monitor several servers, it could have panels that use template queries like this one: + +```text +groupByNode(movingAverage(apps.$app.$server.counters.requests.count, 10), 2, 'sum') +``` + +The following image shows a panel in edit mode using the query: + +{{< figure src="/media/docs/grafana/dashboards/screenshot-template-query-v12.1.png" max-width="750px" alt="A panel using a template query" >}} + +### Variables in URLs + +Variable values are always synced to the URL using [query parameter syntax](https://grafana.com/docs/grafana/latest/dashboards/variables/variable-syntax/#query-parameters), `var-=value`. +For example: + +```text +https://play.grafana.org/d/HYaGDGIMk/templating-global-variables-and-interpolation?orgId=1&from=now-6h&to=now&timezone=utc&var-Server=CCC&var-MyCustomDashboardVariable=Hello%20World%21 +``` + +In the preceding example, the variables and values are `var-Server=CCC` and `var-MyCustomDashboardVariable=Hello%20World%21`. + +## Additional examples + +The following dashboards in Grafana Play provide examples of template variables: + +- [Templating - Repeated panels](https://play.grafana.org/goto/yfZOReUNR?orgId=1) - Using query variables to control how many panels appear in a dashboard. +- [Templating - Nested Variables Drilldown](https://play.grafana.org/d/testdata-nested-variables-drilldown/) - Demonstrates how changing one variable value can change the values available in a nested variable. +- [Templating - Global variables and interpolation](https://play.grafana.org/d/HYaGDGIMk/) - Shows you how the syntax for Grafana variables works. + +## Next steps + The following topics describe how to add and manage variables in your dashboards: {{< section >}} - -A variable is a placeholder for a value. You can use variables in metric queries and in panel titles. So when you change -the value, using the dropdown at the top of the dashboard, your panel's metric queries will change to reflect the new value. - -Variables allow you to create more interactive and dynamic dashboards. Instead of hard-coding things like server, application, -and sensor names in your metric queries, you can use variables in their place. Variables are displayed as dropdown lists at the top of -the dashboard. These dropdowns make it easy to change the data being displayed in your dashboard. - -{{< figure src="/static/img/docs/v50/variables_dashboard.png" alt="Variable drop-down open and two values selected" >}} - -{{< docs/play title="Templating - Global variables and interpolation" url="https://play.grafana.org/d/HYaGDGIMk/" >}} - -Variables are useful for administrators who want to allow Grafana viewers to adjust visualizations without giving them full editing permissions. Grafana viewers can use variables. - -Variables and templates also allow you to single-source dashboards. If you have multiple identical data sources or servers, you can make one dashboard and use variables to change what you are viewing. This simplifies maintenance and upkeep enormously. - -## Templates - -A _template_ is any query that contains a variable. - -For example, if you were administering a dashboard to monitor several servers, you _could_ make a dashboard for each server. Or you could create one dashboard and use panels with template queries like this one: - -``` -wmi_system_threads{instance=~"$server"} -``` - -Variable values are always synced to the URL using the syntax `var-=value`. - -## Additional Examples - -Variables are listed in drop-down lists across the top of the screen. Select different variables to see how the visualizations change. - -To see variable settings, navigate to **Dashboard Settings > Variables**. Click a variable in the list to see its settings. - -Variables can be used in titles, descriptions, text panels, and queries. Queries with text that starts with `$` are templates. Not all panels will have template queries. - -The following dashboards in Grafana Play provide examples of template variables: - -- [Templating, repeated panels](https://play.grafana.org/d/000000025/) - Using query variables to control how many panels appear. -- [Templated Dynamic Dashboard](https://play.grafana.org/d/000000056/) - Uses query variables, chained query variables, an interval variable, and a repeated panel. -- [Templating - Nested Variables Drilldown](https://play.grafana.org/d/testdata-nested-variables-drilldown/) - -## Variable best practices - -- Variable drop-down lists are displayed in the order they are listed in the variable list in Dashboard settings. -- Put the variables that you will change often at the top, so they will be shown first (far left on the dashboard). -- By default, variables don't have a default value. This means that the topmost value in the drop-down is always preselected. If you want to pre-populate a variable with an empty value, you can use the following workaround in the variable settings: - 1. Select the **Include All Option** checkbox. - 2. In the **Custom all value** field, enter a value like `+`. diff --git a/docs/sources/dashboards/variables/add-template-variables/index.md b/docs/sources/dashboards/variables/add-template-variables/index.md index 2e6181432df..38b2bbc27e1 100644 --- a/docs/sources/dashboards/variables/add-template-variables/index.md +++ b/docs/sources/dashboards/variables/add-template-variables/index.md @@ -35,6 +35,7 @@ keywords: - nested - chained - linked + - best practices labels: products: - cloud @@ -136,6 +137,13 @@ To create a variable, follow these steps: +### Variable best practices + +- Variable drop-down lists are displayed in the order in which they're listed in the **Variables** in dashboard settings, so put the variables that you will change often at the top, so they will be shown first (far left on the dashboard). +- By default, variables don't have a default value. This means that the topmost value in the drop-down list is always preselected. If you want to pre-populate a variable with an empty value, you can use the following workaround in the variable settings: + 1. Select the **Include All Option** checkbox. + 2. In the **Custom all value** field, enter a value like `+`. + ## Add a query variable Query variables enable you to write a data source query that can return a list of metric names, tag values, or keys. For example, a query variable might return a list of server names, sensor IDs, or data centers. The variable values change as they dynamically fetch options with a data source query. diff --git a/docs/sources/datasources/influxdb/template-variables/index.md b/docs/sources/datasources/influxdb/template-variables/index.md index 72d48bdccbf..7165889ea00 100644 --- a/docs/sources/datasources/influxdb/template-variables/index.md +++ b/docs/sources/datasources/influxdb/template-variables/index.md @@ -46,9 +46,9 @@ refs: destination: /docs/grafana//dashboards/variables/add-template-variables/#add-a-query-variable variable-best-practices: - pattern: /docs/grafana/ - destination: /docs/grafana//dashboards/variables/#variable-best-practices + destination: /docs/grafana//dashboards/variables/add-template-variables/#variable-best-practices - pattern: /docs/grafana-cloud/ - destination: /docs/grafana-cloud/visualizations/dashboards/variables/#variable-best-practices + destination: /docs/grafana-cloud/visualizations/dashboards/variables/add-template-variables/#variable-best-practices --- # InfluxDB template variables From bd3606d6b1b7f10ca675a6d434c2012b88ab1389 Mon Sep 17 00:00:00 2001 From: Jev Forsberg <46619047+baldm0mma@users.noreply.github.com> Date: Fri, 25 Jul 2025 13:27:01 -0600 Subject: [PATCH 016/131] Chore: Update 11.6.x support date (#108715) baldm0mma/ update 11.6.x support date --- docs/sources/upgrade-guide/when-to-upgrade/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sources/upgrade-guide/when-to-upgrade/index.md b/docs/sources/upgrade-guide/when-to-upgrade/index.md index b92f019c0b4..6467fb25ded 100644 --- a/docs/sources/upgrade-guide/when-to-upgrade/index.md +++ b/docs/sources/upgrade-guide/when-to-upgrade/index.md @@ -113,7 +113,7 @@ Here is an overview of version support through 2026: | 11.3.x | October 22, 2024 | July 22, 2025 | Not Supported | | 11.4.x | December 5, 2024 | September 5, 2025 | Security & Critical Bugs Only | | 11.5.x | January 28, 2025 | October 28, 2025 | Security & Critical Bugs Only | -| 11.6.x (Last minor of 11) | March 25, 2025 | May 25, 2026 | Security & Critical Bugs Only | +| 11.6.x (Last minor of 11) | March 25, 2025 | June 25, 2026 | Security & Critical Bugs Only | | 12.0.x | May 5, 2025 | February 5, 2026 | Security & Critical Bugs Only | | 12.1.x | July 22, 2025 | April 22, 2026 | Full Support until next minor | | 12.2.x | September 23, 2025 | June 23, 2026 | Yet to be released | From 01f863c47f51467916a848cc4bf06033a32f6ba9 Mon Sep 17 00:00:00 2001 From: Galen Kistler <109082771+gtk-grafana@users.noreply.github.com> Date: Fri, 25 Jul 2025 16:43:36 -0500 Subject: [PATCH 017/131] TableNG: Take nanos into account for column sorting (#108614) * feat(ngTable): support nanos --------- Co-authored-by: Leon Sorokin --- .../components/Table/TableNG/utils.test.ts | 38 +++++++++++++++++++ .../src/components/Table/TableNG/utils.ts | 15 ++++++++ 2 files changed, 53 insertions(+) diff --git a/packages/grafana-ui/src/components/Table/TableNG/utils.test.ts b/packages/grafana-ui/src/components/Table/TableNG/utils.test.ts index 9f48dba7b42..f7bfcf2cc9d 100644 --- a/packages/grafana-ui/src/components/Table/TableNG/utils.test.ts +++ b/packages/grafana-ui/src/components/Table/TableNG/utils.test.ts @@ -1,3 +1,5 @@ +import { SortColumn } from 'react-data-grid'; + import { createDataFrame, createTheme, @@ -30,6 +32,7 @@ import { migrateTableDisplayModeToCellOptions, getColumnTypes, getMaxWrapCell, + applySort, } from './utils'; describe('TableNG utils', () => { @@ -1084,4 +1087,39 @@ describe('TableNG utils', () => { it.todo('should only apply wrapping on idiomatic break characters (space, -, etc)'); }); + + describe('applySort', () => { + it('sorts by nanos', () => { + const frame = createDataFrame({ + fields: [ + { name: 'time', values: [1, 1, 2], nanos: [100, 99, 0] }, + { name: 'value', values: [10, 20, 30] }, + ], + }); + + const sortColumns: SortColumn[] = [ + { + columnKey: 'time', + direction: 'ASC', + }, + ]; + + const records = applySort(frameToRecords(frame), frame.fields, sortColumns); + + expect(records).toMatchObject([ + { + time: 1, + value: 20, + }, + { + time: 1, + value: 10, + }, + { + time: 2, + value: 30, + }, + ]); + }); + }); }); diff --git a/packages/grafana-ui/src/components/Table/TableNG/utils.ts b/packages/grafana-ui/src/components/Table/TableNG/utils.ts index 7ba9cabf855..67f4bf497ed 100644 --- a/packages/grafana-ui/src/components/Table/TableNG/utils.ts +++ b/packages/grafana-ui/src/components/Table/TableNG/utils.ts @@ -342,18 +342,33 @@ export function applySort( return rows; } + const sortNanos = sortColumns.map( + (c) => fields.find((f) => f.type === FieldType.time && getDisplayName(f) === c.columnKey)?.nanos + ); + const compareRows = (a: TableRow, b: TableRow): number => { let result = 0; + for (let i = 0; i < sortColumns.length; i++) { const { columnKey, direction } = sortColumns[i]; const compare = getComparator(columnTypes[columnKey]); const sortDir = direction === 'ASC' ? 1 : -1; result = sortDir * compare(a[columnKey], b[columnKey]); + + if (result === 0) { + const nanos = sortNanos[i]; + + if (nanos !== undefined) { + result = sortDir * (nanos[a.__index] - nanos[b.__index]); + } + } + if (result !== 0) { break; } } + return result; }; From 8fcfcc31da003a20275f2fd926e0f7d89da191ba Mon Sep 17 00:00:00 2001 From: Kevin Minehart <5140827+kminehart@users.noreply.github.com> Date: Fri, 25 Jul 2025 21:52:09 -0500 Subject: [PATCH 018/131] CI: run release-build on a schedule; also send source-event input to GE (#108726) * run release-build on a schedule; also send source-event input to GE * remove cron pipelines from drone --- .drone.star | 2 - .drone.yml | 363 +--------------------------- .github/workflows/release-build.yml | 9 +- 3 files changed, 8 insertions(+), 366 deletions(-) diff --git a/.drone.star b/.drone.star index 8cf6438940c..a430359e27d 100644 --- a/.drone.star +++ b/.drone.star @@ -7,7 +7,6 @@ This module returns a Drone configuration including pipelines and secrets. """ -load("scripts/drone/events/cron.star", "cronjobs") load("scripts/drone/events/main.star", "main_pipelines") load("scripts/drone/events/pr.star", "pr_pipelines") load( @@ -37,6 +36,5 @@ def main(_ctx): publish_npm_pipelines() + publish_packages_pipeline() + rgm() + - cronjobs() + secrets() ) diff --git a/.drone.yml b/.drone.yml index b9c112447b3..345aae7d4bd 100644 --- a/.drone.yml +++ b/.drone.yml @@ -2426,367 +2426,6 @@ volumes: - name: github-app temp: {} --- -clone: - retries: 3 -kind: pipeline -name: scan-grafana/grafana:latest-image -platform: - arch: amd64 - os: linux -steps: -- commands: - - echo $${GCR_CREDENTIALS} | docker login -u _json_key --password-stdin https://us.gcr.io - environment: - GCR_CREDENTIALS: - from_secret: gcr_credentials - image: docker:dind - name: authenticate-gcr - volumes: - - name: docker - path: /var/run/docker.sock - - name: config - path: /root/.docker/ -- commands: - - trivy image --exit-code 0 --severity UNKNOWN,LOW,MEDIUM grafana/grafana:latest - depends_on: - - authenticate-gcr - image: aquasec/trivy:0.21.0 - name: scan-unknown-low-medium-vulnerabilities - volumes: - - name: docker - path: /var/run/docker.sock - - name: config - path: /root/.docker/ -- commands: - - trivy image --exit-code 1 --severity HIGH,CRITICAL grafana/grafana:latest - depends_on: - - authenticate-gcr - environment: - GOOGLE_APPLICATION_CREDENTIALS: - from_secret: gcr_credentials_json - image: aquasec/trivy:0.21.0 - name: scan-high-critical-vulnerabilities - volumes: - - name: docker - path: /var/run/docker.sock - - name: config - path: /root/.docker/ -- image: plugins/slack - name: slack-notify-failure - settings: - channel: grafana-backend-ops - template: 'Nightly docker image scan job for grafana/grafana:latest failed: {{build.link}}' - webhook: - from_secret: slack_webhook_backend - when: - status: failure -trigger: - cron: nightly - event: cron -type: docker -volumes: -- host: - path: /var/run/docker.sock - name: docker -- name: config - temp: {} ---- -clone: - retries: 3 -kind: pipeline -name: scan-grafana/grafana:main-image -platform: - arch: amd64 - os: linux -steps: -- commands: - - echo $${GCR_CREDENTIALS} | docker login -u _json_key --password-stdin https://us.gcr.io - environment: - GCR_CREDENTIALS: - from_secret: gcr_credentials - image: docker:dind - name: authenticate-gcr - volumes: - - name: docker - path: /var/run/docker.sock - - name: config - path: /root/.docker/ -- commands: - - trivy image --exit-code 0 --severity UNKNOWN,LOW,MEDIUM grafana/grafana:main - depends_on: - - authenticate-gcr - image: aquasec/trivy:0.21.0 - name: scan-unknown-low-medium-vulnerabilities - volumes: - - name: docker - path: /var/run/docker.sock - - name: config - path: /root/.docker/ -- commands: - - trivy image --exit-code 1 --severity HIGH,CRITICAL grafana/grafana:main - depends_on: - - authenticate-gcr - environment: - GOOGLE_APPLICATION_CREDENTIALS: - from_secret: gcr_credentials_json - image: aquasec/trivy:0.21.0 - name: scan-high-critical-vulnerabilities - volumes: - - name: docker - path: /var/run/docker.sock - - name: config - path: /root/.docker/ -- image: plugins/slack - name: slack-notify-failure - settings: - channel: grafana-backend-ops - template: 'Nightly docker image scan job for grafana/grafana:main failed: {{build.link}}' - webhook: - from_secret: slack_webhook_backend - when: - status: failure -trigger: - cron: nightly - event: cron -type: docker -volumes: -- host: - path: /var/run/docker.sock - name: docker -- name: config - temp: {} ---- -clone: - retries: 3 -kind: pipeline -name: scan-grafana/grafana:latest-ubuntu-image -platform: - arch: amd64 - os: linux -steps: -- commands: - - echo $${GCR_CREDENTIALS} | docker login -u _json_key --password-stdin https://us.gcr.io - environment: - GCR_CREDENTIALS: - from_secret: gcr_credentials - image: docker:dind - name: authenticate-gcr - volumes: - - name: docker - path: /var/run/docker.sock - - name: config - path: /root/.docker/ -- commands: - - trivy image --exit-code 0 --severity UNKNOWN,LOW,MEDIUM grafana/grafana:latest-ubuntu - depends_on: - - authenticate-gcr - image: aquasec/trivy:0.21.0 - name: scan-unknown-low-medium-vulnerabilities - volumes: - - name: docker - path: /var/run/docker.sock - - name: config - path: /root/.docker/ -- commands: - - trivy image --exit-code 1 --severity HIGH,CRITICAL grafana/grafana:latest-ubuntu - depends_on: - - authenticate-gcr - environment: - GOOGLE_APPLICATION_CREDENTIALS: - from_secret: gcr_credentials_json - image: aquasec/trivy:0.21.0 - name: scan-high-critical-vulnerabilities - volumes: - - name: docker - path: /var/run/docker.sock - - name: config - path: /root/.docker/ -- image: plugins/slack - name: slack-notify-failure - settings: - channel: grafana-backend-ops - template: 'Nightly docker image scan job for grafana/grafana:latest-ubuntu failed: - {{build.link}}' - webhook: - from_secret: slack_webhook_backend - when: - status: failure -trigger: - cron: nightly - event: cron -type: docker -volumes: -- host: - path: /var/run/docker.sock - name: docker -- name: config - temp: {} ---- -clone: - retries: 3 -kind: pipeline -name: scan-grafana/grafana:main-ubuntu-image -platform: - arch: amd64 - os: linux -steps: -- commands: - - echo $${GCR_CREDENTIALS} | docker login -u _json_key --password-stdin https://us.gcr.io - environment: - GCR_CREDENTIALS: - from_secret: gcr_credentials - image: docker:dind - name: authenticate-gcr - volumes: - - name: docker - path: /var/run/docker.sock - - name: config - path: /root/.docker/ -- commands: - - trivy image --exit-code 0 --severity UNKNOWN,LOW,MEDIUM grafana/grafana:main-ubuntu - depends_on: - - authenticate-gcr - image: aquasec/trivy:0.21.0 - name: scan-unknown-low-medium-vulnerabilities - volumes: - - name: docker - path: /var/run/docker.sock - - name: config - path: /root/.docker/ -- commands: - - trivy image --exit-code 1 --severity HIGH,CRITICAL grafana/grafana:main-ubuntu - depends_on: - - authenticate-gcr - environment: - GOOGLE_APPLICATION_CREDENTIALS: - from_secret: gcr_credentials_json - image: aquasec/trivy:0.21.0 - name: scan-high-critical-vulnerabilities - volumes: - - name: docker - path: /var/run/docker.sock - - name: config - path: /root/.docker/ -- image: plugins/slack - name: slack-notify-failure - settings: - channel: grafana-backend-ops - template: 'Nightly docker image scan job for grafana/grafana:main-ubuntu failed: - {{build.link}}' - webhook: - from_secret: slack_webhook_backend - when: - status: failure -trigger: - cron: nightly - event: cron -type: docker -volumes: -- host: - path: /var/run/docker.sock - name: docker -- name: config - temp: {} ---- -clone: - retries: 3 -kind: pipeline -name: scan-build-test-and-publish-docker-images -platform: - arch: amd64 - os: linux -steps: -- commands: - - echo $${GCR_CREDENTIALS} | docker login -u _json_key --password-stdin https://us.gcr.io - environment: - GCR_CREDENTIALS: - from_secret: gcr_credentials - image: docker:dind - name: authenticate-gcr - volumes: - - name: docker - path: /var/run/docker.sock - - name: config - path: /root/.docker/ -- commands: - - trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM docker:27-cli - - trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM alpine/git:2.40.1 - - trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM golang:1.24.5-alpine - - trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM node:22.16.0-alpine - - trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM node:22-bookworm - - trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM google/cloud-sdk:431.0.0 - - trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM grafana/grafana-ci-deploy:1.3.3 - - trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM alpine:3.21.3 - - trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM ubuntu:22.04 - - trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM byrnedo/alpine-curl:0.1.8 - - trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM plugins/slack - - trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM us.gcr.io/kubernetes-dev/package-publish:latest - - trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM grafana/drone-downstream - - trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM grafana/docker-puppeteer:1.1.0 - - trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM grafana/docs-base:latest - - trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM cypress/included:14.3.2 - - trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM jwilder/dockerize:0.6.1 - - trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM us-docker.pkg.dev/grafanalabs-global/docker-deployment-tools-prod/github-app-secret-writer:2024-11-05-v11688112090.1-83920c59 - depends_on: - - authenticate-gcr - image: aquasec/trivy:0.21.0 - name: scan-unknown-low-medium-vulnerabilities - volumes: - - name: docker - path: /var/run/docker.sock - - name: config - path: /root/.docker/ -- commands: - - trivy --exit-code 1 --severity HIGH,CRITICAL docker:27-cli - - trivy --exit-code 1 --severity HIGH,CRITICAL alpine/git:2.40.1 - - trivy --exit-code 1 --severity HIGH,CRITICAL golang:1.24.5-alpine - - trivy --exit-code 1 --severity HIGH,CRITICAL node:22.16.0-alpine - - trivy --exit-code 1 --severity HIGH,CRITICAL node:22-bookworm - - trivy --exit-code 1 --severity HIGH,CRITICAL google/cloud-sdk:431.0.0 - - trivy --exit-code 1 --severity HIGH,CRITICAL grafana/grafana-ci-deploy:1.3.3 - - trivy --exit-code 1 --severity HIGH,CRITICAL alpine:3.21.3 - - trivy --exit-code 1 --severity HIGH,CRITICAL ubuntu:22.04 - - trivy --exit-code 1 --severity HIGH,CRITICAL byrnedo/alpine-curl:0.1.8 - - trivy --exit-code 1 --severity HIGH,CRITICAL plugins/slack - - trivy --exit-code 1 --severity HIGH,CRITICAL us.gcr.io/kubernetes-dev/package-publish:latest - - trivy --exit-code 1 --severity HIGH,CRITICAL grafana/drone-downstream - - trivy --exit-code 1 --severity HIGH,CRITICAL grafana/docker-puppeteer:1.1.0 - - trivy --exit-code 1 --severity HIGH,CRITICAL grafana/docs-base:latest - - trivy --exit-code 1 --severity HIGH,CRITICAL cypress/included:14.3.2 - - trivy --exit-code 1 --severity HIGH,CRITICAL jwilder/dockerize:0.6.1 - - trivy --exit-code 1 --severity HIGH,CRITICAL us-docker.pkg.dev/grafanalabs-global/docker-deployment-tools-prod/github-app-secret-writer:2024-11-05-v11688112090.1-83920c59 - depends_on: - - authenticate-gcr - environment: - GOOGLE_APPLICATION_CREDENTIALS: - from_secret: gcr_credentials_json - image: aquasec/trivy:0.21.0 - name: scan-high-critical-vulnerabilities - volumes: - - name: docker - path: /var/run/docker.sock - - name: config - path: /root/.docker/ -- image: plugins/slack - name: slack-notify-failure - settings: - channel: grafana-backend-ops - template: 'Nightly docker image scan job for build-images failed: {{build.link}}' - webhook: - from_secret: slack_webhook_backend - when: - status: failure -trigger: - cron: nightly - event: cron -type: docker -volumes: -- host: - path: /var/run/docker.sock - name: docker -- name: config - temp: {} ---- get: name: app-id path: ci/data/repo/grafana/grafana/github-app @@ -2986,6 +2625,6 @@ kind: secret name: gcr_credentials --- kind: signature -hmac: 30bdd468f35d41ca5594e5d13cf500ab4949ea875f6f88b5121a1254353e76b2 +hmac: aef043aae7394d3160a7147c8b57599bf1a2f4ba5c596ffb795a0e6a049c73a6 ... diff --git a/.github/workflows/release-build.yml b/.github/workflows/release-build.yml index 35b8a219d62..fda8533dc0e 100644 --- a/.github/workflows/release-build.yml +++ b/.github/workflows/release-build.yml @@ -1,6 +1,10 @@ name: Build Release Packages on: workflow_dispatch: + schedule: + # Every weeknight at midnight + # "Scheduled workflows will only run on the default branch." (docs.github.com) + - cron: "0 0 * * 1-5" push: branches: - release-*.*.* @@ -96,8 +100,8 @@ jobs: with: github-token: ${{ steps.generate_token.outputs.token }} script: | - const {REF, VERSION, BUILD_ID, BUCKET, GRAFANA_COMMIT} = process.env; - + const {REF, VERSION, BUILD_ID, BUCKET, GRAFANA_COMMIT, GITHUB_EVENT_NAME} = process.env; + await github.rest.actions.createWorkflowDispatch({ owner: 'grafana', repo: 'grafana-enterprise', @@ -108,6 +112,7 @@ jobs: "build-id": String(BUILD_ID), "bucket": BUCKET, "grafana-commit": GRAFANA_COMMIT, + "source-event": GITHUB_EVENT_NAME, } }) From 910454c84cf24cf3733933377d8909f82ae008d2 Mon Sep 17 00:00:00 2001 From: "grafana-pr-automation[bot]" <140550294+grafana-pr-automation[bot]@users.noreply.github.com> Date: Sun, 27 Jul 2025 00:32:40 +0000 Subject: [PATCH 019/131] I18n: Download translations from Crowdin (#108730) New Crowdin translations by GitHub Action Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- public/locales/cs-CZ/grafana.json | 8 ++++++-- public/locales/de-DE/grafana.json | 8 ++++++-- public/locales/es-ES/grafana.json | 8 ++++++-- public/locales/fr-FR/grafana.json | 8 ++++++-- public/locales/hu-HU/grafana.json | 8 ++++++-- public/locales/id-ID/grafana.json | 8 ++++++-- public/locales/it-IT/grafana.json | 8 ++++++-- public/locales/ja-JP/grafana.json | 8 ++++++-- public/locales/ko-KR/grafana.json | 8 ++++++-- public/locales/nl-NL/grafana.json | 8 ++++++-- public/locales/pl-PL/grafana.json | 8 ++++++-- public/locales/pt-BR/grafana.json | 8 ++++++-- public/locales/pt-PT/grafana.json | 8 ++++++-- public/locales/ru-RU/grafana.json | 8 ++++++-- public/locales/sv-SE/grafana.json | 8 ++++++-- public/locales/tr-TR/grafana.json | 8 ++++++-- public/locales/zh-Hans/grafana.json | 8 ++++++-- public/locales/zh-Hant/grafana.json | 8 ++++++-- 18 files changed, 108 insertions(+), 36 deletions(-) diff --git a/public/locales/cs-CZ/grafana.json b/public/locales/cs-CZ/grafana.json index 74c68092a73..9b064e0918f 100644 --- a/public/locales/cs-CZ/grafana.json +++ b/public/locales/cs-CZ/grafana.json @@ -2488,7 +2488,6 @@ }, "rule-list": { "configure-datasource": "Konfigurovat", - "draft-new-rule": "Navrhnout nové pravidlo", "ds-error": { "title": "Nelze načíst pravidla pro tento zdroj dat" }, @@ -2514,6 +2513,7 @@ "new-alert-rule": "Nové pravidlo výstrahy", "new-datasource-recording-rule": "Nové pravidlo nahrávání zdroje dat", "new-grafana-recording-rule": "Nové pravidlo nahrávání Grafany", + "new-rule-for-export": "", "pagination": { "next-page": "Zobrazit více…" }, @@ -4604,6 +4604,10 @@ }, "edit-actions": { "add": "Přidat {{typeName}}", + "add-conditional-rule": "", + "edit-query-result-rule": "", + "edit-template-variable-rule": "", + "edit-time-range-rule": "", "move": "Přesunout {{typeName}}", "panel-background": "Změnit pozadí panelu", "panel-description": "Změnit popis panelu", @@ -4618,6 +4622,7 @@ "edit-pane": { "elements": { "dashboard": "Nástěnka", + "element": "", "local-variable": "Lokální proměnná", "multiple-elements": "Více prvků", "multiple-elements-delete-text": "Opravdu chcete odstranit tyto prvky?", @@ -5831,7 +5836,6 @@ "move-action": "", "move-read-only-message": "", "moving": "", - "partial-failure-warning": "", "target-path-label": "", "title-this-repository-is-read-only": "" }, diff --git a/public/locales/de-DE/grafana.json b/public/locales/de-DE/grafana.json index 0139a868dc4..72b771fde4e 100644 --- a/public/locales/de-DE/grafana.json +++ b/public/locales/de-DE/grafana.json @@ -2468,7 +2468,6 @@ }, "rule-list": { "configure-datasource": "Konfigurieren", - "draft-new-rule": "Neue Regel entwerfen", "ds-error": { "title": "Regeln für diese Datenquelle können nicht geladen werden" }, @@ -2494,6 +2493,7 @@ "new-alert-rule": "Neue Warnregel", "new-datasource-recording-rule": "Neue Datenquelle-Aufnahmeregel", "new-grafana-recording-rule": "Neue Grafana-Aufnahmeregel", + "new-rule-for-export": "", "pagination": { "next-page": "Mehr anzeigen …" }, @@ -4566,6 +4566,10 @@ }, "edit-actions": { "add": "{{typeName}} hinzufügen", + "add-conditional-rule": "", + "edit-query-result-rule": "", + "edit-template-variable-rule": "", + "edit-time-range-rule": "", "move": "Verschieben von {{typeName}}", "panel-background": "Panel-Hintergrund ändern", "panel-description": "Panel-Beschreibung ändern", @@ -4580,6 +4584,7 @@ "edit-pane": { "elements": { "dashboard": "Dashboard", + "element": "", "local-variable": "Lokale Variable", "multiple-elements": "Mehrere Elemente", "multiple-elements-delete-text": "Sind Sie sicher, dass Sie diese Elemente löschen möchten?", @@ -5789,7 +5794,6 @@ "move-action": "", "move-read-only-message": "", "moving": "", - "partial-failure-warning": "", "target-path-label": "", "title-this-repository-is-read-only": "" }, diff --git a/public/locales/es-ES/grafana.json b/public/locales/es-ES/grafana.json index 644fb0b08d5..ccab92fde0b 100644 --- a/public/locales/es-ES/grafana.json +++ b/public/locales/es-ES/grafana.json @@ -2468,7 +2468,6 @@ }, "rule-list": { "configure-datasource": "Configurar", - "draft-new-rule": "Redactar una nueva regla", "ds-error": { "title": "No se pueden cargar las reglas para esta fuente de datos" }, @@ -2494,6 +2493,7 @@ "new-alert-rule": "Nueva regla de alerta", "new-datasource-recording-rule": "Nueva regla de registro de fuente de datos", "new-grafana-recording-rule": "Nueva regla de registro de Grafana", + "new-rule-for-export": "", "pagination": { "next-page": "Mostrar más..." }, @@ -4566,6 +4566,10 @@ }, "edit-actions": { "add": "Añadir {{typeName}}", + "add-conditional-rule": "", + "edit-query-result-rule": "", + "edit-template-variable-rule": "", + "edit-time-range-rule": "", "move": "", "panel-background": "Cambiar fondo del panel", "panel-description": "Cambiar descripción del panel", @@ -4580,6 +4584,7 @@ "edit-pane": { "elements": { "dashboard": "Panel de control", + "element": "", "local-variable": "Variable local", "multiple-elements": "Múltiples elementos", "multiple-elements-delete-text": "¿Seguro que quieres eliminar estos elementos?", @@ -5789,7 +5794,6 @@ "move-action": "", "move-read-only-message": "", "moving": "", - "partial-failure-warning": "", "target-path-label": "", "title-this-repository-is-read-only": "" }, diff --git a/public/locales/fr-FR/grafana.json b/public/locales/fr-FR/grafana.json index c062ee51b3c..e5741e79d7d 100644 --- a/public/locales/fr-FR/grafana.json +++ b/public/locales/fr-FR/grafana.json @@ -2468,7 +2468,6 @@ }, "rule-list": { "configure-datasource": "Configurer", - "draft-new-rule": "Rédiger une nouvelle règle", "ds-error": { "title": "Impossible de charger les règles pour cette source de données" }, @@ -2494,6 +2493,7 @@ "new-alert-rule": "Nouvelle règle d'alerte", "new-datasource-recording-rule": "Nouvelle règle d’enregistrement de source de données", "new-grafana-recording-rule": "Nouvelle règle d’enregistrement Grafana", + "new-rule-for-export": "", "pagination": { "next-page": "Afficher plus..." }, @@ -4566,6 +4566,10 @@ }, "edit-actions": { "add": "Ajouter {{typeName}}", + "add-conditional-rule": "", + "edit-query-result-rule": "", + "edit-template-variable-rule": "", + "edit-time-range-rule": "", "move": "Déplacer {{typeName}}", "panel-background": "Modifier l’arrière-plan du panneau", "panel-description": "Modifier la description du panneau", @@ -4580,6 +4584,7 @@ "edit-pane": { "elements": { "dashboard": "Tableau de bord", + "element": "", "local-variable": "Variable locale", "multiple-elements": "Éléments multiples", "multiple-elements-delete-text": "Voulez-vous vraiment supprimer ces éléments ?", @@ -5789,7 +5794,6 @@ "move-action": "", "move-read-only-message": "", "moving": "", - "partial-failure-warning": "", "target-path-label": "", "title-this-repository-is-read-only": "" }, diff --git a/public/locales/hu-HU/grafana.json b/public/locales/hu-HU/grafana.json index 2310aa7674f..7731b5bd4eb 100644 --- a/public/locales/hu-HU/grafana.json +++ b/public/locales/hu-HU/grafana.json @@ -2468,7 +2468,6 @@ }, "rule-list": { "configure-datasource": "Konfigurálás", - "draft-new-rule": "Új szabály felvázolása", "ds-error": { "title": "Nem lehet betölteni a szabályokat ehhez az adatforráshoz" }, @@ -2494,6 +2493,7 @@ "new-alert-rule": "Új riasztási szabály", "new-datasource-recording-rule": "Új adatforrás-felvételkészítési szabály", "new-grafana-recording-rule": "Új Grafana-felvételkészítési szabály", + "new-rule-for-export": "", "pagination": { "next-page": "Továbbiak megjelenítése…" }, @@ -4566,6 +4566,10 @@ }, "edit-actions": { "add": "{{typeName}} hozzáadása", + "add-conditional-rule": "", + "edit-query-result-rule": "", + "edit-template-variable-rule": "", + "edit-time-range-rule": "", "move": "{{typeName}} áthelyezése", "panel-background": "Panel hátterének módosítása", "panel-description": "Panel leírásának módosítása", @@ -4580,6 +4584,7 @@ "edit-pane": { "elements": { "dashboard": "Irányítópult", + "element": "", "local-variable": "Helyi változó", "multiple-elements": "Több elem", "multiple-elements-delete-text": "Biztosan törli ezeket az elemeket?", @@ -5789,7 +5794,6 @@ "move-action": "", "move-read-only-message": "", "moving": "", - "partial-failure-warning": "", "target-path-label": "", "title-this-repository-is-read-only": "" }, diff --git a/public/locales/id-ID/grafana.json b/public/locales/id-ID/grafana.json index 54e2e6d381c..1490c225d50 100644 --- a/public/locales/id-ID/grafana.json +++ b/public/locales/id-ID/grafana.json @@ -2458,7 +2458,6 @@ }, "rule-list": { "configure-datasource": "Konfigurasikan", - "draft-new-rule": "Buat draf aturan baru", "ds-error": { "title": "Tidak dapat memuat aturan untuk sumber data ini" }, @@ -2484,6 +2483,7 @@ "new-alert-rule": "Aturan peringatan baru", "new-datasource-recording-rule": "Aturan Perekaman sumber data baru", "new-grafana-recording-rule": "Aturan Perekaman Grafana baru", + "new-rule-for-export": "", "pagination": { "next-page": "Tampilkan lebih banyak..." }, @@ -4547,6 +4547,10 @@ }, "edit-actions": { "add": "Tambahkan {{typeName}}", + "add-conditional-rule": "", + "edit-query-result-rule": "", + "edit-template-variable-rule": "", + "edit-time-range-rule": "", "move": "Pindahkan {{typeName}}", "panel-background": "Ubah latar belakang panel", "panel-description": "Ubah deskripsi panel", @@ -4561,6 +4565,7 @@ "edit-pane": { "elements": { "dashboard": "Dasbor", + "element": "", "local-variable": "Variabel lokal", "multiple-elements": "Beberapa elemen", "multiple-elements-delete-text": "Anda yakin ingin menghapus elemen ini?", @@ -5768,7 +5773,6 @@ "move-action": "", "move-read-only-message": "", "moving": "", - "partial-failure-warning": "", "target-path-label": "", "title-this-repository-is-read-only": "" }, diff --git a/public/locales/it-IT/grafana.json b/public/locales/it-IT/grafana.json index b907d962cbb..bea973dbed5 100644 --- a/public/locales/it-IT/grafana.json +++ b/public/locales/it-IT/grafana.json @@ -2468,7 +2468,6 @@ }, "rule-list": { "configure-datasource": "Configura", - "draft-new-rule": "Scrivi una nuova regola", "ds-error": { "title": "" }, @@ -2494,6 +2493,7 @@ "new-alert-rule": "Nuova regola di avviso", "new-datasource-recording-rule": "Nuova regola di registrazione dell'origine dei dati", "new-grafana-recording-rule": "Nuova regola di registrazione Grafana", + "new-rule-for-export": "", "pagination": { "next-page": "Mostra altro…" }, @@ -4566,6 +4566,10 @@ }, "edit-actions": { "add": "", + "add-conditional-rule": "", + "edit-query-result-rule": "", + "edit-template-variable-rule": "", + "edit-time-range-rule": "", "move": "", "panel-background": "", "panel-description": "", @@ -4580,6 +4584,7 @@ "edit-pane": { "elements": { "dashboard": "Dashboard", + "element": "", "local-variable": "Variabile locale", "multiple-elements": "Elementi multipli", "multiple-elements-delete-text": "Desideri davvero eliminare questi elementi?", @@ -5789,7 +5794,6 @@ "move-action": "", "move-read-only-message": "", "moving": "", - "partial-failure-warning": "", "target-path-label": "", "title-this-repository-is-read-only": "" }, diff --git a/public/locales/ja-JP/grafana.json b/public/locales/ja-JP/grafana.json index 29514e30b14..111f3266e28 100644 --- a/public/locales/ja-JP/grafana.json +++ b/public/locales/ja-JP/grafana.json @@ -2458,7 +2458,6 @@ }, "rule-list": { "configure-datasource": "構成", - "draft-new-rule": "新しいルールの下書きを作成", "ds-error": { "title": "このデータソースのルールを読み込めません" }, @@ -2484,6 +2483,7 @@ "new-alert-rule": "新しいアラートルール", "new-datasource-recording-rule": "新しいデータソース記録ルール", "new-grafana-recording-rule": "新しいGrafana記録ルール", + "new-rule-for-export": "", "pagination": { "next-page": "もっと見る..." }, @@ -4547,6 +4547,10 @@ }, "edit-actions": { "add": "{{typeName}}を追加", + "add-conditional-rule": "", + "edit-query-result-rule": "", + "edit-template-variable-rule": "", + "edit-time-range-rule": "", "move": "{{typeName}}を移動", "panel-background": "パネルの背景を変更", "panel-description": "パネルの説明を変更", @@ -4561,6 +4565,7 @@ "edit-pane": { "elements": { "dashboard": "ダッシュボード", + "element": "", "local-variable": "ローカル変数", "multiple-elements": "複数の要素", "multiple-elements-delete-text": "これらの要素を削除してもよろしいですか?", @@ -5768,7 +5773,6 @@ "move-action": "", "move-read-only-message": "", "moving": "", - "partial-failure-warning": "", "target-path-label": "", "title-this-repository-is-read-only": "" }, diff --git a/public/locales/ko-KR/grafana.json b/public/locales/ko-KR/grafana.json index 5abaa828353..d7addbf12e7 100644 --- a/public/locales/ko-KR/grafana.json +++ b/public/locales/ko-KR/grafana.json @@ -2458,7 +2458,6 @@ }, "rule-list": { "configure-datasource": "구성", - "draft-new-rule": "새 규칙 초안 작성", "ds-error": { "title": "이 데이터 소스에 대한 규칙을 불러올 수 없음" }, @@ -2484,6 +2483,7 @@ "new-alert-rule": "새 경고 규칙", "new-datasource-recording-rule": "새 데이터 소스 기록 규칙", "new-grafana-recording-rule": "새 Grafana 기록 규칙", + "new-rule-for-export": "", "pagination": { "next-page": "더 보기..." }, @@ -4547,6 +4547,10 @@ }, "edit-actions": { "add": "{{typeName}} 추가", + "add-conditional-rule": "", + "edit-query-result-rule": "", + "edit-template-variable-rule": "", + "edit-time-range-rule": "", "move": "", "panel-background": "패널 배경 변경", "panel-description": "패널 설명 변경", @@ -4561,6 +4565,7 @@ "edit-pane": { "elements": { "dashboard": "대시보드", + "element": "", "local-variable": "로컬 변수", "multiple-elements": "여러 요소", "multiple-elements-delete-text": "정말 이 요소를 삭제하시겠어요?", @@ -5768,7 +5773,6 @@ "move-action": "", "move-read-only-message": "", "moving": "", - "partial-failure-warning": "", "target-path-label": "", "title-this-repository-is-read-only": "" }, diff --git a/public/locales/nl-NL/grafana.json b/public/locales/nl-NL/grafana.json index 11af820962a..d4affb86dc3 100644 --- a/public/locales/nl-NL/grafana.json +++ b/public/locales/nl-NL/grafana.json @@ -2468,7 +2468,6 @@ }, "rule-list": { "configure-datasource": "Configureren", - "draft-new-rule": "Een nieuwe regel opstellen", "ds-error": { "title": "Kan geen regels laden voor deze gegevensbron" }, @@ -2494,6 +2493,7 @@ "new-alert-rule": "Nieuwe waarschuwingsregel", "new-datasource-recording-rule": "Nieuwe gegevensbron voor opnameregel", "new-grafana-recording-rule": "Nieuwe Grafana-opnameregel", + "new-rule-for-export": "", "pagination": { "next-page": "Meer weergeven..." }, @@ -4566,6 +4566,10 @@ }, "edit-actions": { "add": "{{typeName}} toevoegen", + "add-conditional-rule": "", + "edit-query-result-rule": "", + "edit-template-variable-rule": "", + "edit-time-range-rule": "", "move": "{{typeName}} verplaatsen ", "panel-background": "Paneelachtergrond wijzigen", "panel-description": "Paneelbeschrijving wijzigen", @@ -4580,6 +4584,7 @@ "edit-pane": { "elements": { "dashboard": "Dashboard", + "element": "", "local-variable": "Lokale variabele", "multiple-elements": "Meerdere elementen", "multiple-elements-delete-text": "Weet je zeker dat je deze elementen wilt verwijderen?", @@ -5789,7 +5794,6 @@ "move-action": "", "move-read-only-message": "", "moving": "", - "partial-failure-warning": "", "target-path-label": "", "title-this-repository-is-read-only": "" }, diff --git a/public/locales/pl-PL/grafana.json b/public/locales/pl-PL/grafana.json index a12c4bff317..121c28f0b17 100644 --- a/public/locales/pl-PL/grafana.json +++ b/public/locales/pl-PL/grafana.json @@ -2488,7 +2488,6 @@ }, "rule-list": { "configure-datasource": "Konfiguruj", - "draft-new-rule": "Zaprojektuj nową regułę", "ds-error": { "title": "Nie można załadować reguł dla tego źródła danych" }, @@ -2514,6 +2513,7 @@ "new-alert-rule": "Nowa reguła alertu", "new-datasource-recording-rule": "Nowa reguła rejestracji źródła danych", "new-grafana-recording-rule": "Nowa reguła rejestracji w usłudze Grafana", + "new-rule-for-export": "", "pagination": { "next-page": "Pokaż więcej…" }, @@ -4604,6 +4604,10 @@ }, "edit-actions": { "add": "Dodaj: {{typeName}}", + "add-conditional-rule": "", + "edit-query-result-rule": "", + "edit-template-variable-rule": "", + "edit-time-range-rule": "", "move": "", "panel-background": "Zmień tło panelu", "panel-description": "Zmień opis panelu", @@ -4618,6 +4622,7 @@ "edit-pane": { "elements": { "dashboard": "Pulpit", + "element": "", "local-variable": "Zmienna lokalna", "multiple-elements": "Wiele elementów", "multiple-elements-delete-text": "Czy na pewno chcesz usunąć te elementy?", @@ -5831,7 +5836,6 @@ "move-action": "", "move-read-only-message": "", "moving": "", - "partial-failure-warning": "", "target-path-label": "", "title-this-repository-is-read-only": "" }, diff --git a/public/locales/pt-BR/grafana.json b/public/locales/pt-BR/grafana.json index 055ea9c3f22..9a2163064f9 100644 --- a/public/locales/pt-BR/grafana.json +++ b/public/locales/pt-BR/grafana.json @@ -2468,7 +2468,6 @@ }, "rule-list": { "configure-datasource": "Configuração", - "draft-new-rule": "Crie o rascunho de uma nova regra", "ds-error": { "title": "Não é possível carregar regras para esta fonte de dados" }, @@ -2494,6 +2493,7 @@ "new-alert-rule": "Nova regra de alerta", "new-datasource-recording-rule": "Nova regra de registro de fonte de dados", "new-grafana-recording-rule": "Nova regra de registro da Grafana", + "new-rule-for-export": "", "pagination": { "next-page": "Exibir mais…" }, @@ -4566,6 +4566,10 @@ }, "edit-actions": { "add": "Adicionar {{typeName}}", + "add-conditional-rule": "", + "edit-query-result-rule": "", + "edit-template-variable-rule": "", + "edit-time-range-rule": "", "move": "", "panel-background": "Alterar plano de fundo do painel", "panel-description": "Alterar descrição do painel", @@ -4580,6 +4584,7 @@ "edit-pane": { "elements": { "dashboard": "Painel de controle", + "element": "", "local-variable": "Variável local", "multiple-elements": "Vários elementos", "multiple-elements-delete-text": "Tem certeza de que deseja excluir estes elementos?", @@ -5789,7 +5794,6 @@ "move-action": "", "move-read-only-message": "", "moving": "", - "partial-failure-warning": "", "target-path-label": "", "title-this-repository-is-read-only": "" }, diff --git a/public/locales/pt-PT/grafana.json b/public/locales/pt-PT/grafana.json index a2299cdc97a..e3e9a7ab70f 100644 --- a/public/locales/pt-PT/grafana.json +++ b/public/locales/pt-PT/grafana.json @@ -2468,7 +2468,6 @@ }, "rule-list": { "configure-datasource": "Configurar", - "draft-new-rule": "Elabore o rascunho de uma nova regra", "ds-error": { "title": "Não é possível carregar regras para esta origem de dados" }, @@ -2494,6 +2493,7 @@ "new-alert-rule": "Nova regra de alerta", "new-datasource-recording-rule": "Nova regra de gravação da origem de dados", "new-grafana-recording-rule": "Nova regra de gravação da Grafana", + "new-rule-for-export": "", "pagination": { "next-page": "Mostrar mais... " }, @@ -4566,6 +4566,10 @@ }, "edit-actions": { "add": "Adicionar {{typeName}}", + "add-conditional-rule": "", + "edit-query-result-rule": "", + "edit-template-variable-rule": "", + "edit-time-range-rule": "", "move": "", "panel-background": "Alterar fundo do painel", "panel-description": "Alterar descrição do painel", @@ -4580,6 +4584,7 @@ "edit-pane": { "elements": { "dashboard": "Painel de controlo", + "element": "", "local-variable": "Variável local", "multiple-elements": "Vários elementos", "multiple-elements-delete-text": "Tem a certeza de que pretende eliminar estes elementos?", @@ -5789,7 +5794,6 @@ "move-action": "", "move-read-only-message": "", "moving": "", - "partial-failure-warning": "", "target-path-label": "", "title-this-repository-is-read-only": "" }, diff --git a/public/locales/ru-RU/grafana.json b/public/locales/ru-RU/grafana.json index caf5f5513fa..5179df1fabd 100644 --- a/public/locales/ru-RU/grafana.json +++ b/public/locales/ru-RU/grafana.json @@ -2488,7 +2488,6 @@ }, "rule-list": { "configure-datasource": "Настроить", - "draft-new-rule": "Составить новое правило", "ds-error": { "title": "Невозможно загрузить правила для этого источника данных" }, @@ -2514,6 +2513,7 @@ "new-alert-rule": "Новое правило оповещения", "new-datasource-recording-rule": "Новое правило записи источника данных", "new-grafana-recording-rule": "Новое правило записи Grafana", + "new-rule-for-export": "", "pagination": { "next-page": "Показать еще…" }, @@ -4604,6 +4604,10 @@ }, "edit-actions": { "add": "Добавить {{typeName}}", + "add-conditional-rule": "", + "edit-query-result-rule": "", + "edit-template-variable-rule": "", + "edit-time-range-rule": "", "move": "", "panel-background": "Изменить фон панели", "panel-description": "Изменить описание панели", @@ -4618,6 +4622,7 @@ "edit-pane": { "elements": { "dashboard": "Дашборд", + "element": "", "local-variable": "Локальная переменная", "multiple-elements": "Несколько элементов", "multiple-elements-delete-text": "Действительно удалить элементы?", @@ -5831,7 +5836,6 @@ "move-action": "", "move-read-only-message": "", "moving": "", - "partial-failure-warning": "", "target-path-label": "", "title-this-repository-is-read-only": "" }, diff --git a/public/locales/sv-SE/grafana.json b/public/locales/sv-SE/grafana.json index c347596c3fb..68b8aa42096 100644 --- a/public/locales/sv-SE/grafana.json +++ b/public/locales/sv-SE/grafana.json @@ -2468,7 +2468,6 @@ }, "rule-list": { "configure-datasource": "Konfigurera", - "draft-new-rule": "Skapa utkast till en ny regel", "ds-error": { "title": "Kan inte ladda regler för denna datakälla" }, @@ -2494,6 +2493,7 @@ "new-alert-rule": "Ny varningsregel", "new-datasource-recording-rule": "Ny registreringsregel för datakälla", "new-grafana-recording-rule": "Ny registreringsregel för Grafana", + "new-rule-for-export": "", "pagination": { "next-page": "Visa mer …" }, @@ -4566,6 +4566,10 @@ }, "edit-actions": { "add": "Lägg till {{typeName}}", + "add-conditional-rule": "", + "edit-query-result-rule": "", + "edit-template-variable-rule": "", + "edit-time-range-rule": "", "move": "", "panel-background": "Ändra panelbakgrund", "panel-description": "Ändra panelbeskrivning", @@ -4580,6 +4584,7 @@ "edit-pane": { "elements": { "dashboard": "Instrumentpanel", + "element": "", "local-variable": "Lokal variabel", "multiple-elements": "Flera element", "multiple-elements-delete-text": "Är du säker på att du vill radera dessa element?", @@ -5789,7 +5794,6 @@ "move-action": "", "move-read-only-message": "", "moving": "", - "partial-failure-warning": "", "target-path-label": "", "title-this-repository-is-read-only": "" }, diff --git a/public/locales/tr-TR/grafana.json b/public/locales/tr-TR/grafana.json index b4c6e0e31e7..85c673683f2 100644 --- a/public/locales/tr-TR/grafana.json +++ b/public/locales/tr-TR/grafana.json @@ -2468,7 +2468,6 @@ }, "rule-list": { "configure-datasource": "Yapılandır", - "draft-new-rule": "Yeni bir kural taslağı oluştur", "ds-error": { "title": "Bu veri kaynağı için kurallar yüklenemiyor" }, @@ -2494,6 +2493,7 @@ "new-alert-rule": "Yeni uyarı kuralı", "new-datasource-recording-rule": "Yeni veri kaynağı kayıt kuralı", "new-grafana-recording-rule": "Yeni Grafana kayıt kuralı", + "new-rule-for-export": "", "pagination": { "next-page": "Daha fazla göster..." }, @@ -4566,6 +4566,10 @@ }, "edit-actions": { "add": "{{typeName}} ekle", + "add-conditional-rule": "", + "edit-query-result-rule": "", + "edit-template-variable-rule": "", + "edit-time-range-rule": "", "move": "", "panel-background": "Panel arka planını değiştir", "panel-description": "Panel açıklamasını değiştir", @@ -4580,6 +4584,7 @@ "edit-pane": { "elements": { "dashboard": "Pano", + "element": "", "local-variable": "Yerel değişken", "multiple-elements": "Birden çok öge", "multiple-elements-delete-text": "Bu ögeleri silmek istediğinize emin misiniz?", @@ -5789,7 +5794,6 @@ "move-action": "", "move-read-only-message": "", "moving": "", - "partial-failure-warning": "", "target-path-label": "", "title-this-repository-is-read-only": "" }, diff --git a/public/locales/zh-Hans/grafana.json b/public/locales/zh-Hans/grafana.json index 7ebd76f8f4b..0c7f83995a0 100644 --- a/public/locales/zh-Hans/grafana.json +++ b/public/locales/zh-Hans/grafana.json @@ -2458,7 +2458,6 @@ }, "rule-list": { "configure-datasource": "配置", - "draft-new-rule": "起草新规则", "ds-error": { "title": "无法加载此数据源的规则" }, @@ -2484,6 +2483,7 @@ "new-alert-rule": "新建警报规则", "new-datasource-recording-rule": "新的数据源录制规则", "new-grafana-recording-rule": "新的 Grafana 录制规则", + "new-rule-for-export": "", "pagination": { "next-page": "显示更多..." }, @@ -4547,6 +4547,10 @@ }, "edit-actions": { "add": "添加{{typeName}}", + "add-conditional-rule": "", + "edit-query-result-rule": "", + "edit-template-variable-rule": "", + "edit-time-range-rule": "", "move": "移动{{typeName}}", "panel-background": "更改面板背景", "panel-description": "更改面板描述", @@ -4561,6 +4565,7 @@ "edit-pane": { "elements": { "dashboard": "仪表板", + "element": "", "local-variable": "局部变量", "multiple-elements": "多个元素", "multiple-elements-delete-text": "您确定要删除这些元素吗?", @@ -5768,7 +5773,6 @@ "move-action": "", "move-read-only-message": "", "moving": "", - "partial-failure-warning": "", "target-path-label": "", "title-this-repository-is-read-only": "" }, diff --git a/public/locales/zh-Hant/grafana.json b/public/locales/zh-Hant/grafana.json index a107cb4664d..d701e5cb5e0 100644 --- a/public/locales/zh-Hant/grafana.json +++ b/public/locales/zh-Hant/grafana.json @@ -2458,7 +2458,6 @@ }, "rule-list": { "configure-datasource": "設定", - "draft-new-rule": "撰寫新規則", "ds-error": { "title": "無法載入此資料來源的規則" }, @@ -2484,6 +2483,7 @@ "new-alert-rule": "新的警報規則", "new-datasource-recording-rule": "新的資料來源錄製規則", "new-grafana-recording-rule": "新的 Grafana 錄製規則", + "new-rule-for-export": "", "pagination": { "next-page": "顯示更多內容…" }, @@ -4547,6 +4547,10 @@ }, "edit-actions": { "add": "新增 {{typeName}}", + "add-conditional-rule": "", + "edit-query-result-rule": "", + "edit-template-variable-rule": "", + "edit-time-range-rule": "", "move": "移動 {{typeName}}", "panel-background": "變更面板背景", "panel-description": "變更面板描述", @@ -4561,6 +4565,7 @@ "edit-pane": { "elements": { "dashboard": "儀表板", + "element": "", "local-variable": "本機變數", "multiple-elements": "多個元素", "multiple-elements-delete-text": "確定要刪除這些元素嗎?", @@ -5768,7 +5773,6 @@ "move-action": "", "move-read-only-message": "", "moving": "", - "partial-failure-warning": "", "target-path-label": "", "title-this-repository-is-read-only": "" }, From 713c9921acb2f2e5c6a30515c946840f26428af7 Mon Sep 17 00:00:00 2001 From: Scott Lepper Date: Mon, 28 Jul 2025 01:49:38 -0400 Subject: [PATCH 020/131] Dashboards: Edit pane variable unique key (#107212) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Dashboards: Edit pane unique key * lint * Update public/app/features/dashboard/components/PanelEditor/OptionsPaneItemDescriptor.tsx Co-authored-by: Torkel Ödegaard * lint --------- Co-authored-by: Torkel Ödegaard --- .../PanelEditor/OptionsPaneItemDescriptor.tsx | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/public/app/features/dashboard/components/PanelEditor/OptionsPaneItemDescriptor.tsx b/public/app/features/dashboard/components/PanelEditor/OptionsPaneItemDescriptor.tsx index c9ff8e91ea8..b512ee41b1b 100644 --- a/public/app/features/dashboard/components/PanelEditor/OptionsPaneItemDescriptor.tsx +++ b/public/app/features/dashboard/components/PanelEditor/OptionsPaneItemDescriptor.tsx @@ -1,4 +1,5 @@ import { css } from '@emotion/css'; +import { uniqueId } from 'lodash'; import { ReactNode } from 'react'; import * as React from 'react'; import Highlighter from 'react-highlight-words'; @@ -31,11 +32,17 @@ export interface OptionsPaneItemInfo { */ export class OptionsPaneItemDescriptor { parent!: OptionsPaneCategoryDescriptor; + props: OptionsPaneItemInfo; - constructor(public props: OptionsPaneItemInfo) {} + constructor(props: OptionsPaneItemInfo) { + this.props = { ...props, id: props.id ?? props.title }; + if (this.props.id === '') { + this.props.id = uniqueId(); + } + } render(searchQuery?: string) { - return ; + return ; } useShowIf() { From d0b791000de182ebafed9ced2844d1ebed8558f0 Mon Sep 17 00:00:00 2001 From: Mariell Hoversholm Date: Mon, 28 Jul 2025 09:12:30 +0200 Subject: [PATCH 021/131] Docs: Update for certutil in container (#108751) Co-authored-by: Roman Pertl --- .../setup-grafana/image-rendering/troubleshooting/index.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/sources/setup-grafana/image-rendering/troubleshooting/index.md b/docs/sources/setup-grafana/image-rendering/troubleshooting/index.md index a2f472bce26..61cd711bd50 100644 --- a/docs/sources/setup-grafana/image-rendering/troubleshooting/index.md +++ b/docs/sources/setup-grafana/image-rendering/troubleshooting/index.md @@ -112,6 +112,11 @@ RUN update-ca-certificates --fresh # Reassume the nonroot user for the service execution. USER nonroot + +# Some CA certificates also need to explicitly be included in the user's network security services database. +# certutil is shipped in v4.0.8 and onwards of the image. +RUN mkdir -p /home/nonroot/.pki/nssdb +RUN certutil -d sql:/home/nonroot/.pki/nssdb -A -n internal-root-ca -t C -i /usr/local/share/ca-certificates/rootCA.crt ``` {{< admonition type="note" >}} From f4b4d8ec959471dd655596cf356d19f85f2e1417 Mon Sep 17 00:00:00 2001 From: antonio <45235678+tonypowa@users.noreply.github.com> Date: Mon, 28 Jul 2025 09:38:03 +0200 Subject: [PATCH 022/131] add video to alerting tutorial pt3 (#108743) --- docs/sources/tutorials/alerting-get-started-pt3/index.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/sources/tutorials/alerting-get-started-pt3/index.md b/docs/sources/tutorials/alerting-get-started-pt3/index.md index caed6c606f0..20141eee062 100644 --- a/docs/sources/tutorials/alerting-get-started-pt3/index.md +++ b/docs/sources/tutorials/alerting-get-started-pt3/index.md @@ -39,6 +39,8 @@ refs: This tutorial is a continuation of the [Get started with Grafana Alerting - Alert routing](http://www.grafana.com/tutorials/alerting-get-started-pt2/) tutorial. +{{< youtube id="WZ8gqKIQ5Oc" >}} + Grouping in Grafana Alerting reduces notification noise by combining related alert instances into a single, concise notification. This is useful for on-call engineers, ensuring they focus on resolving incidents instead of sorting through a flood of notifications. Grouping is configured using labels in the notification policy. These labels reference those generated by alert instances or configured by the user. From 4ad80cec1a1789fb49c69f421bbd312ed2e541e3 Mon Sep 17 00:00:00 2001 From: Alexander Akhmetov Date: Mon, 28 Jul 2025 10:09:26 +0200 Subject: [PATCH 023/131] Alerting: Validate extra configuration with PostableApiAlertingConfig (#108706) --- .../api/api_convert_prometheus_test.go | 33 ++++++- .../api/tooling/definitions/alertmanager.go | 8 +- .../tooling/definitions/alertmanager_test.go | 90 +++++++++++++++++++ 3 files changed, 127 insertions(+), 4 deletions(-) diff --git a/pkg/services/ngalert/api/api_convert_prometheus_test.go b/pkg/services/ngalert/api/api_convert_prometheus_test.go index 7478783da62..e5833280319 100644 --- a/pkg/services/ngalert/api/api_convert_prometheus_test.go +++ b/pkg/services/ngalert/api/api_convert_prometheus_test.go @@ -1567,7 +1567,18 @@ func TestRouteConvertPrometheusPostAlertmanagerConfig(t *testing.T) { ft := featuremgmt.WithFeatures(featuremgmt.FlagAlertingImportAlertmanagerAPI) srv, _, _ := createConvertPrometheusSrv(t, withAlertmanager(mockAM), withFeatureToggles(ft)) - amCfg := apimodels.AlertmanagerUserConfig{} + amCfg := apimodels.AlertmanagerUserConfig{ + AlertmanagerConfig: `{ + "route": { + "receiver": "default" + }, + "receivers": [ + { + "name": "default" + } + ] + }`, + } response := srv.RouteConvertPrometheusPostAlertmanagerConfig(rc, amCfg) require.Equal(t, http.StatusAccepted, response.Status()) @@ -1585,6 +1596,26 @@ func TestRouteConvertPrometheusPostAlertmanagerConfig(t *testing.T) { require.Equal(t, http.StatusBadRequest, response.Status()) require.Contains(t, string(response.Body()), "format should be 'key=value,key2=value2'") }) + + t.Run("should return error when alertmanager config has empty route", func(t *testing.T) { + rc := createRequestCtx() + rc.Req.Header.Set(configIdentifierHeader, identifier) + rc.Req.Header.Set(mergeMatchersHeader, "env=prod") + + amCfg := apimodels.AlertmanagerUserConfig{ + AlertmanagerConfig: `{ + "receivers": [ + { + "name": "default" + } + ] + }`, + } + response := srv.RouteConvertPrometheusPostAlertmanagerConfig(rc, amCfg) + + require.Equal(t, http.StatusBadRequest, response.Status()) + require.Contains(t, string(response.Body()), "failed to parse alertmanager config") + }) } func TestRouteConvertPrometheusGetAlertmanagerConfig(t *testing.T) { diff --git a/pkg/services/ngalert/api/tooling/definitions/alertmanager.go b/pkg/services/ngalert/api/tooling/definitions/alertmanager.go index c73486d277a..7cf30d3b702 100644 --- a/pkg/services/ngalert/api/tooling/definitions/alertmanager.go +++ b/pkg/services/ngalert/api/tooling/definitions/alertmanager.go @@ -745,12 +745,14 @@ func (c ExtraConfiguration) Validate() error { } } - // Alertmanager configuration is validated during YAML unmarshalling. - am := config.Config{} - err := yaml.Unmarshal([]byte(c.AlertmanagerConfig), &am) + cfg, err := c.GetAlertmanagerConfig() if err != nil { return errInvalidExtraConfiguration(fmt.Errorf("failed to parse alertmanager config: %w", err)) } + err = cfg.Validate() + if err != nil { + return errInvalidExtraConfiguration(fmt.Errorf("invalid alertmanager config: %w", err)) + } return nil } diff --git a/pkg/services/ngalert/api/tooling/definitions/alertmanager_test.go b/pkg/services/ngalert/api/tooling/definitions/alertmanager_test.go index 7c18af905e4..e6f074a7938 100644 --- a/pkg/services/ngalert/api/tooling/definitions/alertmanager_test.go +++ b/pkg/services/ngalert/api/tooling/definitions/alertmanager_test.go @@ -403,3 +403,93 @@ func TestPostableUserConfig_GetMergedTemplateDefinitions(t *testing.T) { }) } } + +func TestExtraConfiguration_Validate(t *testing.T) { + testCases := []struct { + name string + config ExtraConfiguration + expectedError string + }{ + { + name: "valid configuration", + config: ExtraConfiguration{ + Identifier: "test-config", + MergeMatchers: config.Matchers{{Type: labels.MatchEqual, Name: "env", Value: "prod"}}, + AlertmanagerConfig: `route: + receiver: default +receivers: + - name: default`, + }, + }, + { + name: "empty identifier", + config: ExtraConfiguration{ + Identifier: "", + MergeMatchers: config.Matchers{{Type: labels.MatchEqual, Name: "env", Value: "prod"}}, + AlertmanagerConfig: `route: {receiver: default}`, + }, + expectedError: "identifier is required", + }, + { + name: "invalid matcher type", + config: ExtraConfiguration{ + Identifier: "test-config", + MergeMatchers: config.Matchers{{Type: labels.MatchNotEqual, Name: "env", Value: "prod"}}, + AlertmanagerConfig: `route: + receiver: default +receivers: + - name: default`, + }, + expectedError: "only matchers with type equal are supported", + }, + { + name: "invalid YAML alertmanager config", + config: ExtraConfiguration{ + Identifier: "test-config", + MergeMatchers: config.Matchers{{Type: labels.MatchEqual, Name: "env", Value: "prod"}}, + AlertmanagerConfig: `invalid: yaml: content: [`, + }, + expectedError: "failed to parse alertmanager config", + }, + { + name: "missing route in alertmanager config", + config: ExtraConfiguration{ + Identifier: "test-config", + MergeMatchers: config.Matchers{{Type: labels.MatchEqual, Name: "env", Value: "prod"}}, + AlertmanagerConfig: `receivers: + - name: default`, + }, + expectedError: "no routes provided", + }, + { + name: "missing receivers in alertmanager config", + config: ExtraConfiguration{ + Identifier: "test-config", + MergeMatchers: config.Matchers{{Type: labels.MatchEqual, Name: "env", Value: "prod"}}, + AlertmanagerConfig: `route: + receiver: default`, + }, + expectedError: "undefined receiver", + }, + { + name: "empty alertmanager config", + config: ExtraConfiguration{ + Identifier: "test-config", + MergeMatchers: config.Matchers{{Type: labels.MatchEqual, Name: "env", Value: "prod"}}, + AlertmanagerConfig: "", + }, + expectedError: "failed to parse alertmanager config", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + err := tc.config.Validate() + if tc.expectedError == "" { + require.NoError(t, err) + } else { + require.ErrorContains(t, err, tc.expectedError) + } + }) + } +} From 3a285d9b166646ffe2a81831fae3cf05dc4b2979 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 28 Jul 2025 09:18:20 +0100 Subject: [PATCH 024/131] Update dependency eslint to v9.32.0 (#108711) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- packages/grafana-eslint-rules/package.json | 2 +- packages/grafana-plugin-configs/package.json | 2 +- yarn.lock | 47 ++++++++------------ 4 files changed, 22 insertions(+), 31 deletions(-) diff --git a/package.json b/package.json index 8f66957123b..af80f4b3e0d 100644 --- a/package.json +++ b/package.json @@ -185,7 +185,7 @@ "esbuild": "0.25.8", "esbuild-loader": "4.3.0", "esbuild-plugin-browserslist": "^1.0.0", - "eslint": "9.31.0", + "eslint": "9.32.0", "eslint-config-prettier": "9.1.0", "eslint-plugin-import": "^2.31.0", "eslint-plugin-jest": "28.11.0", diff --git a/packages/grafana-eslint-rules/package.json b/packages/grafana-eslint-rules/package.json index f83f1f679d9..71203b6d524 100644 --- a/packages/grafana-eslint-rules/package.json +++ b/packages/grafana-eslint-rules/package.json @@ -18,7 +18,7 @@ }, "devDependencies": { "@typescript-eslint/types": "^8.9.0", - "eslint": "9.31.0", + "eslint": "9.32.0", "tslib": "2.8.1" }, "private": true diff --git a/packages/grafana-plugin-configs/package.json b/packages/grafana-plugin-configs/package.json index 239138a9f4f..3ca7029e86d 100644 --- a/packages/grafana-plugin-configs/package.json +++ b/packages/grafana-plugin-configs/package.json @@ -15,7 +15,7 @@ "@types/eslint": "9.6.1", "@types/webpack-bundle-analyzer": "^4.7.0", "copy-webpack-plugin": "12.0.2", - "eslint": "9.31.0", + "eslint": "9.32.0", "eslint-webpack-plugin": "4.2.0", "fork-ts-checker-webpack-plugin": "9.1.0", "glob": "11.0.3", diff --git a/yarn.lock b/yarn.lock index 8aae2c14159..840ec969a1f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2289,16 +2289,7 @@ __metadata: languageName: node linkType: hard -"@eslint/core@npm:^0.14.0": - version: 0.14.0 - resolution: "@eslint/core@npm:0.14.0" - dependencies: - "@types/json-schema": "npm:^7.0.15" - checksum: 10/d9b060cf97468150675ddf4fb3db55edaa32467e0adf9f80919a5bfd15d0835ad7765456f4397ec2d16b0a1bb702af63f6d4712f94194d34fea118231ae1e2db - languageName: node - linkType: hard - -"@eslint/core@npm:^0.15.0": +"@eslint/core@npm:^0.15.0, @eslint/core@npm:^0.15.1": version: 0.15.1 resolution: "@eslint/core@npm:0.15.1" dependencies: @@ -2324,10 +2315,10 @@ __metadata: languageName: node linkType: hard -"@eslint/js@npm:9.31.0": - version: 9.31.0 - resolution: "@eslint/js@npm:9.31.0" - checksum: 10/83b45c707d9a6c62b79a9fb69b7ebcb31e8163647c0fdcae5972b4b2fcbbb1e8eac543986e0cca3582f8462a6587f6b6dc48e362b2ce3feb74282606c3d425ea +"@eslint/js@npm:9.32.0": + version: 9.32.0 + resolution: "@eslint/js@npm:9.32.0" + checksum: 10/a833083a74ed99486c9b72f9be3497ca744692feca12ade7e32119e4b29aba21592055422589a282ed64c46e86b595f147a5270011131a4ea5a2628892bfaf1d languageName: node linkType: hard @@ -2338,13 +2329,13 @@ __metadata: languageName: node linkType: hard -"@eslint/plugin-kit@npm:^0.3.1": - version: 0.3.1 - resolution: "@eslint/plugin-kit@npm:0.3.1" +"@eslint/plugin-kit@npm:^0.3.4": + version: 0.3.4 + resolution: "@eslint/plugin-kit@npm:0.3.4" dependencies: - "@eslint/core": "npm:^0.14.0" + "@eslint/core": "npm:^0.15.1" levn: "npm:^0.4.1" - checksum: 10/ab0c4cecadc6c38c7ae5f71b9831d3521d08237444d8f327751d1133a4369ccd42093a1c06b26fd6c311015807a27d95a0184a761d1cdd264b090896dcf0addb + checksum: 10/9d22a43cbca18e04e818189b63ffabe9128aeea1cf820ffce1e1bcf6446b93778102afc61aff485213eb9bef5b104aad6100b9c9245c28bba566405353377da2 languageName: node linkType: hard @@ -3219,7 +3210,7 @@ __metadata: dependencies: "@typescript-eslint/types": "npm:^8.9.0" "@typescript-eslint/utils": "npm:^8.9.0" - eslint: "npm:9.31.0" + eslint: "npm:9.32.0" tslib: "npm:2.8.1" languageName: unknown linkType: soft @@ -3435,7 +3426,7 @@ __metadata: "@types/eslint": "npm:9.6.1" "@types/webpack-bundle-analyzer": "npm:^4.7.0" copy-webpack-plugin: "npm:12.0.2" - eslint: "npm:9.31.0" + eslint: "npm:9.32.0" eslint-webpack-plugin: "npm:4.2.0" fork-ts-checker-webpack-plugin: "npm:9.1.0" glob: "npm:11.0.3" @@ -16308,9 +16299,9 @@ __metadata: languageName: node linkType: hard -"eslint@npm:9.31.0": - version: 9.31.0 - resolution: "eslint@npm:9.31.0" +"eslint@npm:9.32.0": + version: 9.32.0 + resolution: "eslint@npm:9.32.0" dependencies: "@eslint-community/eslint-utils": "npm:^4.2.0" "@eslint-community/regexpp": "npm:^4.12.1" @@ -16318,8 +16309,8 @@ __metadata: "@eslint/config-helpers": "npm:^0.3.0" "@eslint/core": "npm:^0.15.0" "@eslint/eslintrc": "npm:^3.3.1" - "@eslint/js": "npm:9.31.0" - "@eslint/plugin-kit": "npm:^0.3.1" + "@eslint/js": "npm:9.32.0" + "@eslint/plugin-kit": "npm:^0.3.4" "@humanfs/node": "npm:^0.16.6" "@humanwhocodes/module-importer": "npm:^1.0.1" "@humanwhocodes/retry": "npm:^0.4.2" @@ -16354,7 +16345,7 @@ __metadata: optional: true bin: eslint: bin/eslint.js - checksum: 10/badfe1b62ee44dd389838ab27d6ca4f8a3159743a28c3145edd68af15db33fdacb13f096acdc2c559e9c8774d42fe3e1c513d5539d3297bfe8f342e3e4cfee33 + checksum: 10/0f8cda1fa09ae188dd90bab21212f5cfca92373b93e91361cf4e2b511b5554d6cca31153dd11f0566210fb97a78b9267ed3d207607788b81880d19effe531085 languageName: node linkType: hard @@ -18320,7 +18311,7 @@ __metadata: esbuild: "npm:0.25.8" esbuild-loader: "npm:4.3.0" esbuild-plugin-browserslist: "npm:^1.0.0" - eslint: "npm:9.31.0" + eslint: "npm:9.32.0" eslint-config-prettier: "npm:9.1.0" eslint-plugin-import: "npm:^2.31.0" eslint-plugin-jest: "npm:28.11.0" From f9b34baa357a6364b5449ef204bc091410c2f010 Mon Sep 17 00:00:00 2001 From: Mihai Doarna Date: Mon, 28 Jul 2025 11:31:33 +0300 Subject: [PATCH 025/131] SCIM: Add flag for rejecting non provisioned users from logging in (#108568) add flag for rejecting non provisioned users from logging in --- .../authn/authnimpl/sync/user_sync.go | 36 +++-- .../authn/authnimpl/sync/user_sync_test.go | 147 ++++++++++++------ pkg/services/scimutil/scim_util.go | 34 ++-- pkg/services/scimutil/scim_util_test.go | 92 +++++------ 4 files changed, 181 insertions(+), 128 deletions(-) diff --git a/pkg/services/authn/authnimpl/sync/user_sync.go b/pkg/services/authn/authnimpl/sync/user_sync.go index 7516c840ccc..a82b1434152 100644 --- a/pkg/services/authn/authnimpl/sync/user_sync.go +++ b/pkg/services/authn/authnimpl/sync/user_sync.go @@ -84,8 +84,8 @@ var ( // StaticSCIMConfig represents the static SCIM configuration from config.ini type StaticSCIMConfig struct { - AllowNonProvisionedUsers bool IsUserProvisioningEnabled bool + RejectNonProvisionedUsers bool } func ProvideUserSync(userService user.Service, userProtectionService login.UserProtectionService, authInfoService login.AuthInfoService, @@ -94,13 +94,13 @@ func ProvideUserSync(userService user.Service, userProtectionService login.UserP ) *UserSync { scimSection := cfg.Raw.Section("auth.scim") staticConfig := &StaticSCIMConfig{ - AllowNonProvisionedUsers: scimSection.Key("allow_non_provisioned_users").MustBool(false), IsUserProvisioningEnabled: scimSection.Key("user_sync_enabled").MustBool(false), + RejectNonProvisionedUsers: scimSection.Key("reject_non_provisioned_users").MustBool(false), } return &UserSync{ - allowNonProvisionedUsers: staticConfig.AllowNonProvisionedUsers, isUserProvisioningEnabled: staticConfig.IsUserProvisioningEnabled, + rejectNonProvisionedUsers: staticConfig.RejectNonProvisionedUsers, userService: userService, authInfoService: authInfoService, userProtectionService: userProtectionService, @@ -115,8 +115,8 @@ func ProvideUserSync(userService user.Service, userProtectionService login.UserP } type UserSync struct { - allowNonProvisionedUsers bool isUserProvisioningEnabled bool + rejectNonProvisionedUsers bool userService user.Service authInfoService login.AuthInfoService userProtectionService login.UserProtectionService @@ -187,9 +187,13 @@ func (s *UserSync) ValidateUserProvisioningHook(ctx context.Context, currentIden return nil } - // Reject non-provisioned users - log.Error("Failed to access user, user is not provisioned") - return errUserNotProvisioned.Errorf("user is not provisioned") + // Reject non-provisioned users if configured to do so + if s.shouldRejectNonProvisionedUsers(ctx, currentIdentity) { + log.Error("Failed to authenticate user, user is not provisioned") + return errUserNotProvisioned.Errorf("user is not provisioned") + } + + return nil } func (s *UserSync) skipProvisioningValidation(ctx context.Context, currentIdentity *authn.Identity) bool { @@ -197,12 +201,10 @@ func (s *UserSync) skipProvisioningValidation(ctx context.Context, currentIdenti // Use dynamic SCIM settings if available, otherwise fall back to static config effectiveUserSyncEnabled := s.isUserProvisioningEnabled - effectiveAllowNonProvisionedUsers := s.allowNonProvisionedUsers if s.scimUtil != nil { orgID := currentIdentity.GetOrgID() effectiveUserSyncEnabled = s.scimUtil.IsUserSyncEnabled(ctx, orgID, s.staticConfig.IsUserProvisioningEnabled) - effectiveAllowNonProvisionedUsers = s.scimUtil.AreNonProvisionedUsersAllowed(ctx, orgID, s.staticConfig.AllowNonProvisionedUsers) } if !effectiveUserSyncEnabled { @@ -210,11 +212,6 @@ func (s *UserSync) skipProvisioningValidation(ctx context.Context, currentIdenti return true } - if effectiveAllowNonProvisionedUsers { - log.Debug("Non-provisioned users are allowed, skipping validation") - return true - } - if currentIdentity.AuthenticatedBy == login.GrafanaComAuthModule { log.Debug("User is authenticated via GrafanaComAuthModule, skipping validation") return true @@ -223,6 +220,17 @@ func (s *UserSync) skipProvisioningValidation(ctx context.Context, currentIdenti return false } +func (s *UserSync) shouldRejectNonProvisionedUsers(ctx context.Context, currentIdentity *authn.Identity) bool { + effectiveRejectNonProvisionedUsers := s.rejectNonProvisionedUsers + + if s.scimUtil != nil { + orgID := currentIdentity.GetOrgID() + effectiveRejectNonProvisionedUsers = s.scimUtil.AreNonProvisionedUsersRejected(ctx, orgID, s.staticConfig.RejectNonProvisionedUsers) + } + + return effectiveRejectNonProvisionedUsers +} + // SyncUserHook syncs a user with the database func (s *UserSync) SyncUserHook(ctx context.Context, id *authn.Identity, _ *authn.Request) error { ctx, span := s.tracer.Start(ctx, "user.sync.SyncUserHook") diff --git a/pkg/services/authn/authnimpl/sync/user_sync_test.go b/pkg/services/authn/authnimpl/sync/user_sync_test.go index 04be22dac89..49e50f55fdc 100644 --- a/pkg/services/authn/authnimpl/sync/user_sync_test.go +++ b/pkg/services/authn/authnimpl/sync/user_sync_test.go @@ -1092,11 +1092,24 @@ func TestUserSync_ValidateUserProvisioningHook(t *testing.T) { }, }, { - desc: "it should skip validation if allowedNonProvisionedUsers is enabled", + desc: "it should skip validation if rejectNonProvisionedUsers is disabled", userSyncServiceSetup: func() *UserSync { userSyncService := initUserSyncService() - userSyncService.allowNonProvisionedUsers = true + userSyncService.rejectNonProvisionedUsers = false userSyncService.isUserProvisioningEnabled = true + userSyncService.userService = &usertest.FakeUserService{ + ExpectedUser: &user.User{ + ID: 1, + IsProvisioned: false, + }, + } + userSyncService.authInfoService = &authinfotest.FakeService{ + ExpectedUserAuth: &login.UserAuth{ + UserId: 1, + AuthModule: login.GenericOAuthModule, + AuthId: "1", + }, + } return userSyncService }, identity: &authn.Identity{ @@ -1111,7 +1124,7 @@ func TestUserSync_ValidateUserProvisioningHook(t *testing.T) { desc: "it should skip validation if the user is authenticated via GrafanaComAuthModule", userSyncServiceSetup: func() *UserSync { userSyncService := initUserSyncService() - userSyncService.allowNonProvisionedUsers = false + userSyncService.rejectNonProvisionedUsers = true userSyncService.isUserProvisioningEnabled = true return userSyncService }, @@ -1127,7 +1140,7 @@ func TestUserSync_ValidateUserProvisioningHook(t *testing.T) { desc: "it should fail to validate the identity with the provisioned user, unexpected error", userSyncServiceSetup: func() *UserSync { userSyncService := initUserSyncService() - userSyncService.allowNonProvisionedUsers = false + userSyncService.rejectNonProvisionedUsers = true userSyncService.isUserProvisioningEnabled = true userSyncService.userService = &usertest.FakeUserService{ ExpectedError: errors.New("random error"), @@ -1148,7 +1161,7 @@ func TestUserSync_ValidateUserProvisioningHook(t *testing.T) { desc: "it should fail to validate the identity with the provisioned user, no user found", userSyncServiceSetup: func() *UserSync { userSyncService := initUserSyncService() - userSyncService.allowNonProvisionedUsers = false + userSyncService.rejectNonProvisionedUsers = true userSyncService.isUserProvisioningEnabled = true userSyncService.userService = &usertest.FakeUserService{} return userSyncService @@ -1167,7 +1180,7 @@ func TestUserSync_ValidateUserProvisioningHook(t *testing.T) { desc: "it should fail to validate the provisioned user.ExternalUID with the identity.ExternalUID - empty ExternalUID", userSyncServiceSetup: func() *UserSync { userSyncService := initUserSyncService() - userSyncService.allowNonProvisionedUsers = false + userSyncService.rejectNonProvisionedUsers = true userSyncService.isUserProvisioningEnabled = true userSyncService.userService = &usertest.FakeUserService{ ExpectedUser: &user.User{ @@ -1198,7 +1211,7 @@ func TestUserSync_ValidateUserProvisioningHook(t *testing.T) { desc: "it should fail to validate the provisioned user.ExternalUID with the identity.ExternalUID - different ExternalUID", userSyncServiceSetup: func() *UserSync { userSyncService := initUserSyncService() - userSyncService.allowNonProvisionedUsers = false + userSyncService.rejectNonProvisionedUsers = true userSyncService.isUserProvisioningEnabled = true userSyncService.userService = &usertest.FakeUserService{ ExpectedUser: &user.User{ @@ -1230,7 +1243,7 @@ func TestUserSync_ValidateUserProvisioningHook(t *testing.T) { desc: "it should successfully validate the provisioned user.ExternalUID with the identity.ExternalUID", userSyncServiceSetup: func() *UserSync { userSyncService := initUserSyncService() - userSyncService.allowNonProvisionedUsers = false + userSyncService.rejectNonProvisionedUsers = true userSyncService.isUserProvisioningEnabled = true userSyncService.userService = &usertest.FakeUserService{ ExpectedUser: &user.User{ @@ -1259,10 +1272,10 @@ func TestUserSync_ValidateUserProvisioningHook(t *testing.T) { expectedErr: nil, }, { - desc: "it should failed to validate a non provisioned user when retrieved from the database", + desc: "it should fail to validate a non provisioned user when configured to reject non provisioned users", userSyncServiceSetup: func() *UserSync { userSyncService := initUserSyncService() - userSyncService.allowNonProvisionedUsers = false + userSyncService.rejectNonProvisionedUsers = true userSyncService.isUserProvisioningEnabled = true userSyncService.userService = &usertest.FakeUserService{ ExpectedUser: &user.User{ @@ -1290,6 +1303,38 @@ func TestUserSync_ValidateUserProvisioningHook(t *testing.T) { }, expectedErr: errUserNotProvisioned.Errorf("user is not provisioned"), }, + { + desc: "it should skip to validate a non provisioned user when configured to allow non provisioned users", + userSyncServiceSetup: func() *UserSync { + userSyncService := initUserSyncService() + userSyncService.rejectNonProvisionedUsers = false + userSyncService.isUserProvisioningEnabled = true + userSyncService.userService = &usertest.FakeUserService{ + ExpectedUser: &user.User{ + ID: 1, + IsProvisioned: false, + }, + } + userSyncService.authInfoService = &authinfotest.FakeService{ + ExpectedUserAuth: &login.UserAuth{ + UserId: 1, + AuthModule: login.SAMLAuthModule, + AuthId: "1", + ExternalUID: "random-external-uid", + }, + } + return userSyncService + }, + identity: &authn.Identity{ + AuthenticatedBy: login.SAMLAuthModule, + AuthID: "1", + ExternalUID: "different-external-uid", + ClientParams: authn.ClientParams{ + SyncUser: true, + }, + }, + expectedErr: nil, + }, { desc: "ValidateProvisioning: DB ExternalUID is empty, Incoming ExternalUID is empty - expect mismatch (stricter logic)", userSyncServiceSetup: func() *UserSync { @@ -1351,7 +1396,7 @@ func TestUserSync_ValidateUserProvisioningHook(t *testing.T) { desc: "it should skip ExternalUID validation for a SAML-provisioned user accessed by a non-SAML method with an empty incoming ExternalUID", userSyncServiceSetup: func() *UserSync { userSyncService := initUserSyncService() - userSyncService.allowNonProvisionedUsers = false + userSyncService.rejectNonProvisionedUsers = false userSyncService.isUserProvisioningEnabled = true userSyncService.userService = &usertest.FakeUserService{ ExpectedUser: &user.User{ @@ -1380,7 +1425,7 @@ func TestUserSync_ValidateUserProvisioningHook(t *testing.T) { desc: "it should fail validation when a provisioned user is accessed by SAML with an empty incoming ExternalUID", userSyncServiceSetup: func() *UserSync { userSyncService := initUserSyncService() - userSyncService.allowNonProvisionedUsers = false + userSyncService.rejectNonProvisionedUsers = true userSyncService.isUserProvisioningEnabled = true userSyncService.userService = &usertest.FakeUserService{ ExpectedUser: &user.User{ @@ -1425,10 +1470,10 @@ func TestUserSync_SCIMUtilIntegration(t *testing.T) { // Mock SCIM utility for testing type mockSCIMUtil struct { - userSyncEnabled bool - nonProvisionedUsersAllowed bool - shouldUseDynamicConfig bool - shouldReturnError bool + userSyncEnabled bool + nonProvisionedUsersRejected bool + shouldUseDynamicConfig bool + shouldReturnError bool } createMockSCIMUtil := func(mockCfg *mockSCIMUtil) *scimutil.SCIMUtil { @@ -1453,9 +1498,9 @@ func TestUserSync_SCIMUtilIntegration(t *testing.T) { "namespace": "default", }, "spec": map[string]interface{}{ - "enableUserSync": mockCfg.userSyncEnabled, - "enableGroupSync": false, // Not used for this test - "allowNonProvisionedUsers": mockCfg.nonProvisionedUsersAllowed, + "enableUserSync": mockCfg.userSyncEnabled, + "enableGroupSync": false, // Not used for this test + "rejectNonProvisionedUsers": mockCfg.nonProvisionedUsersRejected, }, }, } @@ -1467,13 +1512,13 @@ func TestUserSync_SCIMUtilIntegration(t *testing.T) { } tests := []struct { - name string - identity *authn.Identity - staticConfig *StaticSCIMConfig - mockSCIMUtil *mockSCIMUtil - expectedUserSyncEnabled bool - expectedNonProvisionedAllowed bool - expectedError error + name string + identity *authn.Identity + staticConfig *StaticSCIMConfig + mockSCIMUtil *mockSCIMUtil + expectedUserSyncEnabled bool + expectedNonProvisionedRejected bool + expectedError error }{ { name: "SCIM util nil - uses static config", @@ -1483,11 +1528,11 @@ func TestUserSync_SCIMUtilIntegration(t *testing.T) { }, staticConfig: &StaticSCIMConfig{ IsUserProvisioningEnabled: true, - AllowNonProvisionedUsers: false, + RejectNonProvisionedUsers: false, }, - mockSCIMUtil: nil, // No SCIM util - expectedUserSyncEnabled: true, - expectedNonProvisionedAllowed: false, + mockSCIMUtil: nil, // No SCIM util + expectedUserSyncEnabled: true, + expectedNonProvisionedRejected: false, }, { name: "SCIM util with dynamic config - user sync enabled", @@ -1497,15 +1542,15 @@ func TestUserSync_SCIMUtilIntegration(t *testing.T) { }, staticConfig: &StaticSCIMConfig{ IsUserProvisioningEnabled: false, // Static disabled - AllowNonProvisionedUsers: false, + RejectNonProvisionedUsers: true, }, mockSCIMUtil: &mockSCIMUtil{ - userSyncEnabled: true, // Dynamic enabled - nonProvisionedUsersAllowed: true, - shouldUseDynamicConfig: true, + userSyncEnabled: true, // Dynamic enabled + nonProvisionedUsersRejected: true, + shouldUseDynamicConfig: true, }, - expectedUserSyncEnabled: true, - expectedNonProvisionedAllowed: true, + expectedUserSyncEnabled: true, + expectedNonProvisionedRejected: true, }, { name: "SCIM util with dynamic config - user sync disabled", @@ -1515,15 +1560,15 @@ func TestUserSync_SCIMUtilIntegration(t *testing.T) { }, staticConfig: &StaticSCIMConfig{ IsUserProvisioningEnabled: true, // Static enabled - AllowNonProvisionedUsers: true, + RejectNonProvisionedUsers: true, }, mockSCIMUtil: &mockSCIMUtil{ - userSyncEnabled: false, // Dynamic disabled - nonProvisionedUsersAllowed: false, - shouldUseDynamicConfig: true, + userSyncEnabled: false, // Dynamic disabled + nonProvisionedUsersRejected: false, + shouldUseDynamicConfig: true, }, - expectedUserSyncEnabled: false, - expectedNonProvisionedAllowed: false, + expectedUserSyncEnabled: false, + expectedNonProvisionedRejected: false, }, { name: "SCIM util with error - falls back to static config", @@ -1533,13 +1578,13 @@ func TestUserSync_SCIMUtilIntegration(t *testing.T) { }, staticConfig: &StaticSCIMConfig{ IsUserProvisioningEnabled: true, - AllowNonProvisionedUsers: false, + RejectNonProvisionedUsers: false, }, mockSCIMUtil: &mockSCIMUtil{ shouldReturnError: true, }, - expectedUserSyncEnabled: true, - expectedNonProvisionedAllowed: false, + expectedUserSyncEnabled: true, + expectedNonProvisionedRejected: false, }, } @@ -1559,14 +1604,14 @@ func TestUserSync_SCIMUtilIntegration(t *testing.T) { } assert.Equal(t, tt.expectedUserSyncEnabled, userSyncEnabled, "User sync enabled mismatch") - // Test non-provisioned users allowed check - var nonProvisionedAllowed bool + // Test non-provisioned users rejected check + var nonProvisionedReject bool if userSync.scimUtil != nil { - nonProvisionedAllowed = userSync.scimUtil.AreNonProvisionedUsersAllowed(ctx, orgID, tt.staticConfig.AllowNonProvisionedUsers) + nonProvisionedReject = userSync.scimUtil.AreNonProvisionedUsersRejected(ctx, orgID, tt.staticConfig.RejectNonProvisionedUsers) } else { - nonProvisionedAllowed = tt.staticConfig.AllowNonProvisionedUsers + nonProvisionedReject = tt.staticConfig.RejectNonProvisionedUsers } - assert.Equal(t, tt.expectedNonProvisionedAllowed, nonProvisionedAllowed, "Non-provisioned users allowed mismatch") + assert.Equal(t, tt.expectedNonProvisionedRejected, nonProvisionedReject, "Non-provisioned users rejected mismatch") }) } } @@ -1765,7 +1810,7 @@ func TestUserSync_GetUsageStats(t *testing.T) { func TestUserSync_SCIMLoginUsageStatSet(t *testing.T) { userSync := initUserSyncService() - userSync.allowNonProvisionedUsers = false + userSync.rejectNonProvisionedUsers = false userSync.isUserProvisioningEnabled = true userSync.userService = &usertest.FakeUserService{ ExpectedUser: &user.User{ diff --git a/pkg/services/scimutil/scim_util.go b/pkg/services/scimutil/scim_util.go index 92d0ac74270..30998d4f5d9 100644 --- a/pkg/services/scimutil/scim_util.go +++ b/pkg/services/scimutil/scim_util.go @@ -44,23 +44,23 @@ func (s *SCIMUtil) IsUserSyncEnabled(ctx context.Context, orgID int64, staticEna return staticEnabled } -// AreNonProvisionedUsersAllowed checks if non-provisioned users are allowed using dynamic configuration with static fallback -func (s *SCIMUtil) AreNonProvisionedUsersAllowed(ctx context.Context, orgID int64, staticAllowed bool) bool { +// AreNonProvisionedUsersRejected checks if non-provisioned users are rejected using dynamic configuration with static fallback +func (s *SCIMUtil) AreNonProvisionedUsersRejected(ctx context.Context, orgID int64, staticRejected bool) bool { if s.k8sClient == nil { s.logger.Debug("K8s client not configured, using static SCIM config for non-provisioned users") - return staticAllowed + return staticRejected } - dynamicAllowed, dynamicConfigFetched := s.fetchDynamicSCIMSetting(ctx, orgID, "allowNonProvisionedUsers") + dynamicRejected, dynamicConfigFetched := s.fetchDynamicSCIMSetting(ctx, orgID, "rejectNonProvisionedUsers") if dynamicConfigFetched { - s.logger.Debug("Using dynamic SCIM config for user sync", "orgID", orgID, "enabled", dynamicAllowed) - return dynamicAllowed + s.logger.Debug("Using dynamic SCIM config for user sync", "orgID", orgID, "enabled", dynamicRejected) + return dynamicRejected } // Fallback to static config if dynamic config wasn't fetched successfully - s.logger.Debug("Using static SCIM config for user sync", "orgID", orgID, "enabled", staticAllowed) - return staticAllowed + s.logger.Debug("Using static SCIM config for user sync", "orgID", orgID, "enabled", staticRejected) + return staticRejected } // fetchDynamicSCIMSetting attempts to retrieve a specific dynamic SCIM configuration setting @@ -82,8 +82,8 @@ func (s *SCIMUtil) fetchDynamicSCIMSetting(ctx context.Context, orgID int64, set enabled = scimConfig.EnableUserSync case "group": enabled = scimConfig.EnableGroupSync - case "allowNonProvisionedUsers": - enabled = scimConfig.AllowNonProvisionedUsers + case "rejectNonProvisionedUsers": + enabled = scimConfig.RejectNonProvisionedUsers default: s.logger.Error("Invalid setting type provided to fetchDynamicSCIMSetting", "settingType", settingType) return false, false @@ -108,9 +108,9 @@ func (s *SCIMUtil) getOrgSCIMConfig(ctx context.Context, orgID int64) (*SCIMConf // SCIMConfigSpec represents the spec part of a SCIMConfig resource type SCIMConfigSpec struct { - EnableUserSync bool `json:"enableUserSync"` - EnableGroupSync bool `json:"enableGroupSync"` - AllowNonProvisionedUsers bool `json:"allowNonProvisionedUsers"` + EnableUserSync bool `json:"enableUserSync"` + EnableGroupSync bool `json:"enableGroupSync"` + RejectNonProvisionedUsers bool `json:"rejectNonProvisionedUsers"` } // unstructuredToSCIMConfig converts an unstructured object to a SCIMConfigSpec @@ -130,11 +130,11 @@ func (s *SCIMUtil) unstructuredToSCIMConfig(obj *unstructured.Unstructured) (*SC enableUserSync, _, _ := unstructured.NestedBool(spec, "enableUserSync") enableGroupSync, _, _ := unstructured.NestedBool(spec, "enableGroupSync") - allowNonProvisionedUsers, _, _ := unstructured.NestedBool(spec, "allowNonProvisionedUsers") + rejectNonProvisionedUsers, _, _ := unstructured.NestedBool(spec, "rejectNonProvisionedUsers") return &SCIMConfigSpec{ - EnableUserSync: enableUserSync, - EnableGroupSync: enableGroupSync, - AllowNonProvisionedUsers: allowNonProvisionedUsers, + EnableUserSync: enableUserSync, + EnableGroupSync: enableGroupSync, + RejectNonProvisionedUsers: rejectNonProvisionedUsers, }, nil } diff --git a/pkg/services/scimutil/scim_util_test.go b/pkg/services/scimutil/scim_util_test.go index 0e9d3b39ee5..f1350402e85 100644 --- a/pkg/services/scimutil/scim_util_test.go +++ b/pkg/services/scimutil/scim_util_test.go @@ -213,33 +213,33 @@ func TestSCIMUtil_IsUserSyncEnabled(t *testing.T) { } } -func TestSCIMUtil_AreNonProvisionedUsersAllowed(t *testing.T) { +func TestSCIMUtil_AreNonProvisionedUsersRejected(t *testing.T) { ctx := context.Background() orgID := int64(1) tests := []struct { name string k8sClient client.K8sHandler - staticAllowed bool + staticRejected bool expectedResult bool setupMock func(*MockK8sHandler) }{ { name: "k8s client nil - returns static config", k8sClient: nil, - staticAllowed: true, + staticRejected: true, expectedResult: true, }, { name: "k8s client nil - returns static config false", k8sClient: nil, - staticAllowed: false, + staticRejected: false, expectedResult: false, }, { - name: "k8s client error - falls back to static config", - k8sClient: &MockK8sHandler{}, - staticAllowed: true, + name: "k8s client error - falls back to static config", + k8sClient: &MockK8sHandler{}, + staticRejected: true, setupMock: func(mockHandler *MockK8sHandler) { mockHandler.On("Get", ctx, "default", orgID, metav1.GetOptions{}, mock.Anything). Return(nil, errors.New("k8s error")) @@ -247,9 +247,9 @@ func TestSCIMUtil_AreNonProvisionedUsersAllowed(t *testing.T) { expectedResult: true, }, { - name: "dynamic config user sync enabled - non-provisioned users allowed", - k8sClient: &MockK8sHandler{}, - staticAllowed: false, + name: "dynamic config user sync enabled - non-provisioned users rejected", + k8sClient: &MockK8sHandler{}, + staticRejected: false, setupMock: func(mockHandler *MockK8sHandler) { obj := createMockSCIMConfigWithNonProvisioned(true, false, true) mockHandler.On("Get", ctx, "default", orgID, metav1.GetOptions{}, mock.Anything). @@ -258,9 +258,9 @@ func TestSCIMUtil_AreNonProvisionedUsersAllowed(t *testing.T) { expectedResult: true, }, { - name: "dynamic config user sync disabled - non-provisioned users not allowed", - k8sClient: &MockK8sHandler{}, - staticAllowed: true, + name: "dynamic config user sync disabled - non-provisioned users allowed", + k8sClient: &MockK8sHandler{}, + staticRejected: true, setupMock: func(mockHandler *MockK8sHandler) { obj := createMockSCIMConfigWithNonProvisioned(false, true, false) mockHandler.On("Get", ctx, "default", orgID, metav1.GetOptions{}, mock.Anything). @@ -269,9 +269,9 @@ func TestSCIMUtil_AreNonProvisionedUsersAllowed(t *testing.T) { expectedResult: false, }, { - name: "dynamic config both settings disabled - non-provisioned users not allowed", - k8sClient: &MockK8sHandler{}, - staticAllowed: true, + name: "dynamic config both settings disabled - non-provisioned users allowed", + k8sClient: &MockK8sHandler{}, + staticRejected: true, setupMock: func(mockHandler *MockK8sHandler) { obj := createMockSCIMConfigWithNonProvisioned(false, false, false) mockHandler.On("Get", ctx, "default", orgID, metav1.GetOptions{}, mock.Anything). @@ -280,9 +280,9 @@ func TestSCIMUtil_AreNonProvisionedUsersAllowed(t *testing.T) { expectedResult: false, }, { - name: "dynamic config both settings enabled - non-provisioned users allowed", - k8sClient: &MockK8sHandler{}, - staticAllowed: false, + name: "dynamic config both settings enabled - non-provisioned users rejected", + k8sClient: &MockK8sHandler{}, + staticRejected: false, setupMock: func(mockHandler *MockK8sHandler) { obj := createMockSCIMConfigWithNonProvisioned(true, true, true) mockHandler.On("Get", ctx, "default", orgID, metav1.GetOptions{}, mock.Anything). @@ -299,7 +299,7 @@ func TestSCIMUtil_AreNonProvisionedUsersAllowed(t *testing.T) { } util := NewSCIMUtil(tt.k8sClient) - result := util.AreNonProvisionedUsersAllowed(ctx, orgID, tt.staticAllowed) + result := util.AreNonProvisionedUsersRejected(ctx, orgID, tt.staticRejected) assert.Equal(t, tt.expectedResult, result) @@ -449,9 +449,9 @@ func TestSCIMUtil_fetchDynamicSCIMSetting(t *testing.T) { }, }, { - name: "allowNonProvisionedUsers setting enabled", + name: "rejectNonProvisionedUsers setting enabled", k8sClient: &MockK8sHandler{}, - settingType: "allowNonProvisionedUsers", + settingType: "rejectNonProvisionedUsers", expectedEnabled: true, expectedDynamicFetched: true, setupMock: func(mockHandler *MockK8sHandler) { @@ -461,9 +461,9 @@ func TestSCIMUtil_fetchDynamicSCIMSetting(t *testing.T) { }, }, { - name: "allowNonProvisionedUsers setting disabled", + name: "rejectNonProvisionedUsers setting disabled", k8sClient: &MockK8sHandler{}, - settingType: "allowNonProvisionedUsers", + settingType: "rejectNonProvisionedUsers", expectedEnabled: false, expectedDynamicFetched: true, setupMock: func(mockHandler *MockK8sHandler) { @@ -570,36 +570,36 @@ func TestSCIMUtil_unstructuredToSCIMConfig(t *testing.T) { name: "valid object with both settings enabled", obj: createMockSCIMConfig(true, true), expectedSpec: SCIMConfigSpec{ - EnableUserSync: true, - EnableGroupSync: true, - AllowNonProvisionedUsers: false, + EnableUserSync: true, + EnableGroupSync: true, + RejectNonProvisionedUsers: false, }, }, { name: "valid object with both settings disabled", obj: createMockSCIMConfig(false, false), expectedSpec: SCIMConfigSpec{ - EnableUserSync: false, - EnableGroupSync: false, - AllowNonProvisionedUsers: false, + EnableUserSync: false, + EnableGroupSync: false, + RejectNonProvisionedUsers: false, }, }, { name: "valid object with mixed settings", obj: createMockSCIMConfig(true, false), expectedSpec: SCIMConfigSpec{ - EnableUserSync: true, - EnableGroupSync: false, - AllowNonProvisionedUsers: false, + EnableUserSync: true, + EnableGroupSync: false, + RejectNonProvisionedUsers: false, }, }, { - name: "valid object with allowNonProvisionedUsers enabled", + name: "valid object with rejectNonProvisionedUsers enabled", obj: createMockSCIMConfigWithNonProvisioned(false, false, true), expectedSpec: SCIMConfigSpec{ - EnableUserSync: false, - EnableGroupSync: false, - AllowNonProvisionedUsers: true, + EnableUserSync: false, + EnableGroupSync: false, + RejectNonProvisionedUsers: true, }, }, { @@ -641,7 +641,7 @@ func createMockSCIMConfig(userSyncEnabled, groupSyncEnabled bool) *unstructured. } // Helper function to create a mock SCIMConfig unstructured object with non-provisioned users setting -func createMockSCIMConfigWithNonProvisioned(userSyncEnabled, groupSyncEnabled, allowNonProvisionedUsers bool) *unstructured.Unstructured { +func createMockSCIMConfigWithNonProvisioned(userSyncEnabled, groupSyncEnabled, rejectNonProvisionedUsers bool) *unstructured.Unstructured { return &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "scim.grafana.com/v0alpha1", @@ -651,9 +651,9 @@ func createMockSCIMConfigWithNonProvisioned(userSyncEnabled, groupSyncEnabled, a "namespace": "default", }, "spec": map[string]interface{}{ - "enableUserSync": userSyncEnabled, - "enableGroupSync": groupSyncEnabled, - "allowNonProvisionedUsers": allowNonProvisionedUsers, + "enableUserSync": userSyncEnabled, + "enableGroupSync": groupSyncEnabled, + "rejectNonProvisionedUsers": rejectNonProvisionedUsers, }, }, } @@ -676,9 +676,9 @@ func TestSCIMUtil_Integration(t *testing.T) { userSyncEnabled := util.IsUserSyncEnabled(ctx, orgID, false) assert.True(t, userSyncEnabled) - // Test non-provisioned users allowed - nonProvisionedAllowed := util.AreNonProvisionedUsersAllowed(ctx, orgID, false) - assert.True(t, nonProvisionedAllowed) + // Test non-provisioned users rejected + nonProvisionedRejected := util.AreNonProvisionedUsersRejected(ctx, orgID, false) + assert.True(t, nonProvisionedRejected) mockClient.AssertExpectations(t) }) @@ -695,8 +695,8 @@ func TestSCIMUtil_Integration(t *testing.T) { assert.True(t, userSyncEnabled) // Test non-provisioned users falls back to static config - nonProvisionedAllowed := util.AreNonProvisionedUsersAllowed(ctx, orgID, true) - assert.True(t, nonProvisionedAllowed) + nonProvisionedRejected := util.AreNonProvisionedUsersRejected(ctx, orgID, true) + assert.True(t, nonProvisionedRejected) mockClient.AssertExpectations(t) }) From cef7f2b3372480e275e284d900a74ab7f7764185 Mon Sep 17 00:00:00 2001 From: Mihai Doarna Date: Mon, 28 Jul 2025 11:32:14 +0300 Subject: [PATCH 026/131] SCIM: Update docs with the reject_non_provisioned_users flag (#108657) * update docs with the reject_non_provisioned_users flag * update docs with new flag and new create user behaviour * address feedback * run prettier --- .../configure-scim-provisioning/_index.md | 20 ++++++--------- .../manage-users-teams/_index.md | 25 +++---------------- 2 files changed, 10 insertions(+), 35 deletions(-) diff --git a/docs/sources/setup-grafana/configure-security/configure-scim-provisioning/_index.md b/docs/sources/setup-grafana/configure-security/configure-scim-provisioning/_index.md index 2782bdab0fd..d3c2496f75b 100644 --- a/docs/sources/setup-grafana/configure-security/configure-scim-provisioning/_index.md +++ b/docs/sources/setup-grafana/configure-security/configure-scim-provisioning/_index.md @@ -50,7 +50,7 @@ Always verify that your SAML identity provider is configured to send a stable, u ## Benefits {{< admonition type="note" >}} -SCIM provisioning only works SAML authentication. +SCIM provisioning only works with SAML authentication. Other authentication methods aren't supported. {{< /admonition >}} @@ -67,25 +67,19 @@ When you enable SCIM in Grafana, the following requirements and restrictions app 1. **Use the same identity provider for user provisioning and for authentication flow**: You must use the same identity provider for both authentication and user provisioning. -2. **Authentication restrictions**: - - Users attempting to log in through other methods (LDAP, OAuth) will be blocked - - By default, users who are not provisioned through SCIM cannot access Grafana - -3. **Security restriction**: When using SAML, the login authentication flow requires the SAML assertion exchange between the Identity Provider and Grafana to include the `userUID` SAML assertion with the user's unique identifier at the Identity Provider. +2. **Security restriction**: When using SAML, the login authentication flow requires the SAML assertion exchange between the Identity Provider and Grafana to include the `userUID` SAML assertion with the user's unique identifier at the Identity Provider. - Configure `userUID` SAML assertion in [Azure AD](/docs/grafana//setup-grafana/configure-security/configure-authentication/saml/configure-saml-with-azuread/#configure-saml-assertions-when-using-scim-provisioning) - Configure `userUID` SAML assertion in [Okta](/docs/grafana//setup-grafana/configure-security/configure-authentication/saml/configure-saml-with-okta/#configure-saml-assertions-when-using-scim-provisioning) -4. **Exceptions**: Users with Basic Auth credentials and those using their Grafana Cloud accounts can still log in regardless of these restrictions. - ## Configure SCIM in Grafana The table below describes all SCIM configuration options. Like any other Grafana configuration, you can apply these options as [environment variables](/docs/grafana//setup-grafana/configure-grafana/#override-configuration-with-environment-variables). -| Setting | Required | Description | Default | -| ----------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------- | -| `user_sync_enabled` | Yes | Enable SCIM user provisioning. When enabled, Grafana will create, update, and deactivate users based on SCIM requests from your identity provider. | `false` | -| `group_sync_enabled` | No | Enable SCIM group provisioning. When enabled, Grafana will create, update, and delete teams based on SCIM requests from your identity provider. Cannot be enabled if Team Sync is enabled. | `false` | -| `allow_non_provisioned_users` | No | Allow non SCIM provisioned users to sign in to Grafana. | `false` | +| Setting | Required | Description | Default | +| ------------------------------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------- | +| `user_sync_enabled` | Yes | Enable SCIM user provisioning. When enabled, Grafana will create, update, and deactivate users based on SCIM requests from your identity provider. | `false` | +| `group_sync_enabled` | No | Enable SCIM group provisioning. When enabled, Grafana will create, update, and delete teams based on SCIM requests from your identity provider. Cannot be enabled if Team Sync is enabled. | `false` | +| `reject_non_provisioned_users` | No | When enabled, prevents non-SCIM provisioned users from signing in. Cloud Portal users can always sign in regardless of this setting. | `false` | {{< admonition type="warning" >}} **Team Sync Compatibility**: diff --git a/docs/sources/setup-grafana/configure-security/configure-scim-provisioning/manage-users-teams/_index.md b/docs/sources/setup-grafana/configure-security/configure-scim-provisioning/manage-users-teams/_index.md index 24f7cf1af0e..2b3b0524884 100644 --- a/docs/sources/setup-grafana/configure-security/configure-scim-provisioning/manage-users-teams/_index.md +++ b/docs/sources/setup-grafana/configure-security/configure-scim-provisioning/manage-users-teams/_index.md @@ -63,7 +63,7 @@ SCIM uses a specific process to establish and maintain user identity between the 2. **Identity linking based on lookup results:** - **If there's a single matching result:** The identity provider retrieves the user's unique ID at Grafana, saves it, confirms it can fetch the user's information, and updates the user's information in Grafana - - **If there are no matching results:** The identity provider attempts to create the user in Grafana. If successful, it retrieves and saves the user's unique ID for future operations. If there's a conflict with an existing user, the identity provider flags the error and Grafana logs the error message + - **If there are no matching results:** The identity provider attempts to create the user in Grafana. If successful, it retrieves and saves the user's unique ID for future operations. If a user with the same email address already exists in Grafana, the user is updated and will be managed by SCIM from that point forward. - The identity provider learns the relationship between the found Grafana user and the Grafana internal ID - The identity provider updates Grafana with the External ID - Grafana updates the authentication validations to expect this External ID @@ -79,10 +79,6 @@ This process ensures secure and consistent user identification across both syste ### Existing Grafana users -{{< admonition type="note" >}} -Existing users must be assigned to the Grafana app in the identity provider to maintain access once SCIM is enabled. -{{< /admonition >}} - For users who already exist in the Grafana instance: - SCIM establishes the relationship through the External ID matching process @@ -147,13 +143,11 @@ The migration process uses the same [user identification mechanism](#how-scim-id - Configure the unique identifier field to match your IDP setup {{< admonition type="note" >}} -When `user_sync_enabled = true`, non-provisioned users will be disallowed from logging in, except for `admin` and Grafana.com login. - -If you want to allow non-provisioned users to log in, enable the `[auth.scim][allow_non_provisioned_users]` option. +To restrict login access to only SCIM-provisioned users, enable the `[auth.scim][reject_non_provisioned_users]` option. Cloud Portal users can always sign in regardless of this setting. ```ini [auth.scim] -allow_non_provisioned_users = true +reject_non_provisioned_users = true ``` {{< /admonition >}} @@ -282,19 +276,6 @@ Team membership maintenance: ### User provisioning issues -#### Error: "User already exists in Grafana" - -**Cause:** The unique identifier field is not working as expected, causing conflicts during user creation. - -**Solution:** Test the unique identifier field to ensure it returns a single, unique user: - -```bash -curl --location 'https://{$GRAFANA_URL}/apis/scim.grafana.app/v0alpha1/namespaces/{$STACK_ID}/Users?filter=userName eq "username@email.com"' \ ---header 'Authorization: Bearer glsa_xxxxxxxxxxxxxxxxxxxxxxxx' -``` - -The response should return exactly one user. If not, configure a different unique identifier field in your identity provider, or remove the duplicate users from Grafana. - #### Error: "invalid namespace" **Cause:** The SCIM endpoint URL is incorrectly formatted. From d529eee8cfe42f7ec3c50619aeb32048bf092c93 Mon Sep 17 00:00:00 2001 From: Joey <90795735+joey-grafana@users.noreply.github.com> Date: Mon, 28 Jul 2025 09:36:07 +0100 Subject: [PATCH 027/131] Tempo: Add options to getTagKeys (#108691) Add options to getTagKeys so time range and timeRangeForTags can be passed into the Tempo language provider --- .../app/plugins/datasource/tempo/datasource.test.ts | 12 +++++++++++- public/app/plugins/datasource/tempo/datasource.ts | 5 +++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/public/app/plugins/datasource/tempo/datasource.test.ts b/public/app/plugins/datasource/tempo/datasource.test.ts index f66520555f5..72c82f356b0 100644 --- a/public/app/plugins/datasource/tempo/datasource.test.ts +++ b/public/app/plugins/datasource/tempo/datasource.test.ts @@ -1227,7 +1227,17 @@ describe('should provide functionality for ad-hoc filters', () => { }); it('for getTagKeys', async () => { - const response = await datasource.getTagKeys(); + const response = await datasource.getTagKeys({ + filters: [], + timeRange: { + from: dateTime('2021-04-20T15:55:00Z'), + to: dateTime('2021-04-20T15:55:00Z'), + raw: { + from: 'now-15m', + to: 'now', + }, + }, + }); expect(response).toEqual([{ text: 'span.label1' }, { text: 'span.label2' }]); }); diff --git a/public/app/plugins/datasource/tempo/datasource.ts b/public/app/plugins/datasource/tempo/datasource.ts index 8d16b28f97d..508f4b043a6 100644 --- a/public/app/plugins/datasource/tempo/datasource.ts +++ b/public/app/plugins/datasource/tempo/datasource.ts @@ -11,6 +11,7 @@ import { DataQueryRequest, DataQueryResponse, DataQueryResponseData, + DataSourceGetTagKeysOptions, DataSourceGetTagValuesOptions, DataSourceInstanceSettings, dateTime, @@ -238,8 +239,8 @@ export class TempoDatasource extends DataSourceWithBackend> { - await this.languageProvider.fetchTags(); + async getTagKeys(options: DataSourceGetTagKeysOptions): Promise> { + await this.languageProvider.fetchTags(this.timeRangeForTags, options.timeRange); const tags = this.languageProvider.tagsV2 || []; return tags .map(({ name, tags }) => From 7596dc319c55cfcdfb6ba7e5b456b30aa969b1b0 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 28 Jul 2025 09:53:57 +0100 Subject: [PATCH 028/131] Update dependency @floating-ui/react to v0.27.14 (#108755) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- packages/grafana-prometheus/package.json | 2 +- packages/grafana-ui/package.json | 2 +- yarn.lock | 14 +++++++------- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index af80f4b3e0d..4b25b18298f 100644 --- a/package.json +++ b/package.json @@ -268,7 +268,7 @@ "@emotion/css": "11.13.5", "@emotion/react": "11.14.0", "@fingerprintjs/fingerprintjs": "^3.4.2", - "@floating-ui/react": "0.27.13", + "@floating-ui/react": "0.27.14", "@formatjs/intl-durationformat": "^0.7.0", "@glideapps/glide-data-grid": "^6.0.0", "@grafana/alerting": "workspace:*", diff --git a/packages/grafana-prometheus/package.json b/packages/grafana-prometheus/package.json index 765c9e5434b..efd2b239574 100644 --- a/packages/grafana-prometheus/package.json +++ b/packages/grafana-prometheus/package.json @@ -40,7 +40,7 @@ }, "dependencies": { "@emotion/css": "11.13.5", - "@floating-ui/react": "0.27.13", + "@floating-ui/react": "0.27.14", "@grafana/data": "12.2.0-pre", "@grafana/e2e-selectors": "12.2.0-pre", "@grafana/i18n": "12.2.0-pre", diff --git a/packages/grafana-ui/package.json b/packages/grafana-ui/package.json index 7fd647aee7e..553dd3b8fa7 100644 --- a/packages/grafana-ui/package.json +++ b/packages/grafana-ui/package.json @@ -66,7 +66,7 @@ "@emotion/css": "11.13.5", "@emotion/react": "11.14.0", "@emotion/serialize": "1.3.3", - "@floating-ui/react": "0.27.13", + "@floating-ui/react": "0.27.14", "@grafana/data": "12.2.0-pre", "@grafana/e2e-selectors": "12.2.0-pre", "@grafana/faro-web-sdk": "^1.13.2", diff --git a/yarn.lock b/yarn.lock index 840ec969a1f..4486bdfc0b8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2393,9 +2393,9 @@ __metadata: languageName: node linkType: hard -"@floating-ui/react@npm:0.27.13": - version: 0.27.13 - resolution: "@floating-ui/react@npm:0.27.13" +"@floating-ui/react@npm:0.27.14": + version: 0.27.14 + resolution: "@floating-ui/react@npm:0.27.14" dependencies: "@floating-ui/react-dom": "npm:^2.1.4" "@floating-ui/utils": "npm:^0.2.10" @@ -2403,7 +2403,7 @@ __metadata: peerDependencies: react: ">=17.0.0" react-dom: ">=17.0.0" - checksum: 10/84a5247e74b7666c069680e8df69e0dcdbf846f6192760c1ec8c53361b2e316895bb43847fba92f6c82e563db45794aeb8755560e769c610ef4a1b956a52d105 + checksum: 10/5466938bdd0db8f7939a640da459bfe8417388d95b1547c69a236f87e4b218992f4a2d7cee14642a6b64c88fbb8df7fced46a01e41b7feb12785e4181498669b languageName: node linkType: hard @@ -3491,7 +3491,7 @@ __metadata: resolution: "@grafana/prometheus@workspace:packages/grafana-prometheus" dependencies: "@emotion/css": "npm:11.13.5" - "@floating-ui/react": "npm:0.27.13" + "@floating-ui/react": "npm:0.27.14" "@grafana/data": "npm:12.2.0-pre" "@grafana/e2e-selectors": "npm:12.2.0-pre" "@grafana/i18n": "npm:12.2.0-pre" @@ -3736,7 +3736,7 @@ __metadata: "@emotion/react": "npm:11.14.0" "@emotion/serialize": "npm:1.3.3" "@faker-js/faker": "npm:^9.0.0" - "@floating-ui/react": "npm:0.27.13" + "@floating-ui/react": "npm:0.27.14" "@grafana/data": "npm:12.2.0-pre" "@grafana/e2e-selectors": "npm:12.2.0-pre" "@grafana/faro-web-sdk": "npm:^1.13.2" @@ -18144,7 +18144,7 @@ __metadata: "@emotion/eslint-plugin": "npm:11.12.0" "@emotion/react": "npm:11.14.0" "@fingerprintjs/fingerprintjs": "npm:^3.4.2" - "@floating-ui/react": "npm:0.27.13" + "@floating-ui/react": "npm:0.27.14" "@formatjs/intl-durationformat": "npm:^0.7.0" "@glideapps/glide-data-grid": "npm:^6.0.0" "@grafana/alerting": "workspace:*" From 15f291aa8ea72dd5bd080409361a25e23b8a8422 Mon Sep 17 00:00:00 2001 From: Chris Chang <51393127+chriscerie@users.noreply.github.com> Date: Mon, 28 Jul 2025 02:15:50 -0700 Subject: [PATCH 029/131] Plugins: Add grafana-iot-twinmaker-datasource to forward_settings_to_plugins (#108560) * Add grafana-iot-twinmaker-datasource to forward settings list * Remove -app --- conf/defaults.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/defaults.ini b/conf/defaults.ini index 65faaa76224..889677b651a 100644 --- a/conf/defaults.ini +++ b/conf/defaults.ini @@ -992,7 +992,7 @@ session_duration = "15m" # Set the plugins that will receive AWS settings for each request (via plugin context) # By default this will include all Grafana Labs owned AWS plugins, or those that make use of AWS settings (ElasticSearch, Prometheus). -forward_settings_to_plugins = cloudwatch, grafana-athena-datasource, grafana-redshift-datasource, grafana-x-ray-datasource, grafana-timestream-datasource, grafana-iot-sitewise-datasource, grafana-iot-twinmaker-app, grafana-opensearch-datasource, aws-datasource-provisioner, elasticsearch, prometheus, grafana-amazonprometheus-datasource, grafana-aurora-datasource +forward_settings_to_plugins = cloudwatch, grafana-athena-datasource, grafana-redshift-datasource, grafana-x-ray-datasource, grafana-timestream-datasource, grafana-iot-sitewise-datasource, grafana-iot-twinmaker-datasource, grafana-opensearch-datasource, aws-datasource-provisioner, elasticsearch, prometheus, grafana-amazonprometheus-datasource, grafana-aurora-datasource #################################### Azure ############################### [azure] From 8d48dbce66bd6324d5d46f2797b05953e897d2a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Farkas?= Date: Mon, 28 Jul 2025 11:40:26 +0200 Subject: [PATCH 030/131] datasources: querier: handle single-tenant instance config (#108469) --- pkg/registry/apis/query/client.go | 21 ----------- pkg/registry/apis/query/client/plugin.go | 2 +- pkg/registry/apis/query/client/supplier.go | 44 ++++++++++++++++++++++ pkg/registry/apis/query/register.go | 9 +++-- pkg/server/wire_gen.go | 4 +- 5 files changed, 52 insertions(+), 28 deletions(-) delete mode 100644 pkg/registry/apis/query/client.go create mode 100644 pkg/registry/apis/query/client/supplier.go diff --git a/pkg/registry/apis/query/client.go b/pkg/registry/apis/query/client.go deleted file mode 100644 index 364e8e5cf9d..00000000000 --- a/pkg/registry/apis/query/client.go +++ /dev/null @@ -1,21 +0,0 @@ -package query - -import ( - "context" - - data "github.com/grafana/grafana-plugin-sdk-go/experimental/apis/data/v0alpha1" - "github.com/grafana/grafana/pkg/registry/apis/query/clientapi" -) - -type CommonDataSourceClientSupplier struct { - Client clientapi.QueryDataClient -} - -func (s *CommonDataSourceClientSupplier) GetDataSourceClient(_ context.Context, _ data.DataSourceRef, _ map[string]string, _ clientapi.InstanceConfigurationSettings) (clientapi.QueryDataClient, error) { - return s.Client, nil -} - -func (s *CommonDataSourceClientSupplier) GetInstanceConfigurationSettings(_ context.Context) (clientapi.InstanceConfigurationSettings, error) { - // FIXME: for now it's an empty structure, we'll find a way to fill it correctly. - return clientapi.InstanceConfigurationSettings{}, nil -} diff --git a/pkg/registry/apis/query/client/plugin.go b/pkg/registry/apis/query/client/plugin.go index 728346bf865..3cd805919d1 100644 --- a/pkg/registry/apis/query/client/plugin.go +++ b/pkg/registry/apis/query/client/plugin.go @@ -64,7 +64,7 @@ var k8sNotFoundError error = &apierrors.StatusError{ } // NewQueryClientForPluginClient creates a client that delegates to the internal plugins.Client stack -func NewQueryClientForPluginClient(p plugins.Client, ctx *plugincontext.Provider, accessControl accesscontrol.AccessControl) clientapi.QueryDataClient { +func newQueryClientForPluginClient(p plugins.Client, ctx *plugincontext.Provider, accessControl accesscontrol.AccessControl) clientapi.QueryDataClient { return &pluginClient{ pluginClient: p, pCtxProvider: ctx, diff --git a/pkg/registry/apis/query/client/supplier.go b/pkg/registry/apis/query/client/supplier.go new file mode 100644 index 00000000000..08c462d466c --- /dev/null +++ b/pkg/registry/apis/query/client/supplier.go @@ -0,0 +1,44 @@ +package client + +import ( + "context" + + data "github.com/grafana/grafana-plugin-sdk-go/experimental/apis/data/v0alpha1" + "github.com/grafana/grafana/pkg/plugins" + "github.com/grafana/grafana/pkg/registry/apis/query/clientapi" + "github.com/grafana/grafana/pkg/services/accesscontrol" + "github.com/grafana/grafana/pkg/services/featuremgmt" + "github.com/grafana/grafana/pkg/services/pluginsintegration/plugincontext" + "github.com/grafana/grafana/pkg/setting" +) + +type singleTenantClientSupplier struct { + client clientapi.QueryDataClient + features featuremgmt.FeatureToggles + cfg *setting.Cfg +} + +func NewSingleTenantClientSupplier(cfg *setting.Cfg, features featuremgmt.FeatureToggles, p plugins.Client, ctxProv *plugincontext.Provider, accessControl accesscontrol.AccessControl) clientapi.DataSourceClientSupplier { + return &singleTenantClientSupplier{ + cfg: cfg, + features: features, + client: newQueryClientForPluginClient(p, ctxProv, accessControl), + } +} + +func (s *singleTenantClientSupplier) GetDataSourceClient(_ context.Context, _ data.DataSourceRef, _ map[string]string, _ clientapi.InstanceConfigurationSettings) (clientapi.QueryDataClient, error) { + return s.client, nil +} + +func (s *singleTenantClientSupplier) GetInstanceConfigurationSettings(ctx context.Context) (clientapi.InstanceConfigurationSettings, error) { + return clientapi.InstanceConfigurationSettings{ + StackID: 0, + FeatureToggles: s.features, + FullConfig: nil, + Options: nil, + SQLExpressionCellLimit: s.cfg.SQLExpressionCellLimit, + SQLExpressionOutputCellLimit: s.cfg.SQLExpressionOutputCellLimit, + SQLExpressionTimeout: s.cfg.SQLExpressionTimeout, + ExpressionsEnabled: s.cfg.ExpressionsEnabled, + }, nil +} diff --git a/pkg/registry/apis/query/register.go b/pkg/registry/apis/query/register.go index bfb99a8cd8d..1efd3efdb2a 100644 --- a/pkg/registry/apis/query/register.go +++ b/pkg/registry/apis/query/register.go @@ -31,6 +31,7 @@ import ( "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/pluginsintegration/plugincontext" "github.com/grafana/grafana/pkg/services/pluginsintegration/pluginstore" + "github.com/grafana/grafana/pkg/setting" ) var _ builder.APIGroupBuilder = (*QueryAPIBuilder)(nil) @@ -93,7 +94,9 @@ func NewQueryAPIBuilder( }, nil } -func RegisterAPIService(features featuremgmt.FeatureToggles, +func RegisterAPIService( + cfg *setting.Cfg, + features featuremgmt.FeatureToggles, apiregistration builder.APIRegistrar, dataSourcesService datasources.DataSourceService, pluginStore pluginstore.Store, @@ -126,9 +129,7 @@ func RegisterAPIService(features featuremgmt.FeatureToggles, builder, err := NewQueryAPIBuilder( features, - &CommonDataSourceClientSupplier{ - Client: client.NewQueryClientForPluginClient(pluginClient, pCtxProvider, accessControl), - }, + client.NewSingleTenantClientSupplier(cfg, features, pluginClient, pCtxProvider, accessControl), ar, client.NewDataSourceRegistryFromStore(pluginStore, dataSourcesService), registerer, diff --git a/pkg/server/wire_gen.go b/pkg/server/wire_gen.go index 9153346ef18..440ede3c8b9 100644 --- a/pkg/server/wire_gen.go +++ b/pkg/server/wire_gen.go @@ -740,7 +740,7 @@ func Initialize(cfg *setting.Cfg, opts Options, apiOpts api.ServerOptions) (*Ser return nil, err } legacyDataSourceLookup := service7.ProvideLegacyDataSourceLookup(service15) - queryAPIBuilder, err := query2.RegisterAPIService(featureToggles, apiserverService, service15, pluginstoreService, accessControl, middlewareHandler, plugincontextProvider, registerer, tracingService, legacyDataSourceLookup, exprService) + queryAPIBuilder, err := query2.RegisterAPIService(cfg, featureToggles, apiserverService, service15, pluginstoreService, accessControl, middlewareHandler, plugincontextProvider, registerer, tracingService, legacyDataSourceLookup, exprService) if err != nil { return nil, err } @@ -1298,7 +1298,7 @@ func InitializeForTest(t sqlutil.ITestDB, testingT interface { return nil, err } legacyDataSourceLookup := service7.ProvideLegacyDataSourceLookup(service15) - queryAPIBuilder, err := query2.RegisterAPIService(featureToggles, apiserverService, service15, pluginstoreService, accessControl, middlewareHandler, plugincontextProvider, registerer, tracingService, legacyDataSourceLookup, exprService) + queryAPIBuilder, err := query2.RegisterAPIService(cfg, featureToggles, apiserverService, service15, pluginstoreService, accessControl, middlewareHandler, plugincontextProvider, registerer, tracingService, legacyDataSourceLookup, exprService) if err != nil { return nil, err } From 252fc67fbdbd53d2fa96a634d9a83eb4d1be101d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20V=C4=93rzemnieks?= Date: Mon, 28 Jul 2025 02:43:37 -0700 Subject: [PATCH 031/131] CloudWatch: Improve smithy error handling (#108523) * CloudWatch: Improve smithy error handling * gofmt --- pkg/tsdb/cloudwatch/services/accounts.go | 8 ++++---- pkg/tsdb/cloudwatch/services/accounts_test.go | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/pkg/tsdb/cloudwatch/services/accounts.go b/pkg/tsdb/cloudwatch/services/accounts.go index 599ddcf0911..4689d79b555 100644 --- a/pkg/tsdb/cloudwatch/services/accounts.go +++ b/pkg/tsdb/cloudwatch/services/accounts.go @@ -4,10 +4,10 @@ import ( "context" "errors" "fmt" - "strings" oam "github.com/aws/aws-sdk-go-v2/service/oam" oamtypes "github.com/aws/aws-sdk-go-v2/service/oam/types" + "github.com/aws/smithy-go" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/models" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/models/resources" ) @@ -28,9 +28,9 @@ func (a *AccountsService) GetAccountsForCurrentUserOrRole(ctx context.Context) ( for { response, err := a.ListSinks(ctx, &oam.ListSinksInput{NextToken: nextToken}) if err != nil { - // TODO: this is a bit hacky, figure out how to do it right in v2 - if strings.Contains(err.Error(), "AccessDeniedException") { - return nil, fmt.Errorf("%w: %s", ErrAccessDeniedException, err.Error()) + smithyErr := &smithy.GenericAPIError{} + if errors.As(err, &smithyErr) && smithyErr.Code == "AccessDeniedException" { + return nil, fmt.Errorf("%w: %s", ErrAccessDeniedException, smithyErr.Message) } return nil, fmt.Errorf("ListSinks error: %w", err) } diff --git a/pkg/tsdb/cloudwatch/services/accounts_test.go b/pkg/tsdb/cloudwatch/services/accounts_test.go index ba75ad4a9a0..48d99eda6bc 100644 --- a/pkg/tsdb/cloudwatch/services/accounts_test.go +++ b/pkg/tsdb/cloudwatch/services/accounts_test.go @@ -2,13 +2,13 @@ package services import ( "context" - "errors" "fmt" "testing" "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/oam" oamtypes "github.com/aws/aws-sdk-go-v2/service/oam/types" + "github.com/aws/smithy-go" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/mocks" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/models/resources" @@ -20,14 +20,14 @@ import ( func TestHandleGetAccounts(t *testing.T) { t.Run("Should return an error in case of insufficient permissions from ListSinks", func(t *testing.T) { fakeOAMClient := &mocks.FakeOAMClient{} - fakeOAMClient.On("ListSinks", mock.Anything).Return(&oam.ListSinksOutput{}, errors.New("AccessDeniedException")) + fakeOAMClient.On("ListSinks", mock.Anything).Return(&oam.ListSinksOutput{}, fmt.Errorf("%w", &smithy.GenericAPIError{Code: "AccessDeniedException", Message: "this is bad"})) accounts := NewAccountsService(fakeOAMClient) resp, err := accounts.GetAccountsForCurrentUserOrRole(context.Background()) assert.Error(t, err) assert.Nil(t, resp) - assert.Equal(t, "access denied. please check your IAM policy: AccessDeniedException", err.Error()) + assert.Equal(t, "access denied. please check your IAM policy: this is bad", err.Error()) assert.ErrorIs(t, err, ErrAccessDeniedException) }) From f969eb0277c5e3429fca7d5c210be52a5312d8ef Mon Sep 17 00:00:00 2001 From: Alexander Akhmetov Date: Mon, 28 Jul 2025 11:44:17 +0200 Subject: [PATCH 032/131] Alerting: Add rule group name validation to the Prometheus conversion API (#108740) Alerting: Add rule group name validation to the conversion API --- .../api/api_convert_prometheus_test.go | 24 +++++++++++++++++++ pkg/services/ngalert/prom/convert_test.go | 16 +++++++++++++ pkg/services/ngalert/prom/models.go | 16 +++++++++---- 3 files changed, 52 insertions(+), 4 deletions(-) diff --git a/pkg/services/ngalert/api/api_convert_prometheus_test.go b/pkg/services/ngalert/api/api_convert_prometheus_test.go index e5833280319..35d3da6d72a 100644 --- a/pkg/services/ngalert/api/api_convert_prometheus_test.go +++ b/pkg/services/ngalert/api/api_convert_prometheus_test.go @@ -291,6 +291,30 @@ func TestRouteConvertPrometheusPostRuleGroup(t *testing.T) { } }) + t.Run("with empty rule group name should return 400", func(t *testing.T) { + srv, _, _ := createConvertPrometheusSrv(t) + rc := createRequestCtx() + + emptyNameGroup := apimodels.PrometheusRuleGroup{ + Name: "", + Interval: prommodel.Duration(1 * time.Minute), + Rules: []apimodels.PrometheusRule{ + { + Alert: "TestAlert", + Expr: "up == 0", + For: util.Pointer(prommodel.Duration(5 * time.Minute)), + Labels: map[string]string{ + "severity": "critical", + }, + }, + }, + } + + response := srv.RouteConvertPrometheusPostRuleGroup(rc, "test", emptyNameGroup) + require.Equal(t, http.StatusBadRequest, response.Status()) + require.Contains(t, string(response.Body()), "rule group name must not be empty") + }) + t.Run("with valid request should return 202", func(t *testing.T) { srv, _, _ := createConvertPrometheusSrv(t) rc := createRequestCtx() diff --git a/pkg/services/ngalert/prom/convert_test.go b/pkg/services/ngalert/prom/convert_test.go index 16b43e1a92d..befa524f468 100644 --- a/pkg/services/ngalert/prom/convert_test.go +++ b/pkg/services/ngalert/prom/convert_test.go @@ -143,6 +143,22 @@ func TestPrometheusRulesToGrafana(t *testing.T) { }, expectError: false, }, + { + name: "rule group with empty name", + orgID: 1, + namespace: "namespaceUID", + promGroup: PrometheusRuleGroup{ + Name: "", + Rules: []PrometheusRule{ + { + Alert: "alert-1", + Expr: "up == 0", + }, + }, + }, + expectError: true, + errorMsg: "rule group name must not be empty", + }, { name: "recording rule", orgID: 1, diff --git a/pkg/services/ngalert/prom/models.go b/pkg/services/ngalert/prom/models.go index 1ac5ad1d0d9..1664a31c1b6 100644 --- a/pkg/services/ngalert/prom/models.go +++ b/pkg/services/ngalert/prom/models.go @@ -7,10 +7,14 @@ import ( ) var ( - ErrPrometheusRuleValidationFailed = errutil.ValidationFailed("alerting.prometheusRuleInvalid") - ErrPrometheusRuleGroupValidationFailed = errutil.ValidationFailed("alerting.prometheusRuleGroupInvalid") + errPrometheusRuleGroupValidationFailedMsg = "{{.Public.Message}}" + ErrPrometheusRuleGroupValidationFailed = errutil.ValidationFailed("alerting.prometheusRuleGroupInvalid").MustTemplate(errPrometheusRuleGroupValidationFailedMsg, errutil.WithPublic(errPrometheusRuleGroupValidationFailedMsg)) ) +func errPrometheusRuleGroupValidationFailed(message string) error { + return ErrPrometheusRuleGroupValidationFailed.Build(errutil.TemplateData{Public: map[string]any{"Message": message}}) +} + type PrometheusRulesFile struct { Groups []PrometheusRuleGroup `yaml:"groups"` } @@ -25,12 +29,16 @@ type PrometheusRuleGroup struct { } func (g *PrometheusRuleGroup) Validate() error { + if g.Name == "" { + return errPrometheusRuleGroupValidationFailed("rule group name must not be empty") + } + if g.Limit != 0 { - return ErrPrometheusRuleGroupValidationFailed.Errorf("limit is not supported") + return errPrometheusRuleGroupValidationFailed("limit is not supported") } if g.QueryOffset != nil && *g.QueryOffset < prommodel.Duration(0) { - return ErrPrometheusRuleGroupValidationFailed.Errorf("query_offset must be >= 0") + return errPrometheusRuleGroupValidationFailed("query_offset must be >= 0") } return nil From 2ea77a7c05e18d7c19e3b6307326fc1272346f52 Mon Sep 17 00:00:00 2001 From: Dana Axinte <53751979+dana-axinte@users.noreply.github.com> Date: Mon, 28 Jul 2025 10:50:24 +0100 Subject: [PATCH 033/131] SecretsManager: Add ability to list all encrypted values (#108512) * list all encrypted values and count * separate interfaces * add time filter to global queries * fix lint --- .../apis/secret/contracts/encryption.go | 11 ++ .../apis/secret/testutils/testutils.go | 38 +++--- .../data/encrypted_value_count_all.sql | 7 + .../data/encrypted_value_list_all.sql | 17 +++ .../encryption/encrypted_value_store.go | 123 ++++++++++++++++++ .../encryption/encrypted_value_store_test.go | 72 ++++++++++ pkg/storage/secret/encryption/query.go | 28 +++- pkg/storage/secret/encryption/query_test.go | 58 +++++++++ ...l--encrypted_value_count_all-count_all.sql | 4 + ...d_value_count_all-count_all_until_time.sql | 5 + ...sql--encrypted_value_list_all-list_all.sql | 11 ++ ...ted_value_list_all-list_all_until_time.sql | 12 ++ ..._value_list_all-list_limit_10_offset_0.sql | 12 ++ ..._value_list_all-list_limit_10_offset_2.sql | 12 ++ ...s--encrypted_value_count_all-count_all.sql | 4 + ...d_value_count_all-count_all_until_time.sql | 5 + ...res--encrypted_value_list_all-list_all.sql | 11 ++ ...ted_value_list_all-list_all_until_time.sql | 12 ++ ..._value_list_all-list_limit_10_offset_0.sql | 12 ++ ..._value_list_all-list_limit_10_offset_2.sql | 12 ++ ...e--encrypted_value_count_all-count_all.sql | 4 + ...d_value_count_all-count_all_until_time.sql | 5 + ...ite--encrypted_value_list_all-list_all.sql | 11 ++ ...ted_value_list_all-list_all_until_time.sql | 12 ++ ..._value_list_all-list_limit_10_offset_0.sql | 12 ++ ..._value_list_all-list_limit_10_offset_2.sql | 12 ++ 26 files changed, 502 insertions(+), 20 deletions(-) create mode 100644 pkg/storage/secret/encryption/data/encrypted_value_count_all.sql create mode 100644 pkg/storage/secret/encryption/data/encrypted_value_list_all.sql create mode 100755 pkg/storage/secret/encryption/testdata/mysql--encrypted_value_count_all-count_all.sql create mode 100755 pkg/storage/secret/encryption/testdata/mysql--encrypted_value_count_all-count_all_until_time.sql create mode 100755 pkg/storage/secret/encryption/testdata/mysql--encrypted_value_list_all-list_all.sql create mode 100755 pkg/storage/secret/encryption/testdata/mysql--encrypted_value_list_all-list_all_until_time.sql create mode 100755 pkg/storage/secret/encryption/testdata/mysql--encrypted_value_list_all-list_limit_10_offset_0.sql create mode 100755 pkg/storage/secret/encryption/testdata/mysql--encrypted_value_list_all-list_limit_10_offset_2.sql create mode 100755 pkg/storage/secret/encryption/testdata/postgres--encrypted_value_count_all-count_all.sql create mode 100755 pkg/storage/secret/encryption/testdata/postgres--encrypted_value_count_all-count_all_until_time.sql create mode 100755 pkg/storage/secret/encryption/testdata/postgres--encrypted_value_list_all-list_all.sql create mode 100755 pkg/storage/secret/encryption/testdata/postgres--encrypted_value_list_all-list_all_until_time.sql create mode 100755 pkg/storage/secret/encryption/testdata/postgres--encrypted_value_list_all-list_limit_10_offset_0.sql create mode 100755 pkg/storage/secret/encryption/testdata/postgres--encrypted_value_list_all-list_limit_10_offset_2.sql create mode 100755 pkg/storage/secret/encryption/testdata/sqlite--encrypted_value_count_all-count_all.sql create mode 100755 pkg/storage/secret/encryption/testdata/sqlite--encrypted_value_count_all-count_all_until_time.sql create mode 100755 pkg/storage/secret/encryption/testdata/sqlite--encrypted_value_list_all-list_all.sql create mode 100755 pkg/storage/secret/encryption/testdata/sqlite--encrypted_value_list_all-list_all_until_time.sql create mode 100755 pkg/storage/secret/encryption/testdata/sqlite--encrypted_value_list_all-list_limit_10_offset_0.sql create mode 100755 pkg/storage/secret/encryption/testdata/sqlite--encrypted_value_list_all-list_limit_10_offset_2.sql diff --git a/pkg/registry/apis/secret/contracts/encryption.go b/pkg/registry/apis/secret/contracts/encryption.go index eb5292ee794..f0596de9034 100644 --- a/pkg/registry/apis/secret/contracts/encryption.go +++ b/pkg/registry/apis/secret/contracts/encryption.go @@ -21,9 +21,20 @@ type EncryptedValue struct { Updated int64 } +// ListOpts defines pagination options for listing encrypted values. +type ListOpts struct { + Limit int64 + Offset int64 +} + type EncryptedValueStorage interface { Create(ctx context.Context, namespace, name string, version int64, encryptedData []byte) (*EncryptedValue, error) Update(ctx context.Context, namespace, name string, version int64, encryptedData []byte) error Get(ctx context.Context, namespace, name string, version int64) (*EncryptedValue, error) Delete(ctx context.Context, namespace, name string, version int64) error } + +type GlobalEncryptedValueStorage interface { + ListAll(ctx context.Context, opts ListOpts, untilTime *int64) ([]*EncryptedValue, error) + CountAll(ctx context.Context, untilTime *int64) (int64, error) +} diff --git a/pkg/registry/apis/secret/testutils/testutils.go b/pkg/registry/apis/secret/testutils/testutils.go index 478b9c63e84..448283abd09 100644 --- a/pkg/registry/apis/secret/testutils/testutils.go +++ b/pkg/registry/apis/secret/testutils/testutils.go @@ -107,6 +107,10 @@ func Setup(t *testing.T, opts ...func(*SetupConfig)) Sut { encryptedValueStorage, err := encryptionstorage.ProvideEncryptedValueStorage(database, tracer) require.NoError(t, err) + // Initialize global encrypted value storage with a fake db + globalEncryptedValueStorage, err := encryptionstorage.ProvideGlobalEncryptedValueStorage(database, tracer) + require.NoError(t, err) + sqlKeeper := sqlkeeper.NewSQLKeeper(tracer, encryptionManager, encryptedValueStorage, nil) var keeperService contracts.KeeperService = newKeeperServiceWrapper(sqlKeeper) @@ -125,26 +129,28 @@ func Setup(t *testing.T, opts ...func(*SetupConfig)) Sut { decryptService := decrypt.ProvideDecryptService(decryptStorage) return Sut{ - SecureValueService: secureValueService, - SecureValueMetadataStorage: secureValueMetadataStorage, - DecryptStorage: decryptStorage, - DecryptService: decryptService, - EncryptedValueStorage: encryptedValueStorage, - SQLKeeper: sqlKeeper, - Database: database, - AccessClient: accessClient, + SecureValueService: secureValueService, + SecureValueMetadataStorage: secureValueMetadataStorage, + DecryptStorage: decryptStorage, + DecryptService: decryptService, + EncryptedValueStorage: encryptedValueStorage, + GlobalEncryptedValueStorage: globalEncryptedValueStorage, + SQLKeeper: sqlKeeper, + Database: database, + AccessClient: accessClient, } } type Sut struct { - SecureValueService contracts.SecureValueService - SecureValueMetadataStorage contracts.SecureValueMetadataStorage - DecryptStorage contracts.DecryptStorage - DecryptService contracts.DecryptService - EncryptedValueStorage contracts.EncryptedValueStorage - SQLKeeper *sqlkeeper.SQLKeeper - Database *database.Database - AccessClient types.AccessClient + SecureValueService contracts.SecureValueService + SecureValueMetadataStorage contracts.SecureValueMetadataStorage + DecryptStorage contracts.DecryptStorage + DecryptService contracts.DecryptService + EncryptedValueStorage contracts.EncryptedValueStorage + GlobalEncryptedValueStorage contracts.GlobalEncryptedValueStorage + SQLKeeper *sqlkeeper.SQLKeeper + Database *database.Database + AccessClient types.AccessClient } type CreateSvConfig struct { diff --git a/pkg/storage/secret/encryption/data/encrypted_value_count_all.sql b/pkg/storage/secret/encryption/data/encrypted_value_count_all.sql new file mode 100644 index 00000000000..5bfc5d2424f --- /dev/null +++ b/pkg/storage/secret/encryption/data/encrypted_value_count_all.sql @@ -0,0 +1,7 @@ +SELECT COUNT(*) AS count +FROM + {{ .Ident "secret_encrypted_value" }} +{{ if .HasUntilTime }} +WHERE {{ .Ident "created" }} <= {{ .Arg .UntilTime }} +{{ end }} +; diff --git a/pkg/storage/secret/encryption/data/encrypted_value_list_all.sql b/pkg/storage/secret/encryption/data/encrypted_value_list_all.sql new file mode 100644 index 00000000000..d318517346d --- /dev/null +++ b/pkg/storage/secret/encryption/data/encrypted_value_list_all.sql @@ -0,0 +1,17 @@ +SELECT + {{ .Ident "namespace" }}, + {{ .Ident "name" }}, + {{ .Ident "version" }}, + {{ .Ident "encrypted_data" }}, + {{ .Ident "created" }}, + {{ .Ident "updated" }} +FROM + {{ .Ident "secret_encrypted_value" }} +{{ if .HasUntilTime }} +WHERE {{ .Ident "created" }} <= {{ .Arg .UntilTime }} +{{ end }} +ORDER BY {{ .Ident "created" }} ASC +{{ if (gt .Limit 0) }} +LIMIT {{ .Arg .Limit }} OFFSET {{ .Arg .Offset }} +{{ end }} +; diff --git a/pkg/storage/secret/encryption/encrypted_value_store.go b/pkg/storage/secret/encryption/encrypted_value_store.go index cd298591b31..3a10d01b957 100644 --- a/pkg/storage/secret/encryption/encrypted_value_store.go +++ b/pkg/storage/secret/encryption/encrypted_value_store.go @@ -206,3 +206,126 @@ func (s *encryptedValStorage) Delete(ctx context.Context, namespace, name string return nil } + +type globalEncryptedValStorage struct { + db contracts.Database + dialect sqltemplate.Dialect + tracer trace.Tracer +} + +func ProvideGlobalEncryptedValueStorage( + db contracts.Database, + tracer trace.Tracer, +) (contracts.GlobalEncryptedValueStorage, error) { + return &globalEncryptedValStorage{ + db: db, + dialect: sqltemplate.DialectForDriver(db.DriverName()), + tracer: tracer, + }, nil +} + +func (s *globalEncryptedValStorage) ListAll(ctx context.Context, opts contracts.ListOpts, untilTime *int64) ([]*contracts.EncryptedValue, error) { + attrs := []attribute.KeyValue{ + attribute.Int64("limit", opts.Limit), + attribute.Int64("offset", opts.Offset), + } + if untilTime != nil { + attrs = append(attrs, attribute.Int64("untilTime", *untilTime)) + } + ctx, span := s.tracer.Start(ctx, "GlobalEncryptedValueStorage.CountAll", trace.WithAttributes(attrs...)) + defer span.End() + + req := listAllEncryptedValues{ + SQLTemplate: sqltemplate.New(s.dialect), + Limit: opts.Limit, + Offset: opts.Offset, + } + if untilTime != nil { + req.HasUntilTime = true + req.UntilTime = *untilTime + } + + query, err := sqltemplate.Execute(sqlEncryptedValueListAll, req) + if err != nil { + return nil, fmt.Errorf("execute template %q: %w", sqlEncryptedValueListAll.Name(), err) + } + + rows, err := s.db.QueryContext(ctx, query, req.GetArgs()...) + if err != nil { + return nil, fmt.Errorf("listing encrypted values %q: %w", sqlEncryptedValueListAll.Name(), err) + } + defer func() { _ = rows.Close() }() + + encryptedValues := make([]*contracts.EncryptedValue, 0) + for rows.Next() { + var row EncryptedValue + err = rows.Scan( + &row.Namespace, + &row.Name, + &row.Version, + &row.EncryptedData, + &row.Created, + &row.Updated, + ) + if err != nil { + return nil, fmt.Errorf("error reading data key row: %w", err) + } + + encryptedValues = append(encryptedValues, &contracts.EncryptedValue{ + Namespace: row.Namespace, + Name: row.Name, + Version: row.Version, + EncryptedData: row.EncryptedData, + Created: row.Created, + Updated: row.Updated, + }) + } + if err := rows.Err(); err != nil { + return nil, fmt.Errorf("read rows error: %w", err) + } + + return encryptedValues, nil +} + +func (s *globalEncryptedValStorage) CountAll(ctx context.Context, untilTime *int64) (int64, error) { + attrs := []attribute.KeyValue{} + if untilTime != nil { + attrs = append(attrs, attribute.Int64("untilTime", *untilTime)) + } + ctx, span := s.tracer.Start(ctx, "GlobalEncryptedValueStorage.CountAll", trace.WithAttributes(attrs...)) + defer span.End() + + req := countAllEncryptedValues{ + SQLTemplate: sqltemplate.New(s.dialect), + } + if untilTime != nil { + req.HasUntilTime = true + req.UntilTime = *untilTime + } + + query, err := sqltemplate.Execute(sqlEncryptedValueCountAll, req) + if err != nil { + return 0, fmt.Errorf("execute template %q: %w", sqlEncryptedValueCountAll.Name(), err) + } + + rows, err := s.db.QueryContext(ctx, query, req.GetArgs()...) + if err != nil { + return 0, fmt.Errorf("getting row: %w", err) + } + defer func() { _ = rows.Close() }() + + if !rows.Next() { + return 0, fmt.Errorf("no rows returned when counting encrypted values") + } + + var count int64 + err = rows.Scan(&count) + if err != nil { + return 0, fmt.Errorf("failed to scan encrypted value row: %w", err) + } + if err := rows.Err(); err != nil { + return 0, fmt.Errorf("read rows error: %w", err) + } + + return count, nil +} diff --git a/pkg/storage/secret/encryption/encrypted_value_store_test.go b/pkg/storage/secret/encryption/encrypted_value_store_test.go index 18b67a651fb..e5f987da4dc 100644 --- a/pkg/storage/secret/encryption/encrypted_value_store_test.go +++ b/pkg/storage/secret/encryption/encrypted_value_store_test.go @@ -4,6 +4,7 @@ import ( "errors" "slices" "testing" + "time" "github.com/grafana/grafana/pkg/registry/apis/secret/contracts" "github.com/grafana/grafana/pkg/registry/apis/secret/testutils" @@ -123,6 +124,77 @@ func TestEncryptedValueStoreImpl(t *testing.T) { err := sut.EncryptedValueStorage.Delete(t.Context(), "test-namespace", "test-name", 1) require.NoError(t, err) }) + + t.Run("listing encrypted values returns them", func(t *testing.T) { + t.Parallel() + + sut := testutils.Setup(t) + createdEvA, err := sut.EncryptedValueStorage.Create(t.Context(), "test-namespace-a", "test-name", 1, []byte("test-data")) + require.NoError(t, err) + + createdEvB, err := sut.EncryptedValueStorage.Create(t.Context(), "test-namespace-b", "test-name", 1, []byte("test-data")) + require.NoError(t, err) + + // List all encrypted values, without pagination + obtainedEVs, err := sut.GlobalEncryptedValueStorage.ListAll(t.Context(), contracts.ListOpts{}, nil) + require.NoError(t, err) + require.NotEmpty(t, obtainedEVs) + require.Len(t, obtainedEVs, 2) + + obtainedEvA := obtainedEVs[0] + require.Equal(t, createdEvA.Namespace, obtainedEvA.Namespace) + require.Equal(t, createdEvA.Name, obtainedEvA.Name) + require.Equal(t, createdEvA.EncryptedData, obtainedEvA.EncryptedData) + + // Test pagination by limiting the results to 1, offset by 0 + obtainedEVs, err = sut.GlobalEncryptedValueStorage.ListAll(t.Context(), contracts.ListOpts{Limit: 1}, nil) + require.NoError(t, err) + require.NotEmpty(t, obtainedEVs) + require.Len(t, obtainedEVs, 1) + + obtainedEvA = obtainedEVs[0] + require.Equal(t, createdEvA.Namespace, obtainedEvA.Namespace) + require.Equal(t, createdEvA.Name, obtainedEvA.Name) + require.Equal(t, createdEvA.EncryptedData, obtainedEvA.EncryptedData) + + // Test pagination by limiting the results to 1, offset by 1 + obtainedEVs, err = sut.GlobalEncryptedValueStorage.ListAll(t.Context(), contracts.ListOpts{Limit: 1, Offset: 1}, nil) + require.NoError(t, err) + require.NotEmpty(t, obtainedEVs) + require.Len(t, obtainedEVs, 1) + + obtainedEvB := obtainedEVs[0] + require.Equal(t, createdEvB.Namespace, obtainedEvB.Namespace) + require.Equal(t, createdEvB.Name, obtainedEvB.Name) + require.Equal(t, createdEvB.EncryptedData, obtainedEvB.EncryptedData) + + // List all encrypted values, until a certain time + pastTime := time.Now().Add(-1 * time.Hour).Unix() + obtainedEVs, err = sut.GlobalEncryptedValueStorage.ListAll(t.Context(), contracts.ListOpts{}, &pastTime) + require.NoError(t, err) + require.Empty(t, obtainedEVs) + }) + + t.Run("counting encrypted values returns their total", func(t *testing.T) { + t.Parallel() + + sut := testutils.Setup(t) + _, err := sut.EncryptedValueStorage.Create(t.Context(), "test-namespace-a", "test-name", 1, []byte("test-data")) + require.NoError(t, err) + + _, err = sut.EncryptedValueStorage.Create(t.Context(), "test-namespace-b", "test-name", 1, []byte("test-data")) + require.NoError(t, err) + + count, err := sut.GlobalEncryptedValueStorage.CountAll(t.Context(), nil) + require.NoError(t, err) + require.Equal(t, int64(2), count) + + // Count all encrypted values, until a certain time + pastTime := time.Now().Add(-1 * time.Hour).Unix() + count, err = sut.GlobalEncryptedValueStorage.CountAll(t.Context(), &pastTime) + require.NoError(t, err) + require.Equal(t, int64(0), count) + }) } func TestStateMachine(t *testing.T) { diff --git a/pkg/storage/secret/encryption/query.go b/pkg/storage/secret/encryption/query.go index 573e295dcaa..47ea83ce0cd 100644 --- a/pkg/storage/secret/encryption/query.go +++ b/pkg/storage/secret/encryption/query.go @@ -17,10 +17,12 @@ var ( sqlTemplates = template.Must(template.New("sql").ParseFS(sqlTemplatesFS, `data/*.sql`)) // The SQL Commands - sqlEncryptedValueCreate = mustTemplate("encrypted_value_create.sql") - sqlEncryptedValueRead = mustTemplate("encrypted_value_read.sql") - sqlEncryptedValueUpdate = mustTemplate("encrypted_value_update.sql") - sqlEncryptedValueDelete = mustTemplate("encrypted_value_delete.sql") + sqlEncryptedValueCreate = mustTemplate("encrypted_value_create.sql") + sqlEncryptedValueRead = mustTemplate("encrypted_value_read.sql") + sqlEncryptedValueUpdate = mustTemplate("encrypted_value_update.sql") + sqlEncryptedValueDelete = mustTemplate("encrypted_value_delete.sql") + sqlEncryptedValueListAll = mustTemplate("encrypted_value_list_all.sql") + sqlEncryptedValueCountAll = mustTemplate("encrypted_value_count_all.sql") sqlDataKeyCreate = mustTemplate("data_key_create.sql") sqlDataKeyRead = mustTemplate("data_key_read.sql") @@ -93,6 +95,24 @@ func (r deleteEncryptedValue) Validate() error { return nil // TODO } +type listAllEncryptedValues struct { + sqltemplate.SQLTemplate + Limit int64 + Offset int64 + HasUntilTime bool + UntilTime int64 +} + +func (r listAllEncryptedValues) Validate() error { return nil } + +type countAllEncryptedValues struct { + sqltemplate.SQLTemplate + HasUntilTime bool + UntilTime int64 +} + +func (r countAllEncryptedValues) Validate() error { return nil } + /*************************************/ /**-- Data Key Queries --**/ /*************************************/ diff --git a/pkg/storage/secret/encryption/query_test.go b/pkg/storage/secret/encryption/query_test.go index c2ebf7a9635..a93ff0b77e6 100644 --- a/pkg/storage/secret/encryption/query_test.go +++ b/pkg/storage/secret/encryption/query_test.go @@ -10,6 +10,7 @@ import ( ) func TestEncryptedValueQueries(t *testing.T) { + untilTime := int64(1234) mocks.CheckQuerySnapshots(t, mocks.TemplateTestSetup{ RootDir: "testdata", Templates: map[*template.Template][]mocks.TemplateTestCase{ @@ -64,6 +65,63 @@ func TestEncryptedValueQueries(t *testing.T) { }, }, }, + sqlEncryptedValueListAll: { + { + Name: "list_limit_10_offset_0", + Data: &listAllEncryptedValues{ + SQLTemplate: mocks.NewTestingSQLTemplate(), + Limit: 10, + Offset: 0, + HasUntilTime: false, + }, + }, + { + Name: "list_limit_10_offset_2", + Data: &listAllEncryptedValues{ + SQLTemplate: mocks.NewTestingSQLTemplate(), + Limit: 10, + Offset: 2, + HasUntilTime: false, + }, + }, + { + Name: "list_all", + Data: &listAllEncryptedValues{ + SQLTemplate: mocks.NewTestingSQLTemplate(), + Limit: 0, + Offset: 0, + HasUntilTime: false, + }, + }, + { + Name: "list_all_until_time", + Data: &listAllEncryptedValues{ + SQLTemplate: mocks.NewTestingSQLTemplate(), + Limit: 0, + Offset: 0, + HasUntilTime: true, + UntilTime: untilTime, + }, + }, + }, + sqlEncryptedValueCountAll: { + { + Name: "count_all", + Data: &countAllEncryptedValues{ + SQLTemplate: mocks.NewTestingSQLTemplate(), + HasUntilTime: false, + UntilTime: 0, + }, + }, + { + Name: "count_all_until_time", + Data: &countAllEncryptedValues{ + SQLTemplate: mocks.NewTestingSQLTemplate(), + HasUntilTime: true, + UntilTime: untilTime, + }, + }, + }, }, }) } diff --git a/pkg/storage/secret/encryption/testdata/mysql--encrypted_value_count_all-count_all.sql b/pkg/storage/secret/encryption/testdata/mysql--encrypted_value_count_all-count_all.sql new file mode 100755 index 00000000000..fc8594ad307 --- /dev/null +++ b/pkg/storage/secret/encryption/testdata/mysql--encrypted_value_count_all-count_all.sql @@ -0,0 +1,4 @@ +SELECT COUNT(*) AS count +FROM + `secret_encrypted_value` +; diff --git a/pkg/storage/secret/encryption/testdata/mysql--encrypted_value_count_all-count_all_until_time.sql b/pkg/storage/secret/encryption/testdata/mysql--encrypted_value_count_all-count_all_until_time.sql new file mode 100755 index 00000000000..760bc4432cc --- /dev/null +++ b/pkg/storage/secret/encryption/testdata/mysql--encrypted_value_count_all-count_all_until_time.sql @@ -0,0 +1,5 @@ +SELECT COUNT(*) AS count +FROM + `secret_encrypted_value` +WHERE `created` <= 1234 +; diff --git a/pkg/storage/secret/encryption/testdata/mysql--encrypted_value_list_all-list_all.sql b/pkg/storage/secret/encryption/testdata/mysql--encrypted_value_list_all-list_all.sql new file mode 100755 index 00000000000..74b699d45f1 --- /dev/null +++ b/pkg/storage/secret/encryption/testdata/mysql--encrypted_value_list_all-list_all.sql @@ -0,0 +1,11 @@ +SELECT + `namespace`, + `name`, + `version`, + `encrypted_data`, + `created`, + `updated` +FROM + `secret_encrypted_value` +ORDER BY `created` ASC +; diff --git a/pkg/storage/secret/encryption/testdata/mysql--encrypted_value_list_all-list_all_until_time.sql b/pkg/storage/secret/encryption/testdata/mysql--encrypted_value_list_all-list_all_until_time.sql new file mode 100755 index 00000000000..b34496aaf93 --- /dev/null +++ b/pkg/storage/secret/encryption/testdata/mysql--encrypted_value_list_all-list_all_until_time.sql @@ -0,0 +1,12 @@ +SELECT + `namespace`, + `name`, + `version`, + `encrypted_data`, + `created`, + `updated` +FROM + `secret_encrypted_value` +WHERE `created` <= 1234 +ORDER BY `created` ASC +; diff --git a/pkg/storage/secret/encryption/testdata/mysql--encrypted_value_list_all-list_limit_10_offset_0.sql b/pkg/storage/secret/encryption/testdata/mysql--encrypted_value_list_all-list_limit_10_offset_0.sql new file mode 100755 index 00000000000..9c33fd6bdbf --- /dev/null +++ b/pkg/storage/secret/encryption/testdata/mysql--encrypted_value_list_all-list_limit_10_offset_0.sql @@ -0,0 +1,12 @@ +SELECT + `namespace`, + `name`, + `version`, + `encrypted_data`, + `created`, + `updated` +FROM + `secret_encrypted_value` +ORDER BY `created` ASC +LIMIT 10 OFFSET 0 +; diff --git a/pkg/storage/secret/encryption/testdata/mysql--encrypted_value_list_all-list_limit_10_offset_2.sql b/pkg/storage/secret/encryption/testdata/mysql--encrypted_value_list_all-list_limit_10_offset_2.sql new file mode 100755 index 00000000000..d7066395a78 --- /dev/null +++ b/pkg/storage/secret/encryption/testdata/mysql--encrypted_value_list_all-list_limit_10_offset_2.sql @@ -0,0 +1,12 @@ +SELECT + `namespace`, + `name`, + `version`, + `encrypted_data`, + `created`, + `updated` +FROM + `secret_encrypted_value` +ORDER BY `created` ASC +LIMIT 10 OFFSET 2 +; diff --git a/pkg/storage/secret/encryption/testdata/postgres--encrypted_value_count_all-count_all.sql b/pkg/storage/secret/encryption/testdata/postgres--encrypted_value_count_all-count_all.sql new file mode 100755 index 00000000000..91c725a708f --- /dev/null +++ b/pkg/storage/secret/encryption/testdata/postgres--encrypted_value_count_all-count_all.sql @@ -0,0 +1,4 @@ +SELECT COUNT(*) AS count +FROM + "secret_encrypted_value" +; diff --git a/pkg/storage/secret/encryption/testdata/postgres--encrypted_value_count_all-count_all_until_time.sql b/pkg/storage/secret/encryption/testdata/postgres--encrypted_value_count_all-count_all_until_time.sql new file mode 100755 index 00000000000..1c691378494 --- /dev/null +++ b/pkg/storage/secret/encryption/testdata/postgres--encrypted_value_count_all-count_all_until_time.sql @@ -0,0 +1,5 @@ +SELECT COUNT(*) AS count +FROM + "secret_encrypted_value" +WHERE "created" <= 1234 +; diff --git a/pkg/storage/secret/encryption/testdata/postgres--encrypted_value_list_all-list_all.sql b/pkg/storage/secret/encryption/testdata/postgres--encrypted_value_list_all-list_all.sql new file mode 100755 index 00000000000..74432ebbf69 --- /dev/null +++ b/pkg/storage/secret/encryption/testdata/postgres--encrypted_value_list_all-list_all.sql @@ -0,0 +1,11 @@ +SELECT + "namespace", + "name", + "version", + "encrypted_data", + "created", + "updated" +FROM + "secret_encrypted_value" +ORDER BY "created" ASC +; diff --git a/pkg/storage/secret/encryption/testdata/postgres--encrypted_value_list_all-list_all_until_time.sql b/pkg/storage/secret/encryption/testdata/postgres--encrypted_value_list_all-list_all_until_time.sql new file mode 100755 index 00000000000..1d7089f751e --- /dev/null +++ b/pkg/storage/secret/encryption/testdata/postgres--encrypted_value_list_all-list_all_until_time.sql @@ -0,0 +1,12 @@ +SELECT + "namespace", + "name", + "version", + "encrypted_data", + "created", + "updated" +FROM + "secret_encrypted_value" +WHERE "created" <= 1234 +ORDER BY "created" ASC +; diff --git a/pkg/storage/secret/encryption/testdata/postgres--encrypted_value_list_all-list_limit_10_offset_0.sql b/pkg/storage/secret/encryption/testdata/postgres--encrypted_value_list_all-list_limit_10_offset_0.sql new file mode 100755 index 00000000000..6f2bbd0b90f --- /dev/null +++ b/pkg/storage/secret/encryption/testdata/postgres--encrypted_value_list_all-list_limit_10_offset_0.sql @@ -0,0 +1,12 @@ +SELECT + "namespace", + "name", + "version", + "encrypted_data", + "created", + "updated" +FROM + "secret_encrypted_value" +ORDER BY "created" ASC +LIMIT 10 OFFSET 0 +; diff --git a/pkg/storage/secret/encryption/testdata/postgres--encrypted_value_list_all-list_limit_10_offset_2.sql b/pkg/storage/secret/encryption/testdata/postgres--encrypted_value_list_all-list_limit_10_offset_2.sql new file mode 100755 index 00000000000..b9f326c8bf0 --- /dev/null +++ b/pkg/storage/secret/encryption/testdata/postgres--encrypted_value_list_all-list_limit_10_offset_2.sql @@ -0,0 +1,12 @@ +SELECT + "namespace", + "name", + "version", + "encrypted_data", + "created", + "updated" +FROM + "secret_encrypted_value" +ORDER BY "created" ASC +LIMIT 10 OFFSET 2 +; diff --git a/pkg/storage/secret/encryption/testdata/sqlite--encrypted_value_count_all-count_all.sql b/pkg/storage/secret/encryption/testdata/sqlite--encrypted_value_count_all-count_all.sql new file mode 100755 index 00000000000..91c725a708f --- /dev/null +++ b/pkg/storage/secret/encryption/testdata/sqlite--encrypted_value_count_all-count_all.sql @@ -0,0 +1,4 @@ +SELECT COUNT(*) AS count +FROM + "secret_encrypted_value" +; diff --git a/pkg/storage/secret/encryption/testdata/sqlite--encrypted_value_count_all-count_all_until_time.sql b/pkg/storage/secret/encryption/testdata/sqlite--encrypted_value_count_all-count_all_until_time.sql new file mode 100755 index 00000000000..1c691378494 --- /dev/null +++ b/pkg/storage/secret/encryption/testdata/sqlite--encrypted_value_count_all-count_all_until_time.sql @@ -0,0 +1,5 @@ +SELECT COUNT(*) AS count +FROM + "secret_encrypted_value" +WHERE "created" <= 1234 +; diff --git a/pkg/storage/secret/encryption/testdata/sqlite--encrypted_value_list_all-list_all.sql b/pkg/storage/secret/encryption/testdata/sqlite--encrypted_value_list_all-list_all.sql new file mode 100755 index 00000000000..74432ebbf69 --- /dev/null +++ b/pkg/storage/secret/encryption/testdata/sqlite--encrypted_value_list_all-list_all.sql @@ -0,0 +1,11 @@ +SELECT + "namespace", + "name", + "version", + "encrypted_data", + "created", + "updated" +FROM + "secret_encrypted_value" +ORDER BY "created" ASC +; diff --git a/pkg/storage/secret/encryption/testdata/sqlite--encrypted_value_list_all-list_all_until_time.sql b/pkg/storage/secret/encryption/testdata/sqlite--encrypted_value_list_all-list_all_until_time.sql new file mode 100755 index 00000000000..1d7089f751e --- /dev/null +++ b/pkg/storage/secret/encryption/testdata/sqlite--encrypted_value_list_all-list_all_until_time.sql @@ -0,0 +1,12 @@ +SELECT + "namespace", + "name", + "version", + "encrypted_data", + "created", + "updated" +FROM + "secret_encrypted_value" +WHERE "created" <= 1234 +ORDER BY "created" ASC +; diff --git a/pkg/storage/secret/encryption/testdata/sqlite--encrypted_value_list_all-list_limit_10_offset_0.sql b/pkg/storage/secret/encryption/testdata/sqlite--encrypted_value_list_all-list_limit_10_offset_0.sql new file mode 100755 index 00000000000..6f2bbd0b90f --- /dev/null +++ b/pkg/storage/secret/encryption/testdata/sqlite--encrypted_value_list_all-list_limit_10_offset_0.sql @@ -0,0 +1,12 @@ +SELECT + "namespace", + "name", + "version", + "encrypted_data", + "created", + "updated" +FROM + "secret_encrypted_value" +ORDER BY "created" ASC +LIMIT 10 OFFSET 0 +; diff --git a/pkg/storage/secret/encryption/testdata/sqlite--encrypted_value_list_all-list_limit_10_offset_2.sql b/pkg/storage/secret/encryption/testdata/sqlite--encrypted_value_list_all-list_limit_10_offset_2.sql new file mode 100755 index 00000000000..b9f326c8bf0 --- /dev/null +++ b/pkg/storage/secret/encryption/testdata/sqlite--encrypted_value_list_all-list_limit_10_offset_2.sql @@ -0,0 +1,12 @@ +SELECT + "namespace", + "name", + "version", + "encrypted_data", + "created", + "updated" +FROM + "secret_encrypted_value" +ORDER BY "created" ASC +LIMIT 10 OFFSET 2 +; From 4da2c50990cf2fd16e97a52be082a8e254f816c5 Mon Sep 17 00:00:00 2001 From: ti361 Date: Mon, 28 Jul 2025 18:10:20 +0800 Subject: [PATCH 034/131] change method "GET" to "DELETE" with the "Delete a report" API (#108750) --- docs/sources/developers/http_api/reporting.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sources/developers/http_api/reporting.md b/docs/sources/developers/http_api/reporting.md index 8666f253e63..4b02276975b 100644 --- a/docs/sources/developers/http_api/reporting.md +++ b/docs/sources/developers/http_api/reporting.md @@ -401,7 +401,7 @@ See note in the [introduction](#reporting-api) for an explanation. ### Example request ```http -GET /api/reports/6 HTTP/1.1 +DELETE /api/reports/6 HTTP/1.1 Accept: application/json Content-Type: application/json Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk From af376cd286a59eeca7870d4c373bd438845554c7 Mon Sep 17 00:00:00 2001 From: Konrad Lalik Date: Mon, 28 Jul 2025 12:22:36 +0200 Subject: [PATCH 035/131] Alerting: Fix backtick handling when hashing queries (#108757) Update the hashQuery algorithm to handle more formatting edge cases --- .../utils/__snapshots__/rule-id.test.tsx.snap | 4 +- .../alerting/unified/utils/rule-id.test.tsx | 118 +++++++++++++++++- .../alerting/unified/utils/rule-id.ts | 14 ++- 3 files changed, 132 insertions(+), 4 deletions(-) diff --git a/public/app/features/alerting/unified/utils/__snapshots__/rule-id.test.tsx.snap b/public/app/features/alerting/unified/utils/__snapshots__/rule-id.test.tsx.snap index 00fe79eb53d..9facadeeacc 100644 --- a/public/app/features/alerting/unified/utils/__snapshots__/rule-id.test.tsx.snap +++ b/public/app/features/alerting/unified/utils/__snapshots__/rule-id.test.tsx.snap @@ -1,5 +1,5 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`hashRulerRule should hash alerting rule 1`] = `"7317348"`; +exports[`hashRulerRule should hash alerting rule 1`] = `"852037155"`; -exports[`hashRulerRule should hash recording rules 1`] = `"-447747460"`; +exports[`hashRulerRule should hash recording rules 1`] = `"914562864"`; diff --git a/public/app/features/alerting/unified/utils/rule-id.test.tsx b/public/app/features/alerting/unified/utils/rule-id.test.tsx index e2652c11885..7fedf534b3b 100644 --- a/public/app/features/alerting/unified/utils/rule-id.test.tsx +++ b/public/app/features/alerting/unified/utils/rule-id.test.tsx @@ -13,7 +13,15 @@ import { RulerRecordingRuleDTO, } from 'app/types/unified-alerting-dto'; -import { equal, getRuleIdFromPathname, hashRule, hashRulerRule, parse, stringifyIdentifier } from './rule-id'; +import { + equal, + getRuleIdFromPathname, + hashQuery, + hashRule, + hashRulerRule, + parse, + stringifyIdentifier, +} from './rule-id'; const alertingRule = { prom: { @@ -258,3 +266,111 @@ describe('useRuleIdFromPathname', () => { expect(result.current).toBe('abc%25def'); }); }); + +describe('hashQuery', () => { + it('should produce the same hash for queries with different whitespace formatting', () => { + const query1 = `sum by (client,origin,destination,met_val)( + sum_over_time( + {client=~"PRU|RVSI"} + ) +)`; + const query2 = `sum by (client,origin,destination,met_val)(sum_over_time({client=~"PRU|RVSI"}))`; + + expect(hashQuery(query1)).toBe(hashQuery(query2)); + }); + + it('should produce the same hash for queries with and without outer parentheses', () => { + const query1 = `sum by (client)(rate(requests_total[5m]))`; + const query2 = `(sum by (client)(rate(requests_total[5m])))`; + + expect(hashQuery(query1)).toBe(hashQuery(query2)); + }); + + it('should produce the same hash for queries with different quote types in label formats', () => { + const query1 = `label_format origin=\`{{.app_host}}\``; + const query2 = `label_format origin="{{.app_host}}"`; + + expect(hashQuery(query1)).toBe(hashQuery(query2)); + }); + + it('should produce the same hash for queries with escaped vs unescaped quotes', () => { + const query1 = `label_format met_val=\`{{"REQ_SENT"}}\``; + const query2 = `label_format met_val="{{\"REQ_SENT\"}}"`; + + expect(hashQuery(query1)).toBe(hashQuery(query2)); + }); + + it('should handle complex Loki recording rules with all formatting differences', () => { + const query1 = `sum by (client,origin,destination,metric_type)( + sum_over_time( + {client=~"FOO|BAR|BAZ", service_name="app_sessions"} + |= "server" + |= "component" + | logfmt + | label_format origin=\`{{.host_name}}\` + | label_format destination=\`{{.component_name}}\` + | label_format metric_type=\`{{"REQUEST_COUNT"}}\` + | keep client,destination,origin,metric_type,response_time + | unwrap response_time + [5m]) +) > 0`; + + const query2 = `(sum by (client,origin,destination,metric_type)(sum_over_time({client=~"FOO|BAR|BAZ", service_name="app_sessions"} |= "server" |= "component" | logfmt | label_format origin="{{.host_name}}" | label_format destination="{{.component_name}}" | label_format metric_type="{{\"REQUEST_COUNT\"}}" | keep client,destination,origin,metric_type,response_time | unwrap response_time[5m])) > 0)`; + + expect(hashQuery(query1)).toBe(hashQuery(query2)); + }); + + it('should produce the same hash for queries with reordered label matchers', () => { + const query1 = `{job="prometheus", instance="localhost:9090"}`; + const query2 = `{instance="localhost:9090", job="prometheus"}`; + + expect(hashQuery(query1)).toBe(hashQuery(query2)); + }); + + it('should handle multiple types of brackets and quotes', () => { + const query1 = `rate(http_requests_total{method="GET"}[5m])`; + const query2 = `rate(http_requests_total{method=\`GET\`}[5m])`; + + expect(hashQuery(query1)).toBe(hashQuery(query2)); + }); + + it('should normalize backslashes properly', () => { + const query1 = `label_format path="{{.file_path}}"`; + const query2 = `label_format path="{{\.file_path}}"`; + + expect(hashQuery(query1)).toBe(hashQuery(query2)); + }); + + it('should handle empty queries', () => { + expect(hashQuery('')).toBe(''); + }); + + it('should handle queries with only parentheses', () => { + expect(hashQuery('()')).toBe(''); + }); + + it('should handle complex nested parentheses and brackets', () => { + const query1 = `((sum(rate(requests[5m]))))`; + const query2 = `sum(rate(requests[5m]))`; + + expect(hashQuery(query1)).toBe(hashQuery(query2)); + }); + + it('should handle mixed quote escaping scenarios', () => { + const query1 = `label_format msg=\`{{"error: \\"timeout\\""}}\``; + const query2 = `label_format msg="{{\"error: \\\"timeout\\\"\"}}"`; + + expect(hashQuery(query1)).toBe(hashQuery(query2)); + }); + + it('should produce consistent results for character sorting', () => { + const query1 = `abc{x="1",y="2"}`; + const query2 = `abc{y="2",x="1"}`; + + const hash1 = hashQuery(query1); + const hash2 = hashQuery(query2); + + expect(hash1).toBe(hash2); + expect(hash1).toBe(hash1.split('').sort().join('')); + }); +}); diff --git a/public/app/features/alerting/unified/utils/rule-id.ts b/public/app/features/alerting/unified/utils/rule-id.ts index b2eb9a663c0..f8db7346df3 100644 --- a/public/app/features/alerting/unified/utils/rule-id.ts +++ b/public/app/features/alerting/unified/utils/rule-id.ts @@ -311,9 +311,21 @@ export function hashQuery(query: string) { if (query.length > 1 && query[0] === '(' && query[query.length - 1] === ')') { query = query.slice(1, -1); } + // whitespace could be added or removed query = query.replace(/\s|\n/g, ''); - // labels matchers can be reordered, so sort the enitre string, esentially comparing just the character counts + + // normalize escaped quotes in template strings like {{\"REQ_SENT\"}} -> {{"REQ_SENT"}} + query = query.replace(/\\"/g, '"'); + + // normalize backtick template strings to double quotes for consistency + // Convert `{{.field}}` to "{{.field}}" + query = query.replace(/`([^`]*)`/g, '"$1"'); + + // remove quotes, brackets, parentheses, backslashes, and backticks + query = query.replace(/['"()\[\]\\`]/g, ''); + + // labels matchers can be reordered, so sort the entire string, essentially comparing just the character counts return query.split('').sort().join(''); } From 814fccb970515f4a7738339a99f7832726d54c2a Mon Sep 17 00:00:00 2001 From: Gilles De Mey Date: Mon, 28 Jul 2025 12:31:51 +0200 Subject: [PATCH 036/131] Alerting: Use the official maildev image again (#108768) --- devenv/docker/blocks/maildev/docker-compose.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devenv/docker/blocks/maildev/docker-compose.yaml b/devenv/docker/blocks/maildev/docker-compose.yaml index 7cc648a23d1..50d639e13bc 100644 --- a/devenv/docker/blocks/maildev/docker-compose.yaml +++ b/devenv/docker/blocks/maildev/docker-compose.yaml @@ -1,5 +1,5 @@ maildev: - image: gillesdemey/maildev + image: maildev/maildev:2.2.1 ports: - "12080:1080" - "1025:1025" From ffb8f4ea0c0eed3cb483edc0973388732d2fc2aa Mon Sep 17 00:00:00 2001 From: Kristina Date: Mon, 28 Jul 2025 05:50:47 -0500 Subject: [PATCH 037/131] Transformations: Rename Regression Analysis to Trendline (#108631) * Rename regression analysis transformation * fix a couple translations * remove extra word * Fix tests * Change frame name to use regression --- .../query-transform-data/transform-data/index.md | 8 +++++--- public/app/features/transformers/docs/content.ts | 8 +++++--- .../features/transformers/regression/regression.test.ts | 6 +++--- public/app/features/transformers/regression/regression.ts | 4 ++-- .../features/transformers/regression/regressionEditor.tsx | 1 + public/locales/en-US/grafana.json | 5 ++++- 6 files changed, 20 insertions(+), 12 deletions(-) diff --git a/docs/sources/panels-visualizations/query-transform-data/transform-data/index.md b/docs/sources/panels-visualizations/query-transform-data/transform-data/index.md index 033115c665c..ba94fe38671 100644 --- a/docs/sources/panels-visualizations/query-transform-data/transform-data/index.md +++ b/docs/sources/panels-visualizations/query-transform-data/transform-data/index.md @@ -1483,17 +1483,19 @@ If you have multiple types it will default to string type. {{< figure src="/media/docs/grafana/transformations/screenshot-grafana-11-2-transpose-transformation.png" class="docs-image--no-shadow" max-width= "1100px" alt="Before and after transpose transformation" >}} -### Regression analysis +### Trendline Use this transformation to create a new data frame containing values predicted by a statistical model. This is useful for finding a trend in chaotic data. It works by fitting a mathematical function to the data, using either linear or polynomial regression. The data frame can then be used in a visualization to display a trendline. There are two different models: -- **Linear regression** - Fits a linear function to the data. +- **Linear** - Fits a linear function to the data. {{< figure src="/static/img/docs/transformations/linear-regression.png" class="docs-image--no-shadow" max-width= "1100px" alt="A time series visualization with a straight line representing the linear function" >}} -- **Polynomial regression** - Fits a polynomial function to the data. +- **Polynomial** - Fits a polynomial function to the data. {{< figure src="/static/img/docs/transformations/polynomial-regression.png" class="docs-image--no-shadow" max-width= "1100px" alt="A time series visualization with a curved line representing the polynomial function" >}} +> **Note:** This transformation was previously called regression analysis. + [Table panel]: ref:table-panel [Calculation types]: ref:calculation-types [sparkline cell type]: ref:sparkline-cell-type diff --git a/public/app/features/transformers/docs/content.ts b/public/app/features/transformers/docs/content.ts index a441149469d..5f7d8e14703 100644 --- a/public/app/features/transformers/docs/content.ts +++ b/public/app/features/transformers/docs/content.ts @@ -1584,25 +1584,27 @@ ${buildImageContent( }, }, regression: { - name: 'Regression analysis', + name: 'Trendline', getHelperDocs: function (imageRenderType: ImageRenderType = ImageRenderType.ShortcodeFigure) { return ` Use this transformation to create a new data frame containing values predicted by a statistical model. This is useful for finding a trend in chaotic data. It works by fitting a mathematical function to the data, using either linear or polynomial regression. The data frame can then be used in a visualization to display a trendline. There are two different models: -- **Linear regression** - Fits a linear function to the data. +- **Linear** - Fits a linear function to the data. ${buildImageContent( '/static/img/docs/transformations/linear-regression.png', imageRenderType, 'A time series visualization with a straight line representing the linear function' )} -- **Polynomial regression** - Fits a polynomial function to the data. +- **Polynomial** - Fits a polynomial function to the data. ${buildImageContent( '/static/img/docs/transformations/polynomial-regression.png', imageRenderType, 'A time series visualization with a curved line representing the polynomial function' )} + +> **Note:** This transformation was previously called regression analysis. `; }, }, diff --git a/public/app/features/transformers/regression/regression.test.ts b/public/app/features/transformers/regression/regression.test.ts index 82aa0952e72..f3048fa32e0 100644 --- a/public/app/features/transformers/regression/regression.test.ts +++ b/public/app/features/transformers/regression/regression.test.ts @@ -10,7 +10,7 @@ import { import { ModelType, getRegressionTransformer, RegressionTransformerOptions } from './regression'; -describe('Regression transformation', () => { +describe('Trendline transformation', () => { const RegressionTransformer = getRegressionTransformer(); it('it should predict a linear regression to exactly fit the data when the data is f(x) = x', () => { @@ -47,7 +47,7 @@ describe('Regression transformation', () => { name: 'Linear regression', fields: [ { name: 'time', type: FieldType.time, values: [0, 1, 2, 3, 4, 5], config: {} }, - { name: 'value predicted', type: FieldType.number, values: [0, 1, 2, 3, 4, 5], config: {} }, + { name: 'value', type: FieldType.number, values: [0, 1, 2, 3, 4, 5], config: {} }, ], length: 6, }), @@ -88,7 +88,7 @@ describe('Regression transformation', () => { name: 'Linear regression', fields: [ { name: 'time', type: FieldType.time, values: [0, 1, 2, 3, 4, 5], config: {} }, - { name: 'value predicted', type: FieldType.number, values: [1, 1, 1, 1, 1, 1], config: {} }, + { name: 'value', type: FieldType.number, values: [1, 1, 1, 1, 1, 1], config: {} }, ], length: 6, }), diff --git a/public/app/features/transformers/regression/regression.ts b/public/app/features/transformers/regression/regression.ts index cda498b5e9b..ce350dde9ac 100644 --- a/public/app/features/transformers/regression/regression.ts +++ b/public/app/features/transformers/regression/regression.ts @@ -37,7 +37,7 @@ export const DEGREES = [ export const getRegressionTransformer: () => SynchronousDataTransformerInfo = () => ({ id: DataTransformerID.regression, - name: t('transformers.regression.name.regression-analysis', 'Regression analysis'), + name: t('transformers.regression.name.trendline', 'Trendline'), description: t( 'transformers.regression.description.create-new-data-frame', 'Create a new data frame containing values predicted by a statistical model.' @@ -129,7 +129,7 @@ export const getRegressionTransformer: () => SynchronousDataTransformerInfo result.predict(x - normalizationSubtrahend)), config: {}, diff --git a/public/app/features/transformers/regression/regressionEditor.tsx b/public/app/features/transformers/regression/regressionEditor.tsx index abf9b862b19..86da5797d10 100644 --- a/public/app/features/transformers/regression/regressionEditor.tsx +++ b/public/app/features/transformers/regression/regressionEditor.tsx @@ -171,5 +171,6 @@ export const getRegressionTransformerRegistryItem: () => TransformerRegistryItem help: getTransformationContent(DataTransformerID.regression).helperDocs, imageDark: darkImage, imageLight: lightImage, + tags: new Set([t('transformers.regression-transformer-editor.tags.regression-analysis', 'Regression analysis')]), }; }; diff --git a/public/locales/en-US/grafana.json b/public/locales/en-US/grafana.json index 2fad1ff4fb6..d0aa51d51e2 100644 --- a/public/locales/en-US/grafana.json +++ b/public/locales/en-US/grafana.json @@ -13443,7 +13443,7 @@ "create-new-data-frame": "Create a new data frame containing values predicted by a statistical model." }, "name": { - "regression-analysis": "Regression analysis" + "trendline": "Trendline" } }, "regression-transformer-editor": { @@ -13465,6 +13465,9 @@ } }, "regression": "regression", + "tags": { + "regression-analysis": "Regression analysis" + }, "tooltip-number-of-xy-points-to-predict": "Number of X,Y points to predict" }, "rename-by-regex-transformer": { From ce64a78d994fe1c25931f417eb377744a6ea9a5f Mon Sep 17 00:00:00 2001 From: Timur Olzhabayev Date: Mon, 28 Jul 2025 12:51:28 +0200 Subject: [PATCH 038/131] Feat: Improve auto-triager logic to check for internal team members via api (#108578) improve auto triager logic to check for internal team members via api --- .github/workflows/issue-opened.yml | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/.github/workflows/issue-opened.yml b/.github/workflows/issue-opened.yml index 80b853d0c69..b54bb968b7f 100644 --- a/.github/workflows/issue-opened.yml +++ b/.github/workflows/issue-opened.yml @@ -39,7 +39,7 @@ jobs: - name: "Get vault secrets" id: vault-secrets - uses: grafana/shared-workflows/actions/get-vault-secrets@main # zizmor: ignore[unpinned-uses] + uses: grafana/shared-workflows/actions/get-vault-secrets@get-vault-secrets/v1.2.1 # zizmor: ignore[unpinned-uses] with: # Secrets placed in the ci/repo/grafana/grafana/plugins_platform_issue_commands_github_bot path in Vault repo_secrets: | @@ -48,10 +48,11 @@ jobs: - name: Generate token id: generate_token - uses: actions/create-github-app-token@3ff1caaa28b64c9cc276ce0a02e2ff584f3900c5 # v2.0.2 + uses: actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e # v2.0.6 with: app-id: ${{ env.GITHUB_APP_ID }} private-key: ${{ env.GITHUB_APP_PRIVATE_KEY }} + permission-issues: write - name: Run Commands uses: ./actions/commands @@ -64,13 +65,13 @@ jobs: permissions: contents: read id-token: write - if: github.repository == 'grafana/grafana' && github.event.issue.author_association != 'MEMBER' && github.event.issue.author_association != 'OWNER' + if: github.repository == 'grafana/grafana' runs-on: ubuntu-latest steps: - name: "Get vault secrets" id: vault-secrets - uses: grafana/shared-workflows/actions/get-vault-secrets@main # zizmor: ignore[unpinned-uses] + uses: grafana/shared-workflows/actions/get-vault-secrets@get-vault-secrets/v1.2.1 # zizmor: ignore[unpinned-uses] with: # Secrets placed in the ci/repo/grafana/grafana/plugins_platform_issue_triager path in Vault repo_secrets: | @@ -81,18 +82,23 @@ jobs: - name: Generate token id: generate_token - uses: actions/create-github-app-token@3ff1caaa28b64c9cc276ce0a02e2ff584f3900c5 # v2.0.2 + uses: actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e # v2.0.6 with: app-id: ${{ env.GITHUB_APP_ID }} private-key: ${{ env.GITHUB_APP_PRIVATE_KEY }} + permission-members: read + permission-issues: write - - name: Checkout - uses: actions/checkout@v4 # v4.2.2 - with: - persist-credentials: false - + - name: Check if member of grafana org + id: check-if-grafana-org-member + continue-on-error: true + run: gh api https://api.github.com/orgs/grafana/members/${{ env.ACTOR }} >/dev/null 2>&1 && echo "is_grafana_org_member=true" >> "$GITHUB_OUTPUT" + env: + GH_TOKEN: ${{ steps.generate_token.outputs.token }} + ACTOR: ${{ github.actor }} - name: Send issue to the auto triager action id: auto_triage + if: steps.check-if-grafana-org-member.outputs.is_grafana_org_member != 'true' && github.event.issue.author_association != 'MEMBER' && github.event.issue.author_association != 'OWNER' uses: grafana/auto-triager@main # zizmor: ignore[unpinned-uses] with: token: ${{ steps.generate_token.outputs.token }} @@ -127,7 +133,7 @@ jobs: steps: - name: "Get vault secrets" id: vault-secrets - uses: grafana/shared-workflows/actions/get-vault-secrets@main # zizmor: ignore[unpinned-uses] + uses: grafana/shared-workflows/actions/get-vault-secrets@get-vault-secrets/v1.2.1 # zizmor: ignore[unpinned-uses] with: # Secrets placed in the ci/repo/grafana/grafana/plugins_platform_issue_triager path in Vault repo_secrets: | From c88a6fc2e72cb9727fe6139c2f0dff337973cc07 Mon Sep 17 00:00:00 2001 From: ismail simsek Date: Mon, 28 Jul 2025 13:02:16 +0200 Subject: [PATCH 039/131] Prometheus: Performance improvements for high cardinality metrics in code editor (#108341) * disable auto fetch * add partially written metric name situation * add new limit * add new methods * rename methods * implement auto complete after typing at least three letters * betterer * cosmetic changes * partial or full trigger * cleaner approach * lint * fix * review feedback --- .betterer.results | 3 - .../src/components/PromQueryField.tsx | 95 +++----- .../monaco-query-field/MonacoQueryField.tsx | 34 ++- .../completions.test.ts | 24 +-- .../monaco-completion-provider/completions.ts | 75 ++++--- .../data_provider.ts | 50 +++-- .../monaco-completion-provider.ts | 143 ++++++++++-- .../monaco-completion-provider/situation.ts | 5 + .../src/components/useMetricsState.test.ts | 113 ---------- .../src/components/useMetricsState.ts | 38 ---- .../usePromQueryFieldEffects.test.ts | 204 ------------------ .../components/usePromQueryFieldEffects.ts | 64 ------ packages/grafana-prometheus/src/constants.ts | 5 + .../src/locales/en-US/grafana-prometheus.json | 4 + 14 files changed, 294 insertions(+), 563 deletions(-) delete mode 100644 packages/grafana-prometheus/src/components/useMetricsState.test.ts delete mode 100644 packages/grafana-prometheus/src/components/useMetricsState.ts delete mode 100644 packages/grafana-prometheus/src/components/usePromQueryFieldEffects.test.ts delete mode 100644 packages/grafana-prometheus/src/components/usePromQueryFieldEffects.ts diff --git a/.betterer.results b/.betterer.results index 6429e7b67b5..1ab5b19047e 100644 --- a/.betterer.results +++ b/.betterer.results @@ -420,9 +420,6 @@ exports[`better eslint`] = { "packages/grafana-o11y-ds-frontend/src/createNodeGraphFrames.ts:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"] ], - "packages/grafana-prometheus/src/components/PromQueryField.tsx:5381": [ - [0, 0, 0, "Unexpected any. Specify a different type.", "0"] - ], "packages/grafana-prometheus/src/components/metrics-browser/useMetricsLabelsValues.ts:5381": [ [0, 0, 0, "Direct usage of localStorage is not allowed. import store from @grafana/data instead", "0"], [0, 0, 0, "Direct usage of localStorage is not allowed. import store from @grafana/data instead", "1"], diff --git a/packages/grafana-prometheus/src/components/PromQueryField.tsx b/packages/grafana-prometheus/src/components/PromQueryField.tsx index 93094992348..289b206b7d2 100644 --- a/packages/grafana-prometheus/src/components/PromQueryField.tsx +++ b/packages/grafana-prometheus/src/components/PromQueryField.tsx @@ -1,10 +1,17 @@ // Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/components/PromQueryField.tsx import { css, cx } from '@emotion/css'; -import { MutableRefObject, ReactNode, useCallback, useState } from 'react'; +import { ReactNode, useCallback, useEffect, useState } from 'react'; -import { getDefaultTimeRange, isDataFrame, QueryEditorProps, QueryHint, toLegacyResponseData } from '@grafana/data'; +import { + DataFrame, + getDefaultTimeRange, + isDataFrame, + QueryEditorProps, + QueryHint, + toLegacyResponseData, +} from '@grafana/data'; import { selectors } from '@grafana/e2e-selectors'; -import { t } from '@grafana/i18n'; +import { t, Trans } from '@grafana/i18n'; import { reportInteraction } from '@grafana/runtime'; import { clearButtonStyles, Icon, useTheme2 } from '@grafana/ui'; @@ -12,12 +19,9 @@ import { PrometheusDatasource } from '../datasource'; import { getInitHints } from '../query_hints'; import { PromOptions, PromQuery } from '../types'; -import { CancelablePromise, isCancelablePromiseRejection, makePromiseCancelable } from './cancelable-promise'; import { MetricsBrowser } from './metrics-browser/MetricsBrowser'; import { MetricsBrowserProvider } from './metrics-browser/MetricsBrowserContext'; import { MonacoQueryFieldWrapper } from './monaco-query-field/MonacoQueryFieldWrapper'; -import { useMetricsState } from './useMetricsState'; -import { usePromQueryFieldEffects } from './usePromQueryFieldEffects'; interface PromQueryFieldProps extends QueryEditorProps { ExtraFieldElement?: ReactNode; @@ -40,68 +44,32 @@ export const PromQueryField = (props: PromQueryFieldProps) => { const theme = useTheme2(); - const [syntaxLoaded, setSyntaxLoaded] = useState(false); const [hint, setHint] = useState(null); const [labelBrowserVisible, setLabelBrowserVisible] = useState(false); - const updateLanguage = useCallback(() => { - if (languageProvider.retrieveMetrics()) { - setSyntaxLoaded(true); - } - }, [languageProvider]); + const refreshHint = useCallback( + (series: DataFrame[]) => { + const initHints = getInitHints(datasource); + const initHint = initHints[0] ?? null; - const refreshMetrics = useCallback( - async (languageProviderInitRef: MutableRefObject | null>) => { - // Cancel any existing initialization using the ref - if (languageProviderInitRef.current) { - languageProviderInitRef.current.cancel(); - } - - if (!languageProvider || !range) { + // If no data or empty series, use default hint + if (!data?.series?.length) { + setHint(initHint); return; } - try { - const initialization = makePromiseCancelable(languageProvider.start(range)); - languageProviderInitRef.current = initialization; + const result = isDataFrame(series[0]) ? series.map(toLegacyResponseData) : series; + const queryHints = datasource.getQueryHints(query, result); + let queryHint = queryHints.length > 0 ? queryHints[0] : null; - const remainingTasks = await initialization.promise; - - // If there are remaining tasks, wait for them - if (Array.isArray(remainingTasks) && remainingTasks.length > 0) { - await Promise.all(remainingTasks); - } - - updateLanguage(); - } catch (err) { - if (isCancelablePromiseRejection(err) && err.isCanceled) { - // do nothing, promise was canceled - } else { - throw err; - } - } finally { - languageProviderInitRef.current = null; - } + setHint(queryHint ?? initHint); }, - [languageProvider, range, updateLanguage] + [data, datasource, query] ); - const refreshHint = useCallback(() => { - const initHints = getInitHints(datasource); - const initHint = initHints[0] ?? null; - - // If no data or empty series, use default hint - if (!data?.series?.length) { - setHint(initHint); - return; - } - - const result = isDataFrame(data.series[0]) ? data.series.map(toLegacyResponseData) : data.series; - const queryHints = datasource.getQueryHints(query, result); - let queryHint = queryHints.length > 0 ? queryHints[0] : null; - - setHint(queryHint ?? initHint); - }, [data, datasource, query]); + useEffect(() => { + refreshHint(data?.series ?? []); + }, [data?.series, refreshHint]); const onChangeQuery = (value: string, override?: boolean) => { if (!onChange) { @@ -137,11 +105,6 @@ export const PromQueryField = (props: PromQueryFieldProps) => { onRunQuery(); }; - // Use our custom effects hook - usePromQueryFieldEffects(languageProvider, range, data?.series, refreshMetrics, refreshHint); - - const { chooserText, buttonDisabled } = useMetricsState(datasource, languageProvider, syntaxLoaded); - return ( <>
{ diff --git a/packages/grafana-prometheus/src/components/monaco-query-field/MonacoQueryField.tsx b/packages/grafana-prometheus/src/components/monaco-query-field/MonacoQueryField.tsx index 0200645d392..e37f9b47f57 100644 --- a/packages/grafana-prometheus/src/components/monaco-query-field/MonacoQueryField.tsx +++ b/packages/grafana-prometheus/src/components/monaco-query-field/MonacoQueryField.tsx @@ -155,7 +155,13 @@ const MonacoQueryField = (props: Props) => { historyProvider: historyRef.current, languageProvider: lpRef.current, }); - const completionProvider = getCompletionProvider(monaco, dataProvider, timeRange); + + // Create completion provider with state for Ctrl+Space detection + const { provider: completionProvider, state: completionState } = getCompletionProvider( + monaco, + dataProvider, + timeRange + ); // completion-providers in monaco are not registered directly to editor-instances, // they are registered to languages. this makes it hard for us to have @@ -182,7 +188,31 @@ const MonacoQueryField = (props: Props) => { filteringCompletionProvider ); - autocompleteDisposeFun.current = dispose; + const handleKeyDown = (event: KeyboardEvent) => { + if ((event.ctrlKey || event.metaKey) && event.code === 'Space') { + // Only handle if this editor is focused + if (editor.hasTextFocus()) { + event.preventDefault(); + event.stopPropagation(); + + completionState.isManualTriggerRequested = true; + editor.trigger('keyboard', 'editor.action.triggerSuggest', {}); + setTimeout(() => { + completionState.isManualTriggerRequested = false; + }, 300); + } + } + }; + + // Add global listener + document.addEventListener('keydown', handleKeyDown, true); + + // Combine cleanup functions + autocompleteDisposeFun.current = () => { + document.removeEventListener('keydown', handleKeyDown, true); + dispose(); + }; + // this code makes the editor resize itself so that the content fits // (it will grow taller when necessary) // FIXME: maybe move this functionality into CodeEditor, like: diff --git a/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/completions.test.ts b/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/completions.test.ts index e6df676beba..7219a53505a 100644 --- a/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/completions.test.ts +++ b/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/completions.test.ts @@ -1,6 +1,6 @@ import { config } from '@grafana/runtime'; -import { SUGGESTIONS_LIMIT } from '../../../constants'; +import { DEFAULT_COMPLETION_LIMIT } from '../../../constants'; import { getFunctions } from '../../../promql'; import { getMockTimeRange } from '../../../test/mocks/datasource'; @@ -12,7 +12,7 @@ const history: string[] = ['previous_metric_name_1', 'previous_metric_name_2', ' const dataProviderSettings = { languageProvider: { datasource: { - metricNamesAutocompleteSuggestionLimit: SUGGESTIONS_LIMIT, + metricNamesAutocompleteSuggestionLimit: DEFAULT_COMPLETION_LIMIT, }, queryLabelKeys: jest.fn(), queryLabelValues: jest.fn(), @@ -23,9 +23,9 @@ const dataProviderSettings = { } as unknown as DataProviderParams; let dataProvider = new DataProvider(dataProviderSettings); const metrics = { - beyondLimit: Array.from(Array(SUGGESTIONS_LIMIT + 1), (_, i) => `metric_name_${i}`), + beyondLimit: Array.from(Array(DEFAULT_COMPLETION_LIMIT + 1), (_, i) => `metric_name_${i}`), get atLimit() { - return this.beyondLimit.slice(0, SUGGESTIONS_LIMIT - 1); + return this.beyondLimit.slice(0, DEFAULT_COMPLETION_LIMIT - 1); }, }; @@ -171,7 +171,7 @@ type MetricNameSituation = Extract { - jest.spyOn(dataProvider, 'getAllMetricNames').mockReturnValue(metrics.atLimit); + jest.spyOn(dataProvider, 'queryMetricNames').mockResolvedValue(metrics.atLimit); const expectedCompletionsCount = getSuggestionCountForSituation(situationType, metrics.atLimit.length); const situation: Situation = { type: situationType, @@ -232,7 +232,7 @@ describe.each(metricNameCompletionSituations)('metric name completions in situat expect(dataProvider.monacoSettings.suggestionsIncomplete).toBe(false); // Cross the metric names threshold, without text input - jest.spyOn(dataProvider, 'getAllMetricNames').mockReturnValueOnce(metrics.beyondLimit); + jest.spyOn(dataProvider, 'queryMetricNames').mockResolvedValue(metrics.beyondLimit); dataProvider.monacoSettings.setInputInRange(''); await getCompletions(situation, dataProvider, timeRange); expect(dataProvider.monacoSettings.suggestionsIncomplete).toBe(true); @@ -250,7 +250,7 @@ describe.each(metricNameCompletionSituations)('metric name completions in situat }; const testMetrics = ['metric_name_1', 'metric_name_2', 'metric_name_1_with_extra_terms', 'unrelated_metric']; - jest.spyOn(dataProvider, 'getAllMetricNames').mockReturnValue(testMetrics); + jest.spyOn(dataProvider, 'queryMetricNames').mockResolvedValue(testMetrics); // Test with a complex query (> 4 terms) dataProvider.monacoSettings.setInputInRange('metric name 1 with extra terms more'); @@ -284,7 +284,7 @@ describe('Label value completions', () => { getAllMetricNames: jest.fn(), metricNamesToMetrics: jest.fn(), getHistory: jest.fn(), - getLabelValues: jest.fn().mockResolvedValue(['value1', 'value"2', 'value\\3', "value'4"]), + queryLabelValues: jest.fn().mockResolvedValue(['value1', 'value"2', 'value\\3', "value'4"]), monacoSettings: { setInputInRange: jest.fn(), inputInRange: '', @@ -397,7 +397,7 @@ describe('Label value completions', () => { const timeRange = getMockTimeRange(); it('should handle empty values', async () => { - jest.spyOn(dataProvider, 'getLabelValues').mockResolvedValue(['']); + jest.spyOn(dataProvider, 'queryLabelValues').mockResolvedValue(['']); const situation: Situation = { type: 'IN_LABEL_SELECTOR_WITH_LABEL_NAME', @@ -412,7 +412,7 @@ describe('Label value completions', () => { }); it('should handle values with multiple special characters', async () => { - jest.spyOn(dataProvider, 'getLabelValues').mockResolvedValue(['test"\\value']); + jest.spyOn(dataProvider, 'queryLabelValues').mockResolvedValue(['test"\\value']); const situation: Situation = { type: 'IN_LABEL_SELECTOR_WITH_LABEL_NAME', @@ -427,7 +427,7 @@ describe('Label value completions', () => { }); it('should handle non-string values', async () => { - jest.spyOn(dataProvider, 'getLabelValues').mockResolvedValue([123 as unknown as string]); + jest.spyOn(dataProvider, 'queryLabelValues').mockResolvedValue([123 as unknown as string]); const situation: Situation = { type: 'IN_LABEL_SELECTOR_WITH_LABEL_NAME', diff --git a/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/completions.ts b/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/completions.ts index f7fc08f8bce..2a463548bfe 100644 --- a/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/completions.ts +++ b/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/completions.ts @@ -5,11 +5,13 @@ import { languages } from 'monaco-editor'; import { TimeRange } from '@grafana/data'; import { config } from '@grafana/runtime'; +import { DEFAULT_COMPLETION_LIMIT } from '../../../constants'; import { escapeLabelValueInExactSelector, prometheusRegularEscape } from '../../../escaping'; import { getFunctions } from '../../../promql'; import { isValidLegacyName } from '../../../utf8_support'; import { DataProvider } from './data_provider'; +import { TriggerType } from './monaco-completion-provider'; import type { Label, Situation } from './situation'; import { NeverCaseError } from './util'; // FIXME: we should not load this from the "outside", but we cannot do that while we have the "old" query-field too @@ -63,8 +65,12 @@ export function filterMetricNames({ metricNames, inputText, limit }: MetricFilte } // we order items like: history, functions, metrics -function getAllMetricNamesCompletions(dataProvider: DataProvider): Completion[] { - let metricNames = dataProvider.getAllMetricNames(); +async function getAllMetricNamesCompletions( + searchTerm: string | undefined, + dataProvider: DataProvider, + timeRange: TimeRange +): Promise { + let metricNames = await dataProvider.queryMetricNames(timeRange, searchTerm); if ( config.featureToggles.prometheusCodeModeMetricNamesSearch && @@ -110,9 +116,16 @@ const getFunctionCompletions: () => Completion[] = () => { })); }; -async function getAllFunctionsAndMetricNamesCompletions(dataProvider: DataProvider): Promise { - const metricNames = getAllMetricNamesCompletions(dataProvider); +async function getFunctionsOnlyCompletions(): Promise { + return Promise.resolve(getFunctionCompletions()); +} +async function getAllFunctionsAndMetricNamesCompletions( + searchTerm: string | undefined, + dataProvider: DataProvider, + timeRange: TimeRange +): Promise { + const metricNames = await getAllMetricNamesCompletions(searchTerm, dataProvider, timeRange); return [...getFunctionCompletions(), ...metricNames]; } @@ -144,7 +157,11 @@ function getAllHistoryCompletions(dataProvider: DataProvider): Completion[] { })); } -function makeSelector(metricName: string | undefined, labels: Label[]): string { +function makeSelector(metricName: string | undefined, labels: Label[]): string | undefined { + if (metricName === undefined && labels.length === 0) { + return undefined; + } + const allLabels = [...labels]; // we transform the metricName to a label, if it exists @@ -165,19 +182,13 @@ async function getLabelNames( dataProvider: DataProvider, timeRange: TimeRange ): Promise { - if (metric === undefined && otherLabels.length === 0) { - // if there is no filtering, we have to use a special endpoint - return Promise.resolve(dataProvider.getAllLabelNames()); - } else { - const selector = makeSelector(metric, otherLabels); - const labelNames = await dataProvider.getSeriesLabels(timeRange, selector); - - // Exclude __name__ from output - otherLabels.push({ name: '__name__', value: '', op: '!=' }); - const usedLabelNames = new Set(otherLabels.map((l) => l.name)); - // names used in the query - return labelNames.filter((l) => !usedLabelNames.has(l)); - } + const selector = makeSelector(metric, otherLabels); + const labelNames = await dataProvider.queryLabelKeys(timeRange, selector, DEFAULT_COMPLETION_LIMIT); + // Exclude __name__ from output + otherLabels.push({ name: '__name__', value: '', op: '!=' }); + const usedLabelNames = new Set(otherLabels.map((l) => l.name)); + // names used in the query + return labelNames.filter((l) => !usedLabelNames.has(l)); } async function getLabelNamesForCompletions( @@ -232,13 +243,8 @@ async function getLabelValues( dataProvider: DataProvider, timeRange: TimeRange ): Promise { - if (metric === undefined && otherLabels.length === 0) { - // if there is no filtering, we have to use a special endpoint - return dataProvider.getLabelValues(timeRange, labelName); - } else { - const selector = makeSelector(metric, otherLabels); - return await dataProvider.getSeriesValues(timeRange, labelName, selector); - } + const selector = makeSelector(metric, otherLabels); + return await dataProvider.queryLabelValues(timeRange, labelName, selector); } async function getLabelValuesForMetricCompletions( @@ -262,21 +268,30 @@ function formatLabelValueForCompletion(value: string, betweenQuotes: boolean): s return betweenQuotes ? text : `"${text}"`; } -export function getCompletions( +export async function getCompletions( situation: Situation, dataProvider: DataProvider, - timeRange: TimeRange + timeRange: TimeRange, + searchTerm?: string, + triggerType: TriggerType = 'full' ): Promise { switch (situation.type) { case 'IN_DURATION': return Promise.resolve(DURATION_COMPLETIONS); case 'IN_FUNCTION': - return getAllFunctionsAndMetricNamesCompletions(dataProvider); + return triggerType === 'full' + ? getAllFunctionsAndMetricNamesCompletions(searchTerm, dataProvider, timeRange) + : getFunctionsOnlyCompletions(); case 'AT_ROOT': { - return getAllFunctionsAndMetricNamesCompletions(dataProvider); + return triggerType === 'full' + ? getAllFunctionsAndMetricNamesCompletions(searchTerm, dataProvider, timeRange) + : getFunctionsOnlyCompletions(); } case 'EMPTY': { - const metricNames = getAllMetricNamesCompletions(dataProvider); + if (triggerType === 'partial') { + return Promise.resolve(getFunctionCompletions()); + } + const metricNames = await getAllMetricNamesCompletions(searchTerm, dataProvider, timeRange); const historyCompletions = getAllHistoryCompletions(dataProvider); return Promise.resolve([...historyCompletions, ...getFunctionCompletions(), ...metricNames]); } diff --git a/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/data_provider.ts b/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/data_provider.ts index b5772fa45cd..8be8851f75a 100644 --- a/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/data_provider.ts +++ b/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/data_provider.ts @@ -1,9 +1,10 @@ -import { HistoryItem } from '@grafana/data'; -import type { Monaco } from '@grafana/ui'; // used in TSDoc `@link` below +import { HistoryItem, TimeRange } from '@grafana/data'; +import { DEFAULT_COMPLETION_LIMIT, METRIC_LABEL } from '../../../constants'; import { type PrometheusLanguageProviderInterface } from '../../../language_provider'; +import { removeQuotesIfExist } from '../../../language_utils'; import { PromQuery } from '../../../types'; -import { isValidLegacyName } from '../../../utf8_support'; +import { escapeForUtf8Support, isValidLegacyName } from '../../../utf8_support'; export const CODE_MODE_SUGGESTIONS_INCOMPLETE_EVENT = 'codeModeSuggestionsIncomplete'; @@ -38,11 +39,10 @@ export interface DataProviderParams { export class DataProvider { readonly languageProvider: PrometheusLanguageProviderInterface; readonly historyProvider: Array>; - readonly getSeriesLabels: typeof this.languageProvider.queryLabelKeys; - readonly getSeriesValues: typeof this.languageProvider.queryLabelValues; - readonly getAllLabelNames: typeof this.languageProvider.retrieveLabelKeys; - readonly getLabelValues: typeof this.languageProvider.queryLabelValues; - readonly metricNamesSuggestionLimit: number; + + readonly metricNamesSuggestionLimit: number = DEFAULT_COMPLETION_LIMIT; + readonly queryLabelKeys: typeof this.languageProvider.queryLabelKeys; + readonly queryLabelValues: typeof this.languageProvider.queryLabelValues; /** * The text that's been typed so far within the current {@link Monaco.Range | Range}. * @@ -56,14 +56,38 @@ export class DataProvider { this.languageProvider = params.languageProvider; this.historyProvider = params.historyProvider; this.inputInRange = ''; - this.metricNamesSuggestionLimit = this.languageProvider.datasource.metricNamesAutocompleteSuggestionLimit; this.suggestionsIncomplete = false; - this.getSeriesLabels = this.languageProvider.queryLabelKeys.bind(this.languageProvider); - this.getSeriesValues = this.languageProvider.queryLabelValues.bind(this.languageProvider); - this.getAllLabelNames = this.languageProvider.retrieveLabelKeys.bind(this.languageProvider); - this.getLabelValues = this.languageProvider.queryLabelValues.bind(this.languageProvider); + + this.queryLabelKeys = this.languageProvider.queryLabelKeys.bind(this.languageProvider); + this.queryLabelValues = this.languageProvider.queryLabelValues.bind(this.languageProvider); } + /** + * Queries metric names with optional filtering. + * Safely constructs regex patterns and handles errors. + */ + queryMetricNames = async (timeRange: TimeRange, searchTerm: string | undefined): Promise => { + try { + let match: string | undefined; + if (searchTerm) { + const escapedWord = escapeForUtf8Support(removeQuotesIfExist(searchTerm)); + match = `{__name__=~".*${escapedWord}.*"}`; + } + + const result = await this.languageProvider.queryLabelValues( + timeRange, + METRIC_LABEL, + match, + DEFAULT_COMPLETION_LIMIT + ); + + return Array.isArray(result) ? result : []; + } catch (error) { + console.warn('Failed to query metric names:', error); + return []; + } + }; + getHistory(): string[] { return this.historyProvider.map((h) => h.query.expr).filter(Boolean); } diff --git a/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/monaco-completion-provider.ts b/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/monaco-completion-provider.ts index def57a02621..576985fae86 100644 --- a/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/monaco-completion-provider.ts +++ b/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/monaco-completion-provider.ts @@ -7,6 +7,8 @@ import { DataProvider } from './data_provider'; import { getSituation } from './situation'; import { NeverCaseError } from './util'; +export type TriggerType = 'partial' | 'full'; + export function getSuggestOptions(): monacoTypes.editor.ISuggestOptions { return { // monaco-editor sometimes provides suggestions automatically, i am not @@ -47,14 +49,57 @@ function getMonacoCompletionItemKind(type: CompletionType, monaco: Monaco): mona } } +function getTriggerType( + context: monacoTypes.languages.CompletionContext, + word: monacoTypes.editor.IWordAtPosition | null, + model: monacoTypes.editor.ITextModel, + position: monacoTypes.Position, + isManualTrigger: boolean +): TriggerType { + // Manual trigger (Ctrl+Space) + if (isManualTrigger) { + return 'full'; + } + + // Trigger characters + const triggerChars = ['{', ',', '[', '(', '=', '~', ' ', '"']; + const charBeforeCursor = model.getValueInRange({ + startLineNumber: position.lineNumber, + endLineNumber: position.lineNumber, + startColumn: Math.max(1, position.column - 1), + endColumn: position.column, + }); + + if (triggerChars.includes(charBeforeCursor)) { + return 'full'; + } + + // Word length >= 3 + if (word && word.word.length >= 3) { + return 'full'; + } + + return 'partial'; +} + export function getCompletionProvider( monaco: Monaco, dataProvider: DataProvider, timeRange: TimeRange -): monacoTypes.languages.CompletionItemProvider { +): { provider: monacoTypes.languages.CompletionItemProvider; state: { isManualTriggerRequested: boolean } } { + // Short debounce to catch rapid typing + let debounceTimer: ReturnType | null = null; + const DEBOUNCE_DELAY = 150; // Much shorter delay to catch rapid typing + + // Simple local state + const state = { + isManualTriggerRequested: false, + }; + const provideCompletionItems = ( model: monacoTypes.editor.ITextModel, - position: monacoTypes.Position + position: monacoTypes.Position, + context: monacoTypes.languages.CompletionContext ): monacoTypes.languages.ProviderResult => { const word = model.getWordAtPosition(position); const range = @@ -66,13 +111,67 @@ export function getCompletionProvider( endColumn: word.endColumn, }) : monaco.Range.fromPositions(position); + + const isManualTrigger = state.isManualTriggerRequested; + if (isManualTrigger) { + state.isManualTriggerRequested = false; + } + + const triggerType: TriggerType = getTriggerType(context, word, model, position, isManualTrigger); + + // For immediate triggers (manual, trigger chars, or already 3+ chars), execute immediately + const isImmediate = isManualTrigger || triggerType === 'full'; + + if (isImmediate) { + if (debounceTimer) { + clearTimeout(debounceTimer); + debounceTimer = null; + } + return executeCompletionLogic(model, position, range, dataProvider, timeRange, word?.word, triggerType); + } + + // For typing scenarios, use short debounce to catch rapid typing + if (debounceTimer) { + clearTimeout(debounceTimer); + } + + return new Promise((resolve) => { + debounceTimer = setTimeout(() => { + // Re-check if we should use full completions after debounce + const updatedWord = model.getWordAtPosition(position); + const updatedTriggerType: TriggerType = getTriggerType(context, updatedWord, model, position, false) + ? 'full' + : 'partial'; + + executeCompletionLogic( + model, + position, + range, + dataProvider, + timeRange, + updatedWord?.word, + updatedTriggerType + ).then(resolve); + }, DEBOUNCE_DELAY); + }); + }; + + const executeCompletionLogic = async ( + model: monacoTypes.editor.ITextModel, + position: monacoTypes.Position, + range: monacoTypes.Range, + dataProvider: DataProvider, + timeRange: TimeRange, + wordText?: string, + triggerType: TriggerType = 'full' + ): Promise => { // documentation says `position` will be "adjusted" in `getOffsetAt` // i don't know what that means, to be sure i clone it - const positionClone = { column: position.column, lineNumber: position.lineNumber, }; + dataProvider.monacoSettings.setInputInRange(model.getValueInRange(range)); // Check to see if the browser supports window.getSelection() @@ -87,7 +186,9 @@ export function getCompletionProvider( const offset = model.getOffsetAt(positionClone); const situation = getSituation(model.getValue(), offset); const completionsPromise = - situation != null ? getCompletions(situation, dataProvider, timeRange) : Promise.resolve([]); + situation != null + ? getCompletions(situation, dataProvider, timeRange, wordText, triggerType) + : Promise.resolve([]); return completionsPromise.then((items) => { // monaco by-default alphabetically orders the items. @@ -95,27 +196,29 @@ export function getCompletionProvider( // so that monaco keeps the order we use const maxIndexDigits = items.length.toString().length; const suggestions: monacoTypes.languages.CompletionItem[] = items.map((item, index) => ({ - kind: getMonacoCompletionItemKind(item.type, monaco), - label: item.label, - insertText: item.insertText, - insertTextRules: item.insertTextRules, - detail: item.detail, - documentation: item.documentation, - sortText: index.toString().padStart(maxIndexDigits, '0'), // to force the order we have range, - command: item.triggerOnInsert - ? { - id: 'editor.action.triggerSuggest', - title: '', - } - : undefined, + label: item.label, + detail: item.detail, + insertText: item.insertText, + documentation: item.documentation, + insertTextRules: item.insertTextRules, + kind: getMonacoCompletionItemKind(item.type, monaco), + sortText: index.toString().padStart(maxIndexDigits, '0'), // to force the order we have + command: item.triggerOnInsert ? { id: 'editor.action.triggerSuggest', title: '' } : undefined, })); - return { suggestions, incomplete: dataProvider.monacoSettings.suggestionsIncomplete }; + + return { + suggestions, + incomplete: dataProvider.monacoSettings.suggestionsIncomplete, + }; }); }; return { - triggerCharacters: ['{', ',', '[', '(', '=', '~', ' ', '"'], - provideCompletionItems, + provider: { + triggerCharacters: ['{', ',', '[', '(', '=', '~', ' ', '"'], + provideCompletionItems, + }, + state, }; } diff --git a/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/situation.ts b/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/situation.ts index 7b1bbac866a..dfc0f40a556 100644 --- a/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/situation.ts +++ b/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/situation.ts @@ -186,6 +186,11 @@ const RESOLVERS: Resolver[] = [ path: [PromQL], fun: resolveTopLevel, }, + { + // Partially written metric name + path: [Identifier, VectorSelector, PromQL], + fun: resolveTopLevel, + }, { path: [FunctionCallBody], fun: resolveInFunction, diff --git a/packages/grafana-prometheus/src/components/useMetricsState.test.ts b/packages/grafana-prometheus/src/components/useMetricsState.test.ts deleted file mode 100644 index c632935a287..00000000000 --- a/packages/grafana-prometheus/src/components/useMetricsState.test.ts +++ /dev/null @@ -1,113 +0,0 @@ -import { renderHook } from '@testing-library/react'; - -import { PrometheusDatasource } from '../datasource'; -import { PrometheusLanguageProviderInterface } from '../language_provider'; - -import { useMetricsState } from './useMetricsState'; - -// Mock implementations -const createMockLanguageProvider = (metrics: string[] = []): PrometheusLanguageProviderInterface => - ({ - retrieveMetrics: () => metrics, - }) as unknown as PrometheusLanguageProviderInterface; - -const createMockDatasource = (lookupsDisabled = false): PrometheusDatasource => - ({ - lookupsDisabled, - }) as unknown as PrometheusDatasource; - -describe('useMetricsState', () => { - describe('chooserText', () => { - it('should return disabled message when lookups are disabled', () => { - const datasource = createMockDatasource(true); - const languageProvider = createMockLanguageProvider([]); - const { result } = renderHook(() => useMetricsState(datasource, languageProvider, true)); - expect(result.current.chooserText).toBe('(Disabled)'); - }); - - it('should return loading message when syntax is not loaded', () => { - const datasource = createMockDatasource(); - const languageProvider = createMockLanguageProvider(['metric1']); - const { result } = renderHook(() => useMetricsState(datasource, languageProvider, false)); - expect(result.current.chooserText).toBe('Loading metrics...'); - }); - - it('should return no metrics message when no metrics are found', () => { - const datasource = createMockDatasource(); - const languageProvider = createMockLanguageProvider([]); - const { result } = renderHook(() => useMetricsState(datasource, languageProvider, true)); - expect(result.current.chooserText).toBe('(No metrics found)'); - }); - - it('should return metrics browser text when metrics are available', () => { - const datasource = createMockDatasource(); - const languageProvider = createMockLanguageProvider(['metric1']); - const { result } = renderHook(() => useMetricsState(datasource, languageProvider, true)); - expect(result.current.chooserText).toBe('Metrics browser'); - }); - }); - - describe('buttonDisabled', () => { - it('should be disabled when syntax is not loaded', () => { - const datasource = createMockDatasource(); - const languageProvider = createMockLanguageProvider(['metric1']); - const { result } = renderHook(() => useMetricsState(datasource, languageProvider, false)); - expect(result.current.buttonDisabled).toBe(true); - }); - - it('should be disabled when no metrics are available', () => { - const datasource = createMockDatasource(); - const languageProvider = createMockLanguageProvider([]); - const { result } = renderHook(() => useMetricsState(datasource, languageProvider, true)); - expect(result.current.buttonDisabled).toBe(true); - }); - - it('should be enabled when syntax is loaded and metrics are available', () => { - const datasource = createMockDatasource(); - const languageProvider = createMockLanguageProvider(['metric1']); - const { result } = renderHook(() => useMetricsState(datasource, languageProvider, true)); - expect(result.current.buttonDisabled).toBe(false); - }); - }); - - describe('hasMetrics', () => { - it('should be false when no metrics are available', () => { - const datasource = createMockDatasource(); - const languageProvider = createMockLanguageProvider([]); - const { result } = renderHook(() => useMetricsState(datasource, languageProvider, true)); - expect(result.current.hasMetrics).toBe(false); - }); - - it('should be true when metrics are available', () => { - const datasource = createMockDatasource(); - const languageProvider = createMockLanguageProvider(['metric1']); - const { result } = renderHook(() => useMetricsState(datasource, languageProvider, true)); - expect(result.current.hasMetrics).toBe(true); - }); - }); - - describe('memoization', () => { - it('should return same values when dependencies have not changed', () => { - const datasource = createMockDatasource(); - const languageProvider = createMockLanguageProvider(['metric1']); - const { result, rerender } = renderHook(() => useMetricsState(datasource, languageProvider, true)); - const firstResult = result.current; - - rerender(); - expect(result.current).toBe(firstResult); - }); - - it('should update when datasource lookupsDisabled changes', () => { - const initialDatasource = createMockDatasource(false); - const languageProvider = createMockLanguageProvider(['metric1']); - const { result, rerender } = renderHook(({ ds }) => useMetricsState(ds, languageProvider, true), { - initialProps: { ds: initialDatasource }, - }); - const firstResult = result.current; - - const updatedDatasource = createMockDatasource(true); - rerender({ ds: updatedDatasource }); - expect(result.current).not.toBe(firstResult); - }); - }); -}); diff --git a/packages/grafana-prometheus/src/components/useMetricsState.ts b/packages/grafana-prometheus/src/components/useMetricsState.ts deleted file mode 100644 index 3ae3fb9aa6f..00000000000 --- a/packages/grafana-prometheus/src/components/useMetricsState.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { useMemo } from 'react'; - -import { PrometheusDatasource } from '../datasource'; -import { PrometheusLanguageProviderInterface } from '../language_provider'; - -function getChooserText(metricsLookupDisabled: boolean, hasSyntax: boolean, hasMetrics: boolean) { - if (metricsLookupDisabled) { - return '(Disabled)'; - } - - if (!hasSyntax) { - return 'Loading metrics...'; - } - - if (!hasMetrics) { - return '(No metrics found)'; - } - - return 'Metrics browser'; -} - -export function useMetricsState( - datasource: PrometheusDatasource, - languageProvider: PrometheusLanguageProviderInterface, - syntaxLoaded: boolean -) { - return useMemo(() => { - const hasMetrics = languageProvider.retrieveMetrics().length > 0; - const chooserText = getChooserText(datasource.lookupsDisabled, syntaxLoaded, hasMetrics); - const buttonDisabled = !(syntaxLoaded && hasMetrics); - - return { - hasMetrics, - chooserText, - buttonDisabled, - }; - }, [languageProvider, datasource.lookupsDisabled, syntaxLoaded]); -} diff --git a/packages/grafana-prometheus/src/components/usePromQueryFieldEffects.test.ts b/packages/grafana-prometheus/src/components/usePromQueryFieldEffects.test.ts deleted file mode 100644 index d3e5017bba1..00000000000 --- a/packages/grafana-prometheus/src/components/usePromQueryFieldEffects.test.ts +++ /dev/null @@ -1,204 +0,0 @@ -import { renderHook } from '@testing-library/react'; - -import { DataFrame, dateTime, TimeRange } from '@grafana/data'; - -import { PrometheusLanguageProviderInterface } from '../language_provider'; - -import { usePromQueryFieldEffects } from './usePromQueryFieldEffects'; - -type TestProps = { - languageProvider: PrometheusLanguageProviderInterface; - range: TimeRange | undefined; - series: DataFrame[]; -}; - -describe('usePromQueryFieldEffects', () => { - const mockLanguageProvider = { - start: jest.fn().mockResolvedValue([]), - timeRange: {}, - metrics: ['metric1'], - startTask: Promise.resolve(), - datasource: {}, - lookupsDisabled: false, - syntax: jest.fn(), - hasLookupsDisabled: jest.fn(), - getBeginningCompletionItems: jest.fn(), - getLabelCompletionItems: jest.fn(), - getMetricCompletionItems: jest.fn(), - getTermCompletionItems: jest.fn(), - request: jest.fn(), - importQueries: jest.fn(), - labelFetchTs: 0, - getDefaultCacheHeaders: jest.fn(), - modifyQuery: jest.fn(), - } as unknown as PrometheusLanguageProviderInterface; - - const mockRange: TimeRange = { - from: dateTime('2022-01-01T00:00:00Z'), - to: dateTime('2022-01-02T00:00:00Z'), - raw: { - from: 'now-1d', - to: 'now', - }, - }; - - const mockNewRange: TimeRange = { - from: dateTime('2022-01-02T00:00:00Z'), - to: dateTime('2022-01-03T00:00:00Z'), - raw: { - from: 'now-1d', - to: 'now', - }, - }; - - let refreshMetricsMock: jest.Mock; - let refreshHintMock: jest.Mock; - - beforeEach(() => { - jest.clearAllMocks(); - refreshMetricsMock = jest.fn().mockImplementation(() => Promise.resolve()); - refreshHintMock = jest.fn(); - }); - - it('should call refreshMetrics and refreshHint on initial render', async () => { - renderHook(() => - usePromQueryFieldEffects(mockLanguageProvider, mockRange, [], refreshMetricsMock, refreshHintMock) - ); - - expect(refreshMetricsMock).toHaveBeenCalledTimes(1); - expect(refreshHintMock).toHaveBeenCalledTimes(2); - }); - - it('should call refreshMetrics when the time range changes', async () => { - const { rerender } = renderHook( - (props: TestProps) => - usePromQueryFieldEffects( - props.languageProvider, - props.range, - props.series, - refreshMetricsMock, - refreshHintMock - ), - { - initialProps: { - languageProvider: mockLanguageProvider, - range: mockRange, - series: [] as DataFrame[], - }, - } - ); - - // Initial render already called refreshMetrics once - expect(refreshMetricsMock).toHaveBeenCalledTimes(1); - - // Change the range - rerender({ - languageProvider: mockLanguageProvider, - range: mockNewRange, - series: [] as DataFrame[], - }); - - expect(refreshMetricsMock).toHaveBeenCalledTimes(2); - }); - - it('should not call refreshMetrics when the time range is the same', () => { - const { rerender } = renderHook( - (props: TestProps) => - usePromQueryFieldEffects( - props.languageProvider, - props.range, - props.series, - refreshMetricsMock, - refreshHintMock - ), - { - initialProps: { - languageProvider: mockLanguageProvider, - range: mockRange, - series: [] as DataFrame[], - }, - } - ); - - // Initial render already called refreshMetrics once - expect(refreshMetricsMock).toHaveBeenCalledTimes(1); - - // Rerender with the same range - rerender({ - languageProvider: mockLanguageProvider, - range: { ...mockRange }, // create a new object with the same values - series: [] as DataFrame[], - }); - - // Should still be called only once (from initial render) - expect(refreshMetricsMock).toHaveBeenCalledTimes(1); - }); - - it('should call refreshHint when series changes', () => { - const mockSeries = [{ name: 'new series', fields: [], length: 0 }] as DataFrame[]; - const { rerender } = renderHook( - (props: TestProps) => - usePromQueryFieldEffects( - props.languageProvider, - props.range, - props.series, - refreshMetricsMock, - refreshHintMock - ), - { - initialProps: { - languageProvider: mockLanguageProvider, - range: mockRange, - series: [] as DataFrame[], - }, - } - ); - - // Initial render already called refreshHint once - expect(refreshHintMock).toHaveBeenCalledTimes(2); - - refreshHintMock.mockClear(); - - // Change the series - rerender({ - languageProvider: mockLanguageProvider, - range: mockRange, - series: mockSeries, - }); - - expect(refreshHintMock).toHaveBeenCalledTimes(1); - }); - - it('should not call refreshHint when series is the same', () => { - const series = [] as DataFrame[]; - const { rerender } = renderHook( - (props: TestProps) => - usePromQueryFieldEffects( - props.languageProvider, - props.range, - props.series, - refreshMetricsMock, - refreshHintMock - ), - { - initialProps: { - languageProvider: mockLanguageProvider, - range: mockRange, - series, - }, - } - ); - - // Initial render already called refreshHint once - refreshHintMock.mockClear(); - - // Rerender with the same series - rerender({ - languageProvider: mockLanguageProvider, - range: mockRange, - series, // same empty array - }); - - expect(refreshHintMock).not.toHaveBeenCalled(); - }); -}); diff --git a/packages/grafana-prometheus/src/components/usePromQueryFieldEffects.ts b/packages/grafana-prometheus/src/components/usePromQueryFieldEffects.ts deleted file mode 100644 index b2371e57236..00000000000 --- a/packages/grafana-prometheus/src/components/usePromQueryFieldEffects.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { MutableRefObject, useEffect, useRef } from 'react'; - -import { DataFrame, DateTime, TimeRange } from '@grafana/data'; - -import { PrometheusLanguageProviderInterface } from '../language_provider'; -import { roundMsToMin } from '../language_utils'; - -import { CancelablePromise } from './cancelable-promise'; - -export function usePromQueryFieldEffects( - languageProvider: PrometheusLanguageProviderInterface, - range: TimeRange | undefined, - series: DataFrame[] | undefined, - refreshMetrics: (languageProviderInitRef: MutableRefObject | null>) => Promise, - refreshHint: () => void -) { - const lastRangeRef = useRef<{ from: DateTime; to: DateTime } | null>(null); - const languageProviderInitRef = useRef | null>(null); - - // Effect for initial load - useEffect(() => { - if (languageProvider) { - refreshMetrics(languageProviderInitRef); - } - refreshHint(); - - return () => { - if (languageProviderInitRef.current) { - languageProviderInitRef.current.cancel(); - languageProviderInitRef.current = null; - } - }; - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - - // Effect for time range changes - useEffect(() => { - if (!range) { - return; - } - - const currentFrom = roundMsToMin(range.from.valueOf()); - const currentTo = roundMsToMin(range.to.valueOf()); - - if (!lastRangeRef.current) { - lastRangeRef.current = { from: range.from, to: range.to }; - } - - const lastFrom = roundMsToMin(lastRangeRef.current.from.valueOf()); - const lastTo = roundMsToMin(lastRangeRef.current.to.valueOf()); - - if (currentFrom !== lastFrom || currentTo !== lastTo) { - lastRangeRef.current = { from: range.from, to: range.to }; - refreshMetrics(languageProviderInitRef); - } - }, [range, refreshMetrics]); - - // Effect for data changes (refreshing hints) - useEffect(() => { - refreshHint(); - }, [series, refreshHint]); - - return languageProviderInitRef; -} diff --git a/packages/grafana-prometheus/src/constants.ts b/packages/grafana-prometheus/src/constants.ts index 2c8dffa179d..fccc7ddfa0d 100644 --- a/packages/grafana-prometheus/src/constants.ts +++ b/packages/grafana-prometheus/src/constants.ts @@ -1,4 +1,7 @@ // Max number of items (metrics, labels, values) that we display as suggestions. Prevents from running out of memory. +/** + * @deprecated + */ export const SUGGESTIONS_LIMIT = 10000; export const PROMETHEUS_QUERY_BUILDER_MAX_RESULTS = 1000; @@ -19,6 +22,8 @@ export const EMPTY_SELECTOR = '{}'; export const DEFAULT_SERIES_LIMIT = 40000; +export const DEFAULT_COMPLETION_LIMIT = 1000; + /** * Only for /series endpoint. Don't use this anywhere else as it cause an expensive query */ diff --git a/packages/grafana-prometheus/src/locales/en-US/grafana-prometheus.json b/packages/grafana-prometheus/src/locales/en-US/grafana-prometheus.json index 85eba24f8a4..b94bb4cded3 100644 --- a/packages/grafana-prometheus/src/locales/en-US/grafana-prometheus.json +++ b/packages/grafana-prometheus/src/locales/en-US/grafana-prometheus.json @@ -199,6 +199,10 @@ "tooltip-use-series-endpoint": "Checking this option will favor the series endpoint with {{exampleParameter}} parameter over the label values endpoint with {{exampleParameter}} parameter. While the label values endpoint is considered more performant, some users may prefer the series because it has a POST method while the label values endpoint only has a GET method." } }, + "metrics-browser": { + "disabled-label": "(Disabled)", + "enabled-label": "Metrics browser" + }, "prom-query-legend-editor": { "get-legend-mode-options": { "description-auto": "Only includes unique labels", From 1c1549363563ec38b9083dcf5303489e4a47795e Mon Sep 17 00:00:00 2001 From: Timur Olzhabayev Date: Mon, 28 Jul 2025 13:23:59 +0200 Subject: [PATCH 040/131] Chore: Add PR author (#108513) * add PR author * show who's PR it is --- .github/workflows/detect-plugin-extension-changes.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/detect-plugin-extension-changes.yml b/.github/workflows/detect-plugin-extension-changes.yml index b5ab96725d9..d7d1204aa40 100644 --- a/.github/workflows/detect-plugin-extension-changes.yml +++ b/.github/workflows/detect-plugin-extension-changes.yml @@ -135,7 +135,7 @@ jobs: "type": "section", "text": { "type": "mrkdwn", - "text": "*PR:* <${{ github.event.pull_request.html_url }}|#${{ github.event.pull_request.number }}>\n*Job:* <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|View Job>" + "text": "*PR:* <${{ github.event.pull_request.html_url }}|#${{ github.event.pull_request.number }}>\n*Job:* <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|View Job>\n*Author:* ${{ github.event.pull_request.user.login }}" } }, { From 1a7a7f1d9992e44023ce0a105b68ebd363b3727d Mon Sep 17 00:00:00 2001 From: Gabriel MABILLE Date: Mon, 28 Jul 2025 13:36:27 +0200 Subject: [PATCH 041/131] `grafana-iam`: Wire the roles api (#108577) --- apps/iam/pkg/apis/iam/v0alpha1/register.go | 34 +++++++++++++++++++++- pkg/registry/apis/iam/authorizer.go | 1 + pkg/registry/apis/iam/models.go | 7 ++++- pkg/registry/apis/iam/register.go | 12 ++++++-- pkg/registry/apis/wireset.go | 1 + pkg/server/wire_gen.go | 4 +-- pkg/services/authz/rbac/mapper.go | 1 + 7 files changed, 54 insertions(+), 6 deletions(-) diff --git a/apps/iam/pkg/apis/iam/v0alpha1/register.go b/apps/iam/pkg/apis/iam/v0alpha1/register.go index c2a3fb14b1a..3e0d4561290 100644 --- a/apps/iam/pkg/apis/iam/v0alpha1/register.go +++ b/apps/iam/pkg/apis/iam/v0alpha1/register.go @@ -23,7 +23,8 @@ var CoreRoleInfo = utils.NewResourceInfo(GROUP, VERSION, utils.TableColumns{ Definition: []metav1.TableColumnDefinition{ {Name: "Name", Type: "string", Format: "name"}, - {Name: "Title", Type: "string", Format: "string", Description: "Core role name"}, // Not sure this is actually needed + {Name: "Group", Type: "string", Format: "group", Description: "Core role group"}, + {Name: "Title", Type: "string", Format: "string", Description: "Core role name"}, {Name: "Created At", Type: "date"}, }, Reader: func(obj any) ([]interface{}, error) { @@ -32,6 +33,7 @@ var CoreRoleInfo = utils.NewResourceInfo(GROUP, VERSION, if core != nil { return []interface{}{ core.Name, + core.Spec.Group, core.Spec.Title, core.CreationTimestamp.UTC().Format(time.RFC3339), }, nil @@ -42,6 +44,34 @@ var CoreRoleInfo = utils.NewResourceInfo(GROUP, VERSION, }, ) +var RoleInfo = utils.NewResourceInfo(GROUP, VERSION, + "roles", "role", "Role", + func() runtime.Object { return &Role{} }, + func() runtime.Object { return &RoleList{} }, + utils.TableColumns{ + Definition: []metav1.TableColumnDefinition{ + {Name: "Name", Type: "string", Format: "name"}, + {Name: "Group", Type: "string", Format: "group", Description: "Role group"}, + {Name: "Title", Type: "string", Format: "string", Description: "Role name"}, + {Name: "Created At", Type: "date"}, + }, + Reader: func(obj any) ([]interface{}, error) { + role, ok := obj.(*Role) + if ok { + if role != nil { + return []interface{}{ + role.Name, + role.Spec.Group, + role.Spec.Title, + role.CreationTimestamp.UTC().Format(time.RFC3339), + }, nil + } + } + return nil, fmt.Errorf("expected role") + }, + }, +) + var ( SchemeBuilder runtime.SchemeBuilder localSchemeBuilder = &SchemeBuilder @@ -58,6 +88,8 @@ func addKnownTypes(scheme *runtime.Scheme) error { scheme.AddKnownTypes(schemeGroupVersion, &CoreRole{}, &CoreRoleList{}, + &Role{}, + &RoleList{}, // What is this about? &metav1.PartialObjectMetadata{}, diff --git a/pkg/registry/apis/iam/authorizer.go b/pkg/registry/apis/iam/authorizer.go index e7938a0b754..42402ed769f 100644 --- a/pkg/registry/apis/iam/authorizer.go +++ b/pkg/registry/apis/iam/authorizer.go @@ -32,6 +32,7 @@ func newIAMAuthorizer(accessClient authlib.AccessClient, legacyAccessClient auth // Access specific resources authorizer := gfauthorizer.NewResourceAuthorizer(accessClient) resourceAuthorizer[iamv0.CoreRoleInfo.GetName()] = authorizer + resourceAuthorizer[iamv0.RoleInfo.GetName()] = authorizer return &iamAuthorizer{resourceAuthorizer: resourceAuthorizer} } diff --git a/pkg/registry/apis/iam/models.go b/pkg/registry/apis/iam/models.go index d4c96edf03a..ac3c21643af 100644 --- a/pkg/registry/apis/iam/models.go +++ b/pkg/registry/apis/iam/models.go @@ -17,14 +17,19 @@ var _ builder.APIGroupValidation = (*IdentityAccessManagementAPIBuilder)(nil) var _ builder.APIGroupMutation = (*IdentityAccessManagementAPIBuilder)(nil) // CoreRoleStorageBackend uses the resource.StorageBackend interface to provide storage for core roles. -// Used wire to identify the storage backend for core roles. +// Used by wire to identify the storage backend for core roles. type CoreRoleStorageBackend interface{ resource.StorageBackend } +// RoleStorageBackend uses the resource.StorageBackend interface to provide storage for custom roles. +// Used by wire to identify the storage backend for custom roles. +type RoleStorageBackend interface{ resource.StorageBackend } + // This is used just so wire has something unique to return type IdentityAccessManagementAPIBuilder struct { // Stores store legacy.LegacyIdentityStore coreRolesStorage CoreRoleStorageBackend + rolesStorage RoleStorageBackend // Access Control authorizer authorizer.Authorizer diff --git a/pkg/registry/apis/iam/register.go b/pkg/registry/apis/iam/register.go index 22d15d2e518..f1de0924641 100644 --- a/pkg/registry/apis/iam/register.go +++ b/pkg/registry/apis/iam/register.go @@ -50,6 +50,7 @@ func RegisterAPIService( accessClient types.AccessClient, reg prometheus.Registerer, coreRolesStorage CoreRoleStorageBackend, + rolesStorage RoleStorageBackend, ) (*IdentityAccessManagementAPIBuilder, error) { store := legacy.NewLegacySQLStores(legacysql.NewDatabaseProvider(sql)) legacyAccessClient := newLegacyAccessClient(ac, store) @@ -58,6 +59,7 @@ func RegisterAPIService( builder := &IdentityAccessManagementAPIBuilder{ store: store, coreRolesStorage: coreRolesStorage, + rolesStorage: rolesStorage, sso: ssoService, authorizer: authorizer, legacyAccessClient: legacyAccessClient, @@ -157,11 +159,17 @@ func (b *IdentityAccessManagementAPIBuilder) UpdateAPIGroupInfo(apiGroupInfo *ge if b.enableAuthZApis { // v0alpha1 - store, err := NewLocalStore(iamv0.CoreRoleInfo, apiGroupInfo.Scheme, opts.OptsGetter, b.reg, b.accessClient, b.coreRolesStorage) + coreRoleStore, err := NewLocalStore(iamv0.CoreRoleInfo, apiGroupInfo.Scheme, opts.OptsGetter, b.reg, b.accessClient, b.coreRolesStorage) if err != nil { return err } - storage[iamv0.CoreRoleInfo.StoragePath()] = store + storage[iamv0.CoreRoleInfo.StoragePath()] = coreRoleStore + + roleStore, err := NewLocalStore(iamv0.RoleInfo, apiGroupInfo.Scheme, opts.OptsGetter, b.reg, b.accessClient, b.rolesStorage) + if err != nil { + return err + } + storage[iamv0.RoleInfo.StoragePath()] = roleStore } apiGroupInfo.VersionedResourcesStorageMap[legacyiamv0.VERSION] = storage diff --git a/pkg/registry/apis/wireset.go b/pkg/registry/apis/wireset.go index ebea70d289b..006d81b421c 100644 --- a/pkg/registry/apis/wireset.go +++ b/pkg/registry/apis/wireset.go @@ -24,6 +24,7 @@ import ( var WireSetExts = wire.NewSet( noopstorage.ProvideStorageBackend, wire.Bind(new(iam.CoreRoleStorageBackend), new(*noopstorage.StorageBackendImpl)), + wire.Bind(new(iam.RoleStorageBackend), new(*noopstorage.StorageBackendImpl)), ) var WireSet = wire.NewSet( diff --git a/pkg/server/wire_gen.go b/pkg/server/wire_gen.go index 440ede3c8b9..481ad2b1845 100644 --- a/pkg/server/wire_gen.go +++ b/pkg/server/wire_gen.go @@ -735,7 +735,7 @@ func Initialize(cfg *setting.Cfg, opts Options, apiOpts api.ServerOptions) (*Ser } folderAPIBuilder := folders.RegisterAPIService(cfg, featureToggles, apiserverService, folderimplService, folderPermissionsService, accessControl, acimplService, registerer, resourceClient) storageBackendImpl := noopstorage.ProvideStorageBackend() - identityAccessManagementAPIBuilder, err := iam.RegisterAPIService(featureToggles, apiserverService, ssosettingsimplService, sqlStore, accessControl, accessClient, registerer, storageBackendImpl) + identityAccessManagementAPIBuilder, err := iam.RegisterAPIService(featureToggles, apiserverService, ssosettingsimplService, sqlStore, accessControl, accessClient, registerer, storageBackendImpl, storageBackendImpl) if err != nil { return nil, err } @@ -1293,7 +1293,7 @@ func InitializeForTest(t sqlutil.ITestDB, testingT interface { } folderAPIBuilder := folders.RegisterAPIService(cfg, featureToggles, apiserverService, folderimplService, folderPermissionsService, accessControl, acimplService, registerer, resourceClient) storageBackendImpl := noopstorage.ProvideStorageBackend() - identityAccessManagementAPIBuilder, err := iam.RegisterAPIService(featureToggles, apiserverService, ssosettingsimplService, sqlStore, accessControl, accessClient, registerer, storageBackendImpl) + identityAccessManagementAPIBuilder, err := iam.RegisterAPIService(featureToggles, apiserverService, ssosettingsimplService, sqlStore, accessControl, accessClient, registerer, storageBackendImpl, storageBackendImpl) if err != nil { return nil, err } diff --git a/pkg/services/authz/rbac/mapper.go b/pkg/services/authz/rbac/mapper.go index 789d3dd31a5..ded19301c83 100644 --- a/pkg/services/authz/rbac/mapper.go +++ b/pkg/services/authz/rbac/mapper.go @@ -105,6 +105,7 @@ func NewMapperRegistry() MapperRegistry { // Teams is a special case. We translate user permissions from id to uid based. "teams": newResourceTranslation("teams", "uid", false), "coreroles": newResourceTranslation("roles", "uid", false), + "roles": newResourceTranslation("roles", "uid", false), }, "secret.grafana.app": { "securevalues": newResourceTranslation("secret.securevalues", "uid", false), From a95fb3a37ca9e0f0917c48fae83b85991e031aa6 Mon Sep 17 00:00:00 2001 From: Serge Zaitsev Date: Mon, 28 Jul 2025 13:38:54 +0200 Subject: [PATCH 042/131] Chore: Omit integration tests if short test flag is passed (#108777) * omit integration tests if short test flag is passed * Update pkg/services/ngalert/models/receivers_test.go Co-authored-by: Matheus Macabu * Update pkg/tests/api/alerting/api_ruler_test.go Co-authored-by: Matheus Macabu * Update pkg/tests/api/alerting/api_ruler_test.go Co-authored-by: Matheus Macabu * Update pkg/tests/api/alerting/api_ruler_test.go Co-authored-by: Matheus Macabu * Update pkg/tests/api/alerting/api_ruler_test.go Co-authored-by: Matheus Macabu * Update pkg/tests/api/alerting/api_ruler_test.go Co-authored-by: Matheus Macabu * Update pkg/services/ngalert/models/receivers_test.go Co-authored-by: Matheus Macabu * Update pkg/cmd/grafana-cli/commands/datamigrations/to_unified_storage_test.go Co-authored-by: Matheus Macabu * Update pkg/services/ngalert/models/receivers_test.go Co-authored-by: Matheus Macabu * fix the rest * false positive --------- Co-authored-by: Matheus Macabu --- pkg/api/dashboard_test.go | 3 + pkg/api/frontendsettings_test.go | 12 +++ pkg/api/org_users_test.go | 3 + pkg/api/plugin_resource_test.go | 3 + pkg/api/pluginproxy/ds_proxy_test.go | 3 + pkg/api/user_test.go | 12 +++ .../encrypt_datasource_passwords_test.go | 4 + .../datamigrations/to_unified_storage_test.go | 4 + pkg/infra/kvstore/kvstore_test.go | 3 + .../remotecache/database_storage_test.go | 6 ++ pkg/infra/remotecache/remotecache_test.go | 3 + pkg/infra/serverlock/serverlock_test.go | 6 ++ .../usagestats/service/usage_stats_test.go | 3 + .../statscollector/concurrent_users_test.go | 6 ++ pkg/login/social/socialimpl/service_test.go | 6 ++ pkg/plugins/manager/client/client_test.go | 3 + .../apis/secret/secure_value_client_test.go | 3 + .../accesscontrol/acimpl/service_test.go | 27 +++++ .../accesscontrol/database/database_test.go | 18 ++++ .../database/externalservices_test.go | 6 ++ pkg/services/accesscontrol/filter_test.go | 3 + .../accesscontrol/migrator/migrator_test.go | 3 + .../resourcepermissions/api_test.go | 18 ++++ .../resourcepermissions/service_test.go | 15 +++ .../anonimpl/anonstore/database_test.go | 9 ++ pkg/services/auth/authimpl/auth_token_test.go | 15 +++ pkg/services/auth/jwt/auth_test.go | 21 ++++ .../service/dashboard_service_test.go | 3 + .../service/service_test.go | 6 ++ .../datasources/service/datasource_test.go | 24 +++++ .../folderimpl/dashboard_folder_store_test.go | 3 + pkg/services/folder/folderimpl/folder_test.go | 18 ++++ .../folderimpl/folder_unifiedstorage_test.go | 3 + .../libraryelements_create_test.go | 3 + .../libraryelements_delete_test.go | 3 + .../libraryelements_get_all_test.go | 3 + .../libraryelements_get_test.go | 3 + .../libraryelements_patch_test.go | 3 + .../libraryelements/libraryelements_test.go | 6 ++ .../librarypanels/librarypanels_test.go | 6 ++ pkg/services/live/live_test.go | 3 + .../loginattemptimpl/login_attempt_test.go | 6 ++ .../ngalert/api/api_provisioning_test.go | 6 ++ pkg/services/ngalert/models/receivers_test.go | 19 ++++ .../ngalert/notifier/alertmanager_test.go | 3 + .../ngalert/notifier/receiver_svc_test.go | 9 ++ .../ngalert/notifier/templates_test.go | 3 + .../ngalert/provisioning/alert_rules_test.go | 9 ++ .../provisioning/contactpoints_test.go | 6 ++ .../ngalert/remote/alertmanager_test.go | 7 +- pkg/services/ngalert/sender/notifier_test.go | 3 + pkg/services/ngalert/state/manager_test.go | 18 +++- .../ngalert/store/instance_database_test.go | 3 + pkg/services/ngalert/store/org_test.go | 3 + .../ngalert/store/range_to_instant_test.go | 12 +++ .../dashboards/file_reader_test.go | 3 + .../provisioning/dashboards/validator_test.go | 3 + .../database/database_test.go | 3 + .../publicdashboards/service/query_test.go | 12 +++ .../publicdashboards/service/service_test.go | 21 ++++ pkg/services/query/query_test.go | 9 ++ .../kvstore/migrations/datasource_mig_test.go | 3 + pkg/services/secrets/kvstore/sql_test.go | 3 + pkg/services/secrets/manager/manager_test.go | 18 ++++ .../serviceaccounts/database/store_test.go | 3 + .../database/token_store_test.go | 12 +++ .../serviceaccounts/manager/service_test.go | 3 + .../shorturls/shorturlimpl/shorturl_test.go | 3 + .../sqlstore/permissions/dashboard_test.go | 9 ++ .../sqlstore/searchstore/filters_test.go | 3 + .../sqlstore/searchstore/search_test.go | 9 ++ pkg/services/sqlstore/session_test.go | 6 ++ pkg/services/sqlstore/sqlstore_test.go | 3 + pkg/services/star/starimpl/store_test.go | 3 + pkg/services/store/service_test.go | 42 ++++++++ pkg/services/user/userimpl/store_test.go | 3 + pkg/storage/unified/apistore/watcher_test.go | 3 + .../federated/federatedtests/stats_test.go | 3 + pkg/storage/unified/sql/list_iterator_test.go | 3 + .../unified/sql/test/benchmark_test.go | 6 ++ .../unified/sql/test/integration_test.go | 9 ++ .../encryption/reencrypt_enterprise_test.go | 3 + .../api/admin/encryption/reencrypt_test.go | 3 + .../alerting/api_admin_configuration_test.go | 3 + .../alerting/api_alertmanager_silence_test.go | 3 + .../api/alerting/api_alertmanager_test.go | 12 ++- .../alerting/api_available_channel_test.go | 3 + ...pi_convert_prometheus_alertmanager_test.go | 9 +- ...t_prometheus_notification_settings_test.go | 6 +- .../alerting/api_convert_prometheus_test.go | 27 +++++ .../alerting/api_notification_channel_test.go | 9 ++ pkg/tests/api/alerting/api_prometheus_test.go | 9 ++ .../api/alerting/api_provisioning_test.go | 15 +++ .../alerting/api_remote_alertmanager_test.go | 6 ++ .../api/alerting/api_ruler_pause_test.go | 6 +- pkg/tests/api/alerting/api_ruler_test.go | 102 +++++++++++++++--- pkg/tests/api/stats/admin_test.go | 3 + pkg/tests/apis/dashboard/dashboards_test.go | 3 + .../library_panels_api_validation_test.go | 6 ++ pkg/tests/apis/provisioning/secrets_test.go | 3 + .../postgres_snapshot_test.go | 4 + pkg/tsdb/influxdb/fsql/fsql_test.go | 3 + pkg/tsdb/mysql/mysql_snapshot_test.go | 4 + 103 files changed, 830 insertions(+), 22 deletions(-) diff --git a/pkg/api/dashboard_test.go b/pkg/api/dashboard_test.go index 8d535c2f127..e3159225c30 100644 --- a/pkg/api/dashboard_test.go +++ b/pkg/api/dashboard_test.go @@ -419,6 +419,9 @@ func TestHTTPServer_GetDashboardVersions_AccessControl(t *testing.T) { } func TestIntegrationDashboardAPIEndpoint(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } t.Run("Given two dashboards with the same title in different folders", func(t *testing.T) { dashOne := dashboards.NewDashboard("dash") dashOne.ID = 2 diff --git a/pkg/api/frontendsettings_test.go b/pkg/api/frontendsettings_test.go index b84a1ae679a..b53e61ed07b 100644 --- a/pkg/api/frontendsettings_test.go +++ b/pkg/api/frontendsettings_test.go @@ -114,6 +114,9 @@ func setupTestEnvironment(t *testing.T, cfg *setting.Cfg, features featuremgmt.F } func TestIntegrationHTTPServer_GetFrontendSettings_hideVersionAnonymous(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } type buildInfo struct { Version string `json:"version"` Commit string `json:"commit"` @@ -183,6 +186,9 @@ func TestIntegrationHTTPServer_GetFrontendSettings_hideVersionAnonymous(t *testi } func TestIntegrationHTTPServer_GetFrontendSettings_pluginsCDNBaseURL(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } type settings struct { PluginsCDNBaseURL string `json:"pluginsCDNBaseURL"` } @@ -233,6 +239,9 @@ func TestIntegrationHTTPServer_GetFrontendSettings_pluginsCDNBaseURL(t *testing. } func TestIntegrationHTTPServer_GetFrontendSettings_apps(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } type settings struct { Apps map[string]*plugins.AppDTO `json:"apps"` } @@ -463,6 +472,9 @@ func newAppSettings(id string, enabled bool) map[string]*pluginsettings.DTO { } func TestIntegrationHTTPServer_GetFrontendSettings_translations(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } type settings struct { Datasources map[string]plugins.DataSourceDTO `json:"datasources"` Panels map[string]*plugins.PanelDTO `json:"panels"` diff --git a/pkg/api/org_users_test.go b/pkg/api/org_users_test.go index bc7afa52e10..585c746f647 100644 --- a/pkg/api/org_users_test.go +++ b/pkg/api/org_users_test.go @@ -65,6 +65,9 @@ func setUpGetOrgUsersDB(t *testing.T, sqlStore db.DB, cfg *setting.Cfg) { } func TestIntegrationOrgUsersAPIEndpoint_userLoggedIn(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } hs := setupSimpleHTTPServer(featuremgmt.WithFeatures()) settings := hs.Cfg diff --git a/pkg/api/plugin_resource_test.go b/pkg/api/plugin_resource_test.go index e3bfda93121..f89d14f5a9b 100644 --- a/pkg/api/plugin_resource_test.go +++ b/pkg/api/plugin_resource_test.go @@ -42,6 +42,9 @@ import ( ) func TestIntegrationCallResource(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } staticRootPath, err := filepath.Abs("../../public/") require.NoError(t, err) diff --git a/pkg/api/pluginproxy/ds_proxy_test.go b/pkg/api/pluginproxy/ds_proxy_test.go index cff5c630000..18b01040d70 100644 --- a/pkg/api/pluginproxy/ds_proxy_test.go +++ b/pkg/api/pluginproxy/ds_proxy_test.go @@ -61,6 +61,9 @@ func TestMain(m *testing.M) { } func TestIntegrationDataSourceProxy_routeRule(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } cfg := &setting.Cfg{} t.Run("Plugin with routes", func(t *testing.T) { diff --git a/pkg/api/user_test.go b/pkg/api/user_test.go index 3ad1e389c1f..c16d1253dd9 100644 --- a/pkg/api/user_test.go +++ b/pkg/api/user_test.go @@ -58,6 +58,9 @@ import ( const newEmail = "newemail@localhost" func TestIntegrationUserAPIEndpoint_userLoggedIn(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } settings := setting.NewCfg() sqlStore := db.InitTestDB(t, sqlstore.InitTestDBOpt{Cfg: settings}) hs := &HTTPServer{ @@ -405,6 +408,9 @@ func Test_GetUserByID(t *testing.T) { } func TestIntegrationHTTPServer_UpdateUser(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } settings := setting.NewCfg() sqlStore := db.InitTestDB(t) @@ -479,6 +485,9 @@ func setupUpdateEmailTests(t *testing.T, cfg *setting.Cfg) (*user.User, *HTTPSer } func TestIntegrationUser_UpdateEmail(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } cases := []struct { Name string Field user.UpdateEmailActionType @@ -1154,6 +1163,9 @@ func updateUserScenario(t *testing.T, ctx updateUserContext, hs *HTTPServer) { } func TestIntegrationHTTPServer_UpdateSignedInUser(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } settings := setting.NewCfg() sqlStore := db.InitTestDB(t) diff --git a/pkg/cmd/grafana-cli/commands/datamigrations/encrypt_datasource_passwords_test.go b/pkg/cmd/grafana-cli/commands/datamigrations/encrypt_datasource_passwords_test.go index 8eb9158629a..2dcc3674b17 100644 --- a/pkg/cmd/grafana-cli/commands/datamigrations/encrypt_datasource_passwords_test.go +++ b/pkg/cmd/grafana-cli/commands/datamigrations/encrypt_datasource_passwords_test.go @@ -21,6 +21,10 @@ func TestMain(m *testing.M) { } func TestIntegrationPasswordMigrationCommand(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } + // setup datasources with password, basic_auth and none store := db.InitTestDB(t) err := store.WithDbSession(context.Background(), func(sess *db.Session) error { diff --git a/pkg/cmd/grafana-cli/commands/datamigrations/to_unified_storage_test.go b/pkg/cmd/grafana-cli/commands/datamigrations/to_unified_storage_test.go index 510908c82e8..5a4fe5eba12 100644 --- a/pkg/cmd/grafana-cli/commands/datamigrations/to_unified_storage_test.go +++ b/pkg/cmd/grafana-cli/commands/datamigrations/to_unified_storage_test.go @@ -12,6 +12,10 @@ import ( func TestIntegrationUnifiedStorageCommand(t *testing.T) { // setup datasources with password, basic_auth and none + if testing.Short() { + t.Skip("skipping integration test in short mode") + } + store := db.InitTestDB(t) err := store.WithDbSession(context.Background(), func(sess *db.Session) error { unistoreMigrationTest(t, sess, store) diff --git a/pkg/infra/kvstore/kvstore_test.go b/pkg/infra/kvstore/kvstore_test.go index 5023edb6b4a..e81524854f4 100644 --- a/pkg/infra/kvstore/kvstore_test.go +++ b/pkg/infra/kvstore/kvstore_test.go @@ -249,6 +249,9 @@ func TestIntegrationKVStore(t *testing.T) { } func TestIntegrationGetItems(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } kv := createTestableKVStore(t) ctx := context.Background() diff --git a/pkg/infra/remotecache/database_storage_test.go b/pkg/infra/remotecache/database_storage_test.go index c0b9cd9ed4a..de294ffd9c5 100644 --- a/pkg/infra/remotecache/database_storage_test.go +++ b/pkg/infra/remotecache/database_storage_test.go @@ -12,6 +12,9 @@ import ( ) func TestIntegrationDatabaseStorageGarbageCollection(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } sqlstore := db.InitTestDB(t) db := &databaseCache{ @@ -59,6 +62,9 @@ func TestIntegrationDatabaseStorageGarbageCollection(t *testing.T) { } func TestIntegrationSecondSet(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } var err error sqlstore := db.InitTestDB(t) diff --git a/pkg/infra/remotecache/remotecache_test.go b/pkg/infra/remotecache/remotecache_test.go index 71cacf3acf2..38b9f9b3f2d 100644 --- a/pkg/infra/remotecache/remotecache_test.go +++ b/pkg/infra/remotecache/remotecache_test.go @@ -34,6 +34,9 @@ func createTestClient(t *testing.T, opts *setting.RemoteCacheSettings, sqlstore } func TestIntegrationCachedBasedOnConfig(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } db, cfg := sqlstore.InitTestDB(t) err := cfg.Load(setting.CommandLineArgs{ HomePath: "../../../", diff --git a/pkg/infra/serverlock/serverlock_test.go b/pkg/infra/serverlock/serverlock_test.go index f13b9bfa141..44b1c44f8bc 100644 --- a/pkg/infra/serverlock/serverlock_test.go +++ b/pkg/infra/serverlock/serverlock_test.go @@ -31,6 +31,9 @@ func createTestableServerLock(t *testing.T) *ServerLockService { } func TestIntegrationServerLock(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } sl := createTestableServerLock(t) operationUID := "test-operation" @@ -67,6 +70,9 @@ func TestIntegrationServerLock(t *testing.T) { } func TestIntegrationLockAndRelease(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } operationUID := "test-operation-release" t.Run("create lock and then release it", func(t *testing.T) { diff --git a/pkg/infra/usagestats/service/usage_stats_test.go b/pkg/infra/usagestats/service/usage_stats_test.go index 6a186e93b84..107d36fcd5e 100644 --- a/pkg/infra/usagestats/service/usage_stats_test.go +++ b/pkg/infra/usagestats/service/usage_stats_test.go @@ -156,6 +156,9 @@ func TestMetrics(t *testing.T) { } func TestIntegrationGetUsageReport_IncludesMetrics(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } sqlStore := dbtest.NewFakeDB() uss := createService(t, sqlStore, true) metricName := "stats.test_metric.count" diff --git a/pkg/infra/usagestats/statscollector/concurrent_users_test.go b/pkg/infra/usagestats/statscollector/concurrent_users_test.go index 6c089a5e712..9bbab0c2f8b 100644 --- a/pkg/infra/usagestats/statscollector/concurrent_users_test.go +++ b/pkg/infra/usagestats/statscollector/concurrent_users_test.go @@ -28,6 +28,9 @@ func TestMain(m *testing.M) { } func TestIntegrationConcurrentUsersMetrics(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } sqlStore, cfg := db.InitTestDBWithCfg(t) statsService := statsimpl.ProvideService(&setting.Cfg{}, sqlStore, &dashboards.FakeDashboardService{}, &foldertest.FakeService{}, &orgtest.FakeOrgService{}, featuremgmt.WithFeatures()) s := createService(t, cfg, sqlStore, statsService) @@ -46,6 +49,9 @@ func TestIntegrationConcurrentUsersMetrics(t *testing.T) { } func TestIntegrationConcurrentUsersStats(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } sqlStore, cfg := db.InitTestDBWithCfg(t) statsService := statsimpl.ProvideService(&setting.Cfg{}, sqlStore, &dashboards.FakeDashboardService{}, &foldertest.FakeService{}, &orgtest.FakeOrgService{}, featuremgmt.WithFeatures()) s := createService(t, cfg, sqlStore, statsService) diff --git a/pkg/login/social/socialimpl/service_test.go b/pkg/login/social/socialimpl/service_test.go index 74760f0a3b5..de65f7b9a02 100644 --- a/pkg/login/social/socialimpl/service_test.go +++ b/pkg/login/social/socialimpl/service_test.go @@ -29,6 +29,9 @@ func TestMain(m *testing.M) { } func TestIntegrationSocialService_ProvideService(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } testCases := []struct { name string setup func(t *testing.T) @@ -125,6 +128,9 @@ func TestIntegrationSocialService_ProvideService(t *testing.T) { } func TestIntegrationSocialService_ProvideService_GrafanaComGrafanaNet(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } testCases := []struct { name string rawIniContent string diff --git a/pkg/plugins/manager/client/client_test.go b/pkg/plugins/manager/client/client_test.go index cf4c7521bd0..e8535e94e18 100644 --- a/pkg/plugins/manager/client/client_test.go +++ b/pkg/plugins/manager/client/client_test.go @@ -157,6 +157,9 @@ func TestCheckHealth(t *testing.T) { } func TestIntegrationCallResource(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } registry := fakes.NewFakePluginRegistry() p := &plugins.Plugin{ JSONData: plugins.JSONData{ diff --git a/pkg/registry/apis/secret/secure_value_client_test.go b/pkg/registry/apis/secret/secure_value_client_test.go index 8f52f5b29cb..44e8349c101 100644 --- a/pkg/registry/apis/secret/secure_value_client_test.go +++ b/pkg/registry/apis/secret/secure_value_client_test.go @@ -14,6 +14,9 @@ import ( ) func TestIntegration_SecureValueClient_CRUD(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } setup := testutils.Setup(t) validator := validator.ProvideSecureValueValidator() diff --git a/pkg/services/accesscontrol/acimpl/service_test.go b/pkg/services/accesscontrol/acimpl/service_test.go index e73a87f1d4f..8a086eb5562 100644 --- a/pkg/services/accesscontrol/acimpl/service_test.go +++ b/pkg/services/accesscontrol/acimpl/service_test.go @@ -50,6 +50,9 @@ func setupTestEnv(t testing.TB) *Service { } func TestIntegrationUsageMetrics(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } tests := []struct { name string expectedValue int @@ -81,6 +84,9 @@ func TestIntegrationUsageMetrics(t *testing.T) { } func TestIntegrationService_DeclareFixedRoles(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } tests := []struct { name string registrations []accesscontrol.RoleRegistration @@ -166,6 +172,9 @@ func TestIntegrationService_DeclareFixedRoles(t *testing.T) { } func TestIntegrationService_DeclarePluginRoles(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } tests := []struct { name string pluginID string @@ -279,6 +288,9 @@ func TestIntegrationService_DeclarePluginRoles(t *testing.T) { } func TestIntegrationService_RegisterFixedRoles(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } tests := []struct { name string token licensing.Licensing @@ -381,6 +393,9 @@ func TestIntegrationService_RegisterFixedRoles(t *testing.T) { } func TestIntegrationService_SearchUsersPermissions(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } searchOption := accesscontrol.SearchOptions{ActionPrefix: "teams"} ctx := context.Background() listAllPerms := map[string][]string{accesscontrol.ActionUsersPermissionsRead: {"users:*"}} @@ -602,6 +617,9 @@ func TestIntegrationService_SearchUsersPermissions(t *testing.T) { } func TestIntegrationService_SearchUserPermissions(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } ctx := context.Background() tests := []struct { name string @@ -833,6 +851,9 @@ func TestIntegrationService_SearchUserPermissions(t *testing.T) { } func TestIntegrationService_SaveExternalServiceRole(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } type run struct { cmd accesscontrol.SaveExternalServiceRoleCommand wantErr bool @@ -919,6 +940,9 @@ func TestIntegrationService_SaveExternalServiceRole(t *testing.T) { } func TestIntegrationService_DeleteExternalServiceRole(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } tests := []struct { name string initCmd *accesscontrol.SaveExternalServiceRoleCommand @@ -972,6 +996,9 @@ func TestIntegrationService_DeleteExternalServiceRole(t *testing.T) { } func TestIntegrationService_GetRoleByName(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } t.Parallel() ctx := context.Background() diff --git a/pkg/services/accesscontrol/database/database_test.go b/pkg/services/accesscontrol/database/database_test.go index f8321d492f9..7ee4343c13d 100644 --- a/pkg/services/accesscontrol/database/database_test.go +++ b/pkg/services/accesscontrol/database/database_test.go @@ -45,6 +45,9 @@ type getUserPermissionsTestCase struct { } func TestIntegrationAccessControlStore_GetUserPermissions(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } tests := []getUserPermissionsTestCase{ { desc: "should successfully get user, team and builtin permissions", @@ -159,6 +162,9 @@ type getTeamsPermissionsTestCase struct { } func TestIntegrationAccessControlStore_GetTeamsPermissions(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } tests := []getTeamsPermissionsTestCase{ { desc: "should successfully get team permissions", @@ -231,6 +237,9 @@ func TestIntegrationAccessControlStore_GetTeamsPermissions(t *testing.T) { } func TestIntegrationAccessControlStore_DeleteUserPermissions(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } t.Run("expect permissions in all orgs to be deleted", func(t *testing.T) { store, permissionsStore, usrSvc, teamSvc, _, sql := setupTestEnv(t) user, _ := createUserAndTeam(t, sql, usrSvc, teamSvc, 1) @@ -313,6 +322,9 @@ func TestIntegrationAccessControlStore_DeleteUserPermissions(t *testing.T) { } func TestIntegrationAccessControlStore_DeleteTeamPermissions(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } t.Run("expect permissions related to team to be deleted", func(t *testing.T) { store, permissionsStore, usrSvc, teamSvc, _, sql := setupTestEnv(t) user, team := createUserAndTeam(t, sql, usrSvc, teamSvc, 1) @@ -493,6 +505,9 @@ func setupTestEnv(t testing.TB) (*database.AccessControlStore, rs.Store, user.Se } func TestIntegrationAccessControlStore_SearchUsersPermissions(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } ctx := context.Background() readTeamPerm := func(teamID string) rs.SetResourcePermissionCommand { return rs.SetResourcePermissionCommand{ @@ -768,6 +783,9 @@ func TestIntegrationAccessControlStore_SearchUsersPermissions(t *testing.T) { } func TestIntegrationAccessControlStore_GetUsersBasicRoles(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } ctx := context.Background() tests := []struct { name string diff --git a/pkg/services/accesscontrol/database/externalservices_test.go b/pkg/services/accesscontrol/database/externalservices_test.go index 4f3f505bcb3..7387faf09c3 100644 --- a/pkg/services/accesscontrol/database/externalservices_test.go +++ b/pkg/services/accesscontrol/database/externalservices_test.go @@ -13,6 +13,9 @@ import ( ) func TestIntegrationAccessControlStore_SaveExternalServiceRole(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } type run struct { cmd accesscontrol.SaveExternalServiceRoleCommand wantErr bool @@ -153,6 +156,9 @@ func TestIntegrationAccessControlStore_SaveExternalServiceRole(t *testing.T) { } func TestIntegrationAccessControlStore_DeleteExternalServiceRole(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } extID := "app1" tests := []struct { name string diff --git a/pkg/services/accesscontrol/filter_test.go b/pkg/services/accesscontrol/filter_test.go index d1e2fc452f6..d8d47d74d27 100644 --- a/pkg/services/accesscontrol/filter_test.go +++ b/pkg/services/accesscontrol/filter_test.go @@ -33,6 +33,9 @@ func TestMain(m *testing.M) { } func TestIntegrationFilter_Datasources(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } tests := []filterDatasourcesTestCase{ { desc: "expect all data sources to be returned", diff --git a/pkg/services/accesscontrol/migrator/migrator_test.go b/pkg/services/accesscontrol/migrator/migrator_test.go index bfa35f17efc..0bf464d2abc 100644 --- a/pkg/services/accesscontrol/migrator/migrator_test.go +++ b/pkg/services/accesscontrol/migrator/migrator_test.go @@ -46,6 +46,9 @@ func batchInsertPermissions(cnt int, sqlStore db.DB) error { // TestIntegrationMigrateScopeSplit tests the scope split migration // also tests the scope split truncation logic func TestIntegrationMigrateScopeSplitTruncation(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } sqlStore := db.InitTestDB(t) logger := log.New("accesscontrol.migrator.test") diff --git a/pkg/services/accesscontrol/resourcepermissions/api_test.go b/pkg/services/accesscontrol/resourcepermissions/api_test.go index a80dfc0afb4..7c4dfd52547 100644 --- a/pkg/services/accesscontrol/resourcepermissions/api_test.go +++ b/pkg/services/accesscontrol/resourcepermissions/api_test.go @@ -31,6 +31,9 @@ type getDescriptionTestCase struct { } func TestIntegrationApi_getDescription(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } tests := []getDescriptionTestCase{ { desc: "should return description", @@ -136,6 +139,9 @@ type getPermissionsTestCase struct { } func TestIntegrationApi_getPermissions(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } tests := []getPermissionsTestCase{ { desc: "expect permissions for resource with id 1", @@ -182,6 +188,9 @@ type setBuiltinPermissionTestCase struct { } func TestIntegrationApi_setBuiltinRolePermission(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } tests := []setBuiltinPermissionTestCase{ { desc: "should set Edit permission for Viewer", @@ -261,6 +270,9 @@ type setTeamPermissionTestCase struct { } func TestIntegrationApi_setTeamPermission(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } tests := []setTeamPermissionTestCase{ { desc: "should set Edit permission for team 1", @@ -368,6 +380,9 @@ type setUserPermissionTestCase struct { } func TestIntegrationApi_setUserPermission(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } tests := []setUserPermissionTestCase{ { desc: "should set Edit permission for user 1", @@ -443,6 +458,9 @@ func TestIntegrationApi_setUserPermission(t *testing.T) { } func TestIntegrationApi_setUserPermissionForTeams(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } type setUserPermissionForTeamsTestCase struct { setUserPermissionTestCase teamCmd *team.CreateTeamCommand diff --git a/pkg/services/accesscontrol/resourcepermissions/service_test.go b/pkg/services/accesscontrol/resourcepermissions/service_test.go index 677ebde6095..bda629a03bd 100644 --- a/pkg/services/accesscontrol/resourcepermissions/service_test.go +++ b/pkg/services/accesscontrol/resourcepermissions/service_test.go @@ -32,6 +32,9 @@ type setUserPermissionTest struct { } func TestIntegrationService_SetUserPermission(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } tests := []setUserPermissionTest{ { desc: "should call hook when updating user permissions", @@ -76,6 +79,9 @@ type setTeamPermissionTest struct { } func TestIntegrationService_SetTeamPermission(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } tests := []setTeamPermissionTest{ { desc: "should call hook when updating user permissions", @@ -125,6 +131,9 @@ type setBuiltInRolePermissionTest struct { } func TestIntegrationService_SetBuiltInRolePermission(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } tests := []setBuiltInRolePermissionTest{ { desc: "should call hook when updating user permissions", @@ -167,6 +176,9 @@ type setPermissionsTest struct { } func TestIntegrationService_SetPermissions(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } tests := []setPermissionsTest{ { desc: "should set all permissions", @@ -236,6 +248,9 @@ func TestIntegrationService_SetPermissions(t *testing.T) { } func TestIntegrationService_RegisterActionSets(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } type registerActionSetsTest struct { desc string options Options diff --git a/pkg/services/anonymous/anonimpl/anonstore/database_test.go b/pkg/services/anonymous/anonimpl/anonstore/database_test.go index 54e625662ed..0f836a7f8b9 100644 --- a/pkg/services/anonymous/anonimpl/anonstore/database_test.go +++ b/pkg/services/anonymous/anonimpl/anonstore/database_test.go @@ -17,6 +17,9 @@ func TestMain(m *testing.M) { } func TestIntegrationAnonStore_DeleteDevicesOlderThan(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } store := db.InitTestDB(t) anonDBStore := ProvideAnonDBStore(store, 0) const keepFor = time.Hour * 24 * 61 @@ -54,6 +57,9 @@ func TestIntegrationAnonStore_DeleteDevicesOlderThan(t *testing.T) { } func TestIntegrationBeyondDeviceLimit(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } store := db.InitTestDB(t) anonDBStore := ProvideAnonDBStore(store, 1) @@ -75,6 +81,9 @@ func TestIntegrationBeyondDeviceLimit(t *testing.T) { } func TestIntegrationAnonStore_DeleteDevice(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } store := db.InitTestDB(t) anonDBStore := ProvideAnonDBStore(store, 0) const keepFor = time.Hour * 24 * 61 diff --git a/pkg/services/auth/authimpl/auth_token_test.go b/pkg/services/auth/authimpl/auth_token_test.go index e4e183ceae7..03e9ae63025 100644 --- a/pkg/services/auth/authimpl/auth_token_test.go +++ b/pkg/services/auth/authimpl/auth_token_test.go @@ -33,6 +33,9 @@ func TestMain(m *testing.M) { } func TestIntegrationUserAuthToken(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } ctx := createTestContext(t) usr := &user.User{ID: int64(10)} @@ -787,6 +790,9 @@ func (c *testContext) updateRotatedAt(id, rotatedAt int64) (bool, error) { } func TestIntegrationTokenCount(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } ctx := createTestContext(t) user := &user.User{ID: int64(10)} @@ -824,6 +830,9 @@ func TestIntegrationTokenCount(t *testing.T) { } func TestIntegrationRevokeAllUserTokens(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } t.Run("should not fail if the external sessions could not be removed", func(t *testing.T) { ctx := createTestContext(t) usr := &user.User{ID: int64(10)} @@ -857,6 +866,9 @@ func TestIntegrationRevokeAllUserTokens(t *testing.T) { } func TestIntegrationRevokeToken(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } t.Run("should not fail if the external sessions could not be removed", func(t *testing.T) { ctx := createTestContext(t) usr := &user.User{ID: int64(10)} @@ -888,6 +900,9 @@ func TestIntegrationRevokeToken(t *testing.T) { } func TestIntegrationBatchRevokeAllUserTokens(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } t.Run("should not fail if the external sessions could not be removed", func(t *testing.T) { ctx := createTestContext(t) userIds := []int64{1, 2, 3} diff --git a/pkg/services/auth/jwt/auth_test.go b/pkg/services/auth/jwt/auth_test.go index 712232cd9d1..18ce9f5dcad 100644 --- a/pkg/services/auth/jwt/auth_test.go +++ b/pkg/services/auth/jwt/auth_test.go @@ -45,6 +45,9 @@ func TestMain(m *testing.M) { } func TestIntegrationVerifyUsingPKIXPublicKeyFile(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } key := rsaKeys[0] unknownKey := rsaKeys[1] @@ -80,6 +83,9 @@ func TestIntegrationVerifyUsingPKIXPublicKeyFile(t *testing.T) { } func TestIntegrationVerifyUsingJWKSetFile(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } configure := func(t *testing.T, cfg *setting.Cfg) { t.Helper() @@ -119,6 +125,9 @@ func TestIntegrationVerifyUsingJWKSetFile(t *testing.T) { } func TestIntegrationVerifyUsingJWKSetURL(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } t.Run("should refuse to start with non-https URL", func(t *testing.T) { var err error @@ -161,6 +170,9 @@ func TestIntegrationVerifyUsingJWKSetURL(t *testing.T) { } func TestIntegrationCachingJWKHTTPResponse(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } jwkCachingScenario(t, "caches the jwk response", func(t *testing.T, sc cachingScenarioContext) { for i := 0; i < 5; i++ { token := sign(t, &jwKeys[0], jwt.Claims{Subject: subject}, nil) @@ -201,6 +213,9 @@ func TestIntegrationCachingJWKHTTPResponse(t *testing.T) { } func TestIntegrationSignatureWithNoneAlgorithm(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } scenario(t, "rejects a token signed with \"none\" algorithm", func(t *testing.T, sc scenarioContext) { token := signNone(t, jwt.Claims{Subject: "foo"}) _, err := sc.authJWTSvc.Verify(sc.ctx, token) @@ -209,6 +224,9 @@ func TestIntegrationSignatureWithNoneAlgorithm(t *testing.T) { } func TestIntegrationClaimValidation(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } key := rsaKeys[0] scenario(t, "validates iss field for equality", func(t *testing.T, sc scenarioContext) { @@ -369,6 +387,9 @@ func jwkCachingScenario(t *testing.T, desc string, fn cachingScenarioFunc, cbs . } func TestIntegrationBase64Paddings(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } key := rsaKeys[0] scenario(t, "verifies a token with base64 padding (non compliant rfc7515#section-2 but accepted)", func(t *testing.T, sc scenarioContext) { diff --git a/pkg/services/dashboards/service/dashboard_service_test.go b/pkg/services/dashboards/service/dashboard_service_test.go index fa1d91e8a0b..68da3b789cc 100644 --- a/pkg/services/dashboards/service/dashboard_service_test.go +++ b/pkg/services/dashboards/service/dashboard_service_test.go @@ -2644,6 +2644,9 @@ func TestCleanUpDashboard(t *testing.T) { } func TestIntegrationK8sDashboardCleanupJob(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } tests := []struct { name string featureEnabled bool diff --git a/pkg/services/dashboardsnapshots/service/service_test.go b/pkg/services/dashboardsnapshots/service/service_test.go index ac364c36acb..d5621692cf9 100644 --- a/pkg/services/dashboardsnapshots/service/service_test.go +++ b/pkg/services/dashboardsnapshots/service/service_test.go @@ -39,6 +39,9 @@ func TestMain(m *testing.M) { } func TestIntegrationDashboardSnapshotsService(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } sqlStore := db.InitTestDB(t) cfg := setting.NewCfg() dsStore := dashsnapdb.ProvideStore(sqlStore, cfg) @@ -98,6 +101,9 @@ func TestIntegrationDashboardSnapshotsService(t *testing.T) { } func TestIntegrationValidateDashboardExists(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } sqlStore := db.InitTestDB(t) cfg := setting.NewCfg() dsStore := dashsnapdb.ProvideStore(sqlStore, cfg) diff --git a/pkg/services/datasources/service/datasource_test.go b/pkg/services/datasources/service/datasource_test.go index a21854821f2..6471824ec59 100644 --- a/pkg/services/datasources/service/datasource_test.go +++ b/pkg/services/datasources/service/datasource_test.go @@ -63,6 +63,9 @@ func (d *dataSourceMockRetriever) GetDataSource(ctx context.Context, query *data } func TestIntegrationService_AddDataSource(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } t.Run("should not fail if the plugin is not installed", func(t *testing.T) { dsService := initDSService(t) dsService.pluginStore = &pluginstore.FakePluginStore{ @@ -354,6 +357,9 @@ func TestService_getAvailableName(t *testing.T) { } func TestIntegrationService_UpdateDataSource(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } t.Run("should return not found error if datasource not found", func(t *testing.T) { dsService := initDSService(t) @@ -804,6 +810,9 @@ func TestIntegrationService_UpdateDataSource(t *testing.T) { } func TestIntegrationService_DeleteDataSource(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } t.Run("should not return an error if data source doesn't exist", func(t *testing.T) { sqlStore := db.InitTestDB(t) secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore()) @@ -1081,6 +1090,9 @@ func TestService_awsServiceNamespace(t *testing.T) { //nolint:goconst func TestIntegrationService_GetHttpTransport(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } cfg := &setting.Cfg{} t.Run("Should use cached proxy", func(t *testing.T) { @@ -1493,6 +1505,9 @@ func TestIntegrationService_GetHttpTransport(t *testing.T) { } func TestIntegrationService_getProxySettings(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } sqlStore := db.InitTestDB(t) secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore()) secretsStore := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger")) @@ -1571,6 +1586,9 @@ func TestIntegrationService_getProxySettings(t *testing.T) { } func TestIntegrationService_getTimeout(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } cfg := &setting.Cfg{} originalTimeout := sdkhttpclient.DefaultTimeoutOptions.Timeout sdkhttpclient.DefaultTimeoutOptions.Timeout = time.Minute @@ -1605,6 +1623,9 @@ func TestIntegrationService_getTimeout(t *testing.T) { } func TestIntegrationService_GetDecryptedValues(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } t.Run("should migrate and retrieve values from secure json data", func(t *testing.T) { ds := &datasources.DataSource{ ID: 1, @@ -1664,6 +1685,9 @@ func TestIntegrationService_GetDecryptedValues(t *testing.T) { } func TestIntegrationDataSource_CustomHeaders(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } sqlStore := db.InitTestDB(t) secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore()) secretsStore := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger")) diff --git a/pkg/services/folder/folderimpl/dashboard_folder_store_test.go b/pkg/services/folder/folderimpl/dashboard_folder_store_test.go index 4a7089c2c0a..894a79aba85 100644 --- a/pkg/services/folder/folderimpl/dashboard_folder_store_test.go +++ b/pkg/services/folder/folderimpl/dashboard_folder_store_test.go @@ -26,6 +26,9 @@ func TestMain(m *testing.M) { } func TestIntegrationDashboardFolderStore(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } var sqlStore db.DB var cfg *setting.Cfg var dashboardStore dashboards.Store diff --git a/pkg/services/folder/folderimpl/folder_test.go b/pkg/services/folder/folderimpl/folder_test.go index efe3c5914df..a9a1b4e27eb 100644 --- a/pkg/services/folder/folderimpl/folder_test.go +++ b/pkg/services/folder/folderimpl/folder_test.go @@ -727,6 +727,9 @@ func TestIntegrationNestedFolderServiceBasicOperations(t *testing.T) { } func TestIntegrationNestedFolderServiceFeatureToggle(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } nestedFolderStore := folder.NewFakeStore() dashStore := dashboards.FakeDashboardStore{} @@ -758,6 +761,9 @@ func TestIntegrationNestedFolderServiceFeatureToggle(t *testing.T) { } func TestIntegrationFolderServiceDualWrite(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } db, _ := sqlstore.InitTestDB(t) cfg := setting.NewCfg() features := featuremgmt.WithFeatures() @@ -817,6 +823,9 @@ func TestIntegrationFolderServiceDualWrite(t *testing.T) { } func TestIntegrationNestedFolderService(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } t.Run("with feature flag unset", func(t *testing.T) { t.Run("Should create a folder in both dashboard and folders tables", func(t *testing.T) { // dash is needed here because folderSvc.Create expects SaveDashboard to return it @@ -1691,6 +1700,9 @@ func TestIntegrationNestedFolderSharedWithMe(t *testing.T) { } func TestIntegrationFolderServiceGetFolder(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } db, _ := sqlstore.InitTestDB(t) signedInAdminUser := user.SignedInUser{UserID: 1, OrgID: orgID, Permissions: map[int64]map[string][]string{ @@ -1802,6 +1814,9 @@ func TestIntegrationFolderServiceGetFolder(t *testing.T) { } func TestIntegrationFolderServiceGetFolders(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } db, cfg := sqlstore.InitTestDB(t) folderStore := ProvideDashboardFolderStore(db) @@ -1873,6 +1888,9 @@ func TestIntegrationFolderServiceGetFolders(t *testing.T) { // TODO replace it with an API test under /pkg/tests/api/folders // whenever the golang client with get updated to allow filtering child folders by permission func TestIntegrationGetChildrenFilterByPermission(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } db, cfg := sqlstore.InitTestDB(t) signedInAdminUser := user.SignedInUser{UserID: 1, OrgID: orgID, Permissions: map[int64]map[string][]string{ diff --git a/pkg/services/folder/folderimpl/folder_unifiedstorage_test.go b/pkg/services/folder/folderimpl/folder_unifiedstorage_test.go index 44bd735445f..609ede53d19 100644 --- a/pkg/services/folder/folderimpl/folder_unifiedstorage_test.go +++ b/pkg/services/folder/folderimpl/folder_unifiedstorage_test.go @@ -848,6 +848,9 @@ func TestGetFoldersFromApiServer(t *testing.T) { } func TestIntegrationDeleteFoldersFromApiServer(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } fakeK8sClient := new(client.MockK8sHandler) fakeK8sClient.On("GetNamespace", mock.Anything, mock.Anything).Return("default") dashboardK8sclient := new(client.MockK8sHandler) diff --git a/pkg/services/libraryelements/libraryelements_create_test.go b/pkg/services/libraryelements/libraryelements_create_test.go index 5a66d170e83..53f1ed38e68 100644 --- a/pkg/services/libraryelements/libraryelements_create_test.go +++ b/pkg/services/libraryelements/libraryelements_create_test.go @@ -12,6 +12,9 @@ import ( ) func TestIntegration_CreateLibraryElement(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } scenarioWithPanel(t, "When an admin tries to create a library panel that already exists, it should fail", func(t *testing.T, sc scenarioContext) { // nolint:staticcheck diff --git a/pkg/services/libraryelements/libraryelements_delete_test.go b/pkg/services/libraryelements/libraryelements_delete_test.go index 5605313b4b6..86d7a886015 100644 --- a/pkg/services/libraryelements/libraryelements_delete_test.go +++ b/pkg/services/libraryelements/libraryelements_delete_test.go @@ -14,6 +14,9 @@ import ( ) func TestIntegration_DeleteLibraryElement(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } scenarioWithPanel(t, "When an admin tries to delete a library panel that does not exist, it should fail", func(t *testing.T, sc scenarioContext) { resp := sc.service.deleteHandler(sc.reqContext) diff --git a/pkg/services/libraryelements/libraryelements_get_all_test.go b/pkg/services/libraryelements/libraryelements_get_all_test.go index 970730399c9..b3a4acb6cd3 100644 --- a/pkg/services/libraryelements/libraryelements_get_all_test.go +++ b/pkg/services/libraryelements/libraryelements_get_all_test.go @@ -14,6 +14,9 @@ import ( ) func TestIntegration_GetAllLibraryElements(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } testScenario(t, "When an admin tries to get all library panels and none exists, it should return none", func(t *testing.T, sc scenarioContext) { resp := sc.service.getAllHandler(sc.reqContext) diff --git a/pkg/services/libraryelements/libraryelements_get_test.go b/pkg/services/libraryelements/libraryelements_get_test.go index b7d654167bc..b05c269ee63 100644 --- a/pkg/services/libraryelements/libraryelements_get_test.go +++ b/pkg/services/libraryelements/libraryelements_get_test.go @@ -18,6 +18,9 @@ import ( ) func TestIntegration_GetLibraryElement(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } scenarioWithPanel(t, "When an admin tries to get a library panel that does not exist, it should fail", func(t *testing.T, sc scenarioContext) { // by uid diff --git a/pkg/services/libraryelements/libraryelements_patch_test.go b/pkg/services/libraryelements/libraryelements_patch_test.go index f92076d041a..1dc29d065ee 100644 --- a/pkg/services/libraryelements/libraryelements_patch_test.go +++ b/pkg/services/libraryelements/libraryelements_patch_test.go @@ -14,6 +14,9 @@ import ( ) func TestIntegration_PatchLibraryElement(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } scenarioWithPanel(t, "When an admin tries to patch a library panel that does not exist, it should fail", func(t *testing.T, sc scenarioContext) { cmd := model.PatchLibraryElementCommand{Kind: int64(model.PanelElement), Version: 1} diff --git a/pkg/services/libraryelements/libraryelements_test.go b/pkg/services/libraryelements/libraryelements_test.go index fd63d239131..ad8b412e860 100644 --- a/pkg/services/libraryelements/libraryelements_test.go +++ b/pkg/services/libraryelements/libraryelements_test.go @@ -62,6 +62,9 @@ func TestMain(m *testing.M) { } func TestIntegration_DeleteLibraryPanelsInFolder(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } scenarioWithPanel(t, "When an admin tries to delete a folder that contains connected library elements, it should fail", func(t *testing.T, sc scenarioContext) { dashJSON := map[string]any{ @@ -140,6 +143,9 @@ func TestIntegration_DeleteLibraryPanelsInFolder(t *testing.T) { } func TestIntegration_GetLibraryPanelConnections(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } scenarioWithPanel(t, "When an admin tries to get connections of library panel, it should succeed and return correct result", func(t *testing.T, sc scenarioContext) { dashJSON := map[string]any{ diff --git a/pkg/services/librarypanels/librarypanels_test.go b/pkg/services/librarypanels/librarypanels_test.go index da8d4057f63..e7118888e67 100644 --- a/pkg/services/librarypanels/librarypanels_test.go +++ b/pkg/services/librarypanels/librarypanels_test.go @@ -56,6 +56,9 @@ func TestMain(m *testing.M) { } func TestIntegrationConnectLibraryPanelsForDashboard(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } scenarioWithLibraryPanel(t, "When an admin tries to store a dashboard with a library panel, it should connect the two", func(t *testing.T, sc scenarioContext) { dashJSON := map[string]any{ @@ -349,6 +352,9 @@ func TestIntegrationConnectLibraryPanelsForDashboard(t *testing.T) { } func TestIntegrationImportLibraryPanelsForDashboard(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } testScenario(t, "When an admin tries to import a dashboard with a library panel that does not exist, it should import the library panel", func(t *testing.T, sc scenarioContext) { var missingUID = "jL6MrxCMz" diff --git a/pkg/services/live/live_test.go b/pkg/services/live/live_test.go index eb685d6a4d2..33b9ca103ef 100644 --- a/pkg/services/live/live_test.go +++ b/pkg/services/live/live_test.go @@ -30,6 +30,9 @@ func TestMain(m *testing.M) { } func TestIntegration_provideLiveService_RedisUnavailable(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } cfg := setting.NewCfg() cfg.LiveHAEngine = "testredisunavailable" diff --git a/pkg/services/loginattempt/loginattemptimpl/login_attempt_test.go b/pkg/services/loginattempt/loginattemptimpl/login_attempt_test.go index 1e220035a7f..6afd594a9c9 100644 --- a/pkg/services/loginattempt/loginattemptimpl/login_attempt_test.go +++ b/pkg/services/loginattempt/loginattemptimpl/login_attempt_test.go @@ -87,6 +87,9 @@ func TestService_Validate(t *testing.T) { } func TestIntegrationUserLoginAttempts(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } ctx := context.Background() cfg := setting.NewCfg() cfg.DisableBruteForceLoginProtection = false @@ -185,6 +188,9 @@ func TestService_ValidateIPAddress(t *testing.T) { } func TestIntegrationIPLoginAttempts(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } ctx := context.Background() cfg := setting.NewCfg() cfg.DisableIPAddressLoginProtection = false diff --git a/pkg/services/ngalert/api/api_provisioning_test.go b/pkg/services/ngalert/api/api_provisioning_test.go index 286dd7e4404..dc60b8dad58 100644 --- a/pkg/services/ngalert/api/api_provisioning_test.go +++ b/pkg/services/ngalert/api/api_provisioning_test.go @@ -68,6 +68,9 @@ func TestMain(m *testing.M) { } func TestIntegrationProvisioningApi(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } t.Run("policies", func(t *testing.T) { t.Run("successful GET returns 200", func(t *testing.T) { sut := createProvisioningSrvSut(t) @@ -1626,6 +1629,9 @@ func TestIntegrationProvisioningApi(t *testing.T) { } func TestIntegrationProvisioningApiContactPointExport(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } createTestEnv := func(t *testing.T, testConfig string) testEnvironment { env := createTestEnv(t, testConfig) env.ac = &recordingAccessControlFake{ diff --git a/pkg/services/ngalert/models/receivers_test.go b/pkg/services/ngalert/models/receivers_test.go index 9ca835e7fe9..4d1b09bd4ef 100644 --- a/pkg/services/ngalert/models/receivers_test.go +++ b/pkg/services/ngalert/models/receivers_test.go @@ -68,6 +68,9 @@ func TestReceiver_EncryptDecrypt(t *testing.T) { } func TestIntegration_Redact(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } redactFn := func(key string) string { return "TESTREDACTED" } @@ -99,6 +102,10 @@ func TestIntegration_Redact(t *testing.T) { func TestIntegration_Validate(t *testing.T) { // Test that all known integration types are valid. + if testing.Short() { + t.Skip("skipping integration test in short mode") + } + for integrationType := range alertingNotify.AllKnownConfigsForTesting { t.Run(integrationType, func(t *testing.T) { validIntegration := IntegrationGen(IntegrationMuts.WithValidConfig(integrationType))() @@ -114,6 +121,10 @@ func TestIntegration_Validate(t *testing.T) { func TestIntegration_WithExistingSecureFields(t *testing.T) { // Test that WithExistingSecureFields will copy over the secure fields from the existing integration. + if testing.Short() { + t.Skip("skipping integration test in short mode") + } + testCases := []struct { name string integration Integration @@ -232,6 +243,10 @@ func TestIntegration_WithExistingSecureFields(t *testing.T) { func TestIntegrationConfig(t *testing.T) { // Test that all known integration types have a config and correctly mark their secrets as secure. + if testing.Short() { + t.Skip("skipping integration test in short mode") + } + for integrationType := range alertingNotify.AllKnownConfigsForTesting { t.Run(integrationType, func(t *testing.T) { config, err := IntegrationConfigFromType(integrationType) @@ -263,6 +278,10 @@ func TestIntegrationConfig(t *testing.T) { func TestIntegration_SecureFields(t *testing.T) { // Test that all known integration types have a config and correctly mark their secrets as secure. + if testing.Short() { + t.Skip("skipping integration test in short mode") + } + for integrationType := range alertingNotify.AllKnownConfigsForTesting { t.Run(integrationType, func(t *testing.T) { t.Run("contains SecureSettings", func(t *testing.T) { diff --git a/pkg/services/ngalert/notifier/alertmanager_test.go b/pkg/services/ngalert/notifier/alertmanager_test.go index e865fca9178..40d23c6817d 100644 --- a/pkg/services/ngalert/notifier/alertmanager_test.go +++ b/pkg/services/ngalert/notifier/alertmanager_test.go @@ -64,6 +64,9 @@ func setupAMTest(t *testing.T) *alertmanager { } func TestIntegrationAlertmanager_newAlertmanager(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } am := setupAMTest(t) require.False(t, am.Ready()) } diff --git a/pkg/services/ngalert/notifier/receiver_svc_test.go b/pkg/services/ngalert/notifier/receiver_svc_test.go index 5ed24d2db2f..5451a53a859 100644 --- a/pkg/services/ngalert/notifier/receiver_svc_test.go +++ b/pkg/services/ngalert/notifier/receiver_svc_test.go @@ -34,6 +34,9 @@ import ( ) func TestIntegrationReceiverService_GetReceiver(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } sqlStore := db.InitTestDB(t) secretsService := manager.SetupTestService(t, database.ProvideSecretsStore(sqlStore)) @@ -62,6 +65,9 @@ func TestIntegrationReceiverService_GetReceiver(t *testing.T) { } func TestIntegrationReceiverService_GetReceivers(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } sqlStore := db.InitTestDB(t) secretsService := manager.SetupTestService(t, database.ProvideSecretsStore(sqlStore)) @@ -92,6 +98,9 @@ func TestIntegrationReceiverService_GetReceivers(t *testing.T) { } func TestIntegrationReceiverService_DecryptRedact(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } sqlStore := db.InitTestDB(t) secretsService := manager.SetupTestService(t, database.ProvideSecretsStore(sqlStore)) diff --git a/pkg/services/ngalert/notifier/templates_test.go b/pkg/services/ngalert/notifier/templates_test.go index 9c6000bfad1..20a5877ba7d 100644 --- a/pkg/services/ngalert/notifier/templates_test.go +++ b/pkg/services/ngalert/notifier/templates_test.go @@ -58,6 +58,9 @@ var ( ) func TestIntegrationTemplateDefaultData(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } am := setupAMTest(t) tests := []struct { diff --git a/pkg/services/ngalert/provisioning/alert_rules_test.go b/pkg/services/ngalert/provisioning/alert_rules_test.go index 253010be25e..ae9eb265b6b 100644 --- a/pkg/services/ngalert/provisioning/alert_rules_test.go +++ b/pkg/services/ngalert/provisioning/alert_rules_test.go @@ -42,6 +42,9 @@ import ( ) func TestIntegrationAlertRuleService(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } ruleService := createAlertRuleService(t, nil) var orgID int64 = 1 u := &user.SignedInUser{ @@ -755,6 +758,9 @@ func TestIntegrationAlertRuleService(t *testing.T) { } func TestIntegrationCreateAlertRule(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } orgID := rand.Int63() u := &user.SignedInUser{OrgID: orgID, UserUID: util.GenerateShortUID()} groupKey := models.GenerateGroupKey(orgID) @@ -1984,6 +1990,9 @@ func TestDeleteRuleGroups(t *testing.T) { } func TestIntegrationProvisiongWithFullpath(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } tracer := tracing.InitializeTracerForTest() inProcBus := bus.ProvideBus(tracer) sqlStore, cfg := db.InitTestDBWithCfg(t) diff --git a/pkg/services/ngalert/provisioning/contactpoints_test.go b/pkg/services/ngalert/provisioning/contactpoints_test.go index bc7b48bf431..5f98590e857 100644 --- a/pkg/services/ngalert/provisioning/contactpoints_test.go +++ b/pkg/services/ngalert/provisioning/contactpoints_test.go @@ -36,6 +36,9 @@ import ( ) func TestIntegrationContactPointService(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } sqlStore := db.InitTestDB(t) secretsService := manager.SetupTestService(t, database.ProvideSecretsStore(sqlStore)) @@ -361,6 +364,9 @@ func TestIntegrationContactPointService(t *testing.T) { } func TestIntegrationContactPointServiceDecryptRedact(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } secretsService := manager.SetupTestService(t, database.ProvideSecretsStore(db.InitTestDB(t))) redactedUser := &user.SignedInUser{OrgID: 1, Permissions: map[int64]map[string][]string{ diff --git a/pkg/services/ngalert/remote/alertmanager_test.go b/pkg/services/ngalert/remote/alertmanager_test.go index bf1d9f0bfbd..d9bd7d5edcc 100644 --- a/pkg/services/ngalert/remote/alertmanager_test.go +++ b/pkg/services/ngalert/remote/alertmanager_test.go @@ -257,8 +257,13 @@ func TestGetRemoteState(t *testing.T) { } func TestIntegrationApplyConfig(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + + // errorHandler returns an error response for the readiness check and state sync. + } const tenantID = "test" - // errorHandler returns an error response for the readiness check and state sync. + errorHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { require.Equal(t, tenantID, r.Header.Get(client.MimirTenantHeader)) require.Equal(t, "true", r.Header.Get(client.RemoteAlertmanagerHeader)) diff --git a/pkg/services/ngalert/sender/notifier_test.go b/pkg/services/ngalert/sender/notifier_test.go index 6b70f91e17b..d1aec6068ab 100644 --- a/pkg/services/ngalert/sender/notifier_test.go +++ b/pkg/services/ngalert/sender/notifier_test.go @@ -1067,6 +1067,9 @@ func TestStop_DrainingEnabled(t *testing.T) { } func TestIntegrationApplyConfig(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } targetURL := "alertmanager:9093" targetGroup := &targetgroup.Group{ Targets: []model.LabelSet{ diff --git a/pkg/services/ngalert/state/manager_test.go b/pkg/services/ngalert/state/manager_test.go index c42bb5f6435..4d419efe252 100644 --- a/pkg/services/ngalert/state/manager_test.go +++ b/pkg/services/ngalert/state/manager_test.go @@ -47,6 +47,9 @@ func TestMain(m *testing.M) { } func TestIntegrationWarmStateCache(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } evaluationTime, err := time.Parse("2006-01-02", "2021-03-25") require.NoError(t, err) ctx := context.Background() @@ -272,6 +275,9 @@ func TestIntegrationWarmStateCache(t *testing.T) { } func TestIntegrationDashboardAnnotations(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } evaluationTime, err := time.Parse("2006-01-02", "2022-01-01") require.NoError(t, err) @@ -1451,7 +1457,11 @@ func printAllAnnotations(annos map[int64]annotations.Item) string { } func TestIntegrationStaleResultsHandler(t *testing.T) { - evaluationTime := time.Now().Truncate(time.Second).UTC() // Truncate to the second since we don't store sub-second precision. + if testing.Short() { + t.Skip("skipping integration test in short mode") + // Truncate to the second since we don't store sub-second precision. + } + evaluationTime := time.Now().Truncate(time.Second).UTC() interval := time.Minute ctx := context.Background() @@ -1738,6 +1748,9 @@ func TestStaleResults(t *testing.T) { } func TestIntegrationDeleteStateByRuleUID(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } interval := time.Minute ctx := context.Background() ng, dbstore := tests.SetupTestEnv(t, 1) @@ -1884,6 +1897,9 @@ func TestIntegrationDeleteStateByRuleUID(t *testing.T) { } func TestIntegrationResetStateByRuleUID(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } interval := time.Minute ctx := context.Background() ng, dbstore := tests.SetupTestEnv(t, 1) diff --git a/pkg/services/ngalert/store/instance_database_test.go b/pkg/services/ngalert/store/instance_database_test.go index 7724c2a5d48..f3d2ae3335a 100644 --- a/pkg/services/ngalert/store/instance_database_test.go +++ b/pkg/services/ngalert/store/instance_database_test.go @@ -301,6 +301,9 @@ func TestIntegrationAlertInstanceOperations(t *testing.T) { } func TestIntegrationFullSync(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } batchSize := 1 ctx := context.Background() diff --git a/pkg/services/ngalert/store/org_test.go b/pkg/services/ngalert/store/org_test.go index 6b16004fc23..c88fdc6b114 100644 --- a/pkg/services/ngalert/store/org_test.go +++ b/pkg/services/ngalert/store/org_test.go @@ -14,6 +14,9 @@ import ( ) func TestIntegrationFetchOrgIds(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } ctx := context.Background() t.Run("returns empty result when no orgs exist", func(t *testing.T) { diff --git a/pkg/services/ngalert/store/range_to_instant_test.go b/pkg/services/ngalert/store/range_to_instant_test.go index c5fa4883a76..97b6966ecdc 100644 --- a/pkg/services/ngalert/store/range_to_instant_test.go +++ b/pkg/services/ngalert/store/range_to_instant_test.go @@ -146,6 +146,9 @@ func TestCanBeInstant(t *testing.T) { } func TestIntegrationMigrateLokiQueryToInstant(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } original := createMigrateableLokiRule(t) migrated := createMigrateableLokiRule(t, func(r *models.AlertRule) { r.Data[0] = lokiQuery(t, "A", "instant", "grafanacloud-logs") @@ -169,6 +172,9 @@ func TestIntegrationMigrateLokiQueryToInstant(t *testing.T) { } func TestIntegrationMigrateMultiLokiQueryToInstant(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } original := createMultiQueryMigratableLokiRule(t) migrated := createMultiQueryMigratableLokiRule(t, func(r *models.AlertRule) { r.Data[0] = lokiQuery(t, "TotalRequests", "instant", "grafanacloud-logs") @@ -206,6 +212,9 @@ func TestIntegrationMigrateMultiLokiQueryToInstant(t *testing.T) { } func TestIntegrationMigratePromQueryToInstant(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } original := createMigratablePromRule(t) migrated := createMigratablePromRule(t, func(r *models.AlertRule) { r.Data[0] = prometheusQuery(t, "A", promExternalDS, promIsInstant) @@ -227,6 +236,9 @@ func TestIntegrationMigratePromQueryToInstant(t *testing.T) { } func TestIntegrationMigrateMultiPromQueryToInstant(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } original := createMultiQueryMigratablePromRule(t) migrated := createMultiQueryMigratablePromRule(t, func(r *models.AlertRule) { r.Data[0] = prometheusQuery(t, "TotalRequests", promExternalDS, promIsInstant) diff --git a/pkg/services/provisioning/dashboards/file_reader_test.go b/pkg/services/provisioning/dashboards/file_reader_test.go index 80f985a71bb..1e201e60ecf 100644 --- a/pkg/services/provisioning/dashboards/file_reader_test.go +++ b/pkg/services/provisioning/dashboards/file_reader_test.go @@ -109,6 +109,9 @@ func TestCreatingNewDashboardFileReader(t *testing.T) { } func TestIntegrationDashboardFileReader(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } logger := log.New("test-logger") cfg := &config{} diff --git a/pkg/services/provisioning/dashboards/validator_test.go b/pkg/services/provisioning/dashboards/validator_test.go index f5affa902e0..02d2d9b2aba 100644 --- a/pkg/services/provisioning/dashboards/validator_test.go +++ b/pkg/services/provisioning/dashboards/validator_test.go @@ -32,6 +32,9 @@ const ( ) func TestIntegrationDuplicatesValidator(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } fakeService := &dashboards.FakeDashboardProvisioning{} defer fakeService.AssertExpectations(t) diff --git a/pkg/services/publicdashboards/database/database_test.go b/pkg/services/publicdashboards/database/database_test.go index 5104206c46a..577a1a204aa 100644 --- a/pkg/services/publicdashboards/database/database_test.go +++ b/pkg/services/publicdashboards/database/database_test.go @@ -683,6 +683,9 @@ func TestIntegrationDelete(t *testing.T) { } func TestIntegrationDeleteByDashboardUIDs(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } var sqlStore db.DB var cfg *setting.Cfg var dashboardStore dashboards.Store diff --git a/pkg/services/publicdashboards/service/query_test.go b/pkg/services/publicdashboards/service/query_test.go index a0c5bcf7367..dd88aab823d 100644 --- a/pkg/services/publicdashboards/service/query_test.go +++ b/pkg/services/publicdashboards/service/query_test.go @@ -308,6 +308,9 @@ const ( ) func TestIntegrationGetQueryDataResponse(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } fakeDashboardService := &dashboards.FakeDashboardService{} service, sqlStore, _ := newPublicDashboardServiceImpl(t, nil, nil, nil, fakeDashboardService, nil) fakeQueryService := &query.FakeQueryService{} @@ -362,6 +365,9 @@ func TestIntegrationGetQueryDataResponse(t *testing.T) { } func TestIntegrationFindAnnotations(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } color := "red" name := "annoName" t.Run("service identity has correct permissions to get annotations dashboards and query datasources", func(t *testing.T) { @@ -718,6 +724,9 @@ func TestIntegrationFindAnnotations(t *testing.T) { } func TestIntegrationGetMetricRequest(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } service, sqlStore, cfg := newPublicDashboardServiceImpl(t, nil, nil, nil, nil, nil) dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore)) require.NoError(t, err) @@ -757,6 +766,9 @@ func TestIntegrationGetMetricRequest(t *testing.T) { } func TestIntegrationBuildMetricRequest(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } fakeDashboardService := &dashboards.FakeDashboardService{} service, sqlStore, cfg := newPublicDashboardServiceImpl(t, nil, nil, nil, fakeDashboardService, nil) diff --git a/pkg/services/publicdashboards/service/service_test.go b/pkg/services/publicdashboards/service/service_test.go index 5ddc7c8f2d9..f79ada33f83 100644 --- a/pkg/services/publicdashboards/service/service_test.go +++ b/pkg/services/publicdashboards/service/service_test.go @@ -61,6 +61,9 @@ func TestLogPrefix(t *testing.T) { } func TestIntegrationGetPublicDashboardForView(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } type storeResp struct { pd *PublicDashboard d *dashboards.Dashboard @@ -453,6 +456,9 @@ func TestIntegrationGetPublicDashboardForView(t *testing.T) { } func TestIntegrationGetPublicDashboard(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } type storeResp struct { pd *PublicDashboard d *dashboards.Dashboard @@ -530,6 +536,9 @@ func TestIntegrationGetPublicDashboard(t *testing.T) { } func TestIntegrationGetEnabledPublicDashboard(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } type storeResp struct { pd *PublicDashboard d *dashboards.Dashboard @@ -595,6 +604,9 @@ func TestIntegrationGetEnabledPublicDashboard(t *testing.T) { // We're using sqlite here because testing all of the behaviors with mocks in // the correct order is convoluted. func TestIntegrationCreatePublicDashboard(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } t.Run("Create public dashboard", func(t *testing.T) { fakeDashboardService := &dashboards.FakeDashboardService{} service, sqlStore, cfg := newPublicDashboardServiceImpl(t, nil, nil, nil, fakeDashboardService, nil) @@ -976,6 +988,9 @@ func assertFalseIfNull(t *testing.T, expectedValue bool, nullableValue *bool) { } func TestIntegrationUpdatePublicDashboard(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } fakeDashboardService := &dashboards.FakeDashboardService{} service, sqlStore, cfg := newPublicDashboardServiceImpl(t, nil, nil, nil, fakeDashboardService, nil) @@ -1220,6 +1235,9 @@ func assertOldValueIfNull(t *testing.T, expectedValue bool, oldValue bool, nulla } func TestIntegrationDeletePublicDashboard(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } pubdash := &PublicDashboard{Uid: "2", OrgId: 1, DashboardUid: "uid"} type mockFindResponse struct { @@ -1390,6 +1408,9 @@ func TestDashboardEnabledChanged(t *testing.T) { } func TestIntegrationPublicDashboardServiceImpl_ListPublicDashboards(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } features := featuremgmt.WithFeatures() testDB, cfg := db.InitTestDBWithCfg(t) dashStore, err := dashboardsDB.ProvideDashboardStore(testDB, cfg, features, tagimpl.ProvideService(testDB)) diff --git a/pkg/services/query/query_test.go b/pkg/services/query/query_test.go index e4d430aa5b3..8b0d17a381c 100644 --- a/pkg/services/query/query_test.go +++ b/pkg/services/query/query_test.go @@ -51,6 +51,9 @@ func TestMain(m *testing.M) { } func TestIntegrationParseMetricRequest(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } t.Run("Test a simple single datasource query", func(t *testing.T) { tc := setup(t, false, nil) mr := metricRequestWithQueries(t, `{ @@ -272,6 +275,9 @@ func TestIntegrationParseMetricRequest(t *testing.T) { } func TestIntegrationQueryDataMultipleSources(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } t.Run("can query multiple datasources", func(t *testing.T) { tc := setup(t, false, nil) query1, err := simplejson.NewJson([]byte(` @@ -455,6 +461,9 @@ func TestIntegrationQueryDataMultipleSources(t *testing.T) { } func TestIntegrationQueryDataWithMTDSClient(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } t.Run("can run a simple datasource query with a mt ds client", func(t *testing.T) { stubbedResponse := &backend.QueryDataResponse{Responses: make(backend.Responses)} testClient := &testClient{ diff --git a/pkg/services/secrets/kvstore/migrations/datasource_mig_test.go b/pkg/services/secrets/kvstore/migrations/datasource_mig_test.go index 8c79e91cc6c..a597c7ea23f 100644 --- a/pkg/services/secrets/kvstore/migrations/datasource_mig_test.go +++ b/pkg/services/secrets/kvstore/migrations/datasource_mig_test.go @@ -45,6 +45,9 @@ func SetupTestDataSourceSecretMigrationService(t *testing.T, sqlStore db.DB, kvS } func TestIntegrationMigrate(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } t.Run("should migrate from legacy to unified with compatibility", func(t *testing.T) { sqlStore := db.InitTestDB(t) kvStore := kvstore.ProvideService(sqlStore) diff --git a/pkg/services/secrets/kvstore/sql_test.go b/pkg/services/secrets/kvstore/sql_test.go index ad37b7a9b1c..7da8fe703fc 100644 --- a/pkg/services/secrets/kvstore/sql_test.go +++ b/pkg/services/secrets/kvstore/sql_test.go @@ -31,6 +31,9 @@ func TestMain(m *testing.M) { } func TestIntegrationSecretsKVStoreSQL(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } sqlStore := db.InitTestDB(t) secretsService := manager.SetupTestService(t, fakes.NewFakeSecretsStore()) kv := NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger")) diff --git a/pkg/services/secrets/manager/manager_test.go b/pkg/services/secrets/manager/manager_test.go index 1f37c31cf8c..223e0f6ab4c 100644 --- a/pkg/services/secrets/manager/manager_test.go +++ b/pkg/services/secrets/manager/manager_test.go @@ -30,6 +30,9 @@ func TestMain(m *testing.M) { } func TestIntegrationSecretsService_EnvelopeEncryption(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } testDB := db.InitTestDB(t) store := database.ProvideSecretsStore(testDB) svc := SetupTestService(t, store) @@ -91,6 +94,9 @@ func TestIntegrationSecretsService_EnvelopeEncryption(t *testing.T) { } func TestIntegrationSecretsService_DataKeys(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } testDB := db.InitTestDB(t) store := database.ProvideSecretsStore(testDB) ctx := context.Background() @@ -169,6 +175,9 @@ func TestIntegrationSecretsService_DataKeys(t *testing.T) { } func TestIntegrationSecretsService_UseCurrentProvider(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } t.Run("When encryption_provider is not specified explicitly, should use 'secretKey' as a current provider", func(t *testing.T) { testDB := db.InitTestDB(t) svc := SetupTestService(t, database.ProvideSecretsStore(testDB)) @@ -274,6 +283,9 @@ func (f *fakeKMS) Provide() (map[secrets.ProviderID]secrets.Provider, error) { } func TestIntegrationSecretsService_Run(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } ctx := context.Background() testDB := db.InitTestDB(t) store := database.ProvideSecretsStore(testDB) @@ -324,6 +336,9 @@ func TestIntegrationSecretsService_Run(t *testing.T) { } func TestIntegrationSecretsService_ReEncryptDataKeys(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } ctx := context.Background() testDB := db.InitTestDB(t) store := database.ProvideSecretsStore(testDB) @@ -371,6 +386,9 @@ func TestIntegrationSecretsService_ReEncryptDataKeys(t *testing.T) { } func TestIntegrationSecretsService_Decrypt(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } ctx := context.Background() testDB := db.InitTestDB(t) store := database.ProvideSecretsStore(testDB) diff --git a/pkg/services/serviceaccounts/database/store_test.go b/pkg/services/serviceaccounts/database/store_test.go index 1d8d3c844dd..dde06bbdb70 100644 --- a/pkg/services/serviceaccounts/database/store_test.go +++ b/pkg/services/serviceaccounts/database/store_test.go @@ -51,6 +51,9 @@ func TestIntegrationStore_CreateServiceAccountOrgNonExistant(t *testing.T) { } func TestIntegration_Store_CreateServiceAccount(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } serviceAccountName := "new Service Account" t.Run("create service account", func(t *testing.T) { _, store := setupTestDatabase(t) diff --git a/pkg/services/serviceaccounts/database/token_store_test.go b/pkg/services/serviceaccounts/database/token_store_test.go index 53c4baa2d7f..4f47563c52f 100644 --- a/pkg/services/serviceaccounts/database/token_store_test.go +++ b/pkg/services/serviceaccounts/database/token_store_test.go @@ -12,6 +12,9 @@ import ( ) func TestIntegration_Store_AddServiceAccountToken(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } userToCreate := tests.TestUser{Login: "servicetestwithTeam@admin", IsServiceAccount: true} db, store := setupTestDatabase(t) user := tests.SetupUserServiceAccount(t, db, store.cfg, userToCreate) @@ -74,6 +77,9 @@ func TestIntegration_Store_AddServiceAccountToken(t *testing.T) { } func TestIntegration_Store_AddServiceAccountToken_WrongServiceAccount(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } saToCreate := tests.TestUser{Login: "servicetestwithTeam@admin", IsServiceAccount: true} db, store := setupTestDatabase(t) sa := tests.SetupUserServiceAccount(t, db, store.cfg, saToCreate) @@ -94,6 +100,9 @@ func TestIntegration_Store_AddServiceAccountToken_WrongServiceAccount(t *testing } func TestIntegration_Store_RevokeServiceAccountToken(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } userToCreate := tests.TestUser{Login: "servicetestwithTeam@admin", IsServiceAccount: true} db, store := setupTestDatabase(t) sa := tests.SetupUserServiceAccount(t, db, store.cfg, userToCreate) @@ -134,6 +143,9 @@ func TestIntegration_Store_RevokeServiceAccountToken(t *testing.T) { } func TestIntegration_Store_DeleteServiceAccountToken(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } userToCreate := tests.TestUser{Login: "servicetestwithTeam@admin", IsServiceAccount: true} db, store := setupTestDatabase(t) sa := tests.SetupUserServiceAccount(t, db, store.cfg, userToCreate) diff --git a/pkg/services/serviceaccounts/manager/service_test.go b/pkg/services/serviceaccounts/manager/service_test.go index 2a0b5219c1b..984c4966042 100644 --- a/pkg/services/serviceaccounts/manager/service_test.go +++ b/pkg/services/serviceaccounts/manager/service_test.go @@ -118,6 +118,9 @@ func TestMain(m *testing.M) { } func TestIntegrationProvideServiceAccount_DeleteServiceAccount(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } storeMock := newServiceAccountStoreFake() acSvc := actest.FakeService{} pSvc := &actest.FakePermissionsService{} diff --git a/pkg/services/shorturls/shorturlimpl/shorturl_test.go b/pkg/services/shorturls/shorturlimpl/shorturl_test.go index 4db93f1ad7f..71a26545aa3 100644 --- a/pkg/services/shorturls/shorturlimpl/shorturl_test.go +++ b/pkg/services/shorturls/shorturlimpl/shorturl_test.go @@ -18,6 +18,9 @@ func TestMain(m *testing.M) { } func TestIntegrationShortURLService(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } user := &user.SignedInUser{UserID: 1} store := db.InitTestDB(t) diff --git a/pkg/services/sqlstore/permissions/dashboard_test.go b/pkg/services/sqlstore/permissions/dashboard_test.go index 7dc57810a2a..46474d70df7 100644 --- a/pkg/services/sqlstore/permissions/dashboard_test.go +++ b/pkg/services/sqlstore/permissions/dashboard_test.go @@ -382,6 +382,9 @@ func TestIntegration_DashboardPermissionFilter_WithSelfContainedPermissions(t *t } func TestIntegration_DashboardNestedPermissionFilter(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } testCases := []struct { desc string queryType string @@ -489,6 +492,9 @@ func TestIntegration_DashboardNestedPermissionFilter(t *testing.T) { } func TestIntegration_DashboardNestedPermissionFilter_WithSelfContainedPermissions(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } testCases := []struct { desc string queryType string @@ -601,6 +607,9 @@ func TestIntegration_DashboardNestedPermissionFilter_WithSelfContainedPermission } func TestIntegration_DashboardNestedPermissionFilter_WithActionSets(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } testCases := []struct { desc string queryType string diff --git a/pkg/services/sqlstore/searchstore/filters_test.go b/pkg/services/sqlstore/searchstore/filters_test.go index c13fd7dbc56..8c94b95c5e2 100644 --- a/pkg/services/sqlstore/searchstore/filters_test.go +++ b/pkg/services/sqlstore/searchstore/filters_test.go @@ -8,6 +8,9 @@ import ( ) func TestIntegrationFolderUIDFilter(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } testCases := []struct { description string uids []string diff --git a/pkg/services/sqlstore/searchstore/search_test.go b/pkg/services/sqlstore/searchstore/search_test.go index d365d053a32..935ab7cf2be 100644 --- a/pkg/services/sqlstore/searchstore/search_test.go +++ b/pkg/services/sqlstore/searchstore/search_test.go @@ -32,6 +32,9 @@ func TestMain(m *testing.M) { } func TestIntegrationBuilder_EqualResults_Basic(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } user := &user.SignedInUser{ UserID: 1, OrgID: 1, @@ -76,6 +79,9 @@ func TestIntegrationBuilder_EqualResults_Basic(t *testing.T) { } func TestIntegrationBuilder_Pagination(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } user := &user.SignedInUser{ UserID: 1, OrgID: 1, @@ -123,6 +129,9 @@ func TestIntegrationBuilder_Pagination(t *testing.T) { } func TestIntegrationBuilder_RBAC(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } testsCases := []struct { desc string userPermissions []accesscontrol.Permission diff --git a/pkg/services/sqlstore/session_test.go b/pkg/services/sqlstore/session_test.go index 3986874d48b..a30f11e6d11 100644 --- a/pkg/services/sqlstore/session_test.go +++ b/pkg/services/sqlstore/session_test.go @@ -13,6 +13,9 @@ import ( ) func TestIntegration_RetryingDisabled(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } store, _ := InitTestDB(t) retryErrors := getRetryErrors(t, store) @@ -61,6 +64,9 @@ func TestIntegration_RetryingDisabled(t *testing.T) { } func TestIntegration_RetryingOnFailures(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } store, _ := InitTestDB(t) retryErrors := getRetryErrors(t, store) store.dbCfg.QueryRetries = 5 diff --git a/pkg/services/sqlstore/sqlstore_test.go b/pkg/services/sqlstore/sqlstore_test.go index 4b5af7b194b..113fbc7464e 100644 --- a/pkg/services/sqlstore/sqlstore_test.go +++ b/pkg/services/sqlstore/sqlstore_test.go @@ -24,6 +24,9 @@ func TestMain(m *testing.M) { } func TestIntegrationIsUniqueConstraintViolation(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } store, _ := InitTestDB(t) testCases := []struct { diff --git a/pkg/services/star/starimpl/store_test.go b/pkg/services/star/starimpl/store_test.go index c9ba91a0426..ad65ac82a5e 100644 --- a/pkg/services/star/starimpl/store_test.go +++ b/pkg/services/star/starimpl/store_test.go @@ -149,6 +149,9 @@ func testIntegrationUserStarsDataAccess(t *testing.T, fn getStore) { } func TestIntegration_StarMigrations(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } testDB := db.InitTestDB(t) d := dashboards.Dashboard{ diff --git a/pkg/services/store/service_test.go b/pkg/services/store/service_test.go index 7d9ecaa7884..b0dca4a0c0c 100644 --- a/pkg/services/store/service_test.go +++ b/pkg/services/store/service_test.go @@ -74,6 +74,9 @@ func TestMain(m *testing.M) { } func TestIntegrationListFiles(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } roots := []storageRuntime{publicStaticFilesStorage} store := newStandardStorageService(db.InitTestDB(t), roots, func(orgId int64) []storageRuntime { @@ -95,6 +98,9 @@ func TestIntegrationListFiles(t *testing.T) { } func TestIntegrationListFilesWithoutPermissions(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } roots := []storageRuntime{publicStaticFilesStorage} store := newStandardStorageService(db.InitTestDB(t), roots, func(orgId int64) []storageRuntime { @@ -129,6 +135,9 @@ func setupUploadStore(t *testing.T, authService storageAuthService) (StorageServ } func TestIntegrationShouldUploadWhenNoFileAlreadyExists(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } service, mockStorage, storageName := setupUploadStore(t, nil) fileName := "/myFile.jpg" @@ -148,6 +157,9 @@ func TestIntegrationShouldUploadWhenNoFileAlreadyExists(t *testing.T) { } func TestIntegrationShouldFailUploadWithoutAccess(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } service, _, storageName := setupUploadStore(t, denyAllAuthService) err := service.Upload(context.Background(), dummyUser, &UploadRequest{ @@ -159,6 +171,9 @@ func TestIntegrationShouldFailUploadWithoutAccess(t *testing.T) { } func TestIntegrationShouldFailUploadWhenFileAlreadyExists(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } service, mockStorage, storageName := setupUploadStore(t, nil) mockStorage.On("Get", mock.Anything, "/myFile.jpg", &filestorage.GetFileOptions{WithContents: false}).Return(&filestorage.File{Contents: make([]byte, 0)}, true, nil) @@ -172,6 +187,9 @@ func TestIntegrationShouldFailUploadWhenFileAlreadyExists(t *testing.T) { } func TestIntegrationShouldDelegateFileDeletion(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } service, mockStorage, storageName := setupUploadStore(t, nil) mockStorage.On("Delete", mock.Anything, "/myFile.jpg").Return(nil) @@ -181,6 +199,9 @@ func TestIntegrationShouldDelegateFileDeletion(t *testing.T) { } func TestIntegrationShouldDelegateFolderCreation(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } service, mockStorage, storageName := setupUploadStore(t, nil) mockStorage.On("CreateFolder", mock.Anything, "/nestedFolder/mostNestedFolder").Return(nil) @@ -190,6 +211,9 @@ func TestIntegrationShouldDelegateFolderCreation(t *testing.T) { } func TestIntegrationShouldDelegateFolderDeletion(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } service, mockStorage, storageName := setupUploadStore(t, nil) cmds := []*DeleteFolderCmd{ { @@ -214,6 +238,9 @@ func TestIntegrationShouldDelegateFolderDeletion(t *testing.T) { } func TestIntegrationShouldUploadSvg(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } service, mockStorage, storageName := setupUploadStore(t, nil) fileName := "/myFile.svg" @@ -233,6 +260,9 @@ func TestIntegrationShouldUploadSvg(t *testing.T) { } func TestIntegrationShouldNotUploadHtmlDisguisedAsSvg(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } service, mockStorage, storageName := setupUploadStore(t, nil) fileName := "/myFile.svg" @@ -247,6 +277,9 @@ func TestIntegrationShouldNotUploadHtmlDisguisedAsSvg(t *testing.T) { } func TestIntegrationShouldNotUploadJpgDisguisedAsSvg(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } service, mockStorage, storageName := setupUploadStore(t, nil) fileName := "/myFile.svg" @@ -261,6 +294,9 @@ func TestIntegrationShouldNotUploadJpgDisguisedAsSvg(t *testing.T) { } func TestIntegrationSetupWithNonUniqueStoragePrefixes(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } prefix := "resources" sqlStorage := newSQLStorage(RootStorageMeta{}, prefix, "Testing upload", "dummy descr", &StorageSQLConfig{}, db.InitTestDB(t), 1, false) sqlStorage2 := newSQLStorage(RootStorageMeta{}, prefix, "Testing upload", "dummy descr", &StorageSQLConfig{}, db.InitTestDB(t), 1, false) @@ -277,6 +313,9 @@ func TestIntegrationSetupWithNonUniqueStoragePrefixes(t *testing.T) { } func TestIntegrationContentRootWithNestedStorage(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } globalOrgID := int64(accesscontrol.GlobalOrgID) testDB := db.InitTestDB(t) orgedUser := &user.SignedInUser{OrgID: 1} @@ -523,6 +562,9 @@ func TestIntegrationContentRootWithNestedStorage(t *testing.T) { } func TestIntegrationShadowingExistingFolderByNestedContentRoot(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } db := db.InitTestDB(t) ctx := context.Background() nestedStorage := newSQLStorage(RootStorageMeta{}, "nested", "Testing upload", "dummy descr", &StorageSQLConfig{}, db, accesscontrol.GlobalOrgID, true) diff --git a/pkg/services/user/userimpl/store_test.go b/pkg/services/user/userimpl/store_test.go index 9dcceee9576..bfa19888346 100644 --- a/pkg/services/user/userimpl/store_test.go +++ b/pkg/services/user/userimpl/store_test.go @@ -1063,6 +1063,9 @@ func createFiveTestUsers(t *testing.T, svc user.Service, fn func(i int) *user.Cr } func TestIntegrationMetricsUsage(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } ss, cfg := db.InitTestDBWithCfg(t) userStore := ProvideStore(ss, setting.NewCfg()) quotaService := quotaimpl.ProvideService(ss, cfg) diff --git a/pkg/storage/unified/apistore/watcher_test.go b/pkg/storage/unified/apistore/watcher_test.go index 91a251b04d0..ab4d64a6813 100644 --- a/pkg/storage/unified/apistore/watcher_test.go +++ b/pkg/storage/unified/apistore/watcher_test.go @@ -190,6 +190,9 @@ func testSetup(t testing.TB, opts ...setupOption) (context.Context, storage.Inte } func TestIntegrationWatch(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } for _, s := range []StorageType{StorageTypeFile, StorageTypeUnified} { t.Run(string(s), func(t *testing.T) { ctx, store, destroyFunc, err := testSetup(t, withStorageType(s)) diff --git a/pkg/storage/unified/federated/federatedtests/stats_test.go b/pkg/storage/unified/federated/federatedtests/stats_test.go index 95cba546d30..8bb14ed475b 100644 --- a/pkg/storage/unified/federated/federatedtests/stats_test.go +++ b/pkg/storage/unified/federated/federatedtests/stats_test.go @@ -39,6 +39,9 @@ func TestMain(m *testing.M) { } func TestIntegrationDirectSQLStats(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } db, cfg := db.InitTestDBWithCfg(t) ctx := context.Background() diff --git a/pkg/storage/unified/sql/list_iterator_test.go b/pkg/storage/unified/sql/list_iterator_test.go index b4eacaf0db2..fe57190b0c6 100644 --- a/pkg/storage/unified/sql/list_iterator_test.go +++ b/pkg/storage/unified/sql/list_iterator_test.go @@ -25,6 +25,9 @@ func TestMain(m *testing.M) { testsuite.Run(m) } func TestIntegrationListIter(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } ctx := context.Background() grafanaDB := db.InitTestDB(t) diff --git a/pkg/storage/unified/sql/test/benchmark_test.go b/pkg/storage/unified/sql/test/benchmark_test.go index 88f9ed2c955..4740d7f5858 100644 --- a/pkg/storage/unified/sql/test/benchmark_test.go +++ b/pkg/storage/unified/sql/test/benchmark_test.go @@ -39,6 +39,9 @@ func newTestBackend(b testing.TB) resource.StorageBackend { } func TestIntegrationBenchmarkSQLStorageBackend(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } tests.SkipIntegrationTestInShortMode(t) opts := test.DefaultBenchmarkOptions() if db.IsTestDbSQLite() { @@ -48,6 +51,9 @@ func TestIntegrationBenchmarkSQLStorageBackend(t *testing.T) { } func TestIntegrationBenchmarkResourceServer(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } tests.SkipIntegrationTestInShortMode(t) ctx := context.Background() diff --git a/pkg/storage/unified/sql/test/integration_test.go b/pkg/storage/unified/sql/test/integration_test.go index e33af48713f..7da9798033e 100644 --- a/pkg/storage/unified/sql/test/integration_test.go +++ b/pkg/storage/unified/sql/test/integration_test.go @@ -36,6 +36,9 @@ func TestMain(m *testing.M) { } func TestIntegrationStorageServer(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } unitest.RunStorageServerTest(t, func(ctx context.Context) resource.StorageBackend { dbstore := db.InitTestDB(t) eDB, err := dbimpl.ProvideResourceDB(dbstore, setting.NewCfg(), nil) @@ -56,6 +59,9 @@ func TestIntegrationStorageServer(t *testing.T) { // TestStorageBackend is a test for the StorageBackend interface. func TestIntegrationSQLStorageBackend(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } t.Run("IsHA (polling notifier)", func(t *testing.T) { unitest.RunStorageBackendTest(t, func(ctx context.Context) resource.StorageBackend { dbstore := db.InitTestDB(t) @@ -96,6 +102,9 @@ func TestIntegrationSQLStorageBackend(t *testing.T) { } func TestIntegrationSearchAndStorage(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } tests.SkipIntegrationTestInShortMode(t) ctx := context.Background() diff --git a/pkg/tests/api/admin/encryption/reencrypt_enterprise_test.go b/pkg/tests/api/admin/encryption/reencrypt_enterprise_test.go index 463688ec1c2..e86fbd169c6 100644 --- a/pkg/tests/api/admin/encryption/reencrypt_enterprise_test.go +++ b/pkg/tests/api/admin/encryption/reencrypt_enterprise_test.go @@ -18,6 +18,9 @@ import ( ) func TestIntegration_AdminApiReencrypt_Enterprise(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } getSecretsFunctions := map[string]func(*testing.T, *server.TestEnv) map[int]secret{} getSecretsFunctions["settings"] = func(t *testing.T, env *server.TestEnv) map[int]secret { return getSettingSecrets(t, env.SQLStore) diff --git a/pkg/tests/api/admin/encryption/reencrypt_test.go b/pkg/tests/api/admin/encryption/reencrypt_test.go index 75864a46d28..42c7f0af986 100644 --- a/pkg/tests/api/admin/encryption/reencrypt_test.go +++ b/pkg/tests/api/admin/encryption/reencrypt_test.go @@ -28,6 +28,9 @@ func TestMain(m *testing.M) { } func TestIntegration_AdminApiReencrypt(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } const ( dataSourceTable = "data_source" secretsTable = "secrets" diff --git a/pkg/tests/api/alerting/api_admin_configuration_test.go b/pkg/tests/api/alerting/api_admin_configuration_test.go index eec6c0b451c..3633a83d35f 100644 --- a/pkg/tests/api/alerting/api_admin_configuration_test.go +++ b/pkg/tests/api/alerting/api_admin_configuration_test.go @@ -27,6 +27,9 @@ import ( ) func TestIntegrationAdminConfiguration_SendingToExternalAlertmanagers(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } testinfra.SQLiteIntegrationTest(t) const disableOrgID int64 = 2 diff --git a/pkg/tests/api/alerting/api_alertmanager_silence_test.go b/pkg/tests/api/alerting/api_alertmanager_silence_test.go index 93b2c107682..27bf59f2879 100644 --- a/pkg/tests/api/alerting/api_alertmanager_silence_test.go +++ b/pkg/tests/api/alerting/api_alertmanager_silence_test.go @@ -26,6 +26,9 @@ import ( ) func TestIntegrationSilenceAuth(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } testinfra.SQLiteIntegrationTest(t) dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ diff --git a/pkg/tests/api/alerting/api_alertmanager_test.go b/pkg/tests/api/alerting/api_alertmanager_test.go index a77338c0d75..0adacaf5e45 100644 --- a/pkg/tests/api/alerting/api_alertmanager_test.go +++ b/pkg/tests/api/alerting/api_alertmanager_test.go @@ -25,6 +25,9 @@ import ( ) func TestIntegrationAMConfigAccess(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } testinfra.SQLiteIntegrationTest(t) dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ @@ -354,6 +357,9 @@ func TestIntegrationAMConfigAccess(t *testing.T) { } func TestIntegrationAlertmanagerCreateSilence(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } testinfra.SQLiteIntegrationTest(t) dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ DisableLegacyAlerting: true, @@ -504,9 +510,13 @@ func TestIntegrationAlertmanagerCreateSilence(t *testing.T) { } func TestIntegrationAlertmanagerStatus(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + + // Setup Grafana and its Database + } testinfra.SQLiteIntegrationTest(t) - // Setup Grafana and its Database dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ DisableLegacyAlerting: true, EnableUnifiedAlerting: true, diff --git a/pkg/tests/api/alerting/api_available_channel_test.go b/pkg/tests/api/alerting/api_available_channel_test.go index 1e3eca05c16..a05c2b7b790 100644 --- a/pkg/tests/api/alerting/api_available_channel_test.go +++ b/pkg/tests/api/alerting/api_available_channel_test.go @@ -16,6 +16,9 @@ import ( ) func TestIntegrationAvailableChannels(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } testinfra.SQLiteIntegrationTest(t) dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ diff --git a/pkg/tests/api/alerting/api_convert_prometheus_alertmanager_test.go b/pkg/tests/api/alerting/api_convert_prometheus_alertmanager_test.go index 2c1369ae6a0..11defae0fe3 100644 --- a/pkg/tests/api/alerting/api_convert_prometheus_alertmanager_test.go +++ b/pkg/tests/api/alerting/api_convert_prometheus_alertmanager_test.go @@ -32,9 +32,13 @@ inhibit_rules: ` func TestIntegrationConvertPrometheusAlertmanagerEndpoints(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + + // Setup Grafana with alerting import feature flag enabled + } testinfra.SQLiteIntegrationTest(t) - // Setup Grafana with alerting import feature flag enabled dir, gpath := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ DisableLegacyAlerting: true, EnableUnifiedAlerting: true, @@ -333,6 +337,9 @@ receivers: } func TestIntegrationConvertPrometheusAlertmanagerEndpoints_FeatureFlagDisabled(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } testinfra.SQLiteIntegrationTest(t) dir, gpath := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ diff --git a/pkg/tests/api/alerting/api_convert_prometheus_notification_settings_test.go b/pkg/tests/api/alerting/api_convert_prometheus_notification_settings_test.go index 397afe89537..a3c1904df75 100644 --- a/pkg/tests/api/alerting/api_convert_prometheus_notification_settings_test.go +++ b/pkg/tests/api/alerting/api_convert_prometheus_notification_settings_test.go @@ -20,9 +20,13 @@ const ( ) func TestIntegrationConvertPrometheusNotificationSettings(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + + // Setup Grafana and its Database + } testinfra.SQLiteIntegrationTest(t) - // Setup Grafana and its Database dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ DisableLegacyAlerting: true, EnableUnifiedAlerting: true, diff --git a/pkg/tests/api/alerting/api_convert_prometheus_test.go b/pkg/tests/api/alerting/api_convert_prometheus_test.go index 00fda97c894..1b5ab0145dc 100644 --- a/pkg/tests/api/alerting/api_convert_prometheus_test.go +++ b/pkg/tests/api/alerting/api_convert_prometheus_test.go @@ -106,6 +106,9 @@ var ( ) func TestIntegrationConvertPrometheusEndpoints_RecordingRuleTargetDatasource(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } runTest := func(t *testing.T, enableLokiPaths bool) { testinfra.SQLiteIntegrationTest(t) @@ -172,6 +175,9 @@ func TestIntegrationConvertPrometheusEndpoints_RecordingRuleTargetDatasource(t * } func TestIntegrationConvertPrometheusEndpoints(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } runTest := func(t *testing.T, enableLokiPaths bool, postContentType string) { testinfra.SQLiteIntegrationTest(t) @@ -377,6 +383,9 @@ func TestIntegrationConvertPrometheusEndpoints(t *testing.T) { } func TestIntegrationConvertPrometheusEndpoints_UpdateRule(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } runTest := func(t *testing.T, enableLokiPaths bool) { testinfra.SQLiteIntegrationTest(t) @@ -457,6 +466,9 @@ func TestIntegrationConvertPrometheusEndpoints_UpdateRule(t *testing.T) { } func TestIntegrationConvertPrometheusEndpoints_Conflict(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } runTest := func(t *testing.T, enableLokiPaths bool) { testinfra.SQLiteIntegrationTest(t) @@ -538,6 +550,9 @@ func TestIntegrationConvertPrometheusEndpoints_Conflict(t *testing.T) { } func TestIntegrationConvertPrometheusEndpoints_CreatePausedRules(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } runTest := func(t *testing.T, enableLokiPaths bool) { testinfra.SQLiteIntegrationTest(t) @@ -645,6 +660,9 @@ func TestIntegrationConvertPrometheusEndpoints_CreatePausedRules(t *testing.T) { } func TestIntegrationConvertPrometheusEndpoints_FolderUIDHeader(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } runTest := func(t *testing.T, enableLokiPaths bool) { testinfra.SQLiteIntegrationTest(t) @@ -741,6 +759,9 @@ func TestIntegrationConvertPrometheusEndpoints_FolderUIDHeader(t *testing.T) { } func TestIntegrationConvertPrometheusEndpoints_Provenance(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } runTest := func(t *testing.T, enableLokiPaths bool) { testinfra.SQLiteIntegrationTest(t) @@ -850,6 +871,9 @@ func TestIntegrationConvertPrometheusEndpoints_Provenance(t *testing.T) { } func TestIntegrationConvertPrometheusEndpoints_Delete(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } runTest := func(t *testing.T, enableLokiPaths bool) { testinfra.SQLiteIntegrationTest(t) @@ -1144,6 +1168,9 @@ func TestIntegrationConvertPrometheusEndpoints_Delete(t *testing.T) { } func TestIntegrationConvertPrometheusEndpoints_GroupLabels(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } testinfra.SQLiteIntegrationTest(t) dir, gpath := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ diff --git a/pkg/tests/api/alerting/api_notification_channel_test.go b/pkg/tests/api/alerting/api_notification_channel_test.go index 37d0501c355..d508db1675b 100644 --- a/pkg/tests/api/alerting/api_notification_channel_test.go +++ b/pkg/tests/api/alerting/api_notification_channel_test.go @@ -40,6 +40,9 @@ import ( ) func TestIntegrationTestReceivers(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } testinfra.SQLiteIntegrationTest(t) t.Run("assert no receivers returns 400 Bad Request", func(t *testing.T) { @@ -544,6 +547,9 @@ func TestIntegrationTestReceivers(t *testing.T) { } func TestIntegrationTestReceiversAlertCustomization(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } testinfra.SQLiteIntegrationTest(t) t.Run("assert custom annotations and labels are sent", func(t *testing.T) { @@ -831,6 +837,9 @@ func TestIntegrationTestReceiversAlertCustomization(t *testing.T) { } func TestIntegrationNotificationChannels(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } testinfra.SQLiteIntegrationTest(t) dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ diff --git a/pkg/tests/api/alerting/api_prometheus_test.go b/pkg/tests/api/alerting/api_prometheus_test.go index 3bf3e889ce1..36e2201b3bf 100644 --- a/pkg/tests/api/alerting/api_prometheus_test.go +++ b/pkg/tests/api/alerting/api_prometheus_test.go @@ -31,6 +31,9 @@ import ( var respModel apimodels.UpdateRuleGroupResponse func TestIntegrationPrometheusRules(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } testinfra.SQLiteIntegrationTest(t) dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ @@ -359,6 +362,9 @@ func TestIntegrationPrometheusRules(t *testing.T) { } func TestIntegrationPrometheusRulesFilterByDashboard(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } testinfra.SQLiteIntegrationTest(t) dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ @@ -690,6 +696,9 @@ func TestIntegrationPrometheusRulesFilterByDashboard(t *testing.T) { } func TestIntegrationPrometheusRulesPermissions(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } testinfra.SQLiteIntegrationTest(t) dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ diff --git a/pkg/tests/api/alerting/api_provisioning_test.go b/pkg/tests/api/alerting/api_provisioning_test.go index e3e41d5dc35..08b4e50e204 100644 --- a/pkg/tests/api/alerting/api_provisioning_test.go +++ b/pkg/tests/api/alerting/api_provisioning_test.go @@ -77,6 +77,9 @@ func createRuleWithNotificationSettings(t *testing.T, client apiClient, folder s } func TestIntegrationProvisioning(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } testinfra.SQLiteIntegrationTest(t) dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ @@ -559,6 +562,9 @@ func TestIntegrationProvisioning(t *testing.T) { } func TestIntegrationProvisioningRules(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } testinfra.SQLiteIntegrationTest(t) dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ @@ -980,6 +986,9 @@ func createTestRequest(method string, url string, user string, body string) *htt } func TestIntegrationExportFileProvision(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } dir, p := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ DisableLegacyAlerting: true, EnableUnifiedAlerting: true, @@ -1068,6 +1077,9 @@ func TestIntegrationExportFileProvision(t *testing.T) { } func TestIntegrationExportFileProvisionMixed(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } dir, p := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ DisableLegacyAlerting: true, EnableUnifiedAlerting: true, @@ -1114,6 +1126,9 @@ func TestIntegrationExportFileProvisionMixed(t *testing.T) { } func TestIntegrationExportFileProvisionContactPoints(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } dir, p := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ DisableLegacyAlerting: true, EnableUnifiedAlerting: true, diff --git a/pkg/tests/api/alerting/api_remote_alertmanager_test.go b/pkg/tests/api/alerting/api_remote_alertmanager_test.go index 9a5975a62b7..3a04fbeed18 100644 --- a/pkg/tests/api/alerting/api_remote_alertmanager_test.go +++ b/pkg/tests/api/alerting/api_remote_alertmanager_test.go @@ -18,6 +18,9 @@ import ( // TestIntegrationRemoteAlertmanagerConfigUpload tests that when we post an alertmanager // configuration to Grafana with remote alertmanager enabled, it gets uploaded to the remote Mimir. func TestIntegrationRemoteAlertmanagerConfigUpload(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } testinfra.SQLiteIntegrationTest(t) s, err := alertmanager.NewAlertmanagerScenario() @@ -133,6 +136,9 @@ receivers: // a historical alertmanager configuration with extra configs, it gets properly decrypted // and uploaded to the remote Mimir. func TestIntegrationRemoteAlertmanagerHistoricalConfigActivation(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } testinfra.SQLiteIntegrationTest(t) s, err := alertmanager.NewAlertmanagerScenario() diff --git a/pkg/tests/api/alerting/api_ruler_pause_test.go b/pkg/tests/api/alerting/api_ruler_pause_test.go index 6c20d276b1a..40f5afb99fd 100644 --- a/pkg/tests/api/alerting/api_ruler_pause_test.go +++ b/pkg/tests/api/alerting/api_ruler_pause_test.go @@ -15,9 +15,13 @@ import ( ) func TestIntegrationAlertRulePauseNamespace(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + + // Setup Grafana and its Database + } testinfra.SQLiteIntegrationTest(t) - // Setup Grafana and its Database dir, p := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ DisableLegacyAlerting: true, EnableUnifiedAlerting: true, diff --git a/pkg/tests/api/alerting/api_ruler_test.go b/pkg/tests/api/alerting/api_ruler_test.go index f98b1970fbf..7db2472ca15 100644 --- a/pkg/tests/api/alerting/api_ruler_test.go +++ b/pkg/tests/api/alerting/api_ruler_test.go @@ -45,9 +45,13 @@ import ( var testData embed.FS func TestIntegrationAlertRulePermissions(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + + // Setup Grafana and its Database + } testinfra.SQLiteIntegrationTest(t) - // Setup Grafana and its Database dir, p := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ DisableLegacyAlerting: true, EnableUnifiedAlerting: true, @@ -349,9 +353,13 @@ func TestIntegrationAlertRulePermissions(t *testing.T) { } func TestIntegrationAlertRuleNestedPermissions(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + + // Setup Grafana and its Database + } testinfra.SQLiteIntegrationTest(t) - // Setup Grafana and its Database dir, p := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ EnableFeatureToggles: []string{featuremgmt.FlagNestedFolders}, DisableLegacyAlerting: true, @@ -784,6 +792,9 @@ func TestAlertRulePostExport(t *testing.T) { } func TestIntegrationAlertRuleEditorSettings(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } testinfra.SQLiteIntegrationTest(t) const folderName = "folder1" @@ -956,9 +967,13 @@ func TestIntegrationAlertRuleEditorSettings(t *testing.T) { } func TestIntegrationAlertRuleConflictingTitle(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + + // Setup Grafana and its Database + } testinfra.SQLiteIntegrationTest(t) - // Setup Grafana and its Database dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ DisableLegacyAlerting: true, EnableUnifiedAlerting: true, @@ -1036,6 +1051,9 @@ func TestIntegrationAlertRuleConflictingTitle(t *testing.T) { } func TestIntegrationRulerRulesFilterByDashboard(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } testinfra.SQLiteIntegrationTest(t) dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ @@ -1406,9 +1424,13 @@ func TestIntegrationRulerRulesFilterByDashboard(t *testing.T) { } func TestIntegrationRuleGroupSequence(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + + // Setup Grafana and its Database + } testinfra.SQLiteIntegrationTest(t) - // Setup Grafana and its Database dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ DisableLegacyAlerting: true, EnableUnifiedAlerting: true, @@ -1512,6 +1534,9 @@ func TestIntegrationRuleGroupSequence(t *testing.T) { } func TestIntegrationRuleCreate(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } testinfra.SQLiteIntegrationTest(t) dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ DisableLegacyAlerting: true, @@ -1647,9 +1672,13 @@ func TestIntegrationRuleCreate(t *testing.T) { } func TestIntegrationRuleUpdate(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + + // Setup Grafana and its Database + } testinfra.SQLiteIntegrationTest(t) - // Setup Grafana and its Database dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ DisableLegacyAlerting: true, EnableUnifiedAlerting: true, @@ -1921,6 +1950,9 @@ func TestIntegrationRuleUpdate(t *testing.T) { } func TestIntegrationAlertAndGroupsQuery(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } testinfra.SQLiteIntegrationTest(t) dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ @@ -2080,9 +2112,13 @@ func TestIntegrationAlertAndGroupsQuery(t *testing.T) { } func TestIntegrationRulerAccess(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + + // Setup Grafana and its Database + } testinfra.SQLiteIntegrationTest(t) - // Setup Grafana and its Database dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ DisableLegacyAlerting: true, EnableUnifiedAlerting: true, @@ -2192,9 +2228,13 @@ func TestIntegrationRulerAccess(t *testing.T) { } func TestIntegrationEval(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + + // Setup Grafana and its Database + } testinfra.SQLiteIntegrationTest(t) - // Setup Grafana and its Database dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ DisableLegacyAlerting: true, EnableUnifiedAlerting: true, @@ -2472,9 +2512,13 @@ func TestIntegrationEval(t *testing.T) { } func TestIntegrationQuota(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + + // Setup Grafana and its Database + } testinfra.SQLiteIntegrationTest(t) - // Setup Grafana and its Database dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ DisableLegacyAlerting: true, EnableUnifiedAlerting: true, @@ -2683,6 +2727,9 @@ func TestIntegrationQuota(t *testing.T) { } func TestIntegrationDeleteFolderWithRules(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } testinfra.SQLiteIntegrationTest(t) opts := testinfra.GrafanaOpts{ @@ -2849,9 +2896,13 @@ func TestIntegrationDeleteFolderWithRules(t *testing.T) { } func TestIntegrationAlertRuleCRUD(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + + // Setup Grafana and its Database + } testinfra.SQLiteIntegrationTest(t) - // Setup Grafana and its Database dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ DisableLegacyAlerting: true, EnableUnifiedAlerting: true, @@ -4130,9 +4181,13 @@ func TestIntegrationAlertRuleCRUD(t *testing.T) { } func TestIntegrationRulePause(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + + // Setup Grafana and its Database + } testinfra.SQLiteIntegrationTest(t) - // Setup Grafana and its Database dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ DisableLegacyAlerting: true, EnableUnifiedAlerting: true, @@ -4260,9 +4315,13 @@ func TestIntegrationRulePause(t *testing.T) { } func TestIntegrationHysteresisRule(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + + // Setup Grafana and its Database. Scheduler is set to evaluate every 1 second + } testinfra.SQLiteIntegrationTest(t) - // Setup Grafana and its Database. Scheduler is set to evaluate every 1 second dir, p := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ DisableLegacyAlerting: true, EnableUnifiedAlerting: true, @@ -4334,9 +4393,11 @@ func TestIntegrationHysteresisRule(t *testing.T) { } func TestIntegrationRuleNotificationSettings(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } testinfra.SQLiteIntegrationTest(t) - // Setup Grafana and its Database. Scheduler is set to evaluate every 1 second dir, p := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ DisableLegacyAlerting: true, EnableUnifiedAlerting: true, @@ -4603,7 +4664,10 @@ func TestIntegrationRuleNotificationSettings(t *testing.T) { } func TestIntegrationRuleUpdateAllDatabases(t *testing.T) { - // Setup Grafana and its Database + if testing.Short() { + t.Skip("skipping integration test in short mode") + } + dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ DisableLegacyAlerting: true, EnableUnifiedAlerting: true, @@ -4655,9 +4719,11 @@ func TestIntegrationRuleUpdateAllDatabases(t *testing.T) { } func TestIntegrationRuleVersions(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } testinfra.SQLiteIntegrationTest(t) - // Setup Grafana and its Database dir, p := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ DisableLegacyAlerting: true, EnableUnifiedAlerting: true, @@ -4745,9 +4811,11 @@ func TestIntegrationRuleVersions(t *testing.T) { } func TestIntegrationRuleSoftDelete(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } testinfra.SQLiteIntegrationTest(t) - // Setup Grafana and its Database dir, p := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ DisableLegacyAlerting: true, EnableUnifiedAlerting: true, @@ -4856,9 +4924,11 @@ func TestIntegrationRuleSoftDelete(t *testing.T) { } func TestIntegrationRulePermanentlyDelete(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } testinfra.SQLiteIntegrationTest(t) - // Setup Grafana and its Database dir, p := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ DisableLegacyAlerting: true, EnableUnifiedAlerting: true, diff --git a/pkg/tests/api/stats/admin_test.go b/pkg/tests/api/stats/admin_test.go index 3e264a75e0c..b1b18a7f2b7 100644 --- a/pkg/tests/api/stats/admin_test.go +++ b/pkg/tests/api/stats/admin_test.go @@ -26,6 +26,9 @@ func TestMain(m *testing.M) { } func TestIntegrationAdminStats(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } t.Run("with unified alerting enabled", func(t *testing.T) { url := grafanaSetup(t, testinfra.GrafanaOpts{ DisableLegacyAlerting: true, diff --git a/pkg/tests/apis/dashboard/dashboards_test.go b/pkg/tests/apis/dashboard/dashboards_test.go index 7e8c36c003a..c20d235eea9 100644 --- a/pkg/tests/apis/dashboard/dashboards_test.go +++ b/pkg/tests/apis/dashboard/dashboards_test.go @@ -218,6 +218,9 @@ func TestIntegrationDashboardsAppV2alpha2(t *testing.T) { } func TestIntegrationLegacySupport(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } ctx := context.Background() helper := apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{ EnableFeatureToggles: []string{ diff --git a/pkg/tests/apis/dashboard/integration/library_panels_api_validation_test.go b/pkg/tests/apis/dashboard/integration/library_panels_api_validation_test.go index 23a0650ebdb..c9d74b964df 100644 --- a/pkg/tests/apis/dashboard/integration/library_panels_api_validation_test.go +++ b/pkg/tests/apis/dashboard/integration/library_panels_api_validation_test.go @@ -21,6 +21,9 @@ import ( // // it also ensures we create the connection in modes 0-2 if a dashboard v1 is created with a reference func TestIntegrationLibraryPanelConnections(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } dualWriterModes := []rest.DualWriterMode{rest.Mode0, rest.Mode1, rest.Mode2, rest.Mode3, rest.Mode4, rest.Mode5} for _, dualWriterMode := range dualWriterModes { t.Run(fmt.Sprintf("DualWriterMode %d", dualWriterMode), func(t *testing.T) { @@ -84,6 +87,9 @@ func TestIntegrationLibraryPanelConnections(t *testing.T) { // this tests the /apis path to ensure authorization is being enforced. /api integration tests are within the service package // only works in modes 0-2 because the library element is created through the /api path func TestIntegrationLibraryElementPermissions(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } dualWriterModes := []rest.DualWriterMode{rest.Mode0, rest.Mode1, rest.Mode2} for _, dualWriterMode := range dualWriterModes { t.Run(fmt.Sprintf("DualWriterMode %d", dualWriterMode), func(t *testing.T) { diff --git a/pkg/tests/apis/provisioning/secrets_test.go b/pkg/tests/apis/provisioning/secrets_test.go index 6f1e152eca0..a85b8a56f62 100644 --- a/pkg/tests/apis/provisioning/secrets_test.go +++ b/pkg/tests/apis/provisioning/secrets_test.go @@ -286,6 +286,9 @@ func TestIntegrationProvisioning_Secrets(t *testing.T) { } func TestIntegrationProvisioning_Secrets_Update(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } ctx := context.Background() helper := runGrafana(t, useAppPlatformSecrets) secretsService := helper.GetEnv().RepositorySecrets diff --git a/pkg/tsdb/grafana-postgresql-datasource/postgres_snapshot_test.go b/pkg/tsdb/grafana-postgresql-datasource/postgres_snapshot_test.go index e0d9e307ae0..c8d248a4c8b 100644 --- a/pkg/tsdb/grafana-postgresql-datasource/postgres_snapshot_test.go +++ b/pkg/tsdb/grafana-postgresql-datasource/postgres_snapshot_test.go @@ -31,6 +31,10 @@ var updateGoldenFiles = false // preconfigured Postgres server suitable for running these tests. func TestIntegrationPostgresSnapshots(t *testing.T) { // the logic in this function is copied from postgres_tests.go + if testing.Short() { + t.Skip("skipping integration test in short mode") + } + shouldRunTest := func() bool { if testing.Short() { return false diff --git a/pkg/tsdb/influxdb/fsql/fsql_test.go b/pkg/tsdb/influxdb/fsql/fsql_test.go index 4f5dadbbd02..ed7b722a6b2 100644 --- a/pkg/tsdb/influxdb/fsql/fsql_test.go +++ b/pkg/tsdb/influxdb/fsql/fsql_test.go @@ -56,6 +56,9 @@ func (suite *FSQLTestSuite) AfterTest(suiteName, testName string) { } func TestFSQLTestSuite(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode") + } suite.Run(t, new(FSQLTestSuite)) } diff --git a/pkg/tsdb/mysql/mysql_snapshot_test.go b/pkg/tsdb/mysql/mysql_snapshot_test.go index c251fc23c42..ca68abbef12 100644 --- a/pkg/tsdb/mysql/mysql_snapshot_test.go +++ b/pkg/tsdb/mysql/mysql_snapshot_test.go @@ -33,6 +33,10 @@ var updateGoldenFiles = false // preconfigured MySQL server suitable for running these tests. func TestIntegrationMySQLSnapshots(t *testing.T) { // the logic in this function is copied from mysql_tests.go + if testing.Short() { + t.Skip("skipping integration test in short mode") + } + shouldRunTest := func() bool { if testing.Short() { return false From 227799a9f86e3b6bec9ed51bae76e76be04f7bb6 Mon Sep 17 00:00:00 2001 From: Matheus Macabu Date: Mon, 28 Jul 2025 14:25:06 +0200 Subject: [PATCH 043/131] Secrets: Add missing indices for secure value (list) and data key (list+read) (#108763) --- pkg/storage/secret/migrator/migrator.go | 30 ++++++++++++++++--------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/pkg/storage/secret/migrator/migrator.go b/pkg/storage/secret/migrator/migrator.go index ee2a5a1c975..0b7790a875f 100644 --- a/pkg/storage/secret/migrator/migrator.go +++ b/pkg/storage/secret/migrator/migrator.go @@ -45,7 +45,7 @@ func (*SecretDB) AddMigration(mg *migrator.Migrator) { tables := []migrator.Table{} - tables = append(tables, migrator.Table{ + secureValueTable := migrator.Table{ Name: TableNameSecureValue, Columns: []*migrator.Column{ // Kubernetes Metadata @@ -74,7 +74,8 @@ func (*SecretDB) AddMigration(mg *migrator.Migrator) { {Cols: []string{"namespace", "name", "version", "active"}, Type: migrator.UniqueIndex}, {Cols: []string{"namespace", "name", "version"}, Type: migrator.UniqueIndex}, }, - }) + } + tables = append(tables, secureValueTable) tables = append(tables, migrator.Table{ Name: TableNameKeeper, @@ -101,22 +102,21 @@ func (*SecretDB) AddMigration(mg *migrator.Migrator) { }, }) - // TODO -- document how the seemingly arbitrary column lengths were chosen - // The answer for now is that they come from the legacy secrets service, but it would be good to know that they will still work in the new service - tables = append(tables, migrator.Table{ + dataKeyTable := migrator.Table{ Name: TableNameDataKey, Columns: []*migrator.Column{ - {Name: "uid", Type: migrator.DB_NVarchar, Length: 100, IsPrimaryKey: true}, + {Name: "uid", Type: migrator.DB_NVarchar, Length: 100, IsPrimaryKey: true}, // Arbitrarily chosen. {Name: "namespace", Type: migrator.DB_NVarchar, Length: 253, Nullable: false}, // Limit enforced by K8s. - {Name: "label", Type: migrator.DB_NVarchar, Length: 100, IsPrimaryKey: false}, + {Name: "label", Type: migrator.DB_NVarchar, Length: 100, IsPrimaryKey: false}, // Arbitrarily chosen. {Name: "active", Type: migrator.DB_Bool, Nullable: false}, - {Name: "provider", Type: migrator.DB_NVarchar, Length: 50, Nullable: false}, + {Name: "provider", Type: migrator.DB_NVarchar, Length: 50, Nullable: false}, // Arbitrarily chosen. {Name: "encrypted_data", Type: migrator.DB_Blob, Nullable: false}, {Name: "created", Type: migrator.DB_DateTime, Nullable: false}, {Name: "updated", Type: migrator.DB_DateTime, Nullable: false}, }, - Indices: []*migrator.Index{}, // TODO: add indexes based on the queries we make. - }) + Indices: []*migrator.Index{}, + } + tables = append(tables, dataKeyTable) encryptedValueTable := migrator.Table{ Name: TableNameEncryptedValue, @@ -142,4 +142,14 @@ func (*SecretDB) AddMigration(mg *migrator.Migrator) { mg.AddMigration(fmt.Sprintf("create table %s, index: %d", tables[t].Name, i), migrator.NewAddIndexMigration(tables[t], tables[t].Indices[i])) } } + + mg.AddMigration("create index for list on "+TableNameSecureValue, migrator.NewAddIndexMigration(secureValueTable, &migrator.Index{ + Cols: []string{"namespace", "active", "updated"}, + Type: migrator.IndexType, + })) + + mg.AddMigration("create index for list and read current on "+TableNameDataKey, migrator.NewAddIndexMigration(dataKeyTable, &migrator.Index{ + Cols: []string{"namespace", "label", "active"}, + Type: migrator.IndexType, + })) } From 90de360424af3b557fd2c6e2978206ac3bd62fce Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 28 Jul 2025 13:29:00 +0100 Subject: [PATCH 044/131] Update dependency jsdom-testing-mocks to v1.14.0 (#108760) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 4486bdfc0b8..1b13a8fb3de 100644 --- a/yarn.lock +++ b/yarn.lock @@ -21233,12 +21233,12 @@ __metadata: linkType: hard "jsdom-testing-mocks@npm:^1.13.1": - version: 1.13.1 - resolution: "jsdom-testing-mocks@npm:1.13.1" + version: 1.14.0 + resolution: "jsdom-testing-mocks@npm:1.14.0" dependencies: bezier-easing: "npm:^2.1.0" css-mediaquery: "npm:^0.1.2" - checksum: 10/434acae65fc89f4d8e0e2dc23b830ebaf4568483d5127da60bf825c8357c489955105b98a5d95ed5c4e1ed48f2fa5369b138f141d55b290cd656008493ac6a65 + checksum: 10/b7f89f4687345f437f9e022cacc9ed577e58c825b4283b61dd46ab61f9612d8a715b6acc12aa91bcd3f6c97455dfe61eeae86ce4694832469f3ad95d179bd671 languageName: node linkType: hard From 0c1cd7fa589fe770ebc347ec813ea3d20e82a7d6 Mon Sep 17 00:00:00 2001 From: Todd Treece <360020+toddtreece@users.noreply.github.com> Date: Mon, 28 Jul 2025 08:34:09 -0400 Subject: [PATCH 045/131] Apps: Update grafana-app-sdk to v0.40.1 (#108786) --- apps/advisor/go.mod | 26 ++++++------- apps/advisor/go.sum | 60 +++++++++++++++--------------- apps/alerting/notifications/go.mod | 20 +++++----- apps/alerting/notifications/go.sum | 48 ++++++++++++------------ apps/dashboard/go.mod | 20 +++++----- apps/dashboard/go.sum | 44 +++++++++++----------- apps/folder/go.mod | 14 +++---- apps/folder/go.sum | 32 ++++++++-------- apps/iam/go.mod | 14 +++---- apps/iam/go.sum | 32 ++++++++-------- apps/investigations/go.mod | 26 ++++++------- apps/investigations/go.sum | 52 +++++++++++++------------- apps/playlist/go.mod | 20 +++++----- apps/playlist/go.sum | 44 +++++++++++----------- apps/sdk.mk | 4 +- apps/secret/go.mod | 16 ++++---- apps/secret/go.sum | 36 +++++++++--------- go.mod | 30 +++++++-------- go.sum | 59 ++++++++++++++--------------- go.work.sum | 50 +++++++++++++++++++++++++ pkg/aggregator/go.mod | 22 +++++------ pkg/aggregator/go.sum | 43 ++++++++++----------- pkg/apimachinery/go.mod | 14 +++---- pkg/apimachinery/go.sum | 28 +++++++------- pkg/apiserver/go.mod | 20 +++++----- pkg/apiserver/go.sum | 40 ++++++++++---------- pkg/build/go.mod | 14 +++---- pkg/build/go.sum | 28 +++++++------- pkg/build/wire/go.mod | 4 +- pkg/build/wire/go.sum | 8 ++-- pkg/codegen/go.mod | 12 +++--- pkg/codegen/go.sum | 24 ++++++------ pkg/plugins/codegen/go.mod | 10 ++--- pkg/plugins/codegen/go.sum | 24 ++++++------ pkg/promlib/go.mod | 16 ++++---- pkg/promlib/go.sum | 36 +++++++++--------- 36 files changed, 521 insertions(+), 469 deletions(-) diff --git a/apps/advisor/go.mod b/apps/advisor/go.mod index 853c9850196..9379b0af3e3 100644 --- a/apps/advisor/go.mod +++ b/apps/advisor/go.mod @@ -7,8 +7,8 @@ require ( github.com/google/go-github/v70 v70.0.0 github.com/grafana/authlib/types v0.0.0-20250710201142-9542f2f28d43 github.com/grafana/grafana v0.0.0-00010101000000-000000000000 - github.com/grafana/grafana-app-sdk v0.40.0 - github.com/grafana/grafana-app-sdk/logging v0.39.3 + github.com/grafana/grafana-app-sdk v0.40.1 + github.com/grafana/grafana-app-sdk/logging v0.40.0 github.com/grafana/grafana-plugin-sdk-go v0.278.0 github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250725144121-b1592b5e36d2 github.com/stretchr/testify v1.10.0 @@ -217,7 +217,7 @@ require ( github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/spf13/cast v1.7.1 // indirect - github.com/spf13/pflag v1.0.6 // indirect + github.com/spf13/pflag v1.0.7 // indirect github.com/stretchr/objx v0.5.2 // indirect github.com/tetratelabs/wazero v1.8.2 // indirect github.com/tjhop/slog-gokit v0.1.3 // indirect @@ -245,23 +245,23 @@ require ( go.opentelemetry.io/proto/otlp v1.7.0 // indirect go.uber.org/atomic v1.11.0 // indirect go.yaml.in/yaml/v2 v2.4.2 // indirect - golang.org/x/crypto v0.39.0 // indirect + golang.org/x/crypto v0.40.0 // indirect golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 // indirect - golang.org/x/mod v0.25.0 // indirect - golang.org/x/net v0.41.0 // indirect + golang.org/x/mod v0.26.0 // indirect + golang.org/x/net v0.42.0 // indirect golang.org/x/oauth2 v0.30.0 // indirect golang.org/x/sync v0.16.0 // indirect - golang.org/x/sys v0.33.0 // indirect - golang.org/x/term v0.32.0 // indirect - golang.org/x/text v0.26.0 // indirect + golang.org/x/sys v0.34.0 // indirect + golang.org/x/term v0.33.0 // indirect + golang.org/x/text v0.27.0 // indirect golang.org/x/time v0.11.0 // indirect - golang.org/x/tools v0.34.0 // indirect + golang.org/x/tools v0.35.0 // indirect golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect gonum.org/v1/gonum v0.16.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect - google.golang.org/grpc v1.73.0 // indirect + google.golang.org/grpc v1.74.0 // indirect google.golang.org/protobuf v1.36.6 // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/fsnotify/fsnotify.v1 v1.4.7 // indirect @@ -273,14 +273,14 @@ require ( gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/api v0.33.3 // indirect - k8s.io/apiextensions-apiserver v0.33.2 // indirect + k8s.io/apiextensions-apiserver v0.33.3 // indirect k8s.io/client-go v0.33.3 // indirect k8s.io/component-base v0.33.3 // indirect k8s.io/klog/v2 v2.130.1 // indirect k8s.io/utils v0.0.0-20241210054802-24370beab758 // indirect sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect sigs.k8s.io/randfill v1.0.0 // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.7.0 // indirect sigs.k8s.io/yaml v1.5.0 // indirect xorm.io/builder v0.3.6 // indirect ) diff --git a/apps/advisor/go.sum b/apps/advisor/go.sum index 2613bb8c90c..778e8e0f26b 100644 --- a/apps/advisor/go.sum +++ b/apps/advisor/go.sum @@ -1,5 +1,5 @@ -cel.dev/expr v0.23.1 h1:K4KOtPCJQjVggkARsjG9RWXP6O4R73aHeJMa/dmCQQg= -cel.dev/expr v0.23.1/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw= +cel.dev/expr v0.24.0 h1:56OvJKSH3hDGL0ml5uSxZmz3/3Pq4tJ+fb1unVLAFcY= +cel.dev/expr v0.24.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw= @@ -309,8 +309,8 @@ github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20250326154945-ae57f3c0d45f h1:C5bqEmzEPLsHm9Mv73lSE9e9bKV23aB1vxOsmZrkl3k= -github.com/cncf/xds/go v0.0.0-20250326154945-ae57f3c0d45f/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= +github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443 h1:aQ3y1lwWyqYPiWZThqv1aFbZMiM9vblcSArJRf2Irls= +github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/cockroachdb/apd/v3 v3.2.1 h1:U+8j7t0axsIgvQUqthuNm82HIrYXodOV2iWLWtEaIwg= @@ -657,10 +657,10 @@ github.com/grafana/dataplane/sdata v0.0.9 h1:AGL1LZnCUG4MnQtnWpBPbQ8ZpptaZs14w6k github.com/grafana/dataplane/sdata v0.0.9/go.mod h1:Jvs5ddpGmn6vcxT7tCTWAZ1mgi4sbcdFt9utQx5uMAU= github.com/grafana/dskit v0.0.0-20250611075409-46f51e1ce914 h1:qcSGhr691f1mmPHwg2svGyO40Ex92G02aOyHzP6XHCE= github.com/grafana/dskit v0.0.0-20250611075409-46f51e1ce914/go.mod h1:OiN4P4aC6LwLzLbEupH3Ue83VfQoNMfG48rsna8jI/E= -github.com/grafana/grafana-app-sdk v0.40.0 h1:KilbCFMYox2cnIi1W6ql7W+n9kms/NvWlBPM1m4Q4mg= -github.com/grafana/grafana-app-sdk v0.40.0/go.mod h1:fn943JEM0CR3mY/Gd3816MUcpob5xnKc8MoojnbMjYY= -github.com/grafana/grafana-app-sdk/logging v0.39.3 h1:mMrcYahnoRu7blKyL/ZVcgv7WCiI2CqxODYh8tBFUgY= -github.com/grafana/grafana-app-sdk/logging v0.39.3/go.mod h1:otUD9XpJD7A5sCLb8mcs9hIXGdeV6lnhzVwe747g4RU= +github.com/grafana/grafana-app-sdk v0.40.1 h1:W8d1CQSgMg/d37xf/0t4PiSa7wVD21XFE8mF6P59YSg= +github.com/grafana/grafana-app-sdk v0.40.1/go.mod h1:4P8h7VB6KcDjX9bAoBQc6IP8iNylxe6bSXLR9gA39gM= +github.com/grafana/grafana-app-sdk/logging v0.40.0 h1:3LHA0pFM9mGGFyq6qoHvJOGEe0H0OVhzzlOKd4Ehu+E= +github.com/grafana/grafana-app-sdk/logging v0.40.0/go.mod h1:otUD9XpJD7A5sCLb8mcs9hIXGdeV6lnhzVwe747g4RU= github.com/grafana/grafana-aws-sdk v1.0.4 h1:D14UAehsOqpjliHmHzveRQ1p43KCsMzdmb7GovWj+SY= github.com/grafana/grafana-aws-sdk v1.0.4/go.mod h1:hO7q7yWV+t6dmiyJjMa3IbuYnYkBua+G/IAlOPVIYKE= github.com/grafana/grafana-azure-sdk-go/v2 v2.1.6 h1:OfCkitCuomzZKW1WYHrG8MxKwtMhALb7jqoj+487eTg= @@ -1093,8 +1093,8 @@ github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= -github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.7 h1:vN6T9TfwStFPFM5XzjsvmzZkLuaLX+HS+0SeFLRgU6M= +github.com/spf13/pflag v1.0.7/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.13.0/go.mod h1:Icm2xNL3/8uyh/wFuB1jI7TiTNKp8632Nwegu+zgdYw= github.com/spiffe/go-spiffe/v2 v2.5.0 h1:N2I01KCUkv1FAjZXJMwh95KK1ZIQLYbPfhaxw8WS0hE= github.com/spiffe/go-spiffe/v2 v2.5.0/go.mod h1:P+NxobPc6wXhVtINNtFjNWGBTreew1GBUCwT2wPmb7g= @@ -1289,8 +1289,8 @@ golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0 golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= -golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= -golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= +golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM= +golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1333,8 +1333,8 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91 golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w= -golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= +golang.org/x/mod v0.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg= +golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1394,8 +1394,8 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= -golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= -golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= +golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= +golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1534,8 +1534,8 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= -golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= +golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= @@ -1543,8 +1543,8 @@ golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= -golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg= -golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= +golang.org/x/term v0.33.0 h1:NuFncQrRcaRvVmgRkvM3j/F00gWIAlcmlB8ACEKmGIg= +golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1558,8 +1558,8 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= -golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= +golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= +golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1628,8 +1628,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= -golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo= -golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg= +golang.org/x/tools v0.35.0 h1:mBffYraMEf7aa0sB+NuKnuCy8qI/9Bughn8dC2Gu5r0= +golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1809,8 +1809,8 @@ google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ5 google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok= -google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc= +google.golang.org/grpc v1.74.0 h1:sxRSkyLxlceWQiqDofxDot3d4u7DyoHPc7SBXMj8gGY= +google.golang.org/grpc v1.74.0/go.mod h1:NZUaK8dAMUfzhK6uxZ+9511LtOrk73UGWOFoNvz7z+s= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= @@ -1880,8 +1880,8 @@ honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9 honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= k8s.io/api v0.33.3 h1:SRd5t//hhkI1buzxb288fy2xvjubstenEKL9K51KBI8= k8s.io/api v0.33.3/go.mod h1:01Y/iLUjNBM3TAvypct7DIj0M0NIZc+PzAHCIo0CYGE= -k8s.io/apiextensions-apiserver v0.33.2 h1:6gnkIbngnaUflR3XwE1mCefN3YS8yTD631JXQhsU6M8= -k8s.io/apiextensions-apiserver v0.33.2/go.mod h1:IvVanieYsEHJImTKXGP6XCOjTwv2LUMos0YWc9O+QP8= +k8s.io/apiextensions-apiserver v0.33.3 h1:qmOcAHN6DjfD0v9kxL5udB27SRP6SG/MTopmge3MwEs= +k8s.io/apiextensions-apiserver v0.33.3/go.mod h1:oROuctgo27mUsyp9+Obahos6CWcMISSAPzQ77CAQGz8= k8s.io/apimachinery v0.33.3 h1:4ZSrmNa0c/ZpZJhAgRdcsFcZOw1PQU1bALVQ0B3I5LA= k8s.io/apimachinery v0.33.3/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM= k8s.io/apiserver v0.33.3 h1:Wv0hGc+QFdMJB4ZSiHrCgN3zL3QRatu56+rpccKC3J4= @@ -1908,8 +1908,8 @@ sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= -sigs.k8s.io/structured-merge-diff/v4 v4.6.0 h1:IUA9nvMmnKWcj5jl84xn+T5MnlZKThmUW1TdblaLVAc= -sigs.k8s.io/structured-merge-diff/v4 v4.6.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps= +sigs.k8s.io/structured-merge-diff/v4 v4.7.0 h1:qPeWmscJcXP0snki5IYF79Z8xrl8ETFxgMd7wez1XkI= +sigs.k8s.io/structured-merge-diff/v4 v4.7.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= sigs.k8s.io/yaml v1.5.0 h1:M10b2U7aEUY6hRtU870n2VTPgR5RZiL/I6Lcc2F4NUQ= diff --git a/apps/alerting/notifications/go.mod b/apps/alerting/notifications/go.mod index b885b4d1eb4..ac5f43ee6bd 100644 --- a/apps/alerting/notifications/go.mod +++ b/apps/alerting/notifications/go.mod @@ -3,8 +3,8 @@ module github.com/grafana/grafana/apps/alerting/notifications go 1.24.5 require ( - github.com/grafana/grafana-app-sdk v0.40.0 - github.com/grafana/grafana-app-sdk/logging v0.39.3 + github.com/grafana/grafana-app-sdk v0.40.1 + github.com/grafana/grafana-app-sdk/logging v0.40.0 k8s.io/apimachinery v0.33.3 k8s.io/apiserver v0.33.3 k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff @@ -62,7 +62,7 @@ require ( github.com/prometheus/procfs v0.16.1 // indirect github.com/puzpuzpuz/xsync/v2 v2.5.1 // indirect github.com/rogpeppe/go-internal v1.14.1 // indirect - github.com/spf13/pflag v1.0.6 // indirect + github.com/spf13/pflag v1.0.7 // indirect github.com/x448/float16 v0.8.4 // indirect go.etcd.io/bbolt v1.4.0 // indirect go.etcd.io/etcd/api/v3 v3.5.21 // indirect @@ -82,24 +82,24 @@ require ( go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect go.yaml.in/yaml/v2 v2.4.2 // indirect - golang.org/x/net v0.41.0 // indirect + golang.org/x/net v0.42.0 // indirect golang.org/x/oauth2 v0.30.0 // indirect golang.org/x/sync v0.16.0 // indirect - golang.org/x/sys v0.33.0 // indirect - golang.org/x/term v0.32.0 // indirect - golang.org/x/text v0.26.0 // indirect + golang.org/x/sys v0.34.0 // indirect + golang.org/x/term v0.33.0 // indirect + golang.org/x/text v0.27.0 // indirect golang.org/x/time v0.11.0 // indirect gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect google.golang.org/genproto v0.0.0-20250603155806-513f23925822 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect - google.golang.org/grpc v1.73.0 // indirect + google.golang.org/grpc v1.74.0 // indirect google.golang.org/protobuf v1.36.6 // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/api v0.33.3 // indirect - k8s.io/apiextensions-apiserver v0.33.2 // indirect + k8s.io/apiextensions-apiserver v0.33.3 // indirect k8s.io/client-go v0.33.3 // indirect k8s.io/component-base v0.33.3 // indirect k8s.io/klog/v2 v2.130.1 // indirect @@ -107,6 +107,6 @@ require ( sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 // indirect sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect sigs.k8s.io/randfill v1.0.0 // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.7.0 // indirect sigs.k8s.io/yaml v1.5.0 // indirect ) diff --git a/apps/alerting/notifications/go.sum b/apps/alerting/notifications/go.sum index c5caf4fb4e0..8f46c0338ee 100644 --- a/apps/alerting/notifications/go.sum +++ b/apps/alerting/notifications/go.sum @@ -84,10 +84,10 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo= github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA= -github.com/grafana/grafana-app-sdk v0.40.0 h1:KilbCFMYox2cnIi1W6ql7W+n9kms/NvWlBPM1m4Q4mg= -github.com/grafana/grafana-app-sdk v0.40.0/go.mod h1:fn943JEM0CR3mY/Gd3816MUcpob5xnKc8MoojnbMjYY= -github.com/grafana/grafana-app-sdk/logging v0.39.3 h1:mMrcYahnoRu7blKyL/ZVcgv7WCiI2CqxODYh8tBFUgY= -github.com/grafana/grafana-app-sdk/logging v0.39.3/go.mod h1:otUD9XpJD7A5sCLb8mcs9hIXGdeV6lnhzVwe747g4RU= +github.com/grafana/grafana-app-sdk v0.40.1 h1:W8d1CQSgMg/d37xf/0t4PiSa7wVD21XFE8mF6P59YSg= +github.com/grafana/grafana-app-sdk v0.40.1/go.mod h1:4P8h7VB6KcDjX9bAoBQc6IP8iNylxe6bSXLR9gA39gM= +github.com/grafana/grafana-app-sdk/logging v0.40.0 h1:3LHA0pFM9mGGFyq6qoHvJOGEe0H0OVhzzlOKd4Ehu+E= +github.com/grafana/grafana-app-sdk/logging v0.40.0/go.mod h1:otUD9XpJD7A5sCLb8mcs9hIXGdeV6lnhzVwe747g4RU= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20191002090509-6af20e3a5340 h1:uGoIog/wiQHI9GAxXO5TJbT0wWKH3O9HhOJW1F9c3fY= @@ -173,8 +173,8 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js= github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= -github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= -github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.7 h1:vN6T9TfwStFPFM5XzjsvmzZkLuaLX+HS+0SeFLRgU6M= +github.com/spf13/pflag v1.0.7/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= @@ -252,8 +252,8 @@ go.yaml.in/yaml/v3 v3.0.3/go.mod h1:tBHosrYAkRZjRAOREWbDnBXUf08JOwYq++0QNwQiWzI= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= -golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= +golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM= +golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= @@ -270,8 +270,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= -golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= +golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= +golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= @@ -288,14 +288,14 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= -golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg= -golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= +golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= +golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/term v0.33.0 h1:NuFncQrRcaRvVmgRkvM3j/F00gWIAlcmlB8ACEKmGIg= +golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= -golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= +golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= +golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0= golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -308,8 +308,8 @@ golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo= -golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg= +golang.org/x/tools v0.35.0 h1:mBffYraMEf7aa0sB+NuKnuCy8qI/9Bughn8dC2Gu5r0= +golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -333,8 +333,8 @@ google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyac google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok= -google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc= +google.golang.org/grpc v1.74.0 h1:sxRSkyLxlceWQiqDofxDot3d4u7DyoHPc7SBXMj8gGY= +google.golang.org/grpc v1.74.0/go.mod h1:NZUaK8dAMUfzhK6uxZ+9511LtOrk73UGWOFoNvz7z+s= google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -358,8 +358,8 @@ honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= k8s.io/api v0.33.3 h1:SRd5t//hhkI1buzxb288fy2xvjubstenEKL9K51KBI8= k8s.io/api v0.33.3/go.mod h1:01Y/iLUjNBM3TAvypct7DIj0M0NIZc+PzAHCIo0CYGE= -k8s.io/apiextensions-apiserver v0.33.2 h1:6gnkIbngnaUflR3XwE1mCefN3YS8yTD631JXQhsU6M8= -k8s.io/apiextensions-apiserver v0.33.2/go.mod h1:IvVanieYsEHJImTKXGP6XCOjTwv2LUMos0YWc9O+QP8= +k8s.io/apiextensions-apiserver v0.33.3 h1:qmOcAHN6DjfD0v9kxL5udB27SRP6SG/MTopmge3MwEs= +k8s.io/apiextensions-apiserver v0.33.3/go.mod h1:oROuctgo27mUsyp9+Obahos6CWcMISSAPzQ77CAQGz8= k8s.io/apimachinery v0.33.3 h1:4ZSrmNa0c/ZpZJhAgRdcsFcZOw1PQU1bALVQ0B3I5LA= k8s.io/apimachinery v0.33.3/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM= k8s.io/apiserver v0.33.3 h1:Wv0hGc+QFdMJB4ZSiHrCgN3zL3QRatu56+rpccKC3J4= @@ -381,8 +381,8 @@ sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= -sigs.k8s.io/structured-merge-diff/v4 v4.6.0 h1:IUA9nvMmnKWcj5jl84xn+T5MnlZKThmUW1TdblaLVAc= -sigs.k8s.io/structured-merge-diff/v4 v4.6.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps= +sigs.k8s.io/structured-merge-diff/v4 v4.7.0 h1:qPeWmscJcXP0snki5IYF79Z8xrl8ETFxgMd7wez1XkI= +sigs.k8s.io/structured-merge-diff/v4 v4.7.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps= sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= sigs.k8s.io/yaml v1.5.0 h1:M10b2U7aEUY6hRtU870n2VTPgR5RZiL/I6Lcc2F4NUQ= sigs.k8s.io/yaml v1.5.0/go.mod h1:wZs27Rbxoai4C0f8/9urLZtZtF3avA3gKvGyPdDqTO4= diff --git a/apps/dashboard/go.mod b/apps/dashboard/go.mod index dc97db7ddc0..423dfbc0986 100644 --- a/apps/dashboard/go.mod +++ b/apps/dashboard/go.mod @@ -4,7 +4,7 @@ go 1.24.5 require ( cuelang.org/go v0.11.1 - github.com/grafana/grafana-app-sdk v0.40.0 + github.com/grafana/grafana-app-sdk v0.40.1 github.com/grafana/grafana-plugin-sdk-go v0.278.0 github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250514132646-acbc7b54ed9e github.com/stretchr/testify v1.10.0 @@ -44,7 +44,7 @@ require ( github.com/google/go-cmp v0.7.0 // indirect github.com/google/uuid v1.6.0 // indirect github.com/gorilla/mux v1.8.1 // indirect - github.com/grafana/grafana-app-sdk/logging v0.39.3 // indirect + github.com/grafana/grafana-app-sdk/logging v0.40.0 // indirect github.com/grafana/otel-profiling-go v0.5.1 // indirect github.com/grafana/pyroscope-go/godeltaprof v0.1.8 // indirect github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0 // indirect @@ -110,19 +110,19 @@ require ( go.opentelemetry.io/proto/otlp v1.7.0 // indirect go.yaml.in/yaml/v2 v2.4.2 // indirect golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 // indirect - golang.org/x/mod v0.25.0 // indirect - golang.org/x/net v0.41.0 // indirect + golang.org/x/mod v0.26.0 // indirect + golang.org/x/net v0.42.0 // indirect golang.org/x/oauth2 v0.30.0 // indirect golang.org/x/sync v0.16.0 // indirect - golang.org/x/sys v0.33.0 // indirect - golang.org/x/term v0.32.0 // indirect - golang.org/x/text v0.26.0 // indirect + golang.org/x/sys v0.34.0 // indirect + golang.org/x/term v0.33.0 // indirect + golang.org/x/text v0.27.0 // indirect golang.org/x/time v0.11.0 // indirect - golang.org/x/tools v0.34.0 // indirect + golang.org/x/tools v0.35.0 // indirect golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect - google.golang.org/grpc v1.73.0 // indirect + google.golang.org/grpc v1.74.0 // indirect google.golang.org/protobuf v1.36.6 // indirect gopkg.in/fsnotify/fsnotify.v1 v1.4.7 // indirect gopkg.in/inf.v0 v0.9.1 // indirect @@ -132,6 +132,6 @@ require ( k8s.io/utils v0.0.0-20241210054802-24370beab758 // indirect sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect sigs.k8s.io/randfill v1.0.0 // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.7.0 // indirect sigs.k8s.io/yaml v1.5.0 // indirect ) diff --git a/apps/dashboard/go.sum b/apps/dashboard/go.sum index 7e6bab5fbb7..95d9b4b63a0 100644 --- a/apps/dashboard/go.sum +++ b/apps/dashboard/go.sum @@ -94,10 +94,10 @@ github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e h1:JKmoR8x90Iww1 github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= -github.com/grafana/grafana-app-sdk v0.40.0 h1:KilbCFMYox2cnIi1W6ql7W+n9kms/NvWlBPM1m4Q4mg= -github.com/grafana/grafana-app-sdk v0.40.0/go.mod h1:fn943JEM0CR3mY/Gd3816MUcpob5xnKc8MoojnbMjYY= -github.com/grafana/grafana-app-sdk/logging v0.39.3 h1:mMrcYahnoRu7blKyL/ZVcgv7WCiI2CqxODYh8tBFUgY= -github.com/grafana/grafana-app-sdk/logging v0.39.3/go.mod h1:otUD9XpJD7A5sCLb8mcs9hIXGdeV6lnhzVwe747g4RU= +github.com/grafana/grafana-app-sdk v0.40.1 h1:W8d1CQSgMg/d37xf/0t4PiSa7wVD21XFE8mF6P59YSg= +github.com/grafana/grafana-app-sdk v0.40.1/go.mod h1:4P8h7VB6KcDjX9bAoBQc6IP8iNylxe6bSXLR9gA39gM= +github.com/grafana/grafana-app-sdk/logging v0.40.0 h1:3LHA0pFM9mGGFyq6qoHvJOGEe0H0OVhzzlOKd4Ehu+E= +github.com/grafana/grafana-app-sdk/logging v0.40.0/go.mod h1:otUD9XpJD7A5sCLb8mcs9hIXGdeV6lnhzVwe747g4RU= github.com/grafana/grafana-plugin-sdk-go v0.278.0 h1:5/rIYparLi02pofdaag8wnjspMMVNCi8cZhC4cdC3Ho= github.com/grafana/grafana-plugin-sdk-go v0.278.0/go.mod h1:+8NXT/XUJ/89GV6FxGQ366NZ3nU+cAXDMd0OUESF9H4= github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250514132646-acbc7b54ed9e h1:BTKk7LHuG1kmAkucwTA7DuMbKpKvJTKrGdBmUNO4dfQ= @@ -234,8 +234,8 @@ github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304/go.mod h1 github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= -github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.7 h1:vN6T9TfwStFPFM5XzjsvmzZkLuaLX+HS+0SeFLRgU6M= +github.com/spf13/pflag v1.0.7/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= @@ -314,15 +314,15 @@ golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 h1:y5zboxd6LQAqYIhHnB48p0ByQ golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6/go.mod h1:U6Lno4MTRCDY+Ba7aCcauB9T60gsv5s4ralQzP72ZoQ= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w= -golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= +golang.org/x/mod v0.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg= +golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= -golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= +golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= +golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -341,14 +341,14 @@ golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= -golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg= -golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= +golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= +golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/term v0.33.0 h1:NuFncQrRcaRvVmgRkvM3j/F00gWIAlcmlB8ACEKmGIg= +golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= -golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= +golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= +golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0= golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -356,8 +356,8 @@ golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo= -golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg= +golang.org/x/tools v0.35.0 h1:mBffYraMEf7aa0sB+NuKnuCy8qI/9Bughn8dC2Gu5r0= +golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -370,8 +370,8 @@ google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 h1: google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822/go.mod h1:h3c4v36UTKzUiuaOKQ6gr3S+0hovBtUrXzTG/i3+XEc= google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 h1:fc6jSaCT0vBduLYZHYrBBNY4dsWuvgyff9noRNDdBeE= google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= -google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok= -google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc= +google.golang.org/grpc v1.74.0 h1:sxRSkyLxlceWQiqDofxDot3d4u7DyoHPc7SBXMj8gGY= +google.golang.org/grpc v1.74.0/go.mod h1:NZUaK8dAMUfzhK6uxZ+9511LtOrk73UGWOFoNvz7z+s= google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -405,8 +405,8 @@ sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= -sigs.k8s.io/structured-merge-diff/v4 v4.6.0 h1:IUA9nvMmnKWcj5jl84xn+T5MnlZKThmUW1TdblaLVAc= -sigs.k8s.io/structured-merge-diff/v4 v4.6.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps= +sigs.k8s.io/structured-merge-diff/v4 v4.7.0 h1:qPeWmscJcXP0snki5IYF79Z8xrl8ETFxgMd7wez1XkI= +sigs.k8s.io/structured-merge-diff/v4 v4.7.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps= sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= sigs.k8s.io/yaml v1.5.0 h1:M10b2U7aEUY6hRtU870n2VTPgR5RZiL/I6Lcc2F4NUQ= sigs.k8s.io/yaml v1.5.0/go.mod h1:wZs27Rbxoai4C0f8/9urLZtZtF3avA3gKvGyPdDqTO4= diff --git a/apps/folder/go.mod b/apps/folder/go.mod index b378d607620..31f8f6078a3 100644 --- a/apps/folder/go.mod +++ b/apps/folder/go.mod @@ -3,7 +3,7 @@ module github.com/grafana/grafana/apps/folder go 1.24.5 require ( - github.com/grafana/grafana-app-sdk v0.40.0 + github.com/grafana/grafana-app-sdk v0.40.1 github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250514132646-acbc7b54ed9e k8s.io/apimachinery v0.33.3 k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff @@ -23,7 +23,7 @@ require ( github.com/go-test/deep v1.1.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/google/gnostic-models v0.6.9 // indirect - github.com/grafana/grafana-app-sdk/logging v0.39.3 // indirect + github.com/grafana/grafana-app-sdk/logging v0.40.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/josharian/intern v1.0.0 // indirect @@ -47,11 +47,11 @@ require ( go.opentelemetry.io/otel v1.37.0 // indirect go.opentelemetry.io/otel/trace v1.37.0 // indirect go.yaml.in/yaml/v2 v2.4.2 // indirect - golang.org/x/net v0.41.0 // indirect + golang.org/x/net v0.42.0 // indirect golang.org/x/oauth2 v0.30.0 // indirect - golang.org/x/sys v0.33.0 // indirect - golang.org/x/term v0.32.0 // indirect - golang.org/x/text v0.26.0 // indirect + golang.org/x/sys v0.34.0 // indirect + golang.org/x/term v0.33.0 // indirect + golang.org/x/text v0.27.0 // indirect golang.org/x/time v0.11.0 // indirect google.golang.org/protobuf v1.36.6 // indirect gopkg.in/inf.v0 v0.9.1 // indirect @@ -61,6 +61,6 @@ require ( k8s.io/utils v0.0.0-20241210054802-24370beab758 // indirect sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect sigs.k8s.io/randfill v1.0.0 // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.7.0 // indirect sigs.k8s.io/yaml v1.5.0 // indirect ) diff --git a/apps/folder/go.sum b/apps/folder/go.sum index b7f94082f13..9707dfb4d4a 100644 --- a/apps/folder/go.sum +++ b/apps/folder/go.sum @@ -32,10 +32,10 @@ github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/grafana/grafana-app-sdk v0.40.0 h1:KilbCFMYox2cnIi1W6ql7W+n9kms/NvWlBPM1m4Q4mg= -github.com/grafana/grafana-app-sdk v0.40.0/go.mod h1:fn943JEM0CR3mY/Gd3816MUcpob5xnKc8MoojnbMjYY= -github.com/grafana/grafana-app-sdk/logging v0.39.3 h1:mMrcYahnoRu7blKyL/ZVcgv7WCiI2CqxODYh8tBFUgY= -github.com/grafana/grafana-app-sdk/logging v0.39.3/go.mod h1:otUD9XpJD7A5sCLb8mcs9hIXGdeV6lnhzVwe747g4RU= +github.com/grafana/grafana-app-sdk v0.40.1 h1:W8d1CQSgMg/d37xf/0t4PiSa7wVD21XFE8mF6P59YSg= +github.com/grafana/grafana-app-sdk v0.40.1/go.mod h1:4P8h7VB6KcDjX9bAoBQc6IP8iNylxe6bSXLR9gA39gM= +github.com/grafana/grafana-app-sdk/logging v0.40.0 h1:3LHA0pFM9mGGFyq6qoHvJOGEe0H0OVhzzlOKd4Ehu+E= +github.com/grafana/grafana-app-sdk/logging v0.40.0/go.mod h1:otUD9XpJD7A5sCLb8mcs9hIXGdeV6lnhzVwe747g4RU= github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250514132646-acbc7b54ed9e h1:BTKk7LHuG1kmAkucwTA7DuMbKpKvJTKrGdBmUNO4dfQ= github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250514132646-acbc7b54ed9e/go.mod h1:IA4SOwun8QyST9c5UNs/fN37XL6boXXDvRYFcFwbipg= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -89,8 +89,8 @@ github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzM github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= -github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= -github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.7 h1:vN6T9TfwStFPFM5XzjsvmzZkLuaLX+HS+0SeFLRgU6M= +github.com/spf13/pflag v1.0.7/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= @@ -120,8 +120,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= -golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= +golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= +golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -130,14 +130,14 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= -golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg= -golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= +golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= +golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/term v0.33.0 h1:NuFncQrRcaRvVmgRkvM3j/F00gWIAlcmlB8ACEKmGIg= +golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= -golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= +golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= +golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0= golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -176,8 +176,8 @@ sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= -sigs.k8s.io/structured-merge-diff/v4 v4.6.0 h1:IUA9nvMmnKWcj5jl84xn+T5MnlZKThmUW1TdblaLVAc= -sigs.k8s.io/structured-merge-diff/v4 v4.6.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps= +sigs.k8s.io/structured-merge-diff/v4 v4.7.0 h1:qPeWmscJcXP0snki5IYF79Z8xrl8ETFxgMd7wez1XkI= +sigs.k8s.io/structured-merge-diff/v4 v4.7.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps= sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= sigs.k8s.io/yaml v1.5.0 h1:M10b2U7aEUY6hRtU870n2VTPgR5RZiL/I6Lcc2F4NUQ= sigs.k8s.io/yaml v1.5.0/go.mod h1:wZs27Rbxoai4C0f8/9urLZtZtF3avA3gKvGyPdDqTO4= diff --git a/apps/iam/go.mod b/apps/iam/go.mod index 43260a0bf87..4b98e9c089f 100644 --- a/apps/iam/go.mod +++ b/apps/iam/go.mod @@ -3,7 +3,7 @@ module github.com/grafana/grafana/apps/iam go 1.24.5 require ( - github.com/grafana/grafana-app-sdk v0.40.0 + github.com/grafana/grafana-app-sdk v0.40.1 github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250514132646-acbc7b54ed9e k8s.io/apimachinery v0.33.3 k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff @@ -23,7 +23,7 @@ require ( github.com/go-test/deep v1.1.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/google/gnostic-models v0.6.9 // indirect - github.com/grafana/grafana-app-sdk/logging v0.39.3 // indirect + github.com/grafana/grafana-app-sdk/logging v0.40.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/josharian/intern v1.0.0 // indirect @@ -47,11 +47,11 @@ require ( go.opentelemetry.io/otel v1.37.0 // indirect go.opentelemetry.io/otel/trace v1.37.0 // indirect go.yaml.in/yaml/v2 v2.4.2 // indirect - golang.org/x/net v0.41.0 // indirect + golang.org/x/net v0.42.0 // indirect golang.org/x/oauth2 v0.30.0 // indirect - golang.org/x/sys v0.33.0 // indirect - golang.org/x/term v0.32.0 // indirect - golang.org/x/text v0.26.0 // indirect + golang.org/x/sys v0.34.0 // indirect + golang.org/x/term v0.33.0 // indirect + golang.org/x/text v0.27.0 // indirect golang.org/x/time v0.11.0 // indirect google.golang.org/protobuf v1.36.6 // indirect gopkg.in/inf.v0 v0.9.1 // indirect @@ -61,6 +61,6 @@ require ( k8s.io/utils v0.0.0-20241210054802-24370beab758 // indirect sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect sigs.k8s.io/randfill v1.0.0 // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.7.0 // indirect sigs.k8s.io/yaml v1.5.0 // indirect ) diff --git a/apps/iam/go.sum b/apps/iam/go.sum index b7f94082f13..9707dfb4d4a 100644 --- a/apps/iam/go.sum +++ b/apps/iam/go.sum @@ -32,10 +32,10 @@ github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/grafana/grafana-app-sdk v0.40.0 h1:KilbCFMYox2cnIi1W6ql7W+n9kms/NvWlBPM1m4Q4mg= -github.com/grafana/grafana-app-sdk v0.40.0/go.mod h1:fn943JEM0CR3mY/Gd3816MUcpob5xnKc8MoojnbMjYY= -github.com/grafana/grafana-app-sdk/logging v0.39.3 h1:mMrcYahnoRu7blKyL/ZVcgv7WCiI2CqxODYh8tBFUgY= -github.com/grafana/grafana-app-sdk/logging v0.39.3/go.mod h1:otUD9XpJD7A5sCLb8mcs9hIXGdeV6lnhzVwe747g4RU= +github.com/grafana/grafana-app-sdk v0.40.1 h1:W8d1CQSgMg/d37xf/0t4PiSa7wVD21XFE8mF6P59YSg= +github.com/grafana/grafana-app-sdk v0.40.1/go.mod h1:4P8h7VB6KcDjX9bAoBQc6IP8iNylxe6bSXLR9gA39gM= +github.com/grafana/grafana-app-sdk/logging v0.40.0 h1:3LHA0pFM9mGGFyq6qoHvJOGEe0H0OVhzzlOKd4Ehu+E= +github.com/grafana/grafana-app-sdk/logging v0.40.0/go.mod h1:otUD9XpJD7A5sCLb8mcs9hIXGdeV6lnhzVwe747g4RU= github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250514132646-acbc7b54ed9e h1:BTKk7LHuG1kmAkucwTA7DuMbKpKvJTKrGdBmUNO4dfQ= github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250514132646-acbc7b54ed9e/go.mod h1:IA4SOwun8QyST9c5UNs/fN37XL6boXXDvRYFcFwbipg= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -89,8 +89,8 @@ github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzM github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= -github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= -github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.7 h1:vN6T9TfwStFPFM5XzjsvmzZkLuaLX+HS+0SeFLRgU6M= +github.com/spf13/pflag v1.0.7/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= @@ -120,8 +120,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= -golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= +golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= +golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -130,14 +130,14 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= -golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg= -golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= +golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= +golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/term v0.33.0 h1:NuFncQrRcaRvVmgRkvM3j/F00gWIAlcmlB8ACEKmGIg= +golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= -golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= +golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= +golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0= golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -176,8 +176,8 @@ sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= -sigs.k8s.io/structured-merge-diff/v4 v4.6.0 h1:IUA9nvMmnKWcj5jl84xn+T5MnlZKThmUW1TdblaLVAc= -sigs.k8s.io/structured-merge-diff/v4 v4.6.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps= +sigs.k8s.io/structured-merge-diff/v4 v4.7.0 h1:qPeWmscJcXP0snki5IYF79Z8xrl8ETFxgMd7wez1XkI= +sigs.k8s.io/structured-merge-diff/v4 v4.7.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps= sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= sigs.k8s.io/yaml v1.5.0 h1:M10b2U7aEUY6hRtU870n2VTPgR5RZiL/I6Lcc2F4NUQ= sigs.k8s.io/yaml v1.5.0/go.mod h1:wZs27Rbxoai4C0f8/9urLZtZtF3avA3gKvGyPdDqTO4= diff --git a/apps/investigations/go.mod b/apps/investigations/go.mod index ec8c3d01dae..9e0d9cbf6d8 100644 --- a/apps/investigations/go.mod +++ b/apps/investigations/go.mod @@ -4,7 +4,7 @@ go 1.24.5 require ( github.com/grafana/grafana v0.0.0-00010101000000-000000000000 - github.com/grafana/grafana-app-sdk v0.40.0 + github.com/grafana/grafana-app-sdk v0.40.1 github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250725152715-69d3b9023cec github.com/stretchr/testify v1.10.0 k8s.io/apimachinery v0.33.3 @@ -78,7 +78,7 @@ require ( github.com/grafana/authlib/types v0.0.0-20250710201142-9542f2f28d43 // indirect github.com/grafana/dataplane/sdata v0.0.9 // indirect github.com/grafana/dskit v0.0.0-20250611075409-46f51e1ce914 // indirect - github.com/grafana/grafana-app-sdk/logging v0.39.3 // indirect + github.com/grafana/grafana-app-sdk/logging v0.40.0 // indirect github.com/grafana/grafana-aws-sdk v1.0.4 // indirect github.com/grafana/grafana-azure-sdk-go/v2 v2.1.6 // indirect github.com/grafana/grafana-plugin-sdk-go v0.278.0 // indirect @@ -155,7 +155,7 @@ require ( github.com/rivo/uniseg v0.4.7 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 // indirect - github.com/spf13/pflag v1.0.6 // indirect + github.com/spf13/pflag v1.0.7 // indirect github.com/stretchr/objx v0.5.2 // indirect github.com/tjhop/slog-gokit v0.1.3 // indirect github.com/unknwon/bra v0.0.0-20200517080246-1e3013ecaff8 // indirect @@ -180,22 +180,22 @@ require ( go.opentelemetry.io/proto/otlp v1.7.0 // indirect go.uber.org/atomic v1.11.0 // indirect go.yaml.in/yaml/v2 v2.4.2 // indirect - golang.org/x/crypto v0.39.0 // indirect + golang.org/x/crypto v0.40.0 // indirect golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 // indirect - golang.org/x/mod v0.25.0 // indirect - golang.org/x/net v0.41.0 // indirect + golang.org/x/mod v0.26.0 // indirect + golang.org/x/net v0.42.0 // indirect golang.org/x/oauth2 v0.30.0 // indirect golang.org/x/sync v0.16.0 // indirect - golang.org/x/sys v0.33.0 // indirect - golang.org/x/term v0.32.0 // indirect - golang.org/x/text v0.26.0 // indirect + golang.org/x/sys v0.34.0 // indirect + golang.org/x/term v0.33.0 // indirect + golang.org/x/text v0.27.0 // indirect golang.org/x/time v0.11.0 // indirect - golang.org/x/tools v0.34.0 // indirect + golang.org/x/tools v0.35.0 // indirect golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect - google.golang.org/grpc v1.73.0 // indirect + google.golang.org/grpc v1.74.0 // indirect google.golang.org/protobuf v1.36.6 // indirect gopkg.in/fsnotify/fsnotify.v1 v1.4.7 // indirect gopkg.in/inf.v0 v0.9.1 // indirect @@ -203,13 +203,13 @@ require ( gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/api v0.33.3 // indirect - k8s.io/apiextensions-apiserver v0.33.2 // indirect + k8s.io/apiextensions-apiserver v0.33.3 // indirect k8s.io/client-go v0.33.3 // indirect k8s.io/component-base v0.33.3 // indirect k8s.io/utils v0.0.0-20241210054802-24370beab758 // indirect sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect sigs.k8s.io/randfill v1.0.0 // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.7.0 // indirect sigs.k8s.io/yaml v1.5.0 // indirect xorm.io/builder v0.3.6 // indirect ) diff --git a/apps/investigations/go.sum b/apps/investigations/go.sum index 903c4ae9e07..d6f3b9daad3 100644 --- a/apps/investigations/go.sum +++ b/apps/investigations/go.sum @@ -333,10 +333,10 @@ github.com/grafana/dataplane/sdata v0.0.9 h1:AGL1LZnCUG4MnQtnWpBPbQ8ZpptaZs14w6k github.com/grafana/dataplane/sdata v0.0.9/go.mod h1:Jvs5ddpGmn6vcxT7tCTWAZ1mgi4sbcdFt9utQx5uMAU= github.com/grafana/dskit v0.0.0-20250611075409-46f51e1ce914 h1:qcSGhr691f1mmPHwg2svGyO40Ex92G02aOyHzP6XHCE= github.com/grafana/dskit v0.0.0-20250611075409-46f51e1ce914/go.mod h1:OiN4P4aC6LwLzLbEupH3Ue83VfQoNMfG48rsna8jI/E= -github.com/grafana/grafana-app-sdk v0.40.0 h1:KilbCFMYox2cnIi1W6ql7W+n9kms/NvWlBPM1m4Q4mg= -github.com/grafana/grafana-app-sdk v0.40.0/go.mod h1:fn943JEM0CR3mY/Gd3816MUcpob5xnKc8MoojnbMjYY= -github.com/grafana/grafana-app-sdk/logging v0.39.3 h1:mMrcYahnoRu7blKyL/ZVcgv7WCiI2CqxODYh8tBFUgY= -github.com/grafana/grafana-app-sdk/logging v0.39.3/go.mod h1:otUD9XpJD7A5sCLb8mcs9hIXGdeV6lnhzVwe747g4RU= +github.com/grafana/grafana-app-sdk v0.40.1 h1:W8d1CQSgMg/d37xf/0t4PiSa7wVD21XFE8mF6P59YSg= +github.com/grafana/grafana-app-sdk v0.40.1/go.mod h1:4P8h7VB6KcDjX9bAoBQc6IP8iNylxe6bSXLR9gA39gM= +github.com/grafana/grafana-app-sdk/logging v0.40.0 h1:3LHA0pFM9mGGFyq6qoHvJOGEe0H0OVhzzlOKd4Ehu+E= +github.com/grafana/grafana-app-sdk/logging v0.40.0/go.mod h1:otUD9XpJD7A5sCLb8mcs9hIXGdeV6lnhzVwe747g4RU= github.com/grafana/grafana-aws-sdk v1.0.4 h1:D14UAehsOqpjliHmHzveRQ1p43KCsMzdmb7GovWj+SY= github.com/grafana/grafana-aws-sdk v1.0.4/go.mod h1:hO7q7yWV+t6dmiyJjMa3IbuYnYkBua+G/IAlOPVIYKE= github.com/grafana/grafana-azure-sdk-go/v2 v2.1.6 h1:OfCkitCuomzZKW1WYHrG8MxKwtMhALb7jqoj+487eTg= @@ -648,8 +648,8 @@ github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c h1:Ho+uVpke github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y= github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= -github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= -github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.7 h1:vN6T9TfwStFPFM5XzjsvmzZkLuaLX+HS+0SeFLRgU6M= +github.com/spf13/pflag v1.0.7/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= @@ -757,8 +757,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= -golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= -golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= +golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM= +golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 h1:y5zboxd6LQAqYIhHnB48p0ByQ/GnQx2BE33L8BOHQkI= golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6/go.mod h1:U6Lno4MTRCDY+Ba7aCcauB9T60gsv5s4ralQzP72ZoQ= @@ -770,8 +770,8 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w= -golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= +golang.org/x/mod v0.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg= +golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -793,8 +793,8 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= -golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= +golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= +golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -846,15 +846,15 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= -golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= +golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= -golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg= -golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= +golang.org/x/term v0.33.0 h1:NuFncQrRcaRvVmgRkvM3j/F00gWIAlcmlB8ACEKmGIg= +golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -863,8 +863,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= -golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= +golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= +golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0= @@ -882,8 +882,8 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo= -golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg= +golang.org/x/tools v0.35.0 h1:mBffYraMEf7aa0sB+NuKnuCy8qI/9Bughn8dC2Gu5r0= +golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -912,8 +912,8 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822/go. google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok= -google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc= +google.golang.org/grpc v1.74.0 h1:sxRSkyLxlceWQiqDofxDot3d4u7DyoHPc7SBXMj8gGY= +google.golang.org/grpc v1.74.0/go.mod h1:NZUaK8dAMUfzhK6uxZ+9511LtOrk73UGWOFoNvz7z+s= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -963,8 +963,8 @@ honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= k8s.io/api v0.33.3 h1:SRd5t//hhkI1buzxb288fy2xvjubstenEKL9K51KBI8= k8s.io/api v0.33.3/go.mod h1:01Y/iLUjNBM3TAvypct7DIj0M0NIZc+PzAHCIo0CYGE= -k8s.io/apiextensions-apiserver v0.33.2 h1:6gnkIbngnaUflR3XwE1mCefN3YS8yTD631JXQhsU6M8= -k8s.io/apiextensions-apiserver v0.33.2/go.mod h1:IvVanieYsEHJImTKXGP6XCOjTwv2LUMos0YWc9O+QP8= +k8s.io/apiextensions-apiserver v0.33.3 h1:qmOcAHN6DjfD0v9kxL5udB27SRP6SG/MTopmge3MwEs= +k8s.io/apiextensions-apiserver v0.33.3/go.mod h1:oROuctgo27mUsyp9+Obahos6CWcMISSAPzQ77CAQGz8= k8s.io/apimachinery v0.33.3 h1:4ZSrmNa0c/ZpZJhAgRdcsFcZOw1PQU1bALVQ0B3I5LA= k8s.io/apimachinery v0.33.3/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM= k8s.io/apiserver v0.33.3 h1:Wv0hGc+QFdMJB4ZSiHrCgN3zL3QRatu56+rpccKC3J4= @@ -984,8 +984,8 @@ sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= -sigs.k8s.io/structured-merge-diff/v4 v4.6.0 h1:IUA9nvMmnKWcj5jl84xn+T5MnlZKThmUW1TdblaLVAc= -sigs.k8s.io/structured-merge-diff/v4 v4.6.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps= +sigs.k8s.io/structured-merge-diff/v4 v4.7.0 h1:qPeWmscJcXP0snki5IYF79Z8xrl8ETFxgMd7wez1XkI= +sigs.k8s.io/structured-merge-diff/v4 v4.7.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps= sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= sigs.k8s.io/yaml v1.5.0 h1:M10b2U7aEUY6hRtU870n2VTPgR5RZiL/I6Lcc2F4NUQ= sigs.k8s.io/yaml v1.5.0/go.mod h1:wZs27Rbxoai4C0f8/9urLZtZtF3avA3gKvGyPdDqTO4= diff --git a/apps/playlist/go.mod b/apps/playlist/go.mod index 1bb57fe534b..0198da5b976 100644 --- a/apps/playlist/go.mod +++ b/apps/playlist/go.mod @@ -3,7 +3,7 @@ module github.com/grafana/grafana/apps/playlist go 1.24.5 require ( - github.com/grafana/grafana-app-sdk v0.40.0 + github.com/grafana/grafana-app-sdk v0.40.1 k8s.io/apimachinery v0.33.3 k8s.io/client-go v0.33.3 k8s.io/klog/v2 v2.130.1 @@ -30,7 +30,7 @@ require ( github.com/google/go-cmp v0.7.0 // indirect github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/grafana/grafana-app-sdk/logging v0.39.3 // indirect + github.com/grafana/grafana-app-sdk/logging v0.40.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect @@ -52,7 +52,7 @@ require ( github.com/prometheus/procfs v0.16.1 // indirect github.com/puzpuzpuz/xsync/v2 v2.5.1 // indirect github.com/rogpeppe/go-internal v1.14.1 // indirect - github.com/spf13/pflag v1.0.6 // indirect + github.com/spf13/pflag v1.0.7 // indirect github.com/x448/float16 v0.8.4 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect go.opentelemetry.io/otel v1.37.0 // indirect @@ -65,26 +65,26 @@ require ( go.opentelemetry.io/otel/trace v1.37.0 // indirect go.opentelemetry.io/proto/otlp v1.7.0 // indirect go.yaml.in/yaml/v2 v2.4.2 // indirect - golang.org/x/net v0.41.0 // indirect + golang.org/x/net v0.42.0 // indirect golang.org/x/oauth2 v0.30.0 // indirect golang.org/x/sync v0.16.0 // indirect - golang.org/x/sys v0.33.0 // indirect - golang.org/x/term v0.32.0 // indirect - golang.org/x/text v0.26.0 // indirect + golang.org/x/sys v0.34.0 // indirect + golang.org/x/term v0.33.0 // indirect + golang.org/x/text v0.27.0 // indirect golang.org/x/time v0.11.0 // indirect gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect - google.golang.org/grpc v1.73.0 // indirect + google.golang.org/grpc v1.74.0 // indirect google.golang.org/protobuf v1.36.6 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/api v0.33.3 // indirect - k8s.io/apiextensions-apiserver v0.33.2 // indirect + k8s.io/apiextensions-apiserver v0.33.3 // indirect k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff // indirect k8s.io/utils v0.0.0-20241210054802-24370beab758 // indirect sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect sigs.k8s.io/randfill v1.0.0 // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.7.0 // indirect sigs.k8s.io/yaml v1.5.0 // indirect ) diff --git a/apps/playlist/go.sum b/apps/playlist/go.sum index 6558ce86a17..5d053231eb3 100644 --- a/apps/playlist/go.sum +++ b/apps/playlist/go.sum @@ -47,10 +47,10 @@ github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/grafana/grafana-app-sdk v0.40.0 h1:KilbCFMYox2cnIi1W6ql7W+n9kms/NvWlBPM1m4Q4mg= -github.com/grafana/grafana-app-sdk v0.40.0/go.mod h1:fn943JEM0CR3mY/Gd3816MUcpob5xnKc8MoojnbMjYY= -github.com/grafana/grafana-app-sdk/logging v0.39.3 h1:mMrcYahnoRu7blKyL/ZVcgv7WCiI2CqxODYh8tBFUgY= -github.com/grafana/grafana-app-sdk/logging v0.39.3/go.mod h1:otUD9XpJD7A5sCLb8mcs9hIXGdeV6lnhzVwe747g4RU= +github.com/grafana/grafana-app-sdk v0.40.1 h1:W8d1CQSgMg/d37xf/0t4PiSa7wVD21XFE8mF6P59YSg= +github.com/grafana/grafana-app-sdk v0.40.1/go.mod h1:4P8h7VB6KcDjX9bAoBQc6IP8iNylxe6bSXLR9gA39gM= +github.com/grafana/grafana-app-sdk/logging v0.40.0 h1:3LHA0pFM9mGGFyq6qoHvJOGEe0H0OVhzzlOKd4Ehu+E= +github.com/grafana/grafana-app-sdk/logging v0.40.0/go.mod h1:otUD9XpJD7A5sCLb8mcs9hIXGdeV6lnhzVwe747g4RU= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1 h1:X5VWvz21y3gzm9Nw/kaUeku/1+uBhcekkmy4IkffJww= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1/go.mod h1:Zanoh4+gvIgluNqcfMVTJueD4wSS5hT7zTt4Mrutd90= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -110,8 +110,8 @@ github.com/puzpuzpuz/xsync/v2 v2.5.1 h1:mVGYAvzDSu52+zaGyNjC+24Xw2bQi3kTr4QJ6N9p github.com/puzpuzpuz/xsync/v2 v2.5.1/go.mod h1:gD2H2krq/w52MfPLE+Uy64TzJDVY7lP2znR9qmR35kU= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= -github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= -github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.7 h1:vN6T9TfwStFPFM5XzjsvmzZkLuaLX+HS+0SeFLRgU6M= +github.com/spf13/pflag v1.0.7/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= @@ -159,8 +159,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= -golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= +golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= +golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -171,22 +171,22 @@ golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= -golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg= -golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= +golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= +golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/term v0.33.0 h1:NuFncQrRcaRvVmgRkvM3j/F00gWIAlcmlB8ACEKmGIg= +golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= -golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= +golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= +golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0= golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo= -golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg= +golang.org/x/tools v0.35.0 h1:mBffYraMEf7aa0sB+NuKnuCy8qI/9Bughn8dC2Gu5r0= +golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -197,8 +197,8 @@ google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 h1: google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822/go.mod h1:h3c4v36UTKzUiuaOKQ6gr3S+0hovBtUrXzTG/i3+XEc= google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 h1:fc6jSaCT0vBduLYZHYrBBNY4dsWuvgyff9noRNDdBeE= google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= -google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok= -google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc= +google.golang.org/grpc v1.74.0 h1:sxRSkyLxlceWQiqDofxDot3d4u7DyoHPc7SBXMj8gGY= +google.golang.org/grpc v1.74.0/go.mod h1:NZUaK8dAMUfzhK6uxZ+9511LtOrk73UGWOFoNvz7z+s= google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -212,8 +212,8 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= k8s.io/api v0.33.3 h1:SRd5t//hhkI1buzxb288fy2xvjubstenEKL9K51KBI8= k8s.io/api v0.33.3/go.mod h1:01Y/iLUjNBM3TAvypct7DIj0M0NIZc+PzAHCIo0CYGE= -k8s.io/apiextensions-apiserver v0.33.2 h1:6gnkIbngnaUflR3XwE1mCefN3YS8yTD631JXQhsU6M8= -k8s.io/apiextensions-apiserver v0.33.2/go.mod h1:IvVanieYsEHJImTKXGP6XCOjTwv2LUMos0YWc9O+QP8= +k8s.io/apiextensions-apiserver v0.33.3 h1:qmOcAHN6DjfD0v9kxL5udB27SRP6SG/MTopmge3MwEs= +k8s.io/apiextensions-apiserver v0.33.3/go.mod h1:oROuctgo27mUsyp9+Obahos6CWcMISSAPzQ77CAQGz8= k8s.io/apimachinery v0.33.3 h1:4ZSrmNa0c/ZpZJhAgRdcsFcZOw1PQU1bALVQ0B3I5LA= k8s.io/apimachinery v0.33.3/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM= k8s.io/client-go v0.33.3 h1:M5AfDnKfYmVJif92ngN532gFqakcGi6RvaOF16efrpA= @@ -229,8 +229,8 @@ sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= -sigs.k8s.io/structured-merge-diff/v4 v4.6.0 h1:IUA9nvMmnKWcj5jl84xn+T5MnlZKThmUW1TdblaLVAc= -sigs.k8s.io/structured-merge-diff/v4 v4.6.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps= +sigs.k8s.io/structured-merge-diff/v4 v4.7.0 h1:qPeWmscJcXP0snki5IYF79Z8xrl8ETFxgMd7wez1XkI= +sigs.k8s.io/structured-merge-diff/v4 v4.7.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps= sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= sigs.k8s.io/yaml v1.5.0 h1:M10b2U7aEUY6hRtU870n2VTPgR5RZiL/I6Lcc2F4NUQ= sigs.k8s.io/yaml v1.5.0/go.mod h1:wZs27Rbxoai4C0f8/9urLZtZtF3avA3gKvGyPdDqTO4= diff --git a/apps/sdk.mk b/apps/sdk.mk index 7a0f51237cf..093075f0be4 100644 --- a/apps/sdk.mk +++ b/apps/sdk.mk @@ -1,4 +1,4 @@ -APP_SDK_VERSION = v0.40.0 +APP_SDK_VERSION = v0.40.1 APP_SDK_DIR = $(shell go env GOPATH)/bin/app-sdk-$(APP_SDK_VERSION) APP_SDK_BIN = $(APP_SDK_DIR)/grafana-app-sdk @@ -20,4 +20,4 @@ $(APP_SDK_BIN): update-app-sdk: ## Update the Grafana App SDK dependency in go.mod @pwd go get github.com/grafana/grafana-app-sdk@$(APP_SDK_VERSION) - go mod tidy || true # TODO: remove this + go mod tidy diff --git a/apps/secret/go.mod b/apps/secret/go.mod index bd2ef50ab1b..b47cd2748cc 100644 --- a/apps/secret/go.mod +++ b/apps/secret/go.mod @@ -3,10 +3,10 @@ module github.com/grafana/grafana/apps/secret go 1.24.5 require ( - github.com/grafana/grafana-app-sdk v0.40.0 + github.com/grafana/grafana-app-sdk v0.40.1 github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250710134100-1f3dc0533caf github.com/stretchr/testify v1.10.0 - google.golang.org/grpc v1.73.0 + google.golang.org/grpc v1.74.0 google.golang.org/protobuf v1.36.6 gopkg.in/yaml.v3 v3.0.1 k8s.io/apimachinery v0.33.3 @@ -28,7 +28,7 @@ require ( github.com/go-test/deep v1.1.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/google/gnostic-models v0.6.9 // indirect - github.com/grafana/grafana-app-sdk/logging v0.39.3 // indirect + github.com/grafana/grafana-app-sdk/logging v0.40.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/josharian/intern v1.0.0 // indirect @@ -52,11 +52,11 @@ require ( go.opentelemetry.io/otel/sdk/metric v1.37.0 // indirect go.opentelemetry.io/otel/trace v1.37.0 // indirect go.yaml.in/yaml/v2 v2.4.2 // indirect - golang.org/x/net v0.41.0 // indirect + golang.org/x/net v0.42.0 // indirect golang.org/x/oauth2 v0.30.0 // indirect - golang.org/x/sys v0.33.0 // indirect - golang.org/x/term v0.32.0 // indirect - golang.org/x/text v0.26.0 // indirect + golang.org/x/sys v0.34.0 // indirect + golang.org/x/term v0.33.0 // indirect + golang.org/x/text v0.27.0 // indirect golang.org/x/time v0.11.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect gopkg.in/inf.v0 v0.9.1 // indirect @@ -64,6 +64,6 @@ require ( k8s.io/klog/v2 v2.130.1 // indirect sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect sigs.k8s.io/randfill v1.0.0 // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.7.0 // indirect sigs.k8s.io/yaml v1.5.0 // indirect ) diff --git a/apps/secret/go.sum b/apps/secret/go.sum index 0e4f4908526..eb2dfb8c73e 100644 --- a/apps/secret/go.sum +++ b/apps/secret/go.sum @@ -36,10 +36,10 @@ github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/grafana/grafana-app-sdk v0.40.0 h1:KilbCFMYox2cnIi1W6ql7W+n9kms/NvWlBPM1m4Q4mg= -github.com/grafana/grafana-app-sdk v0.40.0/go.mod h1:fn943JEM0CR3mY/Gd3816MUcpob5xnKc8MoojnbMjYY= -github.com/grafana/grafana-app-sdk/logging v0.39.3 h1:mMrcYahnoRu7blKyL/ZVcgv7WCiI2CqxODYh8tBFUgY= -github.com/grafana/grafana-app-sdk/logging v0.39.3/go.mod h1:otUD9XpJD7A5sCLb8mcs9hIXGdeV6lnhzVwe747g4RU= +github.com/grafana/grafana-app-sdk v0.40.1 h1:W8d1CQSgMg/d37xf/0t4PiSa7wVD21XFE8mF6P59YSg= +github.com/grafana/grafana-app-sdk v0.40.1/go.mod h1:4P8h7VB6KcDjX9bAoBQc6IP8iNylxe6bSXLR9gA39gM= +github.com/grafana/grafana-app-sdk/logging v0.40.0 h1:3LHA0pFM9mGGFyq6qoHvJOGEe0H0OVhzzlOKd4Ehu+E= +github.com/grafana/grafana-app-sdk/logging v0.40.0/go.mod h1:otUD9XpJD7A5sCLb8mcs9hIXGdeV6lnhzVwe747g4RU= github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250710134100-1f3dc0533caf h1:BBGDHffvVNLoYQlXEpbXcxE0vbpq7pm/8OWF5I+UDZg= github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250710134100-1f3dc0533caf/go.mod h1:eAlOam2uWhrsEZlOoAr7XZ9hbBP7SyYGYn31/aQAPs8= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -93,8 +93,8 @@ github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzM github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= -github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= -github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.7 h1:vN6T9TfwStFPFM5XzjsvmzZkLuaLX+HS+0SeFLRgU6M= +github.com/spf13/pflag v1.0.7/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= @@ -132,8 +132,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= -golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= +golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= +golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -142,14 +142,14 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= -golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg= -golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= +golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= +golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/term v0.33.0 h1:NuFncQrRcaRvVmgRkvM3j/F00gWIAlcmlB8ACEKmGIg= +golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= -golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= +golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= +golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0= golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -162,8 +162,8 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 h1:fc6jSaCT0vBduLYZHYrBBNY4dsWuvgyff9noRNDdBeE= google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= -google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok= -google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc= +google.golang.org/grpc v1.74.0 h1:sxRSkyLxlceWQiqDofxDot3d4u7DyoHPc7SBXMj8gGY= +google.golang.org/grpc v1.74.0/go.mod h1:NZUaK8dAMUfzhK6uxZ+9511LtOrk73UGWOFoNvz7z+s= google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -192,8 +192,8 @@ sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= -sigs.k8s.io/structured-merge-diff/v4 v4.6.0 h1:IUA9nvMmnKWcj5jl84xn+T5MnlZKThmUW1TdblaLVAc= -sigs.k8s.io/structured-merge-diff/v4 v4.6.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps= +sigs.k8s.io/structured-merge-diff/v4 v4.7.0 h1:qPeWmscJcXP0snki5IYF79Z8xrl8ETFxgMd7wez1XkI= +sigs.k8s.io/structured-merge-diff/v4 v4.7.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps= sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= sigs.k8s.io/yaml v1.5.0 h1:M10b2U7aEUY6hRtU870n2VTPgR5RZiL/I6Lcc2F4NUQ= sigs.k8s.io/yaml v1.5.0/go.mod h1:wZs27Rbxoai4C0f8/9urLZtZtF3avA3gKvGyPdDqTO4= diff --git a/go.mod b/go.mod index 46c47ef1f6e..dfddf213482 100644 --- a/go.mod +++ b/go.mod @@ -95,8 +95,8 @@ require ( github.com/grafana/gofpdf v0.0.0-20250307124105-3b9c5d35577f // @grafana/sharing-squad github.com/grafana/gomemcache v0.0.0-20250318131618-74242eea118d // @grafana/grafana-operator-experience-squad github.com/grafana/grafana-api-golang-client v0.27.0 // @grafana/alerting-backend - github.com/grafana/grafana-app-sdk v0.40.0 // @grafana/grafana-app-platform-squad - github.com/grafana/grafana-app-sdk/logging v0.39.3 // @grafana/grafana-app-platform-squad + github.com/grafana/grafana-app-sdk v0.40.1 // @grafana/grafana-app-platform-squad + github.com/grafana/grafana-app-sdk/logging v0.40.0 // @grafana/grafana-app-platform-squad github.com/grafana/grafana-aws-sdk v1.0.4 // @grafana/aws-datasources github.com/grafana/grafana-azure-sdk-go/v2 v2.1.6 // @grafana/partner-datasources github.com/grafana/grafana-cloud-migration-snapshot v1.9.0 // @grafana/grafana-operator-experience-squad @@ -164,7 +164,7 @@ require ( github.com/russellhaering/goxmldsig v1.4.0 // @grafana/grafana-backend-group github.com/shopspring/decimal v1.4.0 // @grafana/grafana-datasources-core-services github.com/spf13/cobra v1.9.1 // @grafana/grafana-app-platform-squad - github.com/spf13/pflag v1.0.6 // @grafana-app-platform-squad + github.com/spf13/pflag v1.0.7 // @grafana-app-platform-squad github.com/spyzhov/ajson v0.9.6 // @grafana/grafana-sharing-squad github.com/stretchr/testify v1.10.0 // @grafana/grafana-backend-group github.com/teris-io/shortid v0.0.0-20171029131806-771a37caa5cf // @grafana/grafana-backend-group @@ -195,18 +195,18 @@ require ( go.uber.org/zap v1.27.0 // @grafana/identity-access-team gocloud.dev v0.42.0 // @grafana/grafana-app-platform-squad gocloud.dev/secrets/hashivault v0.42.0 // @grafana/grafana-operator-experience-squad - golang.org/x/crypto v0.39.0 // @grafana/grafana-backend-group + golang.org/x/crypto v0.40.0 // @grafana/grafana-backend-group golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 // @grafana/alerting-backend - golang.org/x/mod v0.25.0 // indirect; @grafana/grafana-backend-group - golang.org/x/net v0.41.0 // @grafana/oss-big-tent @grafana/partner-datasources + golang.org/x/mod v0.26.0 // indirect; @grafana/grafana-backend-group + golang.org/x/net v0.42.0 // @grafana/oss-big-tent @grafana/partner-datasources golang.org/x/oauth2 v0.30.0 // @grafana/identity-access-team golang.org/x/sync v0.16.0 // @grafana/alerting-backend - golang.org/x/text v0.26.0 // @grafana/grafana-backend-group + golang.org/x/text v0.27.0 // @grafana/grafana-backend-group golang.org/x/time v0.11.0 // @grafana/grafana-backend-group - golang.org/x/tools v0.34.0 // indirect; @grafana/grafana-as-code + golang.org/x/tools v0.35.0 // indirect; @grafana/grafana-as-code gonum.org/v1/gonum v0.16.0 // @grafana/oss-big-tent google.golang.org/api v0.235.0 // @grafana/grafana-backend-group - google.golang.org/grpc v1.73.0 // @grafana/plugins-platform-backend + google.golang.org/grpc v1.74.0 // @grafana/plugins-platform-backend google.golang.org/protobuf v1.36.6 // @grafana/plugins-platform-backend gopkg.in/ini.v1 v1.67.0 // @grafana/alerting-backend gopkg.in/mail.v2 v2.3.1 // @grafana/grafana-backend-group @@ -223,7 +223,7 @@ require ( k8s.io/utils v0.0.0-20241210054802-24370beab758 // @grafana/partner-datasources pgregory.net/rapid v1.2.0 // @grafana/grafana-operator-experience-squad sigs.k8s.io/randfill v1.0.0 // @grafana/grafana-app-platform-squad - sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // @grafana-app-platform-squad + sigs.k8s.io/structured-merge-diff/v4 v4.7.0 // @grafana-app-platform-squad xorm.io/builder v0.3.6 // @grafana/grafana-backend-group ) @@ -248,7 +248,7 @@ require ( ) require ( - cel.dev/expr v0.23.1 // indirect + cel.dev/expr v0.24.0 // indirect cloud.google.com/go v0.121.1 // indirect cloud.google.com/go/auth v0.16.1 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect @@ -344,7 +344,7 @@ require ( github.com/cheekybits/genny v1.0.0 // indirect github.com/chromedp/cdproto v0.0.0-20250429231605-6ed5b53462d4 // indirect github.com/cloudflare/circl v1.6.1 // indirect - github.com/cncf/xds/go v0.0.0-20250326154945-ae57f3c0d45f // indirect + github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443 // indirect github.com/cockroachdb/apd/v3 v3.2.1 // indirect github.com/coreos/go-semver v0.3.1 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect @@ -572,8 +572,8 @@ require ( go.uber.org/multierr v1.11.0 // indirect go.yaml.in/yaml/v2 v2.4.2 // indirect go4.org/netipx v0.0.0-20230125063823-8449b0a6169f // indirect - golang.org/x/sys v0.33.0 // indirect - golang.org/x/term v0.32.0 // indirect + golang.org/x/sys v0.34.0 // indirect + golang.org/x/term v0.33.0 // indirect golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect google.golang.org/genproto v0.0.0-20250603155806-513f23925822 // indirect @@ -586,7 +586,7 @@ require ( gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/src-d/go-errors.v1 v1.0.0 // indirect gopkg.in/telebot.v3 v3.2.1 // indirect - k8s.io/apiextensions-apiserver v0.33.2 // indirect + k8s.io/apiextensions-apiserver v0.33.3 // indirect k8s.io/kms v0.33.3 // indirect modernc.org/libc v1.65.0 // indirect modernc.org/mathutil v1.7.1 // indirect diff --git a/go.sum b/go.sum index 65c00e3ac6b..827f20c85c3 100644 --- a/go.sum +++ b/go.sum @@ -4,8 +4,8 @@ buf.build/gen/go/parca-dev/parca/protocolbuffers/go v1.36.2-20250703125925-3f0fc buf.build/gen/go/parca-dev/parca/protocolbuffers/go v1.36.2-20250703125925-3f0fcf4bff96.1/go.mod h1:1M7nlq2ljfzb95x9LaA2j1gYIvDkVZii58mGvTa9ExM= c2sp.org/CCTV/age v0.0.0-20240306222714-3ec4d716e805 h1:u2qwJeEvnypw+OCPUHmoZE3IqwfuN5kgDfo5MLzpNM0= c2sp.org/CCTV/age v0.0.0-20240306222714-3ec4d716e805/go.mod h1:FomMrUJ2Lxt5jCLmZkG3FHa72zUprnhd3v/Z18Snm4w= -cel.dev/expr v0.23.1 h1:K4KOtPCJQjVggkARsjG9RWXP6O4R73aHeJMa/dmCQQg= -cel.dev/expr v0.23.1/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw= +cel.dev/expr v0.24.0 h1:56OvJKSH3hDGL0ml5uSxZmz3/3Pq4tJ+fb1unVLAFcY= +cel.dev/expr v0.24.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw= @@ -1031,8 +1031,8 @@ github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20220314180256-7f1daf1720fc/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20230310173818-32f1caf87195/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20250326154945-ae57f3c0d45f h1:C5bqEmzEPLsHm9Mv73lSE9e9bKV23aB1vxOsmZrkl3k= -github.com/cncf/xds/go v0.0.0-20250326154945-ae57f3c0d45f/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= +github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443 h1:aQ3y1lwWyqYPiWZThqv1aFbZMiM9vblcSArJRf2Irls= +github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/cockroachdb/apd/v3 v3.2.1 h1:U+8j7t0axsIgvQUqthuNm82HIrYXodOV2iWLWtEaIwg= github.com/cockroachdb/apd/v3 v3.2.1/go.mod h1:klXJcjp+FffLTHlhIG69tezTDvdP065naDsHzKhYSqc= @@ -1594,10 +1594,10 @@ github.com/grafana/gomemcache v0.0.0-20250318131618-74242eea118d h1:oXRJlb9UjVsl github.com/grafana/gomemcache v0.0.0-20250318131618-74242eea118d/go.mod h1:j/s0jkda4UXTemDs7Pgw/vMT06alWc42CHisvYac0qw= github.com/grafana/grafana-api-golang-client v0.27.0 h1:zIwMXcbCB4n588i3O2N6HfNcQogCNTd/vPkEXTr7zX8= github.com/grafana/grafana-api-golang-client v0.27.0/go.mod h1:uNLZEmgKtTjHBtCQMwNn3qsx2mpMb8zU+7T4Xv3NR9Y= -github.com/grafana/grafana-app-sdk v0.40.0 h1:KilbCFMYox2cnIi1W6ql7W+n9kms/NvWlBPM1m4Q4mg= -github.com/grafana/grafana-app-sdk v0.40.0/go.mod h1:fn943JEM0CR3mY/Gd3816MUcpob5xnKc8MoojnbMjYY= -github.com/grafana/grafana-app-sdk/logging v0.39.3 h1:mMrcYahnoRu7blKyL/ZVcgv7WCiI2CqxODYh8tBFUgY= -github.com/grafana/grafana-app-sdk/logging v0.39.3/go.mod h1:otUD9XpJD7A5sCLb8mcs9hIXGdeV6lnhzVwe747g4RU= +github.com/grafana/grafana-app-sdk v0.40.1 h1:W8d1CQSgMg/d37xf/0t4PiSa7wVD21XFE8mF6P59YSg= +github.com/grafana/grafana-app-sdk v0.40.1/go.mod h1:4P8h7VB6KcDjX9bAoBQc6IP8iNylxe6bSXLR9gA39gM= +github.com/grafana/grafana-app-sdk/logging v0.40.0 h1:3LHA0pFM9mGGFyq6qoHvJOGEe0H0OVhzzlOKd4Ehu+E= +github.com/grafana/grafana-app-sdk/logging v0.40.0/go.mod h1:otUD9XpJD7A5sCLb8mcs9hIXGdeV6lnhzVwe747g4RU= github.com/grafana/grafana-aws-sdk v1.0.4 h1:D14UAehsOqpjliHmHzveRQ1p43KCsMzdmb7GovWj+SY= github.com/grafana/grafana-aws-sdk v1.0.4/go.mod h1:hO7q7yWV+t6dmiyJjMa3IbuYnYkBua+G/IAlOPVIYKE= github.com/grafana/grafana-azure-sdk-go/v2 v2.1.6 h1:OfCkitCuomzZKW1WYHrG8MxKwtMhALb7jqoj+487eTg= @@ -2382,8 +2382,9 @@ github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0 github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.7 h1:vN6T9TfwStFPFM5XzjsvmzZkLuaLX+HS+0SeFLRgU6M= +github.com/spf13/pflag v1.0.7/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/spf13/viper v1.13.0/go.mod h1:Icm2xNL3/8uyh/wFuB1jI7TiTNKp8632Nwegu+zgdYw= github.com/spf13/viper v1.20.1 h1:ZMi+z/lvLyPSCoNtFCpqjy0S4kPbirhpTMwl8BkW9X4= @@ -2694,8 +2695,8 @@ golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDf golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= -golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= -golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= +golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM= +golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -2759,8 +2760,8 @@ golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w= -golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= +golang.org/x/mod v0.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg= +golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ= golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -2846,8 +2847,8 @@ golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= -golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= -golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= +golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= +golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -3043,8 +3044,8 @@ golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= -golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= +golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -3064,8 +3065,8 @@ golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0= golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8= -golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg= -golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= +golang.org/x/term v0.33.0 h1:NuFncQrRcaRvVmgRkvM3j/F00gWIAlcmlB8ACEKmGIg= +golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -3088,8 +3089,8 @@ golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= -golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= -golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= +golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= +golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -3175,8 +3176,8 @@ golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= -golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo= -golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg= +golang.org/x/tools v0.35.0 h1:mBffYraMEf7aa0sB+NuKnuCy8qI/9Bughn8dC2Gu5r0= +golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -3478,8 +3479,8 @@ google.golang.org/grpc v1.52.0/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5v google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g= google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8= -google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok= -google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc= +google.golang.org/grpc v1.74.0 h1:sxRSkyLxlceWQiqDofxDot3d4u7DyoHPc7SBXMj8gGY= +google.golang.org/grpc v1.74.0/go.mod h1:NZUaK8dAMUfzhK6uxZ+9511LtOrk73UGWOFoNvz7z+s= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= @@ -3564,8 +3565,8 @@ honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= k8s.io/api v0.0.0-20190813020757-36bff7324fb7/go.mod h1:3Iy+myeAORNCLgjd/Xu9ebwN7Vh59Bw0vh9jhoX+V58= k8s.io/api v0.33.3 h1:SRd5t//hhkI1buzxb288fy2xvjubstenEKL9K51KBI8= k8s.io/api v0.33.3/go.mod h1:01Y/iLUjNBM3TAvypct7DIj0M0NIZc+PzAHCIo0CYGE= -k8s.io/apiextensions-apiserver v0.33.2 h1:6gnkIbngnaUflR3XwE1mCefN3YS8yTD631JXQhsU6M8= -k8s.io/apiextensions-apiserver v0.33.2/go.mod h1:IvVanieYsEHJImTKXGP6XCOjTwv2LUMos0YWc9O+QP8= +k8s.io/apiextensions-apiserver v0.33.3 h1:qmOcAHN6DjfD0v9kxL5udB27SRP6SG/MTopmge3MwEs= +k8s.io/apiextensions-apiserver v0.33.3/go.mod h1:oROuctgo27mUsyp9+Obahos6CWcMISSAPzQ77CAQGz8= k8s.io/apimachinery v0.0.0-20190809020650-423f5d784010/go.mod h1:Waf/xTS2FGRrgXCkO5FP3XxTOWh0qLf2QhL1qFZZ/R8= k8s.io/apimachinery v0.33.3 h1:4ZSrmNa0c/ZpZJhAgRdcsFcZOw1PQU1bALVQ0B3I5LA= k8s.io/apimachinery v0.33.3/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM= @@ -3665,8 +3666,8 @@ sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HR sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= -sigs.k8s.io/structured-merge-diff/v4 v4.6.0 h1:IUA9nvMmnKWcj5jl84xn+T5MnlZKThmUW1TdblaLVAc= -sigs.k8s.io/structured-merge-diff/v4 v4.6.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps= +sigs.k8s.io/structured-merge-diff/v4 v4.7.0 h1:qPeWmscJcXP0snki5IYF79Z8xrl8ETFxgMd7wez1XkI= +sigs.k8s.io/structured-merge-diff/v4 v4.7.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/go.work.sum b/go.work.sum index 4c6414c6e58..6d9b5c84368 100644 --- a/go.work.sum +++ b/go.work.sum @@ -804,6 +804,7 @@ github.com/elastic/go-windows v1.0.2/go.mod h1:bGcDpBzXgYSqM0Gx3DM4+UxFj300SZLix github.com/elastic/lunes v0.1.0 h1:amRtLPjwkWtzDF/RKzcEPMvSsSseLDLW+bnhfNSLRe4= github.com/elastic/lunes v0.1.0/go.mod h1:xGphYIt3XdZRtyWosHQTErsQTd4OP1p9wsbVoHelrd4= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633 h1:H2pdYOb3KQ1/YsqVWoWNLQO+fusocsw354rqGTZtAgw= +github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/emicklei/proto v1.10.0/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A= github.com/envoyproxy/go-control-plane v0.13.1/go.mod h1:X45hY0mufo6Fd0KW3rqsGvQMw58jvjymeCzBU3mWyHw= github.com/envoyproxy/go-control-plane/envoy v1.32.3/go.mod h1:F6hWupPfh75TBXGKA++MCT/CZHFq5r9/uwt/kQYkZfE= @@ -828,6 +829,7 @@ github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyT github.com/fsouza/fake-gcs-server v1.7.0 h1:Un0BXUXrRWYSmYyC1Rqm2e2WJfTPyDy/HGMz31emTi8= github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= +github.com/getkin/kin-openapi v0.128.0/go.mod h1:OZrfXzUfGrNbsKj+xmFBx6E5c6yH3At/tAKSc2UszXM= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= @@ -988,6 +990,7 @@ github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJr github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0/go.mod h1:qztMSjm835F2bXf+5HKAPIS5qsmQDqZna/PgVt4rWtI= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI= github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645 h1:MJG/KsmcqMwFAkh8mTnAwhyKoB+sTAnY4CACC110tbU= github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645/go.mod h1:6iZfnjpejD4L/4DwD7NryNaJyCQdzwWwH2MWhCA90Kw= github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8= @@ -1226,6 +1229,7 @@ github.com/pquerna/cachecontrol v0.1.0/go.mod h1:NrUG3Z7Rdu85UNR3vm7SOsl1nFIeSiQ github.com/pquerna/ffjson v0.0.0-20190930134022-aa0246cd15f7 h1:xoIK0ctDddBMnc74udxJYBqlo9Ylnsp1waqjLsnef20= github.com/pquerna/ffjson v0.0.0-20190930134022-aa0246cd15f7/go.mod h1:YARuvh7BUWHNhzDq2OM5tzR2RiCcN2D7sapiKyCel/M= github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I= +github.com/prometheus/common v0.64.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8= github.com/prometheus/common/assets v0.2.0 h1:0P5OrzoHrYBOSM1OigWL3mY8ZvV2N4zIE/5AahrSrfM= github.com/prometheus/statsd_exporter v0.26.1 h1:ucbIAdPmwAUcA+dU+Opok8Qt81Aw8HanlO+2N/Wjv7w= github.com/prometheus/statsd_exporter v0.26.1/go.mod h1:XlDdjAmRmx3JVvPPYuFNUg+Ynyb5kR69iPPkQjxXFMk= @@ -1511,32 +1515,51 @@ go.opentelemetry.io/contrib/zpages v0.60.0/go.mod h1:xqfToSRGh2MYUsfyErNz8jnNDPl go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8= go.opentelemetry.io/otel v1.31.0/go.mod h1:O0C14Yl9FgkjqcCZAsE053C13OaddMYr/hz6clDkEJE= +go.opentelemetry.io/otel v1.33.0/go.mod h1:SUUkR6csvUQl+yjReHu5uM3EtVV7MBm5FHKRlNx4I8I= +go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y= +go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E= go.opentelemetry.io/otel/bridge/opencensus v1.35.0 h1:4nJfffRbozhqnuukfRkiahA94mnpryCLJLiduMIDJKI= go.opentelemetry.io/otel/bridge/opencensus v1.35.0/go.mod h1:359S30saRYNsB4A46EDx91SpXsQFNgkma7ftg2/L5/M= go.opentelemetry.io/otel/bridge/opentracing v1.35.0 h1:qT4jl1fYl0hHuRopNcwS94QosLFhGYcS0HacPUeXmT4= go.opentelemetry.io/otel/bridge/opentracing v1.35.0/go.mod h1:p5CbIL4v7uQz7mnQD6T/AZc1pPUzwz+2wZ1zrGY9Kgs= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.36.0/go.mod h1:rUKCPscaRWWcqGT6HnEmYrK+YNe5+Sw64xgQTOJ5b30= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.36.0/go.mod h1:RboSDkp7N292rgu+T0MgVt2qgFGu6qa1RpZDOtpL76w= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.33.0/go.mod h1:cpgtDBaqD/6ok/UG0jT15/uKjAY8mRA53diogHBg3UI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.33.0/go.mod h1:57gTHJSE5S1tqg+EKsLPlTWhpHMsWlVmer+LA926XiA= go.opentelemetry.io/otel/exporters/prometheus v0.58.0/go.mod h1:7qo/4CLI+zYSNbv0GMNquzuss2FVZo3OYrGh96n4HNc= go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.35.0/go.mod h1:U2R3XyVPzn0WX7wOIypPuptulsMcPDPs/oiSVOMVnHY= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.36.0/go.mod h1:PD57idA/AiFD5aqoxGxCvT/ILJPeHy3MjqU/NS7KogY= go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= go.opentelemetry.io/otel/metric v1.29.0/go.mod h1:auu/QWieFVWx+DmQOUMgj0F8LHWdgalxXqvp7BII/W8= go.opentelemetry.io/otel/metric v1.31.0/go.mod h1:C3dEloVbLuYoX41KpmAhOqNriGbA+qqH6PQ5E5mUfnY= +go.opentelemetry.io/otel/metric v1.33.0/go.mod h1:L9+Fyctbp6HFTddIxClbQkjtubW6O9QS3Ann/M82u6M= +go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE= +go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs= go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg= go.opentelemetry.io/otel/sdk v1.29.0/go.mod h1:pM8Dx5WKnvxLCb+8lG1PRNIDxu9g9b9g59Qr7hfAAok= go.opentelemetry.io/otel/sdk v1.31.0/go.mod h1:TfRbMdhvxIIr/B2N2LQW2S5v9m3gOQ/08KsbbO5BPT0= +go.opentelemetry.io/otel/sdk v1.33.0/go.mod h1:A1Q5oi7/9XaMlIWzPSxLRWOI8nG3FnzHJNbiENQuihM= +go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg= +go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY= go.opentelemetry.io/otel/sdk/metric v1.29.0/go.mod h1:6zZLdCl2fkauYoZIOn/soQIDSWFmNSRcICarHfuhNJQ= +go.opentelemetry.io/otel/sdk/metric v1.31.0/go.mod h1:CRInTMVvNhUKgSAMbKyTMxqOBC0zgyxzW55lZzX43Y8= go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w= +go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w= go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4= go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ= go.opentelemetry.io/otel/trace v1.31.0/go.mod h1:TXZkRk7SM2ZQLtR6eoAWQFIHPvzQ06FJAsO1tJg480A= +go.opentelemetry.io/otel/trace v1.33.0/go.mod h1:uIcdVUZMpTAmz0tI1z04GoVSezK37CbGV4fr1f2nBck= +go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc= +go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA= go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= go.opentelemetry.io/proto/otlp v1.4.0/go.mod h1:PPBWZIP98o2ElSqI35IHfu7hIhSwvc5N38Jw8pXuGFY= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs= go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= golang.org/x/arch v0.4.0 h1:A8WCeEWhLwPBKNbFi5Wv5UTCBx5zzubnXDlMOFAzFMc= golang.org/x/arch v0.4.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= @@ -1546,6 +1569,7 @@ golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ug golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ= golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc= +golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw= golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= @@ -1571,14 +1595,22 @@ golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM= golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= +golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= +golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E= +golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= golang.org/x/oauth2 v0.19.0/go.mod h1:vYi7skDa1x015PmRRYZ7+s1cWyPgrPiSYRe4rnsexc8= golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.25.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/oauth2 v0.28.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= +golang.org/x/oauth2 v0.29.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= @@ -1588,12 +1620,19 @@ golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/telemetry v0.0.0-20240521205824-bda55230c457 h1:zf5N6UOrA487eEFacMePxjXAJctxKmyjKUsjA11Uzuk= golang.org/x/telemetry v0.0.0-20240521205824-bda55230c457/go.mod h1:pRgIJT+bRLFKnoM1ldnzKoxTIn14Yxz928LQRYYgIN0= +golang.org/x/telemetry v0.0.0-20250710130107-8d8967aff50b h1:DU+gwOBXU+6bO0sEyO7o/NeMlxZxCZEvI7v+J4a1zRQ= +golang.org/x/telemetry v0.0.0-20250710130107-8d8967aff50b/go.mod h1:4ZwOYna0/zsOKwuR5X/m0QFOJpSZvAxFfkQT+Erd9D4= golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g= golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= +golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU= +golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= @@ -1608,6 +1647,9 @@ golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0= golang.org/x/tools v0.28.0/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw= golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY= +golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI= +golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated h1:1h2MnaIAIXISqTFKdENegdpAgUXz6NrPEsbIeWaBRvM= +golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated/go.mod h1:RVAQXBGNv1ib0J382/DPCRS/BPnsGebyM1Gj5VSDpG8= gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0 h1:OE9mWmgKkjJyEmDAAtGMPjXu+YNeGvK9VTSHY6+Qihc= gonum.org/v1/plot v0.15.2 h1:Tlfh/jBk2tqjLZ4/P8ZIwGrLEWQSPDLRm/SNWKNXiGI= gonum.org/v1/plot v0.15.2/go.mod h1:DX+x+DWso3LTha+AdkJEv5Txvi+Tql3KAGkehP0/Ubg= @@ -1659,6 +1701,7 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576/go. google.golang.org/genproto/googleapis/rpc v0.0.0-20241223144023-3abc09e42ca8/go.mod h1:lcTa1sDdWEIHMWlITnIczmw5w60CF9ffkb8Z+DVmmjA= google.golang.org/genproto/googleapis/rpc v0.0.0-20250106144421-5f5ef82da422/go.mod h1:3ENsm/5D1mzDyhpzeRi1NR784I0BcofWBoSc5QqqMK4= google.golang.org/genproto/googleapis/rpc v0.0.0-20250124145028-65684f501c47/go.mod h1:+2Yz8+CLJbIfL9z73EW45avw8Lmge3xVElCP9zEKi50= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a/go.mod h1:uRxBH1mhmO8PGhU89cMcHaXKZqO+OfakD8QQO0oYwlQ= google.golang.org/genproto/googleapis/rpc v0.0.0-20250227231956-55c901821b1e/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I= google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I= google.golang.org/genproto/googleapis/rpc v0.0.0-20250313205543-e70fdf4c4cb4/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I= @@ -1671,8 +1714,12 @@ google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDom google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= google.golang.org/grpc v1.67.3/go.mod h1:YGaHCc6Oap+FzBJTZLBzkGSYt/cvGPFTPxkn7QfSU8s= google.golang.org/grpc v1.68.1/go.mod h1:+q1XYFJjShcqn0QZHvCyeR4CXPA+llXIeUIfIe00waw= +google.golang.org/grpc v1.69.4/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4= google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw= google.golang.org/grpc v1.71.0/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec= +google.golang.org/grpc v1.71.1/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec= +google.golang.org/grpc v1.72.0/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= +google.golang.org/grpc v1.72.1/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= google.golang.org/grpc v1.72.2/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0 h1:M1YKkFIboKNieVO5DLUEVzQfGwJD30Nv2jfUgzb5UcE= google.golang.org/grpc/examples v0.0.0-20230224211313-3775f633ce20 h1:MLBCGN1O7GzIx+cBiwfYPwtmZ41U3Mn/cotLJciaArI= @@ -1681,6 +1728,7 @@ google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojt google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= google.golang.org/protobuf v1.36.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.36.3/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= google.golang.org/protobuf v1.36.4/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= @@ -1714,6 +1762,7 @@ k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= k8s.io/kube-aggregator v0.33.1/go.mod h1:16/wlU5Lj7hNJSv7JSu5FLvxyrgiJVLCHzfVoECAsuI= k8s.io/kube-aggregator v0.33.2/go.mod h1:qQbliLwcdmx7/8mtvkc/9QV/ON2M6ZBMcffEUmrqKFw= +k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= knative.dev/hack v0.0.0-20250514121446-f525e187efdc h1:8HmclJlA0zNE/G1SkgdC3/IFSSyhaSz2iIhihU6YbEo= knative.dev/hack v0.0.0-20250514121446-f525e187efdc/go.mod h1:R0ritgYtjLDO9527h5vb5X6gfvt5LCrJ55BNbVDsWiY= lukechampine.com/uint128 v1.2.0 h1:mBi/5l91vocEN8otkC5bDLhi2KdCticRiwbdB0O+rjI= @@ -1732,4 +1781,5 @@ rsc.io/sampler v1.3.0 h1:7uVkIFmeBqHfdjD+gZwtXXI+RODJ2Wc4O7MPEh/QiW4= sigs.k8s.io/controller-runtime v0.20.4 h1:X3c+Odnxz+iPTRobG4tp092+CvBU9UK0t/bRf+n0DGU= sigs.k8s.io/controller-runtime v0.20.4/go.mod h1:xg2XB0K5ShQzAgsoujxuKN4LNXR2LfwwHsPj7Iaw+XY= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo= sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e h1:4Z09Hglb792X0kfOBBJUPFEyvVfQWrYT/l8h5EKA6JQ= diff --git a/pkg/aggregator/go.mod b/pkg/aggregator/go.mod index 1afd2ff6257..a6f393daf08 100644 --- a/pkg/aggregator/go.mod +++ b/pkg/aggregator/go.mod @@ -17,11 +17,11 @@ require ( k8s.io/component-base v0.33.3 k8s.io/klog/v2 v2.130.1 k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff - sigs.k8s.io/structured-merge-diff/v4 v4.6.0 + sigs.k8s.io/structured-merge-diff/v4 v4.7.0 ) require ( - cel.dev/expr v0.23.1 // indirect + cel.dev/expr v0.24.0 // indirect github.com/BurntSushi/toml v1.5.0 // indirect github.com/NYTimes/gziphandler v1.1.1 // indirect github.com/antlr4-go/antlr/v4 v4.13.1 // indirect @@ -108,7 +108,7 @@ require ( github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/smartystreets/goconvey v1.6.4 // indirect github.com/spf13/cobra v1.9.1 // indirect - github.com/spf13/pflag v1.0.6 // indirect + github.com/spf13/pflag v1.0.7 // indirect github.com/stoewer/go-strcase v1.3.0 // indirect github.com/stretchr/objx v0.5.2 // indirect github.com/ugorji/go/codec v1.2.11 // indirect @@ -137,22 +137,22 @@ require ( go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect go.yaml.in/yaml/v2 v2.4.2 // indirect - golang.org/x/crypto v0.39.0 // indirect + golang.org/x/crypto v0.40.0 // indirect golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 // indirect - golang.org/x/mod v0.25.0 // indirect - golang.org/x/net v0.41.0 // indirect + golang.org/x/mod v0.26.0 // indirect + golang.org/x/net v0.42.0 // indirect golang.org/x/oauth2 v0.30.0 // indirect golang.org/x/sync v0.16.0 // indirect - golang.org/x/sys v0.33.0 // indirect - golang.org/x/term v0.32.0 // indirect - golang.org/x/text v0.26.0 // indirect + golang.org/x/sys v0.34.0 // indirect + golang.org/x/term v0.33.0 // indirect + golang.org/x/text v0.27.0 // indirect golang.org/x/time v0.11.0 // indirect - golang.org/x/tools v0.34.0 // indirect + golang.org/x/tools v0.35.0 // indirect golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect google.golang.org/genproto v0.0.0-20250603155806-513f23925822 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect - google.golang.org/grpc v1.73.0 // indirect + google.golang.org/grpc v1.74.0 // indirect google.golang.org/protobuf v1.36.6 // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/fsnotify/fsnotify.v1 v1.4.7 // indirect diff --git a/pkg/aggregator/go.sum b/pkg/aggregator/go.sum index 808b8b897c1..ec1d4f04729 100644 --- a/pkg/aggregator/go.sum +++ b/pkg/aggregator/go.sum @@ -1,5 +1,5 @@ -cel.dev/expr v0.23.1 h1:K4KOtPCJQjVggkARsjG9RWXP6O4R73aHeJMa/dmCQQg= -cel.dev/expr v0.23.1/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw= +cel.dev/expr v0.24.0 h1:56OvJKSH3hDGL0ml5uSxZmz3/3Pq4tJ+fb1unVLAFcY= +cel.dev/expr v0.24.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= @@ -291,8 +291,9 @@ github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js= github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= -github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.7 h1:vN6T9TfwStFPFM5XzjsvmzZkLuaLX+HS+0SeFLRgU6M= +github.com/spf13/pflag v1.0.7/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stoewer/go-strcase v1.3.0 h1:g0eASXYtp+yvN9fK8sH94oCIk0fau9uV1/ZdJ0AVEzs= github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -402,8 +403,8 @@ go.yaml.in/yaml/v3 v3.0.3/go.mod h1:tBHosrYAkRZjRAOREWbDnBXUf08JOwYq++0QNwQiWzI= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= -golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= +golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM= +golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 h1:y5zboxd6LQAqYIhHnB48p0ByQ/GnQx2BE33L8BOHQkI= golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6/go.mod h1:U6Lno4MTRCDY+Ba7aCcauB9T60gsv5s4ralQzP72ZoQ= @@ -413,8 +414,8 @@ golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w= -golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= +golang.org/x/mod v0.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg= +golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -424,8 +425,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= -golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= +golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= +golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= @@ -450,14 +451,14 @@ golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= -golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg= -golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= +golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= +golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/term v0.33.0 h1:NuFncQrRcaRvVmgRkvM3j/F00gWIAlcmlB8ACEKmGIg= +golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= -golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= +golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= +golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0= golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -471,8 +472,8 @@ golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo= -golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg= +golang.org/x/tools v0.35.0 h1:mBffYraMEf7aa0sB+NuKnuCy8qI/9Bughn8dC2Gu5r0= +golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -498,8 +499,8 @@ google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyac google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok= -google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc= +google.golang.org/grpc v1.74.0 h1:sxRSkyLxlceWQiqDofxDot3d4u7DyoHPc7SBXMj8gGY= +google.golang.org/grpc v1.74.0/go.mod h1:NZUaK8dAMUfzhK6uxZ+9511LtOrk73UGWOFoNvz7z+s= google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -547,8 +548,8 @@ sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= -sigs.k8s.io/structured-merge-diff/v4 v4.6.0 h1:IUA9nvMmnKWcj5jl84xn+T5MnlZKThmUW1TdblaLVAc= -sigs.k8s.io/structured-merge-diff/v4 v4.6.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps= +sigs.k8s.io/structured-merge-diff/v4 v4.7.0 h1:qPeWmscJcXP0snki5IYF79Z8xrl8ETFxgMd7wez1XkI= +sigs.k8s.io/structured-merge-diff/v4 v4.7.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps= sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= sigs.k8s.io/yaml v1.5.0 h1:M10b2U7aEUY6hRtU870n2VTPgR5RZiL/I6Lcc2F4NUQ= sigs.k8s.io/yaml v1.5.0/go.mod h1:wZs27Rbxoai4C0f8/9urLZtZtF3avA3gKvGyPdDqTO4= diff --git a/pkg/apimachinery/go.mod b/pkg/apimachinery/go.mod index a9b83dc6e00..bdfcc22c5af 100644 --- a/pkg/apimachinery/go.mod +++ b/pkg/apimachinery/go.mod @@ -34,7 +34,7 @@ require ( github.com/patrickmn/go-cache v2.1.0+incompatible // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/rogpeppe/go-internal v1.14.1 // indirect - github.com/spf13/pflag v1.0.6 // indirect + github.com/spf13/pflag v1.0.7 // indirect github.com/stretchr/objx v0.5.2 // indirect github.com/x448/float16 v0.8.4 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect @@ -43,18 +43,18 @@ require ( go.opentelemetry.io/otel/sdk/metric v1.37.0 // indirect go.opentelemetry.io/otel/trace v1.37.0 // indirect go.yaml.in/yaml/v2 v2.4.2 // indirect - golang.org/x/crypto v0.39.0 // indirect - golang.org/x/net v0.41.0 // indirect + golang.org/x/crypto v0.40.0 // indirect + golang.org/x/net v0.42.0 // indirect golang.org/x/sync v0.16.0 // indirect - golang.org/x/sys v0.33.0 // indirect - golang.org/x/text v0.26.0 // indirect + golang.org/x/sys v0.34.0 // indirect + golang.org/x/text v0.27.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect - google.golang.org/grpc v1.73.0 // indirect + google.golang.org/grpc v1.74.0 // indirect google.golang.org/protobuf v1.36.6 // indirect gopkg.in/inf.v0 v0.9.1 // indirect k8s.io/klog/v2 v2.130.1 // indirect sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect sigs.k8s.io/randfill v1.0.0 // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.7.0 // indirect sigs.k8s.io/yaml v1.5.0 // indirect ) diff --git a/pkg/apimachinery/go.sum b/pkg/apimachinery/go.sum index b814304bcc7..63fa5245e75 100644 --- a/pkg/apimachinery/go.sum +++ b/pkg/apimachinery/go.sum @@ -63,8 +63,8 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= -github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= -github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.7 h1:vN6T9TfwStFPFM5XzjsvmzZkLuaLX+HS+0SeFLRgU6M= +github.com/spf13/pflag v1.0.7/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= @@ -96,8 +96,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= -golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= -golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= +golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM= +golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= @@ -110,8 +110,8 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= -golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= +golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= +golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -129,8 +129,8 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= -golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= +golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= @@ -142,8 +142,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= -golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= +golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= +golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= @@ -156,8 +156,8 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 h1:fc6jSaCT0vBduLYZHYrBBNY4dsWuvgyff9noRNDdBeE= google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= -google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok= -google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc= +google.golang.org/grpc v1.74.0 h1:sxRSkyLxlceWQiqDofxDot3d4u7DyoHPc7SBXMj8gGY= +google.golang.org/grpc v1.74.0/go.mod h1:NZUaK8dAMUfzhK6uxZ+9511LtOrk73UGWOFoNvz7z+s= google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -183,8 +183,8 @@ sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= -sigs.k8s.io/structured-merge-diff/v4 v4.6.0 h1:IUA9nvMmnKWcj5jl84xn+T5MnlZKThmUW1TdblaLVAc= -sigs.k8s.io/structured-merge-diff/v4 v4.6.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps= +sigs.k8s.io/structured-merge-diff/v4 v4.7.0 h1:qPeWmscJcXP0snki5IYF79Z8xrl8ETFxgMd7wez1XkI= +sigs.k8s.io/structured-merge-diff/v4 v4.7.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps= sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= sigs.k8s.io/yaml v1.5.0 h1:M10b2U7aEUY6hRtU870n2VTPgR5RZiL/I6Lcc2F4NUQ= sigs.k8s.io/yaml v1.5.0/go.mod h1:wZs27Rbxoai4C0f8/9urLZtZtF3avA3gKvGyPdDqTO4= diff --git a/pkg/apiserver/go.mod b/pkg/apiserver/go.mod index 3d1557516a4..a40429d1f8d 100644 --- a/pkg/apiserver/go.mod +++ b/pkg/apiserver/go.mod @@ -5,7 +5,7 @@ go 1.24.5 require ( github.com/google/go-cmp v0.7.0 github.com/grafana/authlib/types v0.0.0-20250710201142-9542f2f28d43 - github.com/grafana/grafana-app-sdk/logging v0.39.3 + github.com/grafana/grafana-app-sdk/logging v0.40.0 github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250514132646-acbc7b54ed9e github.com/prometheus/client_golang v1.22.0 github.com/stretchr/testify v1.10.0 @@ -17,7 +17,7 @@ require ( k8s.io/component-base v0.33.3 k8s.io/klog/v2 v2.130.1 k8s.io/utils v0.0.0-20241210054802-24370beab758 - sigs.k8s.io/structured-merge-diff/v4 v4.6.0 + sigs.k8s.io/structured-merge-diff/v4 v4.7.0 ) require ( @@ -64,7 +64,7 @@ require ( github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/common v0.65.0 // indirect github.com/prometheus/procfs v0.16.1 // indirect - github.com/spf13/pflag v1.0.6 // indirect + github.com/spf13/pflag v1.0.7 // indirect github.com/stretchr/objx v0.5.2 // indirect github.com/x448/float16 v0.8.4 // indirect go.etcd.io/bbolt v1.4.0 // indirect @@ -82,19 +82,19 @@ require ( go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect go.yaml.in/yaml/v2 v2.4.2 // indirect - golang.org/x/crypto v0.39.0 // indirect - golang.org/x/net v0.41.0 // indirect + golang.org/x/crypto v0.40.0 // indirect + golang.org/x/net v0.42.0 // indirect golang.org/x/oauth2 v0.30.0 // indirect golang.org/x/sync v0.16.0 // indirect - golang.org/x/sys v0.33.0 // indirect - golang.org/x/term v0.32.0 // indirect - golang.org/x/text v0.26.0 // indirect + golang.org/x/sys v0.34.0 // indirect + golang.org/x/term v0.33.0 // indirect + golang.org/x/text v0.27.0 // indirect golang.org/x/time v0.11.0 // indirect - golang.org/x/tools v0.34.0 // indirect + golang.org/x/tools v0.35.0 // indirect google.golang.org/genproto v0.0.0-20250603155806-513f23925822 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect - google.golang.org/grpc v1.73.0 // indirect + google.golang.org/grpc v1.74.0 // indirect google.golang.org/protobuf v1.36.6 // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect diff --git a/pkg/apiserver/go.sum b/pkg/apiserver/go.sum index 369b533e3a1..2b015943a28 100644 --- a/pkg/apiserver/go.sum +++ b/pkg/apiserver/go.sum @@ -84,8 +84,8 @@ github.com/grafana/authlib/types v0.0.0-20250710201142-9542f2f28d43 h1:NlkGMnVi/ github.com/grafana/authlib/types v0.0.0-20250710201142-9542f2f28d43/go.mod h1:qeWYbnWzaYGl88JlL9+DsP1GT2Cudm58rLtx13fKZdw= github.com/grafana/dskit v0.0.0-20250611075409-46f51e1ce914 h1:qcSGhr691f1mmPHwg2svGyO40Ex92G02aOyHzP6XHCE= github.com/grafana/dskit v0.0.0-20250611075409-46f51e1ce914/go.mod h1:OiN4P4aC6LwLzLbEupH3Ue83VfQoNMfG48rsna8jI/E= -github.com/grafana/grafana-app-sdk/logging v0.39.3 h1:mMrcYahnoRu7blKyL/ZVcgv7WCiI2CqxODYh8tBFUgY= -github.com/grafana/grafana-app-sdk/logging v0.39.3/go.mod h1:otUD9XpJD7A5sCLb8mcs9hIXGdeV6lnhzVwe747g4RU= +github.com/grafana/grafana-app-sdk/logging v0.40.0 h1:3LHA0pFM9mGGFyq6qoHvJOGEe0H0OVhzzlOKd4Ehu+E= +github.com/grafana/grafana-app-sdk/logging v0.40.0/go.mod h1:otUD9XpJD7A5sCLb8mcs9hIXGdeV6lnhzVwe747g4RU= github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250514132646-acbc7b54ed9e h1:BTKk7LHuG1kmAkucwTA7DuMbKpKvJTKrGdBmUNO4dfQ= github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250514132646-acbc7b54ed9e/go.mod h1:IA4SOwun8QyST9c5UNs/fN37XL6boXXDvRYFcFwbipg= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= @@ -160,8 +160,8 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js= github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= -github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= -github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.7 h1:vN6T9TfwStFPFM5XzjsvmzZkLuaLX+HS+0SeFLRgU6M= +github.com/spf13/pflag v1.0.7/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= @@ -240,8 +240,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= -golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= -golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= +golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM= +golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= @@ -264,8 +264,8 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= -golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= +golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= +golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= @@ -291,23 +291,23 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= -golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= +golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= -golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg= -golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= +golang.org/x/term v0.33.0 h1:NuFncQrRcaRvVmgRkvM3j/F00gWIAlcmlB8ACEKmGIg= +golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= -golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= +golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= +golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0= golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -322,8 +322,8 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo= -golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg= +golang.org/x/tools v0.35.0 h1:mBffYraMEf7aa0sB+NuKnuCy8qI/9Bughn8dC2Gu5r0= +golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -345,8 +345,8 @@ google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyac google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok= -google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc= +google.golang.org/grpc v1.74.0 h1:sxRSkyLxlceWQiqDofxDot3d4u7DyoHPc7SBXMj8gGY= +google.golang.org/grpc v1.74.0/go.mod h1:NZUaK8dAMUfzhK6uxZ+9511LtOrk73UGWOFoNvz7z+s= google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -391,8 +391,8 @@ sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= -sigs.k8s.io/structured-merge-diff/v4 v4.6.0 h1:IUA9nvMmnKWcj5jl84xn+T5MnlZKThmUW1TdblaLVAc= -sigs.k8s.io/structured-merge-diff/v4 v4.6.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps= +sigs.k8s.io/structured-merge-diff/v4 v4.7.0 h1:qPeWmscJcXP0snki5IYF79Z8xrl8ETFxgMd7wez1XkI= +sigs.k8s.io/structured-merge-diff/v4 v4.7.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps= sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= sigs.k8s.io/yaml v1.5.0 h1:M10b2U7aEUY6hRtU870n2VTPgR5RZiL/I6Lcc2F4NUQ= sigs.k8s.io/yaml v1.5.0/go.mod h1:wZs27Rbxoai4C0f8/9urLZtZtF3avA3gKvGyPdDqTO4= diff --git a/pkg/build/go.mod b/pkg/build/go.mod index 14dd91a5033..a10b831a97a 100644 --- a/pkg/build/go.mod +++ b/pkg/build/go.mod @@ -25,14 +25,14 @@ require ( go.opentelemetry.io/otel v1.37.0 // @grafana/grafana-backend-group go.opentelemetry.io/otel/sdk v1.37.0 // indirect; @grafana/grafana-backend-group go.opentelemetry.io/otel/trace v1.37.0 // @grafana/grafana-backend-group - golang.org/x/crypto v0.39.0 // indirect; @grafana/grafana-backend-group - golang.org/x/net v0.41.0 // indirect; @grafana/oss-big-tent @grafana/partner-datasources + golang.org/x/crypto v0.40.0 // indirect; @grafana/grafana-backend-group + golang.org/x/net v0.42.0 // indirect; @grafana/oss-big-tent @grafana/partner-datasources golang.org/x/oauth2 v0.30.0 // @grafana/identity-access-team golang.org/x/sync v0.16.0 // @grafana/alerting-backend - golang.org/x/text v0.26.0 // indirect; @grafana/grafana-backend-group + golang.org/x/text v0.27.0 // indirect; @grafana/grafana-backend-group golang.org/x/time v0.11.0 // indirect; @grafana/grafana-backend-group google.golang.org/api v0.235.0 // @grafana/grafana-backend-group - google.golang.org/grpc v1.73.0 // indirect; @grafana/plugins-platform-backend + google.golang.org/grpc v1.74.0 // indirect; @grafana/plugins-platform-backend google.golang.org/protobuf v1.36.6 // indirect; @grafana/plugins-platform-backend gopkg.in/yaml.v3 v3.0.1 // @grafana/alerting-backend ) @@ -70,7 +70,7 @@ require ( go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 // indirect go.opentelemetry.io/otel/metric v1.37.0 // indirect go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect - golang.org/x/sys v0.33.0 // indirect + golang.org/x/sys v0.34.0 // indirect google.golang.org/genproto v0.0.0-20250603155806-513f23925822 // indirect; @grafana/grafana-backend-group google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect @@ -86,7 +86,7 @@ require ( ) require ( - cel.dev/expr v0.23.1 // indirect + cel.dev/expr v0.24.0 // indirect cloud.google.com/go/monitoring v1.24.2 // indirect github.com/99designs/gqlgen v0.17.73 // indirect github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect @@ -97,7 +97,7 @@ require ( github.com/adrg/xdg v0.5.3 // indirect github.com/cenkalti/backoff/v5 v5.0.2 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect - github.com/cncf/xds/go v0.0.0-20250326154945-ae57f3c0d45f // indirect + github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443 // indirect github.com/containerd/log v0.1.0 // indirect github.com/distribution/reference v0.6.0 // indirect github.com/envoyproxy/go-control-plane/envoy v1.32.4 // indirect diff --git a/pkg/build/go.sum b/pkg/build/go.sum index 9392a9616ff..ead0b353d86 100644 --- a/pkg/build/go.sum +++ b/pkg/build/go.sum @@ -1,5 +1,5 @@ -cel.dev/expr v0.23.1 h1:K4KOtPCJQjVggkARsjG9RWXP6O4R73aHeJMa/dmCQQg= -cel.dev/expr v0.23.1/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw= +cel.dev/expr v0.24.0 h1:56OvJKSH3hDGL0ml5uSxZmz3/3Pq4tJ+fb1unVLAFcY= +cel.dev/expr v0.24.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.121.1 h1:S3kTQSydxmu1JfLRLpKtxRPA7rSrYPRPEUmL/PavVUw= cloud.google.com/go v0.121.1/go.mod h1:nRFlrHq39MNVWu+zESP2PosMWA0ryJw8KUBZ2iZpxbw= @@ -72,8 +72,8 @@ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5P github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cncf/xds/go v0.0.0-20250326154945-ae57f3c0d45f h1:C5bqEmzEPLsHm9Mv73lSE9e9bKV23aB1vxOsmZrkl3k= -github.com/cncf/xds/go v0.0.0-20250326154945-ae57f3c0d45f/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= +github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443 h1:aQ3y1lwWyqYPiWZThqv1aFbZMiM9vblcSArJRf2Irls= +github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= github.com/containerd/containerd v1.3.4/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= @@ -311,8 +311,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= -golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= +golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM= +golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= @@ -327,8 +327,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= -golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= +golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= +golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= @@ -348,13 +348,13 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= -golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= +golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= -golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= +golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= +golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0= golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= @@ -388,8 +388,8 @@ google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyac google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok= -google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc= +google.golang.org/grpc v1.74.0 h1:sxRSkyLxlceWQiqDofxDot3d4u7DyoHPc7SBXMj8gGY= +google.golang.org/grpc v1.74.0/go.mod h1:NZUaK8dAMUfzhK6uxZ+9511LtOrk73UGWOFoNvz7z+s= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= diff --git a/pkg/build/wire/go.mod b/pkg/build/wire/go.mod index 7035d2469ac..5d0be4a4925 100644 --- a/pkg/build/wire/go.mod +++ b/pkg/build/wire/go.mod @@ -6,10 +6,10 @@ require ( github.com/google/go-cmp v0.7.0 github.com/google/subcommands v1.2.0 github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 - golang.org/x/tools v0.34.0 + golang.org/x/tools v0.35.0 ) require ( - golang.org/x/mod v0.25.0 // indirect + golang.org/x/mod v0.26.0 // indirect golang.org/x/sync v0.16.0 // indirect ) diff --git a/pkg/build/wire/go.sum b/pkg/build/wire/go.sum index dd031067566..fb5c52b3f8c 100644 --- a/pkg/build/wire/go.sum +++ b/pkg/build/wire/go.sum @@ -4,9 +4,9 @@ github.com/google/subcommands v1.2.0 h1:vWQspBTo2nEqTUFita5/KeEWlUL8kQObDFbub/EN github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w= -golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= +golang.org/x/mod v0.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg= +golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ= golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= -golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo= -golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg= +golang.org/x/tools v0.35.0 h1:mBffYraMEf7aa0sB+NuKnuCy8qI/9Bughn8dC2Gu5r0= +golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw= diff --git a/pkg/codegen/go.mod b/pkg/codegen/go.mod index 53ead74b2a5..c35ceba70d0 100644 --- a/pkg/codegen/go.mod +++ b/pkg/codegen/go.mod @@ -6,10 +6,10 @@ require ( cuelang.org/go v0.11.1 github.com/dave/dst v0.27.3 github.com/grafana/codejen v0.0.4-0.20230321061741-77f656893a3d - github.com/grafana/cog v0.0.36 + github.com/grafana/cog v0.0.37 github.com/grafana/cuetsy v0.1.11 github.com/matryer/is v1.4.1 - golang.org/x/tools v0.34.0 + golang.org/x/tools v0.35.0 ) require ( @@ -22,7 +22,7 @@ require ( github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/swag v0.23.0 // indirect github.com/go-test/deep v1.1.1 // indirect - github.com/golang/glog v1.2.4 // indirect + github.com/golang/glog v1.2.5 // indirect github.com/google/go-cmp v0.7.0 // indirect github.com/google/uuid v1.6.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect @@ -46,10 +46,10 @@ require ( github.com/ugorji/go/codec v1.2.11 // indirect github.com/xlab/treeprint v1.2.0 // indirect github.com/yalue/merged_fs v1.3.0 // indirect - golang.org/x/mod v0.25.0 // indirect - golang.org/x/net v0.41.0 // indirect + golang.org/x/mod v0.26.0 // indirect + golang.org/x/net v0.42.0 // indirect golang.org/x/sync v0.16.0 // indirect - golang.org/x/text v0.26.0 // indirect + golang.org/x/text v0.27.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/pkg/codegen/go.sum b/pkg/codegen/go.sum index 3eeaf7e9d53..8ee24b96514 100644 --- a/pkg/codegen/go.sum +++ b/pkg/codegen/go.sum @@ -22,8 +22,8 @@ github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U= github.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v1.2.4 h1:CNNw5U8lSiiBk7druxtSHHTsRWcxKoac6kZKm2peBBc= -github.com/golang/glog v1.2.4/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= +github.com/golang/glog v1.2.5 h1:DrW6hGnjIhtvhOIiAKT6Psh/Kd/ldepEa81DKeiRJ5I= +github.com/golang/glog v1.2.5/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= @@ -31,8 +31,8 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/grafana/codejen v0.0.4-0.20230321061741-77f656893a3d h1:hrXbGJ5jgp6yNITzs5o+zXq0V5yT3siNJ+uM8LGwWKk= github.com/grafana/codejen v0.0.4-0.20230321061741-77f656893a3d/go.mod h1:zmwwM/DRyQB7pfuBjTWII3CWtxcXh8LTwAYGfDfpR6s= -github.com/grafana/cog v0.0.36 h1:5kijtkHRzabhCG+ck4sCAEtYp2luaBK8v1CrUHcQ0Es= -github.com/grafana/cog v0.0.36/go.mod h1:UDstzYqMdgIROmbfkHL8fB9XWQO2lnf5z+4W/eJo4Dc= +github.com/grafana/cog v0.0.37 h1:gNyyhP2ZDkLv83N15rUrjNv7ud2JxWIrcF3J58MFI2U= +github.com/grafana/cog v0.0.37/go.mod h1:UDstzYqMdgIROmbfkHL8fB9XWQO2lnf5z+4W/eJo4Dc= github.com/grafana/cue v0.0.0-20230926092038-971951014e3f h1:TmYAMnqg3d5KYEAaT6PtTguL2GjLfvr6wnAX8Azw6tQ= github.com/grafana/cue v0.0.0-20230926092038-971951014e3f/go.mod h1:okjJBHFQFer+a41sAe2SaGm1glWS8oEb6CmJvn5Zdws= github.com/grafana/cuetsy v0.1.11 h1:I3IwBhF+UaQxRM79HnImtrAn8REGdb5M3+C4QrYHoWk= @@ -98,16 +98,16 @@ github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ= github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= github.com/yalue/merged_fs v1.3.0 h1:qCeh9tMPNy/i8cwDsQTJ5bLr6IRxbs6meakNE5O+wyY= github.com/yalue/merged_fs v1.3.0/go.mod h1:WqqchfVYQyclV2tnR7wtRhBddzBvLVR83Cjw9BKQw0M= -golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w= -golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= -golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= -golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= +golang.org/x/mod v0.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg= +golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ= +golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= +golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= -golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= -golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= -golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo= -golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg= +golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= +golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= +golang.org/x/tools v0.35.0 h1:mBffYraMEf7aa0sB+NuKnuCy8qI/9Bughn8dC2Gu5r0= +golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/pkg/plugins/codegen/go.mod b/pkg/plugins/codegen/go.mod index 61c8befdbba..538918b3076 100644 --- a/pkg/plugins/codegen/go.mod +++ b/pkg/plugins/codegen/go.mod @@ -7,7 +7,7 @@ replace github.com/grafana/grafana/pkg/codegen => ../../codegen require ( cuelang.org/go v0.11.1 github.com/grafana/codejen v0.0.4-0.20230321061741-77f656893a3d - github.com/grafana/cog v0.0.36 + github.com/grafana/cog v0.0.37 github.com/grafana/cuetsy v0.1.11 github.com/grafana/grafana/pkg/codegen v0.0.0-20250514132646-acbc7b54ed9e ) @@ -42,11 +42,11 @@ require ( github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 // indirect github.com/xlab/treeprint v1.2.0 // indirect github.com/yalue/merged_fs v1.3.0 // indirect - golang.org/x/mod v0.25.0 // indirect - golang.org/x/net v0.41.0 // indirect + golang.org/x/mod v0.26.0 // indirect + golang.org/x/net v0.42.0 // indirect golang.org/x/oauth2 v0.27.0 // indirect golang.org/x/sync v0.16.0 // indirect - golang.org/x/text v0.26.0 // indirect - golang.org/x/tools v0.34.0 // indirect + golang.org/x/text v0.27.0 // indirect + golang.org/x/tools v0.35.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/pkg/plugins/codegen/go.sum b/pkg/plugins/codegen/go.sum index edb0ad11554..709efab9dd3 100644 --- a/pkg/plugins/codegen/go.sum +++ b/pkg/plugins/codegen/go.sum @@ -30,8 +30,8 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/grafana/codejen v0.0.4-0.20230321061741-77f656893a3d h1:hrXbGJ5jgp6yNITzs5o+zXq0V5yT3siNJ+uM8LGwWKk= github.com/grafana/codejen v0.0.4-0.20230321061741-77f656893a3d/go.mod h1:zmwwM/DRyQB7pfuBjTWII3CWtxcXh8LTwAYGfDfpR6s= -github.com/grafana/cog v0.0.36 h1:5kijtkHRzabhCG+ck4sCAEtYp2luaBK8v1CrUHcQ0Es= -github.com/grafana/cog v0.0.36/go.mod h1:UDstzYqMdgIROmbfkHL8fB9XWQO2lnf5z+4W/eJo4Dc= +github.com/grafana/cog v0.0.37 h1:gNyyhP2ZDkLv83N15rUrjNv7ud2JxWIrcF3J58MFI2U= +github.com/grafana/cog v0.0.37/go.mod h1:UDstzYqMdgIROmbfkHL8fB9XWQO2lnf5z+4W/eJo4Dc= github.com/grafana/cuetsy v0.1.11 h1:I3IwBhF+UaQxRM79HnImtrAn8REGdb5M3+C4QrYHoWk= github.com/grafana/cuetsy v0.1.11/go.mod h1:Ix97+CPD8ws9oSSxR3/Lf4ahU1I4Np83kjJmDVnLZvc= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -92,20 +92,20 @@ github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ= github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= github.com/yalue/merged_fs v1.3.0 h1:qCeh9tMPNy/i8cwDsQTJ5bLr6IRxbs6meakNE5O+wyY= github.com/yalue/merged_fs v1.3.0/go.mod h1:WqqchfVYQyclV2tnR7wtRhBddzBvLVR83Cjw9BKQw0M= -golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w= -golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= -golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= -golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= +golang.org/x/mod v0.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg= +golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ= +golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= +golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= golang.org/x/oauth2 v0.27.0 h1:da9Vo7/tDv5RH/7nZDz1eMGS/q1Vv1N/7FCrBhI9I3M= golang.org/x/oauth2 v0.27.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= -golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= -golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= -golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= -golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo= -golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg= +golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= +golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= +golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= +golang.org/x/tools v0.35.0 h1:mBffYraMEf7aa0sB+NuKnuCy8qI/9Bughn8dC2Gu5r0= +golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= diff --git a/pkg/promlib/go.mod b/pkg/promlib/go.mod index 3f16895acd4..4839a4f96d5 100644 --- a/pkg/promlib/go.mod +++ b/pkg/promlib/go.mod @@ -92,7 +92,7 @@ require ( github.com/rogpeppe/go-internal v1.14.1 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/smartystreets/goconvey v1.6.4 // indirect - github.com/spf13/pflag v1.0.6 // indirect + github.com/spf13/pflag v1.0.7 // indirect github.com/ugorji/go/codec v1.2.11 // indirect github.com/unknwon/bra v0.0.0-20200517080246-1e3013ecaff8 // indirect github.com/unknwon/com v1.0.1 // indirect @@ -117,17 +117,17 @@ require ( go.uber.org/atomic v1.11.0 // indirect go.yaml.in/yaml/v2 v2.4.2 // indirect golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 // indirect - golang.org/x/mod v0.25.0 // indirect - golang.org/x/net v0.41.0 // indirect + golang.org/x/mod v0.26.0 // indirect + golang.org/x/net v0.42.0 // indirect golang.org/x/sync v0.16.0 // indirect - golang.org/x/sys v0.33.0 // indirect - golang.org/x/text v0.26.0 // indirect - golang.org/x/tools v0.34.0 // indirect + golang.org/x/sys v0.34.0 // indirect + golang.org/x/text v0.27.0 // indirect + golang.org/x/tools v0.35.0 // indirect golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect google.golang.org/api v0.235.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect - google.golang.org/grpc v1.73.0 // indirect + google.golang.org/grpc v1.74.0 // indirect gopkg.in/fsnotify/fsnotify.v1 v1.4.7 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect @@ -137,6 +137,6 @@ require ( k8s.io/utils v0.0.0-20241210054802-24370beab758 // indirect sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect sigs.k8s.io/randfill v1.0.0 // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.7.0 // indirect sigs.k8s.io/yaml v1.5.0 // indirect ) diff --git a/pkg/promlib/go.sum b/pkg/promlib/go.sum index f670db8ec6d..47b36a87ee2 100644 --- a/pkg/promlib/go.sum +++ b/pkg/promlib/go.sum @@ -274,8 +274,8 @@ github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304/go.mod h1 github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= -github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.7 h1:vN6T9TfwStFPFM5XzjsvmzZkLuaLX+HS+0SeFLRgU6M= +github.com/spf13/pflag v1.0.7/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= @@ -353,21 +353,21 @@ go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= -golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= +golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM= +golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY= golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 h1:y5zboxd6LQAqYIhHnB48p0ByQ/GnQx2BE33L8BOHQkI= golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6/go.mod h1:U6Lno4MTRCDY+Ba7aCcauB9T60gsv5s4ralQzP72ZoQ= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w= -golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= +golang.org/x/mod v0.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg= +golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= -golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= +golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= +golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -386,12 +386,12 @@ golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= -golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= +golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= -golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= +golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= +golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0= golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -399,8 +399,8 @@ golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo= -golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg= +golang.org/x/tools v0.35.0 h1:mBffYraMEf7aa0sB+NuKnuCy8qI/9Bughn8dC2Gu5r0= +golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -415,8 +415,8 @@ google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 h1: google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822/go.mod h1:h3c4v36UTKzUiuaOKQ6gr3S+0hovBtUrXzTG/i3+XEc= google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 h1:fc6jSaCT0vBduLYZHYrBBNY4dsWuvgyff9noRNDdBeE= google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= -google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok= -google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc= +google.golang.org/grpc v1.74.0 h1:sxRSkyLxlceWQiqDofxDot3d4u7DyoHPc7SBXMj8gGY= +google.golang.org/grpc v1.74.0/go.mod h1:NZUaK8dAMUfzhK6uxZ+9511LtOrk73UGWOFoNvz7z+s= google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -447,8 +447,8 @@ sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= -sigs.k8s.io/structured-merge-diff/v4 v4.6.0 h1:IUA9nvMmnKWcj5jl84xn+T5MnlZKThmUW1TdblaLVAc= -sigs.k8s.io/structured-merge-diff/v4 v4.6.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps= +sigs.k8s.io/structured-merge-diff/v4 v4.7.0 h1:qPeWmscJcXP0snki5IYF79Z8xrl8ETFxgMd7wez1XkI= +sigs.k8s.io/structured-merge-diff/v4 v4.7.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps= sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= sigs.k8s.io/yaml v1.5.0 h1:M10b2U7aEUY6hRtU870n2VTPgR5RZiL/I6Lcc2F4NUQ= sigs.k8s.io/yaml v1.5.0/go.mod h1:wZs27Rbxoai4C0f8/9urLZtZtF3avA3gKvGyPdDqTO4= From a3c96b6eedfae2bec7aea51cb33729988200041d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 28 Jul 2025 12:54:17 +0000 Subject: [PATCH 046/131] Update dependency @grafana/assistant to v0.0.11 (#108788) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 4b25b18298f..f647fe32435 100644 --- a/package.json +++ b/package.json @@ -272,7 +272,7 @@ "@formatjs/intl-durationformat": "^0.7.0", "@glideapps/glide-data-grid": "^6.0.0", "@grafana/alerting": "workspace:*", - "@grafana/assistant": "0.0.10", + "@grafana/assistant": "0.0.11", "@grafana/aws-sdk": "0.7.1", "@grafana/azure-sdk": "0.0.7", "@grafana/data": "workspace:*", diff --git a/yarn.lock b/yarn.lock index 1b13a8fb3de..99cfd2d8de6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3064,9 +3064,9 @@ __metadata: languageName: unknown linkType: soft -"@grafana/assistant@npm:0.0.10": - version: 0.0.10 - resolution: "@grafana/assistant@npm:0.0.10" +"@grafana/assistant@npm:0.0.11": + version: 0.0.11 + resolution: "@grafana/assistant@npm:0.0.11" peerDependencies: "@grafana/data": ">=12.1.0" "@grafana/runtime": ">=12.1.0" @@ -3074,7 +3074,7 @@ __metadata: "@grafana/ui": ">=12.1.0" react: ">=18.0.0" rxjs: ">=7.0.0" - checksum: 10/4b5f0ea03e8cebba07285d4f2ea642211acde0e70207e11456640169fd32d6c550fd3be9256ca41266438237d129b28446981efaa2399e20c2cce064080c1e04 + checksum: 10/2072d4ae6f07e45d92aa62c9785f65dc119abf1f0dc89539cc15ba4b49d6652c356dd3919ba5c8e3f8d34991150d83b6e62167edf17f38e09a67b8ade59a3358 languageName: node linkType: hard @@ -18148,7 +18148,7 @@ __metadata: "@formatjs/intl-durationformat": "npm:^0.7.0" "@glideapps/glide-data-grid": "npm:^6.0.0" "@grafana/alerting": "workspace:*" - "@grafana/assistant": "npm:0.0.10" + "@grafana/assistant": "npm:0.0.11" "@grafana/aws-sdk": "npm:0.7.1" "@grafana/azure-sdk": "npm:0.0.7" "@grafana/data": "workspace:*" From f7523f03bc71f14b67fc9318cdc435cc5403eb44 Mon Sep 17 00:00:00 2001 From: Luminessa Starlight Date: Mon, 28 Jul 2025 09:08:35 -0400 Subject: [PATCH 047/131] TimeRangePicker: new date range format respecting timezone (#108616) * replace new mapper additional code with new rangeUtil.describeTimeRange * add some function descriptions * add regression tests for timezone-respecting range mapping * remove unused import --- .../TimeRangePicker/mapper.test.ts | 109 ++++++++++++++++++ .../DateTimePickers/TimeRangePicker/mapper.ts | 27 ++--- 2 files changed, 117 insertions(+), 19 deletions(-) create mode 100644 packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/mapper.test.ts diff --git a/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/mapper.test.ts b/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/mapper.test.ts new file mode 100644 index 00000000000..ca6d26b22fa --- /dev/null +++ b/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/mapper.test.ts @@ -0,0 +1,109 @@ +import { set } from 'lodash'; + +import { DateTime, dateTimeParse, FeatureToggles } from '@grafana/data'; +import { initRegionalFormatForTests } from '@grafana/i18n'; + +import * as commonFormatModule from '../commonFormat'; + +import { mapOptionToTimeRange, mapRangeToTimeOption } from './mapper'; + +// If this flag is deleted, this mock also should be, and the additional tests for when +// the flag was disabled. +type LocaleFormatPreferenceType = FeatureToggles['localeFormatPreference']; +jest.mock('../commonFormat', () => { + const format = 'YYYY-MM-DD HH:mm:ss' as const; + const moduleObject = { + __esModule: true, + commonFormat: format as undefined | 'YYYY-MM-DD HH:mm:ss', + mockSetCommonFormat, + }; + function mockSetCommonFormat(enabled: LocaleFormatPreferenceType = true) { + moduleObject.commonFormat = enabled ? format : undefined; + } + return moduleObject; +}); +// @ts-expect-error mockSetCommonFormat doesn't exist on the export type of commonFormat, +// but it's added above in the mock. +const mockSetCommonFormat: (enabled: LocaleFormatPreferenceType) => void = commonFormatModule.mockSetCommonFormat; + +function setRegionalFormatToggle(enabled: LocaleFormatPreferenceType) { + mockSetCommonFormat(enabled); + set(window, 'grafanaBootData.settings.featureToggles.localeFormatPreference', enabled); +} + +beforeAll(() => { + initRegionalFormatForTests('en-AU'); +}); + +beforeEach(() => { + setRegionalFormatToggle(true); +}); + +describe('when mapOptionToTimeRange is passed a TimeOption and timezone', () => { + it('returns the equivalent TimeRange', () => { + const result = mapOptionToTimeRange( + { + from: '2025-04-13 04:13:14', + to: '2025-04-13 05:14:15', + display: '13/04/25, 4:13:14 am - 5:14:15 am', + }, + 'America/New_York' + ); + + function toISOStringIfDate(date: string | DateTime) { + return typeof date === 'string' ? date : date.toISOString(); + } + expect(result.from.toISOString()).toBe('2025-04-13T08:13:14.000Z'); + expect(result.to.toISOString()).toBe('2025-04-13T09:14:15.000Z'); + expect(toISOStringIfDate(result.raw.from)).toBe('2025-04-13T08:13:14.000Z'); + expect(toISOStringIfDate(result.raw.to)).toBe('2025-04-13T09:14:15.000Z'); + }); +}); + +describe('when mapRangeToTimeOption is passed a TimeRange and timezone', () => { + it('returns the equivalent TimeOption', () => { + expect( + mapRangeToTimeOption( + { + from: dateTimeParse('2025-04-13T08:13:14Z'), + to: dateTimeParse('2025-04-13T09:14:15Z'), + raw: { + from: dateTimeParse('2025-04-13T08:13:14Z'), + to: dateTimeParse('2025-04-13T09:14:15Z'), + }, + }, + 'America/New_York' + ) + ).toStrictEqual({ + from: '2025-04-13 04:13:14', + to: '2025-04-13 05:14:15', + display: '13/4/25, 4:13:14 am – 5:14:15 am', // "narrow no-break space"s, and "en dash" are the odd characters + }); + }); + + describe('and localeFormatPreference flag is off', () => { + beforeEach(() => { + setRegionalFormatToggle(false); + }); + + it('returns the equivalent TimeOption', () => { + expect( + mapRangeToTimeOption( + { + from: dateTimeParse('2025-04-13T08:13:14Z'), + to: dateTimeParse('2025-04-13T09:14:15Z'), + raw: { + from: dateTimeParse('2025-04-13T08:13:14Z'), + to: dateTimeParse('2025-04-13T09:14:15Z'), + }, + }, + 'America/New_York' + ) + ).toStrictEqual({ + from: '2025-04-13 04:13:14', + to: '2025-04-13 05:14:15', + display: '2025-04-13 04:13:14 to 2025-04-13 05:14:15', + }); + }); + }); +}); diff --git a/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/mapper.ts b/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/mapper.ts index 160a1bdbc96..a9aa1bfe3aa 100644 --- a/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/mapper.ts +++ b/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/mapper.ts @@ -1,23 +1,18 @@ import { TimeOption, TimeRange, TimeZone, rangeUtil, dateTimeFormat } from '@grafana/data'; -import { formatDateRange } from '@grafana/i18n'; import { getFeatureToggle } from '../../../utils/featureToggle'; import { commonFormat } from '../commonFormat'; + +/** + * Takes a printable TimeOption and builds a TimeRange with DateTime properties from it + */ export const mapOptionToTimeRange = (option: TimeOption, timeZone?: TimeZone): TimeRange => { return rangeUtil.convertRawToRange({ from: option.from, to: option.to }, timeZone, undefined, commonFormat); }; -// TODO: Should we keep these format presets somewhere common? -const rangeFormatShort: Intl.DateTimeFormatOptions = { - dateStyle: 'short', - timeStyle: 'short', -}; - -const rangeFormatFull: Intl.DateTimeFormatOptions = { - dateStyle: 'short', - timeStyle: 'medium', -}; - +/** + * Takes a TimeRange and makes a printable TimeOption with formatted date strings correct for the timezone from it + */ export const mapRangeToTimeOption = (range: TimeRange, timeZone?: TimeZone): TimeOption => { const from = dateTimeFormat(range.from, { timeZone, format: commonFormat }); const to = dateTimeFormat(range.to, { timeZone, format: commonFormat }); @@ -25,13 +20,7 @@ export const mapRangeToTimeOption = (range: TimeRange, timeZone?: TimeZone): Tim let display = `${from} to ${to}`; if (getFeatureToggle('localeFormatPreference')) { - const fromDate = range.from.toDate(); - const toDate = range.to.toDate(); - - // The short time format doesn't include seconds, so change the format - // if the range includes seconds - const hasSeconds = fromDate.getSeconds() !== 0 || toDate.getSeconds() !== 0; - display = formatDateRange(fromDate, toDate, hasSeconds ? rangeFormatFull : rangeFormatShort); + display = rangeUtil.describeTimeRange(range, timeZone); } return { From 3a54c3abae438e7463fdcbf292f43289de55c378 Mon Sep 17 00:00:00 2001 From: Bruno Abrantes Date: Mon, 28 Jul 2025 15:50:26 +0200 Subject: [PATCH 048/131] chore: adds documentation around the dual writer (#108687) * chore: adds documentation around the dual writer Signed-off-by: Bruno Abrantes * fix: innacuracies in error returned, disambiguate (validation) and move table upwards for more clarity Signed-off-by: Bruno Abrantes --------- Signed-off-by: Bruno Abrantes --- pkg/storage/unified/README.md | 312 ++++++++++++++++++++++++++++++++++ 1 file changed, 312 insertions(+) diff --git a/pkg/storage/unified/README.md b/pkg/storage/unified/README.md index 84efac5df86..11344724271 100644 --- a/pkg/storage/unified/README.md +++ b/pkg/storage/unified/README.md @@ -469,3 +469,315 @@ For debugging purposes, you can view the memberlist status by visitting `http:// that every instance you create is part of the memberlist. You can also visit `http://127.0.0.1:3000/ring` to view the ring status and the storage-api servers that are part of the ring. + +--- + +## Dual Writer System + +The Dual Writer system is a critical component of Unified Storage that manages the transition between legacy storage and unified storage during the migration process. It provides six different modes (0-5) that control how data is read from and written to both storage systems. + +### Dual Writer Mode Reference Table + +| Mode | Description | Read Source | Read Behavior | Write Targets | Write Behavior | Error Handling | Background Sync | +|------|-------------|-------------|---------------|---------------|----------------|----------------|-----------------| +| **0** | Disabled | Legacy Only | Synchronous | Legacy Only | Synchronous | Legacy errors bubble up | None | +| **1** | Legacy Primary + Best Effort Unified | Legacy Only | Legacy: Sync
Unified: Async (background) | Legacy + Unified | Legacy: Sync
Unified: Async (background) | Only legacy errors bubble up.
Unified errors logged but ignored | Active - syncs legacy → unified | +| **2** | Legacy Primary + Unified Sync | Legacy Only | Legacy: Sync
Unified: Sync (verification read) | Legacy + Unified | Legacy: Sync
Unified: Sync | Legacy errors bubble up first.
Unified errors bubble up (except NotFound which is ignored).
If write succeeds in legacy but fails in unified, unified error bubbles up and legacy is cleaned up | Active - syncs legacy → unified | +| **3** | Unified Primary + Legacy Sync | Unified Primary | Unified: Sync
Legacy: Fallback on NotFound | Legacy + Unified | Legacy: Sync
Unified: Sync | Legacy errors bubble up first.
If legacy succeeds but unified fails, unified error bubbles up and legacy is cleaned up | Prerequisite - only available after sync completes | +| **4** | Unified Only (Post-Sync) | Unified Only | Synchronous | Unified Only | Synchronous | Unified errors bubble up | Prerequisite - only available after sync completes | +| **5** | Unified Only (Force) | Unified Only | Synchronous | Unified Only | Synchronous | Unified errors bubble up | None - bypasses sync requirements | + + +### Dual Writer Architecture + +The dual writer acts as an intermediary layer that sits between the API layer and the storage backends, routing read and write operations based on the configured mode. + +```mermaid +graph TB + subgraph "API Layer" + A[REST API Request] + end + + subgraph "Dual Writer Layer" + B[Dual Writer] + B --> C{Mode Decision} + end + + subgraph "Storage Backends" + D[Legacy Storage
SQL Database] + E[Unified Storage
K8s-style Storage] + end + + subgraph "Background Services" + F[Data Syncer
Background Job] + G[Server Lock Service
Distributed Lock] + end + + A --> B + C --> D + C --> E + F --> D + F --> E + F --> G +``` + +### Mode-Specific Data Flow Diagrams + +#### Mode 0: Legacy Only (Disabled) +```mermaid +sequenceDiagram + participant API as API Request + participant DW as Dual Writer + participant LS as Legacy Storage + participant US as Unified Storage + + Note over DW: Mode 0 - Unified Storage Disabled + + API->>DW: Read/Write Request + DW->>LS: Forward Request + LS-->>DW: Response + DW-->>API: Response + + Note over US: Not Used +``` + +#### Mode 1: Legacy Primary + Best Effort Unified +```mermaid +sequenceDiagram + participant API as API Request + participant DW as Dual Writer + participant LS as Legacy Storage + participant US as Unified Storage + participant BG as Background Sync + + Note over DW: Mode 1 - Legacy Primary, Unified Best-Effort + + %% Read Operations + API->>DW: Read Request + DW->>LS: Read from Legacy + LS-->>DW: Data + DW->>US: Read from Unified (Background) + Note over US: Errors ignored + DW-->>API: Legacy Data + + %% Write Operations + API->>DW: Write Request + DW->>LS: Write to Legacy + LS-->>DW: Success/Error + alt Legacy Write Successful + DW->>US: Write to Unified (Background) + Note over US: Errors ignored + DW-->>API: Legacy Result + else Legacy Write Failed + DW-->>API: Legacy Error + end + + BG->>LS: Periodic Sync Check + BG->>US: Sync Missing Data +``` + +#### Mode 2: Legacy Primary + Unified Sync +```mermaid +sequenceDiagram + participant API as API Request + participant DW as Dual Writer + participant LS as Legacy Storage + participant US as Unified Storage + participant BG as Background Sync + + Note over DW: Mode 2 - Legacy Primary, Unified Synchronous + + %% Read Operations + API->>DW: Read Request + DW->>LS: Read from Legacy + LS-->>DW: Data + DW->>US: Verification Read (Foreground) + Note over US: Verifies unified storage can serve the same object + US-->>DW: Success/Error + alt Verification Read Failed (Non-NotFound) + DW-->>API: Unified Error + else Verification Read Success or NotFound + DW-->>API: Legacy Data + end + + %% Write Operations + API->>DW: Write Request + DW->>LS: Write to Legacy + LS-->>DW: Success/Error + alt Legacy Write Successful + DW->>US: Write to Unified (Foreground) + US-->>DW: Success/Error + alt Unified Write Failed + DW->>LS: Cleanup Legacy (Best Effort) + DW-->>API: Unified Error + else Both Writes Successful + DW-->>API: Legacy Result + end + else Legacy Write Failed + DW-->>API: Legacy Error + end + + BG->>LS: Periodic Sync Check + BG->>US: Sync Missing Data +``` + +#### Mode 3: Unified Primary + Legacy Sync +```mermaid +sequenceDiagram + participant API as API Request + participant DW as Dual Writer + participant LS as Legacy Storage + participant US as Unified Storage + + Note over DW: Mode 3 - Unified Primary, Legacy Sync + Note over DW: Only activated after background sync succeeds + + %% Read Operations + API->>DW: Read Request + DW->>US: Read from Unified + US-->>DW: Data/Error + alt Unified Read NotFound + DW->>LS: Fallback to Legacy + LS-->>DW: Data/Error + DW-->>API: Legacy Result + else Unified Read Success + DW-->>API: Unified Data + end + + %% Write Operations + API->>DW: Write Request + DW->>LS: Write to Legacy + LS-->>DW: Success/Error + alt Legacy Write Successful + DW->>US: Write to Unified + US-->>DW: Success/Error + alt Unified Write Failed + DW->>LS: Cleanup Legacy (Best Effort) + DW-->>API: Unified Error + else Both Writes Successful + DW-->>API: Unified Result + end + else Legacy Write Failed + DW-->>API: Legacy Error + end +``` + +#### Mode 4 & 5: Unified Only +```mermaid +sequenceDiagram + participant API as API Request + participant DW as Dual Writer + participant LS as Legacy Storage + participant US as Unified Storage + + Note over DW: Mode 4/5 - Unified Only + Note over DW: Mode 4: After background sync succeeds + Note over DW: Mode 5: Ignores background sync state + + API->>DW: Read/Write Request + DW->>US: Forward Request + US-->>DW: Response + DW-->>API: Response + + Note over LS: Not Used +``` + +### Background Sync Behavior + +The background sync service runs periodically (default: every hour) and is responsible for: + +1. **Data Synchronization**: Ensures legacy and unified storage contain the same data +2. **Mode Progression**: Enables transition from Mode 2 → Mode 3 → Mode 4 +3. **Conflict Resolution**: Handles cases where data exists in one storage but not the other + +#### Sync Process Flow + +```mermaid +flowchart TD + A[Background Sync Trigger] --> B{Current Mode} + + B -->|Mode 1/2| C[Acquire Distributed Lock] + B -->|Mode 3+| Z[No Sync Needed] + + C --> D[List Legacy Storage Items] + D --> E[List Unified Storage Items] + E --> F[Compare All Items] + + F --> G{Item Comparison} + + G -->|Missing in Unified| H[Create in Unified] + G -->|Missing in Legacy| I[Delete from Unified] + G -->|Different Content| J[Update Unified with Legacy Version] + G -->|Identical| K[No Action Needed] + + H --> L[Track Sync Success] + I --> L + J --> L + K --> L + + L --> M{All Items Synced?} + M -->|Yes| N[Mark Sync Complete
Enable Mode Progression] + M -->|No| O[Log Failures
Retry Next Cycle] + + N --> P[Release Lock] + O --> P + Z --> P +``` + +#### Mode Transition Requirements + +- **Mode 0 → Mode 1**: Configuration change only +- **Mode 1 → Mode 2**: Configuration change only +- **Mode 2 → Mode 3**: Requires successful background sync completion +- **Mode 3 → Mode 4**: Requires successful background sync completion +- **Mode 4 → Mode 5**: Configuration change only +- **Any Mode → Mode 5**: Configuration change only (bypasses sync requirements) + +### Error Handling Strategies + +#### Write Operation Error Priority +1. **Legacy Storage Errors**: Always bubble up immediately if legacy write fails +2. **Unified Storage Errors**: + - Mode 1: Logged but ignored + - Mode 2+: Bubble up after legacy cleanup attempt +3. **Cleanup Operations**: Best effort - failures are logged but don't fail the original operation + +#### Read Operation Fallback +- **Mode 2**: `NotFound` errors from unified storage are ignored (object may not be synced yet), but other errors bubble up +- **Mode 3**: If unified storage returns `NotFound`, automatically falls back to legacy storage +- **Other Modes**: No fallback - errors bubble up directly + +### Configuration + +#### Setting Dual Writer Mode +```ini +[unified_storage.{resource}.{kind}.{group}] +dualWriterMode = {0-5} +``` + +#### Background Sync Configuration +```ini +[unified_storage] +; Enable data sync between legacy and unified storage +enable_data_sync = true + +; Sync interval (default: 1 hour) +data_sync_interval = 1h + +; Maximum records to sync per run (default: 1000) +data_sync_records_limit = 1000 + +; Skip data sync requirement for mode transitions +skip_data_sync = false +``` + +### Monitoring and Observability + +The dual writer system provides metrics for monitoring: + +- `dual_writer_requests_total`: Counter of requests by mode, operation, and status +- `dual_writer_sync_duration_seconds`: Histogram of background sync duration +- `dual_writer_sync_success_total`: Counter of successful sync operations +- `dual_writer_mode_transitions_total`: Counter of mode transitions + +Use these metrics to monitor the health of your migration and identify any issues with the dual writer system. From 2e0747560539423f4a39a6c5ef5df51e1a1a92b5 Mon Sep 17 00:00:00 2001 From: Jacob Valdez Date: Mon, 28 Jul 2025 08:58:13 -0500 Subject: [PATCH 049/131] docs: clarifying alert rule limits in Grafana cloud for migration assistant (#108722) --- .../migration-guide/cloud-migration-assistant.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/sources/administration/migration-guide/cloud-migration-assistant.md b/docs/sources/administration/migration-guide/cloud-migration-assistant.md index 16bb16a93c4..2ca94628b32 100644 --- a/docs/sources/administration/migration-guide/cloud-migration-assistant.md +++ b/docs/sources/administration/migration-guide/cloud-migration-assistant.md @@ -197,8 +197,20 @@ The `grafana-default-email` contact point that's provisioned with every new Graf This is sufficient to have your Alerting configuration up and running in Grafana Cloud with minimal effort. +#### Migration assistant limitations on Grafana Alerting resources + Migration of Silences is not supported by the migration assistant and needs to be configured manually. Alert History is also not available for migration. +Attempting to migrate a large number of alert rules might result in the following error: + +``` +Maximum number of alert rule groups reached: Delete some alert rule groups or upgrade your plan and try again. +``` + +To avoid this, refer to the [Alert rule limits in Grafana Cloud](https://grafana.com/docs/grafana-cloud/alerting-and-irm/alerting/alerting-rules/create-grafana-managed-rule/#alert-rule-limits-in-grafana-cloud) when migrating alert rules. + +#### Prevent duplicated alert notifications + Successfully migrating Alerting resources to your Grafana Cloud instance could result in 2 sets of notifications being generated: 1. From your OSS/Enterprise instance From 27c395694dabd7e521175b92bff735fac6aee5a0 Mon Sep 17 00:00:00 2001 From: Tania <10127682+undef1nd@users.noreply.github.com> Date: Mon, 28 Jul 2025 16:05:57 +0200 Subject: [PATCH 050/131] OpenFeature: Initialize early (#108594) * Move OpenFeatureInit * Remove unused import * Remove todo --- pkg/cmd/grafana-server/commands/cli.go | 6 ++++++ pkg/cmd/grafana-server/commands/target.go | 5 +++++ pkg/server/server.go | 6 ------ 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/pkg/cmd/grafana-server/commands/cli.go b/pkg/cmd/grafana-server/commands/cli.go index 5f438aad2fd..949c865060a 100644 --- a/pkg/cmd/grafana-server/commands/cli.go +++ b/pkg/cmd/grafana-server/commands/cli.go @@ -11,6 +11,7 @@ import ( "syscall" "time" + "github.com/grafana/grafana/pkg/services/featuremgmt" _ "github.com/grafana/pyroscope-go/godeltaprof/http/pprof" "github.com/urfave/cli/v2" @@ -105,6 +106,11 @@ func RunServer(opts standalone.BuildInfo, cli *cli.Context) error { metrics.SetBuildInformation(metrics.ProvideRegisterer(), opts.Version, opts.Commit, opts.BuildBranch, getBuildstamp(opts)) + // Initialize the OpenFeature feature flag system + if err := featuremgmt.InitOpenFeatureWithCfg(cfg); err != nil { + return err + } + s, err := server.Initialize( cfg, server.Options{ diff --git a/pkg/cmd/grafana-server/commands/target.go b/pkg/cmd/grafana-server/commands/target.go index 39f322396ac..e6988b7e4c5 100644 --- a/pkg/cmd/grafana-server/commands/target.go +++ b/pkg/cmd/grafana-server/commands/target.go @@ -7,6 +7,7 @@ import ( "runtime/debug" "strings" + "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/urfave/cli/v2" "github.com/grafana/grafana/pkg/api" @@ -91,6 +92,10 @@ func RunTargetServer(opts standalone.BuildInfo, cli *cli.Context) error { metrics.SetBuildInformation(metrics.ProvideRegisterer(), opts.Version, opts.Commit, opts.BuildBranch, getBuildstamp(opts)) + // Initialize the OpenFeature client with the configuration + if err := featuremgmt.InitOpenFeatureWithCfg(cfg); err != nil { + return err + } s, err := server.InitializeModuleServer( cfg, server.Options{ diff --git a/pkg/server/server.go b/pkg/server/server.go index 794cf656763..ca1263d9e4d 100644 --- a/pkg/server/server.go +++ b/pkg/server/server.go @@ -11,7 +11,6 @@ import ( "strconv" "sync" - "github.com/grafana/grafana/pkg/services/featuremgmt" "golang.org/x/sync/errgroup" "github.com/prometheus/client_golang/prometheus" @@ -132,11 +131,6 @@ func (s *Server) Init() error { return err } - // Initialize the OpenFeature feature flag system - if err := featuremgmt.InitOpenFeatureWithCfg(s.cfg); err != nil { - return err - } - return s.provisioningService.RunInitProvisioners(s.context) } From 6aa3492f4ed096ea9369314771054b605d6255e7 Mon Sep 17 00:00:00 2001 From: Jacob Valdez Date: Mon, 28 Jul 2025 09:08:17 -0500 Subject: [PATCH 051/131] docs: add video shortcode to what's new (#108793) --- docs/sources/whatsnew/whats-new-in-v12-1.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sources/whatsnew/whats-new-in-v12-1.md b/docs/sources/whatsnew/whats-new-in-v12-1.md index 27e4f848682..00fca9ad544 100644 --- a/docs/sources/whatsnew/whats-new-in-v12-1.md +++ b/docs/sources/whatsnew/whats-new-in-v12-1.md @@ -46,7 +46,7 @@ We have one more community contributor to thank for this release. [Chris Hodges] Keep reading to learn about what else we have in store for 12.1. - +{{< youtube id=Umy-kCKkMQM >}} For even more detail about all the changes in this release, refer to the [changelog](https://github.com/grafana/grafana/blob/main/CHANGELOG.md). For the specific steps we recommend when you upgrade to v12.1, check out our [Upgrade Guide](https://grafana.com/docs/grafana//upgrade-guide/upgrade-v12.1/). From fb53a6f077465a9d55480d917cb9ba6933d93856 Mon Sep 17 00:00:00 2001 From: Ashley Harrison Date: Mon, 28 Jul 2025 15:30:50 +0100 Subject: [PATCH 052/131] Chore: Remove cypress `dashboard-new-layouts` tests (#108699) remove cypress dashboard-new-layouts tests --- .github/CODEOWNERS | 2 +- .../workflows/e2e-dashboard-new-layouts.yml | 42 -- .../dashboard-duplicate-panel.spec.ts | 30 -- .../dashboard-edit-flows.ts | 58 -- .../dashboard-group-panels.spec.ts | 506 ------------------ .../dashboard-outline.spec.ts | 26 - .../dashboards-add-panel.spec.ts | 27 - .../dashboards-edit-adhoc-variables.spec.ts | 70 --- ...shboards-edit-datasource-variables.spec.ts | 49 -- ...dashboards-edit-group-by-variables.spec.ts | 68 --- ...oards-edit-panel-title-description.spec.ts | 37 -- ...shboards-edit-panel-transparent-bg.spec.ts | 26 - .../dashboards-edit-query-variables.spec.ts | 68 --- .../dashboards-edit-variables.spec.ts | 147 ----- .../dashboards-move-panel.spec.ts | 59 -- .../dashboards-panel-layouts.spec.ts | 309 ----------- .../dashboards-remove-panel.spec.ts | 35 -- .../dashboards-title-description.spec.ts | 31 -- e2e/run-suite | 23 - package.json | 2 - 20 files changed, 1 insertion(+), 1614 deletions(-) delete mode 100644 .github/workflows/e2e-dashboard-new-layouts.yml delete mode 100644 e2e/dashboard-new-layouts/dashboard-duplicate-panel.spec.ts delete mode 100644 e2e/dashboard-new-layouts/dashboard-edit-flows.ts delete mode 100644 e2e/dashboard-new-layouts/dashboard-group-panels.spec.ts delete mode 100644 e2e/dashboard-new-layouts/dashboard-outline.spec.ts delete mode 100644 e2e/dashboard-new-layouts/dashboards-add-panel.spec.ts delete mode 100644 e2e/dashboard-new-layouts/dashboards-edit-adhoc-variables.spec.ts delete mode 100644 e2e/dashboard-new-layouts/dashboards-edit-datasource-variables.spec.ts delete mode 100644 e2e/dashboard-new-layouts/dashboards-edit-group-by-variables.spec.ts delete mode 100644 e2e/dashboard-new-layouts/dashboards-edit-panel-title-description.spec.ts delete mode 100644 e2e/dashboard-new-layouts/dashboards-edit-panel-transparent-bg.spec.ts delete mode 100644 e2e/dashboard-new-layouts/dashboards-edit-query-variables.spec.ts delete mode 100644 e2e/dashboard-new-layouts/dashboards-edit-variables.spec.ts delete mode 100644 e2e/dashboard-new-layouts/dashboards-move-panel.spec.ts delete mode 100644 e2e/dashboard-new-layouts/dashboards-panel-layouts.spec.ts delete mode 100644 e2e/dashboard-new-layouts/dashboards-remove-panel.spec.ts delete mode 100644 e2e/dashboard-new-layouts/dashboards-title-description.spec.ts diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 3329738f79c..b2edbc703ee 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -407,6 +407,7 @@ /e2e/ @grafana/grafana-frontend-platform /e2e/cloud-plugins-suite/ @grafana/partner-datasources /e2e-playwright/ @grafana/grafana-frontend-platform +/e2e-playwright/dashboard-new-layouts @grafana/dashboards-squad /e2e-playwright/plugin-e2e/ @grafana/oss-big-tent @grafana/partner-datasources /e2e-playwright/plugin-e2e/plugin-e2e-api-tests/ @grafana/plugins-platform-frontend /e2e-playwright/test-plugins/grafana-extensionstest-app/ @grafana/plugins-platform-frontend @@ -1013,7 +1014,6 @@ embed.go @grafana/grafana-as-code /.github/workflows/verify-kinds.yml @grafana/platform-monitoring /.github/workflows/dashboards-issue-add-label.yml @grafana/dashboards-squad /.github/workflows/run-schema-v2-e2e.yml @grafana/dashboards-squad -/.github/workflows/e2e-dashboard-new-layouts.yml @grafana/dashboards-squad /.github/workflows/run-dashboard-search-e2e.yml @grafana/grafana-search-and-storage /.github/workflows/trigger-dashboard-search-e2e.yml @grafana/grafana-search-and-storage /.github/workflows/ephemeral-instances-pr-comment.yml @grafana/grafana-operator-experience-squad diff --git a/.github/workflows/e2e-dashboard-new-layouts.yml b/.github/workflows/e2e-dashboard-new-layouts.yml deleted file mode 100644 index b2b5d1f8215..00000000000 --- a/.github/workflows/e2e-dashboard-new-layouts.yml +++ /dev/null @@ -1,42 +0,0 @@ -name: Run e2e for dashboardNewLayouts - -on: - pull_request: - branches: - - '**' - paths: - - 'e2e/dashboard-new-layouts/**' - - 'public/app/features/dashboard-scene/**' - -env: - ARCH: linux-amd64 - -jobs: - dashboard-new-layouts-e2e: - runs-on: ubuntu-latest - continue-on-error: true - if: github.event.pull_request.draft == false - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - persist-credentials: false - - name: Pin Go version to mod file - uses: actions/setup-go@v5 - with: - go-version-file: 'go.mod' - - run: go version - - uses: actions/setup-node@v4 - with: - node-version-file: '.nvmrc' - cache: 'yarn' - - name: Install dependencies - run: yarn install --immutable - - name: Build grafana - run: make build - - name: Install Cypress dependencies - uses: cypress-io/github-action@108b8684ae52e735ff7891524cbffbcd4be5b19f - with: - runTests: false - - name: Run dashboardNewLayouts e2e - run: yarn e2e:dashboard-new-layouts diff --git a/e2e/dashboard-new-layouts/dashboard-duplicate-panel.spec.ts b/e2e/dashboard-new-layouts/dashboard-duplicate-panel.spec.ts deleted file mode 100644 index 43ac0576f47..00000000000 --- a/e2e/dashboard-new-layouts/dashboard-duplicate-panel.spec.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { e2e } from '../utils'; - -import { flows } from './dashboard-edit-flows'; - -describe('Dashboard panels', () => { - beforeEach(() => { - e2e.flows.login(Cypress.env('USERNAME'), Cypress.env('PASSWORD')); - }); - - it('can duplicate a panel', () => { - e2e.flows.scenes.importV2Dashboard({ title: 'Paste tab' }); - - e2e.flows.scenes.toggleEditMode(); - const panelTitle = 'Unique'; - flows.changePanelTitle('New panel', panelTitle); - - e2e.components.Panels.Panel.title(panelTitle).should('have.length', 1); - - e2e.components.Panels.Panel.menu(panelTitle).click({ force: true }); - e2e.components.Panels.Panel.menuItems('More...').trigger('mouseover'); - e2e.components.Panels.Panel.menuItems('Duplicate').click(); - - e2e.components.Panels.Panel.title(panelTitle).should('have.length', 2); - - // Save, reload, and ensure duplicate has persisted - e2e.flows.scenes.saveDashboard(); - cy.reload(); - e2e.components.Panels.Panel.title(panelTitle).should('have.length', 2); - }); -}); diff --git a/e2e/dashboard-new-layouts/dashboard-edit-flows.ts b/e2e/dashboard-new-layouts/dashboard-edit-flows.ts deleted file mode 100644 index c823d97fd0f..00000000000 --- a/e2e/dashboard-new-layouts/dashboard-edit-flows.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { e2e } from '../utils'; - -const deselectPanels = () => { - e2e.pages.Dashboard.Controls().click(); -}; - -// Common flows for adding/editing variables on the new edit pane -export const flows = { - newEditPaneVariableClick() { - e2e.components.NavToolbar.editDashboard.editButton().should('be.visible').click(); - e2e.components.PanelEditor.Outline.section().should('be.visible').click(); - e2e.components.PanelEditor.Outline.item('Variables').should('be.visible').click(); - e2e.components.PanelEditor.ElementEditPane.addVariableButton().should('be.visible').click(); - }, - newEditPanelCommonVariableInputs(variable: Variable) { - e2e.components.PanelEditor.ElementEditPane.variableType(variable.type) - .scrollIntoView() - .should('be.visible') - .click(); - e2e.components.PanelEditor.ElementEditPane.variableNameInput().clear().type(variable.name).blur(); - e2e.components.PanelEditor.ElementEditPane.variableLabelInput().clear().type(variable.label).blur(); - }, - firstPanelTitleShouldBe(panelTitle: string) { - return e2e.components.Panels.Panel.headerContainer() - .first() - .within(() => cy.get('h2').first().should('have.text', panelTitle)); - }, - deselectPanels, - changePanelTitle(oldPanelTitle: string, newPanelTitle: string) { - deselectPanels(); - const oldPanelRegex = new RegExp(`^${oldPanelTitle}$`); - e2e.flows.scenes.selectPanel(oldPanelRegex); - - e2e.components.PanelEditor.OptionsPane.fieldInput('Title') - .should('have.value', oldPanelTitle) - .clear() - .type(newPanelTitle); - e2e.components.PanelEditor.OptionsPane.fieldInput('Title').should('have.value', newPanelTitle); - }, - changePanelDescription(panelTitle: string, newDescription: string) { - deselectPanels(); - const panelTitleRegex = new RegExp(`^${panelTitle}$`); - e2e.flows.scenes.selectPanel(panelTitleRegex); - - e2e.components.PanelEditor.OptionsPane.fieldLabel('panel-options Description').within(() => { - cy.get('textarea').type(newDescription); - cy.get('textarea').should('have.value', newDescription); - }); - }, -}; - -export type Variable = { - type: string; - name: string; - label?: string; - description?: string; - value: string; -}; diff --git a/e2e/dashboard-new-layouts/dashboard-group-panels.spec.ts b/e2e/dashboard-new-layouts/dashboard-group-panels.spec.ts deleted file mode 100644 index f3d74c171b5..00000000000 --- a/e2e/dashboard-new-layouts/dashboard-group-panels.spec.ts +++ /dev/null @@ -1,506 +0,0 @@ -import { e2e } from '../utils'; - -describe('Grouping panels', () => { - beforeEach(() => { - e2e.flows.login(Cypress.env('USERNAME'), Cypress.env('PASSWORD')); - }); - - /* - * Rows - */ - - it('can group and ungroup new panels into row', () => { - e2e.flows.scenes.importV2Dashboard({ title: 'Group new panels into row' }); - - e2e.components.NavToolbar.editDashboard.editButton().click(); - - // Group into row - e2e.flows.scenes.groupIntoRow(); - - // Verify row and panel titles - e2e.components.DashboardRow.title('New row').should('be.visible'); - e2e.components.Panels.Panel.title('New panel').should('have.length', 3); - - // Save dashboards and reload - e2e.flows.scenes.saveDashboard(); - cy.reload(); - - // Verify row and panel titles after reload - e2e.components.DashboardRow.title('New row').should('be.visible'); - e2e.components.Panels.Panel.title('New panel').should('have.length', 3); - - e2e.components.NavToolbar.editDashboard.editButton().click(); - - // Ungroup - e2e.flows.scenes.ungroupPanels(); - - // Verify Row title is gone - e2e.components.DashboardRow.title('New row').should('not.exist'); - e2e.components.Panels.Panel.title('New panel').should('have.length', 3); - - //Save dashboards and reload - e2e.flows.scenes.saveDashboard(); - cy.reload(); - - // Verify Row title is gone - e2e.components.DashboardRow.title('New row').should('not.exist'); - e2e.components.Panels.Panel.title('New panel').should('have.length', 3); - }); - - it('can add and remove several rows', () => { - e2e.flows.scenes.importV2Dashboard({ title: 'Add and remove rows' }); - - e2e.components.NavToolbar.editDashboard.editButton().click(); - - e2e.flows.scenes.groupIntoRow(); - - e2e.components.CanvasGridAddActions.addRow().click({ scrollBehavior: 'bottom' }); - e2e.flows.scenes.addPanel(); - - e2e.components.CanvasGridAddActions.addRow().click({ scrollBehavior: 'bottom' }); - e2e.components.DashboardEditPaneSplitter.primaryBody().scrollTo('bottom', { ensureScrollable: false }); - e2e.components.CanvasGridAddActions.addPanel().should('have.length', 3).last().click(); - - e2e.components.DashboardRow.title('New row').should('exist'); - e2e.components.DashboardRow.title('New row 1').should('exist'); - e2e.components.DashboardRow.title('New row 2').should('exist'); - - e2e.components.Panels.Panel.title('New panel').should('have.length', 5); - - //Save dashboards and reload - e2e.flows.scenes.saveDashboard(); - cy.reload(); - - e2e.components.DashboardRow.title('New row').should('exist'); - e2e.components.DashboardRow.title('New row 1').should('exist'); - e2e.components.DashboardRow.title('New row 2').should('exist'); - - e2e.components.Panels.Panel.title('New panel').should('have.length', 5); - - e2e.components.NavToolbar.editDashboard.editButton().click(); - - e2e.components.DashboardRow.title('New row 1').parent().click(); - e2e.components.EditPaneHeader.deleteButton().click(); - e2e.pages.ConfirmModal.delete().click(); - - e2e.components.DashboardRow.title('New row 2').parent().click(); - e2e.components.EditPaneHeader.deleteButton().click(); - e2e.pages.ConfirmModal.delete().click(); - - e2e.components.DashboardRow.title('New row').should('exist'); - e2e.components.DashboardRow.title('New row 1').should('not.exist'); - e2e.components.DashboardRow.title('New row 2').should('not.exist'); - e2e.components.Panels.Panel.title('New panel').should('have.length', 3); - - e2e.flows.scenes.saveDashboard(); - cy.reload(); - - e2e.components.DashboardRow.title('New row').should('exist'); - e2e.components.DashboardRow.title('New row 1').should('not.exist'); - e2e.components.DashboardRow.title('New row 2').should('not.exist'); - e2e.components.Panels.Panel.title('New panel').should('have.length', 3); - }); - - it('can paste a copied row', () => { - e2e.flows.scenes.importV2Dashboard({ title: 'Paste row' }); - - e2e.components.NavToolbar.editDashboard.editButton().click(); - - e2e.flows.scenes.groupIntoRow(); - - e2e.components.DashboardRow.title('New row').should('exist'); - - e2e.flows.scenes.editPaneCopy(); - - e2e.components.CanvasGridAddActions.pasteRow().click({ scrollBehavior: 'bottom' }); - - e2e.components.DashboardEditPaneSplitter.primaryBody().scrollTo('bottom', { ensureScrollable: false }); - - e2e.components.DashboardRow.title('New row').should('exist'); - e2e.components.DashboardRow.title('New row 1').should('exist'); - e2e.components.Panels.Panel.title('New panel').should('have.length', 6); - - e2e.flows.scenes.saveDashboard(); - cy.reload(); - - cy.scrollTo('bottom'); - - e2e.components.DashboardRow.title('New row').should('exist'); - e2e.components.DashboardRow.title('New row 1').should('exist'); - e2e.components.Panels.Panel.title('New panel').should('have.length', 6); - }); - - it('can duplicate a row', () => { - e2e.flows.scenes.importV2Dashboard({ title: 'Duplicate row' }); - - e2e.components.NavToolbar.editDashboard.editButton().click(); - - e2e.flows.scenes.groupIntoRow(); - - e2e.components.DashboardRow.title('New row').should('exist'); - - e2e.flows.scenes.editPaneDuplicate(); - - e2e.components.DashboardEditPaneSplitter.primaryBody().scrollTo('bottom', { ensureScrollable: false }); - - e2e.components.DashboardRow.title('New row').should('exist'); - e2e.components.DashboardRow.title('New row 1').should('exist'); - e2e.components.Panels.Panel.title('New panel').should('have.length', 6); - - e2e.flows.scenes.saveDashboard(); - cy.reload(); - - cy.scrollTo('bottom'); - - e2e.components.DashboardRow.title('New row').should('exist'); - e2e.components.DashboardRow.title('New row 1').should('exist'); - e2e.components.Panels.Panel.title('New panel').should('have.length', 6); - }); - - it('can collapse rows', () => { - e2e.flows.scenes.importV2Dashboard({ title: 'Collapse rows' }); - - e2e.components.NavToolbar.editDashboard.editButton().click(); - - e2e.flows.scenes.groupIntoRow(); - - e2e.components.DashboardRow.title('New row').should('exist'); - - e2e.flows.scenes.editPaneDuplicate(); - - e2e.components.DashboardEditPaneSplitter.primaryBody().scrollTo('bottom', { ensureScrollable: false }); - - e2e.components.DashboardRow.title('New row').should('exist'); - e2e.components.DashboardRow.title('New row 1').should('exist'); - e2e.components.Panels.Panel.title('New panel').should('have.length', 6); - - e2e.components.DashboardRow.title('New row').click(); - e2e.components.DashboardRow.title('New row 1').click(); - - e2e.components.DashboardRow.title('New row').should('exist'); - e2e.components.DashboardRow.title('New row 1').should('exist'); - e2e.components.Panels.Panel.title('New panel').should('have.length', 0); - - e2e.flows.scenes.saveDashboard(); - cy.reload(); - - e2e.components.DashboardRow.title('New row').should('exist'); - e2e.components.DashboardRow.title('New row 1').should('exist'); - e2e.components.Panels.Panel.title('New panel').should('have.length', 0); - }); - - it('can convert rows into tabs when changing layout', () => { - e2e.flows.scenes.importV2Dashboard({ title: 'Rows to tabs' }); - - e2e.components.NavToolbar.editDashboard.editButton().click(); - - e2e.flows.scenes.groupIntoRow(); - - e2e.components.DashboardRow.title('New row').should('exist'); - - e2e.flows.scenes.editPaneDuplicate(); - - e2e.components.DashboardRow.title('New row').should('exist'); - e2e.components.DashboardRow.title('New row 1').should('exist'); - - e2e.components.EditPaneHeader.backButton().click({ force: true }); - - // expand collapsed layouts section - e2e.components.OptionsGroup.toggle('group-layout-category').click(); - - e2e.flows.scenes.selectTabsLayout(); - - e2e.components.Tab.title('New row').should('be.visible'); - e2e.components.Tab.title('New row 1').should('be.visible'); - e2e.components.Panels.Panel.title('New panel').should('have.length', 3); - - e2e.components.Tab.title('New row 1').click(); - e2e.components.Panels.Panel.title('New panel').should('have.length', 3); - - e2e.flows.scenes.saveDashboard(); - cy.reload(); - - e2e.components.Tab.title('New row').should('be.visible'); - e2e.components.Tab.title('New row 1').should('be.visible'); - e2e.components.Panels.Panel.title('New panel').should('have.length', 3); - - e2e.components.Tab.title('New row').click(); - e2e.components.Panels.Panel.title('New panel').should('have.length', 3); - }); - - it('can group and ungroup new panels into row with tab', () => { - e2e.flows.scenes.importV2Dashboard({ title: 'Group new panels into tab with row' }); - - e2e.components.NavToolbar.editDashboard.editButton().click(); - - // Group into row with tab - e2e.flows.scenes.groupIntoRow(); - e2e.flows.scenes.groupIntoTab(); - - // Verify tab and panel titles - e2e.components.DashboardRow.title('New row').should('be.visible'); - e2e.components.Tab.title('New tab').should('be.visible'); - e2e.components.Panels.Panel.title('New panel').should('have.length', 3); - - // Save dashboards and reload - e2e.flows.scenes.saveDashboard(); - cy.reload(); - - // Verify tab, row and panel titles after reload - e2e.components.DashboardRow.title('New row').should('be.visible'); - e2e.components.Tab.title('New tab').should('be.visible'); - e2e.components.Panels.Panel.title('New panel').should('have.length', 3); - - e2e.components.NavToolbar.editDashboard.editButton().click(); - - // Ungroup - e2e.flows.scenes.ungroupPanels(); // ungroup tabs - e2e.flows.scenes.ungroupPanels(); // ungroup rows - - // Verify tab and row titles is gone - e2e.components.DashboardRow.title('New row').should('not.exist'); - e2e.components.Tab.title('New tab').should('not.exist'); - e2e.components.Panels.Panel.title('New panel').should('have.length', 3); - - // Save dashboards and reload - e2e.flows.scenes.saveDashboard(); - cy.reload(); - - // Verify Row title is gone - e2e.components.DashboardRow.title('New row').should('not.exist'); - e2e.components.Tab.title('New tab').should('not.exist'); - e2e.components.Panels.Panel.title('New panel').should('have.length', 3); - }); - - /* - * Tabs - */ - - it('can group and ungroup new panels into tab', () => { - e2e.flows.scenes.importV2Dashboard({ title: 'Group new panels into tab' }); - - e2e.components.NavToolbar.editDashboard.editButton().click(); - - // Group into tab - e2e.flows.scenes.groupIntoTab(); - - // Verify tab and panel titles - e2e.components.Tab.title('New tab').should('be.visible'); - e2e.components.Panels.Panel.title('New panel').should('have.length', 3); - - // Save dashboards and reload - e2e.flows.scenes.saveDashboard(); - cy.reload(); - - // Verify row and panel titles after reload - e2e.components.Tab.title('New tab').should('be.visible'); - e2e.components.Panels.Panel.title('New panel').should('have.length', 3); - - e2e.components.NavToolbar.editDashboard.editButton().click(); - - // Ungroup - e2e.flows.scenes.ungroupPanels(); - - // Verify Row title is gone - e2e.components.Tab.title('New tab').should('not.exist'); - e2e.components.Panels.Panel.title('New panel').should('have.length', 3); - - // Save dashboards and reload - e2e.flows.scenes.saveDashboard(); - cy.reload(); - - // Verify Row title is gone - e2e.components.Tab.title('New tab').should('not.exist'); - e2e.components.Panels.Panel.title('New panel').should('have.length', 3); - }); - - it('can add and remove several tabs', () => { - e2e.flows.scenes.importV2Dashboard({ title: 'Add and remove tabs' }); - - e2e.components.NavToolbar.editDashboard.editButton().click(); - - e2e.flows.scenes.groupIntoTab(); - - e2e.components.CanvasGridAddActions.addTab().click(); - e2e.flows.scenes.addPanel(); - - e2e.components.CanvasGridAddActions.addTab().click(); - e2e.flows.scenes.addPanel(); - - e2e.components.Tab.title('New tab').should('exist'); - e2e.components.Tab.title('New tab 1').should('exist'); - e2e.components.Tab.title('New tab 2').should('exist'); - e2e.components.Tab.title('New tab 2').should('have.attr', 'aria-selected', 'true'); - e2e.components.Panels.Panel.title('New panel').should('have.length', 1); - - //Save dashboards and reload - e2e.flows.scenes.saveDashboard(); - cy.reload(); - - e2e.components.Tab.title('New tab').should('exist'); - e2e.components.Tab.title('New tab 1').should('exist'); - e2e.components.Tab.title('New tab 2').should('exist'); - e2e.components.Tab.title('New tab 2').should('have.attr', 'aria-selected', 'true'); - e2e.components.Panels.Panel.title('New panel').should('have.length', 1); - - e2e.components.NavToolbar.editDashboard.editButton().click(); - - e2e.components.Tab.title('New tab 2').click(); - e2e.components.EditPaneHeader.deleteButton().click(); - e2e.pages.ConfirmModal.delete().click(); - - e2e.components.Tab.title('New tab 1').click(); - e2e.components.EditPaneHeader.deleteButton().click(); - e2e.pages.ConfirmModal.delete().click(); - - e2e.components.Tab.title('New tab').should('exist'); - e2e.components.Tab.title('New tab 1').should('not.exist'); - e2e.components.Tab.title('New tab 2').should('not.exist'); - e2e.components.Panels.Panel.title('New panel').should('have.length', 3); - - e2e.flows.scenes.saveDashboard(); - cy.reload(); - - e2e.components.Tab.title('New tab').should('exist'); - e2e.components.Tab.title('New tab 1').should('not.exist'); - e2e.components.Tab.title('New tab 2').should('not.exist'); - e2e.components.Panels.Panel.title('New panel').should('have.length', 3); - }); - - it('can paste a copied tab', () => { - e2e.flows.scenes.importV2Dashboard({ title: 'Paste tab' }); - - e2e.components.NavToolbar.editDashboard.editButton().click(); - - e2e.flows.scenes.groupIntoTab(); - - e2e.components.Tab.title('New tab').should('exist'); - - e2e.flows.scenes.editPaneCopy(); - - e2e.components.CanvasGridAddActions.pasteTab().click(); - - e2e.components.Tab.title('New tab').should('exist'); - e2e.components.Tab.title('New tab 1').should('exist'); - e2e.components.Panels.Panel.title('New panel').should('have.length', 3); - - e2e.flows.scenes.saveDashboard(); - cy.reload(); - - e2e.components.Tab.title('New tab').should('exist'); - e2e.components.Tab.title('New tab 1').should('exist'); - e2e.components.Panels.Panel.title('New panel').should('have.length', 3); - }); - - it('can duplicate a tab', () => { - e2e.flows.scenes.importV2Dashboard({ title: 'Duplicate tab' }); - - e2e.components.NavToolbar.editDashboard.editButton().click(); - - e2e.flows.scenes.groupIntoTab(); - - e2e.components.Tab.title('New tab').should('exist'); - - e2e.flows.scenes.editPaneDuplicate(); - - e2e.components.Tab.title('New tab').should('exist'); - e2e.components.Tab.title('New tab 1').should('exist'); - e2e.components.Panels.Panel.title('New panel').should('have.length', 3); - - e2e.flows.scenes.saveDashboard(); - cy.reload(); - - e2e.components.Tab.title('New tab').should('exist'); - e2e.components.Tab.title('New tab 1').should('exist'); - e2e.components.Panels.Panel.title('New panel').should('have.length', 3); - }); - - it('can convert tabs into rows when changing layout', () => { - e2e.flows.scenes.importV2Dashboard({ title: 'Tabs to rows' }); - - e2e.components.NavToolbar.editDashboard.editButton().click(); - - e2e.flows.scenes.groupIntoTab(); - - e2e.components.Tab.title('New tab').should('exist'); - - e2e.flows.scenes.editPaneDuplicate(); - e2e.flows.scenes.editPaneDuplicate(); - - e2e.components.Tab.title('New tab').should('exist'); - e2e.components.Tab.title('New tab 1').should('exist'); - e2e.components.Tab.title('New tab 2').should('exist'); - - e2e.components.EditPaneHeader.backButton().click({ force: true }); - - // expand collapsed layouts section - e2e.components.OptionsGroup.toggle('group-layout-category').click(); - - e2e.flows.scenes.selectRowsLayout(); - - e2e.components.DashboardRow.title('New tab').should('exist'); - e2e.components.Panels.Panel.title('New panel').first().should('be.visible'); // wait for panels to load - e2e.components.DashboardRow.title('New tab 1').should('exist'); - e2e.components.DashboardRow.title('New tab 2').should('exist'); - - e2e.components.DashboardEditPaneSplitter.primaryBody().scrollTo('bottom', { ensureScrollable: false }); - - e2e.components.Panels.Panel.title('New panel').should('have.length', 9); - - e2e.flows.scenes.saveDashboard(); - cy.reload(); - - e2e.components.DashboardRow.title('New tab').should('exist'); - e2e.components.Panels.Panel.title('New panel').first().should('be.visible'); // wait for panels to load - e2e.components.DashboardRow.title('New tab 1').should('exist'); - e2e.components.DashboardRow.title('New tab 2').should('exist'); - - cy.scrollTo('bottom'); - - e2e.components.Panels.Panel.title('New panel').should('have.length', 9); - }); - - it('can group and ungroup new panels into tab with row', () => { - e2e.flows.scenes.importV2Dashboard({ title: 'Group new panels into tab with row' }); - - e2e.components.NavToolbar.editDashboard.editButton().click(); - - // Group into tab - e2e.flows.scenes.groupIntoTab(); - e2e.flows.scenes.groupIntoRow(); - - // Verify tab and panel titles - e2e.components.Tab.title('New tab').should('be.visible'); - e2e.components.DashboardRow.title('New row').should('be.visible'); - e2e.components.Panels.Panel.title('New panel').should('have.length', 3); - - // Save dashboards and reload - e2e.flows.scenes.saveDashboard(); - cy.reload(); - - // Verify tab, row and panel titles after reload - e2e.components.Tab.title('New tab').should('be.visible'); - e2e.components.DashboardRow.title('New row').should('be.visible'); - e2e.components.Panels.Panel.title('New panel').should('have.length', 3); - - e2e.components.NavToolbar.editDashboard.editButton().click(); - - // Ungroup - e2e.flows.scenes.ungroupPanels(); // ungroup rows - e2e.flows.scenes.ungroupPanels(); // ungroup tabs - - // Verify tab and row titles is gone - e2e.components.Tab.title('New tab').should('not.exist'); - e2e.components.DashboardRow.title('New row').should('not.exist'); - e2e.components.Panels.Panel.title('New panel').should('have.length', 3); - - // Save dashboards and reload - e2e.flows.scenes.saveDashboard(); - cy.reload(); - - // Verify Row title is gone - e2e.components.Tab.title('New tab').should('not.exist'); - e2e.components.DashboardRow.title('New row').should('not.exist'); - e2e.components.Panels.Panel.title('New panel').should('have.length', 3); - }); -}); diff --git a/e2e/dashboard-new-layouts/dashboard-outline.spec.ts b/e2e/dashboard-new-layouts/dashboard-outline.spec.ts deleted file mode 100644 index 6068152514c..00000000000 --- a/e2e/dashboard-new-layouts/dashboard-outline.spec.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { e2e } from '../utils'; - -const PAGE_UNDER_TEST = 'edediimbjhdz4b/a-tall-dashboard'; - -describe('Dashboard Outline', () => { - beforeEach(() => { - e2e.flows.login(Cypress.env('USERNAME'), Cypress.env('PASSWORD')); - }); - - it('can use dashboard outline', () => { - e2e.flows.openDashboard({ uid: `${PAGE_UNDER_TEST}?orgId=1` }); - - e2e.flows.scenes.toggleEditMode(); - - e2e.components.PanelEditor.Outline.section().click(); - - // Should be able to click Variables item in outline to see add variable button - e2e.components.PanelEditor.Outline.item('Variables').click(); - e2e.components.PanelEditor.ElementEditPane.addVariableButton().should('exist'); - - // Clicking a panel should scroll that panel in view - cy.contains('Dashboard panel 48').should('not.exist'); - e2e.components.PanelEditor.Outline.item('Panel #48').click(); - cy.contains('Dashboard panel 48').should('exist'); - }); -}); diff --git a/e2e/dashboard-new-layouts/dashboards-add-panel.spec.ts b/e2e/dashboard-new-layouts/dashboards-add-panel.spec.ts deleted file mode 100644 index 9997351cfdd..00000000000 --- a/e2e/dashboard-new-layouts/dashboards-add-panel.spec.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { e2e } from '../utils'; - -const PAGE_UNDER_TEST = 'kVi2Gex7z/test-variable-output'; -const DASHBOARD_NAME = 'Test variable output'; - -describe('Dashboard panels', () => { - beforeEach(() => { - e2e.flows.login(Cypress.env('USERNAME'), Cypress.env('PASSWORD')); - }); - - it('can add a new panel', () => { - e2e.flows.openDashboard({ uid: `${PAGE_UNDER_TEST}?orgId=1` }); - cy.contains(DASHBOARD_NAME).should('be.visible'); - - // Toggle edit mode - e2e.components.NavToolbar.editDashboard.editButton().should('be.visible').click(); - - e2e.flows.scenes.addPanel(); - - // Check that new panel has been added - e2e.components.Panels.Panel.title('New panel').should('be.visible'); - - // Check that pressing the configure button shows the panel editor - e2e.flows.scenes.configurePanel(); - e2e.components.PanelEditor.General.content().should('be.visible'); - }); -}); diff --git a/e2e/dashboard-new-layouts/dashboards-edit-adhoc-variables.spec.ts b/e2e/dashboard-new-layouts/dashboards-edit-adhoc-variables.spec.ts deleted file mode 100644 index f7350331978..00000000000 --- a/e2e/dashboard-new-layouts/dashboards-edit-adhoc-variables.spec.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { e2e } from '../utils'; - -import { flows, Variable } from './dashboard-edit-flows'; - -const PAGE_UNDER_TEST = 'kVi2Gex7z/test-variable-output'; -const DASHBOARD_NAME = 'Test variable output'; - -describe('Dashboard edit - Ad hoc variables', () => { - beforeEach(() => { - e2e.flows.login(Cypress.env('USERNAME'), Cypress.env('PASSWORD')); - }); - - it('can add a new adhoc variable', () => { - e2e.flows.openDashboard({ uid: `${PAGE_UNDER_TEST}?orgId=1` }); - cy.contains(DASHBOARD_NAME).should('be.visible'); - - const variable: Variable = { - type: 'adhoc', - name: 'VariableUnderTest', - value: 'label1', - label: 'VariableUnderTest', - }; - - // common steps to add a new variable - flows.newEditPaneVariableClick(); - flows.newEditPanelCommonVariableInputs(variable); - - e2e.pages.Dashboard.Settings.Variables.Edit.AdHocFiltersVariable.datasourceSelect().should('be.visible').click(); - const dataSource = 'gdev-loki'; - cy.contains(dataSource).scrollIntoView().should('be.visible').click(); - - // mock the API call to get the labels - const labels = ['label1', 'label2']; - cy.intercept('GET', '**/resources/labels*', { - statusCode: 200, - body: { - status: 'success', - data: labels, - }, - }).as('labels'); - - // select the variable in the dashboard and confirm the variable value is set - e2e.pages.Dashboard.SubMenu.submenuItem().should('be.visible').click(); - e2e.pages.Dashboard.SubMenu.submenuItemLabels(variable.label).should('be.visible').contains(variable.label); - - // mock the API call to get the label values - const labelValues = ['label2Value1']; - cy.intercept('GET', `**/resources/label/${labels[1]}/values*`, { - statusCode: 200, - body: { - status: 'success', - data: labelValues, - }, - }).as('label-values'); - - // choose the label and value - cy.get('div[data-testid]').contains(labels[1]).click(); - cy.get('div[data-testid]').contains('=').click(); - cy.get('div[data-testid]').contains(labelValues[0]).click(); - cy.focused().type('{esc}'); - - // assert the panel is visible and has the correct value - e2e.components.Panels.Panel.content() - .should('be.visible') - .first() - .within(() => { - cy.get('.markdown-html').should('include.text', `VariableUnderTest: ${labels[1]}="${labelValues[0]}"`); - }); - }); -}); diff --git a/e2e/dashboard-new-layouts/dashboards-edit-datasource-variables.spec.ts b/e2e/dashboard-new-layouts/dashboards-edit-datasource-variables.spec.ts deleted file mode 100644 index 25b8b8608ac..00000000000 --- a/e2e/dashboard-new-layouts/dashboards-edit-datasource-variables.spec.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { e2e } from '../utils'; - -import { flows, Variable } from './dashboard-edit-flows'; - -const PAGE_UNDER_TEST = 'kVi2Gex7z/test-variable-output'; -const DASHBOARD_NAME = 'Test variable output'; - -describe('Dashboard edit - datasource variables', () => { - beforeEach(() => { - e2e.flows.login(Cypress.env('USERNAME'), Cypress.env('PASSWORD')); - }); - - it('can add a new datasource variable', () => { - e2e.pages.Dashboards.visit(); - - e2e.flows.openDashboard({ uid: `${PAGE_UNDER_TEST}?orgId=1` }); - cy.contains(DASHBOARD_NAME).should('be.visible'); - - const dsType = 'cloudwatch'; - - const variable: Variable = { - type: 'datasource', - name: 'VariableUnderTest', - label: 'VariableUnderTest', - value: `gdev-${dsType}`, - }; - - // Common steps to add a new variable - flows.newEditPaneVariableClick(); - flows.newEditPanelCommonVariableInputs(variable); - - e2e.pages.Dashboard.Settings.Variables.Edit.DatasourceVariable.datasourceSelect().should('be.visible').click(); - cy.get(`#combobox-option-${dsType}`).click(); - - const regexFilter = 'cloud'; - e2e.pages.Dashboard.Settings.Variables.Edit.DatasourceVariable.nameFilter().should('be.visible').type(regexFilter); - - // Assert the variable dropdown is visible with correct label - e2e.pages.Dashboard.SubMenu.submenuItemLabels(variable.label).should('be.visible').contains(variable.label); - - // Assert the variable values are correctly displayed in the panel - e2e.components.Panels.Panel.content() - .should('be.visible') - .first() - .within(() => { - cy.get('.markdown-html').should('include.text', `${variable.name}: ${variable.value}`); - }); - }); -}); diff --git a/e2e/dashboard-new-layouts/dashboards-edit-group-by-variables.spec.ts b/e2e/dashboard-new-layouts/dashboards-edit-group-by-variables.spec.ts deleted file mode 100644 index 9af0f6d9e8f..00000000000 --- a/e2e/dashboard-new-layouts/dashboards-edit-group-by-variables.spec.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { e2e } from '../utils'; - -import { flows, Variable } from './dashboard-edit-flows'; - -const PAGE_UNDER_TEST = 'kVi2Gex7z/test-variable-output'; -const DASHBOARD_NAME = 'Test variable output'; - -describe('Dashboard edit - Group By variables', () => { - beforeEach(() => { - e2e.flows.login(Cypress.env('USERNAME'), Cypress.env('PASSWORD')); - }); - - it('can add a new group by variable', () => { - e2e.flows.openDashboard({ uid: `${PAGE_UNDER_TEST}?orgId=1` }); - cy.contains(DASHBOARD_NAME).should('be.visible'); - - const variable: Variable = { - type: 'groupby', - name: 'VariableUnderTest', - value: 'label1', - label: 'VariableUnderTest', - }; - - // common steps to add a new variable - flows.newEditPaneVariableClick(); - flows.newEditPanelCommonVariableInputs(variable); - - e2e.pages.Dashboard.Settings.Variables.Edit.GroupByVariable.dataSourceSelect().should('be.visible').click(); - const dataSource = 'gdev-loki'; - cy.contains(dataSource).scrollIntoView().should('be.visible').click(); - - // mock the API call to get the labels - const labels = ['label1', 'label2']; - cy.intercept('GET', '**/resources/labels*', { - statusCode: 200, - body: { - status: 'success', - data: labels, - }, - }).as('labels'); - - // select the variable in the dashboard and confirm the variable value is set - e2e.pages.Dashboard.SubMenu.submenuItem().should('be.visible').click(); - e2e.pages.Dashboard.SubMenu.submenuItemLabels(variable.label).should('be.visible').contains(variable.label); - - // mock the API call to get the label values - const labelValues = ['label2Value1']; - cy.intercept('GET', `**/resources/label/${labels[1]}/values*`, { - statusCode: 200, - body: { - status: 'success', - data: labelValues, - }, - }).as('label-values'); - - // choose the label and value - cy.get('div[data-testid]').contains(labels[1]).click(); - cy.focused().type('{esc}'); - - // assert the panel is visible and has the correct value - e2e.components.Panels.Panel.content() - .should('be.visible') - .first() - .within(() => { - cy.get('.markdown-html').should('include.text', `VariableUnderTest: ${labels[1]}`); - }); - }); -}); diff --git a/e2e/dashboard-new-layouts/dashboards-edit-panel-title-description.spec.ts b/e2e/dashboard-new-layouts/dashboards-edit-panel-title-description.spec.ts deleted file mode 100644 index a7122c53902..00000000000 --- a/e2e/dashboard-new-layouts/dashboards-edit-panel-title-description.spec.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { e2e } from '../utils'; - -import { flows } from './dashboard-edit-flows'; - -const PAGE_UNDER_TEST = '5SdHCadmz/panel-tests-graph'; - -describe('Dashboard', () => { - beforeEach(() => { - e2e.flows.login(Cypress.env('USERNAME'), Cypress.env('PASSWORD')); - }); - - it('can edit panel title and description', () => { - e2e.flows.openDashboard({ uid: `${PAGE_UNDER_TEST}?orgId=1` }); - - e2e.flows.scenes.toggleEditMode(); - - const oldTitle = 'No Data Points Warning'; - flows.firstPanelTitleShouldBe(oldTitle); - - const newDescription = 'A description of this panel'; - flows.changePanelDescription(oldTitle, newDescription); - - const newTitle = 'New Panel Title'; - flows.changePanelTitle(oldTitle, newTitle); - - // Check that new title is reflected in panel header - flows.firstPanelTitleShouldBe(newTitle); - - // Reveal description tooltip and check that its value is as expected - const descriptionIcon = () => cy.get('[data-testid="title-items-container"] > span').first(); - descriptionIcon().click({ force: true }); - descriptionIcon().then((el) => { - const tooltipId = el.attr('aria-describedby'); - cy.get(`[id="${tooltipId}"]`).should('have.text', `${newDescription}\n`); - }); - }); -}); diff --git a/e2e/dashboard-new-layouts/dashboards-edit-panel-transparent-bg.spec.ts b/e2e/dashboard-new-layouts/dashboards-edit-panel-transparent-bg.spec.ts deleted file mode 100644 index ca6c5df485b..00000000000 --- a/e2e/dashboard-new-layouts/dashboards-edit-panel-transparent-bg.spec.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { e2e } from '../utils'; - -const PAGE_UNDER_TEST = '5SdHCadmz/panel-tests-graph'; - -describe('Dashboard', () => { - beforeEach(() => { - e2e.flows.login(Cypress.env('USERNAME'), Cypress.env('PASSWORD')); - }); - - it('can toggle transparent background switch', () => { - e2e.flows.openDashboard({ uid: `${PAGE_UNDER_TEST}?orgId=1` }); - - e2e.flows.scenes.toggleEditMode(); - - e2e.flows.scenes.selectPanel(/^No Data Points Warning$/); - - e2e.components.Panels.Panel.title('No Data Points Warning').then((el) => { - cy.wrap(el.css('background')).should('not.match', /rgba\(0, 0, 0, 0\)/); - }); - - cy.get('#transparent-background').click({ force: true }); - e2e.components.Panels.Panel.title('No Data Points Warning').then((el) => { - cy.wrap(el.css('background')).should('match', /rgba\(0, 0, 0, 0\)/); - }); - }); -}); diff --git a/e2e/dashboard-new-layouts/dashboards-edit-query-variables.spec.ts b/e2e/dashboard-new-layouts/dashboards-edit-query-variables.spec.ts deleted file mode 100644 index 47e445a3421..00000000000 --- a/e2e/dashboard-new-layouts/dashboards-edit-query-variables.spec.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { e2e } from '../utils'; - -import { flows, Variable } from './dashboard-edit-flows'; - -const PAGE_UNDER_TEST = 'kVi2Gex7z/test-variable-output'; -const DASHBOARD_NAME = 'Test variable output'; - -describe('Dashboard edit - Query variable', () => { - beforeEach(() => { - e2e.flows.login(Cypress.env('USERNAME'), Cypress.env('PASSWORD')); - }); - - it('can add a new query variable', () => { - e2e.flows.openDashboard({ uid: `${PAGE_UNDER_TEST}?orgId=1` }); - cy.contains(DASHBOARD_NAME).should('be.visible'); - - const queryVariableOptions = ['default']; - - const variable: Variable = { - type: 'query', - name: 'VariableUnderTest', - value: queryVariableOptions[0], - label: 'VariableUnderTest', // constant doesn't really need a label - }; - - // common steps to add a new variable - flows.newEditPaneVariableClick(); - flows.newEditPanelCommonVariableInputs(variable); - - // open the modal query variable editor - e2e.pages.Dashboard.Settings.Variables.Edit.QueryVariable.queryOptionsOpenButton().should('be.visible').click(); - // select a core data source that just runs a query during preview - e2e.components.DataSourcePicker.container().should('be.visible').click(); - - // spy on the API call to get the query options - cy.intercept('GET', '/api/datasources/**').as('getOptions'); - - const dataSource = 'gdev-cloudwatch'; - // this will trigger an API call to get the query options - cy.contains(dataSource).scrollIntoView().should('be.visible').click(); - // wait for the API call to finish - cy.wait('@getOptions'); - // show the preview of the query results - e2e.pages.Dashboard.Settings.Variables.Edit.QueryVariable.previewButton().should('be.visible').click(); - // assert the query results are shown - e2e.pages.Dashboard.Settings.Variables.Edit.General.previewOfValuesOption().should('be.visible'); - e2e.pages.Dashboard.Settings.Variables.Edit.General.previewOfValuesOption() - .first() - .then(($el) => { - const previewOption = $el.text().trim(); - cy.wrap(previewOption).as('previewOption'); - }); - - // close the modal - e2e.pages.Dashboard.Settings.Variables.Edit.QueryVariable.closeButton().should('be.visible').click(); - // assert the query variable values are in the variable value select - cy.get('@previewOption').then((opt) => { - e2e.pages.Dashboard.SubMenu.submenuItemLabels(variable.name).next().should('have.text', opt); - // assert the panel is visible and has the correct value - e2e.components.Panels.Panel.content() - .should('be.visible') - .first() - .within(() => { - cy.get('.markdown-html').should('include.text', `VariableUnderTest: ${opt}`); - }); - }); - }); -}); diff --git a/e2e/dashboard-new-layouts/dashboards-edit-variables.spec.ts b/e2e/dashboard-new-layouts/dashboards-edit-variables.spec.ts deleted file mode 100644 index 37737b65c6a..00000000000 --- a/e2e/dashboard-new-layouts/dashboards-edit-variables.spec.ts +++ /dev/null @@ -1,147 +0,0 @@ -import { e2e } from '../utils'; - -import { flows, Variable } from './dashboard-edit-flows'; - -const PAGE_UNDER_TEST = 'kVi2Gex7z/test-variable-output'; -const DASHBOARD_NAME = 'Test variable output'; - -describe('Dashboard edit - variables', () => { - beforeEach(() => { - e2e.flows.login(Cypress.env('USERNAME'), Cypress.env('PASSWORD')); - }); - - it('can add a new custom variable', () => { - e2e.flows.openDashboard({ uid: `${PAGE_UNDER_TEST}?orgId=1` }); - cy.contains(DASHBOARD_NAME).should('be.visible'); - - const variable: Variable = { - type: 'custom', - name: 'foo', - label: 'Foo', - value: 'one,two,three', - }; - - // common steps to add a new variable - flows.newEditPaneVariableClick(); - flows.newEditPanelCommonVariableInputs(variable); - - // set the custom variable value - e2e.pages.Dashboard.Settings.Variables.Edit.CustomVariable.customValueInput().clear().type(variable.value).blur(); - - // assert the dropdown for the variable is visible and has the correct values - e2e.pages.Dashboard.SubMenu.submenuItemLabels(variable.label).should('be.visible').contains(variable.label); - const values = variable.value.split(','); - e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownValueLinkTexts(values[0]).should('be.visible'); - - // check that variable deletion works - e2e.components.EditPaneHeader.deleteButton().click(); - e2e.pages.Dashboard.SubMenu.submenuItemLabels(variable.label).should('not.exist'); - }); - - it('can add a new constant variable', () => { - e2e.flows.openDashboard({ uid: `${PAGE_UNDER_TEST}?orgId=1` }); - cy.contains(DASHBOARD_NAME).should('be.visible'); - - const variable: Variable = { - type: 'constant', - name: 'VariableUnderTest', - value: 'foo', - label: 'VariableUnderTest', // constant doesn't really need a label - }; - - // common steps to add a new variable - flows.newEditPaneVariableClick(); - flows.newEditPanelCommonVariableInputs(variable); - - // set the constant variable value - const type = 'variable-type Value'; - const field = e2e.components.PanelEditor.OptionsPane.fieldLabel(type); - field.should('be.visible'); - field.find('input').should('be.visible').clear().type(variable.value).blur(); - - // assert the panel is visible and has the correct value - e2e.components.Panels.Panel.content() - .should('be.visible') - .first() - .within(() => { - cy.get('.markdown-html').should('include.text', `VariableUnderTest: ${variable.value}`); - }); - }); - - it('can add a new textbox variable', () => { - e2e.flows.openDashboard({ uid: `${PAGE_UNDER_TEST}?orgId=1` }); - cy.contains(DASHBOARD_NAME).should('be.visible'); - - const variable: Variable = { - type: 'textbox', - name: 'VariableUnderTest', - value: 'foo', - label: 'VariableUnderTest', - }; - - // common steps to add a new variable - flows.newEditPaneVariableClick(); - flows.newEditPanelCommonVariableInputs(variable); - - // set the textbox variable value - const type = 'variable-type Value'; - const field = e2e.components.PanelEditor.OptionsPane.fieldLabel(type); - field.should('be.visible'); - field.find('input').should('be.visible').clear().type(variable.value).blur(); - - // select the variable in the dashboard and confirm the variable value is set - e2e.pages.Dashboard.SubMenu.submenuItem().should('be.visible').click(); - e2e.pages.Dashboard.SubMenu.submenuItemLabels(variable.label).should('be.visible').contains(variable.label); - - // assert the panel is visible and has the correct value - e2e.components.Panels.Panel.content() - .should('be.visible') - .first() - .within(() => { - cy.get('.markdown-html').should('include.text', `VariableUnderTest: ${variable.value}`); - }); - }); - - it('can add a new interval variable', () => { - e2e.flows.openDashboard({ uid: `${PAGE_UNDER_TEST}?orgId=1` }); - cy.contains(DASHBOARD_NAME).should('be.visible'); - - const variable: Variable = { - type: 'interval', - name: 'VariableUnderTest', - value: '1m', - label: 'VariableUnderTest', - }; - - // common steps to add a new variable - flows.newEditPaneVariableClick(); - flows.newEditPanelCommonVariableInputs(variable); - - // enable the auto option - e2e.pages.Dashboard.Settings.Variables.Edit.IntervalVariable.autoEnabledCheckbox().click({ force: true }); - - // select the variable in the dashboard and confirm the variable value is set - e2e.pages.Dashboard.SubMenu.submenuItem().should('be.visible').click(); - e2e.pages.Dashboard.SubMenu.submenuItemLabels(variable.label).should('be.visible').contains(variable.label); - - // assert the panel is visible and has the correct value - e2e.components.Panels.Panel.content() - .should('be.visible') - .first() - .within(() => { - cy.get('.markdown-html').should('include.text', `VariableUnderTest: ${variable.value}`); - }); - - // select the variable in the dashboard and set the Auto option - e2e.pages.Dashboard.SubMenu.submenuItemLabels(variable.name).next().should('have.text', `1m`).click(); - e2e.components.Select.option().contains('Auto').click(); - - // assert the panel is visible and has the correct "Auto" value - e2e.components.Panels.Panel.content() - .should('be.visible') - .first() - .within(() => { - cy.get('.markdown-html').should('include.text', `VariableUnderTest: 10m`); - }); - }); -}); diff --git a/e2e/dashboard-new-layouts/dashboards-move-panel.spec.ts b/e2e/dashboard-new-layouts/dashboards-move-panel.spec.ts deleted file mode 100644 index 431a75dd54b..00000000000 --- a/e2e/dashboard-new-layouts/dashboards-move-panel.spec.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { e2e } from '../utils'; - -const PAGE_UNDER_TEST = 'ed155665/annotation-filtering'; - -describe('Dashboard', () => { - beforeEach(() => { - e2e.flows.login(Cypress.env('USERNAME'), Cypress.env('PASSWORD')); - }); - - it('can drag and drop panels', () => { - e2e.flows.openDashboard({ uid: `${PAGE_UNDER_TEST}?orgId=1` }); - - e2e.flows.scenes.toggleEditMode(); - - e2e.flows.scenes.movePanel(/^Panel three$/, /^Panel one$/); - e2e.components.Panels.Panel.headerContainer() - .contains(/^Panel three$/) - .then((panel3) => { - e2e.components.Panels.Panel.headerContainer() - .contains(/^Panel one$/) - .should('be.lowerThan', panel3); - }); - - e2e.flows.scenes.movePanel(/^Panel two$/, /^Panel three$/); - e2e.components.Panels.Panel.headerContainer() - .contains(/^Panel three$/) - .then((panel3) => { - e2e.components.Panels.Panel.headerContainer() - .contains(/^Panel two$/) - .should('be.higherThan', panel3); - }); - }); - - // Note, moving a panel from a nested row to a parent row currently just deletes the panel - // This test will need to be updated once the correct behavior is implemented. - it('can move panel from nested row to parent row', () => { - e2e.flows.openDashboard({ uid: `${PAGE_UNDER_TEST}?orgId=1` }); - - e2e.flows.scenes.toggleEditMode(); - - e2e.flows.scenes.groupIntoRow(); - e2e.flows.scenes.groupIntoRow(); - - cy.get('[data-testid="data-testid dashboard-row-title-New row"]') - .first() - .then((el) => { - const rect = el.offset(); - e2e.components.Panels.Panel.headerContainer() - .contains(/^Panel one$/) - .trigger('pointerdown', { which: 1 }) - .trigger('pointermove', { clientX: rect.left, clientY: rect.top }) - .trigger('pointerup'); - }); - - e2e.components.Panels.Panel.headerContainer() - .contains(/^Panel one$/) - .should('not.exist'); - }); -}); diff --git a/e2e/dashboard-new-layouts/dashboards-panel-layouts.spec.ts b/e2e/dashboard-new-layouts/dashboards-panel-layouts.spec.ts deleted file mode 100644 index 49f4e1bcc3e..00000000000 --- a/e2e/dashboard-new-layouts/dashboards-panel-layouts.spec.ts +++ /dev/null @@ -1,309 +0,0 @@ -import { e2e } from '../utils'; - -describe('Dashboard', () => { - beforeEach(() => { - e2e.flows.login(Cypress.env('USERNAME'), Cypress.env('PASSWORD')); - }); - - it('can switch to auto grid layout', () => { - e2e.flows.scenes.importV2Dashboard({ title: 'Switch to auto grid' }); - - e2e.components.NavToolbar.editDashboard.editButton().click(); - - e2e.components.Panels.Panel.title('New panel').should('have.length', 3); - - e2e.components.OptionsGroup.toggle('grid-layout-category').click(); - - e2e.flows.scenes.selectAutoGridLayout(); - - e2e.components.Panels.Panel.title('New panel').should('have.length', 3); - - const checkInputs = () => { - e2e.components.PanelEditor.ElementEditPane.AutoGridLayout.minColumnWidth().should('be.visible'); - e2e.components.PanelEditor.ElementEditPane.AutoGridLayout.maxColumns().should('be.visible'); - e2e.components.PanelEditor.ElementEditPane.AutoGridLayout.rowHeight().should('be.visible'); - e2e.components.PanelEditor.ElementEditPane.AutoGridLayout.fillScreen().should('exist'); - }; - - checkInputs(); - - e2e.flows.scenes.saveDashboard(); - cy.reload(); - - e2e.components.Panels.Panel.title('New panel').should('have.length', 3); - - e2e.components.NavToolbar.editDashboard.editButton().click(); - - checkInputs(); - }); - - it('can change min column width in auto grid layout', () => { - e2e.flows.scenes.importV2Dashboard({ title: 'Set min column width' }); - - e2e.components.NavToolbar.editDashboard.editButton().click(); - - e2e.components.Panels.Panel.title('New panel').should('have.length', 3); - - e2e.components.OptionsGroup.toggle('grid-layout-category').click(); - - e2e.flows.scenes.selectAutoGridLayout(); - - let firstStandardPanelTopOffset = 0; - - // standard min column width will have 1 panel on a second row in edit mode - e2e.components.Panels.Panel.title('New panel') - .first() - .then((el) => { - firstStandardPanelTopOffset = el.offset().top; - }); - - e2e.components.Panels.Panel.title('New panel') - .last() - .then((el) => { - expect(el.offset().top).to.be.greaterThan(firstStandardPanelTopOffset); - }); - - e2e.components.PanelEditor.ElementEditPane.AutoGridLayout.minColumnWidth().should('be.visible').click(); - cy.get('[id=combobox-option-narrow]').click(); - - const checkOffset = () => { - // narrow min column width will have all panels on the same row - let narrowPanelTopOffset = 0; - - e2e.components.Panels.Panel.title('New panel') - .first() - .then((el) => { - narrowPanelTopOffset = el.offset().top; - }); - - e2e.components.Panels.Panel.title('New panel') - .last() - .then((el) => { - expect(el.offset().top).to.eq(narrowPanelTopOffset); - }); - }; - - checkOffset(); - - e2e.flows.scenes.saveDashboard(); - cy.reload(); - - e2e.components.NavToolbar.editDashboard.editButton().click(); - - e2e.components.PanelEditor.ElementEditPane.AutoGridLayout.minColumnWidth().should('have.value', 'Narrow'); - - checkOffset(); - }); - - it('can change to custom min column width in auto grid layout', () => { - e2e.flows.scenes.importV2Dashboard({ title: 'Set custom min column width' }); - - e2e.components.NavToolbar.editDashboard.editButton().click(); - - e2e.components.Panels.Panel.title('New panel').should('have.length', 3); - - e2e.components.OptionsGroup.toggle('grid-layout-category').click(); - - e2e.flows.scenes.selectAutoGridLayout(); - - e2e.components.PanelEditor.ElementEditPane.AutoGridLayout.minColumnWidth().should('be.visible').click(); - cy.get('[id=combobox-option-custom]').click(); - - e2e.components.PanelEditor.ElementEditPane.AutoGridLayout.customMinColumnWidth() - .should('be.visible') - .clear() - .type('900') - .blur(); - - cy.wait(100); // cy too fast and executes next command before resizing is done - - // // changing to 900 custom width to have each panel span the whole row to verify offset - e2e.flows.scenes.verifyPanelsStackedVertically(); - - e2e.flows.scenes.saveDashboard(); - cy.reload(); - - e2e.flows.scenes.verifyPanelsStackedVertically(); - - e2e.components.NavToolbar.editDashboard.editButton().click(); - e2e.components.PanelEditor.ElementEditPane.AutoGridLayout.customMinColumnWidth().should('have.value', '900'); - - e2e.flows.scenes.verifyPanelsStackedVertically(); - - e2e.components.PanelEditor.ElementEditPane.AutoGridLayout.clearCustomMinColumnWidth().should('be.visible').click(); - e2e.components.PanelEditor.ElementEditPane.AutoGridLayout.minColumnWidth().should('have.value', 'Standard'); - }); - - it('can change max columns in auto grid layout', () => { - e2e.flows.scenes.importV2Dashboard({ title: 'Set max columns' }); - - e2e.components.NavToolbar.editDashboard.editButton().click(); - - e2e.components.Panels.Panel.title('New panel').should('have.length', 3); - - e2e.components.OptionsGroup.toggle('grid-layout-category').click(); - - e2e.flows.scenes.selectAutoGridLayout(); - - e2e.components.PanelEditor.ElementEditPane.AutoGridLayout.maxColumns().should('be.visible').click(); - cy.get('[id=combobox-option-1]').click(); - - // changing to 1 max column to have each panel span the whole row to verify offset - e2e.flows.scenes.verifyPanelsStackedVertically(); - - e2e.flows.scenes.saveDashboard(); - cy.reload(); - - e2e.flows.scenes.verifyPanelsStackedVertically(); - - e2e.components.NavToolbar.editDashboard.editButton().click(); - - e2e.components.PanelEditor.ElementEditPane.AutoGridLayout.maxColumns().should('have.value', '1'); - - e2e.flows.scenes.verifyPanelsStackedVertically(); - }); - - it('can change row height in auto grid layout', () => { - e2e.flows.scenes.importV2Dashboard({ title: 'Set row height' }); - - e2e.components.NavToolbar.editDashboard.editButton().click(); - - e2e.components.Panels.Panel.title('New panel').should('have.length', 3); - - e2e.components.OptionsGroup.toggle('grid-layout-category').click(); - - e2e.flows.scenes.selectAutoGridLayout(); - - let regularRowHeight = 0; - - e2e.components.Panels.Panel.title('New panel') - .first() - .then((el) => { - regularRowHeight = el.height(); - }); - - e2e.components.PanelEditor.ElementEditPane.AutoGridLayout.rowHeight().should('be.visible').click(); - cy.get('[id=combobox-option-short]').click(); - - e2e.components.Panels.Panel.title('New panel') - .first() - .then((el) => { - expect(el.height()).to.be.lessThan(regularRowHeight); - }); - - e2e.components.PanelEditor.ElementEditPane.AutoGridLayout.rowHeight().should('be.visible').click(); - cy.get('[id=combobox-option-tall]').click(); - - const checkHeight = () => { - e2e.components.Panels.Panel.title('New panel') - .first() - .then((el) => { - expect(el.height()).to.be.greaterThan(regularRowHeight); - }); - }; - - checkHeight(); - - e2e.flows.scenes.saveDashboard(); - cy.reload(); - - checkHeight(); - - e2e.components.NavToolbar.editDashboard.editButton().click(); - - e2e.components.PanelEditor.ElementEditPane.AutoGridLayout.rowHeight().should('have.value', 'Tall'); - - checkHeight(); - }); - - it('can change to custom row height in auto grid layout', () => { - e2e.flows.scenes.importV2Dashboard({ title: 'Set custom row height' }); - - e2e.components.NavToolbar.editDashboard.editButton().click(); - - e2e.components.Panels.Panel.title('New panel').should('have.length', 3); - - e2e.components.OptionsGroup.toggle('grid-layout-category').click(); - - e2e.flows.scenes.selectAutoGridLayout(); - - let regularRowHeight = 0; - - e2e.components.Panels.Panel.title('New panel') - .first() - .then((el) => { - regularRowHeight = el.height(); - }); - - e2e.components.PanelEditor.ElementEditPane.AutoGridLayout.rowHeight().should('be.visible').click(); - cy.get('[id=combobox-option-custom]').click(); - e2e.components.PanelEditor.ElementEditPane.AutoGridLayout.customRowHeight().clear().type('800').blur(); - cy.wait(100); // cy too fast and executes next command before resizing is done - - e2e.components.Panels.Panel.title('New panel') - .first() - .then((el) => { - const elHeight = el.height(); - expect(elHeight).be.closeTo(800, 5); // some flakyness and get 798 sometimes - expect(elHeight).to.be.greaterThan(regularRowHeight); - }); - - e2e.flows.scenes.saveDashboard(); - cy.reload(); - - e2e.components.Panels.Panel.title('New panel') - .first() - .then((el) => { - expect(el.height()).be.closeTo(800, 5); // some flakyness and get 798 sometimes - }); - - e2e.components.NavToolbar.editDashboard.editButton().click(); - - e2e.components.PanelEditor.ElementEditPane.AutoGridLayout.customRowHeight().should('have.value', '800'); - e2e.components.PanelEditor.ElementEditPane.AutoGridLayout.clearCustomRowHeight().should('be.visible').click(); - e2e.components.PanelEditor.ElementEditPane.AutoGridLayout.rowHeight().should('have.value', 'Standard'); - }); - - it('can change fill screen in auto grid layout', () => { - e2e.flows.scenes.importV2Dashboard({ title: 'Set fill screen' }); - - e2e.components.NavToolbar.editDashboard.editButton().click(); - - e2e.components.Panels.Panel.title('New panel').should('have.length', 3); - - e2e.components.OptionsGroup.toggle('grid-layout-category').click(); - - e2e.flows.scenes.selectAutoGridLayout(); - - e2e.components.PanelEditor.ElementEditPane.AutoGridLayout.minColumnWidth().should('be.visible').click(); - cy.get('[id=combobox-option-narrow]').click(); - - let initialHeight = 0; - - e2e.components.Panels.Panel.title('New panel') - .first() - .then((el) => { - initialHeight = el.height(); - }); - - e2e.components.PanelEditor.ElementEditPane.AutoGridLayout.fillScreen().click({ force: true }); - - const checkHeight = () => { - e2e.components.Panels.Panel.title('New panel') - .first() - .then((el) => { - expect(el.height()).to.be.greaterThan(initialHeight); - }); - }; - - checkHeight(); - e2e.flows.scenes.saveDashboard(); - cy.reload(); - - checkHeight(); - e2e.components.NavToolbar.editDashboard.editButton().click(); - e2e.components.PanelEditor.ElementEditPane.AutoGridLayout.fillScreen().should('be.checked'); - - checkHeight(); - }); -}); diff --git a/e2e/dashboard-new-layouts/dashboards-remove-panel.spec.ts b/e2e/dashboard-new-layouts/dashboards-remove-panel.spec.ts deleted file mode 100644 index 7256a4f4740..00000000000 --- a/e2e/dashboard-new-layouts/dashboards-remove-panel.spec.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { e2e } from '../utils'; - -const PAGE_UNDER_TEST = 'edediimbjhdz4b/a-tall-dashboard'; - -describe('Dashboard panels', () => { - beforeEach(() => { - e2e.flows.login(Cypress.env('USERNAME'), Cypress.env('PASSWORD')); - }); - - it('can remove a panel', () => { - e2e.flows.openDashboard({ uid: `${PAGE_UNDER_TEST}?orgId=1` }); - - e2e.flows.scenes.toggleEditMode(); - - e2e.flows.scenes.removePanels(/^Panel #1$/); - - // Check that panel has been deleted - e2e.components.Panels.Panel.headerContainer() - .contains(/^Panel #1$/) - .should('not.exist'); - }); - - it('can remove several panels at once', () => { - e2e.flows.openDashboard({ uid: `${PAGE_UNDER_TEST}?orgId=1` }); - - e2e.flows.scenes.toggleEditMode(); - - e2e.flows.scenes.removePanels(/^Panel #1$/, /^Panel #2$/, /^Panel #3$/); - - // Check that panels have been deleted - e2e.components.Panels.Panel.headerContainer() - .contains(/^Panel #[123]$/) - .should('not.exist'); - }); -}); diff --git a/e2e/dashboard-new-layouts/dashboards-title-description.spec.ts b/e2e/dashboard-new-layouts/dashboards-title-description.spec.ts deleted file mode 100644 index 2ae8eb28f3e..00000000000 --- a/e2e/dashboard-new-layouts/dashboards-title-description.spec.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { e2e } from '../utils'; - -const PAGE_UNDER_TEST = 'ed155665/annotation-filtering'; - -describe('Dashboard', () => { - beforeEach(() => { - e2e.flows.login(Cypress.env('USERNAME'), Cypress.env('PASSWORD')); - }); - - it('can change dashboard description and title', () => { - e2e.flows.openDashboard({ uid: `${PAGE_UNDER_TEST}?orgId=1` }); - - e2e.flows.scenes.toggleEditMode(); - - // Check that current dashboard title is visible in breadcrumb - cy.get('[aria-label="Breadcrumbs"]').contains('Annotation filtering').should('exist'); - - const titleInput = () => cy.get('[aria-label="dashboard-options Title field property editor"] input'); - titleInput().should('have.value', 'Annotation filtering').clear().type('New dashboard title'); - titleInput().should('have.value', 'New dashboard title'); - - // Check that new dashboard title is reflected in breadcrumb - cy.get('[aria-label="Breadcrumbs"]').contains('New dashboard title').should('exist'); - - // Check that we can successfully change the dashboard description - const descriptionTextArea = () => - cy.get('[aria-label="dashboard-options Description field property editor"] textarea'); - descriptionTextArea().clear().type('Dashboard description'); - descriptionTextArea().should('have.value', 'Dashboard description'); - }); -}); diff --git a/e2e/run-suite b/e2e/run-suite index 386fbae4f0e..3303918e1fd 100755 --- a/e2e/run-suite +++ b/e2e/run-suite @@ -30,7 +30,6 @@ rootForEnterpriseSuite="./e2e/extensions" rootForOldArch="./e2e/old-arch" rootForKubernetesDashboards="./e2e/dashboards-suite" rootForSearchDashboards="./e2e/dashboards-search-suite" -rootForDashboardNewLayouts="./e2e/dashboard-new-layouts" declare -A cypressConfig=( [screenshotsFolder]=./e2e/"${args[0]}"/screenshots @@ -148,28 +147,6 @@ case "$1" in ;; esac ;; - "dashboard-new-layouts") - env[kubernetesDashboards]=true - env[dashboardNewLayouts]=true - env[groupByVariable]=true - cypressConfig[specPattern]=$rootForDashboardNewLayouts/$testFilesForSingleSuite - cypressConfig[video]=false - case "$2" in - "debug") - echo -e "Debug mode" - env[SLOWMO]=1 - PARAMS="--no-exit" - enterpriseSuite=$(basename "${args[2]}") - ;; - "dev") - echo "Dev mode" - # remove comment to run in slomo ( demo mode ) - # env[SLOWMO]=1 - CMD="cypress open" - enterpriseSuite=$(basename "${args[2]}") - ;; - esac - ;; "enterprise-smtp") env[SMTP_PLUGIN_ENABLED]=true cypressConfig[specPattern]=./e2e/extensions/enterprise/smtp-suite/$testFilesForSingleSuite diff --git a/package.json b/package.json index f647fe32435..34741ebf2a2 100644 --- a/package.json +++ b/package.json @@ -15,8 +15,6 @@ "e2e:old-arch": "./e2e/start-and-run-suite old-arch", "e2e:schema-v2": "./e2e/start-and-run-suite dashboards-schema-v2", "e2e:dashboards-search": "./e2e/start-and-run-suite dashboards-search", - "e2e:dashboard-new-layouts": "./e2e/start-and-run-suite dashboard-new-layouts", - "e2e:dashboard-new-layouts:dev": "./e2e/start-and-run-suite dashboard-new-layouts dev", "e2e:debug": "./e2e/start-and-run-suite debug", "e2e:dev": "./e2e/start-and-run-suite dev", "e2e:benchmark:live": "./e2e/start-and-run-suite benchmark live", From 6b4d93b8ecf95a6df0a97598e5c1a9cf2596e5f8 Mon Sep 17 00:00:00 2001 From: Adam Simpson Date: Mon, 28 Jul 2025 10:42:32 -0400 Subject: [PATCH 053/131] querier: check for headers to force expr parsing (#108701) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Gábor Farkas --- pkg/services/query/query.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/pkg/services/query/query.go b/pkg/services/query/query.go index d3f05438e45..e2c3f68043d 100644 --- a/pkg/services/query/query.go +++ b/pkg/services/query/query.go @@ -25,6 +25,7 @@ import ( "github.com/grafana/grafana/pkg/services/contexthandler" "github.com/grafana/grafana/pkg/services/datasources" "github.com/grafana/grafana/pkg/services/mtdsclient" + "github.com/grafana/grafana/pkg/services/ngalert/models" "github.com/grafana/grafana/pkg/services/pluginsintegration/plugincontext" "github.com/grafana/grafana/pkg/services/validations" "github.com/grafana/grafana/pkg/setting" @@ -97,6 +98,12 @@ func (s *ServiceImpl) Run(ctx context.Context) error { // QueryData processes queries and returns query responses. It handles queries to single or mixed datasources, as well as expressions. func (s *ServiceImpl) QueryData(ctx context.Context, user identity.Requester, skipDSCache bool, reqDTO dtos.MetricRequest) (*backend.QueryDataResponse, error) { + fromAlert := false + for header, val := range s.headers { + if header == models.FromAlertHeaderName && val == "true" { + fromAlert = true + } + } // Parse the request into parsed queries grouped by datasource uid parsedReq, err := s.parseMetricRequest(ctx, user, skipDSCache, reqDTO) if err != nil { @@ -104,7 +111,7 @@ func (s *ServiceImpl) QueryData(ctx context.Context, user identity.Requester, sk } // If there are expressions, handle them and return - if parsedReq.hasExpression { + if parsedReq.hasExpression || fromAlert { return s.handleExpressions(ctx, user, parsedReq) } // If there is only one datasource, query it and return From 4c6888654cf0e225c84b446e931c03a63c60cfdb Mon Sep 17 00:00:00 2001 From: Alex Khomenko Date: Mon, 28 Jul 2025 17:55:28 +0300 Subject: [PATCH 054/131] Provisioning: Re-fetch folders after creating or deleting a repository (#108778) * refetch folder * Simplify refetches * Cleanup * Tests * More test mocks * Function selectors * Comment * Remove unused selector --- .../clients/provisioning/v0alpha1/index.ts | 13 ++++++++ .../scene/NavToolbarActions.tsx | 2 +- .../Wizard/ProvisioningWizard.test.tsx | 4 +++ .../features/provisioning/utils/selectors.ts | 31 +++++++------------ 4 files changed, 30 insertions(+), 20 deletions(-) diff --git a/public/app/api/clients/provisioning/v0alpha1/index.ts b/public/app/api/clients/provisioning/v0alpha1/index.ts index c92490184b1..eb200d83d01 100644 --- a/public/app/api/clients/provisioning/v0alpha1/index.ts +++ b/public/app/api/clients/provisioning/v0alpha1/index.ts @@ -3,6 +3,8 @@ import { isFetchError } from '@grafana/runtime'; import { notifyApp } from '../../../../core/actions'; import { createSuccessNotification, createErrorNotification } from '../../../../core/copy/appNotification'; +import { PAGE_SIZE } from '../../../../features/browse-dashboards/api/services'; +import { refetchChildren } from '../../../../features/browse-dashboards/state/actions'; import { createOnCacheEntryAdded } from '../utils/createOnCacheEntryAdded'; import { @@ -59,6 +61,12 @@ export const provisioningAPIv0alpha1 = generatedAPI.enhanceEndpoints({ ); } } + // Refetch dashboards and folders after deleting a provisioned repository. + // We need to add timeout to ensure that the deletion is processed before refetching since the deletion is done + // via a background job. + setTimeout(() => { + dispatch(refetchChildren({ parentUID: undefined, pageSize: PAGE_SIZE })); + }, 1000); }, }, deletecollectionRepository: { @@ -84,6 +92,9 @@ export const provisioningAPIv0alpha1 = generatedAPI.enhanceEndpoints({ ); } } + setTimeout(() => { + dispatch(refetchChildren({ parentUID: undefined, pageSize: PAGE_SIZE })); + }, 1000); }, }, createRepositoryTest: { @@ -189,6 +200,8 @@ export const provisioningAPIv0alpha1 = generatedAPI.enhanceEndpoints({ ); } } + // Refetch dashboards and folders after creating/updating a provisioned repository + dispatch(refetchChildren({ parentUID: undefined, pageSize: PAGE_SIZE })); }, }, }, diff --git a/public/app/features/dashboard-scene/scene/NavToolbarActions.tsx b/public/app/features/dashboard-scene/scene/NavToolbarActions.tsx index 49b4a3c9f53..00dbd0943a3 100644 --- a/public/app/features/dashboard-scene/scene/NavToolbarActions.tsx +++ b/public/app/features/dashboard-scene/scene/NavToolbarActions.tsx @@ -73,7 +73,7 @@ export function ToolbarActions({ dashboard }: Props) { // Means we are not in settings view, fullscreen panel or edit panel const isShowingDashboard = !editview && !isViewingPanel && !isEditingPanel; const isEditingAndShowingDashboard = isEditing && isShowingDashboard; - const folderRepo = useSelector((state) => selectFolderRepository(state, meta.folderUid)); + const folderRepo = useSelector((state) => selectFolderRepository()(state, meta.folderUid)); const isManaged = Boolean(dashboard.isManagedRepository() || folderRepo); // Internal only; diff --git a/public/app/features/provisioning/Wizard/ProvisioningWizard.test.tsx b/public/app/features/provisioning/Wizard/ProvisioningWizard.test.tsx index 83fc75ddfb9..f9c293137d9 100644 --- a/public/app/features/provisioning/Wizard/ProvisioningWizard.test.tsx +++ b/public/app/features/provisioning/Wizard/ProvisioningWizard.test.tsx @@ -38,6 +38,10 @@ jest.mock('app/api/clients/provisioning/v0alpha1', () => ({ useCreateRepositoryJobsMutation: jest.fn(), })); +jest.mock('app/features/browse-dashboards/api/services', () => ({ + PAGE_SIZE: 20, +})); + const mockUseCreateOrUpdateRepository = useCreateOrUpdateRepository as jest.MockedFunction< typeof useCreateOrUpdateRepository >; diff --git a/public/app/features/provisioning/utils/selectors.ts b/public/app/features/provisioning/utils/selectors.ts index 1e88f0b9530..372d3567e2b 100644 --- a/public/app/features/provisioning/utils/selectors.ts +++ b/public/app/features/provisioning/utils/selectors.ts @@ -1,28 +1,21 @@ import { createSelector } from '@reduxjs/toolkit'; -import { RootState } from 'app/store/configureStore'; - import { Repository, provisioningAPIv0alpha1 as provisioningAPI } from '../../../api/clients/provisioning/v0alpha1'; const emptyRepos: Repository[] = []; -const baseSelector = provisioningAPI.endpoints.listRepository.select({}); +const getBaseSelector = () => provisioningAPI.endpoints.listRepository.select({}); -export const selectAllRepos = createSelector(baseSelector, (result) => result.data?.items || emptyRepos); +export const selectAllRepos = () => createSelector(getBaseSelector(), (result) => result.data?.items || emptyRepos); -export const selectFolderRepository = createSelector( - selectAllRepos, - (_, folderUid?: string) => folderUid, - (repositories: Repository[], folderUid) => { - if (!folderUid) { - return undefined; +export const selectFolderRepository = () => + createSelector( + selectAllRepos(), + (_, folderUid?: string) => folderUid, + (repositories: Repository[], folderUid) => { + if (!folderUid) { + return undefined; + } + return repositories.find((repo: Repository) => repo.metadata?.name === folderUid); } - return repositories.find((repo: Repository) => repo.metadata?.name === folderUid); - } -); - -export const selectRepoByName = createSelector( - selectAllRepos, - (state: RootState, id: string) => id, - (repositories: Repository[], name) => repositories.find((repo: Repository) => repo.metadata?.name === name) -); + ); From e261d5f14a9f4fdd40c787f99980936b228332c5 Mon Sep 17 00:00:00 2001 From: Isabella Siu Date: Mon, 28 Jul 2025 10:58:21 -0400 Subject: [PATCH 055/131] CloudWatch: Clear log groups when region is changed (#108727) --- .../QueryEditor/QueryHeader.test.tsx | 20 +++++++++++++++---- .../components/QueryEditor/QueryHeader.tsx | 4 ++-- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/public/app/plugins/datasource/cloudwatch/components/QueryEditor/QueryHeader.test.tsx b/public/app/plugins/datasource/cloudwatch/components/QueryEditor/QueryHeader.test.tsx index 01af5b18121..5658dedf92f 100644 --- a/public/app/plugins/datasource/cloudwatch/components/QueryEditor/QueryHeader.test.tsx +++ b/public/app/plugins/datasource/cloudwatch/components/QueryEditor/QueryHeader.test.tsx @@ -26,14 +26,19 @@ describe('QueryHeader', () => { { value: 'us-east-2', label: 'us-east-2' }, { value: 'us-east-1', label: 'us-east-1' }, ]); - it('should reset account id if new region is not monitoring account', async () => { + it('should reset account id and log groups if new region is not monitoring account', async () => { config.featureToggles.cloudWatchCrossAccountQuerying = true; const onChange = jest.fn(); datasource.resources.isMonitoringAccount = jest.fn().mockResolvedValue(false); render( { ...validMetricSearchBuilderQuery, region: 'us-east-2', accountId: undefined, + logGroups: [], }); }); - it('should not reset account id if new region is a monitoring account', async () => { + it('should reset log groups but not account id if new region is a monitoring account', async () => { config.featureToggles.cloudWatchCrossAccountQuerying = true; const onChange = jest.fn(); datasource.resources.isMonitoringAccount = jest.fn().mockResolvedValue(true); @@ -56,7 +62,12 @@ describe('QueryHeader', () => { render( { ...validMetricSearchBuilderQuery, region: 'us-east-2', accountId: '123', + logGroups: [], }); }); diff --git a/public/app/plugins/datasource/cloudwatch/components/QueryEditor/QueryHeader.tsx b/public/app/plugins/datasource/cloudwatch/components/QueryEditor/QueryHeader.tsx index d252f1fa78d..57568a0666e 100644 --- a/public/app/plugins/datasource/cloudwatch/components/QueryEditor/QueryHeader.tsx +++ b/public/app/plugins/datasource/cloudwatch/components/QueryEditor/QueryHeader.tsx @@ -47,9 +47,9 @@ const QueryHeader = ({ const onRegionChange = async (region: string) => { if (config.featureToggles.cloudWatchCrossAccountQuerying && isCloudWatchMetricsQuery(query)) { const isMonitoringAccount = await datasource.resources.isMonitoringAccount(region); - onChange({ ...query, region, accountId: isMonitoringAccount ? query.accountId : undefined }); + onChange({ ...query, logGroups: [], region, accountId: isMonitoringAccount ? query.accountId : undefined }); } else { - onChange({ ...query, region }); + onChange({ ...query, logGroups: [], region }); } }; From 2d3fde46074f936743c39759d0b5844be60e5365 Mon Sep 17 00:00:00 2001 From: Angel Kozlev Date: Mon, 28 Jul 2025 16:21:36 +0100 Subject: [PATCH 056/131] Pyroscope: Remove LegacyForms from ConfigEditor (#104973) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Pyroscope: Remove LegacyForms from ConfigEditor * Pyroscope: Align fields in form * Pyroscope: Add id to input and label for a11y * Update public/app/plugins/datasource/grafana-pyroscope-datasource/ConfigEditor.tsx --------- Co-authored-by: Piotr Jamróz Co-authored-by: Joey --- .../ConfigEditor.tsx | 64 ++++++++----------- 1 file changed, 25 insertions(+), 39 deletions(-) diff --git a/public/app/plugins/datasource/grafana-pyroscope-datasource/ConfigEditor.tsx b/public/app/plugins/datasource/grafana-pyroscope-datasource/ConfigEditor.tsx index 3b2e3cbb5d0..f3442a6a52d 100644 --- a/public/app/plugins/datasource/grafana-pyroscope-datasource/ConfigEditor.tsx +++ b/public/app/plugins/datasource/grafana-pyroscope-datasource/ConfigEditor.tsx @@ -11,15 +11,7 @@ import { convertLegacyAuthProps, } from '@grafana/plugin-ui'; import { config } from '@grafana/runtime'; -import { - Divider, - EventsWithValidation, - LegacyForms, - SecureSocksProxySettings, - Stack, - regexValidation, - useStyles2, -} from '@grafana/ui'; +import { Divider, Field, Input, SecureSocksProxySettings, Stack, useStyles2 } from '@grafana/ui'; import { PyroscopeDataSourceOptions } from './types'; @@ -56,7 +48,7 @@ export const ConfigEditor = (props: Props) => { isCollapsible={true} isInitiallyOpen={false} > - + {config.secureSocksDSProxyEnabled && ( @@ -64,36 +56,30 @@ export const ConfigEditor = (props: Props) => { )} - { - onOptionsChange({ - ...options, - jsonData: { - ...options.jsonData, - minStep: event.currentTarget.value, - }, - }); - }} - validationEvents={{ - [EventsWithValidation.onBlur]: [ - regexValidation( - /^$|^\d+(ms|[Mwdhmsy])$/, - 'Value is not valid, you can use number with time unit specifier: y, M, w, d, h, m, s' - ), - ], - }} - /> - } - tooltip="Minimal step used for metric query. Should be the same or higher as the scrape interval setting in the Pyroscope database." - /> + htmlFor="minimal-step" + description="Minimal step used for metric query. Should be the same or higher as the scrape interval setting in the Pyroscope database." + error="Value is not valid, you can use number with time unit specifier: y, M, w, d, h, m, s" + invalid={!!options.jsonData.minStep && !/^\d+(ms|[Mwdhmsy])$/.test(options.jsonData.minStep)} + > + { + onOptionsChange({ + ...options, + jsonData: { + ...options.jsonData, + minStep: event.currentTarget.value, + }, + }); + }} + /> + From d5fb158ebd3c8b943949a981e4c4948145373b1d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 28 Jul 2025 16:43:04 +0100 Subject: [PATCH 057/131] Update dependency rollup to v4.46.1 (#108792) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 182 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 101 insertions(+), 81 deletions(-) diff --git a/yarn.lock b/yarn.lock index 99cfd2d8de6..3b83aff5bd6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6865,128 +6865,142 @@ __metadata: languageName: node linkType: hard -"@rollup/rollup-android-arm-eabi@npm:4.26.0": - version: 4.26.0 - resolution: "@rollup/rollup-android-arm-eabi@npm:4.26.0" +"@rollup/rollup-android-arm-eabi@npm:4.46.1": + version: 4.46.1 + resolution: "@rollup/rollup-android-arm-eabi@npm:4.46.1" conditions: os=android & cpu=arm languageName: node linkType: hard -"@rollup/rollup-android-arm64@npm:4.26.0": - version: 4.26.0 - resolution: "@rollup/rollup-android-arm64@npm:4.26.0" +"@rollup/rollup-android-arm64@npm:4.46.1": + version: 4.46.1 + resolution: "@rollup/rollup-android-arm64@npm:4.46.1" conditions: os=android & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-darwin-arm64@npm:4.26.0": - version: 4.26.0 - resolution: "@rollup/rollup-darwin-arm64@npm:4.26.0" +"@rollup/rollup-darwin-arm64@npm:4.46.1": + version: 4.46.1 + resolution: "@rollup/rollup-darwin-arm64@npm:4.46.1" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-darwin-x64@npm:4.26.0": - version: 4.26.0 - resolution: "@rollup/rollup-darwin-x64@npm:4.26.0" +"@rollup/rollup-darwin-x64@npm:4.46.1": + version: 4.46.1 + resolution: "@rollup/rollup-darwin-x64@npm:4.46.1" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@rollup/rollup-freebsd-arm64@npm:4.26.0": - version: 4.26.0 - resolution: "@rollup/rollup-freebsd-arm64@npm:4.26.0" +"@rollup/rollup-freebsd-arm64@npm:4.46.1": + version: 4.46.1 + resolution: "@rollup/rollup-freebsd-arm64@npm:4.46.1" conditions: os=freebsd & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-freebsd-x64@npm:4.26.0": - version: 4.26.0 - resolution: "@rollup/rollup-freebsd-x64@npm:4.26.0" +"@rollup/rollup-freebsd-x64@npm:4.46.1": + version: 4.46.1 + resolution: "@rollup/rollup-freebsd-x64@npm:4.46.1" conditions: os=freebsd & cpu=x64 languageName: node linkType: hard -"@rollup/rollup-linux-arm-gnueabihf@npm:4.26.0": - version: 4.26.0 - resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.26.0" +"@rollup/rollup-linux-arm-gnueabihf@npm:4.46.1": + version: 4.46.1 + resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.46.1" conditions: os=linux & cpu=arm & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-arm-musleabihf@npm:4.26.0": - version: 4.26.0 - resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.26.0" +"@rollup/rollup-linux-arm-musleabihf@npm:4.46.1": + version: 4.46.1 + resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.46.1" conditions: os=linux & cpu=arm & libc=musl languageName: node linkType: hard -"@rollup/rollup-linux-arm64-gnu@npm:4.26.0": - version: 4.26.0 - resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.26.0" +"@rollup/rollup-linux-arm64-gnu@npm:4.46.1": + version: 4.46.1 + resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.46.1" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-arm64-musl@npm:4.26.0": - version: 4.26.0 - resolution: "@rollup/rollup-linux-arm64-musl@npm:4.26.0" +"@rollup/rollup-linux-arm64-musl@npm:4.46.1": + version: 4.46.1 + resolution: "@rollup/rollup-linux-arm64-musl@npm:4.46.1" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"@rollup/rollup-linux-powerpc64le-gnu@npm:4.26.0": - version: 4.26.0 - resolution: "@rollup/rollup-linux-powerpc64le-gnu@npm:4.26.0" +"@rollup/rollup-linux-loongarch64-gnu@npm:4.46.1": + version: 4.46.1 + resolution: "@rollup/rollup-linux-loongarch64-gnu@npm:4.46.1" + conditions: os=linux & cpu=loong64 & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-ppc64-gnu@npm:4.46.1": + version: 4.46.1 + resolution: "@rollup/rollup-linux-ppc64-gnu@npm:4.46.1" conditions: os=linux & cpu=ppc64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-riscv64-gnu@npm:4.26.0": - version: 4.26.0 - resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.26.0" +"@rollup/rollup-linux-riscv64-gnu@npm:4.46.1": + version: 4.46.1 + resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.46.1" conditions: os=linux & cpu=riscv64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-s390x-gnu@npm:4.26.0": - version: 4.26.0 - resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.26.0" +"@rollup/rollup-linux-riscv64-musl@npm:4.46.1": + version: 4.46.1 + resolution: "@rollup/rollup-linux-riscv64-musl@npm:4.46.1" + conditions: os=linux & cpu=riscv64 & libc=musl + languageName: node + linkType: hard + +"@rollup/rollup-linux-s390x-gnu@npm:4.46.1": + version: 4.46.1 + resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.46.1" conditions: os=linux & cpu=s390x & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-x64-gnu@npm:4.26.0": - version: 4.26.0 - resolution: "@rollup/rollup-linux-x64-gnu@npm:4.26.0" +"@rollup/rollup-linux-x64-gnu@npm:4.46.1": + version: 4.46.1 + resolution: "@rollup/rollup-linux-x64-gnu@npm:4.46.1" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-x64-musl@npm:4.26.0": - version: 4.26.0 - resolution: "@rollup/rollup-linux-x64-musl@npm:4.26.0" +"@rollup/rollup-linux-x64-musl@npm:4.46.1": + version: 4.46.1 + resolution: "@rollup/rollup-linux-x64-musl@npm:4.46.1" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@rollup/rollup-win32-arm64-msvc@npm:4.26.0": - version: 4.26.0 - resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.26.0" +"@rollup/rollup-win32-arm64-msvc@npm:4.46.1": + version: 4.46.1 + resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.46.1" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-win32-ia32-msvc@npm:4.26.0": - version: 4.26.0 - resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.26.0" +"@rollup/rollup-win32-ia32-msvc@npm:4.46.1": + version: 4.46.1 + resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.46.1" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@rollup/rollup-win32-x64-msvc@npm:4.26.0": - version: 4.26.0 - resolution: "@rollup/rollup-win32-x64-msvc@npm:4.26.0" +"@rollup/rollup-win32-x64-msvc@npm:4.46.1": + version: 4.46.1 + resolution: "@rollup/rollup-win32-x64-msvc@npm:4.46.1" conditions: os=win32 & cpu=x64 languageName: node linkType: hard @@ -9435,10 +9449,10 @@ __metadata: languageName: node linkType: hard -"@types/estree@npm:*, @types/estree@npm:1.0.6, @types/estree@npm:^1.0.0, @types/estree@npm:^1.0.5, @types/estree@npm:^1.0.6": - version: 1.0.6 - resolution: "@types/estree@npm:1.0.6" - checksum: 10/9d35d475095199c23e05b431bcdd1f6fec7380612aed068b14b2a08aa70494de8a9026765a5a91b1073f636fb0368f6d8973f518a31391d519e20c59388ed88d +"@types/estree@npm:*, @types/estree@npm:1.0.8, @types/estree@npm:^1.0.0, @types/estree@npm:^1.0.5, @types/estree@npm:^1.0.6": + version: 1.0.8 + resolution: "@types/estree@npm:1.0.8" + checksum: 10/25a4c16a6752538ffde2826c2cc0c6491d90e69cd6187bef4a006dd2c3c45469f049e643d7e516c515f21484dc3d48fd5c870be158a5beb72f5baf3dc43e4099 languageName: node linkType: hard @@ -28225,28 +28239,30 @@ __metadata: linkType: hard "rollup@npm:^4.22.4": - version: 4.26.0 - resolution: "rollup@npm:4.26.0" + version: 4.46.1 + resolution: "rollup@npm:4.46.1" dependencies: - "@rollup/rollup-android-arm-eabi": "npm:4.26.0" - "@rollup/rollup-android-arm64": "npm:4.26.0" - "@rollup/rollup-darwin-arm64": "npm:4.26.0" - "@rollup/rollup-darwin-x64": "npm:4.26.0" - "@rollup/rollup-freebsd-arm64": "npm:4.26.0" - "@rollup/rollup-freebsd-x64": "npm:4.26.0" - "@rollup/rollup-linux-arm-gnueabihf": "npm:4.26.0" - "@rollup/rollup-linux-arm-musleabihf": "npm:4.26.0" - "@rollup/rollup-linux-arm64-gnu": "npm:4.26.0" - "@rollup/rollup-linux-arm64-musl": "npm:4.26.0" - "@rollup/rollup-linux-powerpc64le-gnu": "npm:4.26.0" - "@rollup/rollup-linux-riscv64-gnu": "npm:4.26.0" - "@rollup/rollup-linux-s390x-gnu": "npm:4.26.0" - "@rollup/rollup-linux-x64-gnu": "npm:4.26.0" - "@rollup/rollup-linux-x64-musl": "npm:4.26.0" - "@rollup/rollup-win32-arm64-msvc": "npm:4.26.0" - "@rollup/rollup-win32-ia32-msvc": "npm:4.26.0" - "@rollup/rollup-win32-x64-msvc": "npm:4.26.0" - "@types/estree": "npm:1.0.6" + "@rollup/rollup-android-arm-eabi": "npm:4.46.1" + "@rollup/rollup-android-arm64": "npm:4.46.1" + "@rollup/rollup-darwin-arm64": "npm:4.46.1" + "@rollup/rollup-darwin-x64": "npm:4.46.1" + "@rollup/rollup-freebsd-arm64": "npm:4.46.1" + "@rollup/rollup-freebsd-x64": "npm:4.46.1" + "@rollup/rollup-linux-arm-gnueabihf": "npm:4.46.1" + "@rollup/rollup-linux-arm-musleabihf": "npm:4.46.1" + "@rollup/rollup-linux-arm64-gnu": "npm:4.46.1" + "@rollup/rollup-linux-arm64-musl": "npm:4.46.1" + "@rollup/rollup-linux-loongarch64-gnu": "npm:4.46.1" + "@rollup/rollup-linux-ppc64-gnu": "npm:4.46.1" + "@rollup/rollup-linux-riscv64-gnu": "npm:4.46.1" + "@rollup/rollup-linux-riscv64-musl": "npm:4.46.1" + "@rollup/rollup-linux-s390x-gnu": "npm:4.46.1" + "@rollup/rollup-linux-x64-gnu": "npm:4.46.1" + "@rollup/rollup-linux-x64-musl": "npm:4.46.1" + "@rollup/rollup-win32-arm64-msvc": "npm:4.46.1" + "@rollup/rollup-win32-ia32-msvc": "npm:4.46.1" + "@rollup/rollup-win32-x64-msvc": "npm:4.46.1" + "@types/estree": "npm:1.0.8" fsevents: "npm:~2.3.2" dependenciesMeta: "@rollup/rollup-android-arm-eabi": @@ -28269,10 +28285,14 @@ __metadata: optional: true "@rollup/rollup-linux-arm64-musl": optional: true - "@rollup/rollup-linux-powerpc64le-gnu": + "@rollup/rollup-linux-loongarch64-gnu": + optional: true + "@rollup/rollup-linux-ppc64-gnu": optional: true "@rollup/rollup-linux-riscv64-gnu": optional: true + "@rollup/rollup-linux-riscv64-musl": + optional: true "@rollup/rollup-linux-s390x-gnu": optional: true "@rollup/rollup-linux-x64-gnu": @@ -28289,7 +28309,7 @@ __metadata: optional: true bin: rollup: dist/bin/rollup - checksum: 10/aec4d876617298400c0c03d35fed67e5193addc82a76f2b2a2f4c2b000cafbca84a33cf2e686dea1d1caa06fe4028dd94b8e6cd1f5bc3bbd19026a188bb2ec55 + checksum: 10/dc79db54312e895acc8dc0f0b2ef7e507d9ee1f742944ed060f10c17010076f60df13a46baed66780cede9ccaa604dfc87edfbe0d0c47c63b32e66a647c0f5c8 languageName: node linkType: hard From 2ee0f93e8c64c054af924c8425d718843f4fb985 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 28 Jul 2025 16:09:18 +0000 Subject: [PATCH 058/131] Update scenes to v6.28.2 (#108809) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/yarn.lock b/yarn.lock index 3b83aff5bd6..9ac783e535e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3601,10 +3601,10 @@ __metadata: linkType: soft "@grafana/scenes-react@npm:^6.27.2": - version: 6.28.1 - resolution: "@grafana/scenes-react@npm:6.28.1" + version: 6.28.2 + resolution: "@grafana/scenes-react@npm:6.28.2" dependencies: - "@grafana/scenes": "npm:6.28.1" + "@grafana/scenes": "npm:6.28.2" lru-cache: "npm:^10.2.2" react-use: "npm:^17.4.0" peerDependencies: @@ -3616,13 +3616,13 @@ __metadata: react: ^18.0.0 react-dom: ^18.0.0 react-router-dom: ^6.28.0 - checksum: 10/03278682a8ff7ebb399d522b3f54aee820cb34ab85f79d321ee44c4fbb1a490b6d62a8f03cae68187a70cc4345715d41441a72ae3915e6bebfe20fbfb61f9108 + checksum: 10/c00730312828639f8a596c9fd9b0336ec57ca5cec624ac4f09a5fa0be93282d180451e3bcbf83c0209ff04486def25ff98d7b0ea6c370e91b8990112c3e903f2 languageName: node linkType: hard -"@grafana/scenes@npm:6.28.1, @grafana/scenes@npm:^6.27.2": - version: 6.28.1 - resolution: "@grafana/scenes@npm:6.28.1" +"@grafana/scenes@npm:6.28.2, @grafana/scenes@npm:^6.27.2": + version: 6.28.2 + resolution: "@grafana/scenes@npm:6.28.2" dependencies: "@floating-ui/react": "npm:^0.26.16" "@leeoniya/ufuzzy": "npm:^1.0.16" @@ -3642,7 +3642,7 @@ __metadata: react: ^18.0.0 react-dom: ^18.0.0 react-router-dom: ^6.28.0 - checksum: 10/603cb2b421e59a51ee36af6f1d6554e6f328db3aea42da7960e33c14de4ce298b2c261affa6dd651fe8d4ffb4a58e7825958a3b66d00daa3410e91f5f1fb185f + checksum: 10/53370553ac4ac38d41ab1d782ee14cf05f483e35e5338406d619efb61e4c9881fd361c98ee116ae8bf40ab1a5fa2c82ca859fc519f6d532853c275e71949c654 languageName: node linkType: hard From 2dd655a50d4e0d3501d47356d700b07e9f43e837 Mon Sep 17 00:00:00 2001 From: Alex Spencer <52186778+alexjonspencer1@users.noreply.github.com> Date: Mon, 28 Jul 2025 09:14:30 -0700 Subject: [PATCH 059/131] Correlations: Fix flaky test (#108618) * chore: fix flaky test * chore: remove assert in equal, use require instead * chore: skip flaky test --- pkg/tests/api/correlations/correlations_update_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/tests/api/correlations/correlations_update_test.go b/pkg/tests/api/correlations/correlations_update_test.go index 8da638344d7..53e092e9b68 100644 --- a/pkg/tests/api/correlations/correlations_update_test.go +++ b/pkg/tests/api/correlations/correlations_update_test.go @@ -217,6 +217,7 @@ func TestIntegrationUpdateCorrelation(t *testing.T) { }) t.Run("updating a correlation pointing to a read-only data source should work", func(t *testing.T) { + t.Skip("flaky test") correlation := ctx.createCorrelation(correlations.CreateCorrelationCommand{ SourceUID: writableDs, TargetUID: &writableDs, From b32a6b008801d85f8face032cfef92a49bf24663 Mon Sep 17 00:00:00 2001 From: Ashley Harrison Date: Mon, 28 Jul 2025 17:21:10 +0100 Subject: [PATCH 060/131] Chore: Remove `smoke-tests-suite` from cypress (#108700) * remove smoke-tests-suite from cypress * restore shared/smokeTestScenario for enterprise --- .github/workflows/pr-e2e-tests.yml | 2 - e2e/smoke-tests-suite/1-smoketests.spec.ts | 3 -- .../panels_smokescreen.spec.ts | 38 ------------------- e2e/verify/specs/smoketests.spec.ts | 3 -- 4 files changed, 46 deletions(-) delete mode 100644 e2e/smoke-tests-suite/1-smoketests.spec.ts delete mode 100644 e2e/smoke-tests-suite/panels_smokescreen.spec.ts delete mode 100644 e2e/verify/specs/smoketests.spec.ts diff --git a/.github/workflows/pr-e2e-tests.yml b/.github/workflows/pr-e2e-tests.yml index 215a4016344..30590d458fe 100644 --- a/.github/workflows/pr-e2e-tests.yml +++ b/.github/workflows/pr-e2e-tests.yml @@ -143,8 +143,6 @@ jobs: path: e2e/various-suite - suite: dashboards-suite path: e2e/dashboards-suite - - suite: smoke-tests-suite - path: e2e/smoke-tests-suite - suite: panels-suite path: e2e/panels-suite - suite: various-suite (old arch) diff --git a/e2e/smoke-tests-suite/1-smoketests.spec.ts b/e2e/smoke-tests-suite/1-smoketests.spec.ts deleted file mode 100644 index b66a6eee28f..00000000000 --- a/e2e/smoke-tests-suite/1-smoketests.spec.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { smokeTestScenario } from '../shared/smokeTestScenario'; - -smokeTestScenario(); diff --git a/e2e/smoke-tests-suite/panels_smokescreen.spec.ts b/e2e/smoke-tests-suite/panels_smokescreen.spec.ts deleted file mode 100644 index ca63dadba19..00000000000 --- a/e2e/smoke-tests-suite/panels_smokescreen.spec.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { GrafanaBootConfig } from '@grafana/runtime'; - -import { e2e } from '../utils'; - -describe('Panels smokescreen', () => { - beforeEach(() => { - e2e.flows.login(Cypress.env('USERNAME'), Cypress.env('PASSWORD'), false); - }); - - after(() => { - e2e.flows.revertAllChanges(); - }); - - it('Tests each panel type in the panel edit view to ensure no crash', () => { - e2e.flows.addDashboard(); - - e2e.flows.addPanel({ - dataSourceName: 'gdev-testdata', - timeout: 10000, - visitDashboardAtStart: false, - }); - - cy.window().then((win: Cypress.AUTWindow & { grafanaBootData: GrafanaBootConfig['bootData'] }) => { - // Loop through every panel type and ensure no crash - Object.entries(win.grafanaBootData.settings.panels).forEach(([_, panel]) => { - // TODO: Remove Flame Graph check as part of addressing #66803 - if (!panel.hideFromList && panel.state !== 'deprecated') { - e2e.components.PanelEditor.toggleVizPicker().click(); - e2e.components.PluginVisualization.item(panel.name).scrollIntoView().should('be.visible').click(); - - e2e.components.PanelEditor.toggleVizPicker().should((e) => expect(e).to.contain(panel.name)); - // TODO: Come up with better check / better failure messaging to clearly indicate which panel failed - cy.contains('An unexpected error happened').should('not.exist'); - } - }); - }); - }); -}); diff --git a/e2e/verify/specs/smoketests.spec.ts b/e2e/verify/specs/smoketests.spec.ts deleted file mode 100644 index 39409d544ba..00000000000 --- a/e2e/verify/specs/smoketests.spec.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { smokeTestScenario } from '../../shared/smokeTestScenario'; - -smokeTestScenario(); From 672e6d08bf0b6295c2ff3fcc6ae83a697a5cd20a Mon Sep 17 00:00:00 2001 From: Ashley Harrison Date: Mon, 28 Jul 2025 17:25:02 +0100 Subject: [PATCH 061/131] Chore: Remove old storybook-verification cypress test (#108696) * add check for frontend code changing * remove cache * add to pr-e2e-tests instead * fix CODEOWNERS * remove cypress test --- .github/CODEOWNERS | 2 - .github/workflows/pr-e2e-tests.yml | 29 +++++++++++ .../storybook-verification-playwright.yml | 47 ----------------- .github/workflows/storybook-verification.yml | 52 ------------------- e2e/storybook/verify.spec.ts | 14 ----- 5 files changed, 29 insertions(+), 115 deletions(-) delete mode 100644 .github/workflows/storybook-verification-playwright.yml delete mode 100644 .github/workflows/storybook-verification.yml delete mode 100644 e2e/storybook/verify.spec.ts diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index b2edbc703ee..4cf7c2c931f 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1004,8 +1004,6 @@ embed.go @grafana/grafana-as-code /.github/workflows/scripts/json-file-to-job-output.js @grafana/plugins-platform-frontend /.github/workflows/stale.yml @grafana/grafana-developer-enablement-squad /.github/workflows/storybook-a11y.yml @grafana/grafana-frontend-platform -/.github/workflows/storybook-verification.yml @grafana/grafana-frontend-platform -/.github/workflows/storybook-verification-playwright.yml @grafana/grafana-frontend-platform /.github/workflows/update-make-docs.yml @grafana/docs-tooling /.github/workflows/scripts/kinds/verify-kinds.go @grafana/platform-monitoring /.github/workflows/scripts/create-security-branch/create-security-branch.sh @grafana/grafana-developer-enablement-squad diff --git a/.github/workflows/pr-e2e-tests.yml b/.github/workflows/pr-e2e-tests.yml index 30590d458fe..ce7703d2b76 100644 --- a/.github/workflows/pr-e2e-tests.yml +++ b/.github/workflows/pr-e2e-tests.yml @@ -196,6 +196,34 @@ jobs: path: videos retention-days: 1 + run-storybook-test: + name: Verify Storybook (Playwright) + runs-on: ubuntu-latest + needs: detect-changes + if: needs.detect-changes.outputs.changed == 'true' + permissions: + contents: read + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + persist-credentials: false + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + + - name: Install dependencies + run: yarn install --immutable + + - name: Install Playwright browsers + run: npx playwright install --with-deps + + - name: Run Storybook and E2E tests + run: yarn e2e:playwright:storybook + run-playwright-tests: needs: - build-grafana @@ -232,6 +260,7 @@ jobs: required-playwright-tests: needs: - run-playwright-tests + - run-storybook-test - build-grafana if: ${{ !cancelled() }} name: All Playwright tests complete diff --git a/.github/workflows/storybook-verification-playwright.yml b/.github/workflows/storybook-verification-playwright.yml deleted file mode 100644 index e3924a67a85..00000000000 --- a/.github/workflows/storybook-verification-playwright.yml +++ /dev/null @@ -1,47 +0,0 @@ -name: Verify Storybook (Playwright) - -on: - pull_request: - paths: - - 'packages/grafana-ui/**' - - 'e2e-playwright/storybook/**' - - '!docs/**' - - '!*.md' - push: - branches: - - main - paths: - - 'packages/grafana-ui/**' - - 'e2e-playwright/storybook/**' - - '!docs/**' - - '!*.md' - -permissions: {} - -jobs: - verify-storybook: - name: Verify Storybook (Playwright) - runs-on: ubuntu-latest - permissions: - contents: read - - steps: - - name: Checkout code - uses: actions/checkout@v4 - with: - persist-credentials: false - - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version-file: '.nvmrc' - cache: 'yarn' - - - name: Install dependencies - run: yarn install --immutable - - - name: Install Playwright browsers - run: npx playwright install --with-deps - - - name: Run Storybook and E2E tests - run: yarn e2e:playwright:storybook diff --git a/.github/workflows/storybook-verification.yml b/.github/workflows/storybook-verification.yml deleted file mode 100644 index 2777836d5cb..00000000000 --- a/.github/workflows/storybook-verification.yml +++ /dev/null @@ -1,52 +0,0 @@ -name: Verify Storybook - -on: - pull_request: - paths: - - 'packages/grafana-ui/**' - - '!docs/**' - - '!*.md' - push: - branches: - - main - paths: - - 'packages/grafana-ui/**' - - '!docs/**' - - '!*.md' - -permissions: {} - -jobs: - verify-storybook: - name: Verify Storybook - runs-on: ubuntu-latest - permissions: - contents: read - - steps: - - name: Checkout code - uses: actions/checkout@v4 - with: - persist-credentials: false - - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version-file: '.nvmrc' - cache: 'yarn' - - - name: Install dependencies - run: yarn install --immutable - - - name: Run Storybook and E2E tests - uses: cypress-io/github-action@108b8684ae52e735ff7891524cbffbcd4be5b19f - with: - browser: chrome - start: yarn storybook --quiet - wait-on: 'http://localhost:9001' - wait-on-timeout: 60 - command: yarn e2e:storybook - install: false - env: - HOST: localhost - PORT: 9001 diff --git a/e2e/storybook/verify.spec.ts b/e2e/storybook/verify.spec.ts deleted file mode 100644 index f6210d890d1..00000000000 --- a/e2e/storybook/verify.spec.ts +++ /dev/null @@ -1,14 +0,0 @@ -// very basic test to verify that the button story loads correctly -// this is only intended to catch some basic build errors with storybook -// NOTE: storybook must already be running (`yarn storybook`) for this test to work -describe('Verify storybook', () => { - it('Loads the button story correctly', () => { - cy.visit('?path=/story/inputs-button--basic'); - getIframeBody().find('button:contains("Example button")').should('be.visible'); - }); -}); - -// see https://www.cypress.io/blog/2020/02/12/working-with-iframes-in-cypress -function getIframeBody() { - return cy.get('#storybook-preview-iframe').its('0.contentDocument.body').should('not.be.empty').then(cy.wrap); -} From a009da2087c473e33d56461f74f4ccd503fd27c7 Mon Sep 17 00:00:00 2001 From: Josh Hunt Date: Mon, 28 Jul 2025 17:32:18 +0100 Subject: [PATCH 062/131] Playwright: Acceptance tests (#108770) * create a set of acceptance tests to run with bench * move tests back, fix login tests to work with supplied credentials: * rename files again * rename skip message --- e2e-playwright/scenarios/login.spec.ts | 19 --------- .../{panels-smokescreen.spec.ts => panels.ts} | 28 +++++++------ ...-smoketests.spec.ts => smoketests.spec.ts} | 2 +- e2e-playwright/unauthenticated/login.spec.ts | 40 +++++++++++++++++++ package.json | 1 + playwright.config.ts | 4 +- 6 files changed, 59 insertions(+), 35 deletions(-) delete mode 100644 e2e-playwright/scenarios/login.spec.ts rename e2e-playwright/smoke-tests-suite/{panels-smokescreen.spec.ts => panels.ts} (62%) rename e2e-playwright/smoke-tests-suite/{1-smoketests.spec.ts => smoketests.spec.ts} (98%) create mode 100644 e2e-playwright/unauthenticated/login.spec.ts diff --git a/e2e-playwright/scenarios/login.spec.ts b/e2e-playwright/scenarios/login.spec.ts deleted file mode 100644 index afef3d867d1..00000000000 --- a/e2e-playwright/scenarios/login.spec.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { test, expect } from '@grafana/plugin-e2e'; - -test( - 'Scenario test: Can login successfully', - { - tag: ['@scenarios'], - }, - async ({ selectors, page }) => { - await page.goto(selectors.pages.Login.url); - - await page.getByTestId(selectors.pages.Login.username).fill('admin'); - await page.getByTestId(selectors.pages.Login.password).fill('admin'); - await page.getByTestId(selectors.pages.Login.submit).click(); - - await page.getByTestId(selectors.pages.Login.skip).click(); - - await expect(page.getByTestId(selectors.components.NavToolbar.commandPaletteTrigger)).toBeVisible(); - } -); diff --git a/e2e-playwright/smoke-tests-suite/panels-smokescreen.spec.ts b/e2e-playwright/smoke-tests-suite/panels.ts similarity index 62% rename from e2e-playwright/smoke-tests-suite/panels-smokescreen.spec.ts rename to e2e-playwright/smoke-tests-suite/panels.ts index 61e17bec7c6..c65bd0d28ce 100644 --- a/e2e-playwright/smoke-tests-suite/panels-smokescreen.spec.ts +++ b/e2e-playwright/smoke-tests-suite/panels.ts @@ -4,7 +4,7 @@ import { GrafanaBootConfig } from '@grafana/runtime'; test.describe( 'Panels smokescreen', { - tag: ['@smoke'], + tag: ['@acceptance'], }, () => { test('Tests each panel type in the panel edit view to ensure no crash', async ({ @@ -14,6 +14,7 @@ test.describe( }) => { // this test can absolutely take longer than the default 30s timeout test.setTimeout(60000); + // Create new dashboard const dashboardPage = await gotoDashboardPage({}); @@ -30,19 +31,20 @@ test.describe( // Loop through every panel type and ensure no crash for (const [_, panel] of Object.entries(panelTypes)) { - // Skip hidden and deprecated panels - if (!panel.hideFromList && panel.state !== 'deprecated') { - // Open visualization picker - const vizPicker = dashboardPage.getByGrafanaSelector(selectors.components.PanelEditor.toggleVizPicker); - await vizPicker.click(); - await dashboardPage.getByGrafanaSelector(selectors.components.PluginVisualization.item(panel.name)).click(); - - // Verify panel type is selected - await expect(vizPicker).toHaveText(panel.name); - - // Ensure no unexpected error occurred - await expect(page.getByText('An unexpected error happened')).toBeHidden(); + if (panel.hideFromList || panel.state === 'deprecated') { + continue; // Skip hidden and deprecated panels } + + // Select the panel type in the viz picker + const vizPicker = dashboardPage.getByGrafanaSelector(selectors.components.PanelEditor.toggleVizPicker); + await vizPicker.click(); + await dashboardPage.getByGrafanaSelector(selectors.components.PluginVisualization.item(panel.name)).click(); + + // Verify panel type is selected + await expect(vizPicker).toHaveText(panel.name); + + // Ensure no unexpected error occurred + await expect(page.getByText('An unexpected error happened')).toBeHidden(); } }); } diff --git a/e2e-playwright/smoke-tests-suite/1-smoketests.spec.ts b/e2e-playwright/smoke-tests-suite/smoketests.spec.ts similarity index 98% rename from e2e-playwright/smoke-tests-suite/1-smoketests.spec.ts rename to e2e-playwright/smoke-tests-suite/smoketests.spec.ts index a6bea288915..2fcd785b22a 100644 --- a/e2e-playwright/smoke-tests-suite/1-smoketests.spec.ts +++ b/e2e-playwright/smoke-tests-suite/smoketests.spec.ts @@ -5,7 +5,7 @@ import { test, expect } from '@grafana/plugin-e2e'; test.describe( 'Smoke tests', { - tag: ['@smoke'], + tag: ['@acceptance'], }, () => { test('Login, create test data source, create dashboard and panel scenario', async ({ diff --git a/e2e-playwright/unauthenticated/login.spec.ts b/e2e-playwright/unauthenticated/login.spec.ts new file mode 100644 index 00000000000..2cd226134bb --- /dev/null +++ b/e2e-playwright/unauthenticated/login.spec.ts @@ -0,0 +1,40 @@ +import { test, expect } from '@grafana/plugin-e2e'; + +test( + 'Can login successfully', + { + tag: ['@acceptance'], + }, + async ({ selectors, page, grafanaAPICredentials }) => { + test.skip(grafanaAPICredentials.password === 'admin', 'Does not run with default password'); + + await page.goto(selectors.pages.Login.url); + + await page.getByTestId(selectors.pages.Login.username).fill(grafanaAPICredentials.user); + await page.getByTestId(selectors.pages.Login.password).fill(grafanaAPICredentials.password); + + await page.getByTestId(selectors.pages.Login.submit).click(); + + await expect(page.getByTestId(selectors.components.NavToolbar.commandPaletteTrigger)).toBeVisible(); + } +); + +test( + 'Can login successfully and skip password change', + { + tag: ['@acceptance'], + }, + async ({ selectors, page, grafanaAPICredentials }) => { + test.skip(grafanaAPICredentials.password !== 'admin', 'Only runs with the default password'); + + await page.goto(selectors.pages.Login.url); + + await page.getByTestId(selectors.pages.Login.username).fill(grafanaAPICredentials.user); + await page.getByTestId(selectors.pages.Login.password).fill(grafanaAPICredentials.password); + + await page.getByTestId(selectors.pages.Login.submit).click(); + await page.getByTestId(selectors.pages.Login.skip).click(); + + await expect(page.getByTestId(selectors.components.NavToolbar.commandPaletteTrigger)).toBeVisible(); + } +); diff --git a/package.json b/package.json index 34741ebf2a2..931e39234b2 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "e2e:enterprise:debug": "./e2e/start-and-run-suite enterprise debug", "e2e:playwright": "yarn playwright test", "e2e:playwright:storybook": "yarn playwright test -c playwright.storybook.config.ts", + "e2e:acceptance": "yarn playwright test --grep @acceptance", "e2e:storybook": "PORT=9001 ./e2e/run-suite storybook true", "e2e:plugin:build": "nx run-many -t build --projects='@test-plugins/*'", "e2e:plugin:build:dev": "nx run-many -t dev --projects='@test-plugins/*' --maxParallel=100", diff --git a/playwright.config.ts b/playwright.config.ts index b569bc6feea..a3388e20c5e 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -205,8 +205,8 @@ export default defineConfig({ dependencies: ['authenticate'], }, { - name: 'scenarios', - testDir: path.join(testDirRoot, '/scenarios'), + name: 'unauthenticated', + testDir: path.join(testDirRoot, '/unauthenticated'), use: { ...devices['Desktop Chrome'], }, From aa7ae5fc65e41321ad5aa7400ac79f3c00b6ed68 Mon Sep 17 00:00:00 2001 From: Will Assis <35489495+gassiss@users.noreply.github.com> Date: Mon, 28 Jul 2025 12:35:20 -0400 Subject: [PATCH 063/131] unified-storage: add tracing to distributor methods (#108791) * add tracing to distributor methods --- .../unified/resource/search_server_distributor.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/pkg/storage/unified/resource/search_server_distributor.go b/pkg/storage/unified/resource/search_server_distributor.go index 14527f0e6b3..1e1c00e7a7e 100644 --- a/pkg/storage/unified/resource/search_server_distributor.go +++ b/pkg/storage/unified/resource/search_server_distributor.go @@ -33,6 +33,7 @@ func ProvideSearchDistributorServer(cfg *setting.Cfg, features featuremgmt.Featu log: log.New("index-server-distributor"), ring: ring, clientPool: ringClientPool, + tracing: tracer, } healthService, err := ProvideHealthService(distributorServer) @@ -80,6 +81,7 @@ type distributorServer struct { clientPool *ringclient.Pool ring *ring.Ring log log.Logger + tracing trace.Tracer } var ( @@ -92,6 +94,8 @@ var ( ) func (ds *distributorServer) Search(ctx context.Context, r *resourcepb.ResourceSearchRequest) (*resourcepb.ResourceSearchResponse, error) { + ctx, span := ds.tracing.Start(ctx, "distributor.Search") + defer span.End() ctx, client, err := ds.getClientToDistributeRequest(ctx, r.Options.Key.Namespace, "Search") if err != nil { return nil, err @@ -101,6 +105,8 @@ func (ds *distributorServer) Search(ctx context.Context, r *resourcepb.ResourceS } func (ds *distributorServer) GetStats(ctx context.Context, r *resourcepb.ResourceStatsRequest) (*resourcepb.ResourceStatsResponse, error) { + ctx, span := ds.tracing.Start(ctx, "distributor.GetStats") + defer span.End() ctx, client, err := ds.getClientToDistributeRequest(ctx, r.Namespace, "GetStats") if err != nil { return nil, err @@ -110,6 +116,8 @@ func (ds *distributorServer) GetStats(ctx context.Context, r *resourcepb.Resourc } func (ds *distributorServer) CountManagedObjects(ctx context.Context, r *resourcepb.CountManagedObjectsRequest) (*resourcepb.CountManagedObjectsResponse, error) { + ctx, span := ds.tracing.Start(ctx, "distributor.CountManagedObjects") + defer span.End() ctx, client, err := ds.getClientToDistributeRequest(ctx, r.Namespace, "CountManagedObjects") if err != nil { return nil, err @@ -119,6 +127,8 @@ func (ds *distributorServer) CountManagedObjects(ctx context.Context, r *resourc } func (ds *distributorServer) ListManagedObjects(ctx context.Context, r *resourcepb.ListManagedObjectsRequest) (*resourcepb.ListManagedObjectsResponse, error) { + ctx, span := ds.tracing.Start(ctx, "distributor.ListManagedObjects") + defer span.End() ctx, client, err := ds.getClientToDistributeRequest(ctx, r.Namespace, "ListManagedObjects") if err != nil { return nil, err From f41570a6f73cf98964b5ed9d78b5d2e46cc7b4fb Mon Sep 17 00:00:00 2001 From: Stephanie Hingtgen Date: Mon, 28 Jul 2025 11:37:17 -0500 Subject: [PATCH 064/131] Annotations: Move to integration tests (#108736) --- .../accesscontrol/accesscontrol_test.go | 228 --------- .../annotationsimpl/annotations_test.go | 368 --------------- .../annotationsimpl/xorm_store_test.go | 5 + pkg/tests/api/annotations/annotations_test.go | 439 ++++++++++++++++++ 4 files changed, 444 insertions(+), 596 deletions(-) delete mode 100644 pkg/services/annotations/accesscontrol/accesscontrol_test.go delete mode 100644 pkg/services/annotations/annotationsimpl/annotations_test.go create mode 100644 pkg/tests/api/annotations/annotations_test.go diff --git a/pkg/services/annotations/accesscontrol/accesscontrol_test.go b/pkg/services/annotations/accesscontrol/accesscontrol_test.go deleted file mode 100644 index f4ec20ffcfa..00000000000 --- a/pkg/services/annotations/accesscontrol/accesscontrol_test.go +++ /dev/null @@ -1,228 +0,0 @@ -package accesscontrol - -import ( - "context" - "fmt" - "testing" - - "github.com/stretchr/testify/require" - - "github.com/grafana/grafana/pkg/bus" - "github.com/grafana/grafana/pkg/components/simplejson" - "github.com/grafana/grafana/pkg/infra/db" - "github.com/grafana/grafana/pkg/infra/kvstore" - "github.com/grafana/grafana/pkg/infra/serverlock" - "github.com/grafana/grafana/pkg/infra/tracing" - "github.com/grafana/grafana/pkg/services/accesscontrol" - "github.com/grafana/grafana/pkg/services/accesscontrol/actest" - accesscontrolmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock" - "github.com/grafana/grafana/pkg/services/annotations" - "github.com/grafana/grafana/pkg/services/annotations/testutil" - "github.com/grafana/grafana/pkg/services/apiserver" - "github.com/grafana/grafana/pkg/services/apiserver/client" - "github.com/grafana/grafana/pkg/services/dashboards" - "github.com/grafana/grafana/pkg/services/dashboards/database" - dashboardsservice "github.com/grafana/grafana/pkg/services/dashboards/service" - "github.com/grafana/grafana/pkg/services/featuremgmt" - "github.com/grafana/grafana/pkg/services/folder/folderimpl" - "github.com/grafana/grafana/pkg/services/quota/quotatest" - "github.com/grafana/grafana/pkg/services/search/sort" - "github.com/grafana/grafana/pkg/services/supportbundles/supportbundlestest" - "github.com/grafana/grafana/pkg/services/tag/tagimpl" - "github.com/grafana/grafana/pkg/services/user" - "github.com/grafana/grafana/pkg/storage/legacysql/dualwrite" - "github.com/grafana/grafana/pkg/tests/testsuite" -) - -func TestMain(m *testing.M) { - testsuite.Run(m) -} - -func TestIntegrationAuthorize(t *testing.T) { - if testing.Short() { - t.Skip("skipping integration test") - } - - sql, cfg := db.InitTestDBWithCfg(t) - folderStore := folderimpl.ProvideDashboardFolderStore(sql) - fStore := folderimpl.ProvideStore(sql) - dashStore, err := database.ProvideDashboardStore(sql, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sql)) - require.NoError(t, err) - ac := actest.FakeAccessControl{ExpectedEvaluate: true} - folderSvc := folderimpl.ProvideService( - fStore, ac, bus.ProvideBus(tracing.InitializeTracerForTest()), dashStore, folderStore, - nil, sql, featuremgmt.WithFeatures(), supportbundlestest.NewFakeBundleService(), nil, cfg, nil, tracing.InitializeTracerForTest(), nil, dualwrite.ProvideTestService(), sort.ProvideService(), apiserver.WithoutRestConfig) - dashSvc, err := dashboardsservice.ProvideDashboardServiceImpl(cfg, dashStore, folderStore, featuremgmt.WithFeatures(), accesscontrolmock.NewMockedPermissionsService(), - ac, actest.FakeService{}, folderSvc, nil, client.MockTestRestConfig{}, nil, quotatest.New(false, nil), nil, nil, nil, dualwrite.ProvideTestService(), sort.ProvideService(), - serverlock.ProvideService(sql, tracing.InitializeTracerForTest()), - kvstore.NewFakeKVStore()) - require.NoError(t, err) - dashSvc.RegisterDashboardPermissions(accesscontrolmock.NewMockedPermissionsService()) - - u := &user.SignedInUser{ - UserID: 1, - OrgID: 1, - } - - dash1, err := dashSvc.SaveDashboard(context.Background(), &dashboards.SaveDashboardDTO{ - User: u, - OrgID: 1, - Dashboard: &dashboards.Dashboard{ - Title: "Dashboard 1", - Data: simplejson.New(), - }, - }, false) - require.NoError(t, err) - - dash2, err := dashSvc.SaveDashboard(context.Background(), &dashboards.SaveDashboardDTO{ - User: u, - OrgID: 1, - Dashboard: &dashboards.Dashboard{ - Title: "Dashboard 2", - Data: simplejson.New(), - }, - }, false) - require.NoError(t, err) - - role := testutil.SetupRBACRole(t, sql, u) - - type testCase struct { - name string - permissions map[string][]string - featureToggle string - expectedResources *AccessResources - expectedErr error - } - - testCases := []testCase{ - { - name: "should have both scopes and all dashboards", - permissions: map[string][]string{ - accesscontrol.ActionAnnotationsRead: {accesscontrol.ScopeAnnotationsAll}, - dashboards.ActionDashboardsRead: {dashboards.ScopeDashboardsAll}, - }, - expectedResources: &AccessResources{ - Dashboards: map[string]int64{dash1.UID: dash1.ID, dash2.UID: dash2.ID}, - CanAccessOrgAnnotations: true, - CanAccessDashAnnotations: true, - }, - }, - { - name: "should have no dashboards if missing annotation read permission on dashboards and FlagAnnotationPermissionUpdate is enabled", - permissions: map[string][]string{ - accesscontrol.ActionAnnotationsRead: {accesscontrol.ScopeAnnotationsAll}, - dashboards.ActionDashboardsRead: {dashboards.ScopeDashboardsAll}, - }, - featureToggle: featuremgmt.FlagAnnotationPermissionUpdate, - expectedResources: &AccessResources{ - Dashboards: nil, - CanAccessOrgAnnotations: true, - CanAccessDashAnnotations: true, - }, - }, - { - name: "should have dashboard and organization scope and all dashboards if FlagAnnotationPermissionUpdate is enabled", - permissions: map[string][]string{ - accesscontrol.ActionAnnotationsRead: {accesscontrol.ScopeAnnotationsTypeOrganization, dashboards.ScopeDashboardsAll}, - }, - featureToggle: featuremgmt.FlagAnnotationPermissionUpdate, - expectedResources: &AccessResources{ - Dashboards: map[string]int64{dash1.UID: dash1.ID, dash2.UID: dash2.ID}, - CanAccessOrgAnnotations: true, - CanAccessDashAnnotations: true, - }, - }, - { - name: "should have dashboard and organization scope and all dashboards if FlagAnnotationPermissionUpdate is enabled and folder based scope is used", - permissions: map[string][]string{ - accesscontrol.ActionAnnotationsRead: {accesscontrol.ScopeAnnotationsTypeOrganization, dashboards.ScopeFoldersAll}, - }, - featureToggle: featuremgmt.FlagAnnotationPermissionUpdate, - expectedResources: &AccessResources{ - Dashboards: map[string]int64{dash1.UID: dash1.ID, dash2.UID: dash2.ID}, - CanAccessOrgAnnotations: true, - CanAccessDashAnnotations: true, - }, - }, - { - name: "should have only organization scope and no dashboards", - permissions: map[string][]string{ - accesscontrol.ActionAnnotationsRead: {accesscontrol.ScopeAnnotationsTypeOrganization}, - dashboards.ActionDashboardsRead: {dashboards.ScopeDashboardsAll}, - }, - expectedResources: &AccessResources{ - Dashboards: nil, - CanAccessOrgAnnotations: true, - }, - }, - { - name: "should have only dashboard scope and all dashboards", - permissions: map[string][]string{ - accesscontrol.ActionAnnotationsRead: {accesscontrol.ScopeAnnotationsTypeDashboard}, - dashboards.ActionDashboardsRead: {dashboards.ScopeDashboardsAll}, - }, - expectedResources: &AccessResources{ - Dashboards: map[string]int64{dash1.UID: dash1.ID, dash2.UID: dash2.ID}, - CanAccessDashAnnotations: true, - }, - }, - { - name: "should have only dashboard scope and all dashboards if FlagAnnotationPermissionUpdate is enabled", - permissions: map[string][]string{ - accesscontrol.ActionAnnotationsRead: {dashboards.ScopeDashboardsAll}, - }, - featureToggle: featuremgmt.FlagAnnotationPermissionUpdate, - expectedResources: &AccessResources{ - Dashboards: map[string]int64{dash1.UID: dash1.ID, dash2.UID: dash2.ID}, - CanAccessOrgAnnotations: false, - CanAccessDashAnnotations: true, - }, - }, - { - name: "should have only dashboard scope and only dashboard 1", - permissions: map[string][]string{ - accesscontrol.ActionAnnotationsRead: {accesscontrol.ScopeAnnotationsTypeDashboard}, - dashboards.ActionDashboardsRead: {fmt.Sprintf("dashboards:uid:%s", dash1.UID)}, - }, - expectedResources: &AccessResources{ - Dashboards: map[string]int64{dash1.UID: dash1.ID}, - CanAccessDashAnnotations: true, - }, - }, - { - name: "should have only dashboard scope and only dashboard 1 if FlagAnnotationPermissionUpdate is enabled", - permissions: map[string][]string{ - accesscontrol.ActionAnnotationsRead: {dashboards.ScopeDashboardsProvider.GetResourceScopeUID(dash1.UID)}, - }, - featureToggle: featuremgmt.FlagAnnotationPermissionUpdate, - expectedResources: &AccessResources{ - Dashboards: map[string]int64{dash1.UID: dash1.ID}, - CanAccessOrgAnnotations: false, - CanAccessDashAnnotations: true, - }, - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - u.Permissions = map[int64]map[string][]string{1: tc.permissions} - testutil.SetupRBACPermission(t, sql, role, u) - authz := NewAuthService(sql, featuremgmt.WithFeatures(tc.featureToggle), dashSvc) - - query := annotations.ItemQuery{SignedInUser: u, OrgID: 1} - resources, err := authz.Authorize(context.Background(), query) - require.NoError(t, err) - - if tc.expectedResources.Dashboards != nil { - require.Equal(t, tc.expectedResources.Dashboards, resources.Dashboards) - } - - require.Equal(t, tc.expectedResources.CanAccessDashAnnotations, resources.CanAccessDashAnnotations) - require.Equal(t, tc.expectedResources.CanAccessOrgAnnotations, resources.CanAccessOrgAnnotations) - - if tc.expectedErr != nil { - require.Equal(t, tc.expectedErr, err) - } - }) - } -} diff --git a/pkg/services/annotations/annotationsimpl/annotations_test.go b/pkg/services/annotations/annotationsimpl/annotations_test.go deleted file mode 100644 index 9cb5a099812..00000000000 --- a/pkg/services/annotations/annotationsimpl/annotations_test.go +++ /dev/null @@ -1,368 +0,0 @@ -package annotationsimpl - -import ( - "context" - "errors" - "fmt" - "testing" - - "github.com/prometheus/client_golang/prometheus" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/grafana/grafana/pkg/bus" - "github.com/grafana/grafana/pkg/components/simplejson" - "github.com/grafana/grafana/pkg/infra/db" - "github.com/grafana/grafana/pkg/infra/kvstore" - "github.com/grafana/grafana/pkg/infra/log" - "github.com/grafana/grafana/pkg/infra/serverlock" - "github.com/grafana/grafana/pkg/infra/tracing" - "github.com/grafana/grafana/pkg/services/accesscontrol" - "github.com/grafana/grafana/pkg/services/accesscontrol/actest" - accesscontrolmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock" - "github.com/grafana/grafana/pkg/services/annotations" - "github.com/grafana/grafana/pkg/services/annotations/testutil" - "github.com/grafana/grafana/pkg/services/apiserver" - "github.com/grafana/grafana/pkg/services/apiserver/client" - "github.com/grafana/grafana/pkg/services/dashboards" - "github.com/grafana/grafana/pkg/services/dashboards/database" - dashboardsservice "github.com/grafana/grafana/pkg/services/dashboards/service" - "github.com/grafana/grafana/pkg/services/featuremgmt" - "github.com/grafana/grafana/pkg/services/folder" - "github.com/grafana/grafana/pkg/services/folder/folderimpl" - alertingStore "github.com/grafana/grafana/pkg/services/ngalert/store" - "github.com/grafana/grafana/pkg/services/quota/quotatest" - "github.com/grafana/grafana/pkg/services/search/sort" - "github.com/grafana/grafana/pkg/services/supportbundles/supportbundlestest" - "github.com/grafana/grafana/pkg/services/tag/tagimpl" - "github.com/grafana/grafana/pkg/services/user" - "github.com/grafana/grafana/pkg/setting" - "github.com/grafana/grafana/pkg/storage/legacysql/dualwrite" - "github.com/grafana/grafana/pkg/tests/testsuite" -) - -func TestMain(m *testing.M) { - testsuite.Run(m) -} - -func TestIntegrationAnnotationListingWithRBAC(t *testing.T) { - if testing.Short() { - t.Skip("skipping integration test") - } - sql := db.InitTestDB(t) - - cfg := setting.NewCfg() - cfg.AnnotationMaximumTagsLength = 60 - - features := featuremgmt.WithFeatures() - tagService := tagimpl.ProvideService(sql) - ruleStore := alertingStore.SetupStoreForTesting(t, sql) - folderStore := folderimpl.ProvideDashboardFolderStore(sql) - fStore := folderimpl.ProvideStore(sql) - dashStore, err := database.ProvideDashboardStore(sql, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sql)) - require.NoError(t, err) - ac := actest.FakeAccessControl{ExpectedEvaluate: true} - folderSvc := folderimpl.ProvideService( - fStore, ac, bus.ProvideBus(tracing.InitializeTracerForTest()), dashStore, folderStore, - nil, sql, featuremgmt.WithFeatures(), supportbundlestest.NewFakeBundleService(), nil, cfg, nil, tracing.InitializeTracerForTest(), nil, dualwrite.ProvideTestService(), sort.ProvideService(), apiserver.WithoutRestConfig) - dashSvc, err := dashboardsservice.ProvideDashboardServiceImpl(cfg, dashStore, folderStore, featuremgmt.WithFeatures(), accesscontrolmock.NewMockedPermissionsService(), - ac, actest.FakeService{}, folderSvc, nil, client.MockTestRestConfig{}, nil, quotatest.New(false, nil), nil, nil, nil, dualwrite.ProvideTestService(), sort.ProvideService(), - serverlock.ProvideService(sql, tracing.InitializeTracerForTest()), - kvstore.NewFakeKVStore()) - require.NoError(t, err) - dashSvc.RegisterDashboardPermissions(accesscontrolmock.NewMockedPermissionsService()) - repo := ProvideService(sql, cfg, features, tagService, tracing.InitializeTracerForTest(), ruleStore, dashSvc, prometheus.NewPedanticRegistry()) - - dashboard1 := testutil.CreateDashboard(t, sql, cfg, features, dashboards.SaveDashboardCommand{ - UserID: 1, - OrgID: 1, - IsFolder: false, - Dashboard: simplejson.NewFromAny(map[string]any{ - "title": "Dashboard 1", - }), - }) - - dashboard2 := testutil.CreateDashboard(t, sql, cfg, features, dashboards.SaveDashboardCommand{ - UserID: 1, - OrgID: 1, - IsFolder: false, - Dashboard: simplejson.NewFromAny(map[string]any{ - "title": "Dashboard 2", - }), - }) - - dash1Annotation := &annotations.Item{ - OrgID: 1, - DashboardID: 1, // nolint: staticcheck - DashboardUID: dashboard1.UID, - Epoch: 10, - } - err = repo.Save(context.Background(), dash1Annotation) - require.NoError(t, err) - - dash2Annotation := &annotations.Item{ - OrgID: 1, - DashboardID: 2, // nolint: staticcheck - DashboardUID: dashboard2.UID, - Epoch: 10, - Tags: []string{"foo:bar"}, - } - err = repo.Save(context.Background(), dash2Annotation) - require.NoError(t, err) - - organizationAnnotation := &annotations.Item{ - OrgID: 1, - Epoch: 10, - } - err = repo.Save(context.Background(), organizationAnnotation) - require.NoError(t, err) - - u := &user.SignedInUser{ - UserID: 1, - OrgID: 1, - } - role := testutil.SetupRBACRole(t, sql, u) - - type testStruct struct { - description string - permissions map[string][]string - expectedAnnotationIds []int64 - expectedError bool - } - - testCases := []testStruct{ - { - description: "Should find all annotations when has permissions to list all annotations and read all dashboards", - permissions: map[string][]string{ - accesscontrol.ActionAnnotationsRead: {accesscontrol.ScopeAnnotationsAll}, - dashboards.ActionDashboardsRead: {dashboards.ScopeDashboardsAll}, - }, - expectedAnnotationIds: []int64{dash1Annotation.ID, dash2Annotation.ID, organizationAnnotation.ID}, - }, - { - description: "Should find all dashboard annotations", - permissions: map[string][]string{ - accesscontrol.ActionAnnotationsRead: {accesscontrol.ScopeAnnotationsTypeDashboard}, - dashboards.ActionDashboardsRead: {dashboards.ScopeDashboardsAll}, - }, - expectedAnnotationIds: []int64{dash1Annotation.ID, dash2Annotation.ID}, - }, - { - description: "Should find only annotations from dashboards that user can read", - permissions: map[string][]string{ - accesscontrol.ActionAnnotationsRead: {accesscontrol.ScopeAnnotationsTypeDashboard}, - dashboards.ActionDashboardsRead: {fmt.Sprintf("dashboards:uid:%s", dashboard1.UID)}, - }, - expectedAnnotationIds: []int64{dash1Annotation.ID}, - }, - { - description: "Should find no annotations if user can't view dashboards or organization annotations", - permissions: map[string][]string{ - accesscontrol.ActionAnnotationsRead: {accesscontrol.ScopeAnnotationsTypeDashboard}, - }, - expectedAnnotationIds: []int64{}, - }, - { - description: "Should find only organization annotations", - permissions: map[string][]string{ - accesscontrol.ActionAnnotationsRead: {accesscontrol.ScopeAnnotationsTypeOrganization}, - dashboards.ActionDashboardsRead: {dashboards.ScopeDashboardsAll}, - }, - expectedAnnotationIds: []int64{organizationAnnotation.ID}, - }, - { - description: "Should error if user doesn't have annotation read permissions", - permissions: map[string][]string{ - dashboards.ActionDashboardsRead: {dashboards.ScopeDashboardsAll}, - }, - expectedError: true, - }, - } - - for _, tc := range testCases { - t.Run(tc.description, func(t *testing.T) { - u.Permissions = map[int64]map[string][]string{1: tc.permissions} - testutil.SetupRBACPermission(t, sql, role, u) - - results, err := repo.Find(context.Background(), &annotations.ItemQuery{ - OrgID: 1, - SignedInUser: u, - }) - if tc.expectedError { - require.Error(t, err) - return - } - require.NoError(t, err) - assert.Len(t, results, len(tc.expectedAnnotationIds)) - for _, r := range results { - assert.Contains(t, tc.expectedAnnotationIds, r.ID) - } - }) - } -} - -func TestIntegrationAnnotationListingWithInheritedRBAC(t *testing.T) { - if testing.Short() { - t.Skip("skipping integration test") - } - - orgID := int64(1) - permissions := []accesscontrol.Permission{ - { - Action: dashboards.ActionFoldersCreate, - Scope: dashboards.ScopeFoldersAll, - }, - } - usr := &user.SignedInUser{ - UserID: 1, - OrgID: orgID, - Permissions: map[int64]map[string][]string{orgID: accesscontrol.GroupScopesByActionContext(context.Background(), permissions)}, - } - - var role *accesscontrol.Role - - type dashInfo struct { - UID string - ID int64 - } - - allDashboards := make([]dashInfo, 0, folder.MaxNestedFolderDepth+1) - annotationsTexts := make([]string, 0, folder.MaxNestedFolderDepth+1) - - setupFolderStructure := func() (db.DB, dashboards.DashboardService) { - sql, cfg := db.InitTestDBWithCfg(t) - - // enable nested folders so that the folder table is populated for all the tests - features := featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders) - - tagService := tagimpl.ProvideService(sql) - - dashStore, err := database.ProvideDashboardStore(sql, cfg, features, tagService) - require.NoError(t, err) - - ac := actest.FakeAccessControl{ExpectedEvaluate: true} - fStore := folderimpl.ProvideStore(sql) - folderStore := folderimpl.ProvideDashboardFolderStore(sql) - folderSvc := folderimpl.ProvideService( - fStore, ac, bus.ProvideBus(tracing.InitializeTracerForTest()), dashStore, folderStore, - nil, sql, features, supportbundlestest.NewFakeBundleService(), nil, cfg, nil, tracing.InitializeTracerForTest(), nil, dualwrite.ProvideTestService(), sort.ProvideService(), apiserver.WithoutRestConfig) - dashSvc, err := dashboardsservice.ProvideDashboardServiceImpl(cfg, dashStore, folderStore, features, accesscontrolmock.NewMockedPermissionsService(), - ac, actest.FakeService{}, folderSvc, nil, client.MockTestRestConfig{}, nil, quotatest.New(false, nil), nil, nil, nil, dualwrite.ProvideTestService(), sort.ProvideService(), - serverlock.ProvideService(sql, tracing.InitializeTracerForTest()), - kvstore.NewFakeKVStore(), - ) - require.NoError(t, err) - dashSvc.RegisterDashboardPermissions(accesscontrolmock.NewMockedPermissionsService()) - cfg.AnnotationMaximumTagsLength = 60 - - store := NewXormStore(cfg, log.New("annotation.test"), sql, tagService) - - parentUID := "" - for i := 0; ; i++ { - uid := fmt.Sprintf("f%d", i) - f, err := folderSvc.Create(context.Background(), &folder.CreateFolderCommand{ - UID: uid, - OrgID: orgID, - Title: uid, - SignedInUser: usr, - ParentUID: parentUID, - }) - if err != nil { - if errors.Is(err, folder.ErrMaximumDepthReached) { - break - } - - t.Log("unexpected error", "error", err) - t.Fail() - } - - dashboard, err := dashSvc.SaveDashboard(context.Background(), &dashboards.SaveDashboardDTO{ - User: usr, - OrgID: orgID, - Dashboard: &dashboards.Dashboard{ - IsFolder: false, - Title: fmt.Sprintf("Dashboard under %s", f.UID), - Data: simplejson.New(), - FolderID: f.ID, // nolint:staticcheck - FolderUID: f.UID, - }, - }, false) - require.NoError(t, err) - - allDashboards = append(allDashboards, dashInfo{UID: dashboard.UID, ID: dashboard.ID}) - - parentUID = f.UID - - annotationTxt := fmt.Sprintf("annotation %d", i) - dash1Annotation := &annotations.Item{ - OrgID: orgID, - DashboardID: dashboard.ID, // nolint: staticcheck - DashboardUID: dashboard.UID, - Epoch: 10, - Text: annotationTxt, - } - err = store.Add(context.Background(), dash1Annotation) - require.NoError(t, err) - - annotationsTexts = append(annotationsTexts, annotationTxt) - } - - role = testutil.SetupRBACRole(t, sql, usr) - return sql, dashSvc - } - - sql, dashSvc := setupFolderStructure() - - testCases := []struct { - desc string - features featuremgmt.FeatureToggles - permissions map[string][]string - expectedAnnotationText []string - expectedError bool - }{ - { - desc: "Should find only annotations from dashboards under folders that user can read", - features: featuremgmt.WithFeatures(), - permissions: map[string][]string{ - accesscontrol.ActionAnnotationsRead: {accesscontrol.ScopeAnnotationsTypeDashboard}, - dashboards.ActionDashboardsRead: {"folders:uid:f0"}, - }, - expectedAnnotationText: annotationsTexts[:1], - }, - { - desc: "Should find only annotations from dashboards under inherited folders if nested folder are enabled", - features: featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders), - permissions: map[string][]string{ - accesscontrol.ActionAnnotationsRead: {accesscontrol.ScopeAnnotationsTypeDashboard}, - dashboards.ActionDashboardsRead: {"folders:uid:f0"}, - }, - expectedAnnotationText: annotationsTexts[:], - }, - } - - for _, tc := range testCases { - t.Run(tc.desc, func(t *testing.T) { - cfg := setting.NewCfg() - cfg.AnnotationMaximumTagsLength = 60 - ruleStore := alertingStore.SetupStoreForTesting(t, sql) - repo := ProvideService(sql, cfg, tc.features, tagimpl.ProvideService(sql), tracing.InitializeTracerForTest(), ruleStore, dashSvc, prometheus.NewPedanticRegistry()) - - usr.Permissions = map[int64]map[string][]string{1: tc.permissions} - testutil.SetupRBACPermission(t, sql, role, usr) - - results, err := repo.Find(context.Background(), &annotations.ItemQuery{ - OrgID: 1, - SignedInUser: usr, - }) - if tc.expectedError { - require.Error(t, err) - return - } - require.NoError(t, err) - require.Len(t, results, len(tc.expectedAnnotationText)) - for _, r := range results { - assert.Contains(t, tc.expectedAnnotationText, r.Text) - } - }) - } -} diff --git a/pkg/services/annotations/annotationsimpl/xorm_store_test.go b/pkg/services/annotations/annotationsimpl/xorm_store_test.go index 015c42a5075..a24365d031f 100644 --- a/pkg/services/annotations/annotationsimpl/xorm_store_test.go +++ b/pkg/services/annotations/annotationsimpl/xorm_store_test.go @@ -23,8 +23,13 @@ import ( "github.com/grafana/grafana/pkg/services/tag/tagimpl" "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/setting" + "github.com/grafana/grafana/pkg/tests/testsuite" ) +func TestMain(m *testing.M) { + testsuite.Run(m) +} + func TestIntegrationAnnotations(t *testing.T) { if testing.Short() { t.Skip("skipping integration test") diff --git a/pkg/tests/api/annotations/annotations_test.go b/pkg/tests/api/annotations/annotations_test.go new file mode 100644 index 00000000000..18b4e28f55c --- /dev/null +++ b/pkg/tests/api/annotations/annotations_test.go @@ -0,0 +1,439 @@ +package annotations + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "net/http" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/grafana/grafana/pkg/api/dtos" + + "github.com/grafana/grafana/pkg/services/dashboards" + "github.com/grafana/grafana/pkg/services/featuremgmt" + "github.com/grafana/grafana/pkg/services/folder" + "github.com/grafana/grafana/pkg/services/org" + "github.com/grafana/grafana/pkg/services/user" + "github.com/grafana/grafana/pkg/tests" + "github.com/grafana/grafana/pkg/tests/testinfra" + "github.com/grafana/grafana/pkg/tests/testsuite" +) + +func TestMain(m *testing.M) { + testsuite.Run(m) +} + +func TestIntegrationAnnotations(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test") + } + + dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ + DisableAnonymous: true, + EnableFeatureToggles: []string{featuremgmt.FlagAnnotationPermissionUpdate}, + }) + grafanaListedAddr, env := testinfra.StartGrafanaEnv(t, dir, path) + noneUserID := tests.CreateUser(t, env.SQLStore, env.Cfg, user.CreateUserCommand{ + DefaultOrgRole: string(org.RoleNone), + Login: "noneuser", + Password: "noneuser", + IsAdmin: false, + OrgID: 1, + }) + + tests.CreateUser(t, env.SQLStore, env.Cfg, user.CreateUserCommand{ + DefaultOrgRole: string(org.RoleEditor), + Login: "editor", + Password: "editor", + IsAdmin: false, + OrgID: 1, + }) + + tests.CreateUser(t, env.SQLStore, env.Cfg, user.CreateUserCommand{ + DefaultOrgRole: string(org.RoleViewer), + Login: "viewer", + Password: "viewer", + IsAdmin: false, + OrgID: 1, + }) + savedFolder := createFolder(t, grafanaListedAddr, "Test Folder") + dash1 := createDashboard(t, grafanaListedAddr, "Dashboard 1", savedFolder.ID, savedFolder.UID) // nolint:staticcheck + dash2 := createDashboard(t, grafanaListedAddr, "Dashboard 2", savedFolder.ID, savedFolder.UID) // nolint:staticcheck + createAnnotation(t, grafanaListedAddr, "admin", "admin", map[string]interface{}{ + "dashboardId": dash1.ID, + "panelId": 1, + "text": "Dashboard 1 annotation", + "time": 1234567890000, + }) + + createAnnotation(t, grafanaListedAddr, "admin", "admin", map[string]interface{}{ + "dashboardId": dash2.ID, + "panelId": 1, + "text": "Dashboard 2 annotation", + "time": 1234567890000, + }) + + createAnnotation(t, grafanaListedAddr, "admin", "admin", map[string]interface{}{ + "text": "Organization annotation", + "time": 1234567890000, + }) + + t.Run("basic tests", func(t *testing.T) { + t.Run("should allow accessing annotations for specific dashboard", func(t *testing.T) { + url := fmt.Sprintf("http://admin:admin@%s/api/annotations?dashboardId=%d", grafanaListedAddr, dash1.ID) + resp, err := http.Get(url) // nolint:gosec + require.NoError(t, err) + assert.Equal(t, http.StatusOK, resp.StatusCode) + + body, err := io.ReadAll(resp.Body) + require.NoError(t, err) + err = resp.Body.Close() + require.NoError(t, err) + + var annotations []interface{} + err = json.Unmarshal(body, &annotations) + require.NoError(t, err) + assert.Len(t, annotations, 1) + }) + + t.Run("should allow accessing annotations for specific dashboard by UID", func(t *testing.T) { + url := fmt.Sprintf("http://admin:admin@%s/api/annotations?dashboardUID=%s", grafanaListedAddr, dash1.UID) + resp, err := http.Get(url) // nolint:gosec + require.NoError(t, err) + assert.Equal(t, http.StatusOK, resp.StatusCode) + + body, err := io.ReadAll(resp.Body) + require.NoError(t, err) + err = resp.Body.Close() + require.NoError(t, err) + + var annotations []interface{} + err = json.Unmarshal(body, &annotations) + require.NoError(t, err) + assert.Len(t, annotations, 1) + }) + }) + + t.Run("access control tests", func(t *testing.T) { + viewPermissions := []map[string]interface{}{ + { + "permission": 1, + "userId": noneUserID, + }, + } + + t.Run("should have no dashboards if missing annotation read permission on dashboards", func(t *testing.T) { + url := fmt.Sprintf("http://noneuser:noneuser@%s/api/annotations", grafanaListedAddr) + resp, err := http.Get(url) // nolint:gosec + require.NoError(t, err) + assert.Equal(t, resp.StatusCode, http.StatusForbidden) + err = resp.Body.Close() + require.NoError(t, err) + }) + + t.Run("should be able to see annotations for dashboards that user has access to", func(t *testing.T) { + setDashboardPermissions(t, grafanaListedAddr, dash1.UID, viewPermissions) + + // should be able to get first one + url := fmt.Sprintf("http://noneuser:noneuser@%s/api/annotations?dashboardId=%d", grafanaListedAddr, dash1.ID) + resp, err := http.Get(url) // nolint:gosec + require.NoError(t, err) + assert.Equal(t, http.StatusOK, resp.StatusCode) + err = resp.Body.Close() + require.NoError(t, err) + + // cannot get the second one + url = fmt.Sprintf("http://noneuser:noneuser@%s/api/annotations?dashboardId=%d", grafanaListedAddr, dash2.ID) + resp, err = http.Get(url) // nolint:gosec + require.NoError(t, err) + assert.Equal(t, http.StatusBadRequest, resp.StatusCode) + err = resp.Body.Close() + require.NoError(t, err) + }) + + t.Run("should inherit folder permissions", func(t *testing.T) { + setFolderPermissions(t, grafanaListedAddr, savedFolder.UID, viewPermissions) + + url := fmt.Sprintf("http://noneuser:noneuser@%s/api/annotations", grafanaListedAddr) + resp, err := http.Get(url) // nolint:gosec + require.NoError(t, err) + assert.Equal(t, http.StatusOK, resp.StatusCode) + + body, err := io.ReadAll(resp.Body) + require.NoError(t, err) + err = resp.Body.Close() + require.NoError(t, err) + + var annotations []interface{} + err = json.Unmarshal(body, &annotations) + require.NoError(t, err) + assert.Len(t, annotations, 2) + }) + + t.Run("should allow admin to access all annotations", func(t *testing.T) { + url := fmt.Sprintf("http://admin:admin@%s/api/annotations", grafanaListedAddr) + resp, err := http.Get(url) // nolint:gosec + require.NoError(t, err) + assert.Equal(t, http.StatusOK, resp.StatusCode) + body, err := io.ReadAll(resp.Body) + require.NoError(t, err) + err = resp.Body.Close() + require.NoError(t, err) + + var annotations []interface{} + err = json.Unmarshal(body, &annotations) + require.NoError(t, err) + assert.Len(t, annotations, 3) + }) + + dash3 := createDashboard(t, grafanaListedAddr, "Dashboard 3", 0, "") + createAnnotation(t, grafanaListedAddr, "admin", "admin", map[string]interface{}{ + "dashboardId": dash3.ID, + "panelId": 1, + "text": "Dashboard 3 annotation", + "time": 1234567890000, + }) + + t.Run("should allow editor to access org annotations and annotations for dashboards they have access to (dash3)", func(t *testing.T) { + url := fmt.Sprintf("http://editor:editor@%s/api/annotations", grafanaListedAddr) + resp, err := http.Get(url) // nolint:gosec + require.NoError(t, err) + assert.Equal(t, http.StatusOK, resp.StatusCode) + body, err := io.ReadAll(resp.Body) + require.NoError(t, err) + err = resp.Body.Close() + require.NoError(t, err) + + var annotations []interface{} + err = json.Unmarshal(body, &annotations) + require.NoError(t, err) + assert.Len(t, annotations, 2) + }) + + t.Run("should allow viewer to access org annotations and annotations for dashboards they have access to (dash3)", func(t *testing.T) { + url := fmt.Sprintf("http://viewer:viewer@%s/api/annotations", grafanaListedAddr) + resp, err := http.Get(url) // nolint:gosec + require.NoError(t, err) + assert.Equal(t, http.StatusOK, resp.StatusCode) + body, err := io.ReadAll(resp.Body) + require.NoError(t, err) + err = resp.Body.Close() + require.NoError(t, err) + + var annotations []interface{} + err = json.Unmarshal(body, &annotations) + require.NoError(t, err) + assert.Len(t, annotations, 2) + }) + + t.Run("should allow editor to create org annotations", func(t *testing.T) { + annotationPayload := map[string]interface{}{ + "text": "Test annotations", + "time": 1234567890000, + } + + payloadBytes, err := json.Marshal(annotationPayload) + require.NoError(t, err) + url := fmt.Sprintf("http://editor:editor@%s/api/annotations", grafanaListedAddr) + resp, err := http.Post(url, "application/json", bytes.NewBuffer(payloadBytes)) // nolint:gosec + require.NoError(t, err) + assert.Equal(t, http.StatusOK, resp.StatusCode) + err = resp.Body.Close() + require.NoError(t, err) + }) + + t.Run("should deny viewer from creating org annotations", func(t *testing.T) { + annotationPayload := map[string]interface{}{ + "text": "Test annotation", + "time": 1234567890000, + } + + payloadBytes, err := json.Marshal(annotationPayload) + require.NoError(t, err) + + url := fmt.Sprintf("http://viewer:viewer@%s/api/annotations", grafanaListedAddr) + resp, err := http.Post(url, "application/json", bytes.NewBuffer(payloadBytes)) // nolint:gosec + require.NoError(t, err) + assert.Equal(t, http.StatusForbidden, resp.StatusCode) + err = resp.Body.Close() + require.NoError(t, err) + }) + + t.Run("should allow editor to create dashboard annotations", func(t *testing.T) { + annotationPayload := map[string]interface{}{ + "dashboardId": dash3.ID, + "panelId": 1, + "text": "Test annotations", + "time": 1234567890000, + } + + payloadBytes, err := json.Marshal(annotationPayload) + require.NoError(t, err) + url := fmt.Sprintf("http://editor:editor@%s/api/annotations", grafanaListedAddr) + resp, err := http.Post(url, "application/json", bytes.NewBuffer(payloadBytes)) // nolint:gosec + require.NoError(t, err) + assert.Equal(t, http.StatusOK, resp.StatusCode) + err = resp.Body.Close() + require.NoError(t, err) + }) + + t.Run("should deny viewer from creating dashboard annotations", func(t *testing.T) { + annotationPayload := map[string]interface{}{ + "dashboardId": dash3.ID, + "panelId": 1, + "text": "Test annotation", + "time": 1234567890000, + } + + payloadBytes, err := json.Marshal(annotationPayload) + require.NoError(t, err) + + url := fmt.Sprintf("http://viewer:viewer@%s/api/annotations", grafanaListedAddr) + resp, err := http.Post(url, "application/json", bytes.NewBuffer(payloadBytes)) // nolint:gosec + require.NoError(t, err) + assert.Equal(t, http.StatusForbidden, resp.StatusCode) + err = resp.Body.Close() + require.NoError(t, err) + }) + }) +} + +func createAnnotation(t *testing.T, grafanaListedAddr string, username, password string, payload map[string]interface{}) { + t.Helper() + + payloadBytes, err := json.Marshal(payload) + require.NoError(t, err) + + url := fmt.Sprintf("http://%s:%s@%s/api/annotations", username, password, grafanaListedAddr) + resp, err := http.Post(url, "application/json", bytes.NewBuffer(payloadBytes)) // nolint:gosec + require.NoError(t, err) + assert.Equal(t, http.StatusOK, resp.StatusCode) + err = resp.Body.Close() + require.NoError(t, err) +} + +func setDashboardPermissions(t *testing.T, grafanaListedAddr string, dashboardUID string, permissions []map[string]interface{}) { + t.Helper() + + payload := map[string]interface{}{ + "items": permissions, + } + + payloadBytes, err := json.Marshal(payload) + require.NoError(t, err) + + url := fmt.Sprintf("http://admin:admin@%s/api/dashboards/uid/%s/permissions", grafanaListedAddr, dashboardUID) + req, err := http.NewRequest(http.MethodPost, url, bytes.NewBuffer(payloadBytes)) + require.NoError(t, err) + req.Header.Set("Content-Type", "application/json") + + client := &http.Client{} + resp, err := client.Do(req) + require.NoError(t, err) + assert.Equal(t, http.StatusOK, resp.StatusCode) + err = resp.Body.Close() + require.NoError(t, err) +} + +func setFolderPermissions(t *testing.T, grafanaListedAddr string, folderUID string, permissions []map[string]interface{}) { + t.Helper() + + payload := map[string]interface{}{ + "items": permissions, + } + + payloadBytes, err := json.Marshal(payload) + require.NoError(t, err) + + url := fmt.Sprintf("http://admin:admin@%s/api/folders/%s/permissions", grafanaListedAddr, folderUID) + req, err := http.NewRequest(http.MethodPost, url, bytes.NewBuffer(payloadBytes)) + require.NoError(t, err) + req.Header.Set("Content-Type", "application/json") + + client := &http.Client{} + resp, err := client.Do(req) + require.NoError(t, err) + assert.Equal(t, http.StatusOK, resp.StatusCode) + err = resp.Body.Close() + require.NoError(t, err) +} + +func createFolder(t *testing.T, grafanaListedAddr string, title string) *dtos.Folder { + t.Helper() + + buf1 := &bytes.Buffer{} + err := json.NewEncoder(buf1).Encode(folder.CreateFolderCommand{ + Title: title, + }) + require.NoError(t, err) + u := fmt.Sprintf("http://admin:admin@%s/api/folders", grafanaListedAddr) + // nolint:gosec + resp, err := http.Post(u, "application/json", buf1) + require.NoError(t, err) + assert.Equal(t, http.StatusOK, resp.StatusCode) + t.Cleanup(func() { + err := resp.Body.Close() + require.NoError(t, err) + }) + b, err := io.ReadAll(resp.Body) + require.NoError(t, err) + require.Equal(t, http.StatusOK, resp.StatusCode) + var f *dtos.Folder + err = json.Unmarshal(b, &f) + require.NoError(t, err) + + return f +} + +func createDashboard(t *testing.T, grafanaListedAddr string, title string, folderID int64, folderUID string) *dashboards.Dashboard { + t.Helper() + + buf := &bytes.Buffer{} + err := json.NewEncoder(buf).Encode(map[string]interface{}{ + "dashboard": map[string]interface{}{ + "title": title, + }, + "folderId": folderID, + "folderUid": folderUID, + "overwrite": true, + }) + require.NoError(t, err) + + u := fmt.Sprintf("http://admin:admin@%s/api/dashboards/db", grafanaListedAddr) + // nolint:gosec + resp, err := http.Post(u, "application/json", buf) + require.NoError(t, err) + require.Equal(t, http.StatusOK, resp.StatusCode) + t.Cleanup(func() { + err := resp.Body.Close() + require.NoError(t, err) + }) + + b, err := io.ReadAll(resp.Body) + require.NoError(t, err) + + var saveResp struct { + Status string `json:"status"` + Slug string `json:"slug"` + Version int64 `json:"version"` + ID int64 `json:"id"` + UID string `json:"uid"` + URL string `json:"url"` + FolderUID string `json:"folderUid"` + } + err = json.Unmarshal(b, &saveResp) + require.NoError(t, err) + require.NotEmpty(t, saveResp.UID) + + return &dashboards.Dashboard{ + ID: saveResp.ID, // nolint:staticcheck + UID: saveResp.UID, + Slug: saveResp.Slug, + Version: int(saveResp.Version), + FolderUID: saveResp.FolderUID, + } +} From 5ef744aa20728d2fe225c2011e98cb6484e1946e Mon Sep 17 00:00:00 2001 From: Stephanie Hingtgen Date: Mon, 28 Jul 2025 11:38:10 -0500 Subject: [PATCH 065/131] Library panels: Move to integration tests (#108737) --- .../libraryelements/libraryelements_test.go | 74 --------- .../library_panels_api_validation_test.go | 143 ++++++++++++++++++ 2 files changed, 143 insertions(+), 74 deletions(-) diff --git a/pkg/services/libraryelements/libraryelements_test.go b/pkg/services/libraryelements/libraryelements_test.go index ad8b412e860..def4ff5660a 100644 --- a/pkg/services/libraryelements/libraryelements_test.go +++ b/pkg/services/libraryelements/libraryelements_test.go @@ -216,80 +216,6 @@ func TestIntegration_GetLibraryPanelConnections(t *testing.T) { } }) - scenarioWithPanel(t, "When a user tries to get connections of library panel, dashboards in inaccessible folders should not be returned", - func(t *testing.T, sc scenarioContext) { - accessibleFolder := createFolder(t, sc, "AccessibleFolder", sc.service.folderService) - inaccessibleFolder := createFolder(t, sc, "InAccessibleFolder", sc.service.folderService) - restrictedUser := user.SignedInUser{ - UserID: 2, - Name: "Non-Admin User", - Login: "non-admin-user", - OrgID: sc.user.OrgID, - OrgRole: org.RoleViewer, - LastSeenAt: time.Now(), - Permissions: map[int64]map[string][]string{ - sc.user.OrgID: { - dashboards.ActionFoldersRead: { - dashboards.ScopeFoldersProvider.GetResourceScopeUID(accessibleFolder.UID), - }, - dashboards.ActionDashboardsRead: {dashboards.ScopeDashboardsProvider.GetResourceScopeUID("*")}, - }, - }, - } - - command := getCreatePanelCommand(accessibleFolder.ID, accessibleFolder.UID, "Accessible Library Panel") // nolint:staticcheck - sc.reqContext.Req.Body = mockRequestBody(command) - resp := sc.service.createHandler(sc.reqContext) - libraryElement := validateAndUnMarshalResponse(t, resp) - - dashJSON := map[string]any{ - "panels": []any{ - map[string]any{ - "id": int64(1), - "gridPos": map[string]any{ - "h": 6, - "w": 6, - "x": 0, - "y": 0, - }, - "libraryPanel": map[string]any{ - "uid": libraryElement.Result.UID, - "name": libraryElement.Result.Name, - }, - }, - }, - } - accessibleDash := dashboards.Dashboard{ - Title: "Accessible Dashboard", - Data: simplejson.NewFromAny(dashJSON), - } - - // create the dashboard in the general folder, an accessible folder, and an inaccessible folder - dashInGeneral := createDashboard(t, sc.sqlStore, restrictedUser, &accessibleDash, 0, "") - err := sc.service.ConnectElementsToDashboard(sc.reqContext.Req.Context(), sc.reqContext.SignedInUser, []string{libraryElement.Result.UID}, dashInGeneral.ID) - require.NoError(t, err) - - dashInAccessibleFolder := createDashboard(t, sc.sqlStore, restrictedUser, &accessibleDash, 0, accessibleFolder.UID) - err = sc.service.ConnectElementsToDashboard(sc.reqContext.Req.Context(), sc.reqContext.SignedInUser, []string{libraryElement.Result.UID}, dashInAccessibleFolder.ID) - require.NoError(t, err) - - dashInInaccessibleFolder := createDashboard(t, sc.sqlStore, restrictedUser, &accessibleDash, 0, inaccessibleFolder.UID) - err = sc.service.ConnectElementsToDashboard(sc.reqContext.Req.Context(), sc.reqContext.SignedInUser, []string{libraryElement.Result.UID}, dashInInaccessibleFolder.ID) - require.NoError(t, err) - - sc.reqContext.SignedInUser = &restrictedUser - sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": libraryElement.Result.UID}) - - // connections should return the general folder one and the accessible folder one - connectionsResp := sc.service.getConnectionsHandler(sc.reqContext) - var result = validateAndUnMarshalConnectionResponse(t, connectionsResp) - require.Len(t, result.Result, 2) - uids := []string{result.Result[0].ConnectionUID, result.Result[1].ConnectionUID} - require.Contains(t, uids, dashInGeneral.UID) - require.Contains(t, uids, dashInAccessibleFolder.UID) - require.NotContains(t, uids, dashInInaccessibleFolder.UID) - }) - scenarioWithPanel(t, "When an admin tries to create a connection with an element that exists, but the original folder does not, it should still succeed", func(t *testing.T, sc scenarioContext) { b, err := json.Marshal(map[string]string{"test": "test"}) diff --git a/pkg/tests/apis/dashboard/integration/library_panels_api_validation_test.go b/pkg/tests/apis/dashboard/integration/library_panels_api_validation_test.go index c9d74b964df..b2857d97a69 100644 --- a/pkg/tests/apis/dashboard/integration/library_panels_api_validation_test.go +++ b/pkg/tests/apis/dashboard/integration/library_panels_api_validation_test.go @@ -12,6 +12,7 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" "github.com/grafana/grafana/pkg/apiserver/rest" + "github.com/grafana/grafana/pkg/services/org" "github.com/grafana/grafana/pkg/tests/apis" "github.com/grafana/grafana/pkg/tests/testinfra" ) @@ -292,3 +293,145 @@ func deleteLibraryElement(t *testing.T, ctx TestContext, user apis.User, uid str return nil } + +func TestIntegrationLibraryPanelConnectionsWithFolderAccess(t *testing.T) { + dualWriterModes := []rest.DualWriterMode{rest.Mode0, rest.Mode1, rest.Mode2, rest.Mode3, rest.Mode4, rest.Mode5} + for _, dualWriterMode := range dualWriterModes { + t.Run(fmt.Sprintf("DualWriterMode %d", dualWriterMode), func(t *testing.T) { + helper := apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{ + DisableAnonymous: true, + EnableFeatureToggles: []string{ + "unifiedStorageSearch", + "kubernetesLibraryPanels", + "kubernetesClientDashboardsFolders", + }, + }) + ctx := createTestContext(t, helper, helper.Org1, dualWriterMode) + + accessibleFolder, err := createFolder(t, ctx.Helper, ctx.AdminUser, "AccessibleFolder") + require.NoError(t, err) + require.NotNil(t, accessibleFolder) + + inaccessibleFolder, err := createFolder(t, ctx.Helper, ctx.AdminUser, "InAccessibleFolder") + require.NoError(t, err) + require.NotNil(t, inaccessibleFolder) + + setResourceUserPermission(t, ctx, ctx.AdminUser, false, accessibleFolder.UID, addUserPermission(t, nil, ctx.ViewerUser, ResourcePermissionLevelView)) + setResourceUserPermission(t, ctx, ctx.AdminUser, false, inaccessibleFolder.UID, []ResourcePermissionSetting{}) + + libraryElement := map[string]interface{}{ + "kind": 1, + "name": "Accessible Library Panel", + "folderUid": accessibleFolder.UID, + "model": map[string]interface{}{ + "type": "text", + "title": "Accessible Library Panel", + }, + } + libraryElementURL := "/api/library-elements" + libraryElementData, err := postHelper(t, &ctx, libraryElementURL, libraryElement, ctx.AdminUser) + require.NoError(t, err) + require.NotNil(t, libraryElementData) + data := libraryElementData["result"].(map[string]interface{}) + uid := data["uid"].(string) + require.NotEmpty(t, uid) + + dashInGeneral := createDashboardObject(t, "Dashboard in General", "", 1) + dashInGeneral.Object["spec"].(map[string]interface{})["panels"] = []interface{}{ + map[string]interface{}{ + "id": 1, + "title": "Library Panel", + "type": "library-panel-ref", + "libraryPanel": map[string]interface{}{ + "uid": uid, + "name": "Accessible Library Panel", + }, + }, + } + adminClient := getResourceClient(t, ctx.Helper, ctx.AdminUser, getDashboardGVR()) + createdDashInGeneral, err := adminClient.Resource.Create(context.Background(), dashInGeneral, v1.CreateOptions{}) + require.NoError(t, err) + require.NotNil(t, createdDashInGeneral) + + dashInAccessibleFolder := createDashboardObject(t, "Dashboard in Accessible Folder", accessibleFolder.UID, 1) + dashInAccessibleFolder.Object["spec"].(map[string]interface{})["panels"] = []interface{}{ + map[string]interface{}{ + "id": 1, + "title": "Library Panel", + "type": "library-panel-ref", + "libraryPanel": map[string]interface{}{ + "uid": uid, + "name": "Accessible Library Panel", + }, + }, + } + createdDashInAccessible, err := adminClient.Resource.Create(context.Background(), dashInAccessibleFolder, v1.CreateOptions{}) + require.NoError(t, err) + require.NotNil(t, createdDashInAccessible) + + dashInInaccessibleFolder := createDashboardObject(t, "Dashboard in Inaccessible Folder", inaccessibleFolder.UID, 1) + dashInInaccessibleFolder.Object["spec"].(map[string]interface{})["panels"] = []interface{}{ + map[string]interface{}{ + "id": 1, + "title": "Library Panel", + "type": "library-panel-ref", + "libraryPanel": map[string]interface{}{ + "uid": uid, + "name": "Accessible Library Panel", + }, + }, + } + createdDashInInaccessible, err := adminClient.Resource.Create(context.Background(), dashInInaccessibleFolder, v1.CreateOptions{}) + require.NoError(t, err) + require.NotNil(t, createdDashInInaccessible) + + connectionsURL := fmt.Sprintf("/api/library-elements/%s/connections", uid) + connectionsData, err := getDashboardViaHTTP(t, &ctx, connectionsURL, ctx.AdminUser) + require.NoError(t, err) + require.NotNil(t, connectionsData) + connections := connectionsData["result"].([]interface{}) + require.Len(t, connections, 3, "Admin should see all connections") + connectionUIDs := make([]string, 0, len(connections)) + for _, conn := range connections { + connMap := conn.(map[string]interface{}) + if connectionUID, ok := connMap["connectionUid"].(string); ok { + connectionUIDs = append(connectionUIDs, connectionUID) + } + } + generalDashUID := createdDashInGeneral.GetName() + accessibleDashUID := createdDashInAccessible.GetName() + inaccessibleDashUID := createdDashInInaccessible.GetName() + require.Contains(t, connectionUIDs, generalDashUID, "Admin should see dashboard in general folder") + require.Contains(t, connectionUIDs, accessibleDashUID, "Admin should see dashboard in accessible folder") + require.Contains(t, connectionUIDs, inaccessibleDashUID, "Admin should see dashboard in inaccessible folder") + + limitedUser := ctx.Helper.CreateUser("limited-user", "Org1", org.RoleViewer, nil) + // can access accessibleFolder but not inaccessibleFolder + setResourceUserPermission(t, ctx, ctx.AdminUser, false, accessibleFolder.UID, addUserPermission(t, nil, limitedUser, ResourcePermissionLevelView)) + setResourceUserPermission(t, ctx, ctx.AdminUser, false, inaccessibleFolder.UID, []ResourcePermissionSetting{}) + connectionsDataLimited, err := getDashboardViaHTTP(t, &ctx, connectionsURL, limitedUser) + require.NoError(t, err) + require.NotNil(t, connectionsDataLimited) + connectionsLimited := connectionsDataLimited["result"].([]interface{}) + require.Len(t, connectionsLimited, 2, "Limited user should only see connections to accessible dashboards") + + connectionUIDsLimited := make([]string, 0, len(connectionsLimited)) + for _, conn := range connectionsLimited { + connMap := conn.(map[string]interface{}) + if connectionUID, ok := connMap["connectionUid"].(string); ok { + connectionUIDsLimited = append(connectionUIDsLimited, connectionUID) + } + } + require.Contains(t, connectionUIDsLimited, generalDashUID, "Limited user should see dashboard in general folder") + require.Contains(t, connectionUIDsLimited, accessibleDashUID, "Limited user should see dashboard in accessible folder") + require.NotContains(t, connectionUIDsLimited, inaccessibleDashUID, "Limited user should NOT see dashboard in inaccessible folder") + + err = adminClient.Resource.Delete(context.Background(), createdDashInGeneral.GetName(), v1.DeleteOptions{}) + require.NoError(t, err) + err = adminClient.Resource.Delete(context.Background(), createdDashInAccessible.GetName(), v1.DeleteOptions{}) + require.NoError(t, err) + err = adminClient.Resource.Delete(context.Background(), createdDashInInaccessible.GetName(), v1.DeleteOptions{}) + require.NoError(t, err) + }) + } +} From caa75b1d9421ba3e07d5d07618e1f4b81472f200 Mon Sep 17 00:00:00 2001 From: Stephanie Hingtgen Date: Mon, 28 Jul 2025 12:14:09 -0500 Subject: [PATCH 066/131] Public dashboards: move to integration tests (#108735) --- .../publicdashboards/api/common_test.go | 92 --- .../publicdashboards/api/query_test.go | 147 ----- .../publicdashboards/service/service_test.go | 559 ------------------ .../public_dashboard_query_test.go | 195 ++++++ .../public_dashboards_api_test.go | 439 ++++++++++++++ 5 files changed, 634 insertions(+), 798 deletions(-) create mode 100644 pkg/tests/api/publicdashboards/public_dashboard_query_test.go create mode 100644 pkg/tests/api/publicdashboards/public_dashboards_api_test.go diff --git a/pkg/services/publicdashboards/api/common_test.go b/pkg/services/publicdashboards/api/common_test.go index d022408d82f..c7847135380 100644 --- a/pkg/services/publicdashboards/api/common_test.go +++ b/pkg/services/publicdashboards/api/common_test.go @@ -1,7 +1,6 @@ package api import ( - "context" "io" "net/http" "net/http/httptest" @@ -9,32 +8,15 @@ import ( "github.com/stretchr/testify/require" - "github.com/grafana/grafana-plugin-sdk-go/backend" - "github.com/grafana/grafana-plugin-sdk-go/data" - "github.com/grafana/grafana/pkg/api/routing" - "github.com/grafana/grafana/pkg/infra/db" - "github.com/grafana/grafana/pkg/infra/localcache" "github.com/grafana/grafana/pkg/infra/log" - "github.com/grafana/grafana/pkg/plugins" "github.com/grafana/grafana/pkg/services/accesscontrol/acimpl" "github.com/grafana/grafana/pkg/services/contexthandler/ctxkey" contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model" - "github.com/grafana/grafana/pkg/services/datasources" - fakeDatasources "github.com/grafana/grafana/pkg/services/datasources/fakes" - "github.com/grafana/grafana/pkg/services/datasources/guardian" - datasourceService "github.com/grafana/grafana/pkg/services/datasources/service" "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/licensing/licensingtest" - "github.com/grafana/grafana/pkg/services/mtdsclient" - "github.com/grafana/grafana/pkg/services/pluginsintegration/pluginconfig" - "github.com/grafana/grafana/pkg/services/pluginsintegration/plugincontext" - pluginSettings "github.com/grafana/grafana/pkg/services/pluginsintegration/pluginsettings/service" - "github.com/grafana/grafana/pkg/services/pluginsintegration/pluginstore" "github.com/grafana/grafana/pkg/services/publicdashboards" publicdashboardModels "github.com/grafana/grafana/pkg/services/publicdashboards/models" - "github.com/grafana/grafana/pkg/services/query" - fakeSecrets "github.com/grafana/grafana/pkg/services/secrets/fakes" "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/tests/testsuite" @@ -108,77 +90,3 @@ func callAPI(server *web.Mux, method, path string, body io.Reader, t *testing.T) server.ServeHTTP(recorder, req) return recorder } - -// helper to query.Service -// allows us to stub the cache and plugin clients -func buildQueryDataService(t *testing.T, cs datasources.CacheService, fpc *fakePluginClient, store db.DB) *query.ServiceImpl { - // build database if we need one - if store == nil { - store = db.InitTestDB(t) - } - - // default cache service - if cs == nil { - cs = datasourceService.ProvideCacheService(localcache.ProvideService(), store, guardian.ProvideGuardian()) - } - - // default fakePluginClient - if fpc == nil { - fpc = &fakePluginClient{ - QueryDataHandlerFunc: func(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) { - resp := backend.Responses{ - "A": backend.DataResponse{ - Frames: []*data.Frame{{}}, - }, - } - return &backend.QueryDataResponse{Responses: resp}, nil - }, - } - } - - ds := &fakeDatasources.FakeDataSourceService{} - pCtxProvider := plugincontext.ProvideService(setting.NewCfg(), - localcache.ProvideService(), &pluginstore.FakePluginStore{ - PluginList: []pluginstore.Plugin{ - { - JSONData: plugins.JSONData{ - ID: "mysql", - }, - }, - }, - }, &fakeDatasources.FakeCacheService{}, ds, - pluginSettings.ProvideService(store, fakeSecrets.NewFakeSecretsService()), pluginconfig.NewFakePluginRequestConfigProvider()) - - return query.ProvideService( - setting.NewCfg(), - cs, - nil, - &fakeDataSourceRequestValidator{}, - fpc, - pCtxProvider, - mtdsclient.NewNullMTDatasourceClientBuilder(), - ) -} - -// copied from pkg/api/metrics_test.go -type fakeDataSourceRequestValidator struct { - err error -} - -func (rv *fakeDataSourceRequestValidator) Validate(ds *datasources.DataSource, req *http.Request) error { - return rv.err -} - -// copied from pkg/api/plugins_test.go -type fakePluginClient struct { - plugins.Client - backend.QueryDataHandlerFunc -} - -func (c *fakePluginClient) QueryData(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) { - if c.QueryDataHandlerFunc != nil { - return c.QueryDataHandlerFunc.QueryData(ctx, req) - } - - return backend.NewQueryDataResponse(), nil -} diff --git a/pkg/services/publicdashboards/api/query_test.go b/pkg/services/publicdashboards/api/query_test.go index c3b508d5627..02367824fbd 100644 --- a/pkg/services/publicdashboards/api/query_test.go +++ b/pkg/services/publicdashboards/api/query_test.go @@ -1,7 +1,6 @@ package api import ( - "context" "encoding/json" "errors" "fmt" @@ -20,35 +19,9 @@ import ( "github.com/grafana/grafana/pkg/api/dtos" "github.com/grafana/grafana/pkg/apimachinery/errutil" "github.com/grafana/grafana/pkg/components/simplejson" - "github.com/grafana/grafana/pkg/infra/db" - "github.com/grafana/grafana/pkg/infra/kvstore" - "github.com/grafana/grafana/pkg/infra/localcache" - "github.com/grafana/grafana/pkg/infra/log" - "github.com/grafana/grafana/pkg/infra/serverlock" - "github.com/grafana/grafana/pkg/infra/tracing" - "github.com/grafana/grafana/pkg/services/accesscontrol/actest" - acmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock" - "github.com/grafana/grafana/pkg/services/annotations/annotationstest" - "github.com/grafana/grafana/pkg/services/apiserver/client" "github.com/grafana/grafana/pkg/services/dashboards" - dashboardStore "github.com/grafana/grafana/pkg/services/dashboards/database" - "github.com/grafana/grafana/pkg/services/dashboards/service" - "github.com/grafana/grafana/pkg/services/datasources" - "github.com/grafana/grafana/pkg/services/datasources/guardian" - datasourcesService "github.com/grafana/grafana/pkg/services/datasources/service" - "github.com/grafana/grafana/pkg/services/featuremgmt" - "github.com/grafana/grafana/pkg/services/folder/folderimpl" - "github.com/grafana/grafana/pkg/services/folder/foldertest" - "github.com/grafana/grafana/pkg/services/licensing/licensingtest" "github.com/grafana/grafana/pkg/services/publicdashboards" - publicdashboardsStore "github.com/grafana/grafana/pkg/services/publicdashboards/database" . "github.com/grafana/grafana/pkg/services/publicdashboards/models" - publicdashboardsService "github.com/grafana/grafana/pkg/services/publicdashboards/service" - "github.com/grafana/grafana/pkg/services/quota/quotatest" - "github.com/grafana/grafana/pkg/services/search/sort" - "github.com/grafana/grafana/pkg/services/tag/tagimpl" - "github.com/grafana/grafana/pkg/services/user" - "github.com/grafana/grafana/pkg/storage/legacysql/dualwrite" "github.com/grafana/grafana/pkg/web" ) @@ -258,126 +231,6 @@ func getValidQueryPath(accessToken string) string { return fmt.Sprintf("/api/public/dashboards/%s/panels/2/query", accessToken) } -func TestIntegrationUnauthenticatedUserCanGetPubdashPanelQueryData(t *testing.T) { - if testing.Short() { - t.Skip("skipping integration test") - } - db, cfg := db.InitTestDBWithCfg(t) - - cacheService := datasourcesService.ProvideCacheService(localcache.ProvideService(), db, guardian.ProvideGuardian()) - qds := buildQueryDataService(t, cacheService, nil, db) - dsStore := datasourcesService.CreateStore(db, log.New("publicdashboards.test")) - _, _ = dsStore.AddDataSource(context.Background(), &datasources.AddDataSourceCommand{ - UID: "ds1", - OrgID: 1, - Name: "laban", - Type: datasources.DS_MYSQL, - Access: datasources.DS_ACCESS_DIRECT, - URL: "http://test", - Database: "site", - ReadOnly: true, - }) - - // Create Dashboard - saveDashboardCmd := dashboards.SaveDashboardCommand{ - OrgID: 1, - FolderUID: "", - IsFolder: false, - Dashboard: simplejson.NewFromAny(map[string]any{ - "id": nil, - "title": "test", - "panels": []map[string]any{ - { - "id": 1, - "targets": []map[string]any{ - { - "datasource": map[string]string{ - "type": "mysql", - "uid": "ds1", - }, - "refId": "A", - }, - }, - }, - }, - }), - } - - // create dashboard - dashboardStoreService, err := dashboardStore.ProvideDashboardStore(db, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(db)) - require.NoError(t, err) - dashboard, err := dashboardStoreService.SaveDashboard(context.Background(), saveDashboardCmd) - require.NoError(t, err) - - // Create public dashboard - isEnabled := true - savePubDashboardCmd := &SavePublicDashboardDTO{ - DashboardUid: dashboard.UID, - OrgID: dashboard.OrgID, - PublicDashboard: &PublicDashboardDTO{ - IsEnabled: &isEnabled, - }, - } - - annotationsService := annotationstest.NewFakeAnnotationsRepo() - - // create public dashboard - store := publicdashboardsStore.ProvideStore(db, cfg, featuremgmt.WithFeatures()) - cfg.PublicDashboardsEnabled = true - ac := actest.FakeAccessControl{} - ws := publicdashboardsService.ProvideServiceWrapper(store) - folderStore := folderimpl.ProvideDashboardFolderStore(db) - dashPermissionService := acmock.NewMockedPermissionsService() - dashService, err := service.ProvideDashboardServiceImpl( - cfg, dashboardStoreService, folderStore, - featuremgmt.WithFeatures(), acmock.NewMockedPermissionsService(), ac, actest.FakeService{}, - foldertest.NewFakeService(), nil, client.MockTestRestConfig{}, nil, quotatest.New(false, nil), nil, nil, - nil, dualwrite.ProvideTestService(), sort.ProvideService(), - serverlock.ProvideService(db, tracing.InitializeTracerForTest()), - kvstore.NewFakeKVStore(), - ) - require.NoError(t, err) - dashService.RegisterDashboardPermissions(dashPermissionService) - - license := licensingtest.NewFakeLicensing() - license.On("FeatureEnabled", FeaturePublicDashboardsEmailSharing).Return(false) - pds := publicdashboardsService.ProvideService(cfg, featuremgmt.WithFeatures(), store, qds, annotationsService, ac, ws, dashService, license) - pubdash, err := pds.Create(context.Background(), &user.SignedInUser{}, savePubDashboardCmd) - require.NoError(t, err) - - // setup test server - server := setupTestServer(t, cfg, pds, anonymousUser) - - resp := callAPI(server, http.MethodPost, - fmt.Sprintf("/api/public/dashboards/%s/panels/1/query", pubdash.AccessToken), - strings.NewReader(`{}`), - t, - ) - require.Equal(t, http.StatusOK, resp.Code) - require.NoError(t, err) - require.JSONEq( - t, - `{ - "results": { - "A": { - "status": 200, - "frames": [ - { - "data": { - "values": [] - }, - "schema": { - "fields": [] - } - } - ] - } - } - }`, - resp.Body.String(), - ) -} - func TestAPIGetAnnotations(t *testing.T) { testCases := []struct { Name string diff --git a/pkg/services/publicdashboards/service/service_test.go b/pkg/services/publicdashboards/service/service_test.go index f79ada33f83..d10eb8641dc 100644 --- a/pkg/services/publicdashboards/service/service_test.go +++ b/pkg/services/publicdashboards/service/service_test.go @@ -16,33 +16,16 @@ import ( "github.com/grafana/grafana/pkg/api/dtos" "github.com/grafana/grafana/pkg/apimachinery/errutil" - "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/components/simplejson" - "github.com/grafana/grafana/pkg/infra/db" - "github.com/grafana/grafana/pkg/infra/kvstore" - "github.com/grafana/grafana/pkg/infra/serverlock" - "github.com/grafana/grafana/pkg/infra/tracing" - "github.com/grafana/grafana/pkg/services/accesscontrol" - "github.com/grafana/grafana/pkg/services/accesscontrol/actest" - acmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock" - "github.com/grafana/grafana/pkg/services/apiserver" - "github.com/grafana/grafana/pkg/services/apiserver/client" "github.com/grafana/grafana/pkg/services/dashboards" dashboardsDB "github.com/grafana/grafana/pkg/services/dashboards/database" - dashsvc "github.com/grafana/grafana/pkg/services/dashboards/service" "github.com/grafana/grafana/pkg/services/featuremgmt" - "github.com/grafana/grafana/pkg/services/folder/folderimpl" - "github.com/grafana/grafana/pkg/services/org" . "github.com/grafana/grafana/pkg/services/publicdashboards" . "github.com/grafana/grafana/pkg/services/publicdashboards/models" "github.com/grafana/grafana/pkg/services/publicdashboards/service/intervalv2" "github.com/grafana/grafana/pkg/services/publicdashboards/validation" - "github.com/grafana/grafana/pkg/services/quota/quotatest" - "github.com/grafana/grafana/pkg/services/search/sort" - "github.com/grafana/grafana/pkg/services/supportbundles/supportbundlestest" "github.com/grafana/grafana/pkg/services/tag/tagimpl" "github.com/grafana/grafana/pkg/services/user" - "github.com/grafana/grafana/pkg/storage/legacysql/dualwrite" "github.com/grafana/grafana/pkg/tests/testsuite" "github.com/grafana/grafana/pkg/util" ) @@ -1407,548 +1390,6 @@ func TestDashboardEnabledChanged(t *testing.T) { }) } -func TestIntegrationPublicDashboardServiceImpl_ListPublicDashboards(t *testing.T) { - if testing.Short() { - t.Skip("skipping integration test in short mode") - } - features := featuremgmt.WithFeatures() - testDB, cfg := db.InitTestDBWithCfg(t) - dashStore, err := dashboardsDB.ProvideDashboardStore(testDB, cfg, features, tagimpl.ProvideService(testDB)) - require.NoError(t, err) - ac := actest.FakeAccessControl{ExpectedEvaluate: true} - - fStore := folderimpl.ProvideStore(testDB) - folderPermissions := acmock.NewMockedPermissionsService() - folderStore := folderimpl.ProvideDashboardFolderStore(testDB) - folderSvc := folderimpl.ProvideService( - fStore, ac, bus.ProvideBus(tracing.InitializeTracerForTest()), dashStore, folderStore, - nil, testDB, features, supportbundlestest.NewFakeBundleService(), nil, cfg, nil, tracing.InitializeTracerForTest(), nil, dualwrite.ProvideTestService(), sort.ProvideService(), apiserver.WithoutRestConfig) - - dashboardService, err := dashsvc.ProvideDashboardServiceImpl(cfg, dashStore, folderStore, featuremgmt.WithFeatures(), folderPermissions, ac, actest.FakeService{}, folderSvc, nil, client.MockTestRestConfig{}, nil, quotatest.New(false, nil), nil, nil, nil, dualwrite.ProvideTestService(), sort.ProvideService(), - serverlock.ProvideService(testDB, tracing.InitializeTracerForTest()), - kvstore.NewFakeKVStore()) - require.NoError(t, err) - dashboardService.RegisterDashboardPermissions(&actest.FakePermissionsService{}) - - // insert in test data so we can check that permissions are working properly through the dashboard service - // this will create 4 dashboards and 3 users - // user1 has access to all dashboards ("*") - // user2 has access to solely one dashboard - // user3 has access to all created dashboards through specific permissions - creatingUser := &user.SignedInUser{ - UserID: 1, - OrgID: 1, - OrgRole: org.RoleAdmin, - } - dashboardsToSave := []dashboards.SaveDashboardDTO{ - { - OrgID: 1, - User: creatingUser, - Dashboard: &dashboards.Dashboard{ - OrgID: 1, - UID: "9S6TmO67z", - Title: "test", - Slug: "test", - Data: simplejson.New(), - }, - }, - { - OrgID: 1, - User: creatingUser, - Dashboard: &dashboards.Dashboard{ - OrgID: 1, - UID: "1S6TmO67z", - Title: "my first dashboard", - Slug: "my-first-dashboard", - Data: simplejson.New(), - }, - }, - { - OrgID: 1, - User: creatingUser, - Dashboard: &dashboards.Dashboard{ - OrgID: 1, - UID: "2S6TmO67z", - Title: "my second dashboard", - Slug: "my-second-dashboard", - Data: simplejson.New(), - }, - }, - { - OrgID: 1, - User: creatingUser, - Dashboard: &dashboards.Dashboard{ - OrgID: 1, - UID: "0S6TmO67z", - Title: "my zero dashboard", - Slug: "my-zero-dashboard", - Data: simplejson.New(), - }, - }, - } - for _, dash := range dashboardsToSave { - _, err = dashboardService.SaveDashboard(context.Background(), &dash, true) - require.NoError(t, err) - } - - users := []user.User{ - { - ID: 1, - UID: "user1", - Email: "test1@gmail.com", - Login: "user1", - Created: time.Now(), - Updated: time.Now(), - }, - { - ID: 2, - UID: "user2", - Login: "user2", - Email: "test2@gmail.com", - Created: time.Now(), - Updated: time.Now(), - }, - { - ID: 3, - UID: "user3", - Login: "user3", - Email: "test3@gmail.com", - Created: time.Now(), - Updated: time.Now(), - }, - } - roles := []accesscontrol.Role{ - { - ID: 1, - UID: "role1", - Name: "forUser1", - Created: time.Now(), - Updated: time.Now(), - }, - { - ID: 2, - UID: "role2", - Name: "forUser2", - Created: time.Now(), - Updated: time.Now(), - }, - { - ID: 3, - UID: "role3", - Name: "forUser3", - Created: time.Now(), - Updated: time.Now(), - }, - } - - userRoles := []accesscontrol.UserRole{ - { - ID: 1, - OrgID: 1, - UserID: 1, - RoleID: 1, - Created: time.Now(), - }, - { - ID: 2, - OrgID: 1, - UserID: 2, - RoleID: 2, - Created: time.Now(), - }, - { - ID: 3, - OrgID: 1, - UserID: 3, - RoleID: 3, - Created: time.Now(), - }, - } - - permissions := []accesscontrol.Permission{ - { - ID: 1, - RoleID: 1, - Action: dashboards.ActionDashboardsRead, - Scope: "*", - Kind: "dashboards", - Created: time.Now(), - Updated: time.Now(), - }, - { - ID: 2, - RoleID: 2, - Action: dashboards.ActionDashboardsRead, - Scope: "dashboards:uid:1S6TmO67z", - Attribute: "uid", - Identifier: "1S6TmO67z", - Kind: "dashboards", - Created: time.Now(), - Updated: time.Now(), - }, - { - ID: 3, - RoleID: 3, - Action: dashboards.ActionDashboardsRead, - Scope: "dashboards:uid:0S6TmO67z", - Identifier: "0S6TmO67z", - Attribute: "uid", - Kind: "dashboards", - Created: time.Now(), - Updated: time.Now(), - }, - { - ID: 4, - RoleID: 3, - Action: dashboards.ActionDashboardsRead, - Scope: "dashboards:uid:1S6TmO67z", - Identifier: "1S6TmO67z", - Kind: "dashboards", - Attribute: "uid", - Created: time.Now(), - Updated: time.Now(), - }, - { - ID: 5, - RoleID: 3, - Action: dashboards.ActionDashboardsRead, - Scope: "dashboards:uid:2S6TmO67z", - Identifier: "2S6TmO67z", - Kind: "dashboards", - Attribute: "uid", - Created: time.Now(), - Updated: time.Now(), - }, - { - ID: 6, - RoleID: 3, - Action: dashboards.ActionDashboardsRead, - Scope: "dashboards:uid:9S6TmO67z", - Identifier: "9S6TmO67z", - Kind: "dashboards", - Attribute: "uid", - Created: time.Now(), - Updated: time.Now(), - }, - { - ID: 7, - RoleID: 1, - Action: dashboards.ActionFoldersRead, - Scope: "*", - Kind: "folders", - Created: time.Now(), - Updated: time.Now(), - }, - { - ID: 8, - RoleID: 2, - Action: dashboards.ActionFoldersRead, - Scope: "*", - Kind: "folders", - Created: time.Now(), - Updated: time.Now(), - }, - { - ID: 9, - RoleID: 3, - Action: dashboards.ActionFoldersRead, - Scope: "*", - Kind: "folders", - Created: time.Now(), - Updated: time.Now(), - }, - } - - err = testDB.WithDbSession(context.Background(), func(sess *db.Session) error { - if _, err := sess.Insert(users); err != nil { - return err - } - if _, err := sess.Insert(roles); err != nil { - return err - } - - if _, err := sess.Insert(userRoles); err != nil { - return err - } - _, err := sess.Insert(permissions) - return err - }) - require.NoError(t, err) - - type args struct { - ctx context.Context - query *PublicDashboardListQuery - } - type mockResponse struct { - PublicDashboardListResponseWithPagination *PublicDashboardListResponseWithPagination - Err error - DashboardResponse []dashboards.DashboardSearchProjection - DashboardErr error - } - - expectedFinalResponse := []*PublicDashboardListResponse{ - { - Uid: "1GwW7mgVk", - AccessToken: "1b458cb7fe7f42c68712078bcacee6e3", - DashboardUid: "1S6TmO67z", - Title: "my first dashboard", - Slug: "my-first-dashboard", - IsEnabled: true, - }, - { - Uid: "2GwW7mgVk", - AccessToken: "2b458cb7fe7f42c68712078bcacee6e3", - DashboardUid: "2S6TmO67z", - Title: "my second dashboard", - Slug: "my-second-dashboard", - IsEnabled: false, - }, - { - Uid: "0GwW7mgVk", - AccessToken: "0b458cb7fe7f42c68712078bcacee6e3", - DashboardUid: "0S6TmO67z", - Title: "my zero dashboard", - Slug: "my-zero-dashboard", - IsEnabled: true, - }, - { - Uid: "9GwW7mgVk", - AccessToken: "deletedashboardaccesstoken", - DashboardUid: "9S6TmO67z", - Title: "test", - Slug: "test", - IsEnabled: true, - }, - } - mockedStoreResponse := []*PublicDashboardListResponse{ - { - Uid: "0GwW7mgVk", - AccessToken: "0b458cb7fe7f42c68712078bcacee6e3", - DashboardUid: "0S6TmO67z", - IsEnabled: true, - }, - { - Uid: "1GwW7mgVk", - AccessToken: "1b458cb7fe7f42c68712078bcacee6e3", - DashboardUid: "1S6TmO67z", - IsEnabled: true, - }, - { - Uid: "2GwW7mgVk", - AccessToken: "2b458cb7fe7f42c68712078bcacee6e3", - DashboardUid: "2S6TmO67z", - IsEnabled: false, - }, - { - Uid: "9GwW7mgVk", - AccessToken: "deletedashboardaccesstoken", - DashboardUid: "9S6TmO67z", - IsEnabled: true, - }, - } - - testCases := []struct { - name string - args args - want *PublicDashboardListResponseWithPagination - mockResponse *mockResponse - wantErr assert.ErrorAssertionFunc - }{ - { - name: "should return full response when user has access to all dashboards", - args: args{ - ctx: context.Background(), - query: &PublicDashboardListQuery{ - User: &user.SignedInUser{OrgID: 1, UserID: 1, Permissions: map[int64]map[string][]string{1: {"dashboards:read": {"*"}, "folders:read": {"*"}}}}, - OrgID: 1, - Page: 1, - Limit: 50, - }, - }, - mockResponse: &mockResponse{ - PublicDashboardListResponseWithPagination: &PublicDashboardListResponseWithPagination{ - TotalCount: int64(len(mockedStoreResponse)), - PublicDashboards: mockedStoreResponse, - }, - Err: nil, - }, - want: &PublicDashboardListResponseWithPagination{ - Page: 1, - PerPage: 50, - TotalCount: int64(len(expectedFinalResponse)), - PublicDashboards: expectedFinalResponse, - }, - wantErr: assert.NoError, - }, - { - name: "should only return the one dashboard user 2 has access to", - args: args{ - ctx: context.Background(), - query: &PublicDashboardListQuery{ - User: &user.SignedInUser{OrgID: 1, UserID: 2, Permissions: map[int64]map[string][]string{1: {"dashboards:read": {"dashboards:uid:1S6TmO67z"}, "folders:read": {"*"}}}}, - OrgID: 1, - Page: 1, - Limit: 50, - }, - }, - mockResponse: &mockResponse{ - PublicDashboardListResponseWithPagination: &PublicDashboardListResponseWithPagination{ - TotalCount: int64(len(mockedStoreResponse)), - PublicDashboards: mockedStoreResponse, - }, - Err: nil, - }, - want: &PublicDashboardListResponseWithPagination{ - Page: 1, - PerPage: 50, - TotalCount: 1, - PublicDashboards: []*PublicDashboardListResponse{expectedFinalResponse[0]}, - }, - wantErr: assert.NoError, - }, - { - name: "should return full response when user 3 has specific access to all dashboards", - args: args{ - ctx: context.Background(), - query: &PublicDashboardListQuery{ - User: &user.SignedInUser{OrgID: 1, UserID: 3, Permissions: map[int64]map[string][]string{1: {"dashboards:read": {"dashboards:uid:0S6TmO67z", "dashboards:uid:1S6TmO67z", "dashboards:uid:2S6TmO67z", "dashboards:uid:9S6TmO67z"}, "folders:read": {"*"}}}}, - OrgID: 1, - Page: 1, - Limit: 50, - }, - }, - mockResponse: &mockResponse{ - PublicDashboardListResponseWithPagination: &PublicDashboardListResponseWithPagination{ - TotalCount: int64(len(mockedStoreResponse)), - PublicDashboards: mockedStoreResponse, - }, - Err: nil, - }, - want: &PublicDashboardListResponseWithPagination{ - Page: 1, - PerPage: 50, - TotalCount: int64(len(expectedFinalResponse)), - PublicDashboards: expectedFinalResponse, - }, - wantErr: assert.NoError, - }, - { - name: "should an empty response for a user with no access", - args: args{ - ctx: context.Background(), - query: &PublicDashboardListQuery{ - User: &user.SignedInUser{OrgID: 1, UserID: 4, Permissions: map[int64]map[string][]string{}}, - OrgID: 1, - Page: 1, - Limit: 50, - }, - }, - mockResponse: &mockResponse{ - PublicDashboardListResponseWithPagination: &PublicDashboardListResponseWithPagination{ - TotalCount: int64(len(mockedStoreResponse)), - PublicDashboards: mockedStoreResponse, - }, - Err: nil, - }, - want: &PublicDashboardListResponseWithPagination{ - Page: 1, - PerPage: 50, - TotalCount: 0, - PublicDashboards: []*PublicDashboardListResponse{}, - }, - wantErr: assert.NoError, - }, - { - name: "should return correct pagination response if limited", - args: args{ - ctx: context.Background(), - query: &PublicDashboardListQuery{ - User: &user.SignedInUser{OrgID: 1, UserID: 1, Permissions: map[int64]map[string][]string{1: {"dashboards:read": {"*"}, "folders:read": {"*"}}}}, - OrgID: 1, - Page: 1, - Limit: 2, - }, - }, - mockResponse: &mockResponse{ - PublicDashboardListResponseWithPagination: &PublicDashboardListResponseWithPagination{ - TotalCount: int64(len(mockedStoreResponse)), - PublicDashboards: mockedStoreResponse, - }, - Err: nil, - }, - want: &PublicDashboardListResponseWithPagination{ - Page: 1, - PerPage: 2, - TotalCount: 4, - PublicDashboards: expectedFinalResponse[:2], - }, - wantErr: assert.NoError, - }, - { - name: "should return correct page", - args: args{ - ctx: context.Background(), - query: &PublicDashboardListQuery{ - User: &user.SignedInUser{OrgID: 1, UserID: 1, Permissions: map[int64]map[string][]string{1: {"dashboards:read": {"*"}, "folders:read": {"*"}}}}, - OrgID: 1, - Page: 2, - Limit: 2, - }, - }, - mockResponse: &mockResponse{ - PublicDashboardListResponseWithPagination: &PublicDashboardListResponseWithPagination{ - TotalCount: int64(len(mockedStoreResponse)), - PublicDashboards: mockedStoreResponse, - }, - Err: nil, - }, - want: &PublicDashboardListResponseWithPagination{ - Page: 2, - PerPage: 2, - TotalCount: 4, - PublicDashboards: expectedFinalResponse[2:], - }, - wantErr: assert.NoError, - }, - { - name: "should return error when store returns error", - args: args{ - ctx: context.Background(), - query: &PublicDashboardListQuery{ - User: &user.SignedInUser{OrgID: 1, Permissions: map[int64]map[string][]string{ - 1: {"dashboards:read": {"dashboards:uid:0S6TmO67z"}}}, - }, - OrgID: 1, - Page: 1, - Limit: 50, - }, - }, - mockResponse: &mockResponse{ - PublicDashboardListResponseWithPagination: nil, - Err: errors.New("an err"), - }, - want: nil, - wantErr: assert.Error, - }, - } - - for _, tt := range testCases { - t.Run(tt.name, func(t *testing.T) { - store := NewFakePublicDashboardStore(t) - store.On("FindAll", mock.Anything, mock.Anything). - Return(tt.mockResponse.PublicDashboardListResponseWithPagination, tt.mockResponse.Err) - pd, _, _ := newPublicDashboardServiceImpl(t, testDB, cfg, store, dashboardService, nil) - pd.ac = ac - - got, err := pd.FindAllWithPagination(tt.args.ctx, tt.args.query) - if !tt.wantErr(t, err, fmt.Sprintf("FindAllWithPagination(%v, %v)", tt.args.ctx, tt.args.query)) { - return - } - assert.Equalf(t, tt.want, got, "FindAllWithPagination(%v, %v)", tt.args.ctx, tt.args.query) - }) - } -} - func TestPublicDashboardServiceImpl_NewPublicDashboardUid(t *testing.T) { mockedDashboard := &PublicDashboard{ IsEnabled: true, diff --git a/pkg/tests/api/publicdashboards/public_dashboard_query_test.go b/pkg/tests/api/publicdashboards/public_dashboard_query_test.go new file mode 100644 index 00000000000..7f12940c705 --- /dev/null +++ b/pkg/tests/api/publicdashboards/public_dashboard_query_test.go @@ -0,0 +1,195 @@ +package publicdashboards + +import ( + "encoding/json" + "fmt" + "net/http" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/grafana/grafana/pkg/services/featuremgmt" + "github.com/grafana/grafana/pkg/services/org" + "github.com/grafana/grafana/pkg/services/user" + "github.com/grafana/grafana/pkg/tests" + "github.com/grafana/grafana/pkg/tests/testinfra" +) + +func TestPublicDashboardQueryAPI(t *testing.T) { + dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ + AppModeProduction: false, + EnableFeatureToggles: []string{ + featuremgmt.FlagPublicDashboardsEmailSharing, + }, + }) + + grafanaListedAddr, env := testinfra.StartGrafanaEnv(t, dir, path) + adminUsername := fmt.Sprintf("testadmin-%d", time.Now().UnixNano()) + tests.CreateUser(t, env.SQLStore, env.Cfg, user.CreateUserCommand{ + DefaultOrgRole: string(org.RoleAdmin), + Login: adminUsername, + Password: "admin", + IsAdmin: true, + }) + adminClient := createHTTPClient(grafanaListedAddr, adminUsername, "admin") + + datasourcePayload := map[string]interface{}{ + "name": "Test Data Source", + "type": "prometheus", + "uid": "prometheus", + "url": "http://localhost:9090", + "access": "proxy", + } + datasourceBytes, err := json.Marshal(datasourcePayload) + require.NoError(t, err) + var datasourceResult map[string]interface{} + createDatasourceResp := doRequest(t, adminClient, "POST", "/api/datasources", datasourceBytes, &datasourceResult) + require.Equal(t, 200, createDatasourceResp.StatusCode) + + t.Run("unauthenticated user can query public dashboard panel", func(t *testing.T) { + // create dashboard first + dashboardPayload := map[string]interface{}{ + "dashboard": map[string]interface{}{ + "title": "Test Dashboard for Query", + "time": map[string]interface{}{ + "from": "now-1h", + "to": "now", + }, + "panels": []map[string]interface{}{ + { + "id": 1, + "type": "stat", + "title": "Test Panel", + "targets": []map[string]interface{}{ + { + "refId": "A", + "expr": "up", + "datasource": map[string]interface{}{ + "type": "prometheus", + "uid": "prometheus", + }, + }, + }, + }, + }, + }, + "folderUid": "", + "overwrite": false, + } + payloadBytes, err := json.Marshal(dashboardPayload) + require.NoError(t, err) + var dashboardResult map[string]interface{} + createDashboardResp := doRequest(t, adminClient, "POST", "/api/dashboards/db", payloadBytes, &dashboardResult) + require.Equal(t, 200, createDashboardResp.StatusCode) + + // make it public + dashboardUID := dashboardResult["uid"].(string) + publicDashboardPayload := map[string]interface{}{ + "isEnabled": true, + "annotationsEnabled": false, + "timeSelectionEnabled": false, + "share": "public", + } + payloadBytes, err = json.Marshal(publicDashboardPayload) + require.NoError(t, err) + createURL := fmt.Sprintf("/api/dashboards/uid/%s/public-dashboards", dashboardUID) + var publicDashboard map[string]interface{} + createResp := doRequest(t, adminClient, "POST", createURL, payloadBytes, &publicDashboard) + require.Equal(t, 200, createResp.StatusCode) + assert.Equal(t, true, publicDashboard["isEnabled"]) + assert.NotEmpty(t, publicDashboard["accessToken"]) + + // test unauthenticated query to the public dashboard panel + accessToken := publicDashboard["accessToken"].(string) + queryPayload := map[string]interface{}{} + queryBytes, err := json.Marshal(queryPayload) + require.NoError(t, err) + queryURL := fmt.Sprintf("/api/public/dashboards/%s/panels/1/query", accessToken) + unauthenticatedClient := createUnauthenticatedClient(grafanaListedAddr) + + var queryResult map[string]interface{} + doRequest(t, unauthenticatedClient, "POST", queryURL, queryBytes, &queryResult) + assert.NotNil(t, queryResult["results"]) + results := queryResult["results"].(map[string]interface{}) + assert.NotNil(t, results["A"]) + }) + + t.Run("unauthenticated user cannot query disabled public dashboard", func(t *testing.T) { + // create the dashboard + dashboardPayload := map[string]interface{}{ + "dashboard": map[string]interface{}{ + "title": "Test Disabled Dashboard", + "time": map[string]interface{}{ + "from": "now-1h", + "to": "now", + }, + "panels": []map[string]interface{}{ + { + "id": 1, + "type": "stat", + "title": "Test Panel", + }, + }, + }, + "folderUid": "", + "overwrite": false, + } + payloadBytes, err := json.Marshal(dashboardPayload) + require.NoError(t, err) + var dashboardResult map[string]interface{} + createDashboardResp := doRequest(t, adminClient, "POST", "/api/dashboards/db", payloadBytes, &dashboardResult) + require.Equal(t, 200, createDashboardResp.StatusCode) + + // make it a disabled public dashboard + dashboardUID := dashboardResult["uid"].(string) + publicDashboardPayload := map[string]interface{}{ + "isEnabled": false, + "annotationsEnabled": false, + "timeSelectionEnabled": true, + "share": "public", + } + payloadBytes, err = json.Marshal(publicDashboardPayload) + require.NoError(t, err) + createURL := fmt.Sprintf("/api/dashboards/uid/%s/public-dashboards", dashboardUID) + var publicDashboard map[string]interface{} + createResp := doRequest(t, adminClient, "POST", createURL, payloadBytes, &publicDashboard) + require.Equal(t, 200, createResp.StatusCode) + assert.Equal(t, false, publicDashboard["isEnabled"]) + assert.NotEmpty(t, publicDashboard["accessToken"]) + + accessToken := publicDashboard["accessToken"].(string) + + queryPayload := map[string]interface{}{ + "intervalMs": 1000, + "maxDataPoints": 100, + "timeRange": map[string]interface{}{ + "from": "now-1h", + "to": "now", + }, + } + queryBytes, err := json.Marshal(queryPayload) + require.NoError(t, err) + + // should not be able to query anymore + queryURL := fmt.Sprintf("/api/public/dashboards/%s/panels/1/query", accessToken) + unauthenticatedClient := createUnauthenticatedClient(grafanaListedAddr) + var queryResult map[string]interface{} + queryResp := doRequest(t, unauthenticatedClient, "POST", queryURL, queryBytes, &queryResult) + require.Equal(t, 403, queryResp.StatusCode) + require.Nil(t, queryResult["results"]) + }) +} + +func createUnauthenticatedClient(host string) *httpClient { + baseURL := fmt.Sprintf("http://%s", host) + return &httpClient{ + baseURL: baseURL, + client: &http.Client{ + CheckRedirect: func(req *http.Request, via []*http.Request) error { + return http.ErrUseLastResponse + }, + }, + } +} diff --git a/pkg/tests/api/publicdashboards/public_dashboards_api_test.go b/pkg/tests/api/publicdashboards/public_dashboards_api_test.go new file mode 100644 index 00000000000..d4a97e068a7 --- /dev/null +++ b/pkg/tests/api/publicdashboards/public_dashboards_api_test.go @@ -0,0 +1,439 @@ +package publicdashboards + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "net/http" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/grafana/grafana/pkg/services/featuremgmt" + "github.com/grafana/grafana/pkg/services/org" + "github.com/grafana/grafana/pkg/services/user" + "github.com/grafana/grafana/pkg/tests" + "github.com/grafana/grafana/pkg/tests/testinfra" + "github.com/grafana/grafana/pkg/tests/testsuite" +) + +func TestMain(m *testing.M) { + testsuite.Run(m) +} + +func TestPublicDashboardsAPI(t *testing.T) { + dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ + AppModeProduction: false, + EnableFeatureToggles: []string{ + featuremgmt.FlagPublicDashboardsEmailSharing, + }, + }) + + grafanaListedAddr, env := testinfra.StartGrafanaEnv(t, dir, path) + adminUsername := fmt.Sprintf("testadmin-%d", time.Now().UnixNano()) + tests.CreateUser(t, env.SQLStore, env.Cfg, user.CreateUserCommand{ + DefaultOrgRole: string(org.RoleAdmin), + Login: adminUsername, + Password: "admin", + IsAdmin: true, + }) + adminClient := createHTTPClient(grafanaListedAddr, adminUsername, "admin") + + t.Run("should create, get, update, and delete public dashboard", func(t *testing.T) { + dashboardPayload := map[string]interface{}{ + "dashboard": map[string]interface{}{ + "title": "Test Dashboard", + "panels": []map[string]interface{}{ + { + "id": 1, + "type": "stat", + "title": "Test Panel", + }, + }, + }, + "folderUid": "", + "overwrite": false, + } + + payloadBytes, err := json.Marshal(dashboardPayload) + require.NoError(t, err) + + var dashboardResult map[string]interface{} + createDashboardResp := doRequest(t, adminClient, "POST", "/api/dashboards/db", payloadBytes, &dashboardResult) + require.Equal(t, 200, createDashboardResp.StatusCode) + + dashboardUID := dashboardResult["uid"].(string) + + var listResult map[string]interface{} + doRequest(t, adminClient, "GET", "/api/dashboards/public-dashboards", nil, &listResult) + publicDashboardPayload := map[string]interface{}{ + "isEnabled": true, + "annotationsEnabled": false, + "timeSelectionEnabled": true, + "share": "public", + } + + payloadBytes, err = json.Marshal(publicDashboardPayload) + require.NoError(t, err) + + createURL := fmt.Sprintf("/api/dashboards/uid/%s/public-dashboards", dashboardUID) + var publicDashboard map[string]interface{} + createResp := doRequest(t, adminClient, "POST", createURL, payloadBytes, &publicDashboard) + require.Equal(t, 200, createResp.StatusCode) + assert.Equal(t, true, publicDashboard["isEnabled"]) + assert.Equal(t, false, publicDashboard["annotationsEnabled"]) + assert.Equal(t, true, publicDashboard["timeSelectionEnabled"]) + assert.Equal(t, "public", publicDashboard["share"]) + assert.NotEmpty(t, publicDashboard["accessToken"]) + assert.NotEmpty(t, publicDashboard["uid"]) + + accessToken := publicDashboard["accessToken"].(string) + publicDashboardUID := publicDashboard["uid"].(string) + + // get the public dashboard + getURL := fmt.Sprintf("/api/dashboards/uid/%s/public-dashboards", dashboardUID) + var retrievedPD map[string]interface{} + getResp := doRequest(t, adminClient, "GET", getURL, nil, &retrievedPD) + require.Equal(t, 200, getResp.StatusCode) + + // view the public dashboard + viewURL := fmt.Sprintf("/api/public/dashboards/%s", accessToken) + var dashboardData map[string]interface{} + viewResp := doRequest(t, adminClient, "GET", viewURL, nil, &dashboardData) + require.Equal(t, 200, viewResp.StatusCode) + assert.Equal(t, "Test Dashboard", dashboardData["dashboard"].(map[string]interface{})["title"]) + assert.Equal(t, "Test Panel", dashboardData["dashboard"].(map[string]interface{})["panels"].([]interface{})[0].(map[string]interface{})["title"]) + + updatePayload := map[string]interface{}{ + "isEnabled": false, + "annotationsEnabled": true, + "timeSelectionEnabled": false, + "share": "email", + } + updateBytes, err := json.Marshal(updatePayload) + require.NoError(t, err) + updateURL := fmt.Sprintf("/api/dashboards/uid/%s/public-dashboards/%s", dashboardUID, publicDashboardUID) + var updatedPD map[string]interface{} + updateResp := doRequest(t, adminClient, "PATCH", updateURL, updateBytes, &updatedPD) + require.Equal(t, 200, updateResp.StatusCode) + assert.Equal(t, false, updatedPD["isEnabled"]) + assert.Equal(t, true, updatedPD["annotationsEnabled"]) + assert.Equal(t, false, updatedPD["timeSelectionEnabled"]) + assert.Equal(t, "email", updatedPD["share"]) + + deleteURL := fmt.Sprintf("/api/dashboards/uid/%s/public-dashboards/%s", dashboardUID, publicDashboardUID) + var deleteResult map[string]interface{} + deleteResp := doRequest(t, adminClient, "DELETE", deleteURL, nil, &deleteResult) + require.Equal(t, 200, deleteResp.StatusCode) + var getAfterDeleteResult map[string]interface{} + getAfterDeleteResp := doRequest(t, adminClient, "GET", getURL, nil, &getAfterDeleteResult) + require.Equal(t, 404, getAfterDeleteResp.StatusCode) + }) + + t.Run("should list public dashboards", func(t *testing.T) { + dashboardPayload := map[string]interface{}{ + "dashboard": map[string]interface{}{ + "title": "Test Dashboard for List", + "panels": []map[string]interface{}{ + { + "id": 1, + "type": "stat", + "title": "Test Panel", + }, + }, + }, + "folderUid": "", + "overwrite": false, + } + + payloadBytes, err := json.Marshal(dashboardPayload) + require.NoError(t, err) + + var dashboardResult map[string]interface{} + createDashboardResp := doRequest(t, adminClient, "POST", "/api/dashboards/db", payloadBytes, &dashboardResult) + require.Equal(t, 200, createDashboardResp.StatusCode) + dashboardUID := dashboardResult["uid"].(string) + + publicDashboardPayload := map[string]interface{}{ + "isEnabled": true, + "annotationsEnabled": false, + "timeSelectionEnabled": true, + "share": "public", + } + + payloadBytes, err = json.Marshal(publicDashboardPayload) + require.NoError(t, err) + + createURL := fmt.Sprintf("/api/dashboards/uid/%s/public-dashboards", dashboardUID) + var createResult map[string]interface{} + createResp := doRequest(t, adminClient, "POST", createURL, payloadBytes, &createResult) + require.Equal(t, 200, createResp.StatusCode) + + var listData map[string]interface{} + listResp := doRequest(t, adminClient, "GET", "/api/dashboards/public-dashboards", nil, &listData) + require.Equal(t, 200, listResp.StatusCode) + assert.NotEmpty(t, listData["publicDashboards"]) + publicDashboards := listData["publicDashboards"].([]interface{}) + assert.GreaterOrEqual(t, len(publicDashboards), 1) + }) + + t.Run("should handle invalid access token", func(t *testing.T) { + var viewResult map[string]interface{} + viewResp := doRequest(t, adminClient, "GET", "/api/public/dashboards/invalid-token", nil, &viewResult) + require.Equal(t, 400, viewResp.StatusCode) + }) + + t.Run("should handle disabled public dashboard", func(t *testing.T) { + dashboardPayload := map[string]interface{}{ + "dashboard": map[string]interface{}{ + "title": "Test Dashboard Disabled", + "panels": []map[string]interface{}{ + { + "id": 1, + "type": "stat", + "title": "Test Panel", + }, + }, + }, + "folderUid": "", + "overwrite": false, + } + + payloadBytes, err := json.Marshal(dashboardPayload) + require.NoError(t, err) + + var dashboardResult map[string]interface{} + createDashboardResp := doRequest(t, adminClient, "POST", "/api/dashboards/db", payloadBytes, &dashboardResult) + require.Equal(t, 200, createDashboardResp.StatusCode) + + dashboardUID := dashboardResult["uid"].(string) + publicDashboardPayload := map[string]interface{}{ + "isEnabled": false, + "annotationsEnabled": false, + "timeSelectionEnabled": true, + "share": "public", + } + + payloadBytes, err = json.Marshal(publicDashboardPayload) + require.NoError(t, err) + + createURL := fmt.Sprintf("/api/dashboards/uid/%s/public-dashboards", dashboardUID) + var publicDashboard map[string]interface{} + createResp := doRequest(t, adminClient, "POST", createURL, payloadBytes, &publicDashboard) + require.Equal(t, 200, createResp.StatusCode) + accessToken := publicDashboard["accessToken"].(string) + + var viewResult map[string]interface{} + viewResp := doRequest(t, adminClient, "GET", fmt.Sprintf("/api/public/dashboards/%s", accessToken), nil, &viewResult) + require.Equal(t, 403, viewResp.StatusCode) + }) + + t.Run("permission test", func(t *testing.T) { + dashboards := []map[string]interface{}{ + { + "dashboard": map[string]interface{}{ + "title": "test", + "uid": "9S6TmO67z", + "panels": []map[string]interface{}{ + { + "id": 1, + "type": "stat", + "title": "Test Panel", + }, + }, + }, + "folderUid": "", + "overwrite": false, + }, + { + "dashboard": map[string]interface{}{ + "title": "my first dashboard", + "uid": "1S6TmO67z", + "panels": []map[string]interface{}{ + { + "id": 1, + "type": "stat", + "title": "Test Panel", + }, + }, + }, + "folderUid": "", + "overwrite": false, + }, + { + "dashboard": map[string]interface{}{ + "title": "my second dashboard", + "uid": "2S6TmO67z", + "panels": []map[string]interface{}{ + { + "id": 1, + "type": "stat", + "title": "Test Panel", + }, + }, + }, + "folderUid": "", + "overwrite": false, + }, + { + "dashboard": map[string]interface{}{ + "title": "my zero dashboard", + "uid": "0S6TmO67z", + "panels": []map[string]interface{}{ + { + "id": 1, + "type": "stat", + "title": "Test Panel", + }, + }, + }, + "folderUid": "", + "overwrite": false, + }, + } + + dashboardUIDs := make([]string, len(dashboards)) + publicDashboardUIDs := make([]string, len(dashboards)) + + for i, dashboardPayload := range dashboards { + payloadBytes, err := json.Marshal(dashboardPayload) + require.NoError(t, err) + + var dashboardResult map[string]interface{} + createDashboardResp := doRequest(t, adminClient, "POST", "/api/dashboards/db", payloadBytes, &dashboardResult) + require.Equal(t, 200, createDashboardResp.StatusCode) + dashboardUIDs[i] = dashboardResult["uid"].(string) + + isEnabled := i != 1 + publicDashboardPayload := map[string]interface{}{ + "isEnabled": isEnabled, + "annotationsEnabled": false, + "timeSelectionEnabled": true, + "share": "public", + } + + payloadBytes, err = json.Marshal(publicDashboardPayload) + require.NoError(t, err) + + createURL := fmt.Sprintf("/api/dashboards/uid/%s/public-dashboards", dashboardUIDs[i]) + var publicDashboard map[string]interface{} + createResp := doRequest(t, adminClient, "POST", createURL, payloadBytes, &publicDashboard) + require.Equal(t, 200, createResp.StatusCode) + publicDashboardUIDs[i] = publicDashboard["uid"].(string) + } + + t.Run("admin user should see all dashboards", func(t *testing.T) { + var listData map[string]interface{} + listResp := doRequest(t, adminClient, "GET", "/api/dashboards/public-dashboards?page=1&perpage=50", nil, &listData) + require.Equal(t, 200, listResp.StatusCode) + + totalCount := int64(listData["totalCount"].(float64)) + assert.GreaterOrEqual(t, totalCount, int64(4)) + }) + + t.Run("user with access to just one dashboard should see only that dashboard", func(t *testing.T) { + limitedUserUsername := fmt.Sprintf("limiteduser-%d", time.Now().UnixNano()) + limitedUserID := tests.CreateUser(t, env.SQLStore, env.Cfg, user.CreateUserCommand{ + DefaultOrgRole: string(org.RoleNone), + Login: limitedUserUsername, + Password: "password", + IsAdmin: false, + }) + limitedUserClient := createHTTPClient(grafanaListedAddr, limitedUserUsername, "password") + permissionPayload := map[string]interface{}{ + "permission": "View", + } + permissionBytes, err := json.Marshal(permissionPayload) + require.NoError(t, err) + + permissionURL := fmt.Sprintf("/api/access-control/dashboards/9S6TmO67z/users/%d", limitedUserID) + var permissionResult map[string]interface{} + permissionResp := doRequest(t, adminClient, "POST", permissionURL, permissionBytes, &permissionResult) + require.Equal(t, 200, permissionResp.StatusCode) + + var listData map[string]interface{} + listResp := doRequest(t, limitedUserClient, "GET", "/api/dashboards/public-dashboards?page=1&perpage=50", nil, &listData) + require.Equal(t, 200, listResp.StatusCode) + + totalCount := int64(listData["totalCount"].(float64)) + assert.Equal(t, int64(1), totalCount) + }) + + t.Run("pagination should work correctly", func(t *testing.T) { + var listData map[string]interface{} + listResp := doRequest(t, adminClient, "GET", "/api/dashboards/public-dashboards?page=1&perpage=2", nil, &listData) + require.Equal(t, 200, listResp.StatusCode) + assert.NotEmpty(t, listData["publicDashboards"]) + publicDashboards := listData["publicDashboards"].([]interface{}) + assert.Equal(t, 2, len(publicDashboards)) + totalCount := int64(listData["totalCount"].(float64)) + assert.GreaterOrEqual(t, totalCount, int64(4)) + + var listDataPage2 map[string]interface{} + listRespPage2 := doRequest(t, adminClient, "GET", "/api/dashboards/public-dashboards?page=2&perpage=2", nil, &listDataPage2) + require.Equal(t, 200, listRespPage2.StatusCode) + publicDashboardsPage2 := listDataPage2["publicDashboards"].([]interface{}) + assert.Equal(t, 2, len(publicDashboardsPage2)) + }) + }) +} + +type httpClient struct { + baseURL string + client *http.Client +} + +func createHTTPClient(host, username, password string) *httpClient { + baseURL := fmt.Sprintf("http://%s:%s@%s", username, password, host) + return &httpClient{ + baseURL: baseURL, + client: &http.Client{ + CheckRedirect: func(req *http.Request, via []*http.Request) error { + return http.ErrUseLastResponse + }, + }, + } +} + +type httpResponse struct { + StatusCode int + Body []byte +} + +func doRequest(t *testing.T, client *httpClient, method, path string, body []byte, result interface{}) httpResponse { + t.Helper() + + var req *http.Request + var err error + + url := client.baseURL + path + if body != nil { + req, err = http.NewRequest(method, url, bytes.NewReader(body)) + req.Header.Set("Content-Type", "application/json") + } else { + req, err = http.NewRequest(method, url, nil) + } + require.NoError(t, err) + + resp, err := client.client.Do(req) + require.NoError(t, err) + defer resp.Body.Close() // nolint:errcheck + + respBody, err := io.ReadAll(resp.Body) + require.NoError(t, err) + + response := httpResponse{ + StatusCode: resp.StatusCode, + Body: respBody, + } + + if result != nil && len(respBody) > 0 { + err = json.Unmarshal(respBody, result) + require.NoError(t, err) + } + + return response +} From 8b940f210f3913078a01366c05a57f835b4ae6fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Farkas?= Date: Mon, 28 Jul 2025 19:58:11 +0200 Subject: [PATCH 067/131] datasources: querier: temporary concurrency fix (#108503) --- pkg/services/query/query.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/services/query/query.go b/pkg/services/query/query.go index e2c3f68043d..73612d41f22 100644 --- a/pkg/services/query/query.go +++ b/pkg/services/query/query.go @@ -223,6 +223,7 @@ func QueryData(ctx context.Context, log log.Logger, dscache datasources.CacheSer dataSourceRequestValidator: validations.ProvideValidator(), mtDatasourceClientBuilder: mtDatasourceClientBuilder, headers: headers, + concurrentQueryLimit: 16, // TODO: make it configurable } return s.QueryData(ctx, nil, false, reqDTO) } From 4b9e03e7c07d70c62c5cadba3a73c94e1268a8df Mon Sep 17 00:00:00 2001 From: Paul Marbach Date: Mon, 28 Jul 2025 17:03:55 -0400 Subject: [PATCH 068/131] TableNG: Simplify row height calculation and make more extensible (#108624) * TableNG: Simplify row height calculation and make more extensible * add a cache for the results of rowHeight when it's a function * JSDoc comment for util * from the other branch, copy the related code and tests * rework the line counters a bit, limit line counting to string fields * add test for string case for buildRowLineCounters * add the concept of estimates vs. counts * add a comment * ceil, not floor * try to be as terse as possible * test for estimates * comment the type * more comment in test * swap * fix #108804 * convert em letter spacing to px for avgCharWidth calculation * tweak whee em-to-px math happens, and force count to occur on every row when wrap is on to avoid short row issues * update test * update to clamp single-line estimation using a hardcoded value (0.85) * add assertion for not calling counter in that case * uwrap 0.1.2 * fix betterer issues * fix typography ctx extra import --------- Co-authored-by: Leon Sorokin --- packages/grafana-ui/package.json | 2 +- .../Table/TableNG/Cells/ImageCell.tsx | 7 +- .../src/components/Table/TableNG/TableNG.tsx | 53 ++- .../src/components/Table/TableNG/constants.ts | 4 +- .../components/Table/TableNG/hooks.test.ts | 285 ++++++++++-- .../src/components/Table/TableNG/hooks.ts | 178 ++------ .../src/components/Table/TableNG/types.ts | 26 ++ .../components/Table/TableNG/utils.test.ts | 409 ++++++++++++++---- .../src/components/Table/TableNG/utils.ts | 218 ++++++++-- yarn.lock | 10 +- 10 files changed, 853 insertions(+), 339 deletions(-) diff --git a/packages/grafana-ui/package.json b/packages/grafana-ui/package.json index 553dd3b8fa7..8738aab4d7c 100644 --- a/packages/grafana-ui/package.json +++ b/packages/grafana-ui/package.json @@ -131,7 +131,7 @@ "tslib": "2.8.1", "uplot": "1.6.32", "uuid": "11.1.0", - "uwrap": "0.1.1" + "uwrap": "0.1.2" }, "devDependencies": { "@babel/core": "7.28.0", diff --git a/packages/grafana-ui/src/components/Table/TableNG/Cells/ImageCell.tsx b/packages/grafana-ui/src/components/Table/TableNG/Cells/ImageCell.tsx index 9953ef0948e..a9fd4420ff3 100644 --- a/packages/grafana-ui/src/components/Table/TableNG/Cells/ImageCell.tsx +++ b/packages/grafana-ui/src/components/Table/TableNG/Cells/ImageCell.tsx @@ -8,11 +8,8 @@ import { TableCellDisplayMode } from '../../types'; import { MaybeWrapWithLink } from '../MaybeWrapWithLink'; import { ImageCellProps } from '../types'; -const DATALINKS_HEIGHT_OFFSET = 10; - export const ImageCell = ({ cellOptions, field, height, justifyContent, value, rowIdx }: ImageCellProps) => { - const calculatedHeight = height - DATALINKS_HEIGHT_OFFSET; - const styles = useStyles2(getStyles, calculatedHeight, justifyContent); + const styles = useStyles2(getStyles, height, justifyContent); const { text } = field.display!(value); const { alt, title } = @@ -27,7 +24,7 @@ export const ImageCell = ({ cellOptions, field, height, justifyContent, value, r ); }; -const getStyles = (theme: GrafanaTheme2, height: number, justifyContent: Property.JustifyContent) => ({ +const getStyles = (_theme: GrafanaTheme2, height: number, justifyContent: Property.JustifyContent) => ({ image: css({ height, width: 'auto', diff --git a/packages/grafana-ui/src/components/Table/TableNG/TableNG.tsx b/packages/grafana-ui/src/components/Table/TableNG/TableNG.tsx index c84fb2d4194..40cd49278d3 100644 --- a/packages/grafana-ui/src/components/Table/TableNG/TableNG.tsx +++ b/packages/grafana-ui/src/components/Table/TableNG/TableNG.tsx @@ -26,7 +26,7 @@ import { ReducerID, } from '@grafana/data'; import { t, Trans } from '@grafana/i18n'; -import { FieldColorModeId, TableCellHeight } from '@grafana/schema'; +import { FieldColorModeId } from '@grafana/schema'; import { useStyles2, useTheme2 } from '../../../themes/ThemeContext'; import { ContextMenu } from '../../ContextMenu/ContextMenu'; @@ -52,29 +52,30 @@ import { useRowHeight, useScrollbarWidth, useSortedRows, - useTypographyCtx, } from './hooks'; import { TableNGProps, TableRow, TableSummaryRow, TableColumn, ContextMenuProps } from './types'; import { + applySort, + computeColWidths, + createTypographyContext, + displayJsonValue, + extractPixelValue, frameToRecords, + getAlignment, + getApplyToRowBgFn, + getCellColors, + getCellLinks, + getCellOptions, getDefaultRowHeight, getDisplayName, getIsNestedTable, - getVisibleFields, - shouldTextOverflow, - getApplyToRowBgFn, - computeColWidths, - applySort, - getCellColors, - getCellOptions, - shouldTextWrap, - isCellInspectEnabled, - getCellLinks, - withDataLinksActionsTooltip, - displayJsonValue, - getAlignment, getJustifyContent, + getVisibleFields, + isCellInspectEnabled, + shouldTextOverflow, + shouldTextWrap, TextAlign, + withDataLinksActionsTooltip, } from './utils'; type CellRootRenderer = (key: React.Key, props: CellRendererProps) => React.ReactNode; @@ -160,7 +161,6 @@ export function TableNG(props: TableNGProps) { } = useSortedRows(filteredRows, data.fields, { hasNestedFrames, initialSortBy }); const defaultRowHeight = getDefaultRowHeight(theme, cellHeight); - const defaultHeaderHeight = getDefaultRowHeight(theme, TableCellHeight.Sm); const [isInspecting, setIsInspecting] = useState(false); const [expandedRows, setExpandedRows] = useState(() => new Set()); @@ -172,13 +172,20 @@ export function TableNG(props: TableNGProps) { () => (hasNestedFrames ? width - COLUMN.EXPANDER_WIDTH : width) - scrollbarWidth, [width, hasNestedFrames, scrollbarWidth] ); - const typographyCtx = useTypographyCtx(); + const typographyCtx = useMemo( + () => + createTypographyContext( + theme.typography.fontSize, + theme.typography.fontFamily, + extractPixelValue(theme.typography.body.letterSpacing!) * theme.typography.fontSize + ), + [theme] + ); const widths = useMemo(() => computeColWidths(visibleFields, availableWidth), [visibleFields, availableWidth]); const headerHeight = useHeaderHeight({ columnWidths: widths, fields: visibleFields, enabled: hasHeader, - defaultHeight: defaultHeaderHeight, sortColumns, showTypeIcons: showTypeIcons ?? false, typographyCtx, @@ -285,7 +292,6 @@ export function TableNG(props: TableNGProps) { }; let lastRowIdx = -1; - let _rowHeight = 0; // shared when whole row will be styled by a single cell's color let rowCellStyle: Partial = { color: undefined, @@ -381,7 +387,6 @@ export function TableNG(props: TableNGProps) { // meh, this should be cached by the renderRow() call? if (rowIdx !== lastRowIdx) { - _rowHeight = typeof rowHeight === 'function' ? rowHeight(props.row) : rowHeight; lastRowIdx = rowIdx; rowCellStyle.color = undefined; @@ -420,6 +425,9 @@ export function TableNG(props: TableNGProps) { const renderCellContent = (props: RenderCellProps): JSX.Element => { const rowIdx = props.row.__index; const value = props.row[props.column.key]; + // TODO: it would be nice to get rid of passing height down as a prop. but this value + // is cached so the cost of calling for every cell is low. + const height = typeof rowHeight === 'function' ? rowHeight(props.row) : rowHeight; const frame = data; return ( @@ -428,7 +436,7 @@ export function TableNG(props: TableNGProps) { cellOptions, frame, field, - height: _rowHeight, + height, justifyContent, rowIdx, theme, @@ -580,7 +588,7 @@ export function TableNG(props: TableNGProps) { {...commonDataGridProps} className={clsx(styles.grid, styles.gridNested)} headerRowClass={clsx(styles.headerRow, { [styles.displayNone]: !hasNestedHeaders })} - headerRowHeight={hasNestedHeaders ? defaultHeaderHeight : 0} + headerRowHeight={hasNestedHeaders ? TABLE.HEADER_HEIGHT : 0} columns={nestedColumns} rows={expandedRecords} renderers={{ renderRow, renderCell: renderCellRoot }} @@ -599,7 +607,6 @@ export function TableNG(props: TableNGProps) { crossFilterOrder, crossFilterRows, data, - defaultHeaderHeight, defaultRowHeight, enableSharedCrosshair, expandedRows, diff --git a/packages/grafana-ui/src/components/Table/TableNG/constants.ts b/packages/grafana-ui/src/components/Table/TableNG/constants.ts index 31a537136d2..7638dd98804 100644 --- a/packages/grafana-ui/src/components/Table/TableNG/constants.ts +++ b/packages/grafana-ui/src/components/Table/TableNG/constants.ts @@ -13,7 +13,9 @@ export const TABLE = { PAGINATION_LIMIT: 750, SCROLL_BAR_WIDTH: 8, SCROLL_BAR_MARGIN: 2, + FONT_SIZE: 14, LINE_HEIGHT: 22, + HEADER_HEIGHT: 28, NESTED_NO_DATA_HEIGHT: 60, - BORDER_RIGHT: 0.666667, + BORDER_RIGHT: 1, }; diff --git a/packages/grafana-ui/src/components/Table/TableNG/hooks.test.ts b/packages/grafana-ui/src/components/Table/TableNG/hooks.test.ts index 4df9128205a..f7a1a1b858a 100644 --- a/packages/grafana-ui/src/components/Table/TableNG/hooks.test.ts +++ b/packages/grafana-ui/src/components/Table/TableNG/hooks.test.ts @@ -1,23 +1,19 @@ import { act, renderHook } from '@testing-library/react'; -import { varPreLine } from 'uwrap'; import { cacheFieldDisplayNames, createDataFrame, Field, FieldType } from '@grafana/data'; +import { TableCellDisplayMode } from '@grafana/schema'; +import { TABLE } from './constants'; import { useFilteredRows, usePaginatedRows, useSortedRows, useFooterCalcs, useHeaderHeight, - useTypographyCtx, + useRowHeight, } from './hooks'; - -jest.mock('uwrap', () => ({ - // ...jest.requireActual('uwrap'), - varPreLine: jest.fn(() => ({ - count: jest.fn(() => 1), - })), -})); +import { TableRow } from './types'; +import { createTypographyContext } from './utils'; describe('TableNG hooks', () => { function setupData() { @@ -28,21 +24,21 @@ describe('TableNG hooks', () => { type: FieldType.string, display: (v) => ({ text: v as string, numeric: NaN }), config: {}, - values: [], + values: ['Alice', 'Bob', 'Charlie'], }, { name: 'age', type: FieldType.number, display: (v) => ({ text: (v as number).toString(), numeric: v as number }), config: {}, - values: [], + values: [30, 25, 35], }, { name: 'active', type: FieldType.boolean, display: (v) => ({ text: (v as boolean).toString(), numeric: NaN }), config: {}, - values: [], + values: [true, false, true], }, ]; @@ -149,7 +145,7 @@ describe('TableNG hooks', () => { height: 300, width: 800, enabled: false, - headerHeight: 28, + headerHeight: TABLE.HEADER_HEIGHT, footerHeight: 0, }) ); @@ -201,7 +197,7 @@ describe('TableNG hooks', () => { height: 140, width: 800, rowHeight: 10, - headerHeight: 28, + headerHeight: TABLE.HEADER_HEIGHT, footerHeight: 45, }) ); @@ -429,16 +425,16 @@ describe('TableNG hooks', () => { }); describe('useHeaderHeight', () => { + const typographyCtx = createTypographyContext(14, 'sans-serif'); + it('should return 0 when no header is present', () => { const { fields } = setupData(); const { result } = renderHook(() => { - const typographyCtx = useTypographyCtx(); return useHeaderHeight({ fields, columnWidths: [], enabled: false, typographyCtx, - defaultHeight: 28, sortColumns: [], }); }); @@ -448,31 +444,20 @@ describe('TableNG hooks', () => { it('should return the default height when wrap is disabled', () => { const { fields } = setupData(); const { result } = renderHook(() => { - const typographyCtx = useTypographyCtx(); return useHeaderHeight({ fields, columnWidths: [], enabled: true, typographyCtx, - defaultHeight: 28, sortColumns: [], }); }); - expect(result.current).toBe(22); + expect(result.current).toBe(28); }); it('should return the appropriate height for wrapped text', () => { - // Simulate 2 lines of text - jest.mocked(varPreLine).mockReturnValue({ - count: jest.fn(() => 2), - each: jest.fn(), - split: jest.fn(), - test: jest.fn(), - }); - const { fields } = setupData(); const { result } = renderHook(() => { - const typographyCtx = useTypographyCtx(); return useHeaderHeight({ fields: fields.map((field) => { if (field.name === 'name') { @@ -492,8 +477,7 @@ describe('TableNG hooks', () => { }), columnWidths: [100, 100, 100], enabled: true, - typographyCtx: { ...typographyCtx, avgCharWidth: 5 }, - defaultHeight: 28, + typographyCtx: { ...typographyCtx, avgCharWidth: 5, wrappedCount: jest.fn(() => 2) }, sortColumns: [], }); }); @@ -504,19 +488,9 @@ describe('TableNG hooks', () => { it('should calculate the available width for a header cell based on the icons rendered within it', () => { const countFn = jest.fn(() => 1); - // Simulate 2 lines of text - jest.mocked(varPreLine).mockReturnValue({ - count: countFn, - each: jest.fn(), - split: jest.fn(), - test: jest.fn(), - }); - const { fields } = setupData(); renderHook(() => { - const typographyCtx = useTypographyCtx(); - return useHeaderHeight({ fields: fields.map((field) => { if (field.name === 'name') { @@ -536,17 +510,15 @@ describe('TableNG hooks', () => { }), columnWidths: [100, 100, 100], enabled: true, - typographyCtx: { ...typographyCtx, avgCharWidth: 10 }, - defaultHeight: 28, + typographyCtx: { ...typographyCtx, wrappedCount: countFn }, sortColumns: [], showTypeIcons: false, }); }); - expect(countFn).toHaveBeenCalledWith('Longer name that needs wrapping', 87); + expect(countFn).toHaveBeenCalledWith('Longer name that needs wrapping', 86); renderHook(() => { - const typographyCtx = useTypographyCtx(); return useHeaderHeight({ fields: fields.map((field) => { if (field.name === 'name') { @@ -567,14 +539,233 @@ describe('TableNG hooks', () => { }), columnWidths: [100, 100, 100], enabled: true, - typographyCtx: { ...typographyCtx, avgCharWidth: 10 }, - defaultHeight: 28, + typographyCtx: { ...typographyCtx, wrappedCount: countFn }, sortColumns: [{ columnKey: 'Longer name that needs wrapping', direction: 'ASC' }], showTypeIcons: true, }); }); - expect(countFn).toHaveBeenCalledWith('Longer name that needs wrapping', 27); + expect(countFn).toHaveBeenCalledWith('Longer name that needs wrapping', 26); + }); + }); + + describe('useRowHeight', () => { + const typographyCtx = createTypographyContext(14, 'sans-serif'); + + it('returns the default height if there are no wrapped columns or nested frames', () => { + const { fields } = setupData(); + + const defaultHeight = 40; + + expect( + renderHook(() => { + return useRowHeight({ + fields, + columnWidths: [100, 100, 100], + defaultHeight, + typographyCtx: typographyCtx, + hasNestedFrames: false, + expandedRows: new Set(), + }); + }).result.current + ).toBe(defaultHeight); + }); + + describe('nested frames', () => { + it('returns 0 if the parent row is not expanded', () => { + const { fields } = setupData(); + + expect( + renderHook(() => { + const rowHeight = useRowHeight({ + fields: [ + { name: 'nested', type: FieldType.nestedFrames, values: [createDataFrame({ fields })], config: {} }, + ], + columnWidths: [100, 100, 100], + defaultHeight: 40, + typographyCtx: typographyCtx, + hasNestedFrames: true, + expandedRows: new Set(), + }); + if (typeof rowHeight !== 'function') { + throw new Error('Expected rowHeight to be a function'); + } + return rowHeight({ __depth: 1, data: createDataFrame({ fields }), __index: 0 }); + }).result.current + ).toBe(0); + }); + + it('returns a static height if there are no rows in the nested frame', () => { + const { fields } = setupData(); + + expect( + renderHook(() => { + const rowHeight = useRowHeight({ + fields: [ + { name: 'nested', type: FieldType.nestedFrames, values: [createDataFrame({ fields })], config: {} }, + ], + columnWidths: [100, 100, 100], + defaultHeight: 40, + typographyCtx: typographyCtx, + hasNestedFrames: true, + expandedRows: new Set([0]), + }); + if (typeof rowHeight !== 'function') { + throw new Error('Expected rowHeight to be a function'); + } + return rowHeight({ + __depth: 1, + data: undefined, + __index: 0, + }); + }).result.current + ).toBe(TABLE.NESTED_NO_DATA_HEIGHT + TABLE.CELL_PADDING * 2); + }); + + it('calculates the height to return based on the number of rows in the nested frame', () => { + const { fields } = setupData(); + + const defaultHeight = 40; + + expect( + renderHook(() => { + const rowHeight = useRowHeight({ + fields: [ + { name: 'nested', type: FieldType.nestedFrames, values: [createDataFrame({ fields })], config: {} }, + ], + columnWidths: [100, 100, 100], + defaultHeight, + typographyCtx: typographyCtx, + hasNestedFrames: true, + expandedRows: new Set([0]), + }); + if (typeof rowHeight !== 'function') { + throw new Error('Expected rowHeight to be a function'); + } + return rowHeight({ + __index: 0, + __depth: 1, + data: createDataFrame({ fields }), + }); + }).result.current + ).toBe(defaultHeight * 4 + TABLE.CELL_PADDING * 2); // 3 rows + header + padding + }); + + it('removes the header if configured', () => { + const { fields } = setupData(); + + const defaultHeight = 40; + + expect( + renderHook(() => { + const rowHeight = useRowHeight({ + fields: [ + { name: 'nested', type: FieldType.nestedFrames, values: [createDataFrame({ fields })], config: {} }, + ], + columnWidths: [100, 100, 100], + defaultHeight, + typographyCtx: typographyCtx, + hasNestedFrames: true, + expandedRows: new Set([0]), + }); + if (typeof rowHeight !== 'function') { + throw new Error('Expected rowHeight to be a function'); + } + return rowHeight({ + __index: 0, + __depth: 1, + data: createDataFrame({ fields, meta: { custom: { noHeader: true } } }), + }); + }).result.current + ).toBe(defaultHeight * 3 + TABLE.CELL_PADDING * 2); // 3 rows + padding (no header) + }); + }); + + // we test the lineCounters and getRowHeight directly to check that all of that + // math is working correctly. we mainly want to confirm here that the + // cache is clearing and that the local logic in this hook works. + describe('wrapped columns', () => { + let rows: TableRow[]; + let fieldsWithWrappedText: Field[]; + + beforeEach(() => { + const { fields, rows: _rows } = setupData(); + + rows = _rows; + fieldsWithWrappedText = fields.map((field) => { + if (field.name === 'name') { + return { + ...field, + name: 'Longer name that needs wrapping', + config: { + ...field.config, + custom: { + ...field.config?.custom, + cellOptions: { + cellType: TableCellDisplayMode.Auto, + wrapText: true, + }, + }, + }, + }; + } + return field; + }); + }); + + it('handles changes to default height on re-render', () => { + const { result, rerender } = renderHook( + ({ defaultHeight }) => { + const rowHeight = useRowHeight({ + fields: fieldsWithWrappedText, + columnWidths: [100, 100, 100], + defaultHeight, + typographyCtx: typographyCtx, + hasNestedFrames: false, + expandedRows: new Set(), + }); + if (typeof rowHeight !== 'function') { + throw new Error('Expected rowHeight to be a function'); + } + return rowHeight; + }, + { + initialProps: { defaultHeight: 40 }, + } + ); + + expect(result.current(rows[0])).toBe(40); + + // change the column widths + rerender({ defaultHeight: 50 }); + + expect(result.current(rows[0])).toBe(50); + }); + + it('adjusts the width of the columns based on the cell padding and border', () => { + fieldsWithWrappedText[0].values[0] = 'Annie Lennox'; + + const wrappedCountFn = jest.fn(() => 2); + const estimateLinesFn = jest.fn(() => 2); + const { result } = renderHook(() => { + const rowHeight = useRowHeight({ + fields: fieldsWithWrappedText, + columnWidths: [100, 100, 100], + defaultHeight: 40, + typographyCtx: { ...typographyCtx, wrappedCount: wrappedCountFn, estimateLines: estimateLinesFn }, + hasNestedFrames: false, + expandedRows: new Set(), + }); + if (typeof rowHeight !== 'function') { + throw new Error('Expected rowHeight to be a function'); + } + return rowHeight; + }); + + expect(result.current(rows[0])).toEqual(expect.any(Number)); + + expect(estimateLinesFn).toHaveBeenCalledWith('Annie Lennox', 100 - TABLE.CELL_PADDING * 2 - TABLE.BORDER_RIGHT); + }); }); }); }); diff --git a/packages/grafana-ui/src/components/Table/TableNG/hooks.ts b/packages/grafana-ui/src/components/Table/TableNG/hooks.ts index e5f30a68d27..70a790d9133 100644 --- a/packages/grafana-ui/src/components/Table/TableNG/hooks.ts +++ b/packages/grafana-ui/src/components/Table/TableNG/hooks.ts @@ -1,22 +1,20 @@ import { useState, useMemo, useEffect, useCallback, useRef, useLayoutEffect, RefObject } from 'react'; import { Column, DataGridHandle, DataGridProps, SortColumn } from 'react-data-grid'; -import { varPreLine } from 'uwrap'; import { Field, fieldReducers, FieldType, formattedValueToString, reduceField } from '@grafana/data'; -import { useTheme2 } from '../../../themes/ThemeContext'; -import { TableCellDisplayMode, TableColumnResizeActionCallback } from '../types'; +import { TableColumnResizeActionCallback } from '../types'; import { TABLE } from './constants'; -import { FilterType, TableFooterCalc, TableRow, TableSortByFieldState, TableSummaryRow } from './types'; +import { FilterType, TableFooterCalc, TableRow, TableSortByFieldState, TableSummaryRow, TypographyCtx } from './types'; import { getDisplayName, processNestedTableRows, applySort, - getCellOptions, getColumnTypes, - GetMaxWrapCellOptions, - getMaxWrapCell, + getRowHeight, + buildHeaderLineCounters, + buildRowLineCounters, } from './utils'; // Helper function to get displayed value @@ -314,49 +312,6 @@ export function useFooterCalcs( }, [fields, enabled, footerOptions, isCountRowsSet, rows]); } -interface TypographyCtx { - ctx: CanvasRenderingContext2D; - font: string; - avgCharWidth: number; - calcRowHeight: (text: string, cellWidth: number, defaultHeight: number) => number; -} - -export function useTypographyCtx(): TypographyCtx { - const theme = useTheme2(); - const typographyCtx = useMemo((): TypographyCtx => { - const font = `${theme.typography.fontSize}px ${theme.typography.fontFamily}`; - const canvas = document.createElement('canvas'); - const ctx = canvas.getContext('2d')!; - // set in grafana/data in createTypography.ts - const letterSpacing = 0.15; - - ctx.letterSpacing = `${letterSpacing}px`; - ctx.font = font; - const txt = - "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s"; - const txtWidth = ctx.measureText(txt).width; - const avgCharWidth = txtWidth / txt.length + letterSpacing; - const { count } = varPreLine(ctx); - - const calcRowHeight = (text: string, cellWidth: number, defaultHeight: number) => { - if (text === '') { - return defaultHeight; - } - const numLines = count(text, cellWidth); - const totalHeight = numLines * TABLE.LINE_HEIGHT + 2 * TABLE.CELL_PADDING; - return Math.max(totalHeight, defaultHeight); - }; - - return { - calcRowHeight, - ctx, - font, - avgCharWidth, - }; - }, [theme.typography.fontSize, theme.typography.fontFamily]); - return typographyCtx; -} - const ICON_WIDTH = 16; const ICON_GAP = 4; @@ -364,7 +319,6 @@ interface UseHeaderHeightOptions { enabled: boolean; fields: Field[]; columnWidths: number[]; - defaultHeight: number; sortColumns: SortColumn[]; typographyCtx: TypographyCtx; showTypeIcons?: boolean; @@ -374,12 +328,14 @@ export function useHeaderHeight({ fields, enabled, columnWidths, - defaultHeight, sortColumns, - typographyCtx: { calcRowHeight, avgCharWidth }, + typographyCtx, showTypeIcons = false, }: UseHeaderHeightOptions): number { const perIconSpace = ICON_WIDTH + ICON_GAP; + + const lineCounters = useMemo(() => buildHeaderLineCounters(fields, typographyCtx), [fields, typographyCtx]); + const columnAvailableWidths = useMemo( () => columnWidths.map((c, idx) => { @@ -396,46 +352,26 @@ export function useHeaderHeight({ if (showTypeIcons) { width -= perIconSpace; } - return Math.floor(width); + // sadly, the math for this is off by exactly 1 pixel. shrug. + return Math.floor(width) - 1; }), [fields, columnWidths, sortColumns, showTypeIcons, perIconSpace] ); - const [wrappedColHeaderIdxs, hasWrappedColHeaders] = useMemo(() => { - let hasWrappedColHeaders = false; - return [ - fields.map((field) => { - const wrapText = field.config?.custom?.wrapHeaderText ?? false; - if (wrapText) { - hasWrappedColHeaders = true; - } - return wrapText; - }), - hasWrappedColHeaders, - ]; - }, [fields]); - - const maxWrapCellOptions = useMemo( - () => ({ - colWidths: columnAvailableWidths, - avgCharWidth, - wrappedColIdxs: wrappedColHeaderIdxs, - }), - [columnAvailableWidths, avgCharWidth, wrappedColHeaderIdxs] - ); - - // TODO: is there a less clunky way to subtract the top padding value? const headerHeight = useMemo(() => { if (!enabled) { return 0; } - if (!hasWrappedColHeaders) { - return defaultHeight - TABLE.CELL_PADDING; - } - - const { text: maxLinesText, idx: maxLinesIdx } = getMaxWrapCell(fields, -1, maxWrapCellOptions); - return calcRowHeight(maxLinesText, columnAvailableWidths[maxLinesIdx], defaultHeight) - TABLE.CELL_PADDING; - }, [fields, enabled, hasWrappedColHeaders, maxWrapCellOptions, calcRowHeight, columnAvailableWidths, defaultHeight]); + return getRowHeight( + fields, + -1, + columnAvailableWidths, + TABLE.HEADER_HEIGHT, + lineCounters, + TABLE.LINE_HEIGHT, + TABLE.CELL_PADDING + ); + }, [fields, enabled, columnAvailableWidths, lineCounters]); return headerHeight; } @@ -455,42 +391,15 @@ export function useRowHeight({ hasNestedFrames, defaultHeight, expandedRows, - typographyCtx: { calcRowHeight, avgCharWidth }, + typographyCtx, }: UseRowHeightOptions): number | ((row: TableRow) => number) { - const [wrappedColIdxs, hasWrappedCols] = useMemo(() => { - let hasWrappedCols = false; - return [ - fields.map((field) => { - if (field.type !== FieldType.string) { - return false; - } + const lineCounters = useMemo(() => buildRowLineCounters(fields, typographyCtx), [fields, typographyCtx]); + const hasWrappedCols = useMemo(() => lineCounters?.length ?? 0 > 0, [lineCounters]); - const cellOptions = getCellOptions(field); - const wrapText = 'wrapText' in cellOptions && cellOptions.wrapText; - const type = cellOptions.type; - const result = !!wrapText && type !== TableCellDisplayMode.Image; - if (result === true) { - hasWrappedCols = true; - } - return result; - }), - hasWrappedCols, - ]; - }, [fields]); - - const colWidths = useMemo( - () => columnWidths.map((c) => c - 2 * TABLE.CELL_PADDING - TABLE.BORDER_RIGHT), - [columnWidths] - ); - - const maxWrapCellOptions = useMemo( - () => ({ - colWidths, - avgCharWidth, - wrappedColIdxs, - }), - [colWidths, avgCharWidth, wrappedColIdxs] - ); + const colWidths = useMemo(() => { + const columnWidthAffordance = 2 * TABLE.CELL_PADDING + TABLE.BORDER_RIGHT; + return columnWidths.map((c) => c - columnWidthAffordance); + }, [columnWidths]); const rowHeight = useMemo(() => { // row height is only complicated when there are nested frames or wrapped columns. @@ -498,6 +407,9 @@ export function useRowHeight({ return defaultHeight; } + // this cache should get blown away on resize, data refresh, updated fields, etc. + // caching by __index is ok because sorting does not modify the __index. + const cache: Array = Array(fields[0].values.length); return (row: TableRow) => { // nested rows if (row.__depth > 0) { @@ -512,23 +424,25 @@ export function useRowHeight({ } const nestedHeaderHeight = row.data?.meta?.custom?.noHeader ? 0 : defaultHeight; - return Math.max(defaultHeight, defaultHeight * rowCount + nestedHeaderHeight + TABLE.CELL_PADDING * 2); + return defaultHeight * rowCount + nestedHeaderHeight + TABLE.CELL_PADDING * 2; } // regular rows - const { text: maxLinesText, idx: maxLinesIdx } = getMaxWrapCell(fields, row.__index, maxWrapCellOptions); - return calcRowHeight(maxLinesText, colWidths[maxLinesIdx], defaultHeight); + let result = cache[row.__index]; + if (!result) { + result = cache[row.__index] = getRowHeight( + fields, + row.__index, + colWidths, + defaultHeight, + lineCounters, + TABLE.LINE_HEIGHT, + TABLE.CELL_PADDING * 2 + ); + } + return result; }; - }, [ - calcRowHeight, - defaultHeight, - expandedRows, - fields, - hasNestedFrames, - hasWrappedCols, - maxWrapCellOptions, - colWidths, - ]); + }, [hasNestedFrames, hasWrappedCols, defaultHeight, fields, colWidths, lineCounters, expandedRows]); return rowHeight; } diff --git a/packages/grafana-ui/src/components/Table/TableNG/types.ts b/packages/grafana-ui/src/components/Table/TableNG/types.ts index bee921c1c71..1d736974189 100644 --- a/packages/grafana-ui/src/components/Table/TableNG/types.ts +++ b/packages/grafana-ui/src/components/Table/TableNG/types.ts @@ -261,3 +261,29 @@ export interface ScrollPosition { x: number; y: number; } + +export interface TypographyCtx { + ctx: CanvasRenderingContext2D; + font: string; + avgCharWidth: number; + estimateLines: LineCounter; + wrappedCount: LineCounter; +} + +export type LineCounter = (value: unknown, width: number) => number; +export interface LineCounterEntry { + /** + * given a values and the available width, returns the line count for that value + */ + counter: LineCounter; + /** + * if getting an accurate line count is expensive, you can provide an estimate method + * which will be used when looping over the row. the counter method will only be invoked + * for the cell which is the maximum line count for the row. + */ + estimate?: LineCounter; + /** + * indicates which field indexes of the visible fields this line counter applies to. + */ + fieldIdxs: number[]; +} diff --git a/packages/grafana-ui/src/components/Table/TableNG/utils.test.ts b/packages/grafana-ui/src/components/Table/TableNG/utils.test.ts index f7bfcf2cc9d..e86de2a7009 100644 --- a/packages/grafana-ui/src/components/Table/TableNG/utils.test.ts +++ b/packages/grafana-ui/src/components/Table/TableNG/utils.test.ts @@ -16,7 +16,8 @@ import { BarGaugeDisplayMode, TableCellBackgroundDisplayMode, TableCellHeight } import { TableCellDisplayMode } from '../types'; -import { TABLE } from './constants'; +import { COLUMN, TABLE } from './constants'; +import { LineCounterEntry } from './types'; import { extractPixelValue, frameToRecords, @@ -31,8 +32,14 @@ import { getJustifyContent, migrateTableDisplayModeToCellOptions, getColumnTypes, - getMaxWrapCell, + computeColWidths, + getRowHeight, + buildRowLineCounters, + buildHeaderLineCounters, + getTextLineEstimator, + createTypographyContext, applySort, + SINGLE_LINE_ESTIMATE_THRESHOLD, } from './utils'; describe('TableNG utils', () => { @@ -975,117 +982,345 @@ describe('TableNG utils', () => { }); }); - describe('getMaxWrapCell', () => { - it('should return the maximum wrap cell length from field state', () => { - const field1: Field = { - name: 'field1', - type: FieldType.string, - config: {}, - values: ['beep boop', 'foo bar baz', 'lorem ipsum dolor sit amet'], - }; + describe('createTypographyCtx', () => { + // we can't test the effectiveness of this typography context in unit tests, only that it + // actually executed the JS correctly. If you called `count` with a sensible value and width, + // it wouldn't give you a very reasonable answer in Jest's DOM environment for some reason. + it('creates the context using uwrap', () => { + const ctx = createTypographyContext(14, 'sans-serif', 0.15); + expect(ctx).toEqual( + expect.objectContaining({ + font: '14px sans-serif', + ctx: expect.any(CanvasRenderingContext2D), + wrappedCount: expect.any(Function), + estimateLines: expect.any(Function), + avgCharWidth: expect.any(Number), + }) + ); + expect(ctx.wrappedCount('the quick brown fox jumps over the lazy dog', 100)).toEqual(expect.any(Number)); + expect(ctx.estimateLines('the quick brown fox jumps over the lazy dog', 100)).toEqual(expect.any(Number)); + }); + }); - const field2: Field = { - name: 'field2', - type: FieldType.string, - config: {}, - values: ['asdfasdf asdfasdf asdfasdf', 'asdf asdf asdf asdf asdf', ''], - }; + describe('getTextLineEstimator', () => { + const counter = getTextLineEstimator(10); - const field3: Field = { - name: 'field3', - type: FieldType.string, - config: {}, - values: ['foo', 'bar', 'baz'], - // No alignmentFactors in state - }; - - const fields = [field1, field2, field3]; - - const result = getMaxWrapCell(fields, 0, { - colWidths: [30, 50, 100], - avgCharWidth: 5, - wrappedColIdxs: [true, true, true], - }); - expect(result).toEqual({ - text: 'asdfasdf asdfasdf asdfasdf', - idx: 1, - numLines: 2.6, - }); + it('returns -1 if there are no strings or dashes within the string', () => { + expect(counter('asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdf', 5)).toBe(-1); }); - it('should take colWidths into account when calculating max wrap cell', () => { + it('calculates an approximate rendered height for the text based on the width and avgCharWidth', () => { + expect(counter('asdfas dfasdfasdf asdfasdfasdfa sdfasdfasdfasdf 23', 200)).toBe(2.5); + }); + }); + + describe('buildHeaderLineCounters', () => { + const ctx = { + font: '14px sans-serif', + ctx: {} as CanvasRenderingContext2D, + count: jest.fn(() => 2), + avgCharWidth: 7, + wrappedCount: jest.fn(() => 2), + estimateLines: jest.fn(() => 2), + }; + + it('returns an array of line counters for each column', () => { const fields: Field[] = [ + { name: 'Name', type: FieldType.string, values: [], config: { custom: { wrapHeaderText: true } } }, + { name: 'Age', type: FieldType.number, values: [], config: { custom: { wrapHeaderText: true } } }, + ]; + const counters = buildHeaderLineCounters(fields, ctx); + expect(counters![0].counter).toEqual(expect.any(Function)); + expect(counters![0].fieldIdxs).toEqual([0, 1]); + }); + + it('does not return the index of columns which are not wrapped', () => { + const fields: Field[] = [ + { name: 'Name', type: FieldType.string, values: [], config: { custom: {} } }, + { name: 'Age', type: FieldType.number, values: [], config: { custom: { wrapHeaderText: true } } }, + ]; + + const counters = buildHeaderLineCounters(fields, ctx); + expect(counters![0].fieldIdxs).toEqual([1]); + }); + + it('returns undefined if no columns are wrapped', () => { + const fields: Field[] = [ + { name: 'Name', type: FieldType.string, values: [], config: { custom: {} } }, + { name: 'Age', type: FieldType.number, values: [], config: { custom: {} } }, + ]; + + const counters = buildHeaderLineCounters(fields, ctx); + expect(counters).toBeUndefined(); + }); + }); + + describe('buildRowLineCounters', () => { + const ctx = { + font: '14px sans-serif', + ctx: {} as CanvasRenderingContext2D, + count: jest.fn(() => 2), + wrappedCount: jest.fn(() => 2), + estimateLines: jest.fn(() => 2), + avgCharWidth: 7, + }; + + it('returns an array of line counters for each column', () => { + const fields: Field[] = [ + { name: 'Name', type: FieldType.string, values: [], config: { custom: { cellOptions: { wrapText: true } } } }, { - name: 'field', + name: 'Address', type: FieldType.string, - config: {}, - values: ['short', 'a bit longer text'], + values: [], + config: { custom: { cellOptions: { wrapText: true } } }, }, + ]; + const counters = buildRowLineCounters(fields, ctx); + expect(counters![0].counter).toEqual(expect.any(Function)); + expect(counters![0].fieldIdxs).toEqual([0, 1]); + }); + + it('does not return the index of columns which are not wrapped', () => { + const fields: Field[] = [ + { name: 'Name', type: FieldType.string, values: [], config: { custom: {} } }, { - name: 'field', + name: 'Address', type: FieldType.string, - config: {}, - values: ['short', 'quite a bit longer text'], - }, - { - name: 'field', - type: FieldType.string, - config: {}, - values: ['short', 'less text'], + values: [], + config: { custom: { cellOptions: { wrapText: true } } }, }, ]; - // Simulate a narrow column width that would cause wrapping - const colWidths = [50, 1000, 30]; // 50px width - const avgCharWidth = 5; // Assume average character width is 5px - - const result = getMaxWrapCell(fields, 1, { colWidths, avgCharWidth, wrappedColIdxs: [true, true, true] }); - - // With a 50px width and 5px per character, we can fit 10 characters per line - // "the longest text in this field" has 31 characters, so it should wrap to 4 lines - expect(result).toEqual({ - idx: 0, - numLines: 1.7, - text: 'a bit longer text', - }); + const counters = buildRowLineCounters(fields, ctx); + expect(counters![0].fieldIdxs).toEqual([1]); }); - it('should use the display name if the rowIdx is -1 (which is used to calc header height in wrapped rows)', () => { + it('does not enable text counting for non-string fields', () => { const fields: Field[] = [ - { - name: 'Field with a very long name', - type: FieldType.string, - config: {}, - values: ['short', 'a bit longer text'], - }, + { name: 'Name', type: FieldType.string, values: [], config: { custom: {} } }, + { name: 'Age', type: FieldType.number, values: [], config: { custom: { cellOptions: { wrapText: true } } } }, + ]; + + const counters = buildRowLineCounters(fields, ctx); + // empty array - we had one column that indicated it wraps, but it was numeric, so we just ignore it + expect(counters).toEqual([]); + }); + + it('returns an undefined if no columns are wrapped', () => { + const fields: Field[] = [ + { name: 'Name', type: FieldType.string, values: [], config: { custom: {} } }, + { name: 'Age', type: FieldType.number, values: [], config: { custom: {} } }, + ]; + + const counters = buildRowLineCounters(fields, ctx); + expect(counters).toBeUndefined(); + }); + }); + + describe('getRowHeight', () => { + let fields: Field[]; + let counters: LineCounterEntry[]; + + beforeEach(() => { + fields = [ { name: 'Name', type: FieldType.string, - config: {}, - values: ['short', 'quite a bit longer text'], + values: ['foo', 'bar', 'baz', 'longer one here', 'shorter'], + config: { custom: { cellOptions: { wrapText: true } } }, }, { - name: 'Another field', - type: FieldType.string, - config: {}, - values: ['short', 'less text'], + name: 'Age', + type: FieldType.number, + values: [1, 2, 3, 123456, 789122349932], + config: { custom: { cellOptions: { wrapText: true } } }, }, ]; - - // Simulate a narrow column width that would cause wrapping - const colWidths = [50, 1000, 30]; // 50px width - const avgCharWidth = 5; // Assume average character width is 5px - - const result = getMaxWrapCell(fields, -1, { colWidths, avgCharWidth, wrappedColIdxs: [true, true, true] }); - - // With a 50px width and 5px per character, we can fit 10 characters per line - // "the longest text in this field" has 31 characters, so it should wrap to 4 lines - expect(result).toEqual({ idx: 0, numLines: 2.7, text: 'Field with a very long name' }); + counters = [ + { counter: jest.fn((value, _length: number) => String(value).split(' ').length), fieldIdxs: [0] }, // Mocked to count words as lines + { counter: jest.fn((value, _length: number) => Math.ceil(String(value).length / 3)), fieldIdxs: [1] }, // Mocked to return a line for every 3 digits of a number + ]; }); - it.todo('should ignore columns which are not wrapped'); + it('should use the default height for single-line rows', () => { + // 1 line @ 20px, 10px vertical padding = 30, minimum is 36 + expect(getRowHeight(fields, 0, [30, 30], 36, counters, 20, 10)).toBe(36); + }); - it.todo('should only apply wrapping on idiomatic break characters (space, -, etc)'); + it('should use the default height for multi-line rows which are shorter than the default height', () => { + // 3 lines @ 5px, 5px vertical padding = 20, minimum is 36 + expect(getRowHeight(fields, 3, [30, 30], 36, counters, 5, 5)).toBe(36); + }); + + it('should return the row height using line counters for multi-line', () => { + // 3 lines @ 20px ('longer', 'one', 'here'), 10px vertical padding + expect(getRowHeight(fields, 3, [30, 30], 36, counters, 20, 10)).toBe(70); + + // 4 lines @ 15px (789 122 349 932), 15px vertical padding + expect(getRowHeight(fields, 4, [30, 30], 36, counters, 15, 15)).toBe(75); + }); + + it('should take colWidths into account when calculating max wrap cell', () => { + getRowHeight(fields, 3, [50, 60], 36, counters, 20, 10); + expect(counters[0].counter).toHaveBeenCalledWith('longer one here', 50); + expect(counters[1].counter).toHaveBeenCalledWith(123456, 60); + }); + + // this is used to calc wrapped header height + it('should use the display name if the rowIdx is -1', () => { + getRowHeight(fields, -1, [50, 60], 36, counters, 20, 10); + expect(counters[0].counter).toHaveBeenCalledWith('Name', 50); + expect(counters[1].counter).toHaveBeenCalledWith('Age', 60); + }); + + it('should ignore columns which do not have line counters', () => { + const height = getRowHeight(fields, 3, [30, 30], 36, [counters[1]], 20, 10); + // 2 lines @ 20px, 10px vertical padding (not 3 lines, since we don't line count Name) + expect(height).toBe(50); + }); + + it('should return the default height if there are no counters to apply', () => { + const height = getRowHeight(fields, 3, [30, 30], 36, [], 20, 10); + expect(height).toBe(36); + }); + + describe('estimations vs. precise counts', () => { + beforeEach(() => { + counters = [ + { counter: jest.fn((value, _length: number) => String(value).split(' ').length), fieldIdxs: [0] }, // Mocked to count words as lines + { + estimate: jest.fn((value) => String(value).length), // Mocked to return a line for every digits of a number + counter: jest.fn((value, _length: number) => Math.ceil(String(value).length / 3)), + fieldIdxs: [1], + }, + ]; + }); + + // 2 lines @ 20px (123,456), 10px vertical padding. when we did this before, 'longer one here' would win, making it 70px. + // the `estimate` function is picking `123456` as the longer one now (6 lines), then the `counter` function is used + // to calculate the height (2 lines). this is a very forced case, but we just want to prove that it actually works. + it('uses the estimate value rather than the precise value to select the row height', () => { + expect(getRowHeight(fields, 3, [30, 30], 36, counters, 20, 10)).toBe(50); + }); + + it('returns doesnt bother getting the precise count if the estimates are all below the threshold', () => { + jest.mocked(counters[0].counter).mockReturnValue(SINGLE_LINE_ESTIMATE_THRESHOLD - 0.3); + jest.mocked(counters[1].estimate!).mockReturnValue(SINGLE_LINE_ESTIMATE_THRESHOLD - 0.1); + + expect(getRowHeight(fields, 3, [30, 30], 36, counters, 20, 10)).toBe(36); + + // this is what we really care about - we want to save on performance by not calling the counter in this case. + expect(counters[1].counter).not.toHaveBeenCalled(); + }); + + it('uses the precise count if the estimate is above the threshold, even if its below 1', () => { + // NOTE: if this fails, just change the test to use a different value besides 0.1 + expect(SINGLE_LINE_ESTIMATE_THRESHOLD + 0.1).toBeLessThan(1); + + jest.mocked(counters[0].counter).mockReturnValue(SINGLE_LINE_ESTIMATE_THRESHOLD - 0.3); + jest.mocked(counters[1].estimate!).mockReturnValue(SINGLE_LINE_ESTIMATE_THRESHOLD + 0.1); + + expect(getRowHeight(fields, 3, [30, 30], 36, counters, 20, 10)).toBe(50); + }); + }); + }); + + describe('computeColWidths', () => { + it('returns the configured widths if all columns set them', () => { + expect( + computeColWidths( + [ + { + name: 'A', + type: FieldType.string, + values: [], + config: { custom: { width: 100 } }, + }, + { + name: 'B', + type: FieldType.string, + values: [], + config: { custom: { width: 200 } }, + }, + ], + 500 + ) + ).toEqual([100, 200]); + }); + + it('fills the available space if a column has no width set', () => { + expect( + computeColWidths( + [ + { + name: 'A', + type: FieldType.string, + values: [], + config: {}, + }, + { + name: 'B', + type: FieldType.string, + values: [], + config: { custom: { width: 200 } }, + }, + ], + 500 + ) + ).toEqual([300, 200]); + }); + + it('applies minimum width when auto width would dip below it', () => { + expect( + computeColWidths( + [ + { + name: 'A', + type: FieldType.string, + values: [], + config: { custom: { minWidth: 100 } }, + }, + { + name: 'B', + type: FieldType.string, + values: [], + config: { custom: { minWidth: 100 } }, + }, + ], + 100 + ) + ).toEqual([100, 100]); + }); + + it('should use the global column default width when nothing is set', () => { + expect( + computeColWidths( + [ + { + name: 'A', + type: FieldType.string, + values: [], + config: {}, + }, + { + name: 'B', + type: FieldType.string, + values: [], + config: {}, + }, + ], + // we have two columns but have set the table to the width of one default column. + COLUMN.DEFAULT_WIDTH + ) + ).toEqual([COLUMN.DEFAULT_WIDTH, COLUMN.DEFAULT_WIDTH]); + }); + }); + + describe('displayJsonValue', () => { + it.todo('should parse and then stringify string values'); + it.todo('should not throw for non-serializable string values'); + it.todo('should stringify non-string values'); + it.todo('should not throw for non-serializable non-string values'); }); describe('applySort', () => { diff --git a/packages/grafana-ui/src/components/Table/TableNG/utils.ts b/packages/grafana-ui/src/components/Table/TableNG/utils.ts index 67f4bf497ed..a24a361bfda 100644 --- a/packages/grafana-ui/src/components/Table/TableNG/utils.ts +++ b/packages/grafana-ui/src/components/Table/TableNG/utils.ts @@ -1,6 +1,7 @@ import { Property } from 'csstype'; import { SortColumn } from 'react-data-grid'; import tinycolor from 'tinycolor2'; +import { Count, varPreLine } from 'uwrap'; import { FieldType, @@ -25,7 +26,16 @@ import { getTextColorForAlphaBackground } from '../../../utils/colors'; import { TableCellOptions } from '../types'; import { COLUMN, TABLE } from './constants'; -import { CellColors, TableRow, ColumnTypes, FrameToRowsConverter, Comparator } from './types'; +import { + CellColors, + TableRow, + ColumnTypes, + FrameToRowsConverter, + Comparator, + TypographyCtx, + LineCounter, + LineCounterEntry, +} from './types'; /* ---------------------------- Cell calculations --------------------------- */ export type CellNumLinesCalculator = (text: string, cellWidth: number) => number; @@ -71,58 +81,190 @@ export function shouldTextWrap(field: Field): boolean { return Boolean(cellOptions?.wrapText); } -// matches characters which CSS -const spaceRegex = /[\s-]/; +/** + * @internal creates a typography context based on a font size and family. used to measure text + * and estimate size of text in cells. + */ +export function createTypographyContext(fontSize: number, fontFamily: string, letterSpacing = 0.15): TypographyCtx { + const font = `${fontSize}px ${fontFamily}`; + const canvas = document.createElement('canvas'); + const ctx = canvas.getContext('2d')!; -export interface GetMaxWrapCellOptions { - colWidths: number[]; - avgCharWidth: number; - wrappedColIdxs: boolean[]; + ctx.letterSpacing = `${letterSpacing}px`; + ctx.font = font; + const txt = + "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s."; + const txtWidth = ctx.measureText(txt).width; + const avgCharWidth = txtWidth / txt.length + letterSpacing; + const { count } = varPreLine(ctx); + + return { + ctx, + font, + avgCharWidth, + estimateLines: getTextLineEstimator(avgCharWidth), + wrappedCount: wrapUwrapCount(count), + }; } /** * @internal - * loop through the fields and their values, determine which cell is going to determine the - * height of the row based on its content and width, and then return the text, index, and number of lines for that cell. */ -export function getMaxWrapCell( +export function wrapUwrapCount(count: Count): LineCounter { + return (value, width) => { + if (value == null) { + return 1; + } + + return count(String(value), width); + }; +} + +/** + * @internal returns a line counter which guesstimates a number of lines in a text cell based on the typography context's avgCharWidth. + */ +export function getTextLineEstimator(avgCharWidth: number): LineCounter { + return (value, width) => { + if (!value) { + return -1; + } + + // we don't have string breaking enabled in the table, + // so an unbroken string is by definition a single line. + const strValue = String(value); + if (!spaceRegex.test(strValue)) { + return -1; + } + + const charsPerLine = width / avgCharWidth; + return strValue.length / charsPerLine; + }; +} + +/** + * @internal return a text line counter for every field which has wrapHeaderText enabled. + */ +export function buildHeaderLineCounters(fields: Field[], typographyCtx: TypographyCtx): LineCounterEntry[] | undefined { + const wrappedColIdxs = fields.reduce((acc: number[], field, idx) => { + if (field.config?.custom?.wrapHeaderText) { + acc.push(idx); + } + return acc; + }, []); + + if (wrappedColIdxs.length === 0) { + return undefined; + } + + // don't bother with estimating the line counts for the headers, because it's punishing + // when we get it wrong and there won't be that many compared to how many rows a table might contain. + return [{ counter: typographyCtx.wrappedCount, fieldIdxs: wrappedColIdxs }]; +} + +const spaceRegex = /[\s-]/; + +/** + * @internal return a text line counter for every field which has wrapHeaderText enabled. we do this once as we're rendering + * the table, and then getRowHeight uses the output of this to caluclate the height of each row. + */ +export function buildRowLineCounters(fields: Field[], typographyCtx: TypographyCtx): LineCounterEntry[] | undefined { + const result: Record = {}; + let wrappedFields = 0; + + for (let fieldIdx = 0; fieldIdx < fields.length; fieldIdx++) { + const field = fields[fieldIdx]; + if (shouldTextWrap(field)) { + wrappedFields++; + // TODO: Pills, DataLinks, and JSON will have custom line counters here. + + // for string fields, we really want to find the longest field ahead of time to reduce the number of calls to `count`. + // calling `count` is going to get a perfectly accurate line count, but it is expensive, so we'd rather estimate the line + // count and call the counter only for the field which will take up the most space based on its + if (field.type === FieldType.string) { + result.textCounter = result.textCounter ?? { + counter: typographyCtx.wrappedCount, + estimate: typographyCtx.estimateLines, + fieldIdxs: [], + }; + result.textCounter.fieldIdxs.push(fieldIdx); + } + } + } + + if (wrappedFields === 0) { + return undefined; + } + + return Object.values(result); +} + +// in some cases, the estimator might return a value that is less than 1, but when measured by the counter, it actually +// realizes that it's a multi-line cell. to avoid this, we want to give a little buffer away from 1 before we fully trust +// the estimator to have told us that a cell is single-line. +export const SINGLE_LINE_ESTIMATE_THRESHOLD = 0.85; + +/** + * @internal + * loop through the fields and their values, determine which cell is going to determine the height of the row based + * on its content and width, and return the height in pixels of that row, with vertial padding applied. + */ +export function getRowHeight( fields: Field[], rowIdx: number, - { colWidths, avgCharWidth, wrappedColIdxs }: GetMaxWrapCellOptions -): { - text: string; - idx: number; - numLines: number; -} { - let maxLines = 1; - let maxLinesIdx = -1; - let maxLinesText = ''; + columnWidths: number[], + defaultHeight: number, + lineCounters?: LineCounterEntry[], + lineHeight = TABLE.LINE_HEIGHT, + verticalPadding = 0 +): number { + if (!lineCounters?.length) { + return defaultHeight; + } - // TODO: consider changing how we store this, using a record by column key instead of an array - for (let i = 0; i < colWidths.length; i++) { - if (wrappedColIdxs[i]) { - const field = fields[i]; + let maxLines = -1; + let maxValue = ''; + let maxWidth = 0; + let preciseCounter: LineCounter | undefined; + + for (const { estimate, counter, fieldIdxs } of lineCounters) { + // for some of the line counters, getting the precise count of the lines is expensive. those line counters + // set both an "estimate" and a "counter" function. if the cell we find to be the max was estimated, we will + // get the "true" value right before calculating the row height by hanging onto a reference to the counter fn. + const count = estimate ?? counter; + const isEstimating = estimate !== undefined; + + for (const fieldIdx of fieldIdxs) { + const field = fields[fieldIdx]; // special case: for the header, provide `-1` as the row index. - const cellTextRaw = rowIdx === -1 ? getDisplayName(field) : field.values[rowIdx]; - - if (cellTextRaw != null) { - const cellText = String(cellTextRaw); - - if (spaceRegex.test(cellText)) { - const charsPerLine = colWidths[i] / avgCharWidth; - const approxLines = cellText.length / charsPerLine; - - if (approxLines > maxLines) { - maxLines = approxLines; - maxLinesIdx = i; - maxLinesText = cellText; - } + const cellValueRaw = rowIdx === -1 ? getDisplayName(field) : field.values[rowIdx]; + if (cellValueRaw != null) { + const colWidth = columnWidths[fieldIdx]; + const approxLines = count(cellValueRaw, colWidth); + if (approxLines > maxLines) { + maxLines = approxLines; + maxValue = cellValueRaw; + maxWidth = colWidth; + preciseCounter = isEstimating ? counter : undefined; } } } } - return { text: maxLinesText, idx: maxLinesIdx, numLines: maxLines }; + // if the value is -1 or the estimate for the max cell was less than the SINGLE_LINE_ESTIMATE_THRESHOLD, we trust + // that the estimator correctly identified that no text wrapping is needed for this row, skipping the preciseCounter. + if (maxLines < SINGLE_LINE_ESTIMATE_THRESHOLD) { + return defaultHeight; + } + + // if we finished this row height loop with an estimate, we need to call + // the `preciseCounter` method to get the exact line count. + if (preciseCounter !== undefined) { + maxLines = preciseCounter(maxValue, maxWidth); + } + + // we want a round number of lines for rendering + const totalHeight = Math.ceil(maxLines) * lineHeight + verticalPadding; + return Math.max(totalHeight, defaultHeight); } /** diff --git a/yarn.lock b/yarn.lock index 9ac783e535e..897c95579e7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3869,7 +3869,7 @@ __metadata: typescript: "npm:5.8.3" uplot: "npm:1.6.32" uuid: "npm:11.1.0" - uwrap: "npm:0.1.1" + uwrap: "npm:0.1.2" webpack: "npm:5.97.1" peerDependencies: react: ^18.0.0 @@ -31787,10 +31787,10 @@ __metadata: languageName: node linkType: hard -"uwrap@npm:0.1.1": - version: 0.1.1 - resolution: "uwrap@npm:0.1.1" - checksum: 10/d5d02cb2f0e7fd997862913458d67e0c7fa9fd5bc1025baca9e183ac87046be9148942e59440fef8d01a34d5674c0395bb46b13e00359602ea3155b305466090 +"uwrap@npm:0.1.2": + version: 0.1.2 + resolution: "uwrap@npm:0.1.2" + checksum: 10/621d9d148d903410ef555739baca1ba84500d59a5028611bc2fca53313ffd6c9b870e25dc5cad73b41f18fe72879a3d94a6b8ebc5e141c84a94188ee1c483492 languageName: node linkType: hard From bee169d7a66f1338a108d8831385404366686af0 Mon Sep 17 00:00:00 2001 From: Drew Slobodnjak <60050885+drew08t@users.noreply.github.com> Date: Mon, 28 Jul 2025 14:06:33 -0700 Subject: [PATCH 069/131] Geomap: Add option to toggle no-repeating (#108201) * Geomap: Add option to toggle no-repeating * Add option and apply to all basemaps * Clean up some comments * Update docs * Add tests * Fix option change handling issues * Update translations * Fix e2e test --- .../visualizations/geomap/index.md | 8 ++ .../panels-suite/geomap-layer-types.spec.ts | 2 +- .../panelcfg/x/GeomapPanelCfg_types.gen.ts | 2 + .../grafana-schema/src/veneer/common.types.ts | 2 + .../app/plugins/panel/geomap/GeomapPanel.tsx | 62 ++++++++--- .../geomap/layers/basemaps/carto.test.ts | 103 ++++++++++++++++++ .../panel/geomap/layers/basemaps/carto.ts | 3 + .../geomap/layers/basemaps/generic.test.ts | 103 ++++++++++++++++++ .../panel/geomap/layers/basemaps/generic.ts | 3 + .../panel/geomap/layers/basemaps/osm.test.ts | 67 ++++++++++++ .../panel/geomap/layers/basemaps/osm.ts | 4 +- .../plugins/panel/geomap/migrations.test.ts | 27 +++++ public/app/plugins/panel/geomap/module.tsx | 8 ++ public/app/plugins/panel/geomap/panelcfg.cue | 1 + .../app/plugins/panel/geomap/panelcfg.gen.ts | 2 + public/locales/en-US/grafana.json | 2 + 16 files changed, 380 insertions(+), 19 deletions(-) create mode 100644 public/app/plugins/panel/geomap/layers/basemaps/carto.test.ts create mode 100644 public/app/plugins/panel/geomap/layers/basemaps/generic.test.ts create mode 100644 public/app/plugins/panel/geomap/layers/basemaps/osm.test.ts diff --git a/docs/sources/panels-visualizations/visualizations/geomap/index.md b/docs/sources/panels-visualizations/visualizations/geomap/index.md index fe8dbd11e65..3a10dea71d6 100644 --- a/docs/sources/panels-visualizations/visualizations/geomap/index.md +++ b/docs/sources/panels-visualizations/visualizations/geomap/index.md @@ -184,6 +184,14 @@ The **Share view** option allows you to link the movement and zoom actions of mu You might need to reload the dashboard for this feature to work. {{< /admonition >}} +#### No map repeating + +The **No map repeating** option prevents the base map tiles from repeating horizontally when you pan across the world. This constrains the view to a single instance of the world map and avoids visual confusion when displaying global datasets. + +{{< admonition type="note" >}} +Enabling this option requires the map to reinitialize. +{{< /admonition >}} + ### Map layers options Geomaps support showing multiple layers. Each layer determines how you visualize geospatial data on top of the base map. diff --git a/e2e/old-arch/panels-suite/geomap-layer-types.spec.ts b/e2e/old-arch/panels-suite/geomap-layer-types.spec.ts index 17779dde1c9..803e2e7042d 100644 --- a/e2e/old-arch/panels-suite/geomap-layer-types.spec.ts +++ b/e2e/old-arch/panels-suite/geomap-layer-types.spec.ts @@ -13,7 +13,7 @@ describe('Geomap layer types', () => { it('Tests changing the layer type', () => { e2e.flows.openDashboard({ uid: DASHBOARD_ID, queryParams: { editPanel: 1 } }); - cy.get('[data-testid="layer-drag-drop-list"]').should('be.visible'); + cy.get('[data-testid="layer-drag-drop-list"]').scrollIntoView().should('be.visible'); e2e.components.PanelEditor.OptionsPane.fieldLabel(MAP_LAYERS_TYPE).should('be.visible'); cy.get('[data-testid="layer-drag-drop-list"]').contains('markers'); diff --git a/packages/grafana-schema/src/raw/composable/geomap/panelcfg/x/GeomapPanelCfg_types.gen.ts b/packages/grafana-schema/src/raw/composable/geomap/panelcfg/x/GeomapPanelCfg_types.gen.ts index 0a085d8ec6e..fa1e3eaf299 100644 --- a/packages/grafana-schema/src/raw/composable/geomap/panelcfg/x/GeomapPanelCfg_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/geomap/panelcfg/x/GeomapPanelCfg_types.gen.ts @@ -33,6 +33,7 @@ export interface MapViewConfig { lon?: number; maxZoom?: number; minZoom?: number; + noRepeat?: boolean; padding?: number; shared?: boolean; zoom?: number; @@ -43,6 +44,7 @@ export const defaultMapViewConfig: Partial = { id: 'zero', lat: 0, lon: 0, + noRepeat: false, zoom: 1, }; diff --git a/packages/grafana-schema/src/veneer/common.types.ts b/packages/grafana-schema/src/veneer/common.types.ts index fb3bfe18c57..7a119bdb1af 100644 --- a/packages/grafana-schema/src/veneer/common.types.ts +++ b/packages/grafana-schema/src/veneer/common.types.ts @@ -6,6 +6,8 @@ export interface MapLayerOptions extends raw.MapLayerOptions { // Custom options depending on the type config?: TConfig; filterData?: MatcherConfig; + // Disable world repetition for basemap layers + noRepeat?: boolean; } export interface DataQuery extends raw.DataQuery { diff --git a/public/app/plugins/panel/geomap/GeomapPanel.tsx b/public/app/plugins/panel/geomap/GeomapPanel.tsx index 14399a2893d..6984228c6f7 100644 --- a/public/app/plugins/panel/geomap/GeomapPanel.tsx +++ b/public/app/plugins/panel/geomap/GeomapPanel.tsx @@ -2,14 +2,14 @@ import { css } from '@emotion/css'; import { Global } from '@emotion/react'; import OpenLayersMap from 'ol/Map'; import MapBrowserEvent from 'ol/MapBrowserEvent'; -import View from 'ol/View'; +import View, { ViewOptions } from 'ol/View'; import Attribution from 'ol/control/Attribution'; import ScaleLine from 'ol/control/ScaleLine'; import Zoom from 'ol/control/Zoom'; import { Coordinate } from 'ol/coordinate'; import { isEmpty } from 'ol/extent'; import MouseWheelZoom from 'ol/interaction/MouseWheelZoom'; -import { fromLonLat } from 'ol/proj'; +import { fromLonLat, transformExtent } from 'ol/proj'; import { Component, ReactNode } from 'react'; import * as React from 'react'; import { Subscription } from 'rxjs'; @@ -132,11 +132,6 @@ export class GeomapPanel extends Component { this.dataChanged(nextProps.data); } - // Options changed - if (this.props.options !== nextProps.options) { - this.optionsChanged(nextProps.options); - } - return true; // always? } @@ -148,6 +143,10 @@ export class GeomapPanel extends Component { if (this.map && this.props.data !== prevProps.data) { this.dataChanged(this.props.data); } + // Handle options changes + if (this.props.options !== prevProps.options) { + this.optionsChanged(prevProps.options, this.props.options); + } } /** This function will actually update the JSON model */ @@ -177,18 +176,29 @@ export class GeomapPanel extends Component { * * NOTE: changes to basemap and layers are handled independently */ - optionsChanged(options: Options) { - const oldOptions = this.props.options; - if (options.view !== oldOptions.view) { - const view = this.initMapView(options.view); + optionsChanged(oldOptions: Options, newOptions: Options) { + // First check if noRepeat changed - requires full map reinitialization + const noRepeatChanged = oldOptions.view?.noRepeat !== newOptions.view?.noRepeat; + if (noRepeatChanged) { + if (this.mapDiv) { + this.initMapRef(this.mapDiv); + } + // Skip other options processing + return; + } + + // Handle incremental view changes + if (oldOptions.view !== newOptions.view) { + const view = this.initMapView(newOptions.view); if (this.map && view) { this.map.setView(view); } } - if (options.controls !== oldOptions.controls) { - this.initControls(options.controls ?? { showZoom: true, showAttribution: true }); + // Handle controls changes + if (newOptions.controls !== oldOptions.controls) { + this.initControls(newOptions.controls ?? { showZoom: true, showAttribution: true }); } } @@ -234,7 +244,12 @@ export class GeomapPanel extends Component { this.byName.clear(); const layers: MapLayerState[] = []; try { - layers.push(await initLayer(this, map, options.basemap ?? DEFAULT_BASEMAP_CONFIG, true)); + // Pass noRepeat setting to basemap layer + const basemapOptions = { + ...(options.basemap ?? DEFAULT_BASEMAP_CONFIG), + noRepeat: options.view?.noRepeat ?? false, + }; + layers.push(await initLayer(this, map, basemapOptions, true)); // Default layer values if (!options.layers) { @@ -284,11 +299,24 @@ export class GeomapPanel extends Component { }; initMapView = (config: MapViewConfig): View | undefined => { - let view = new View({ + const noRepeat = config.noRepeat ?? false; + + let viewOptions: ViewOptions = { center: [0, 0], zoom: 1, - showFullExtent: true, // allows zooming so the full range is visible - }); + }; + + // Only apply constraints when no-repeat is enabled + if (noRepeat) { + // Define the world extent in EPSG:3857 (Web Mercator) + const worldExtent = [-180, -85.05112878, 180, 85.05112878]; // [minx, miny, maxx, maxy] in EPSG:4326 + const projectedExtent = transformExtent(worldExtent, 'EPSG:4326', 'EPSG:3857'); + viewOptions.extent = projectedExtent; + viewOptions.showFullExtent = false; + viewOptions.constrainOnlyCenter = false; + } + + let view = new View(viewOptions); // With shared views, all panels use the same view instance if (config.shared) { diff --git a/public/app/plugins/panel/geomap/layers/basemaps/carto.test.ts b/public/app/plugins/panel/geomap/layers/basemaps/carto.test.ts new file mode 100644 index 00000000000..88e3f95d9a3 --- /dev/null +++ b/public/app/plugins/panel/geomap/layers/basemaps/carto.test.ts @@ -0,0 +1,103 @@ +import OpenLayersMap from 'ol/Map'; +import TileLayer from 'ol/layer/Tile'; +import XYZ from 'ol/source/XYZ'; + +import { EventBus, GrafanaTheme2, MapLayerOptions } from '@grafana/data'; + +import { carto, CartoConfig, LayerTheme } from './carto'; + +describe('CARTO basemap layer noRepeat functionality', () => { + let mockMap: OpenLayersMap; + let mockEventBus: EventBus; + let mockTheme: GrafanaTheme2; + + beforeEach(() => { + mockMap = {} as OpenLayersMap; + mockEventBus = {} as EventBus; + mockTheme = { isDark: false } as GrafanaTheme2; + }); + + it('should set wrapX to false when noRepeat is true', async () => { + const options: MapLayerOptions = { + name: 'Test CARTO Layer', + type: 'carto', + config: { + theme: LayerTheme.Light, + showLabels: true, + }, + noRepeat: true, + }; + + const result = await carto.create(mockMap, options, mockEventBus, mockTheme); + const layer = result.init(); + + expect(layer).toBeInstanceOf(TileLayer); + const source = (layer as TileLayer).getSource() as XYZ; + expect(source).toBeInstanceOf(XYZ); + expect(source.getWrapX()).toBe(false); + }); + + it('should set wrapX to true when noRepeat is false', async () => { + const options: MapLayerOptions = { + name: 'Test CARTO Layer', + type: 'carto', + config: { + theme: LayerTheme.Dark, + showLabels: false, + }, + noRepeat: false, + }; + + const result = await carto.create(mockMap, options, mockEventBus, mockTheme); + const layer = result.init(); + + expect(layer).toBeInstanceOf(TileLayer); + const source = (layer as TileLayer).getSource() as XYZ; + expect(source).toBeInstanceOf(XYZ); + expect(source.getWrapX()).toBe(true); + }); + + it('should set wrapX to true when noRepeat is undefined (defaults to false)', async () => { + const options: MapLayerOptions = { + name: 'Test CARTO Layer', + type: 'carto', + config: { + theme: LayerTheme.Auto, + showLabels: true, + }, + // noRepeat not specified + }; + + const result = await carto.create(mockMap, options, mockEventBus, mockTheme); + const layer = result.init(); + + expect(layer).toBeInstanceOf(TileLayer); + const source = (layer as TileLayer).getSource() as XYZ; + expect(source).toBeInstanceOf(XYZ); + expect(source.getWrapX()).toBe(true); + }); + + it('should preserve theme and label settings when noRepeat is set', async () => { + const mockDarkTheme = { isDark: true } as GrafanaTheme2; + const options: MapLayerOptions = { + name: 'Test CARTO Layer', + type: 'carto', + config: { + theme: LayerTheme.Auto, // Should use dark theme from mockDarkTheme + showLabels: false, + }, + noRepeat: true, + }; + + const result = await carto.create(mockMap, options, mockEventBus, mockDarkTheme); + const layer = result.init(); + + expect(layer).toBeInstanceOf(TileLayer); + const source = (layer as TileLayer).getSource() as XYZ; + expect(source.getWrapX()).toBe(false); + + // Check that the URL reflects the dark theme without labels + const urls = source.getUrls(); + expect(urls?.[0]).toContain('dark_nolabels'); + }); +}); diff --git a/public/app/plugins/panel/geomap/layers/basemaps/carto.ts b/public/app/plugins/panel/geomap/layers/basemaps/carto.ts index 92f3c54502f..3e2572a702f 100644 --- a/public/app/plugins/panel/geomap/layers/basemaps/carto.ts +++ b/public/app/plugins/panel/geomap/layers/basemaps/carto.ts @@ -51,10 +51,13 @@ export const carto: MapLayerRegistryItem = { style += '_nolabels'; } const scale = window.devicePixelRatio > 1 ? '@2x' : ''; + const noRepeat = options.noRepeat ?? false; + return new TileLayer({ source: new XYZ({ attributions: `
©CARTO ©OpenStreetMap contributors`, url: `https://{1-4}.basemaps.cartocdn.com/${style}/{z}/{x}/{y}${scale}.png`, + wrapX: !noRepeat, }), }); }, diff --git a/public/app/plugins/panel/geomap/layers/basemaps/generic.test.ts b/public/app/plugins/panel/geomap/layers/basemaps/generic.test.ts new file mode 100644 index 00000000000..180a2be2644 --- /dev/null +++ b/public/app/plugins/panel/geomap/layers/basemaps/generic.test.ts @@ -0,0 +1,103 @@ +import OpenLayersMap from 'ol/Map'; +import TileLayer from 'ol/layer/Tile'; +import XYZ from 'ol/source/XYZ'; + +import { EventBus, GrafanaTheme2, MapLayerOptions } from '@grafana/data'; + +import { xyzTiles, XYZConfig } from './generic'; + +describe('XYZ tile layer noRepeat functionality', () => { + let mockMap: OpenLayersMap; + let mockEventBus: EventBus; + let mockTheme: GrafanaTheme2; + + beforeEach(() => { + mockMap = {} as OpenLayersMap; + mockEventBus = {} as EventBus; + mockTheme = {} as GrafanaTheme2; + }); + + it('should set wrapX to false when noRepeat is true', async () => { + const options: MapLayerOptions = { + name: 'Test Layer', + type: 'xyz', + config: { + url: 'https://example.com/{z}/{x}/{y}.png', + attribution: 'Test Attribution', + }, + noRepeat: true, + }; + + const result = await xyzTiles.create(mockMap, options, mockEventBus, mockTheme); + const layer = result.init(); + + expect(layer).toBeInstanceOf(TileLayer); + const source = (layer as TileLayer).getSource() as XYZ; + expect(source).toBeInstanceOf(XYZ); + expect(source.getWrapX()).toBe(false); + }); + + it('should set wrapX to true when noRepeat is false', async () => { + const options: MapLayerOptions = { + name: 'Test Layer', + type: 'xyz', + config: { + url: 'https://example.com/{z}/{x}/{y}.png', + attribution: 'Test Attribution', + }, + noRepeat: false, + }; + + const result = await xyzTiles.create(mockMap, options, mockEventBus, mockTheme); + const layer = result.init(); + + expect(layer).toBeInstanceOf(TileLayer); + const source = (layer as TileLayer).getSource() as XYZ; + expect(source).toBeInstanceOf(XYZ); + expect(source.getWrapX()).toBe(true); + }); + + it('should set wrapX to true when noRepeat is undefined (defaults to false)', async () => { + const options: MapLayerOptions = { + name: 'Test Layer', + type: 'xyz', + config: { + url: 'https://example.com/{z}/{x}/{y}.png', + attribution: 'Test Attribution', + }, + // noRepeat not specified + }; + + const result = await xyzTiles.create(mockMap, options, mockEventBus, mockTheme); + const layer = result.init(); + + expect(layer).toBeInstanceOf(TileLayer); + const source = (layer as TileLayer).getSource() as XYZ; + expect(source).toBeInstanceOf(XYZ); + expect(source.getWrapX()).toBe(true); + }); + + it('should preserve other layer properties when noRepeat is set', async () => { + const options: MapLayerOptions = { + name: 'Test Layer', + type: 'xyz', + config: { + url: 'https://example.com/{z}/{x}/{y}.png', + attribution: 'Test Attribution', + minZoom: 2, + maxZoom: 18, + }, + noRepeat: true, + }; + + const result = await xyzTiles.create(mockMap, options, mockEventBus, mockTheme); + const layer = result.init(); + + expect(layer).toBeInstanceOf(TileLayer); + expect(layer.getMinZoom()).toBe(2); + expect(layer.getMaxZoom()).toBe(18); + + const source = (layer as TileLayer).getSource() as XYZ; + expect(source.getWrapX()).toBe(false); + }); +}); diff --git a/public/app/plugins/panel/geomap/layers/basemaps/generic.ts b/public/app/plugins/panel/geomap/layers/basemaps/generic.ts index 2ed2a022037..f3381902e26 100644 --- a/public/app/plugins/panel/geomap/layers/basemaps/generic.ts +++ b/public/app/plugins/panel/geomap/layers/basemaps/generic.ts @@ -35,10 +35,13 @@ export const xyzTiles: MapLayerRegistryItem = { cfg.url = defaultXYZConfig.url; cfg.attribution = cfg.attribution ?? defaultXYZConfig.attribution; } + const noRepeat = options.noRepeat ?? false; + return new TileLayer({ source: new XYZ({ url: cfg.url, attributions: cfg.attribution, // singular? + wrapX: !noRepeat, }), minZoom: cfg.minZoom, maxZoom: cfg.maxZoom, diff --git a/public/app/plugins/panel/geomap/layers/basemaps/osm.test.ts b/public/app/plugins/panel/geomap/layers/basemaps/osm.test.ts new file mode 100644 index 00000000000..19a62533b2a --- /dev/null +++ b/public/app/plugins/panel/geomap/layers/basemaps/osm.test.ts @@ -0,0 +1,67 @@ +import OpenLayersMap from 'ol/Map'; +import TileLayer from 'ol/layer/Tile'; +import OSM from 'ol/source/OSM'; + +import { EventBus, MapLayerOptions, GrafanaTheme2 } from '@grafana/data'; + +import { standard } from './osm'; + +describe('OSM layer noRepeat functionality', () => { + let mockMap: OpenLayersMap; + let mockEventBus: EventBus; + let mockTheme: GrafanaTheme2; + + beforeEach(() => { + mockMap = {} as OpenLayersMap; + mockEventBus = {} as EventBus; + mockTheme = {} as GrafanaTheme2; + }); + + it('should set wrapX to false when noRepeat is true', async () => { + const options: MapLayerOptions = { + name: 'Test OSM Layer', + type: 'osm-standard', + noRepeat: true, + }; + + const result = await standard.create(mockMap, options, mockEventBus, mockTheme); + const layer = result.init(); + + expect(layer).toBeInstanceOf(TileLayer); + const source = (layer as TileLayer).getSource() as OSM; + expect(source).toBeInstanceOf(OSM); + expect(source.getWrapX()).toBe(false); + }); + + it('should set wrapX to true when noRepeat is false', async () => { + const options: MapLayerOptions = { + name: 'Test OSM Layer', + type: 'osm-standard', + noRepeat: false, + }; + + const result = await standard.create(mockMap, options, mockEventBus, mockTheme); + const layer = result.init(); + + expect(layer).toBeInstanceOf(TileLayer); + const source = (layer as TileLayer).getSource() as OSM; + expect(source).toBeInstanceOf(OSM); + expect(source.getWrapX()).toBe(true); + }); + + it('should set wrapX to true when noRepeat is undefined (defaults to false)', async () => { + const options: MapLayerOptions = { + name: 'Test OSM Layer', + type: 'osm-standard', + // noRepeat not specified + }; + + const result = await standard.create(mockMap, options, mockEventBus, mockTheme); + const layer = result.init(); + + expect(layer).toBeInstanceOf(TileLayer); + const source = (layer as TileLayer).getSource() as OSM; + expect(source).toBeInstanceOf(OSM); + expect(source.getWrapX()).toBe(true); + }); +}); diff --git a/public/app/plugins/panel/geomap/layers/basemaps/osm.ts b/public/app/plugins/panel/geomap/layers/basemaps/osm.ts index c644702b1ca..078ddafff43 100644 --- a/public/app/plugins/panel/geomap/layers/basemaps/osm.ts +++ b/public/app/plugins/panel/geomap/layers/basemaps/osm.ts @@ -16,8 +16,10 @@ export const standard: MapLayerRegistryItem = { */ create: async (map: OpenLayersMap, options: MapLayerOptions, eventBus: EventBus) => ({ init: () => { + const noRepeat = options.noRepeat ?? false; + return new TileLayer({ - source: new OSM(), + source: new OSM({ wrapX: !noRepeat }), }); }, }), diff --git a/public/app/plugins/panel/geomap/migrations.test.ts b/public/app/plugins/panel/geomap/migrations.test.ts index eda219ea9ec..6cf672211dd 100644 --- a/public/app/plugins/panel/geomap/migrations.test.ts +++ b/public/app/plugins/panel/geomap/migrations.test.ts @@ -248,4 +248,31 @@ describe('geomap migrations', () => { } `); }); + it('should handle migration when noRepeat is not set', () => { + const panel = { + id: 2, + type: 'geomap', + options: { + view: { + id: 'coords', + zoom: 5, + }, + layers: [ + { + type: 'markers', + config: { + showLegend: false, + }, + }, + ], + }, + pluginVersion: '8.2.0', + } as PanelModel; + + panel.options = mapMigrationHandler(panel); + + expect(panel.options.view.noRepeat).toBeUndefined(); + expect(panel.options.view.id).toBe('coords'); + expect(panel.options.view.zoom).toBe(5); + }); }); diff --git a/public/app/plugins/panel/geomap/module.tsx b/public/app/plugins/panel/geomap/module.tsx index f8c7825f896..7573f9317aa 100644 --- a/public/app/plugins/panel/geomap/module.tsx +++ b/public/app/plugins/panel/geomap/module.tsx @@ -42,6 +42,14 @@ export const plugin = new PanelPlugin(GeomapPanel) defaultValue: defaultMapViewConfig.shared, }); + builder.addBooleanSwitch({ + category, + path: 'view.noRepeat', + name: t('geomap.name-no-repeat', 'No map repeating'), + description: t('geomap.description-no-repeat', 'Prevent the map from repeating horizontally'), + defaultValue: false, + }); + // eslint-disable-next-line const state = context.instanceState as GeomapInstanceState; if (!state?.layers) { diff --git a/public/app/plugins/panel/geomap/panelcfg.cue b/public/app/plugins/panel/geomap/panelcfg.cue index 67d12b9293a..7384ec581e5 100644 --- a/public/app/plugins/panel/geomap/panelcfg.cue +++ b/public/app/plugins/panel/geomap/panelcfg.cue @@ -45,6 +45,7 @@ composableKinds: PanelCfg: { lastOnly?: bool layer?: string shared?: bool + noRepeat?: bool | *false } @cuetsy(kind="interface") ControlsOptions: { diff --git a/public/app/plugins/panel/geomap/panelcfg.gen.ts b/public/app/plugins/panel/geomap/panelcfg.gen.ts index 7e4288bf050..cffd8e01e13 100644 --- a/public/app/plugins/panel/geomap/panelcfg.gen.ts +++ b/public/app/plugins/panel/geomap/panelcfg.gen.ts @@ -31,6 +31,7 @@ export interface MapViewConfig { lon?: number; maxZoom?: number; minZoom?: number; + noRepeat?: boolean; padding?: number; shared?: boolean; zoom?: number; @@ -41,6 +42,7 @@ export const defaultMapViewConfig: Partial = { id: 'zero', lat: 0, lon: 0, + noRepeat: false, zoom: 1, }; diff --git a/public/locales/en-US/grafana.json b/public/locales/en-US/grafana.json index d0aa51d51e2..f9f5d8553c8 100644 --- a/public/locales/en-US/grafana.json +++ b/public/locales/en-US/grafana.json @@ -7512,6 +7512,7 @@ }, "description-initial-view": "This location will show when the panel first loads.", "description-mouse-wheel-zoom": "Enable zoom control via mouse wheel", + "description-no-repeat": "Prevent the map from repeating horizontally", "description-share-view": "Use the same view across multiple panels. Note: this may require a dashboard reload.", "description-show-attribution": "Show the map source attribution info in the lower right", "description-show-debug": "Show map info", @@ -7571,6 +7572,7 @@ }, "name-initial-view": "Initial view", "name-mouse-wheel-zoom": "Mouse wheel zoom", + "name-no-repeat": "No map repeating", "name-share-view": "Share view", "name-show-attribution": "Show attribution", "name-show-debug": "Show debug", From 4392cea75a89239b1b56b9f094aa2fb405a5e0b3 Mon Sep 17 00:00:00 2001 From: Russ <8377044+rdubrock@users.noreply.github.com> Date: Mon, 28 Jul 2025 14:23:41 -0800 Subject: [PATCH 070/131] chore: add an option to hide the metrics browser in a PromQueryField (#108718) --- .../src/components/PromQueryField.test.tsx | 13 ++++++++ .../src/components/PromQueryField.tsx | 32 +++++++++++-------- 2 files changed, 31 insertions(+), 14 deletions(-) diff --git a/packages/grafana-prometheus/src/components/PromQueryField.test.tsx b/packages/grafana-prometheus/src/components/PromQueryField.test.tsx index d3fc7b80360..62fbdde8232 100644 --- a/packages/grafana-prometheus/src/components/PromQueryField.test.tsx +++ b/packages/grafana-prometheus/src/components/PromQueryField.test.tsx @@ -80,6 +80,19 @@ describe('PromQueryField', () => { expect(bcButton).toBeDisabled(); }); + it('renders no metrics chooser if hidden by props', async () => { + const props = { + ...defaultProps, + hideMetricsBrowser: true, + }; + const queryField = render(); + + // wait for component to render + await screen.findByTestId('dummy-code-input'); + + expect(queryField.queryByRole('button')).not.toBeInTheDocument(); + }); + it('renders an initial hint if no data and initial hint provided', async () => { const props = defaultProps; props.datasource.lookupsDisabled = true; diff --git a/packages/grafana-prometheus/src/components/PromQueryField.tsx b/packages/grafana-prometheus/src/components/PromQueryField.tsx index 289b206b7d2..1a6f95bba50 100644 --- a/packages/grafana-prometheus/src/components/PromQueryField.tsx +++ b/packages/grafana-prometheus/src/components/PromQueryField.tsx @@ -25,6 +25,7 @@ import { MonacoQueryFieldWrapper } from './monaco-query-field/MonacoQueryFieldWr interface PromQueryFieldProps extends QueryEditorProps { ExtraFieldElement?: ReactNode; + hideMetricsBrowser?: boolean; 'data-testid'?: string; } @@ -40,6 +41,7 @@ export const PromQueryField = (props: PromQueryFieldProps) => { range, onChange, onRunQuery, + hideMetricsBrowser = false, } = props; const theme = useTheme2(); @@ -111,20 +113,22 @@ export const PromQueryField = (props: PromQueryFieldProps) => { className="gf-form-inline gf-form-inline--xs-view-flex-column flex-grow-1" data-testid={props['data-testid']} > - + {!hideMetricsBrowser && ( + + )}
Date: Tue, 29 Jul 2025 02:52:27 -0500 Subject: [PATCH 071/131] Dashboards: Move to integration tests (#108734) --- .../database/database_folder_test.go | 219 ---- .../dashboard_service_integration_test.go | 1092 ----------------- .../service/dashboard_service_test.go | 5 + .../api/dashboards/api_dashboards_test.go | 618 ++++++++-- 4 files changed, 545 insertions(+), 1389 deletions(-) delete mode 100644 pkg/services/dashboards/service/dashboard_service_integration_test.go diff --git a/pkg/services/dashboards/database/database_folder_test.go b/pkg/services/dashboards/database/database_folder_test.go index f41ffe9a11f..dfe02a39416 100644 --- a/pkg/services/dashboards/database/database_folder_test.go +++ b/pkg/services/dashboards/database/database_folder_test.go @@ -2,36 +2,20 @@ package database import ( "context" - "errors" - "fmt" "testing" - "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/infra/db" - "github.com/grafana/grafana/pkg/infra/tracing" - "github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/accesscontrol/actest" - "github.com/grafana/grafana/pkg/services/accesscontrol/mock" - "github.com/grafana/grafana/pkg/services/apiserver" "github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/featuremgmt" - "github.com/grafana/grafana/pkg/services/folder" - "github.com/grafana/grafana/pkg/services/folder/folderimpl" "github.com/grafana/grafana/pkg/services/org" - "github.com/grafana/grafana/pkg/services/org/orgimpl" - "github.com/grafana/grafana/pkg/services/quota/quotatest" - "github.com/grafana/grafana/pkg/services/search/sort" - "github.com/grafana/grafana/pkg/services/supportbundles/supportbundlestest" "github.com/grafana/grafana/pkg/services/tag/tagimpl" "github.com/grafana/grafana/pkg/services/user" - "github.com/grafana/grafana/pkg/services/user/userimpl" "github.com/grafana/grafana/pkg/setting" - "github.com/grafana/grafana/pkg/storage/legacysql/dualwrite" ) var testFeatureToggles = featuremgmt.WithFeatures(featuremgmt.FlagPanelTitleSearch) @@ -230,197 +214,6 @@ func TestIntegrationDashboardFolderDataAccess(t *testing.T) { }) } -func TestIntegrationDashboardInheritedFolderRBAC(t *testing.T) { - if testing.Short() { - t.Skip("skipping integration test") - } - // the maximux nested folder hierarchy starting from parent down to subfolders - nestedFolders := make([]*folder.Folder, 0, folder.MaxNestedFolderDepth+1) - - var sqlStore db.DB - var cfg *setting.Cfg - const ( - dashInRootTitle = "dashboard in root" - dashInParentTitle = "dashboard in parent" - dashInSubfolderTitle = "dashboard in subfolder" - ) - var viewer *user.SignedInUser - - setup := func() { - sqlStore, cfg = db.InitTestDBWithCfg(t) - cfg.AutoAssignOrg = true - cfg.AutoAssignOrgId = 1 - cfg.AutoAssignOrgRole = string(org.RoleViewer) - - tracer := tracing.InitializeTracerForTest() - quotaService := quotatest.New(false, nil) - - // enable nested folders so that the folder table is populated for all the tests - features := featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders) - - var err error - dashboardWriteStore, err := ProvideDashboardStore(sqlStore, cfg, features, tagimpl.ProvideService(sqlStore)) - require.NoError(t, err) - - orgService, err := orgimpl.ProvideService(sqlStore, cfg, quotaService) - require.NoError(t, err) - usrSvc, err := userimpl.ProvideService( - sqlStore, orgService, cfg, nil, nil, tracer, - quotaService, supportbundlestest.NewFakeBundleService(), - ) - require.NoError(t, err) - - usr := createUser(t, usrSvc, orgService, "viewer", false) - viewer = &user.SignedInUser{ - UserID: usr.ID, - OrgID: usr.OrgID, - OrgRole: org.RoleViewer, - } - - // create admin user in the same org - currentUserCmd := user.CreateUserCommand{Login: "admin", Email: "admin@test.com", Name: "an admin", IsAdmin: false, OrgID: viewer.OrgID} - u, err := usrSvc.Create(context.Background(), ¤tUserCmd) - require.NoError(t, err) - admin := user.SignedInUser{ - UserID: u.ID, - OrgID: u.OrgID, - OrgRole: org.RoleAdmin, - Permissions: map[int64]map[string][]string{u.OrgID: accesscontrol.GroupScopesByActionContext(context.Background(), []accesscontrol.Permission{ - { - Action: dashboards.ActionFoldersCreate, - Scope: dashboards.ScopeFoldersAll, - }}), - }, - } - require.NotEqual(t, viewer.UserID, admin.UserID) - - folderStore := folderimpl.ProvideStore(sqlStore) - folderSvc := folderimpl.ProvideService( - folderStore, mock.New(), bus.ProvideBus(tracer), dashboardWriteStore, folderimpl.ProvideDashboardFolderStore(sqlStore), - nil, sqlStore, features, supportbundlestest.NewFakeBundleService(), nil, cfg, nil, tracing.InitializeTracerForTest(), nil, dualwrite.ProvideTestService(), sort.ProvideService(), apiserver.WithoutRestConfig) - - parentUID := "" - for i := 0; ; i++ { - uid := fmt.Sprintf("f%d", i) - f, err := folderSvc.Create(context.Background(), &folder.CreateFolderCommand{ - UID: uid, - OrgID: admin.OrgID, - Title: uid, - SignedInUser: &admin, - ParentUID: parentUID, - }) - if err != nil { - if errors.Is(err, folder.ErrMaximumDepthReached) { - break - } - - t.Log("unexpected error", "error", err) - t.Fail() - } - - nestedFolders = append(nestedFolders, f) - - parentUID = f.UID - } - require.LessOrEqual(t, 2, len(nestedFolders)) - - saveDashboardCmd := dashboards.SaveDashboardCommand{ - UserID: admin.UserID, - OrgID: admin.OrgID, - IsFolder: false, - Dashboard: simplejson.NewFromAny(map[string]any{ - "title": dashInRootTitle, - }), - } - _, err = dashboardWriteStore.SaveDashboard(context.Background(), saveDashboardCmd) - require.NoError(t, err) - - saveDashboardCmd = dashboards.SaveDashboardCommand{ - UserID: admin.UserID, - OrgID: admin.OrgID, - IsFolder: false, - Dashboard: simplejson.NewFromAny(map[string]any{ - "title": dashInParentTitle, - }), - FolderUID: nestedFolders[0].UID, - } - _, err = dashboardWriteStore.SaveDashboard(context.Background(), saveDashboardCmd) - require.NoError(t, err) - - saveDashboardCmd = dashboards.SaveDashboardCommand{ - UserID: admin.UserID, - OrgID: admin.OrgID, - IsFolder: false, - Dashboard: simplejson.NewFromAny(map[string]any{ - "title": dashInSubfolderTitle, - }), - FolderUID: nestedFolders[1].UID, - } - _, err = dashboardWriteStore.SaveDashboard(context.Background(), saveDashboardCmd) - require.NoError(t, err) - } - - setup() - - nestedFolderTitles := make([]string, 0, len(nestedFolders)) - for _, f := range nestedFolders { - nestedFolderTitles = append(nestedFolderTitles, f.Title) - } - - testCases := []struct { - desc string - features featuremgmt.FeatureToggles - permissions map[string][]string - expectedTitles []string - }{ - { - desc: "it should not return folder if ACL is not set for parent folder", - features: featuremgmt.WithFeatures(featuremgmt.FlagPanelTitleSearch), - permissions: nil, - expectedTitles: nil, - }, - { - desc: "it should not return subfolder if nested folders are disabled and the user has permission to read folders under parent folder", - features: featuremgmt.WithFeatures(featuremgmt.FlagPanelTitleSearch), - permissions: map[string][]string{ - dashboards.ActionFoldersRead: {fmt.Sprintf("folders:uid:%s", nestedFolders[0].UID)}, - }, - expectedTitles: []string{nestedFolders[0].Title}, - }, - { - desc: "it should return subfolder if nested folders are enabled and the user has permission to read folders under parent folder", - features: featuremgmt.WithFeatures(featuremgmt.FlagPanelTitleSearch, featuremgmt.FlagNestedFolders), - permissions: map[string][]string{ - dashboards.ActionFoldersRead: {fmt.Sprintf("folders:uid:%s", nestedFolders[0].UID)}, - }, - expectedTitles: nestedFolderTitles, - }, - } - - for _, tc := range testCases { - t.Run(tc.desc, func(t *testing.T) { - dashboardReadStore, err := ProvideDashboardStore(sqlStore, cfg, tc.features, tagimpl.ProvideService(sqlStore)) - require.NoError(t, err) - - viewer.Permissions = map[int64]map[string][]string{viewer.OrgID: tc.permissions} - actest.AddUserPermissionToDB(t, sqlStore, viewer) - - query := &dashboards.FindPersistedDashboardsQuery{ - SignedInUser: viewer, - OrgId: viewer.OrgID, - } - - res, err := testSearchDashboards(dashboardReadStore, query) - require.NoError(t, err) - - require.Equal(t, len(tc.expectedTitles), len(res)) - for i, tlt := range tc.expectedTitles { - assert.Equal(t, tlt, res[i].Title) - } - }) - } -} - func moveDashboard(t *testing.T, dashboardStore dashboards.Store, orgId int64, dashboard *simplejson.Json, newFolderId int64, newFolderUID string) *dashboards.Dashboard { t.Helper() @@ -437,15 +230,3 @@ func moveDashboard(t *testing.T, dashboardStore dashboards.Store, orgId int64, d return dash } - -func createUser(t *testing.T, userSrv user.Service, orgSrv org.Service, name string, isAdmin bool) user.User { - t.Helper() - - o, err := orgSrv.CreateWithMember(context.Background(), &org.CreateOrgCommand{Name: fmt.Sprintf("test org %d", time.Now().UnixNano())}) - require.NoError(t, err) - - currentUserCmd := user.CreateUserCommand{Login: name, Email: name + "@test.com", Name: "a " + name, IsAdmin: isAdmin, OrgID: o.ID} - currentUser, err := userSrv.Create(context.Background(), ¤tUserCmd) - require.NoError(t, err) - return *currentUser -} diff --git a/pkg/services/dashboards/service/dashboard_service_integration_test.go b/pkg/services/dashboards/service/dashboard_service_integration_test.go deleted file mode 100644 index 38c11736a1b..00000000000 --- a/pkg/services/dashboards/service/dashboard_service_integration_test.go +++ /dev/null @@ -1,1092 +0,0 @@ -package service - -import ( - "context" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" - - "github.com/grafana/grafana/pkg/bus" - "github.com/grafana/grafana/pkg/components/simplejson" - "github.com/grafana/grafana/pkg/infra/db" - "github.com/grafana/grafana/pkg/infra/kvstore" - "github.com/grafana/grafana/pkg/infra/serverlock" - "github.com/grafana/grafana/pkg/infra/tracing" - "github.com/grafana/grafana/pkg/services/accesscontrol" - "github.com/grafana/grafana/pkg/services/accesscontrol/acimpl" - "github.com/grafana/grafana/pkg/services/accesscontrol/actest" - accesscontrolmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock" - "github.com/grafana/grafana/pkg/services/apiserver" - "github.com/grafana/grafana/pkg/services/apiserver/client" - "github.com/grafana/grafana/pkg/services/dashboards" - "github.com/grafana/grafana/pkg/services/dashboards/database" - "github.com/grafana/grafana/pkg/services/featuremgmt" - "github.com/grafana/grafana/pkg/services/folder/folderimpl" - "github.com/grafana/grafana/pkg/services/org" - "github.com/grafana/grafana/pkg/services/publicdashboards" - "github.com/grafana/grafana/pkg/services/quota/quotatest" - "github.com/grafana/grafana/pkg/services/search/sort" - "github.com/grafana/grafana/pkg/services/supportbundles/supportbundlestest" - "github.com/grafana/grafana/pkg/services/tag/tagimpl" - "github.com/grafana/grafana/pkg/services/user" - "github.com/grafana/grafana/pkg/setting" - "github.com/grafana/grafana/pkg/storage/legacysql/dualwrite" - "github.com/grafana/grafana/pkg/tests/testsuite" -) - -const testOrgID int64 = 1 - -func TestMain(m *testing.M) { - testsuite.Run(m) -} - -func TestIntegrationIntegratedDashboardService(t *testing.T) { - if testing.Short() { - t.Skip("skipping integration test") - } - t.Run("Given saved folders and dashboards in organization A", func(t *testing.T) { - // Basic validation tests - - permissionScenario(t, "When saving a dashboard with non-existing id", func(t *testing.T, sc *permissionScenarioContext) { - cmd := dashboards.SaveDashboardCommand{ - OrgID: testOrgID, - Dashboard: simplejson.NewFromAny(map[string]any{ - "id": float64(123412321), - "title": "Expect error", - }), - } - - _, err := callSaveWithResult(t, cmd, sc.sqlStore, nil) - assert.Equal(t, dashboards.ErrDashboardNotFound, err) - }) - - // Given other organization - - t.Run("Given organization B", func(t *testing.T) { - const otherOrgId int64 = 2 - - permissionScenario(t, "When creating a dashboard with same id as dashboard in organization A", func(t *testing.T, sc *permissionScenarioContext) { - cmd := dashboards.SaveDashboardCommand{ - OrgID: otherOrgId, - Dashboard: simplejson.NewFromAny(map[string]any{ - "id": sc.savedDashInFolder.ID, - "title": "Expect error", - }), - Overwrite: false, - } - - _, err := callSaveWithResult(t, cmd, sc.sqlStore, nil) - assert.Equal(t, dashboards.ErrDashboardNotFound, err) - }) - - permissionScenario(t, "When creating a dashboard with same uid as dashboard in organization A, it should create a new dashboard in org B", func(t *testing.T, sc *permissionScenarioContext) { - const otherOrgId int64 = 2 - cmd := dashboards.SaveDashboardCommand{ - OrgID: otherOrgId, - Dashboard: simplejson.NewFromAny(map[string]any{ - "uid": sc.savedDashInFolder.UID, - "title": "Dash with existing uid in other org", - }), - Overwrite: false, - } - - res, _ := callSaveWithResult(t, cmd, sc.sqlStore, nil) - require.NotNil(t, res) - - _, err := sc.dashboardStore.GetDashboard(context.Background(), &dashboards.GetDashboardQuery{ - OrgID: otherOrgId, - UID: sc.savedDashInFolder.UID, - }) - require.NoError(t, err) - }) - }) - - t.Run("Given user has permission to save", func(t *testing.T) { - t.Run("and overwrite flag is set to false", func(t *testing.T) { - const shouldOverwrite = false - - permissionScenario(t, "When creating a dashboard in General folder with same name as dashboard in other folder", func(t *testing.T, sc *permissionScenarioContext) { - cmd := dashboards.SaveDashboardCommand{ - OrgID: testOrgID, - Dashboard: simplejson.NewFromAny(map[string]any{ - "id": nil, - "title": sc.savedDashInFolder.Title, - }), - FolderUID: "", - Overwrite: shouldOverwrite, - } - - res, _ := callSaveWithResult(t, cmd, sc.sqlStore, nil) - require.NotNil(t, res) - - _, err := sc.dashboardStore.GetDashboard(context.Background(), &dashboards.GetDashboardQuery{ - ID: res.ID, - OrgID: cmd.OrgID, - }) - - require.NoError(t, err) - }) - - permissionScenario(t, "When creating a dashboard in other folder with same name as dashboard in General folder", func(t *testing.T, sc *permissionScenarioContext) { - cmd := dashboards.SaveDashboardCommand{ - OrgID: testOrgID, - Dashboard: simplejson.NewFromAny(map[string]any{ - "id": nil, - "title": sc.savedDashInGeneralFolder.Title, - }), - FolderUID: sc.savedFolder.UID, - Overwrite: shouldOverwrite, - } - - res, _ := callSaveWithResult(t, cmd, sc.sqlStore, nil) - require.NotNil(t, res) - - assert.NotEqual(t, sc.savedDashInGeneralFolder.ID, res.ID) - - _, err := sc.dashboardStore.GetDashboard(context.Background(), &dashboards.GetDashboardQuery{ - ID: res.ID, - OrgID: cmd.OrgID, - }) - require.NoError(t, err) - }) - - permissionScenario(t, "When creating a folder with same name as dashboard in other folder", func(t *testing.T, sc *permissionScenarioContext) { - cmd := dashboards.SaveDashboardCommand{ - OrgID: testOrgID, - Dashboard: simplejson.NewFromAny(map[string]any{ - "id": nil, - "title": sc.savedDashInFolder.Title, - }), - IsFolder: true, - Overwrite: shouldOverwrite, - } - - res, _ := callSaveWithResult(t, cmd, sc.sqlStore, nil) - require.NotNil(t, res) - - assert.NotEqual(t, sc.savedDashInGeneralFolder.ID, res.ID) - assert.True(t, res.IsFolder) - - _, err := sc.dashboardStore.GetDashboard(context.Background(), &dashboards.GetDashboardQuery{ - ID: res.ID, - OrgID: cmd.OrgID, - }) - require.NoError(t, err) - }) - - permissionScenario(t, "When saving a dashboard without id and uid and unique title in folder", func(t *testing.T, sc *permissionScenarioContext) { - cmd := dashboards.SaveDashboardCommand{ - OrgID: testOrgID, - Dashboard: simplejson.NewFromAny(map[string]any{ - "title": "Dash without id and uid", - }), - Overwrite: shouldOverwrite, - } - - res, _ := callSaveWithResult(t, cmd, sc.sqlStore, nil) - require.NotNil(t, res) - - assert.Greater(t, res.ID, int64(0)) - assert.NotEmpty(t, res.UID) - _, err := sc.dashboardStore.GetDashboard(context.Background(), &dashboards.GetDashboardQuery{ - ID: res.ID, - OrgID: cmd.OrgID, - }) - require.NoError(t, err) - }) - - permissionScenario(t, "When saving a dashboard when dashboard id is zero ", func(t *testing.T, sc *permissionScenarioContext) { - cmd := dashboards.SaveDashboardCommand{ - OrgID: testOrgID, - Dashboard: simplejson.NewFromAny(map[string]any{ - "id": 0, - "title": "Dash with zero id", - }), - Overwrite: shouldOverwrite, - } - - res, _ := callSaveWithResult(t, cmd, sc.sqlStore, nil) - require.NotNil(t, res) - - _, err := sc.dashboardStore.GetDashboard(context.Background(), &dashboards.GetDashboardQuery{ - ID: res.ID, - OrgID: cmd.OrgID, - }) - require.NoError(t, err) - }) - - permissionScenario(t, "When saving a dashboard in non-existing folder", func(t *testing.T, sc *permissionScenarioContext) { - cmd := dashboards.SaveDashboardCommand{ - OrgID: testOrgID, - Dashboard: simplejson.NewFromAny(map[string]any{ - "title": "Expect error", - }), - FolderUID: "123412321", - Overwrite: shouldOverwrite, - } - - _, err := callSaveWithResult(t, cmd, sc.sqlStore, nil) - assert.Equal(t, dashboards.ErrFolderNotFound, err) - }) - - permissionScenario(t, "When updating an existing dashboard by id without current version", func(t *testing.T, sc *permissionScenarioContext) { - cmd := dashboards.SaveDashboardCommand{ - OrgID: 1, - Dashboard: simplejson.NewFromAny(map[string]any{ - "id": sc.savedDashInGeneralFolder.ID, - "title": "test dash 23", - }), - FolderUID: sc.savedFolder.UID, - Overwrite: shouldOverwrite, - } - - _, err := callSaveWithResult(t, cmd, sc.sqlStore, nil) - assert.Equal(t, dashboards.ErrDashboardVersionMismatch, err) - }) - - permissionScenario(t, "When updating an existing dashboard by id with current version", func(t *testing.T, sc *permissionScenarioContext) { - cmd := dashboards.SaveDashboardCommand{ - OrgID: 1, - Dashboard: simplejson.NewFromAny(map[string]any{ - "id": sc.savedDashInGeneralFolder.ID, - "title": "Updated title", - "version": sc.savedDashInGeneralFolder.Version, - }), - FolderUID: sc.savedFolder.UID, - Overwrite: shouldOverwrite, - } - - res, _ := callSaveWithResult(t, cmd, sc.sqlStore, nil) - require.NotNil(t, res) - - _, err := sc.dashboardStore.GetDashboard(context.Background(), &dashboards.GetDashboardQuery{ - ID: sc.savedDashInGeneralFolder.ID, - OrgID: cmd.OrgID, - }) - - require.NoError(t, err) - }) - - permissionScenario(t, "When updating an existing dashboard by uid without current version", func(t *testing.T, sc *permissionScenarioContext) { - cmd := dashboards.SaveDashboardCommand{ - OrgID: 1, - Dashboard: simplejson.NewFromAny(map[string]any{ - "uid": sc.savedDashInFolder.UID, - "title": "test dash 23", - }), - FolderUID: "", - Overwrite: shouldOverwrite, - } - - _, err := callSaveWithResult(t, cmd, sc.sqlStore, nil) - assert.Equal(t, dashboards.ErrDashboardVersionMismatch, err) - }) - - permissionScenario(t, "When updating an existing dashboard by uid with current version", func(t *testing.T, sc *permissionScenarioContext) { - cmd := dashboards.SaveDashboardCommand{ - OrgID: 1, - Dashboard: simplejson.NewFromAny(map[string]any{ - "uid": sc.savedDashInFolder.UID, - "title": "Updated title", - "version": sc.savedDashInFolder.Version, - }), - FolderUID: "", - Overwrite: shouldOverwrite, - } - - res, _ := callSaveWithResult(t, cmd, sc.sqlStore, nil) - require.NotNil(t, res) - - _, err := sc.dashboardStore.GetDashboard(context.Background(), &dashboards.GetDashboardQuery{ - ID: sc.savedDashInFolder.ID, - OrgID: cmd.OrgID, - }) - require.NoError(t, err) - }) - - permissionScenario(t, "When creating a dashboard with same name as dashboard in other folder", func(t *testing.T, sc *permissionScenarioContext) { - cmd := dashboards.SaveDashboardCommand{ - OrgID: testOrgID, - Dashboard: simplejson.NewFromAny(map[string]any{ - "id": nil, - "title": sc.savedDashInFolder.Title, - }), - FolderUID: sc.savedDashInFolder.FolderUID, - Overwrite: shouldOverwrite, - } - - _, err := callSaveWithResult(t, cmd, sc.sqlStore, nil) - require.NoError(t, err) - }) - - permissionScenario(t, "When creating a dashboard with same name as dashboard in General folder", func(t *testing.T, sc *permissionScenarioContext) { - cmd := dashboards.SaveDashboardCommand{ - OrgID: testOrgID, - Dashboard: simplejson.NewFromAny(map[string]any{ - "id": nil, - "title": sc.savedDashInGeneralFolder.Title, - }), - FolderUID: sc.savedDashInGeneralFolder.FolderUID, - Overwrite: shouldOverwrite, - } - - _, err := callSaveWithResult(t, cmd, sc.sqlStore, nil) - require.NoError(t, err) - }) - - permissionScenario(t, "When creating a folder with same name as existing folder", func(t *testing.T, sc *permissionScenarioContext) { - cmd := dashboards.SaveDashboardCommand{ - OrgID: testOrgID, - Dashboard: simplejson.NewFromAny(map[string]any{ - "id": nil, - "title": sc.savedFolder.Title, - }), - IsFolder: true, - Overwrite: shouldOverwrite, - } - - _, err := callSaveWithResult(t, cmd, sc.sqlStore, nil) - require.NoError(t, err) - }) - }) - - t.Run("and overwrite flag is set to true", func(t *testing.T) { - const shouldOverwrite = true - - permissionScenario(t, "When updating an existing dashboard by id without current version", func(t *testing.T, sc *permissionScenarioContext) { - cmd := dashboards.SaveDashboardCommand{ - OrgID: 1, - Dashboard: simplejson.NewFromAny(map[string]any{ - "id": sc.savedDashInGeneralFolder.ID, - "title": "Updated title", - }), - FolderUID: sc.savedFolder.UID, - Overwrite: shouldOverwrite, - } - - res, _ := callSaveWithResult(t, cmd, sc.sqlStore, nil) - require.NotNil(t, res) - - _, err := sc.dashboardStore.GetDashboard(context.Background(), &dashboards.GetDashboardQuery{ - ID: sc.savedDashInGeneralFolder.ID, - OrgID: cmd.OrgID, - }) - require.NoError(t, err) - }) - - permissionScenario(t, "When updating an existing dashboard by uid without current version", func(t *testing.T, sc *permissionScenarioContext) { - cmd := dashboards.SaveDashboardCommand{ - OrgID: 1, - Dashboard: simplejson.NewFromAny(map[string]any{ - "uid": sc.savedDashInFolder.UID, - "title": "Updated title", - }), - FolderUID: "", - Overwrite: shouldOverwrite, - } - - res, _ := callSaveWithResult(t, cmd, sc.sqlStore, nil) - require.NotNil(t, res) - - _, err := sc.dashboardStore.GetDashboard(context.Background(), &dashboards.GetDashboardQuery{ - ID: sc.savedDashInFolder.ID, - OrgID: cmd.OrgID, - }) - require.NoError(t, err) - }) - - permissionScenario(t, "When updating uid for existing dashboard using id", func(t *testing.T, sc *permissionScenarioContext) { - cmd := dashboards.SaveDashboardCommand{ - OrgID: 1, - Dashboard: simplejson.NewFromAny(map[string]any{ - "id": sc.savedDashInFolder.ID, - "uid": "new-uid", - "title": sc.savedDashInFolder.Title, - }), - Overwrite: shouldOverwrite, - } - - res, _ := callSaveWithResult(t, cmd, sc.sqlStore, nil) - require.NotNil(t, res) - assert.Equal(t, sc.savedDashInFolder.ID, res.ID) - assert.Equal(t, "new-uid", res.UID) - - _, err := sc.dashboardStore.GetDashboard(context.Background(), &dashboards.GetDashboardQuery{ - ID: sc.savedDashInFolder.ID, - OrgID: cmd.OrgID, - }) - require.NoError(t, err) - }) - - permissionScenario(t, "When updating uid to an existing uid for existing dashboard using id", func(t *testing.T, sc *permissionScenarioContext) { - cmd := dashboards.SaveDashboardCommand{ - OrgID: 1, - Dashboard: simplejson.NewFromAny(map[string]any{ - "id": sc.savedDashInFolder.ID, - "uid": sc.savedDashInGeneralFolder.UID, - "title": sc.savedDashInFolder.Title, - }), - Overwrite: shouldOverwrite, - } - - _, err := callSaveWithResult(t, cmd, sc.sqlStore, nil) - assert.Equal(t, dashboards.ErrDashboardWithSameUIDExists, err) - }) - - permissionScenario(t, "When creating a dashboard with same name as dashboard in other folder", func(t *testing.T, sc *permissionScenarioContext) { - t.Skip() - - cmd := dashboards.SaveDashboardCommand{ - OrgID: testOrgID, - Dashboard: simplejson.NewFromAny(map[string]any{ - "id": nil, - "title": sc.savedDashInFolder.Title, - }), - FolderUID: sc.savedDashInFolder.FolderUID, - Overwrite: shouldOverwrite, - } - - res, _ := callSaveWithResult(t, cmd, sc.sqlStore, nil) - require.NotNil(t, res) - assert.Equal(t, sc.savedDashInFolder.ID, res.ID) - assert.Equal(t, sc.savedDashInFolder.UID, res.UID) - - _, err := sc.dashboardStore.GetDashboard(context.Background(), &dashboards.GetDashboardQuery{ - ID: res.ID, - OrgID: cmd.OrgID, - }) - require.NoError(t, err) - }) - - permissionScenario(t, "When creating a dashboard with same name as dashboard in General folder", func(t *testing.T, sc *permissionScenarioContext) { - t.Skip() - - cmd := dashboards.SaveDashboardCommand{ - OrgID: testOrgID, - Dashboard: simplejson.NewFromAny(map[string]any{ - "id": nil, - "title": sc.savedDashInGeneralFolder.Title, - }), - FolderUID: sc.savedDashInGeneralFolder.FolderUID, - Overwrite: shouldOverwrite, - } - - res, _ := callSaveWithResult(t, cmd, sc.sqlStore, nil) - require.NotNil(t, res) - assert.Equal(t, sc.savedDashInGeneralFolder.ID, res.ID) - assert.Equal(t, sc.savedDashInGeneralFolder.UID, res.UID) - - _, err := sc.dashboardStore.GetDashboard(context.Background(), &dashboards.GetDashboardQuery{ - ID: res.ID, - OrgID: cmd.OrgID, - }) - require.NoError(t, err) - }) - - permissionScenario(t, "When updating existing folder to a dashboard using id", func(t *testing.T, sc *permissionScenarioContext) { - cmd := dashboards.SaveDashboardCommand{ - OrgID: 1, - Dashboard: simplejson.NewFromAny(map[string]any{ - "id": sc.savedFolder.ID, - "title": "new title", - }), - IsFolder: false, - Overwrite: shouldOverwrite, - } - - _, err := callSaveWithResult(t, cmd, sc.sqlStore, nil) - assert.Equal(t, dashboards.ErrDashboardTypeMismatch, err) - }) - - permissionScenario(t, "When updating existing dashboard to a folder using id", func(t *testing.T, sc *permissionScenarioContext) { - cmd := dashboards.SaveDashboardCommand{ - OrgID: 1, - Dashboard: simplejson.NewFromAny(map[string]any{ - "id": sc.savedDashInFolder.ID, - "title": "new folder title", - }), - IsFolder: true, - Overwrite: shouldOverwrite, - } - - _, err := callSaveWithResult(t, cmd, sc.sqlStore, nil) - assert.Equal(t, dashboards.ErrDashboardTypeMismatch, err) - }) - - permissionScenario(t, "When updating existing folder to a dashboard using uid", func(t *testing.T, sc *permissionScenarioContext) { - cmd := dashboards.SaveDashboardCommand{ - OrgID: 1, - Dashboard: simplejson.NewFromAny(map[string]any{ - "uid": sc.savedFolder.UID, - "title": "new title", - }), - IsFolder: false, - Overwrite: shouldOverwrite, - } - - _, err := callSaveWithResult(t, cmd, sc.sqlStore, nil) - assert.Equal(t, dashboards.ErrDashboardTypeMismatch, err) - }) - - permissionScenario(t, "When updating existing dashboard to a folder using uid", func(t *testing.T, sc *permissionScenarioContext) { - cmd := dashboards.SaveDashboardCommand{ - OrgID: 1, - Dashboard: simplejson.NewFromAny(map[string]any{ - "uid": sc.savedDashInFolder.UID, - "title": "new folder title", - }), - IsFolder: true, - Overwrite: shouldOverwrite, - } - - _, err := callSaveWithResult(t, cmd, sc.sqlStore, nil) - assert.Equal(t, dashboards.ErrDashboardTypeMismatch, err) - }) - - permissionScenario(t, "When updating existing folder to a dashboard using title", func(t *testing.T, sc *permissionScenarioContext) { - cmd := dashboards.SaveDashboardCommand{ - OrgID: 1, - Dashboard: simplejson.NewFromAny(map[string]any{ - "title": sc.savedFolder.Title, - }), - IsFolder: false, - Overwrite: shouldOverwrite, - } - - _, err := callSaveWithResult(t, cmd, sc.sqlStore, nil) - require.NoError(t, err) - }) - - permissionScenario(t, "When updating existing dashboard to a folder using title", func(t *testing.T, sc *permissionScenarioContext) { - cmd := dashboards.SaveDashboardCommand{ - OrgID: 1, - Dashboard: simplejson.NewFromAny(map[string]any{ - "title": sc.savedDashInGeneralFolder.Title, - }), - IsFolder: true, - Overwrite: shouldOverwrite, - } - - _, err := callSaveWithResult(t, cmd, sc.sqlStore, nil) - require.NoError(t, err) - }) - }) - }) - }) -} - -func TestIntegrationDashboardServicePermissions(t *testing.T) { - if testing.Short() { - t.Skip("skipping integration test") - } - t.Run("Given saved folders and dashboards in organization A", func(t *testing.T) { - permissionScenario(t, "When creating a new dashboard in the General folder, requires create permissions scoped to the general folder", - func(t *testing.T, sc *permissionScenarioContext) { - sqlStore := db.InitTestDB(t) - cmd := dashboards.SaveDashboardCommand{ - OrgID: testOrgID, - Dashboard: simplejson.NewFromAny(map[string]any{ - "title": "Dash", - }), - UserID: 10000, - Overwrite: true, - } - - permissions := map[int64]map[string][]string{ - testOrgID: { - dashboards.ActionDashboardsWrite: {dashboards.ScopeDashboardsAll}, - }, - } - _, err := callSaveWithResult(t, cmd, sqlStore, permissions) - assert.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err) - - permissions = map[int64]map[string][]string{ - testOrgID: { - dashboards.ActionDashboardsCreate: {dashboards.ScopeFoldersProvider.GetResourceScopeUID(accesscontrol.GeneralFolderUID)}, - }, - } - _, err = callSaveWithResult(t, cmd, sqlStore, permissions) - assert.Nil(t, err) - }) - - permissionScenario(t, "When creating a new dashboard in other folder, requires create permissions scoped to the other folder", func(t *testing.T, sc *permissionScenarioContext) { - cmd := dashboards.SaveDashboardCommand{ - OrgID: testOrgID, - Dashboard: simplejson.NewFromAny(map[string]any{ - "title": "Dash", - }), - FolderUID: sc.otherSavedFolder.UID, - UserID: 10000, - Overwrite: true, - } - - permissions := map[int64]map[string][]string{ - testOrgID: { - dashboards.ActionDashboardsCreate: {dashboards.ScopeFoldersProvider.GetResourceScopeUID("different_folder_uid")}, - }, - } - _, err := callSaveWithResult(t, cmd, sc.sqlStore, permissions) - assert.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err) - - permissions = map[int64]map[string][]string{ - testOrgID: { - dashboards.ActionDashboardsCreate: {dashboards.ScopeFoldersProvider.GetResourceScopeUID(sc.otherSavedFolder.UID)}, - }, - } - _, err = callSaveWithResult(t, cmd, sc.sqlStore, permissions) - assert.Nil(t, err) - }) - - permissionScenario(t, "When creating a new dashboard by existing UID in folder, requires write permissions on the existing dashboard", func(t *testing.T, sc *permissionScenarioContext) { - cmd := dashboards.SaveDashboardCommand{ - OrgID: testOrgID, - Dashboard: simplejson.NewFromAny(map[string]any{ - "uid": sc.savedDashInFolder.UID, - "title": "New dash", - }), - FolderUID: sc.savedFolder.UID, - UserID: 10000, - Overwrite: true, - } - - permissions := map[int64]map[string][]string{ - testOrgID: { - dashboards.ActionDashboardsWrite: {dashboards.ScopeDashboardsProvider.GetResourceScopeUID("different_dash_uid")}, - }, - } - _, err := callSaveWithResult(t, cmd, sc.sqlStore, permissions) - assert.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err) - - permissions = map[int64]map[string][]string{ - testOrgID: { - dashboards.ActionDashboardsWrite: {dashboards.ScopeDashboardsProvider.GetResourceScopeUID(sc.savedDashInFolder.UID)}, - }, - } - _, err = callSaveWithResult(t, cmd, sc.sqlStore, permissions) - assert.Nil(t, err) - }) - - permissionScenario(t, "When moving a dashboard by existing uid to other folder from General folder, requires dashboard creation permissions on the destination folder and write access to the dashboard", func(t *testing.T, sc *permissionScenarioContext) { - cmd := dashboards.SaveDashboardCommand{ - OrgID: testOrgID, - Dashboard: simplejson.NewFromAny(map[string]any{ - "uid": sc.savedDashInGeneralFolder.UID, - "title": "Dash", - }), - FolderUID: sc.otherSavedFolder.UID, - UserID: 10000, - Overwrite: true, - } - - // Perms to write dashboard but not create dashboards in the destination folder - permissions := map[int64]map[string][]string{ - testOrgID: { - dashboards.ActionDashboardsWrite: {dashboards.ScopeDashboardsProvider.GetResourceScopeUID(sc.savedDashInGeneralFolder.UID)}, - }, - } - _, err := callSaveWithResult(t, cmd, sc.sqlStore, permissions) - assert.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err) - - // Perms to create dashboards in the destination folder but not write the dashboard - permissions = map[int64]map[string][]string{ - testOrgID: { - dashboards.ActionDashboardsCreate: {dashboards.ScopeFoldersProvider.GetResourceScopeUID(sc.otherSavedFolder.UID)}, - }, - } - _, err = callSaveWithResult(t, cmd, sc.sqlStore, permissions) - assert.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err) - - // Perms to write dashboard and create dashboards in the destination folder - permissions = map[int64]map[string][]string{ - testOrgID: { - dashboards.ActionDashboardsWrite: {dashboards.ScopeDashboardsProvider.GetResourceScopeUID(sc.savedDashInGeneralFolder.UID)}, - dashboards.ActionDashboardsCreate: {dashboards.ScopeFoldersProvider.GetResourceScopeUID(sc.otherSavedFolder.UID)}, - }, - } - _, err = callSaveWithResult(t, cmd, sc.sqlStore, permissions) - assert.Nil(t, err) - }) - - permissionScenario(t, "When moving a dashboard by existing uid to the General folder from other folder, requires dashboard creation permissions on the general folder and write access to the dashboard", func(t *testing.T, sc *permissionScenarioContext) { - cmd := dashboards.SaveDashboardCommand{ - OrgID: testOrgID, - Dashboard: simplejson.NewFromAny(map[string]any{ - "uid": sc.savedDashInFolder.UID, - "title": "Dash", - }), - FolderUID: "", - UserID: 10000, - Overwrite: true, - } - - // Perms to write dashboard but not create dashboards in the destination folder - permissions := map[int64]map[string][]string{ - testOrgID: { - dashboards.ActionDashboardsWrite: {dashboards.ScopeDashboardsProvider.GetResourceScopeUID(sc.savedDashInFolder.UID)}, - }, - } - _, err := callSaveWithResult(t, cmd, sc.sqlStore, permissions) - assert.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err) - - // Perms to create dashboards in the destination folder but not write the dashboard - permissions = map[int64]map[string][]string{ - testOrgID: { - dashboards.ActionDashboardsCreate: {dashboards.ScopeFoldersProvider.GetResourceScopeUID(accesscontrol.GeneralFolderUID)}, - }, - } - _, err = callSaveWithResult(t, cmd, sc.sqlStore, permissions) - assert.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err) - - // Perms to write dashboard and create dashboards in the destination folder - permissions = map[int64]map[string][]string{ - testOrgID: { - dashboards.ActionDashboardsWrite: {dashboards.ScopeDashboardsProvider.GetResourceScopeUID(sc.savedDashInFolder.UID)}, - dashboards.ActionDashboardsCreate: {dashboards.ScopeFoldersProvider.GetResourceScopeUID(accesscontrol.GeneralFolderUID)}, - }, - } - _, err = callSaveWithResult(t, cmd, sc.sqlStore, permissions) - assert.NoError(t, err) - }) - }) -} - -type permissionScenarioContext struct { - sqlStore db.DB - dashboardStore dashboards.Store - savedFolder *dashboards.Dashboard - savedDashInFolder *dashboards.Dashboard - otherSavedFolder *dashboards.Dashboard - savedDashInGeneralFolder *dashboards.Dashboard -} - -type permissionScenarioFunc func(t *testing.T, sc *permissionScenarioContext) - -func permissionScenario(t *testing.T, desc string, fn permissionScenarioFunc) { - t.Helper() - - t.Run(desc, func(t *testing.T) { - features := featuremgmt.WithFeatures() - cfg := setting.NewCfg() - sqlStore := db.InitTestDB(t) - quotaService := quotatest.New(false, nil) - ac := actest.FakeAccessControl{ExpectedEvaluate: true} - dashboardStore, err := database.ProvideDashboardStore(sqlStore, cfg, features, tagimpl.ProvideService(sqlStore)) - require.NoError(t, err) - folderStore := folderimpl.ProvideDashboardFolderStore(sqlStore) - folderPermissions := accesscontrolmock.NewMockedPermissionsService() - folderPermissions.On("SetPermissions", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return([]accesscontrol.ResourcePermission{}, nil) - tracer := tracing.InitializeTracerForTest() - publicDashboardFakeService := publicdashboards.NewFakePublicDashboardServiceWrapper(t) - folderStore2 := folderimpl.ProvideStore(sqlStore) - folderService := folderimpl.ProvideService( - folderStore2, - actest.FakeAccessControl{ExpectedEvaluate: true}, - bus.ProvideBus(tracer), - dashboardStore, - folderStore, - nil, - sqlStore, - features, - supportbundlestest.NewFakeBundleService(), - publicDashboardFakeService, - cfg, - nil, - tracer, - nil, - dualwrite.ProvideTestService(), - sort.ProvideService(), - apiserver.WithoutRestConfig, - ) - dashboardPermissions := accesscontrolmock.NewMockedPermissionsService() - dashboardService, err := ProvideDashboardServiceImpl( - cfg, dashboardStore, folderStore, - featuremgmt.WithFeatures(), - folderPermissions, - ac, - actest.FakeService{}, - folderService, - nil, - client.MockTestRestConfig{}, - nil, - quotaService, - nil, - nil, - nil, - dualwrite.ProvideTestService(), - sort.ProvideService(), - serverlock.ProvideService(sqlStore, tracing.InitializeTracerForTest()), - kvstore.NewFakeKVStore(), - ) - dashboardService.RegisterDashboardPermissions(dashboardPermissions) - require.NoError(t, err) - - savedFolder := saveTestFolder(t, "Saved folder", testOrgID, sqlStore) - savedDashInFolder := saveTestDashboard(t, "Saved dash in folder", testOrgID, savedFolder.UID, sqlStore) - saveTestDashboard(t, "Other saved dash in folder", testOrgID, savedFolder.UID, sqlStore) - savedDashInGeneralFolder := saveTestDashboard(t, "Saved dashboard in general folder", testOrgID, "", sqlStore) - otherSavedFolder := saveTestFolder(t, "Other saved folder", testOrgID, sqlStore) - - require.Equal(t, "Saved folder", savedFolder.Title) - require.Equal(t, "saved-folder", savedFolder.Slug) - require.NotEqual(t, int64(0), savedFolder.ID) - require.True(t, savedFolder.IsFolder) - require.NotEmpty(t, savedFolder.UID) - - require.Equal(t, "Saved dash in folder", savedDashInFolder.Title) - require.Equal(t, "saved-dash-in-folder", savedDashInFolder.Slug) - require.NotEqual(t, int64(0), savedDashInFolder.ID) - require.False(t, savedDashInFolder.IsFolder) - require.NotEmpty(t, savedDashInFolder.UID) - - sc := &permissionScenarioContext{ - sqlStore: sqlStore, - savedDashInFolder: savedDashInFolder, - otherSavedFolder: otherSavedFolder, - savedDashInGeneralFolder: savedDashInGeneralFolder, - savedFolder: savedFolder, - dashboardStore: dashboardStore, - } - - fn(t, sc) - }) -} - -func callSaveWithResult(t *testing.T, cmd dashboards.SaveDashboardCommand, sqlStore db.DB, permissions map[int64]map[string][]string) (*dashboards.Dashboard, error) { - t.Helper() - - features := featuremgmt.WithFeatures() - dto := toSaveDashboardDto(cmd) - var ac accesscontrol.AccessControl - ac = actest.FakeAccessControl{ExpectedEvaluate: true} - if permissions != nil { - dto.User = &user.SignedInUser{UserID: cmd.UserID, OrgID: testOrgID, Permissions: permissions} - ac = acimpl.ProvideAccessControl(features) - } - cfg := setting.NewCfg() - quotaService := quotatest.New(false, nil) - dashboardStore, err := database.ProvideDashboardStore(sqlStore, cfg, features, tagimpl.ProvideService(sqlStore)) - require.NoError(t, err) - folderStore := folderimpl.ProvideDashboardFolderStore(sqlStore) - folderPermissions := accesscontrolmock.NewMockedPermissionsService() - folderPermissions.On("SetPermissions", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return([]accesscontrol.ResourcePermission{}, nil) - tracer := tracing.InitializeTracerForTest() - publicDashboardFakeService := publicdashboards.NewFakePublicDashboardServiceWrapper(t) - folderStore2 := folderimpl.ProvideStore(sqlStore) - folderService := folderimpl.ProvideService( - folderStore2, - actest.FakeAccessControl{ExpectedEvaluate: true}, - bus.ProvideBus(tracer), - dashboardStore, - folderStore, - nil, - sqlStore, - features, - supportbundlestest.NewFakeBundleService(), - publicDashboardFakeService, - cfg, - nil, - tracer, - nil, - dualwrite.ProvideTestService(), - sort.ProvideService(), - apiserver.WithoutRestConfig, - ) - dashboardPermissions := accesscontrolmock.NewMockedPermissionsService() - dashboardPermissions.On("SetPermissions", - mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return([]accesscontrol.ResourcePermission{}, nil) - service, err := ProvideDashboardServiceImpl( - cfg, dashboardStore, folderStore, - featuremgmt.WithFeatures(), - folderPermissions, - ac, - actest.FakeService{}, - folderService, - nil, - client.MockTestRestConfig{}, - nil, - quotaService, - nil, - nil, - nil, - dualwrite.ProvideTestService(), - sort.ProvideService(), - serverlock.ProvideService(sqlStore, tracing.InitializeTracerForTest()), - kvstore.NewFakeKVStore(), - ) - require.NoError(t, err) - service.RegisterDashboardPermissions(dashboardPermissions) - return service.SaveDashboard(context.Background(), &dto, false) -} - -func saveTestDashboard(t *testing.T, title string, orgID int64, folderUID string, sqlStore db.DB) *dashboards.Dashboard { - t.Helper() - - cmd := dashboards.SaveDashboardCommand{ - OrgID: orgID, - FolderUID: folderUID, - IsFolder: false, - Dashboard: simplejson.NewFromAny(map[string]any{ - "id": nil, - "title": title, - }), - } - - dto := dashboards.SaveDashboardDTO{ - OrgID: orgID, - Dashboard: cmd.GetDashboardModel(), - User: &user.SignedInUser{ - UserID: 1, - OrgRole: org.RoleAdmin, - }, - } - features := featuremgmt.WithFeatures() - cfg := setting.NewCfg() - quotaService := quotatest.New(false, nil) - dashboardStore, err := database.ProvideDashboardStore(sqlStore, cfg, features, tagimpl.ProvideService(sqlStore)) - require.NoError(t, err) - folderStore := folderimpl.ProvideDashboardFolderStore(sqlStore) - dashboardPermissions := accesscontrolmock.NewMockedPermissionsService() - dashboardPermissions.On("SetPermissions", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return([]accesscontrol.ResourcePermission{}, nil) - tracer := tracing.InitializeTracerForTest() - publicDashboardFakeService := publicdashboards.NewFakePublicDashboardServiceWrapper(t) - folderStore2 := folderimpl.ProvideStore(sqlStore) - folderService := folderimpl.ProvideService(folderStore2, - actest.FakeAccessControl{ExpectedEvaluate: true}, - bus.ProvideBus(tracer), - dashboardStore, - folderStore, - nil, - sqlStore, - features, - supportbundlestest.NewFakeBundleService(), - publicDashboardFakeService, - cfg, - nil, - tracer, - nil, - dualwrite.ProvideTestService(), - sort.ProvideService(), - apiserver.WithoutRestConfig, - ) - service, err := ProvideDashboardServiceImpl( - cfg, dashboardStore, folderStore, - features, - accesscontrolmock.NewMockedPermissionsService(), - actest.FakeAccessControl{ExpectedEvaluate: true}, - actest.FakeService{}, - folderService, - nil, - client.MockTestRestConfig{}, - nil, - quotaService, - nil, - nil, - nil, - dualwrite.ProvideTestService(), - sort.ProvideService(), - serverlock.ProvideService(sqlStore, tracing.InitializeTracerForTest()), - kvstore.NewFakeKVStore(), - ) - require.NoError(t, err) - service.RegisterDashboardPermissions(dashboardPermissions) - res, err := service.SaveDashboard(context.Background(), &dto, false) - - require.NoError(t, err) - - return res -} - -func saveTestFolder(t *testing.T, title string, orgID int64, sqlStore db.DB) *dashboards.Dashboard { - t.Helper() - cmd := dashboards.SaveDashboardCommand{ - OrgID: orgID, - FolderUID: "", - IsFolder: true, - Dashboard: simplejson.NewFromAny(map[string]any{ - "id": nil, - "title": title, - }), - } - - dto := dashboards.SaveDashboardDTO{ - OrgID: orgID, - Dashboard: cmd.GetDashboardModel(), - User: &user.SignedInUser{ - OrgID: orgID, - UserID: 1, - OrgRole: org.RoleAdmin, - Permissions: map[int64]map[string][]string{ - orgID: {dashboards.ActionFoldersWrite: {dashboards.ScopeFoldersAll}, dashboards.ActionDashboardsWrite: {dashboards.ScopeDashboardsAll}}, - }, - }, - } - - features := featuremgmt.WithFeatures() - cfg := setting.NewCfg() - quotaService := quotatest.New(false, nil) - dashboardStore, err := database.ProvideDashboardStore(sqlStore, cfg, features, tagimpl.ProvideService(sqlStore)) - require.NoError(t, err) - folderStore := folderimpl.ProvideDashboardFolderStore(sqlStore) - folderPermissions := accesscontrolmock.NewMockedPermissionsService() - tracer := tracing.InitializeTracerForTest() - publicDashboardFakeService := publicdashboards.NewFakePublicDashboardServiceWrapper(t) - folderStore2 := folderimpl.ProvideStore(sqlStore) - folderService := folderimpl.ProvideService(folderStore2, - actest.FakeAccessControl{ExpectedEvaluate: true}, - bus.ProvideBus(tracer), - dashboardStore, - folderStore, - nil, - sqlStore, - features, - supportbundlestest.NewFakeBundleService(), - publicDashboardFakeService, - cfg, - nil, - tracer, - nil, - dualwrite.ProvideTestService(), - sort.ProvideService(), - apiserver.WithoutRestConfig, - ) - folderPermissions.On("SetPermissions", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return([]accesscontrol.ResourcePermission{}, nil) - service, err := ProvideDashboardServiceImpl( - cfg, dashboardStore, folderStore, - featuremgmt.WithFeatures(), - folderPermissions, - actest.FakeAccessControl{ExpectedEvaluate: true}, - actest.FakeService{}, - folderService, - nil, - client.MockTestRestConfig{}, - nil, - quotaService, - nil, - nil, - nil, - dualwrite.ProvideTestService(), - sort.ProvideService(), - serverlock.ProvideService(sqlStore, tracing.InitializeTracerForTest()), - kvstore.NewFakeKVStore(), - ) - require.NoError(t, err) - service.RegisterDashboardPermissions(accesscontrolmock.NewMockedPermissionsService()) - res, err := service.SaveDashboard(context.Background(), &dto, false) - require.NoError(t, err) - - return res -} - -func toSaveDashboardDto(cmd dashboards.SaveDashboardCommand) dashboards.SaveDashboardDTO { - dash := (&cmd).GetDashboardModel() - - return dashboards.SaveDashboardDTO{ - Dashboard: dash, - Message: cmd.Message, - OrgID: cmd.OrgID, - User: &user.SignedInUser{UserID: cmd.UserID}, - Overwrite: cmd.Overwrite, - } -} diff --git a/pkg/services/dashboards/service/dashboard_service_test.go b/pkg/services/dashboards/service/dashboard_service_test.go index 68da3b789cc..34a9279bec4 100644 --- a/pkg/services/dashboards/service/dashboard_service_test.go +++ b/pkg/services/dashboards/service/dashboard_service_test.go @@ -47,8 +47,13 @@ import ( "github.com/grafana/grafana/pkg/storage/unified/resource" "github.com/grafana/grafana/pkg/storage/unified/resourcepb" "github.com/grafana/grafana/pkg/storage/unified/search" + "github.com/grafana/grafana/pkg/tests/testsuite" ) +func TestMain(m *testing.M) { + testsuite.Run(m) +} + func TestDashboardService(t *testing.T) { t.Run("Dashboard service tests", func(t *testing.T) { fakeStore := dashboards.FakeDashboardStore{} diff --git a/pkg/tests/api/dashboards/api_dashboards_test.go b/pkg/tests/api/dashboards/api_dashboards_test.go index 37a1f195044..0d87e0c6f00 100644 --- a/pkg/tests/api/dashboards/api_dashboards_test.go +++ b/pkg/tests/api/dashboards/api_dashboards_test.go @@ -21,8 +21,11 @@ import ( "github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/folder" + "github.com/grafana/grafana/pkg/services/org" "github.com/grafana/grafana/pkg/services/plugindashboards" "github.com/grafana/grafana/pkg/services/search/model" + "github.com/grafana/grafana/pkg/services/user" + "github.com/grafana/grafana/pkg/tests" "github.com/grafana/grafana/pkg/tests/testinfra" "github.com/grafana/grafana/pkg/tests/testsuite" "github.com/grafana/grafana/pkg/util" @@ -32,21 +35,243 @@ func TestMain(m *testing.M) { testsuite.Run(m) } +func TestIntegrationDashboardServiceValidation(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test") + } + + dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ + DisableAnonymous: true, + EnableFeatureToggles: []string{featuremgmt.FlagKubernetesClientDashboardsFolders}, + }) + grafanaListedAddr, env := testinfra.StartGrafanaEnv(t, dir, path) + + orgPayload := map[string]interface{}{ + "name": "Org B", + } + orgPayloadBytes, err := json.Marshal(orgPayload) + require.NoError(t, err) + + orgURL := fmt.Sprintf("http://admin:admin@%s/api/orgs", grafanaListedAddr) + orgResp, err := http.Post(orgURL, "application/json", bytes.NewBuffer(orgPayloadBytes)) // nolint:gosec + require.NoError(t, err) + assert.Equal(t, http.StatusOK, orgResp.StatusCode) + err = orgResp.Body.Close() + require.NoError(t, err) + + tests.CreateUser(t, env.SQLStore, env.Cfg, user.CreateUserCommand{ + DefaultOrgRole: string(org.RoleAdmin), + Login: "admin-org2", + Password: "admin", + IsAdmin: true, + OrgID: 2, + }) + + savedFolder := createFolder(t, grafanaListedAddr, "Saved folder") + savedDashInFolder := createDashboard(t, grafanaListedAddr, "Saved dash in folder", savedFolder.ID, savedFolder.UID) // nolint:staticcheck + savedDashInGeneralFolder := createDashboard(t, grafanaListedAddr, "Saved dashboard in general folder", 0, "") + + t.Run("When saving a dashboard with non-existing id in org A", func(t *testing.T) { + resp, err := postDashboard(t, grafanaListedAddr, "admin", "admin", map[string]interface{}{ + "dashboard": map[string]interface{}{ + "id": 123412321, + "title": "Expect error", + }, + }) + require.NoError(t, err) + assert.Equal(t, http.StatusNotFound, resp.StatusCode) + err = resp.Body.Close() + require.NoError(t, err) + }) + + t.Run("When saving a dashboard with existing ID from org A in org B", func(t *testing.T) { + resp, err := postDashboard(t, grafanaListedAddr, "admin-org2", "admin", map[string]interface{}{ + "dashboard": map[string]interface{}{ + "id": savedDashInFolder.ID, // nolint:staticcheck + "title": "Expect error", + }, + }) + require.NoError(t, err) + assert.Equal(t, http.StatusNotFound, resp.StatusCode) + err = resp.Body.Close() + require.NoError(t, err) + }) + + t.Run("When saving a dashboard with same UID in org A and org B, should be okay", func(t *testing.T) { + resp, err := postDashboard(t, grafanaListedAddr, "admin-org2", "admin", map[string]interface{}{ + "dashboard": map[string]interface{}{ + "uid": savedDashInFolder.UID, + "title": "Saved dash in folder", + }, + }) + require.NoError(t, err) + assert.Equal(t, http.StatusOK, resp.StatusCode) + err = resp.Body.Close() + require.NoError(t, err) + }) + + t.Run("When creating a dashboard in General folder with same name as dashboard in other folder", func(t *testing.T) { + resp, err := postDashboard(t, grafanaListedAddr, "admin", "admin", map[string]interface{}{ + "dashboard": map[string]interface{}{ + "title": "Saved dash in folder", + }, + }) + require.NoError(t, err) + assert.Equal(t, http.StatusOK, resp.StatusCode) + err = resp.Body.Close() + require.NoError(t, err) + }) + t.Run("When creating a dashboard in other folder with same name as dashboard in General folder", func(t *testing.T) { + resp, err := postDashboard(t, grafanaListedAddr, "admin", "admin", map[string]interface{}{ + "dashboard": map[string]interface{}{ + "uid": savedDashInFolder, + "title": "Dash with existing uid in other org", + }, + }) + require.NoError(t, err) + assert.Equal(t, http.StatusOK, resp.StatusCode) + err = resp.Body.Close() + require.NoError(t, err) + }) + + t.Run("When creating a folder with same name as dashboard in other folder", func(t *testing.T) { + f := createFolder(t, grafanaListedAddr, "Saved dashboard in general folder") + require.Equal(t, f.Title, "Saved dashboard in general folder") + }) + + t.Run("When saving a dashboard without id and uid and unique title in folder", func(t *testing.T) { + resp, err := postDashboard(t, grafanaListedAddr, "admin", "admin", map[string]interface{}{ + "dashboard": map[string]interface{}{ + "title": "Unique", + }, + }) + require.NoError(t, err) + assert.Equal(t, http.StatusOK, resp.StatusCode) + err = resp.Body.Close() + require.NoError(t, err) + }) + + t.Run("When saving a dashboard with id 0", func(t *testing.T) { + resp, err := postDashboard(t, grafanaListedAddr, "admin", "admin", map[string]interface{}{ + "dashboard": map[string]interface{}{ + "id": 0, + "title": "Dash with zero id", + }, + }) + require.NoError(t, err) + assert.Equal(t, http.StatusOK, resp.StatusCode) + err = resp.Body.Close() + require.NoError(t, err) + }) + + t.Run("When saving a dashboard in non-existing folder", func(t *testing.T) { + resp, err := postDashboard(t, grafanaListedAddr, "admin", "admin", map[string]interface{}{ + "dashboard": map[string]interface{}{ + "title": "no folder", + }, + "folderUid": "non-existing-folder", + }) + require.NoError(t, err) + assert.Equal(t, http.StatusBadRequest, resp.StatusCode) + err = resp.Body.Close() + require.NoError(t, err) + }) + + t.Run("When saving a dashboard with incorrect version but no overwrite", func(t *testing.T) { + resp, err := postDashboard(t, grafanaListedAddr, "admin", "admin", map[string]interface{}{ + "dashboard": map[string]interface{}{ + "uid": savedDashInFolder.UID, + "version": 1, + }, + "folderUid": savedDashInFolder.FolderUID, + }) + require.NoError(t, err) + assert.Equal(t, http.StatusBadRequest, resp.StatusCode) + err = resp.Body.Close() + require.NoError(t, err) + }) + + t.Run("When saving a dashboard with current version and overwrite is true", func(t *testing.T) { + resp, err := postDashboard(t, grafanaListedAddr, "admin", "admin", map[string]interface{}{ + "dashboard": map[string]interface{}{ + "uid": savedDashInFolder.UID, + "version": savedDashInFolder.Version, + "title": "Saved dash in folder", + }, + "folderUid": savedDashInFolder.FolderUID, + }) + require.NoError(t, err) + assert.Equal(t, http.StatusOK, resp.StatusCode) + err = resp.Body.Close() + require.NoError(t, err) + }) + + t.Run("When saving a dashboard with no version set and title set to a folder title", func(t *testing.T) { + resp, err := postDashboard(t, grafanaListedAddr, "admin", "admin", map[string]interface{}{ + "dashboard": map[string]interface{}{ + "uid": savedDashInFolder.UID, + "title": "Saved folder", + }, + "folderUid": savedDashInFolder.FolderUID, + "overwrite": true, + }) + require.NoError(t, err) + assert.Equal(t, http.StatusOK, resp.StatusCode) + err = resp.Body.Close() + require.NoError(t, err) + }) + + t.Run("When updating uid with id", func(t *testing.T) { + resp, err := postDashboard(t, grafanaListedAddr, "admin", "admin", map[string]interface{}{ + "dashboard": map[string]interface{}{ + "id": savedDashInFolder.ID, // nolint:staticcheck + "uid": "new-uid", + "title": "Updated title", + }, + "folderUid": savedDashInFolder.FolderUID, + "overwrite": true, + }) + require.NoError(t, err) + assert.Equal(t, http.StatusOK, resp.StatusCode) + err = resp.Body.Close() + require.NoError(t, err) + }) + t.Run("When updating uid with a dashboard already using that uid", func(t *testing.T) { + resp, err := postDashboard(t, grafanaListedAddr, "admin", "admin", map[string]interface{}{ + "dashboard": map[string]interface{}{ + "id": savedDashInFolder.ID, // nolint:staticcheck + "uid": savedDashInGeneralFolder.UID, + "title": "Updated title", + }, + "folderUid": savedDashInFolder.FolderUID, + "overwrite": true, + }) + require.NoError(t, err) + assert.Equal(t, http.StatusBadRequest, resp.StatusCode) + err = resp.Body.Close() + require.NoError(t, err) + }) + + t.Run("When trying to update to a folder", func(t *testing.T) { + resp, err := postDashboard(t, grafanaListedAddr, "admin", "admin", map[string]interface{}{ + "dashboard": map[string]interface{}{ + "id": savedDashInFolder.ID, // nolint:staticcheck + "uid": savedDashInFolder.UID, + "title": "Updated title", + }, + "isFolder": true, + "folderUid": savedDashInFolder.FolderUID, + "overwrite": true, + }) + require.NoError(t, err) + require.NoError(t, err) + assert.Equal(t, http.StatusBadRequest, resp.StatusCode) + err = resp.Body.Close() + require.NoError(t, err) + }) +} + func TestIntegrationDashboardQuota(t *testing.T) { - if testing.Short() { - t.Skip("skipping integration test") - } - testDashboardQuota(t, []string{}) -} - -func TestIntegrationDashboardQuotaK8s(t *testing.T) { - if testing.Short() { - t.Skip("skipping integration test") - } - testDashboardQuota(t, []string{featuremgmt.FlagKubernetesClientDashboardsFolders}) -} - -func testDashboardQuota(t *testing.T, featureToggles []string) { // enable quota and set low dashboard quota // Setup Grafana and its Database dashboardQuota := int64(1) @@ -54,7 +279,7 @@ func testDashboardQuota(t *testing.T, featureToggles []string) { DisableAnonymous: true, EnableQuota: true, DashboardOrgQuota: &dashboardQuota, - EnableFeatureToggles: featureToggles, + EnableFeatureToggles: []string{featuremgmt.FlagKubernetesClientDashboardsFolders}, }) grafanaListedAddr, _ := testinfra.StartGrafanaEnv(t, dir, path) @@ -110,27 +335,10 @@ func testDashboardQuota(t *testing.T, featureToggles []string) { } func TestIntegrationUpdatingProvisionionedDashboards(t *testing.T) { - if testing.Short() { - t.Skip("skipping integration test") - } - - testUpdatingProvisionionedDashboards(t, []string{}) -} - -func TestIntegrationUpdatingProvisionionedDashboardsK8s(t *testing.T) { - if testing.Short() { - t.Skip("skipping integration test") - } - - // will be the default in g12 - testUpdatingProvisionionedDashboards(t, []string{featuremgmt.FlagKubernetesClientDashboardsFolders}) -} - -func testUpdatingProvisionionedDashboards(t *testing.T, featureToggles []string) { // Setup Grafana and its Database dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ DisableAnonymous: true, - EnableFeatureToggles: featureToggles, + EnableFeatureToggles: []string{featuremgmt.FlagKubernetesClientDashboardsFolders}, }) provDashboardsDir := filepath.Join(dir, "conf", "provisioning", "dashboards") @@ -187,7 +395,7 @@ providers: var dashboardID int64 for _, d := range *dashboardList { dashboardUID = d.UID - dashboardID = d.ID + dashboardID = d.ID // nolint:staticcheck } assert.Equal(t, int64(1), dashboardID) @@ -281,34 +489,10 @@ providers: } func TestIntegrationCreate(t *testing.T) { - if testing.Short() { - t.Skip("skipping integration test") - } - - testCreate(t, []string{}) -} - -func TestIntegrationCreateK8s(t *testing.T) { - if testing.Short() { - t.Skip("skipping integration test") - } - - testCreate(t, []string{featuremgmt.FlagKubernetesClientDashboardsFolders}) -} - -func TestIntegrationPreserveSchemaVersion(t *testing.T) { - if testing.Short() { - t.Skip("skipping integration test") - } - - testPreserveSchemaVersion(t, []string{featuremgmt.FlagKubernetesClientDashboardsFolders}) -} - -func testCreate(t *testing.T, featureToggles []string) { // Setup Grafana and its Database dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ DisableAnonymous: true, - EnableFeatureToggles: featureToggles, + EnableFeatureToggles: []string{featuremgmt.FlagKubernetesClientDashboardsFolders}, }) grafanaListedAddr, _ := testinfra.StartGrafanaEnv(t, dir, path) @@ -461,10 +645,10 @@ func intPtr(n int) *int { return &n } -func testPreserveSchemaVersion(t *testing.T, featureToggles []string) { +func TestIntegrationPreserveSchemaVersion(t *testing.T) { dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ DisableAnonymous: true, - EnableFeatureToggles: featureToggles, + EnableFeatureToggles: []string{featuremgmt.FlagKubernetesClientDashboardsFolders}, }) grafanaListedAddr, _ := testinfra.StartGrafanaEnv(t, dir, path) @@ -553,25 +737,9 @@ func testPreserveSchemaVersion(t *testing.T, featureToggles []string) { } func TestIntegrationImportDashboardWithLibraryPanels(t *testing.T) { - if testing.Short() { - t.Skip("skipping integration test") - } - - testImportDashboardWithLibraryPanels(t, []string{}) -} - -func TestIntegrationImportDashboardWithLibraryPanelsK8s(t *testing.T) { - if testing.Short() { - t.Skip("skipping integration test") - } - - testImportDashboardWithLibraryPanels(t, []string{featuremgmt.FlagKubernetesClientDashboardsFolders}) -} - -func testImportDashboardWithLibraryPanels(t *testing.T, featureToggles []string) { dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ DisableAnonymous: true, - EnableFeatureToggles: featureToggles, + EnableFeatureToggles: []string{featuremgmt.FlagKubernetesClientDashboardsFolders}, }) grafanaListedAddr, _ := testinfra.StartGrafanaEnv(t, dir, path) @@ -762,3 +930,297 @@ func testImportDashboardWithLibraryPanels(t *testing.T, featureToggles []string) }) }) } + +func createDashboard(t *testing.T, grafanaListedAddr string, title string, folderID int64, folderUID string) *dashboards.Dashboard { + t.Helper() + + buf := &bytes.Buffer{} + err := json.NewEncoder(buf).Encode(map[string]interface{}{ + "dashboard": map[string]interface{}{ + "title": title, + }, + "folderId": folderID, + "folderUid": folderUID, + "overwrite": true, + }) + require.NoError(t, err) + + u := fmt.Sprintf("http://admin:admin@%s/api/dashboards/db", grafanaListedAddr) + // nolint:gosec + resp, err := http.Post(u, "application/json", buf) + require.NoError(t, err) + require.Equal(t, http.StatusOK, resp.StatusCode) + t.Cleanup(func() { + err := resp.Body.Close() + require.NoError(t, err) + }) + + b, err := io.ReadAll(resp.Body) + require.NoError(t, err) + + var saveResp struct { + Status string `json:"status"` + Slug string `json:"slug"` + Version int64 `json:"version"` + ID int64 `json:"id"` + UID string `json:"uid"` + URL string `json:"url"` + FolderUID string `json:"folderUid"` + } + err = json.Unmarshal(b, &saveResp) + require.NoError(t, err) + require.NotEmpty(t, saveResp.UID) + + return &dashboards.Dashboard{ + ID: saveResp.ID, // nolint:staticcheck + UID: saveResp.UID, + Slug: saveResp.Slug, + Version: int(saveResp.Version), + FolderUID: saveResp.FolderUID, + } +} + +func postDashboard(t *testing.T, grafanaListedAddr, user, password string, payload map[string]interface{}) (*http.Response, error) { + t.Helper() + + payloadBytes, err := json.Marshal(payload) + require.NoError(t, err) + + u := fmt.Sprintf("http://%s:%s@%s/api/dashboards/db", user, password, grafanaListedAddr) + return http.Post(u, "application/json", bytes.NewBuffer(payloadBytes)) // nolint:gosec +} + +func TestIntegrationDashboardServicePermissions(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test") + } + + dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ + DisableAnonymous: true, + EnableFeatureToggles: []string{featuremgmt.FlagKubernetesClientDashboardsFolders}, + }) + grafanaListedAddr, env := testinfra.StartGrafanaEnv(t, dir, path) + tests.CreateUser(t, env.SQLStore, env.Cfg, user.CreateUserCommand{ + DefaultOrgRole: string(org.RoleEditor), + Login: "editor", + Password: "editor", + IsAdmin: false, + }) + tests.CreateUser(t, env.SQLStore, env.Cfg, user.CreateUserCommand{ + DefaultOrgRole: string(org.RoleViewer), + Login: "viewer", + Password: "viewer", + IsAdmin: false, + }) + savedFolder := createFolder(t, grafanaListedAddr, "Saved folder") + otherSavedFolder := createFolder(t, grafanaListedAddr, "Other saved folder") + savedDashInFolder := createDashboard(t, grafanaListedAddr, "Saved dash in folder", savedFolder.ID, savedFolder.UID) // nolint:staticcheck + savedDashInGeneralFolder := createDashboard(t, grafanaListedAddr, "Saved dashboard in general folder", 0, "") + + t.Run("When creating a new dashboard in the General folder, requires create permissions scoped to the general folder", func(t *testing.T) { + dashboardPayload := map[string]interface{}{ + "dashboard": map[string]interface{}{ + "title": "Dash", + }, + "overwrite": true, + } + + payloadBytes, err := json.Marshal(dashboardPayload) + require.NoError(t, err) + + u := fmt.Sprintf("http://viewer:viewer@%s/api/dashboards/db", grafanaListedAddr) + resp, err := http.Post(u, "application/json", bytes.NewBuffer(payloadBytes)) // nolint:gosec + require.NoError(t, err) + assert.Equal(t, http.StatusForbidden, resp.StatusCode) + err = resp.Body.Close() + require.NoError(t, err) + + u = fmt.Sprintf("http://editor:editor@%s/api/dashboards/db", grafanaListedAddr) + resp, err = http.Post(u, "application/json", bytes.NewBuffer(payloadBytes)) // nolint:gosec + require.NoError(t, err) + assert.Equal(t, http.StatusOK, resp.StatusCode) + err = resp.Body.Close() + require.NoError(t, err) + }) + + t.Run("When creating a new dashboard in other folder, requires create permissions scoped to the other folder", func(t *testing.T) { + dashboardPayload := map[string]interface{}{ + "dashboard": map[string]interface{}{ + "title": "Dash", + }, + "folderUid": otherSavedFolder.UID, + "overwrite": true, + } + + resp, err := postDashboard(t, grafanaListedAddr, "viewer", "viewer", dashboardPayload) + require.NoError(t, err) + assert.Equal(t, http.StatusForbidden, resp.StatusCode) + err = resp.Body.Close() + require.NoError(t, err) + + resp, err = postDashboard(t, grafanaListedAddr, "editor", "editor", dashboardPayload) + require.NoError(t, err) + assert.Equal(t, http.StatusOK, resp.StatusCode) + err = resp.Body.Close() + require.NoError(t, err) + }) + + t.Run("When creating a new dashboard by existing UID in folder, requires write permissions on the existing dashboard", func(t *testing.T) { + dashboardPayload := map[string]interface{}{ + "dashboard": map[string]interface{}{ + "uid": savedDashInFolder.UID, + "title": "New dash", + }, + "folderUid": savedFolder.UID, + "overwrite": true, + } + + resp, err := postDashboard(t, grafanaListedAddr, "viewer", "viewer", dashboardPayload) + require.NoError(t, err) + assert.Equal(t, http.StatusForbidden, resp.StatusCode) + err = resp.Body.Close() + require.NoError(t, err) + + resp, err = postDashboard(t, grafanaListedAddr, "editor", "editor", dashboardPayload) + require.NoError(t, err) + assert.Equal(t, http.StatusOK, resp.StatusCode) + err = resp.Body.Close() + require.NoError(t, err) + }) + + t.Run("When moving a dashboard by existing uid to other folder from General folder, requires dashboard creation permissions on the destination folder and write access to the dashboard", func(t *testing.T) { + dashboardPayload := map[string]interface{}{ + "dashboard": map[string]interface{}{ + "uid": savedDashInGeneralFolder.UID, + "title": "Dash", + }, + "folderUid": otherSavedFolder.UID, + "overwrite": true, + } + + resp, err := postDashboard(t, grafanaListedAddr, "viewer", "viewer", dashboardPayload) + require.NoError(t, err) + assert.Equal(t, http.StatusForbidden, resp.StatusCode) + err = resp.Body.Close() + require.NoError(t, err) + + resp, err = postDashboard(t, grafanaListedAddr, "editor", "editor", dashboardPayload) + require.NoError(t, err) + assert.Equal(t, http.StatusOK, resp.StatusCode) + err = resp.Body.Close() + require.NoError(t, err) + }) + + t.Run("When moving a dashboard by existing uid to the General folder from other folder, requires dashboard creation permissions on the general folder and write access to the dashboard", func(t *testing.T) { + dashboardPayload := map[string]interface{}{ + "dashboard": map[string]interface{}{ + "uid": savedDashInFolder.UID, + "title": "Dash", + }, + "folderUid": "", + "overwrite": true, + } + + resp, err := postDashboard(t, grafanaListedAddr, "viewer", "viewer", dashboardPayload) + require.NoError(t, err) + assert.Equal(t, http.StatusForbidden, resp.StatusCode) + err = resp.Body.Close() + require.NoError(t, err) + + resp, err = postDashboard(t, grafanaListedAddr, "editor", "editor", dashboardPayload) + require.NoError(t, err) + assert.Equal(t, http.StatusOK, resp.StatusCode) + err = resp.Body.Close() + require.NoError(t, err) + }) + + t.Run("RBAC tests", func(t *testing.T) { + setFolderPermissions := func(t *testing.T, grafanaListedAddr string, folderUID string, permissions []map[string]interface{}) { + t.Helper() + + permissionPayload := map[string]interface{}{ + "items": permissions, + } + + payloadBytes, err := json.Marshal(permissionPayload) + require.NoError(t, err) + + u := fmt.Sprintf("http://admin:admin@%s/api/folders/%s/permissions", grafanaListedAddr, folderUID) + resp, err := http.Post(u, "application/json", bytes.NewBuffer(payloadBytes)) // nolint:gosec + require.NoError(t, err) + assert.Equal(t, http.StatusOK, resp.StatusCode) + err = resp.Body.Close() + require.NoError(t, err) + } + + searchDashboards := func(t *testing.T, grafanaListedAddr string, userLogin, userPassword string) []map[string]interface{} { + t.Helper() + + u := fmt.Sprintf("http://%s:%s@%s/api/search?type=dash-db", userLogin, userPassword, grafanaListedAddr) + resp, err := http.Get(u) // nolint:gosec + require.NoError(t, err) + assert.Equal(t, http.StatusOK, resp.StatusCode) + defer resp.Body.Close() // nolint:errcheck + + var results []map[string]interface{} + err = json.NewDecoder(resp.Body).Decode(&results) + require.NoError(t, err) + + return results + } + + noneUserID := tests.CreateUser(t, env.SQLStore, env.Cfg, user.CreateUserCommand{ + DefaultOrgRole: string(org.RoleNone), + Login: "noneuser", + Password: "noneuser", + IsAdmin: false, + }) + parentFolder := createFolder(t, grafanaListedAddr, "parent") + childFolder := createFolder(t, grafanaListedAddr, "child") + createDashboard(t, grafanaListedAddr, "dashboard in root", 0, "") + createDashboard(t, grafanaListedAddr, "dashboard in parent", parentFolder.ID, parentFolder.UID) // nolint:staticcheck + createDashboard(t, grafanaListedAddr, "dashboard in child", childFolder.ID, childFolder.UID) // nolint:staticcheck + + viewPermissions := []map[string]interface{}{ + { + "permission": 1, + "userId": noneUserID, + }, + } + t.Run("it should not return folder if ACL is not set for parent folder", func(t *testing.T) { + results := searchDashboards(t, grafanaListedAddr, "noneuser", "noneuser") + assert.Empty(t, results, "Should not return any dashboards when no permissions are set") + }) + + t.Run("it should return child folder when user has permission to read child folder", func(t *testing.T) { + setFolderPermissions(t, grafanaListedAddr, childFolder.UID, viewPermissions) + results := searchDashboards(t, grafanaListedAddr, "noneuser", "noneuser") + + foundTitles := make([]string, 0) + for _, result := range results { + if title, ok := result["title"].(string); ok { + foundTitles = append(foundTitles, title) + } + } + + assert.Contains(t, foundTitles, "dashboard in child", "Should return dashboard in child folder") + }) + + t.Run("it should return parent folder when user has permission to read parent folder but no permission to read child folder", func(t *testing.T) { + setFolderPermissions(t, grafanaListedAddr, parentFolder.UID, viewPermissions) + setFolderPermissions(t, grafanaListedAddr, childFolder.UID, []map[string]interface{}{}) + + results := searchDashboards(t, grafanaListedAddr, "noneuser", "noneuser") + + foundTitles := make([]string, 0) + for _, result := range results { + if title, ok := result["title"].(string); ok { + foundTitles = append(foundTitles, title) + } + } + + assert.Contains(t, foundTitles, "dashboard in parent", "Should return dashboard in parent folder") + assert.NotContains(t, foundTitles, "dashboard in child", "Should not return dashboard in child folder") + }) + }) +} From a2698dc3b5cbbfeeda01115504b1695b3e2807fa Mon Sep 17 00:00:00 2001 From: Ashley Harrison Date: Tue, 29 Jul 2025 09:30:18 +0100 Subject: [PATCH 072/131] Chore: Unskip some a11y story checks and fix any associated issues (#108613) * fix some a11y issues with the stories * fix lockfile * fix tests * put aria-label on * add aria-describedby * undo changes to VizLegendTable * use useID for image id --- .betterer.results | 84 ------------ .../grafana-data/src/themes/createColors.ts | 2 +- .../AutoSaveField/AutoSaveField.story.tsx | 18 ++- .../src/components/Button/Button.story.tsx | 10 +- .../components/Carousel/Carousel.story.tsx | 2 - .../src/components/Carousel/Carousel.test.tsx | 9 +- .../src/components/Carousel/Carousel.tsx | 30 +++-- .../components/Cascader/Cascader.story.tsx | 22 ++- .../ColorPicker/ColorPickerInput.story.tsx | 23 ++-- .../ConfirmButton/ConfirmButton.story.tsx | 2 - .../components/ConfirmButton/DeleteButton.tsx | 7 +- .../ContextMenu/ContextMenu.story.tsx | 5 +- .../DateTimePickers/TimeOfDayPicker.story.tsx | 23 ++-- .../DateTimePickers/TimeOfDayPicker.tsx | 3 + .../src/components/Forms/Field.story.tsx | 24 ++-- .../src/components/Forms/FieldSet.story.tsx | 15 ++- .../src/components/Forms/Form.story.tsx | 126 ++++++++++-------- .../components/Forms/InlineField.story.tsx | 28 ++-- .../InlineToast/InlineToast.story.tsx | 10 +- .../src/components/Input/Input.story.tsx | 37 ++--- .../src/components/Layout/Grid/Grid.story.tsx | 18 +-- .../LoadingBar/LoadingBar.story.tsx | 2 - .../src/components/LoadingBar/LoadingBar.tsx | 2 +- .../PanelChrome/PanelChrome.story.tsx | 2 +- .../src/components/Segment/Segment.story.tsx | 6 +- .../components/Segment/SegmentAsync.story.tsx | 6 +- .../components/Segment/SegmentInput.story.tsx | 5 +- .../src/components/Segment/styles.ts | 8 +- .../components/Select/SelectPerf.story.tsx | 37 +++-- .../StatsPicker/StatsPicker.story.tsx | 29 ++-- .../src/components/Switch/Switch.story.tsx | 11 +- .../TableInputCSV/TableInputCSV.story.tsx | 4 - .../TableInputCSV/TableInputCSV.tsx | 3 +- .../src/components/Tags/TagList.story.tsx | 2 - .../src/components/Tags/TagList.tsx | 10 +- .../src/components/Text/Text.story.tsx | 2 - .../components/ThemeDemos/ThemeDemo.story.tsx | 2 - .../src/components/ThemeDemos/ThemeDemo.tsx | 39 ++++-- .../ThemeDemos/Typography.story.tsx | 10 +- .../ToolbarButton/ToolbarButton.story.tsx | 12 +- .../src/utils/storybook/StoryExample.tsx | 14 +- public/locales/en-US/grafana.json | 4 + public/sass/_variables.light.generated.scss | 2 +- 43 files changed, 348 insertions(+), 362 deletions(-) diff --git a/.betterer.results b/.betterer.results index 1ab5b19047e..95894921943 100644 --- a/.betterer.results +++ b/.betterer.results @@ -4229,36 +4229,12 @@ exports[`no skipping a11y tests in stories`] = { "packages/grafana-alerting/src/grafana/contactPoints/components/ContactPointSelector/ContactPointSelector.story.tsx:5381": [ [0, 0, 0, "No skipping of a11y tests in stories. Please fix the component or story instead.", "5381"] ], - "packages/grafana-ui/src/components/AutoSaveField/AutoSaveField.story.tsx:5381": [ - [0, 0, 0, "No skipping of a11y tests in stories. Please fix the component or story instead.", "5381"] - ], - "packages/grafana-ui/src/components/Button/Button.story.tsx:5381": [ - [0, 0, 0, "No skipping of a11y tests in stories. Please fix the component or story instead.", "5381"] - ], - "packages/grafana-ui/src/components/Carousel/Carousel.story.tsx:5381": [ - [0, 0, 0, "No skipping of a11y tests in stories. Please fix the component or story instead.", "5381"] - ], - "packages/grafana-ui/src/components/Cascader/Cascader.story.tsx:5381": [ - [0, 0, 0, "No skipping of a11y tests in stories. Please fix the component or story instead.", "5381"] - ], "packages/grafana-ui/src/components/ColorPicker/ColorPicker.story.tsx:5381": [ [0, 0, 0, "No skipping of a11y tests in stories. Please fix the component or story instead.", "5381"] ], - "packages/grafana-ui/src/components/ColorPicker/ColorPickerInput.story.tsx:5381": [ - [0, 0, 0, "No skipping of a11y tests in stories. Please fix the component or story instead.", "5381"] - ], "packages/grafana-ui/src/components/Combobox/MultiCombobox.story.tsx:5381": [ [0, 0, 0, "No skipping of a11y tests in stories. Please fix the component or story instead.", "5381"] ], - "packages/grafana-ui/src/components/ConfirmButton/ConfirmButton.story.tsx:5381": [ - [0, 0, 0, "No skipping of a11y tests in stories. Please fix the component or story instead.", "5381"] - ], - "packages/grafana-ui/src/components/ContextMenu/ContextMenu.story.tsx:5381": [ - [0, 0, 0, "No skipping of a11y tests in stories. Please fix the component or story instead.", "5381"] - ], - "packages/grafana-ui/src/components/DateTimePickers/TimeOfDayPicker.story.tsx:5381": [ - [0, 0, 0, "No skipping of a11y tests in stories. Please fix the component or story instead.", "5381"] - ], "packages/grafana-ui/src/components/FileDropzone/FileDropzone.story.tsx:5381": [ [0, 0, 0, "No skipping of a11y tests in stories. Please fix the component or story instead.", "5381"] ], @@ -4268,45 +4244,21 @@ exports[`no skipping a11y tests in stories`] = { "packages/grafana-ui/src/components/Forms/Checkbox.story.tsx:5381": [ [0, 0, 0, "No skipping of a11y tests in stories. Please fix the component or story instead.", "5381"] ], - "packages/grafana-ui/src/components/Forms/Field.story.tsx:5381": [ - [0, 0, 0, "No skipping of a11y tests in stories. Please fix the component or story instead.", "5381"] - ], "packages/grafana-ui/src/components/Forms/FieldArray.story.tsx:5381": [ [0, 0, 0, "No skipping of a11y tests in stories. Please fix the component or story instead.", "5381"] ], - "packages/grafana-ui/src/components/Forms/FieldSet.story.tsx:5381": [ - [0, 0, 0, "No skipping of a11y tests in stories. Please fix the component or story instead.", "5381"] - ], - "packages/grafana-ui/src/components/Forms/Form.story.tsx:5381": [ - [0, 0, 0, "No skipping of a11y tests in stories. Please fix the component or story instead.", "5381"] - ], - "packages/grafana-ui/src/components/Forms/InlineField.story.tsx:5381": [ - [0, 0, 0, "No skipping of a11y tests in stories. Please fix the component or story instead.", "5381"] - ], "packages/grafana-ui/src/components/Forms/RadioButtonGroup/RadioButtonGroup.story.tsx:5381": [ [0, 0, 0, "No skipping of a11y tests in stories. Please fix the component or story instead.", "5381"] ], - "packages/grafana-ui/src/components/InlineToast/InlineToast.story.tsx:5381": [ - [0, 0, 0, "No skipping of a11y tests in stories. Please fix the component or story instead.", "5381"] - ], - "packages/grafana-ui/src/components/Input/Input.story.tsx:5381": [ - [0, 0, 0, "No skipping of a11y tests in stories. Please fix the component or story instead.", "5381"] - ], "packages/grafana-ui/src/components/InteractiveTable/InteractiveTable.story.tsx:5381": [ [0, 0, 0, "No skipping of a11y tests in stories. Please fix the component or story instead.", "5381"] ], - "packages/grafana-ui/src/components/Layout/Grid/Grid.story.tsx:5381": [ - [0, 0, 0, "No skipping of a11y tests in stories. Please fix the component or story instead.", "5381"] - ], "packages/grafana-ui/src/components/Layout/Stack/Stack.story.tsx:5381": [ [0, 0, 0, "No skipping of a11y tests in stories. Please fix the component or story instead.", "5381"] ], "packages/grafana-ui/src/components/Link/TextLink.story.tsx:5381": [ [0, 0, 0, "No skipping of a11y tests in stories. Please fix the component or story instead.", "5381"] ], - "packages/grafana-ui/src/components/LoadingBar/LoadingBar.story.tsx:5381": [ - [0, 0, 0, "No skipping of a11y tests in stories. Please fix the component or story instead.", "5381"] - ], "packages/grafana-ui/src/components/Menu/Menu.story.tsx:5381": [ [0, 0, 0, "No skipping of a11y tests in stories. Please fix the component or story instead.", "5381"] ], @@ -4325,54 +4277,18 @@ exports[`no skipping a11y tests in stories`] = { "packages/grafana-ui/src/components/ScrollContainer/ScrollContainer.story.tsx:5381": [ [0, 0, 0, "No skipping of a11y tests in stories. Please fix the component or story instead.", "5381"] ], - "packages/grafana-ui/src/components/Segment/Segment.story.tsx:5381": [ - [0, 0, 0, "No skipping of a11y tests in stories. Please fix the component or story instead.", "5381"] - ], - "packages/grafana-ui/src/components/Segment/SegmentAsync.story.tsx:5381": [ - [0, 0, 0, "No skipping of a11y tests in stories. Please fix the component or story instead.", "5381"] - ], - "packages/grafana-ui/src/components/Segment/SegmentInput.story.tsx:5381": [ - [0, 0, 0, "No skipping of a11y tests in stories. Please fix the component or story instead.", "5381"] - ], "packages/grafana-ui/src/components/Select/Select.story.tsx:5381": [ [0, 0, 0, "No skipping of a11y tests in stories. Please fix the component or story instead.", "5381"] ], - "packages/grafana-ui/src/components/Select/SelectPerf.story.tsx:5381": [ - [0, 0, 0, "No skipping of a11y tests in stories. Please fix the component or story instead.", "5381"] - ], "packages/grafana-ui/src/components/Slider/RangeSlider.story.tsx:5381": [ [0, 0, 0, "No skipping of a11y tests in stories. Please fix the component or story instead.", "5381"] ], "packages/grafana-ui/src/components/Slider/Slider.story.tsx:5381": [ [0, 0, 0, "No skipping of a11y tests in stories. Please fix the component or story instead.", "5381"] ], - "packages/grafana-ui/src/components/StatsPicker/StatsPicker.story.tsx:5381": [ - [0, 0, 0, "No skipping of a11y tests in stories. Please fix the component or story instead.", "5381"] - ], - "packages/grafana-ui/src/components/Switch/Switch.story.tsx:5381": [ - [0, 0, 0, "No skipping of a11y tests in stories. Please fix the component or story instead.", "5381"] - ], "packages/grafana-ui/src/components/Table/Table.story.tsx:5381": [ [0, 0, 0, "No skipping of a11y tests in stories. Please fix the component or story instead.", "5381"] ], - "packages/grafana-ui/src/components/TableInputCSV/TableInputCSV.story.tsx:5381": [ - [0, 0, 0, "No skipping of a11y tests in stories. Please fix the component or story instead.", "5381"] - ], - "packages/grafana-ui/src/components/Tags/TagList.story.tsx:5381": [ - [0, 0, 0, "No skipping of a11y tests in stories. Please fix the component or story instead.", "5381"] - ], - "packages/grafana-ui/src/components/Text/Text.story.tsx:5381": [ - [0, 0, 0, "No skipping of a11y tests in stories. Please fix the component or story instead.", "5381"] - ], - "packages/grafana-ui/src/components/ThemeDemos/ThemeDemo.story.tsx:5381": [ - [0, 0, 0, "No skipping of a11y tests in stories. Please fix the component or story instead.", "5381"] - ], - "packages/grafana-ui/src/components/ThemeDemos/Typography.story.tsx:5381": [ - [0, 0, 0, "No skipping of a11y tests in stories. Please fix the component or story instead.", "5381"] - ], - "packages/grafana-ui/src/components/ToolbarButton/ToolbarButton.story.tsx:5381": [ - [0, 0, 0, "No skipping of a11y tests in stories. Please fix the component or story instead.", "5381"] - ], "packages/grafana-ui/src/components/VizLayout/VizLayout.story.tsx:5381": [ [0, 0, 0, "No skipping of a11y tests in stories. Please fix the component or story instead.", "5381"] ], diff --git a/packages/grafana-data/src/themes/createColors.ts b/packages/grafana-data/src/themes/createColors.ts index 9f9afcbfaa9..706f87d280e 100644 --- a/packages/grafana-data/src/themes/createColors.ts +++ b/packages/grafana-data/src/themes/createColors.ts @@ -186,7 +186,7 @@ class LightColors implements ThemeColorsBase> { text = { primary: `rgba(${this.blackBase}, 1)`, secondary: `rgba(${this.blackBase}, 0.75)`, - disabled: `rgba(${this.blackBase}, 0.64)`, + disabled: `rgba(${this.blackBase}, 0.65)`, link: this.primary.text, maxContrast: palette.black, }; diff --git a/packages/grafana-ui/src/components/AutoSaveField/AutoSaveField.story.tsx b/packages/grafana-ui/src/components/AutoSaveField/AutoSaveField.story.tsx index 24df1318d55..c19df03d2c3 100644 --- a/packages/grafana-ui/src/components/AutoSaveField/AutoSaveField.story.tsx +++ b/packages/grafana-ui/src/components/AutoSaveField/AutoSaveField.story.tsx @@ -1,5 +1,5 @@ import { StoryFn, Meta } from '@storybook/react'; -import { useState } from 'react'; +import { useId, useState } from 'react'; import { Combobox } from '../Combobox/Combobox'; import { Checkbox } from '../Forms/Checkbox'; @@ -35,8 +35,6 @@ const meta: Meta = { 'validationMessageHorizontalOverflow', ], }, - // TODO fix a11y issue in story and remove this - a11y: { test: 'off' }, }, argTypes: { saveErrorMessage: { control: 'text' }, @@ -76,10 +74,12 @@ const themeOptions = [ export const Basic: StoryFn = (args) => { const [inputValue, setInputValue] = useState(''); + const id = useId(); return ( {(onChange) => ( { const value = e.currentTarget.value; @@ -105,12 +105,19 @@ export const AllComponents: StoryFn = (args) => { const [checkBoxValue, setCheckBoxValue] = useState(false); const [textAreaValue, setTextAreaValue] = useState(''); const [switchValue, setSwitchValue] = useState(false); + const textId = useId(); + const comboboxId = useId(); + const radioButtonId = useId(); + const checkBoxId = useId(); + const textAreaId = useId(); + const switchId = useId(); return (
{(onChange) => ( { const value = e.currentTarget.value; @@ -123,6 +130,7 @@ export const AllComponents: StoryFn = (args) => { {(onChange) => ( { @@ -139,6 +147,7 @@ export const AllComponents: StoryFn = (args) => { > {(onChange) => ( { @@ -155,6 +164,7 @@ export const AllComponents: StoryFn = (args) => { > {(onChange) => ( { > {(onChange) => (