Compare commits

...

8 Commits

Author SHA1 Message Date
github-actions[bot]
33d374ec7b apply security patch: release-11.2.7/320-202502130525.patch
commit ade17b4335e796e7410b6f91341b92d2139e772e
Author: AgnesToulet <35176601+AgnesToulet@users.noreply.github.com>
Date:   Tue Feb 11 10:57:05 2025 +0100

    Dashboards: Prevent title longer than 5 000 characters

    (cherry picked from commit f9e0789210004b0bd7902255644ef348ae7b3aa8)
2025-02-14 15:23:15 +00:00
Kevin Minehart
848c99ad0c [release-11.2.7] Docker: Missing libresolv.so.2 from glibc (#100743)
Docker: Missing libresolv.so.2 from glibc (#100729)

* Docker: Missing libresolv.so.2 from glibc

* Misplaced &&

(cherry picked from commit 3a8a24e662)
2025-02-14 17:21:12 +02:00
Todd Treece
1f1c5b7468 [release-11.2.7] Metrics: Use correct gatherer in graphite bridge (#100678)
Metrics: Use correct gatherer in graphite bridge (#100624)

(cherry picked from commit 5a74a1a0f6)
2025-02-13 23:35:25 +02:00
Misi
1327403277 [release-11.2.7] IAM: log error when malformed json arrays are found in SSO configs (#100654)
IAM: Log error when malformed json arrays are found in SSO configs (#99896)

(cherry picked from commit eeadb7e771)
2025-02-13 18:38:37 +01:00
Josh Hunt
beee65fb83 [release-11.2.7] Chore: pin tonistiigi/binfmt version (#100526)
Chore: pin tonistiigi/binfmt version (#100510)

* Chore: pin tonistiigi/binfmt version

* change version to qemu-v7.0.0-28

* uninstall first, log version

* uninstall first, log version

* uninstall first, log version

(cherry picked from commit a9b4b1e5be)
2025-02-12 23:00:32 -06:00
Kevin Minehart
12135fa1d4 [release-11.2.7] CI: Add release branches to patch automation (#100531)
CI: Add release branches to patch automation (#100442)

* CI: Add release branches to patch automation

* Update .github/workflows/create-security-patch-from-security-mirror.yml

Co-authored-by: Agnès Toulet <35176601+AgnesToulet@users.noreply.github.com>

---------

Co-authored-by: Agnès Toulet <35176601+AgnesToulet@users.noreply.github.com>
(cherry picked from commit a8b98ded66)
2025-02-12 15:58:07 -06:00
Jev Forsberg
7f5e5e904d [release-11.2.7] Chore: Update grabpl version to v3.1.2 (#100240)
Chore: Update grabpl version to v3.1.2 (#100157)

baldm0mma/ update grabpl version

(cherry picked from commit 8e3327a446)
2025-02-07 08:29:07 -07:00
Jacob Valdez
f01252c56b [v11.2.x] Docs: Adding info on decrypting encrypted certificates (#100159) 2025-02-07 08:56:19 -06:00
22 changed files with 179 additions and 49 deletions

View File

@@ -629,7 +629,7 @@ steps:
name: identify-runner
- commands:
- mkdir -p bin
- curl -fL -o bin/grabpl https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v3.1.1/grabpl
- curl -fL -o bin/grabpl https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v3.1.2/grabpl
- chmod +x bin/grabpl
image: byrnedo/alpine-curl:0.1.8
name: grabpl
@@ -696,6 +696,9 @@ steps:
token:
from_secret: drone_token
- commands:
- docker run --privileged --rm tonistiigi/binfmt:qemu-v7.0.0-28 --version
- docker run --privileged --rm tonistiigi/binfmt:qemu-v7.0.0-28 --uninstall 'qemu-*'
- docker run --privileged --rm tonistiigi/binfmt:qemu-v7.0.0-28 --install all
- /src/grafana-build artifacts -a targz:grafana:linux/amd64 -a targz:grafana:linux/arm64
-a targz:grafana:linux/arm/v7 --go-version=1.22.11 --yarn-cache=$$YARN_CACHE_FOLDER
--build-id=$$DRONE_BUILD_NUMBER --grafana-dir=$$PWD > packages.txt
@@ -937,7 +940,9 @@ steps:
image: grafana/docker-puppeteer:1.1.0
name: test-a11y-frontend
- commands:
- docker run --privileged --rm tonistiigi/binfmt --install all
- docker run --privileged --rm tonistiigi/binfmt:qemu-v7.0.0-28 --version
- docker run --privileged --rm tonistiigi/binfmt:qemu-v7.0.0-28 --uninstall 'qemu-*'
- docker run --privileged --rm tonistiigi/binfmt:qemu-v7.0.0-28 --install all
- /src/grafana-build artifacts -a docker:grafana:linux/amd64 -a docker:grafana:linux/amd64:ubuntu
-a docker:grafana:linux/arm64 -a docker:grafana:linux/arm64:ubuntu -a docker:grafana:linux/arm/v7
-a docker:grafana:linux/arm/v7:ubuntu --yarn-cache=$$YARN_CACHE_FOLDER --build-id=$$DRONE_BUILD_NUMBER
@@ -1095,7 +1100,7 @@ steps:
path: /github-app
- commands:
- mkdir -p bin
- curl -fL -o bin/grabpl https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v3.1.1/grabpl
- curl -fL -o bin/grabpl https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v3.1.2/grabpl
- chmod +x bin/grabpl
image: byrnedo/alpine-curl:0.1.8
name: grabpl
@@ -2098,7 +2103,7 @@ steps:
name: identify-runner
- commands:
- mkdir -p bin
- curl -fL -o bin/grabpl https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v3.1.1/grabpl
- curl -fL -o bin/grabpl https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v3.1.2/grabpl
- chmod +x bin/grabpl
image: byrnedo/alpine-curl:0.1.8
name: grabpl
@@ -2164,6 +2169,9 @@ steps:
image: node:20.9.0-alpine
name: build-frontend-packages
- commands:
- docker run --privileged --rm tonistiigi/binfmt:qemu-v7.0.0-28 --version
- docker run --privileged --rm tonistiigi/binfmt:qemu-v7.0.0-28 --uninstall 'qemu-*'
- docker run --privileged --rm tonistiigi/binfmt:qemu-v7.0.0-28 --install all
- /src/grafana-build artifacts -a targz:grafana:linux/amd64 -a targz:grafana:linux/arm64
-a targz:grafana:linux/arm/v7 --go-version=1.22.11 --yarn-cache=$$YARN_CACHE_FOLDER
--build-id=$$DRONE_BUILD_NUMBER --grafana-dir=$$PWD > packages.txt
@@ -2441,7 +2449,9 @@ steps:
repo:
- grafana/grafana
- commands:
- docker run --privileged --rm tonistiigi/binfmt --install all
- docker run --privileged --rm tonistiigi/binfmt:qemu-v7.0.0-28 --version
- docker run --privileged --rm tonistiigi/binfmt:qemu-v7.0.0-28 --uninstall 'qemu-*'
- docker run --privileged --rm tonistiigi/binfmt:qemu-v7.0.0-28 --install all
- /src/grafana-build artifacts -a docker:grafana:linux/amd64 -a docker:grafana:linux/amd64:ubuntu
-a docker:grafana:linux/arm64 -a docker:grafana:linux/arm64:ubuntu -a docker:grafana:linux/arm/v7
-a docker:grafana:linux/arm/v7:ubuntu --yarn-cache=$$YARN_CACHE_FOLDER --build-id=$$DRONE_BUILD_NUMBER
@@ -2644,7 +2654,7 @@ services:
steps:
- commands:
- mkdir -p bin
- curl -fL -o bin/grabpl https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v3.1.1/grabpl
- curl -fL -o bin/grabpl https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v3.1.2/grabpl
- chmod +x bin/grabpl
image: byrnedo/alpine-curl:0.1.8
name: grabpl
@@ -3228,7 +3238,7 @@ services:
steps:
- commands:
- mkdir -p bin
- curl -fL -o bin/grabpl https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v3.1.1/grabpl
- curl -fL -o bin/grabpl https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v3.1.2/grabpl
- chmod +x bin/grabpl
image: byrnedo/alpine-curl:0.1.8
name: grabpl
@@ -3473,7 +3483,7 @@ steps:
name: identify-runner
- commands:
- mkdir -p bin
- curl -fL -o bin/grabpl https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v3.1.1/grabpl
- curl -fL -o bin/grabpl https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v3.1.2/grabpl
- chmod +x bin/grabpl
image: byrnedo/alpine-curl:0.1.8
name: grabpl
@@ -3605,7 +3615,7 @@ steps:
name: identify-runner
- commands:
- mkdir -p bin
- curl -fL -o bin/grabpl https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v3.1.1/grabpl
- curl -fL -o bin/grabpl https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v3.1.2/grabpl
- chmod +x bin/grabpl
image: byrnedo/alpine-curl:0.1.8
name: grabpl
@@ -4936,7 +4946,7 @@ services:
steps:
- commands:
- mkdir -p bin
- curl -fL -o bin/grabpl https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v3.1.1/grabpl
- curl -fL -o bin/grabpl https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v3.1.2/grabpl
- chmod +x bin/grabpl
image: byrnedo/alpine-curl:0.1.8
name: grabpl
@@ -5695,6 +5705,6 @@ kind: secret
name: gcr_credentials
---
kind: signature
hmac: 812a2ddecbf18b9e10cc4953a157c4d613b5bab169f4cfe72431295e3ce68b2e
hmac: a812aa5256b686f7422b378d66f25eb0d096afbbf2ce8cc200c7984e01601876
...

View File

@@ -11,6 +11,7 @@ on:
branches:
- "main"
- "v*.*.*"
- "release-*.*.*"
# This is run before the pull request has been merged, so we'll run against the src branch
jobs:

View File

@@ -151,7 +151,8 @@ RUN if grep -i -q alpine /etc/issue && [ `arch` = "x86_64" ]; then \
usr/glibc-compat/lib/libdl.so.2 \
usr/glibc-compat/lib/libm.so.6 \
usr/glibc-compat/lib/libpthread.so.0 \
usr/glibc-compat/lib/librt.so.1 && \
usr/glibc-compat/lib/librt.so.1 \
usr/glibc-compat/lib/libresolv.so.2 && \
mkdir /lib64 && \
ln -s /usr/glibc-compat/lib/ld-linux-x86-64.so.2 /lib64; \
fi

View File

@@ -272,6 +272,10 @@ Path to the certificate file (if `protocol` is set to `https` or `h2`).
Path to the certificate key file (if `protocol` is set to `https` or `h2`).
### cert_pass
Optional. Password to decrypt encrypted certificates.
### certs_watch_interval
Controls whether `cert_key` and `cert_file` are periodically watched for changes.

View File

@@ -244,6 +244,8 @@ To configure Grafana HTTPS and restart Grafana, complete the following steps.
> **Note**: The standard port for SSL traffic is 443, which you can use instead of Grafana's default port 3000. This change might require additional operating system privileges or configuration to bind to lower-numbered privileged ports.
1. Optional. From Grafana v11.2, edit the `cert_pass` configuration option with the decryption password if you are using encrypted certificates.
1. [Restart the Grafana server]({{< relref "./start-restart-grafana#linux" >}}) using `systemd`, `init.d`, or the binary as appropriate for your environment.
## Troubleshooting

View File

@@ -26,12 +26,13 @@ func (lw *logWrapper) Println(v ...any) {
lw.logger.Info("graphite metric bridge", v...)
}
func ProvideService(cfg *setting.Cfg, reg prometheus.Registerer) (*InternalMetricsService, error) {
func ProvideService(cfg *setting.Cfg, reg prometheus.Registerer, gatherer prometheus.Gatherer) (*InternalMetricsService, error) {
initMetricVars(reg)
initFrontendMetrics(reg)
s := &InternalMetricsService{
Cfg: cfg,
Cfg: cfg,
gatherer: gatherer,
}
return s, s.readSettings()
}
@@ -41,6 +42,7 @@ type InternalMetricsService struct {
intervalSeconds int64
graphiteCfg *graphitebridge.Config
gatherer prometheus.Gatherer
}
func (im *InternalMetricsService) Run(ctx context.Context) error {

View File

@@ -5,8 +5,6 @@ import (
"strings"
"time"
"github.com/prometheus/client_golang/prometheus"
"github.com/grafana/grafana/pkg/infra/metrics/graphitebridge"
)
@@ -40,7 +38,7 @@ func (im *InternalMetricsService) parseGraphiteSettings() error {
URL: address,
Prefix: graphiteSection.Key("prefix").MustString("prod.grafana.%(instance_name)s"),
CountersAsDelta: true,
Gatherer: prometheus.DefaultGatherer,
Gatherer: im.gatherer,
Interval: time.Duration(im.intervalSeconds) * time.Second,
Timeout: 10 * time.Second,
Logger: &logWrapper{logger: metricsLogger},

View File

@@ -78,10 +78,17 @@ type keySetJWKS struct {
}
func NewAzureADProvider(info *social.OAuthInfo, cfg *setting.Cfg, orgRoleMapper *OrgRoleMapper, ssoSettings ssosettings.Service, features featuremgmt.FeatureToggles, cache remotecache.CacheStorage) *SocialAzureAD {
s := newSocialBase(social.AzureADProviderName, orgRoleMapper, info, features, cfg)
allowedOrganizations, err := util.SplitStringWithError(info.Extra[allowedOrganizationsKey])
if err != nil {
s.log.Error("Invalid auth configuration setting", "config", allowedOrganizationsKey, "provider", social.AzureADProviderName, "error", err)
}
provider := &SocialAzureAD{
SocialBase: newSocialBase(social.AzureADProviderName, orgRoleMapper, info, features, cfg),
SocialBase: s,
cache: cache,
allowedOrganizations: util.SplitString(info.Extra[allowedOrganizationsKey]),
allowedOrganizations: allowedOrganizations,
forceUseGraphAPI: MustBool(info.Extra[forceUseGraphAPIKey], ExtraAzureADSettingKeys[forceUseGraphAPIKey].DefaultValue.(bool)),
}
@@ -169,7 +176,7 @@ func (s *SocialAzureAD) UserInfo(ctx context.Context, client *http.Client, token
}
func (s *SocialAzureAD) Reload(ctx context.Context, settings ssoModels.SSOSettings) error {
newInfo, err := CreateOAuthInfoFromKeyValues(settings.Settings)
newInfo, err := CreateOAuthInfoFromKeyValuesWithLogging(s.log, social.AzureADProviderName, settings.Settings)
if err != nil {
return ssosettings.ErrInvalidSettings.Errorf("SSO settings map cannot be converted to OAuthInfo: %v", err)
}
@@ -183,7 +190,12 @@ func (s *SocialAzureAD) Reload(ctx context.Context, settings ssoModels.SSOSettin
appendUniqueScope(s.Config, social.OfflineAccessScope)
}
s.allowedOrganizations = util.SplitString(newInfo.Extra[allowedOrganizationsKey])
allowedOrganizations, err := util.SplitStringWithError(newInfo.Extra[allowedOrganizationsKey])
if err != nil {
s.log.Error("Invalid auth configuration setting", "config", allowedOrganizationsKey, "provider", social.AzureADProviderName, "error", err)
}
s.allowedOrganizations = allowedOrganizations
s.forceUseGraphAPI = MustBool(newInfo.Extra[forceUseGraphAPIKey], false)
return nil

View File

@@ -2,6 +2,7 @@ package connectors
import (
"context"
"errors"
"fmt"
"io"
"net/http"
@@ -13,6 +14,7 @@ import (
"github.com/mitchellh/mapstructure"
"golang.org/x/oauth2"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/login/social"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/util"
@@ -155,9 +157,25 @@ func MustBool(value any, defaultValue bool) bool {
return result
}
// CreateOAuthInfoFromKeyValuesWithLogging creates an OAuthInfo struct from a map[string]any using mapstructure
// it puts all extra key values into OAuthInfo's Extra map.
// It logs as errors any parsing errors that are not critical
func CreateOAuthInfoFromKeyValuesWithLogging(l log.Logger, provider string, settingsKV map[string]any) (*social.OAuthInfo, error) {
parsingWarns := []error{}
info, err := createOAuthInfoFromKeyValues(settingsKV, &parsingWarns)
if len(parsingWarns) > 0 {
l.Error("Invalid auth configuration setting", "error", errors.Join(parsingWarns...), "provider", provider)
}
return info, err
}
// CreateOAuthInfoFromKeyValues creates an OAuthInfo struct from a map[string]any using mapstructure
// it puts all extra key values into OAuthInfo's Extra map
func CreateOAuthInfoFromKeyValues(settingsKV map[string]any) (*social.OAuthInfo, error) {
return createOAuthInfoFromKeyValues(settingsKV, nil)
}
func createOAuthInfoFromKeyValues(settingsKV map[string]any, parsingWarns *[]error) (*social.OAuthInfo, error) {
emptyStrToSliceDecodeHook := func(from reflect.Type, to reflect.Type, data any) (any, error) {
if from.Kind() == reflect.String && to.Kind() == reflect.Slice {
strData, ok := data.(string)
@@ -168,7 +186,12 @@ func CreateOAuthInfoFromKeyValues(settingsKV map[string]any) (*social.OAuthInfo,
if strData == "" {
return []string{}, nil
}
return util.SplitString(strData), nil
splitStr, err := util.SplitStringWithError(strData)
if err != nil && parsingWarns != nil {
*parsingWarns = append(*parsingWarns, err)
}
return splitStr, nil
}
return data, nil
}

View File

@@ -53,6 +53,18 @@ type SocialGenericOAuth struct {
}
func NewGenericOAuthProvider(info *social.OAuthInfo, cfg *setting.Cfg, orgRoleMapper *OrgRoleMapper, ssoSettings ssosettings.Service, features featuremgmt.FeatureToggles) *SocialGenericOAuth {
s := newSocialBase(social.GenericOAuthProviderName, orgRoleMapper, info, features, cfg)
teamIds, err := util.SplitStringWithError(info.Extra[teamIdsKey])
if err != nil {
s.log.Error("Invalid auth configuration setting", "config", teamIdsKey, "provider", social.GenericOAuthProviderName, "error", err)
}
allowedOrganizations, err := util.SplitStringWithError(info.Extra[allowedOrganizationsKey])
if err != nil {
s.log.Error("Invalid auth configuration setting", "config", allowedOrganizationsKey, "provider", social.GenericOAuthProviderName, "error", err)
}
provider := &SocialGenericOAuth{
SocialBase: newSocialBase(social.GenericOAuthProviderName, orgRoleMapper, info, features, cfg),
teamsUrl: info.TeamsUrl,
@@ -63,8 +75,8 @@ func NewGenericOAuthProvider(info *social.OAuthInfo, cfg *setting.Cfg, orgRoleMa
loginAttributePath: info.Extra[loginAttributePathKey],
idTokenAttributeName: info.Extra[idTokenAttributeNameKey],
teamIdsAttributePath: info.TeamIdsAttributePath,
teamIds: util.SplitString(info.Extra[teamIdsKey]),
allowedOrganizations: util.SplitString(info.Extra[allowedOrganizationsKey]),
teamIds: teamIds,
allowedOrganizations: allowedOrganizations,
}
if features.IsEnabledGlobally(featuremgmt.FlagSsoSettingsApi) {
@@ -118,7 +130,7 @@ func validateTeamsUrlWhenNotEmpty(info *social.OAuthInfo, requester identity.Req
}
func (s *SocialGenericOAuth) Reload(ctx context.Context, settings ssoModels.SSOSettings) error {
newInfo, err := CreateOAuthInfoFromKeyValues(settings.Settings)
newInfo, err := CreateOAuthInfoFromKeyValuesWithLogging(s.log, social.GenericOAuthProviderName, settings.Settings)
if err != nil {
return ssosettings.ErrInvalidSettings.Errorf("SSO settings map cannot be converted to OAuthInfo: %v", err)
}
@@ -128,6 +140,15 @@ func (s *SocialGenericOAuth) Reload(ctx context.Context, settings ssoModels.SSOS
s.updateInfo(ctx, social.GenericOAuthProviderName, newInfo)
teamIds, err := util.SplitStringWithError(newInfo.Extra[teamIdsKey])
if err != nil {
s.log.Error("Invalid auth configuration setting", "config", teamIdsKey, "provider", social.GenericOAuthProviderName, "error", err)
}
allowedOrganizations, err := util.SplitStringWithError(newInfo.Extra[allowedOrganizationsKey])
if err != nil {
s.log.Error("Invalid auth configuration setting", "config", allowedOrganizationsKey, "provider", social.GenericOAuthProviderName, "error", err)
}
s.teamsUrl = newInfo.TeamsUrl
s.emailAttributeName = newInfo.EmailAttributeName
s.emailAttributePath = newInfo.EmailAttributePath
@@ -136,8 +157,8 @@ func (s *SocialGenericOAuth) Reload(ctx context.Context, settings ssoModels.SSOS
s.loginAttributePath = newInfo.Extra[loginAttributePathKey]
s.idTokenAttributeName = newInfo.Extra[idTokenAttributeNameKey]
s.teamIdsAttributePath = newInfo.TeamIdsAttributePath
s.teamIds = util.SplitString(newInfo.Extra[teamIdsKey])
s.allowedOrganizations = util.SplitString(newInfo.Extra[allowedOrganizationsKey])
s.teamIds = teamIds
s.allowedOrganizations = allowedOrganizations
return nil
}

View File

@@ -62,13 +62,23 @@ var (
)
func NewGitHubProvider(info *social.OAuthInfo, cfg *setting.Cfg, orgRoleMapper *OrgRoleMapper, ssoSettings ssosettings.Service, features featuremgmt.FeatureToggles) *SocialGithub {
teamIdsSplitted := util.SplitString(info.Extra[teamIdsKey])
s := newSocialBase(social.GitHubProviderName, orgRoleMapper, info, features, cfg)
teamIdsSplitted, err := util.SplitStringWithError(info.Extra[teamIdsKey])
if err != nil {
s.log.Error("Invalid auth configuration setting", "config", teamIdsKey, "provider", social.GitHubProviderName, "error", err)
}
teamIds := mustInts(teamIdsSplitted)
allowedOrganizations, err := util.SplitStringWithError(info.Extra[allowedOrganizationsKey])
if err != nil {
s.log.Error("Invalid auth configuration setting", "config", allowedOrganizationsKey, "provider", social.GitHubProviderName, "error", err)
}
provider := &SocialGithub{
SocialBase: newSocialBase(social.GitHubProviderName, orgRoleMapper, info, features, cfg),
SocialBase: s,
teamIds: teamIds,
allowedOrganizations: util.SplitString(info.Extra[allowedOrganizationsKey]),
allowedOrganizations: allowedOrganizations,
}
if len(teamIdsSplitted) != len(teamIds) {
@@ -117,14 +127,22 @@ func teamIdsNumbersValidator(info *social.OAuthInfo, requester identity.Requeste
}
func (s *SocialGithub) Reload(ctx context.Context, settings ssoModels.SSOSettings) error {
newInfo, err := CreateOAuthInfoFromKeyValues(settings.Settings)
newInfo, err := CreateOAuthInfoFromKeyValuesWithLogging(s.log, social.GitHubProviderName, settings.Settings)
if err != nil {
return ssosettings.ErrInvalidSettings.Errorf("SSO settings map cannot be converted to OAuthInfo: %v", err)
}
teamIdsSplitted := util.SplitString(newInfo.Extra[teamIdsKey])
teamIdsSplitted, err := util.SplitStringWithError(newInfo.Extra[teamIdsKey])
if err != nil {
s.log.Error("Invalid auth configuration setting", "config", teamIdsKey, "provider", social.GitHubProviderName, "error", err)
}
teamIds := mustInts(teamIdsSplitted)
allowedOrganizations, err := util.SplitStringWithError(newInfo.Extra[allowedOrganizationsKey])
if err != nil {
s.log.Error("Invalid auth configuration setting", "config", allowedOrganizationsKey, "provider", social.GitHubProviderName, "error", err)
}
if len(teamIdsSplitted) != len(teamIds) {
s.log.Warn("Failed to parse team ids. Team ids must be a list of numbers.", "teamIds", teamIdsSplitted)
}
@@ -135,7 +153,7 @@ func (s *SocialGithub) Reload(ctx context.Context, settings ssoModels.SSOSetting
s.updateInfo(ctx, social.GitHubProviderName, newInfo)
s.teamIds = teamIds
s.allowedOrganizations = util.SplitString(newInfo.Extra[allowedOrganizationsKey])
s.allowedOrganizations = allowedOrganizations
return nil
}

View File

@@ -87,7 +87,7 @@ func (s *SocialGitlab) Validate(ctx context.Context, newSettings ssoModels.SSOSe
}
func (s *SocialGitlab) Reload(ctx context.Context, settings ssoModels.SSOSettings) error {
newInfo, err := CreateOAuthInfoFromKeyValues(settings.Settings)
newInfo, err := CreateOAuthInfoFromKeyValuesWithLogging(s.log, social.GitlabProviderName, settings.Settings)
if err != nil {
return ssosettings.ErrInvalidSettings.Errorf("SSO settings map cannot be converted to OAuthInfo: %v", err)
}

View File

@@ -87,7 +87,7 @@ func (s *SocialGoogle) Validate(ctx context.Context, newSettings ssoModels.SSOSe
}
func (s *SocialGoogle) Reload(ctx context.Context, settings ssoModels.SSOSettings) error {
newInfo, err := CreateOAuthInfoFromKeyValues(settings.Settings)
newInfo, err := CreateOAuthInfoFromKeyValuesWithLogging(s.log, social.GoogleProviderName, settings.Settings)
if err != nil {
return ssosettings.ErrInvalidSettings.Errorf("SSO settings map cannot be converted to OAuthInfo: %v", err)
}

View File

@@ -36,15 +36,22 @@ type OrgRecord struct {
}
func NewGrafanaComProvider(info *social.OAuthInfo, cfg *setting.Cfg, orgRoleMapper *OrgRoleMapper, ssoSettings ssosettings.Service, features featuremgmt.FeatureToggles) *SocialGrafanaCom {
s := newSocialBase(social.GrafanaComProviderName, orgRoleMapper, info, features, cfg)
// Override necessary settings
info.AuthUrl = cfg.GrafanaComURL + "/oauth2/authorize"
info.TokenUrl = cfg.GrafanaComURL + "/api/oauth2/token"
info.AuthStyle = "inheader"
allowedOrganizations, err := util.SplitStringWithError(info.Extra[allowedOrganizationsKey])
if err != nil {
s.log.Error("Invalid auth configuration setting", "config", allowedOrganizationsKey, "provider", social.GrafanaComProviderName, "error", err)
}
provider := &SocialGrafanaCom{
SocialBase: newSocialBase(social.GrafanaComProviderName, orgRoleMapper, info, features, cfg),
SocialBase: s,
url: cfg.GrafanaComURL,
allowedOrganizations: util.SplitString(info.Extra[allowedOrganizationsKey]),
allowedOrganizations: allowedOrganizations,
}
if features.IsEnabledGlobally(featuremgmt.FlagSsoSettingsApi) {
@@ -77,11 +84,16 @@ func (s *SocialGrafanaCom) Validate(ctx context.Context, newSettings ssoModels.S
}
func (s *SocialGrafanaCom) Reload(ctx context.Context, settings ssoModels.SSOSettings) error {
newInfo, err := CreateOAuthInfoFromKeyValues(settings.Settings)
newInfo, err := CreateOAuthInfoFromKeyValuesWithLogging(s.log, social.GrafanaComProviderName, settings.Settings)
if err != nil {
return ssosettings.ErrInvalidSettings.Errorf("SSO settings map cannot be converted to OAuthInfo: %v", err)
}
allowedOrganizations, err := util.SplitStringWithError(newInfo.Extra[allowedOrganizationsKey])
if err != nil {
s.log.Error("Invalid auth configuration setting", "config", allowedOrganizationsKey, "provider", social.GrafanaComProviderName, "error", err)
}
// Override necessary settings
newInfo.AuthUrl = s.cfg.GrafanaComURL + "/oauth2/authorize"
newInfo.TokenUrl = s.cfg.GrafanaComURL + "/api/oauth2/token"
@@ -93,7 +105,7 @@ func (s *SocialGrafanaCom) Reload(ctx context.Context, settings ssoModels.SSOSet
s.updateInfo(ctx, social.GrafanaComProviderName, newInfo)
s.url = s.cfg.GrafanaComURL
s.allowedOrganizations = util.SplitString(newInfo.Extra[allowedOrganizationsKey])
s.allowedOrganizations = allowedOrganizations
return nil
}

View File

@@ -84,7 +84,7 @@ func (s *SocialOkta) Validate(ctx context.Context, newSettings ssoModels.SSOSett
}
func (s *SocialOkta) Reload(ctx context.Context, settings ssoModels.SSOSettings) error {
newInfo, err := CreateOAuthInfoFromKeyValues(settings.Settings)
newInfo, err := CreateOAuthInfoFromKeyValuesWithLogging(s.log, social.OktaProviderName, settings.Settings)
if err != nil {
return ssosettings.ErrInvalidSettings.Errorf("SSO settings map cannot be converted to OAuthInfo: %v", err)
}

View File

@@ -65,7 +65,7 @@ func ProvideService(cfg *setting.Cfg,
continue
}
info, err := connectors.CreateOAuthInfoFromKeyValues(ssoSetting.Settings)
info, err := connectors.CreateOAuthInfoFromKeyValuesWithLogging(ss.log, ssoSetting.Provider, ssoSetting.Settings)
if err != nil {
ss.log.Error("Failed to create OAuthInfo for provider", "error", err, "provider", ssoSetting.Provider)
continue
@@ -85,7 +85,7 @@ func ProvideService(cfg *setting.Cfg,
settingsKVs := convertIniSectionToMap(sec)
info, err := connectors.CreateOAuthInfoFromKeyValues(settingsKVs)
info, err := connectors.CreateOAuthInfoFromKeyValuesWithLogging(ss.log, name, settingsKVs)
if err != nil {
ss.log.Error("Failed to create OAuthInfo for provider", "error", err, "provider", name)
continue

View File

@@ -47,6 +47,11 @@ var (
StatusCode: 400,
Status: "empty-name",
}
ErrDashboardTitleTooLong = DashboardErr{
Reason: "Dashboard title cannot contain more than 5 000 characters",
StatusCode: 400,
Status: "title-too-long",
}
ErrDashboardFolderCannotHaveParent = DashboardErr{
Reason: "A Dashboard Folder cannot be added to another folder",
StatusCode: 400,

View File

@@ -113,6 +113,10 @@ func (dr *DashboardServiceImpl) BuildSaveDashboardCommand(ctx context.Context, d
return nil, dashboards.ErrDashboardTitleEmpty
}
if len(dash.Title) > 5000 {
return nil, dashboards.ErrDashboardTitleTooLong
}
metrics.MFolderIDsServiceCount.WithLabelValues(metrics.Dashboard).Inc()
// nolint:staticcheck
if dash.IsFolder && dash.FolderID > 0 {

View File

@@ -33,9 +33,18 @@ func stringsFallback(vals ...string) string {
// SplitString splits a string and returns a list of strings. It supports JSON list syntax and strings separated by commas or spaces.
// It supports quoted strings with spaces, e.g. "foo bar", "baz".
// It will return an empty list if it fails to parse the string.
func SplitString(str string) []string {
result, _ := SplitStringWithError(str)
return result
}
// SplitStringWithError splits a string and returns a list of strings. It supports JSON list syntax and strings separated by commas or spaces.
// It supports quoted strings with spaces, e.g. "foo bar", "baz".
// It returns an error if it cannot parse the string.
func SplitStringWithError(str string) ([]string, error) {
if len(str) == 0 {
return []string{}
return []string{}, nil
}
// JSON list syntax support
@@ -43,9 +52,9 @@ func SplitString(str string) []string {
var res []string
err := json.Unmarshal([]byte(str), &res)
if err != nil {
return []string{}
return []string{}, fmt.Errorf("incorrect format: %s", str)
}
return res
return res, nil
}
matches := stringListItemMatcher.FindAllString(str, -1)
@@ -55,7 +64,7 @@ func SplitString(str string) []string {
result[i] = strings.Trim(match, "\"")
}
return result
return result, nil
}
// GetAgeString returns a string representing certain time from years to minutes.

View File

@@ -53,7 +53,10 @@ const strToValue = (val: string | string[]): SelectableValue[] => {
}
// Stored as JSON Array
if (val.startsWith('[') && val.endsWith(']')) {
return JSON.parse(val).map((v: string) => ({ label: v, value: v }));
// Fallback to parsing it like a non-json string if it is not valid json, instead of crashing.
try {
return JSON.parse(val).map((v: string) => ({ label: v, value: v }));
} catch {}
}
return val.split(/[\s,]/).map((s) => ({ label: s, value: s }));

View File

@@ -34,6 +34,9 @@ def rgm_artifacts_step(name = "rgm-package", artifacts = ["targz:grafana:linux/a
"_EXPERIMENTAL_DAGGER_CLOUD_TOKEN": from_secret(rgm_dagger_token),
},
"commands": [
"docker run --privileged --rm tonistiigi/binfmt:qemu-v7.0.0-28 --version",
"docker run --privileged --rm tonistiigi/binfmt:qemu-v7.0.0-28 --uninstall 'qemu-*'",
"docker run --privileged --rm tonistiigi/binfmt:qemu-v7.0.0-28 --install all",
cmd +
"--go-version={} ".format(golang_version) +
"--yarn-cache=$$YARN_CACHE_FOLDER " +
@@ -58,7 +61,9 @@ def rgm_build_docker_step(ubuntu, alpine, depends_on = ["yarn-install"], file =
"_EXPERIMENTAL_DAGGER_CLOUD_TOKEN": from_secret(rgm_dagger_token),
},
"commands": [
"docker run --privileged --rm tonistiigi/binfmt --install all",
"docker run --privileged --rm tonistiigi/binfmt:qemu-v7.0.0-28 --version",
"docker run --privileged --rm tonistiigi/binfmt:qemu-v7.0.0-28 --uninstall 'qemu-*'",
"docker run --privileged --rm tonistiigi/binfmt:qemu-v7.0.0-28 --install all",
"/src/grafana-build artifacts " +
"-a docker:grafana:linux/amd64 " +
"-a docker:grafana:linux/amd64:ubuntu " +

View File

@@ -2,7 +2,7 @@
global variables
"""
grabpl_version = "v3.1.1"
grabpl_version = "v3.1.2"
golang_version = "1.22.11"
# nodejs_version should match what's in ".nvmrc", but without the v prefix.