* Move repository package to apps
* Move operators to grafana/grafana
* Go mod tidy
* Own package by git sync team for now
* Merged
* Do not use settings in local extra
* Remove dependency on webhook extra
* Hack to work around issue with secure contracts
* Sync Go modules
* Revert "Move operators to grafana/grafana"
This reverts commit 9f19b30a2e.
116 lines
2.7 KiB
Go
116 lines
2.7 KiB
Go
package signature
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
"sync"
|
|
|
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
|
"k8s.io/client-go/dynamic"
|
|
|
|
"github.com/grafana/grafana/apps/provisioning/pkg/repository"
|
|
"github.com/grafana/grafana/pkg/apimachinery/utils"
|
|
"github.com/grafana/grafana/pkg/registry/apis/provisioning/resources"
|
|
)
|
|
|
|
const maxUsers = 10000
|
|
|
|
type loadUsersOnceSigner struct {
|
|
signatures map[string]repository.CommitSignature
|
|
client dynamic.ResourceInterface
|
|
once sync.Once
|
|
onceErr error
|
|
}
|
|
|
|
// NewLoadUsersOnceSigner returns a Signer that loads the signatures from users
|
|
// it will only load the signatures once and cache them
|
|
// if the user is not found, it will use the grafana user as the author
|
|
func NewLoadUsersOnceSigner(client dynamic.ResourceInterface) Signer {
|
|
return &loadUsersOnceSigner{
|
|
client: client,
|
|
once: sync.Once{},
|
|
signatures: map[string]repository.CommitSignature{},
|
|
}
|
|
}
|
|
|
|
func (s *loadUsersOnceSigner) Sign(ctx context.Context, item utils.GrafanaMetaAccessor) (context.Context, error) {
|
|
if s.onceErr != nil {
|
|
return ctx, fmt.Errorf("load signatures: %w", s.onceErr)
|
|
}
|
|
|
|
var err error
|
|
s.once.Do(func() {
|
|
s.signatures, err = s.load(ctx, s.client)
|
|
s.onceErr = err
|
|
})
|
|
if err != nil {
|
|
return ctx, fmt.Errorf("load signatures: %w", err)
|
|
}
|
|
|
|
id := item.GetUpdatedBy()
|
|
if id == "" {
|
|
id = item.GetCreatedBy()
|
|
}
|
|
if id == "" {
|
|
id = "grafana"
|
|
}
|
|
|
|
sig := s.signatures[id] // lookup
|
|
if sig.Name == "" && sig.Email == "" {
|
|
sig.Name = id
|
|
}
|
|
t, err := item.GetUpdatedTimestamp()
|
|
if err == nil && t != nil {
|
|
sig.When = *t
|
|
} else {
|
|
sig.When = item.GetCreationTimestamp().Time
|
|
}
|
|
|
|
return repository.WithAuthorSignature(ctx, sig), nil
|
|
}
|
|
|
|
func (s *loadUsersOnceSigner) load(ctx context.Context, client dynamic.ResourceInterface) (map[string]repository.CommitSignature, error) {
|
|
userInfo := make(map[string]repository.CommitSignature)
|
|
var count int
|
|
err := resources.ForEach(ctx, client, func(item *unstructured.Unstructured) error {
|
|
count++
|
|
if count > maxUsers {
|
|
return errors.New("too many users")
|
|
}
|
|
|
|
sig := repository.CommitSignature{}
|
|
// FIXME: should we improve logging here?
|
|
var (
|
|
ok bool
|
|
err error
|
|
)
|
|
|
|
sig.Name, ok, err = unstructured.NestedString(item.Object, "spec", "login")
|
|
if !ok || err != nil {
|
|
return nil
|
|
}
|
|
sig.Email, ok, err = unstructured.NestedString(item.Object, "spec", "email")
|
|
if !ok || err != nil {
|
|
return nil
|
|
}
|
|
|
|
if sig.Name == sig.Email {
|
|
if sig.Name == "" {
|
|
sig.Name = item.GetName()
|
|
} else if strings.Contains(sig.Email, "@") {
|
|
sig.Email = "" // don't use the same value for name+email
|
|
}
|
|
}
|
|
|
|
userInfo["user:"+item.GetName()] = sig
|
|
return nil
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return userInfo, nil
|
|
}
|