Provisioning: Use inline secrets for gitsync (#109908)
Co-authored-by: Clarity-89 <homes89@ukr.net> Co-authored-by: Roberto Jimenez Sanchez <roberto.jimenez@grafana.com>
This commit is contained in:
co-authored by
Clarity-89
Roberto Jimenez Sanchez
parent
04f392d37b
commit
ce65391067
@@ -6,6 +6,8 @@ import (
|
||||
|
||||
"github.com/google/go-github/v70/github"
|
||||
"golang.org/x/oauth2"
|
||||
|
||||
common "github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1"
|
||||
)
|
||||
|
||||
// Factory creates new GitHub clients.
|
||||
@@ -20,16 +22,15 @@ func ProvideFactory() *Factory {
|
||||
return &Factory{}
|
||||
}
|
||||
|
||||
func (r *Factory) New(ctx context.Context, ghToken string) Client {
|
||||
func (r *Factory) New(ctx context.Context, ghToken common.RawSecureValue) Client {
|
||||
if r.Client != nil {
|
||||
return NewClient(github.NewClient(r.Client))
|
||||
}
|
||||
|
||||
tokenSrc := oauth2.StaticTokenSource(
|
||||
&oauth2.Token{AccessToken: ghToken},
|
||||
)
|
||||
|
||||
if len(ghToken) > 0 {
|
||||
if !ghToken.IsZero() {
|
||||
tokenSrc := oauth2.StaticTokenSource(
|
||||
&oauth2.Token{AccessToken: string(ghToken)},
|
||||
)
|
||||
tokenClient := oauth2.NewClient(ctx, tokenSrc)
|
||||
return NewClient(github.NewClient(tokenClient))
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.52.4. DO NOT EDIT.
|
||||
// Code generated by mockery v2.53.4. DO NOT EDIT.
|
||||
|
||||
package github
|
||||
|
||||
@@ -503,168 +503,6 @@ func (_c *MockGithubRepository_Move_Call) RunAndReturn(run func(context.Context,
|
||||
return _c
|
||||
}
|
||||
|
||||
// OnCreate provides a mock function with given fields: ctx
|
||||
func (_m *MockGithubRepository) OnCreate(ctx context.Context) ([]map[string]interface{}, error) {
|
||||
ret := _m.Called(ctx)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for OnCreate")
|
||||
}
|
||||
|
||||
var r0 []map[string]interface{}
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context) ([]map[string]interface{}, error)); ok {
|
||||
return rf(ctx)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context) []map[string]interface{}); ok {
|
||||
r0 = rf(ctx)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]map[string]interface{})
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context) error); ok {
|
||||
r1 = rf(ctx)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// MockGithubRepository_OnCreate_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'OnCreate'
|
||||
type MockGithubRepository_OnCreate_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// OnCreate is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
func (_e *MockGithubRepository_Expecter) OnCreate(ctx interface{}) *MockGithubRepository_OnCreate_Call {
|
||||
return &MockGithubRepository_OnCreate_Call{Call: _e.mock.On("OnCreate", ctx)}
|
||||
}
|
||||
|
||||
func (_c *MockGithubRepository_OnCreate_Call) Run(run func(ctx context.Context)) *MockGithubRepository_OnCreate_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockGithubRepository_OnCreate_Call) Return(_a0 []map[string]interface{}, _a1 error) *MockGithubRepository_OnCreate_Call {
|
||||
_c.Call.Return(_a0, _a1)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockGithubRepository_OnCreate_Call) RunAndReturn(run func(context.Context) ([]map[string]interface{}, error)) *MockGithubRepository_OnCreate_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// OnDelete provides a mock function with given fields: ctx
|
||||
func (_m *MockGithubRepository) OnDelete(ctx context.Context) error {
|
||||
ret := _m.Called(ctx)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for OnDelete")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context) error); ok {
|
||||
r0 = rf(ctx)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// MockGithubRepository_OnDelete_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'OnDelete'
|
||||
type MockGithubRepository_OnDelete_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// OnDelete is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
func (_e *MockGithubRepository_Expecter) OnDelete(ctx interface{}) *MockGithubRepository_OnDelete_Call {
|
||||
return &MockGithubRepository_OnDelete_Call{Call: _e.mock.On("OnDelete", ctx)}
|
||||
}
|
||||
|
||||
func (_c *MockGithubRepository_OnDelete_Call) Run(run func(ctx context.Context)) *MockGithubRepository_OnDelete_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockGithubRepository_OnDelete_Call) Return(_a0 error) *MockGithubRepository_OnDelete_Call {
|
||||
_c.Call.Return(_a0)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockGithubRepository_OnDelete_Call) RunAndReturn(run func(context.Context) error) *MockGithubRepository_OnDelete_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// OnUpdate provides a mock function with given fields: ctx
|
||||
func (_m *MockGithubRepository) OnUpdate(ctx context.Context) ([]map[string]interface{}, error) {
|
||||
ret := _m.Called(ctx)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for OnUpdate")
|
||||
}
|
||||
|
||||
var r0 []map[string]interface{}
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context) ([]map[string]interface{}, error)); ok {
|
||||
return rf(ctx)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context) []map[string]interface{}); ok {
|
||||
r0 = rf(ctx)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]map[string]interface{})
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context) error); ok {
|
||||
r1 = rf(ctx)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// MockGithubRepository_OnUpdate_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'OnUpdate'
|
||||
type MockGithubRepository_OnUpdate_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// OnUpdate is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
func (_e *MockGithubRepository_Expecter) OnUpdate(ctx interface{}) *MockGithubRepository_OnUpdate_Call {
|
||||
return &MockGithubRepository_OnUpdate_Call{Call: _e.mock.On("OnUpdate", ctx)}
|
||||
}
|
||||
|
||||
func (_c *MockGithubRepository_OnUpdate_Call) Run(run func(ctx context.Context)) *MockGithubRepository_OnUpdate_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockGithubRepository_OnUpdate_Call) Return(_a0 []map[string]interface{}, _a1 error) *MockGithubRepository_OnUpdate_Call {
|
||||
_c.Call.Return(_a0, _a1)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockGithubRepository_OnUpdate_Call) RunAndReturn(run func(context.Context) ([]map[string]interface{}, error)) *MockGithubRepository_OnUpdate_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// Owner provides a mock function with no fields
|
||||
func (_m *MockGithubRepository) Owner() string {
|
||||
ret := _m.Called()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.52.4. DO NOT EDIT.
|
||||
// Code generated by mockery v2.53.4. DO NOT EDIT.
|
||||
|
||||
package github
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.52.4. DO NOT EDIT.
|
||||
// Code generated by mockery v2.53.4. DO NOT EDIT.
|
||||
|
||||
package github
|
||||
|
||||
|
||||
@@ -8,10 +8,9 @@ import (
|
||||
|
||||
provisioning "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/provisioning/controller"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/provisioning/secrets"
|
||||
)
|
||||
|
||||
func Mutator(secrets secrets.RepositorySecrets) controller.Mutator {
|
||||
func Mutator() controller.Mutator {
|
||||
return func(ctx context.Context, obj runtime.Object) error {
|
||||
repo, ok := obj.(*provisioning.Repository)
|
||||
if !ok {
|
||||
@@ -31,16 +30,6 @@ func Mutator(secrets secrets.RepositorySecrets) controller.Mutator {
|
||||
repo.Spec.GitHub.URL = url
|
||||
}
|
||||
|
||||
if repo.Spec.GitHub.Token != "" {
|
||||
secretName := repo.Name + githubTokenSecretSuffix
|
||||
nameOrValue, err := secrets.Encrypt(ctx, repo, secretName, repo.Spec.GitHub.Token)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
repo.Spec.GitHub.EncryptedToken = nameOrValue
|
||||
repo.Spec.GitHub.Token = ""
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,25 +2,21 @@ package github
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
provisioning "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/provisioning/secrets"
|
||||
"github.com/stretchr/testify/assert"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
|
||||
provisioning "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1"
|
||||
)
|
||||
|
||||
func TestMutator(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
obj runtime.Object
|
||||
token string
|
||||
setupMocks func(*secrets.MockRepositorySecrets)
|
||||
expectedToken string
|
||||
expectedEncryptedToken string
|
||||
expectedError string
|
||||
name string
|
||||
obj runtime.Object
|
||||
token string
|
||||
expectedError string
|
||||
}{
|
||||
{
|
||||
name: "trims trailing .git and slash from GitHub URL",
|
||||
@@ -35,9 +31,6 @@ func TestMutator(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
setupMocks: func(mockSecrets *secrets.MockRepositorySecrets) {},
|
||||
expectedToken: "",
|
||||
expectedEncryptedToken: "",
|
||||
},
|
||||
{
|
||||
name: "trims only trailing slash from GitHub URL",
|
||||
@@ -52,9 +45,6 @@ func TestMutator(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
setupMocks: func(mockSecrets *secrets.MockRepositorySecrets) {},
|
||||
expectedToken: "",
|
||||
expectedEncryptedToken: "",
|
||||
},
|
||||
{
|
||||
name: "trims only trailing .git from GitHub URL",
|
||||
@@ -69,9 +59,6 @@ func TestMutator(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
setupMocks: func(mockSecrets *secrets.MockRepositorySecrets) {},
|
||||
expectedToken: "",
|
||||
expectedEncryptedToken: "",
|
||||
},
|
||||
{
|
||||
name: "does not trim if no .git or slash",
|
||||
@@ -86,76 +73,6 @@ func TestMutator(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
setupMocks: func(mockSecrets *secrets.MockRepositorySecrets) {},
|
||||
expectedToken: "",
|
||||
expectedEncryptedToken: "",
|
||||
},
|
||||
{
|
||||
name: "successful token encryption",
|
||||
obj: &provisioning.Repository{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test-repo",
|
||||
Namespace: "default",
|
||||
},
|
||||
Spec: provisioning.RepositorySpec{
|
||||
GitHub: &provisioning.GitHubRepositoryConfig{
|
||||
Token: "secret-token",
|
||||
},
|
||||
},
|
||||
},
|
||||
setupMocks: func(mockSecrets *secrets.MockRepositorySecrets) {
|
||||
mockSecrets.EXPECT().Encrypt(
|
||||
context.Background(),
|
||||
&provisioning.Repository{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test-repo",
|
||||
Namespace: "default",
|
||||
},
|
||||
Spec: provisioning.RepositorySpec{
|
||||
GitHub: &provisioning.GitHubRepositoryConfig{
|
||||
Token: "secret-token",
|
||||
},
|
||||
},
|
||||
},
|
||||
"test-repo"+githubTokenSecretSuffix,
|
||||
"secret-token",
|
||||
).Return([]byte("encrypted-token"), nil)
|
||||
},
|
||||
expectedToken: "",
|
||||
expectedEncryptedToken: "encrypted-token",
|
||||
},
|
||||
{
|
||||
name: "encryption error",
|
||||
obj: &provisioning.Repository{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test-repo",
|
||||
Namespace: "default",
|
||||
},
|
||||
Spec: provisioning.RepositorySpec{
|
||||
GitHub: &provisioning.GitHubRepositoryConfig{
|
||||
Token: "secret-token",
|
||||
},
|
||||
},
|
||||
},
|
||||
setupMocks: func(mockSecrets *secrets.MockRepositorySecrets) {
|
||||
mockSecrets.EXPECT().Encrypt(
|
||||
context.Background(),
|
||||
&provisioning.Repository{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test-repo",
|
||||
Namespace: "default",
|
||||
},
|
||||
Spec: provisioning.RepositorySpec{
|
||||
GitHub: &provisioning.GitHubRepositoryConfig{
|
||||
Token: "secret-token",
|
||||
},
|
||||
},
|
||||
},
|
||||
"test-repo"+githubTokenSecretSuffix,
|
||||
"secret-token",
|
||||
).Return(nil, errors.New("encryption failed"))
|
||||
},
|
||||
expectedError: "encryption failed",
|
||||
},
|
||||
{
|
||||
name: "no github spec",
|
||||
@@ -168,9 +85,6 @@ func TestMutator(t *testing.T) {
|
||||
GitHub: nil,
|
||||
},
|
||||
},
|
||||
setupMocks: func(_ *secrets.MockRepositorySecrets) {
|
||||
// No expectations
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "empty token",
|
||||
@@ -180,30 +94,19 @@ func TestMutator(t *testing.T) {
|
||||
Namespace: "default",
|
||||
},
|
||||
Spec: provisioning.RepositorySpec{
|
||||
GitHub: &provisioning.GitHubRepositoryConfig{
|
||||
Token: "",
|
||||
},
|
||||
GitHub: &provisioning.GitHubRepositoryConfig{},
|
||||
},
|
||||
},
|
||||
setupMocks: func(_ *secrets.MockRepositorySecrets) {
|
||||
// No expectations
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "non-repository object",
|
||||
obj: &runtime.Unknown{},
|
||||
setupMocks: func(_ *secrets.MockRepositorySecrets) {
|
||||
// No expectations
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
mockSecrets := secrets.NewMockRepositorySecrets(t)
|
||||
tt.setupMocks(mockSecrets)
|
||||
|
||||
mutator := Mutator(mockSecrets)
|
||||
mutator := Mutator()
|
||||
err := mutator(context.Background(), tt.obj)
|
||||
|
||||
if tt.expectedError != "" {
|
||||
@@ -211,16 +114,6 @@ func TestMutator(t *testing.T) {
|
||||
assert.Contains(t, err.Error(), tt.expectedError)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Check that token was cleared and encrypted token was set
|
||||
if repo, ok := tt.obj.(*provisioning.Repository); ok && repo.Spec.GitHub != nil {
|
||||
if tt.expectedEncryptedToken != "" {
|
||||
// Token should be cleared after encryption
|
||||
assert.Empty(t, repo.Spec.GitHub.Token, "Token should be cleared after encryption")
|
||||
// EncryptedToken should be set to the expected value
|
||||
assert.Equal(t, tt.expectedEncryptedToken, string(repo.Spec.GitHub.EncryptedToken), "EncryptedToken should match expected value")
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -7,25 +7,20 @@ import (
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/grafana/grafana-app-sdk/logging"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
|
||||
provisioning "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1"
|
||||
common "github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/provisioning/repository"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/provisioning/repository/git"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/provisioning/safepath"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/provisioning/secrets"
|
||||
)
|
||||
|
||||
//nolint:gosec // This is a constant for a secret suffix
|
||||
const githubTokenSecretSuffix = "-github-token"
|
||||
|
||||
// Make sure all public functions of this struct call the (*githubRepository).logger function, to ensure the GH repo details are included.
|
||||
type githubRepository struct {
|
||||
git.GitRepository
|
||||
config *provisioning.Repository
|
||||
gh Client // assumes github.com base URL
|
||||
secrets secrets.RepositorySecrets
|
||||
config *provisioning.Repository
|
||||
gh Client // assumes github.com base URL
|
||||
|
||||
owner string
|
||||
repo string
|
||||
@@ -42,7 +37,6 @@ type GithubRepository interface {
|
||||
repository.Reader
|
||||
repository.RepositoryWithURLs
|
||||
repository.StageableRepository
|
||||
repository.Hooks
|
||||
Owner() string
|
||||
Repo() string
|
||||
Client() Client
|
||||
@@ -53,8 +47,7 @@ func NewGitHub(
|
||||
config *provisioning.Repository,
|
||||
gitRepo git.GitRepository,
|
||||
factory *Factory,
|
||||
token string,
|
||||
secrets secrets.RepositorySecrets,
|
||||
token common.RawSecureValue,
|
||||
) (GithubRepository, error) {
|
||||
owner, repo, err := ParseOwnerRepoGithub(config.Spec.GitHub.URL)
|
||||
if err != nil {
|
||||
@@ -67,7 +60,6 @@ func NewGitHub(
|
||||
gh: factory.New(ctx, token), // TODO, baseURL from config
|
||||
owner: owner,
|
||||
repo: repo,
|
||||
secrets: secrets,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -242,23 +234,3 @@ func (r *githubRepository) RefURLs(ctx context.Context, ref string) (*provisioni
|
||||
|
||||
return urls, nil
|
||||
}
|
||||
|
||||
func (r *githubRepository) OnCreate(_ context.Context) ([]map[string]interface{}, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (r *githubRepository) OnUpdate(_ context.Context) ([]map[string]interface{}, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (r *githubRepository) OnDelete(ctx context.Context) error {
|
||||
logger := logging.FromContext(ctx)
|
||||
secretName := r.config.Name + githubTokenSecretSuffix
|
||||
if err := r.secrets.Delete(ctx, r.config, secretName); err != nil {
|
||||
return fmt.Errorf("delete github token secret: %w", err)
|
||||
}
|
||||
|
||||
logger.Info("Deleted github token secret", "secretName", secretName)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -15,9 +15,9 @@ import (
|
||||
field "k8s.io/apimachinery/pkg/util/validation/field"
|
||||
|
||||
provisioning "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1"
|
||||
common "github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/provisioning/repository"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/provisioning/repository/git"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/provisioning/secrets"
|
||||
)
|
||||
|
||||
func TestNewGitHub(t *testing.T) {
|
||||
@@ -81,16 +81,13 @@ func TestNewGitHub(t *testing.T) {
|
||||
|
||||
gitRepo := git.NewMockGitRepository(t)
|
||||
|
||||
mockSecrets := secrets.NewMockRepositorySecrets(t)
|
||||
|
||||
// Call the function under test
|
||||
repo, err := NewGitHub(
|
||||
context.Background(),
|
||||
tt.config,
|
||||
gitRepo,
|
||||
factory,
|
||||
tt.token,
|
||||
mockSecrets,
|
||||
common.RawSecureValue(tt.token),
|
||||
)
|
||||
|
||||
// Check results
|
||||
@@ -179,10 +176,14 @@ func TestGitHubRepositoryValidate(t *testing.T) {
|
||||
GitHub: &provisioning.GitHubRepositoryConfig{
|
||||
URL: "https://github.com/grafana/grafana",
|
||||
Branch: "main",
|
||||
Token: "valid-token",
|
||||
Path: "dashboards",
|
||||
},
|
||||
},
|
||||
Secure: provisioning.SecureValues{
|
||||
Token: common.InlineSecureValue{
|
||||
Name: "with-name",
|
||||
},
|
||||
},
|
||||
},
|
||||
mockSetup: func(m *git.MockGitRepository) {
|
||||
m.On("Config").Return(&provisioning.Repository{
|
||||
@@ -190,10 +191,14 @@ func TestGitHubRepositoryValidate(t *testing.T) {
|
||||
GitHub: &provisioning.GitHubRepositoryConfig{
|
||||
URL: "https://github.com/grafana/grafana",
|
||||
Branch: "main",
|
||||
Token: "valid-token",
|
||||
Path: "dashboards",
|
||||
},
|
||||
},
|
||||
Secure: provisioning.SecureValues{
|
||||
Token: common.InlineSecureValue{
|
||||
Name: "with-name",
|
||||
},
|
||||
},
|
||||
})
|
||||
m.On("Validate").Return(field.ErrorList{})
|
||||
},
|
||||
@@ -223,7 +228,11 @@ func TestGitHubRepositoryValidate(t *testing.T) {
|
||||
GitHub: &provisioning.GitHubRepositoryConfig{
|
||||
URL: "",
|
||||
Branch: "main",
|
||||
Token: "valid-token",
|
||||
},
|
||||
},
|
||||
Secure: provisioning.SecureValues{
|
||||
Token: common.InlineSecureValue{
|
||||
Name: "with-name",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -233,7 +242,11 @@ func TestGitHubRepositoryValidate(t *testing.T) {
|
||||
GitHub: &provisioning.GitHubRepositoryConfig{
|
||||
URL: "",
|
||||
Branch: "main",
|
||||
Token: "valid-token",
|
||||
},
|
||||
},
|
||||
Secure: provisioning.SecureValues{
|
||||
Token: common.InlineSecureValue{
|
||||
Name: "with-name",
|
||||
},
|
||||
},
|
||||
})
|
||||
@@ -248,7 +261,11 @@ func TestGitHubRepositoryValidate(t *testing.T) {
|
||||
GitHub: &provisioning.GitHubRepositoryConfig{
|
||||
URL: "invalid-url",
|
||||
Branch: "main",
|
||||
Token: "valid-token",
|
||||
},
|
||||
},
|
||||
Secure: provisioning.SecureValues{
|
||||
Token: common.InlineSecureValue{
|
||||
Name: "with-name",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -258,7 +275,11 @@ func TestGitHubRepositoryValidate(t *testing.T) {
|
||||
GitHub: &provisioning.GitHubRepositoryConfig{
|
||||
URL: "invalid-url",
|
||||
Branch: "main",
|
||||
Token: "valid-token",
|
||||
},
|
||||
},
|
||||
Secure: provisioning.SecureValues{
|
||||
Token: common.InlineSecureValue{
|
||||
Name: "with-name",
|
||||
},
|
||||
},
|
||||
})
|
||||
@@ -273,7 +294,11 @@ func TestGitHubRepositoryValidate(t *testing.T) {
|
||||
GitHub: &provisioning.GitHubRepositoryConfig{
|
||||
URL: "https://gitlab.com/grafana/grafana",
|
||||
Branch: "main",
|
||||
Token: "valid-token",
|
||||
},
|
||||
},
|
||||
Secure: provisioning.SecureValues{
|
||||
Token: common.InlineSecureValue{
|
||||
Name: "with-name",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -283,7 +308,11 @@ func TestGitHubRepositoryValidate(t *testing.T) {
|
||||
GitHub: &provisioning.GitHubRepositoryConfig{
|
||||
URL: "https://gitlab.com/grafana/grafana",
|
||||
Branch: "main",
|
||||
Token: "valid-token",
|
||||
},
|
||||
},
|
||||
Secure: provisioning.SecureValues{
|
||||
Token: common.InlineSecureValue{
|
||||
Name: "with-name",
|
||||
},
|
||||
},
|
||||
})
|
||||
@@ -339,7 +368,11 @@ func TestGitHubRepositoryTest(t *testing.T) {
|
||||
GitHub: &provisioning.GitHubRepositoryConfig{
|
||||
URL: "https://github.com/grafana/grafana",
|
||||
Branch: "main",
|
||||
Token: "valid-token",
|
||||
},
|
||||
},
|
||||
Secure: provisioning.SecureValues{
|
||||
Token: common.InlineSecureValue{
|
||||
Name: "with-name",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -361,7 +394,11 @@ func TestGitHubRepositoryTest(t *testing.T) {
|
||||
GitHub: &provisioning.GitHubRepositoryConfig{
|
||||
URL: "invalid-url",
|
||||
Branch: "main",
|
||||
Token: "valid-token",
|
||||
},
|
||||
},
|
||||
Secure: provisioning.SecureValues{
|
||||
Token: common.InlineSecureValue{
|
||||
Name: "with-name",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -878,7 +915,11 @@ func TestGitHubRepositoryDelegation(t *testing.T) {
|
||||
GitHub: &provisioning.GitHubRepositoryConfig{
|
||||
URL: "https://github.com/grafana/grafana",
|
||||
Branch: "main",
|
||||
Token: "test-token",
|
||||
},
|
||||
},
|
||||
Secure: provisioning.SecureValues{
|
||||
Token: common.InlineSecureValue{
|
||||
Name: "with-name",
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -1095,7 +1136,6 @@ func TestGitHubRepositoryAccessors(t *testing.T) {
|
||||
GitHub: &provisioning.GitHubRepositoryConfig{
|
||||
URL: "https://github.com/grafana/grafana",
|
||||
Branch: "main",
|
||||
Token: "test-token",
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -1137,82 +1177,6 @@ func TestGitHubRepositoryAccessors(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestGitHubRepository_OnDelete(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
setupMock func(*secrets.MockRepositorySecrets)
|
||||
config *provisioning.Repository
|
||||
expectedError string
|
||||
}{
|
||||
{
|
||||
name: "successful secret deletion",
|
||||
setupMock: func(mockSecrets *secrets.MockRepositorySecrets) {
|
||||
mockSecrets.EXPECT().Delete(
|
||||
context.Background(),
|
||||
&provisioning.Repository{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test-repo",
|
||||
Namespace: "default",
|
||||
},
|
||||
},
|
||||
"test-repo"+githubTokenSecretSuffix,
|
||||
).Return(nil)
|
||||
},
|
||||
config: &provisioning.Repository{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test-repo",
|
||||
Namespace: "default",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "secret deletion error",
|
||||
setupMock: func(mockSecrets *secrets.MockRepositorySecrets) {
|
||||
mockSecrets.EXPECT().Delete(
|
||||
context.Background(),
|
||||
&provisioning.Repository{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test-repo",
|
||||
Namespace: "default",
|
||||
},
|
||||
},
|
||||
"test-repo"+githubTokenSecretSuffix,
|
||||
).Return(errors.New("failed to delete secret"))
|
||||
},
|
||||
config: &provisioning.Repository{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test-repo",
|
||||
Namespace: "default",
|
||||
},
|
||||
},
|
||||
expectedError: "delete github token secret: failed to delete secret",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
mockSecrets := secrets.NewMockRepositorySecrets(t)
|
||||
tt.setupMock(mockSecrets)
|
||||
|
||||
githubRepo := &githubRepository{
|
||||
config: tt.config,
|
||||
secrets: mockSecrets,
|
||||
}
|
||||
|
||||
err := githubRepo.OnDelete(context.Background())
|
||||
|
||||
if tt.expectedError != "" {
|
||||
require.Error(t, err)
|
||||
require.Contains(t, err.Error(), tt.expectedError)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
mockSecrets.AssertExpectations(t)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGithubRepository_Move(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -1262,7 +1226,6 @@ func TestGithubRepository_Move(t *testing.T) {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Create mock git repository
|
||||
mockGitRepo := git.NewMockGitRepository(t)
|
||||
mockSecrets := &secrets.MockRepositorySecrets{}
|
||||
|
||||
// Setup mock expectations
|
||||
tt.setupMock(mockGitRepo)
|
||||
@@ -1285,7 +1248,6 @@ func TestGithubRepository_Move(t *testing.T) {
|
||||
GitRepository: mockGitRepo,
|
||||
owner: "example",
|
||||
repo: "repo",
|
||||
secrets: mockSecrets,
|
||||
}
|
||||
|
||||
// Execute move operation
|
||||
|
||||
Reference in New Issue
Block a user