694 lines
23 KiB
Go
694 lines
23 KiB
Go
package github_test
|
|
|
|
import (
|
|
"context"
|
|
"encoding/base64"
|
|
"errors"
|
|
"testing"
|
|
|
|
provisioning "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1"
|
|
"github.com/grafana/grafana/apps/provisioning/pkg/connection/github"
|
|
common "github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/mock"
|
|
"github.com/stretchr/testify/require"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
)
|
|
|
|
//nolint:gosec // Test RSA private key (generated for testing purposes only)
|
|
const testPrivateKeyPEM = `-----BEGIN RSA PRIVATE KEY-----
|
|
MIIEowIBAAKCAQEAoInVbLY9io2Q/wHvUIXlEHg2Qyvd8eRzBAVEJ92DS6fx9H10
|
|
06V0VRm78S0MXyo6i+n8ZAbZ0/R+GWpP2Ephxm0Gs2zo+iO2mpB19xQFI4o6ZTOw
|
|
b2WyjSaa2Vr4oyDkqti6AvfjW4VUAu932e08GkgwmmQSHXj7FX2CMWjgUwTTcuaX
|
|
65SHNKLNYLUP0HTumLzoZeqDTdoMMpKNdgH9Avr4/8vkVJ0mD6rqvxnw3JHsseNO
|
|
WdQTxf2aApBNHIIKxWZ2i/ZmjLNey7kltgjEquGiBdJvip3fHhH5XHdkrXcjRtnw
|
|
OJDnDmi5lQwv5yUBOSkbvbXRv/L/m0YLoD/fbwIDAQABAoIBAFfl//hM8/cnuesV
|
|
+R1Con/ZAgTXQOdPqPXbmEyniVrkMqMmCdBUOBTcST4s5yg36+RtkeaGpb/ajyyF
|
|
PAB2AYDucwvMpudGpJWOYTiOOp4R8hU1LvZfXVrRd1lo6NgQi4NLtNUpOtACeVQ+
|
|
H4Yv0YemXQ47mnuOoRNMK/u3q5NoIdSahWptXBgUno8KklNpUrH3IYWaUxfBzDN3
|
|
2xsVRTn2SfTSyoDmTDdTgptJONmoK1/sV7UsgWksdFc6XyYhsFAZgOGEJrBABRvF
|
|
546dyQ0cWxuPyVXpM7CN3tqC5ssvLjElg3LicK1V6gnjpdRnnvX88d1Eh3Uc/9IM
|
|
OZInT2ECgYEA6W8sQXTWinyEwl8SDKKMbB2ApIghAcFgdRxprZE4WFxjsYNCNL70
|
|
dnSB7MRuzmxf5W77cV0N7JhH66N8HvY6Xq9olrpQ5dNttR4w8Pyv3wavDe8x7seL
|
|
5L2Xtbu7ihDr8Dk27MjiBSin3IxhBP5CJS910+pR6LrAWtEuU+FzFfECgYEAsA6y
|
|
qxHhCMXlTnauXhsnmPd1g61q7chW8kLQFYtHMLlQlgjHTW7irDZ9cPbPYDNjwRLO
|
|
7KLorcpv2NKe7rqq2ZyCm6hf1b9WnlQjo3dLpNWMu6fhy/smK8MgbRqcWpX+oTKF
|
|
79mK6hbY7o6eBzsQHBl7Z+LBNuwYmp9qOodPa18CgYEArv6ipKdcNhFGzRfMRiCN
|
|
OHederp6VACNuP2F05IsNUF9kxOdTEFirnKE++P+VU01TqA2azOhPp6iO+ohIGzi
|
|
MR06QNSH1OL9OWvasK4dggpWrRGF00VQgDgJRTnpS4WH+lxJ6pRlrAxgWpv6F24s
|
|
VAgSQr1Ejj2B+hMasdMvHWECgYBJ4uE4yhgXBnZlp4kmFV9Y4wF+cZkekaVrpn6N
|
|
jBYkbKFVVfnOlWqru3KJpgsB5I9IyAvvY68iwIKQDFSG+/AXw4dMrC0MF3DSoZ0T
|
|
TU2Br92QI7SvVod+djV1lGVp3ukt3XY4YqPZ+hywgUnw3uiz4j3YK2HLGup4ec6r
|
|
IX5DIQKBgHRLzvT3zqtlR1Oh0vv098clLwt+pGzXOxzJpxioOa5UqK13xIpFXbcg
|
|
iWUVh5YXCcuqaICUv4RLIEac5xQitk9Is/9IhP0NJ/81rHniosvdSpCeFXzxTImS
|
|
B8Uc0WUgheB4+yVKGnYpYaSOgFFI5+1BYUva/wDHLy2pWHz39Usb
|
|
-----END RSA PRIVATE KEY-----`
|
|
|
|
func TestConnection_Mutate(t *testing.T) {
|
|
privateKeyBase64 := base64.StdEncoding.EncodeToString([]byte(testPrivateKeyPEM))
|
|
|
|
tests := []struct {
|
|
name string
|
|
connection *provisioning.Connection
|
|
secrets github.ConnectionSecrets
|
|
wantErr bool
|
|
validateError func(t *testing.T, err error)
|
|
validateResult func(t *testing.T, connection *provisioning.Connection)
|
|
}{
|
|
{
|
|
name: "should add URL to Github connection",
|
|
connection: &provisioning.Connection{
|
|
ObjectMeta: metav1.ObjectMeta{Name: "test-connection"},
|
|
Spec: provisioning.ConnectionSpec{
|
|
Type: provisioning.GithubConnectionType,
|
|
GitHub: &provisioning.GitHubConnectionConfig{
|
|
AppID: "123",
|
|
InstallationID: "456",
|
|
},
|
|
},
|
|
Secure: provisioning.ConnectionSecure{
|
|
PrivateKey: common.InlineSecureValue{
|
|
Create: common.NewSecretValue(privateKeyBase64),
|
|
},
|
|
},
|
|
},
|
|
secrets: github.ConnectionSecrets{
|
|
PrivateKey: common.NewSecretValue(privateKeyBase64),
|
|
},
|
|
wantErr: false,
|
|
validateResult: func(t *testing.T, connection *provisioning.Connection) {
|
|
assert.Equal(t, "https://github.com/settings/installations/456", connection.Spec.URL)
|
|
},
|
|
},
|
|
{
|
|
name: "should generate JWT token when private key is provided",
|
|
connection: &provisioning.Connection{
|
|
ObjectMeta: metav1.ObjectMeta{Name: "test-connection"},
|
|
Spec: provisioning.ConnectionSpec{
|
|
Type: provisioning.GithubConnectionType,
|
|
GitHub: &provisioning.GitHubConnectionConfig{
|
|
AppID: "123",
|
|
InstallationID: "456",
|
|
},
|
|
},
|
|
Secure: provisioning.ConnectionSecure{
|
|
PrivateKey: common.InlineSecureValue{
|
|
Create: common.NewSecretValue(privateKeyBase64),
|
|
},
|
|
},
|
|
},
|
|
secrets: github.ConnectionSecrets{
|
|
PrivateKey: common.NewSecretValue(privateKeyBase64),
|
|
},
|
|
wantErr: false,
|
|
validateResult: func(t *testing.T, connection *provisioning.Connection) {
|
|
assert.Equal(t, "https://github.com/settings/installations/456", connection.Spec.URL)
|
|
assert.False(t, connection.Secure.Token.Create.IsZero(), "JWT token should be generated")
|
|
},
|
|
},
|
|
{
|
|
name: "should not generate JWT token when no new private key is provided",
|
|
connection: &provisioning.Connection{
|
|
ObjectMeta: metav1.ObjectMeta{Name: "test-connection", Generation: 1},
|
|
Spec: provisioning.ConnectionSpec{
|
|
Type: provisioning.GithubConnectionType,
|
|
GitHub: &provisioning.GitHubConnectionConfig{
|
|
AppID: "123",
|
|
InstallationID: "456",
|
|
},
|
|
},
|
|
Secure: provisioning.ConnectionSecure{
|
|
PrivateKey: common.InlineSecureValue{
|
|
// The private key is already in the stoere
|
|
Name: "somePrivateKey",
|
|
},
|
|
Token: common.InlineSecureValue{
|
|
Create: common.NewSecretValue("someToken"),
|
|
},
|
|
},
|
|
},
|
|
secrets: github.ConnectionSecrets{
|
|
PrivateKey: common.NewSecretValue(privateKeyBase64),
|
|
Token: common.NewSecretValue("someToken"),
|
|
},
|
|
wantErr: false,
|
|
validateResult: func(t *testing.T, connection *provisioning.Connection) {
|
|
assert.Equal(t, "https://github.com/settings/installations/456", connection.Spec.URL)
|
|
assert.False(t, connection.Secure.Token.Create.IsZero(), "JWT token should be generated")
|
|
assert.Equal(t, "someToken", connection.Secure.Token.Create.DangerouslyExposeAndConsumeValue())
|
|
},
|
|
},
|
|
{
|
|
name: "should do nothing when GitHub config is nil",
|
|
connection: &provisioning.Connection{
|
|
ObjectMeta: metav1.ObjectMeta{Name: "test-connection"},
|
|
Spec: provisioning.ConnectionSpec{
|
|
Type: provisioning.GitlabConnectionType,
|
|
Gitlab: &provisioning.GitlabConnectionConfig{
|
|
ClientID: "clientID",
|
|
},
|
|
},
|
|
},
|
|
secrets: github.ConnectionSecrets{},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "should fail when private key is not base64",
|
|
connection: &provisioning.Connection{
|
|
ObjectMeta: metav1.ObjectMeta{Name: "test-connection"},
|
|
Spec: provisioning.ConnectionSpec{
|
|
Type: provisioning.GithubConnectionType,
|
|
GitHub: &provisioning.GitHubConnectionConfig{
|
|
AppID: "123",
|
|
InstallationID: "456",
|
|
},
|
|
},
|
|
Secure: provisioning.ConnectionSecure{
|
|
PrivateKey: common.InlineSecureValue{
|
|
Create: common.NewSecretValue("invalid-key"),
|
|
},
|
|
},
|
|
},
|
|
secrets: github.ConnectionSecrets{
|
|
PrivateKey: "invalid-key",
|
|
},
|
|
wantErr: true,
|
|
validateError: func(t *testing.T, err error) {
|
|
assert.Contains(t, err.Error(), "failed to generate JWT token")
|
|
assert.Contains(t, err.Error(), "failed to decode base64 private key")
|
|
},
|
|
},
|
|
{
|
|
name: "should fail when private key is invalid",
|
|
connection: &provisioning.Connection{
|
|
ObjectMeta: metav1.ObjectMeta{Name: "test-connection"},
|
|
Spec: provisioning.ConnectionSpec{
|
|
Type: provisioning.GithubConnectionType,
|
|
GitHub: &provisioning.GitHubConnectionConfig{
|
|
AppID: "123",
|
|
InstallationID: "456",
|
|
},
|
|
},
|
|
Secure: provisioning.ConnectionSecure{
|
|
PrivateKey: common.InlineSecureValue{
|
|
Create: common.NewSecretValue(base64.StdEncoding.EncodeToString([]byte("invalid-key"))),
|
|
},
|
|
},
|
|
},
|
|
secrets: github.ConnectionSecrets{},
|
|
wantErr: true,
|
|
validateError: func(t *testing.T, err error) {
|
|
assert.Contains(t, err.Error(), "failed to generate JWT token")
|
|
assert.Contains(t, err.Error(), "failed to parse private key")
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
mockFactory := github.NewMockGithubFactory(t)
|
|
conn := github.NewConnection(tt.connection, mockFactory, tt.secrets)
|
|
|
|
err := conn.Mutate(context.Background())
|
|
|
|
if tt.wantErr {
|
|
require.Error(t, err)
|
|
if tt.validateError != nil {
|
|
tt.validateError(t, err)
|
|
}
|
|
} else {
|
|
require.NoError(t, err)
|
|
if tt.validateResult != nil {
|
|
tt.validateResult(t, tt.connection)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestConnection_GenerateRepositoryToken(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
connection *provisioning.Connection
|
|
repo *provisioning.Repository
|
|
setupMock func(*github.MockGithubFactory)
|
|
expectedToken common.RawSecureValue
|
|
expectedError string
|
|
}{
|
|
{
|
|
name: "success",
|
|
connection: &provisioning.Connection{
|
|
ObjectMeta: metav1.ObjectMeta{Name: "test-connection"},
|
|
Spec: provisioning.ConnectionSpec{
|
|
Type: provisioning.GithubConnectionType,
|
|
GitHub: &provisioning.GitHubConnectionConfig{
|
|
AppID: "123",
|
|
InstallationID: "456",
|
|
},
|
|
},
|
|
Secure: provisioning.ConnectionSecure{
|
|
Token: common.InlineSecureValue{
|
|
Create: common.RawSecureValue("jwt-token"),
|
|
},
|
|
},
|
|
},
|
|
repo: &provisioning.Repository{
|
|
ObjectMeta: metav1.ObjectMeta{Name: "test-repo"},
|
|
Spec: provisioning.RepositorySpec{
|
|
Type: provisioning.GitHubRepositoryType,
|
|
GitHub: &provisioning.GitHubRepositoryConfig{
|
|
URL: "https://github.com/test-owner/test-repo",
|
|
},
|
|
},
|
|
},
|
|
setupMock: func(mockFactory *github.MockGithubFactory) {
|
|
mockClient := github.NewMockClient(t)
|
|
mockFactory.EXPECT().New(mock.Anything, common.RawSecureValue("jwt-token")).Return(mockClient)
|
|
mockClient.EXPECT().CreateInstallationAccessToken(mock.Anything, "456", "test-repo").
|
|
Return(github.InstallationToken{Token: "ghs_repository_token_123", ExpiresAt: "2024-01-01T00:00:00Z"}, nil)
|
|
},
|
|
expectedToken: common.RawSecureValue("ghs_repository_token_123"),
|
|
},
|
|
{
|
|
name: "nil repository returns error",
|
|
connection: &provisioning.Connection{
|
|
ObjectMeta: metav1.ObjectMeta{Name: "test-connection"},
|
|
Spec: provisioning.ConnectionSpec{
|
|
Type: provisioning.GithubConnectionType,
|
|
GitHub: &provisioning.GitHubConnectionConfig{
|
|
AppID: "123",
|
|
InstallationID: "456",
|
|
},
|
|
},
|
|
},
|
|
repo: nil,
|
|
expectedError: "a repository is required to generate a token",
|
|
},
|
|
{
|
|
name: "connection without GitHub config returns error",
|
|
connection: &provisioning.Connection{
|
|
ObjectMeta: metav1.ObjectMeta{Name: "test-connection"},
|
|
Spec: provisioning.ConnectionSpec{
|
|
Type: provisioning.GitlabConnectionType,
|
|
Gitlab: &provisioning.GitlabConnectionConfig{
|
|
ClientID: "clientID",
|
|
},
|
|
},
|
|
},
|
|
repo: &provisioning.Repository{
|
|
ObjectMeta: metav1.ObjectMeta{Name: "test-repo"},
|
|
Spec: provisioning.RepositorySpec{
|
|
Type: provisioning.GitHubRepositoryType,
|
|
GitHub: &provisioning.GitHubRepositoryConfig{
|
|
URL: "https://github.com/test-owner/test-repo",
|
|
},
|
|
},
|
|
},
|
|
expectedError: "connection is not a GitHub connection",
|
|
},
|
|
{
|
|
name: "repository without GitHub config returns error",
|
|
connection: &provisioning.Connection{
|
|
ObjectMeta: metav1.ObjectMeta{Name: "test-connection"},
|
|
Spec: provisioning.ConnectionSpec{
|
|
Type: provisioning.GithubConnectionType,
|
|
GitHub: &provisioning.GitHubConnectionConfig{
|
|
AppID: "123",
|
|
InstallationID: "456",
|
|
},
|
|
},
|
|
Secure: provisioning.ConnectionSecure{
|
|
Token: common.InlineSecureValue{
|
|
Create: common.RawSecureValue("jwt-token"),
|
|
},
|
|
},
|
|
},
|
|
repo: &provisioning.Repository{
|
|
ObjectMeta: metav1.ObjectMeta{Name: "test-repo"},
|
|
Spec: provisioning.RepositorySpec{
|
|
Type: provisioning.GitHubRepositoryType,
|
|
GitHub: nil,
|
|
},
|
|
},
|
|
expectedError: "repository is not a GitHub repo",
|
|
},
|
|
{
|
|
name: "invalid repository URL returns error",
|
|
connection: &provisioning.Connection{
|
|
ObjectMeta: metav1.ObjectMeta{Name: "test-connection"},
|
|
Spec: provisioning.ConnectionSpec{
|
|
Type: provisioning.GithubConnectionType,
|
|
GitHub: &provisioning.GitHubConnectionConfig{
|
|
AppID: "123",
|
|
InstallationID: "456",
|
|
},
|
|
},
|
|
Secure: provisioning.ConnectionSecure{
|
|
Token: common.InlineSecureValue{
|
|
Create: common.RawSecureValue("jwt-token"),
|
|
},
|
|
},
|
|
},
|
|
repo: &provisioning.Repository{
|
|
ObjectMeta: metav1.ObjectMeta{Name: "test-repo"},
|
|
Spec: provisioning.RepositorySpec{
|
|
Type: provisioning.GitHubRepositoryType,
|
|
GitHub: &provisioning.GitHubRepositoryConfig{
|
|
URL: "invalid-url",
|
|
},
|
|
},
|
|
},
|
|
expectedError: "failed to parse repo URL",
|
|
},
|
|
{
|
|
name: "GitHub API error",
|
|
connection: &provisioning.Connection{
|
|
ObjectMeta: metav1.ObjectMeta{Name: "test-connection"},
|
|
Spec: provisioning.ConnectionSpec{
|
|
Type: provisioning.GithubConnectionType,
|
|
GitHub: &provisioning.GitHubConnectionConfig{
|
|
AppID: "123",
|
|
InstallationID: "456",
|
|
},
|
|
},
|
|
Secure: provisioning.ConnectionSecure{
|
|
Token: common.InlineSecureValue{
|
|
Create: common.RawSecureValue("jwt-token"),
|
|
},
|
|
},
|
|
},
|
|
repo: &provisioning.Repository{
|
|
ObjectMeta: metav1.ObjectMeta{Name: "test-repo"},
|
|
Spec: provisioning.RepositorySpec{
|
|
Type: provisioning.GitHubRepositoryType,
|
|
GitHub: &provisioning.GitHubRepositoryConfig{
|
|
URL: "https://github.com/test-owner/test-repo",
|
|
},
|
|
},
|
|
},
|
|
setupMock: func(mockFactory *github.MockGithubFactory) {
|
|
mockClient := github.NewMockClient(t)
|
|
mockFactory.EXPECT().New(mock.Anything, common.RawSecureValue("jwt-token")).Return(mockClient)
|
|
mockClient.EXPECT().CreateInstallationAccessToken(mock.Anything, "456", "test-repo").
|
|
Return(github.InstallationToken{}, errors.New("API rate limit exceeded"))
|
|
},
|
|
expectedError: "failed to create installation access token",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
mockFactory := github.NewMockGithubFactory(t)
|
|
if tt.setupMock != nil {
|
|
tt.setupMock(mockFactory)
|
|
}
|
|
|
|
conn := github.NewConnection(tt.connection, mockFactory, github.ConnectionSecrets{
|
|
Token: tt.connection.Secure.Token.Create,
|
|
PrivateKey: tt.connection.Secure.PrivateKey.Create,
|
|
})
|
|
token, err := conn.GenerateRepositoryToken(context.Background(), tt.repo)
|
|
|
|
if tt.expectedError != "" {
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), tt.expectedError)
|
|
} else {
|
|
require.NoError(t, err)
|
|
assert.Equal(t, tt.expectedToken, token)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestConnection_Validate(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
connection *provisioning.Connection
|
|
setupMock func(*github.MockGithubFactory)
|
|
wantErr bool
|
|
errMsgContains []string
|
|
}{
|
|
{
|
|
name: "invalid type returns error",
|
|
connection: &provisioning.Connection{
|
|
ObjectMeta: metav1.ObjectMeta{Name: "test-connection"},
|
|
Spec: provisioning.ConnectionSpec{
|
|
Type: "invalid",
|
|
},
|
|
},
|
|
wantErr: true,
|
|
errMsgContains: []string{"spec.type"},
|
|
},
|
|
{
|
|
name: "github type without github config returns error",
|
|
connection: &provisioning.Connection{
|
|
ObjectMeta: metav1.ObjectMeta{Name: "test-connection"},
|
|
Spec: provisioning.ConnectionSpec{
|
|
Type: provisioning.GithubConnectionType,
|
|
},
|
|
},
|
|
wantErr: true,
|
|
errMsgContains: []string{"spec.github"},
|
|
},
|
|
{
|
|
name: "github type without private key returns error",
|
|
connection: &provisioning.Connection{
|
|
ObjectMeta: metav1.ObjectMeta{Name: "test-connection"},
|
|
Spec: provisioning.ConnectionSpec{
|
|
Type: provisioning.GithubConnectionType,
|
|
GitHub: &provisioning.GitHubConnectionConfig{
|
|
AppID: "123",
|
|
InstallationID: "456",
|
|
},
|
|
},
|
|
},
|
|
wantErr: true,
|
|
errMsgContains: []string{"secure.privateKey"},
|
|
},
|
|
{
|
|
name: "github type without token returns error",
|
|
connection: &provisioning.Connection{
|
|
ObjectMeta: metav1.ObjectMeta{Name: "test-connection"},
|
|
Spec: provisioning.ConnectionSpec{
|
|
Type: provisioning.GithubConnectionType,
|
|
GitHub: &provisioning.GitHubConnectionConfig{
|
|
AppID: "123",
|
|
InstallationID: "456",
|
|
},
|
|
},
|
|
Secure: provisioning.ConnectionSecure{
|
|
PrivateKey: common.InlineSecureValue{
|
|
Create: common.NewSecretValue("test-private-key"),
|
|
},
|
|
},
|
|
},
|
|
wantErr: true,
|
|
errMsgContains: []string{"secure.token"},
|
|
},
|
|
{
|
|
name: "github type with client secret returns error",
|
|
connection: &provisioning.Connection{
|
|
ObjectMeta: metav1.ObjectMeta{Name: "test-connection"},
|
|
Spec: provisioning.ConnectionSpec{
|
|
Type: provisioning.GithubConnectionType,
|
|
GitHub: &provisioning.GitHubConnectionConfig{
|
|
AppID: "123",
|
|
InstallationID: "456",
|
|
},
|
|
},
|
|
Secure: provisioning.ConnectionSecure{
|
|
ClientSecret: common.InlineSecureValue{
|
|
Create: common.NewSecretValue("test-client-secret"),
|
|
},
|
|
},
|
|
},
|
|
wantErr: true,
|
|
errMsgContains: []string{"secure.clientSecret"},
|
|
},
|
|
{
|
|
name: "github type without appID returns error",
|
|
connection: &provisioning.Connection{
|
|
ObjectMeta: metav1.ObjectMeta{Name: "test-connection"},
|
|
Spec: provisioning.ConnectionSpec{
|
|
Type: provisioning.GithubConnectionType,
|
|
GitHub: &provisioning.GitHubConnectionConfig{
|
|
InstallationID: "456",
|
|
},
|
|
},
|
|
Secure: provisioning.ConnectionSecure{
|
|
PrivateKey: common.InlineSecureValue{
|
|
Create: common.NewSecretValue("test-private-key"),
|
|
},
|
|
Token: common.InlineSecureValue{
|
|
Create: common.NewSecretValue("test-token"),
|
|
},
|
|
},
|
|
},
|
|
wantErr: true,
|
|
errMsgContains: []string{"spec.github.appID"},
|
|
},
|
|
{
|
|
name: "github type without installationID returns error",
|
|
connection: &provisioning.Connection{
|
|
ObjectMeta: metav1.ObjectMeta{Name: "test-connection"},
|
|
Spec: provisioning.ConnectionSpec{
|
|
Type: provisioning.GithubConnectionType,
|
|
GitHub: &provisioning.GitHubConnectionConfig{
|
|
AppID: "123",
|
|
},
|
|
},
|
|
Secure: provisioning.ConnectionSecure{
|
|
PrivateKey: common.InlineSecureValue{
|
|
Name: "test-private-key",
|
|
},
|
|
Token: common.InlineSecureValue{
|
|
Name: "test-token",
|
|
},
|
|
},
|
|
},
|
|
wantErr: true,
|
|
errMsgContains: []string{"spec.github.installationID"},
|
|
},
|
|
{
|
|
name: "github type with valid config is valid",
|
|
connection: &provisioning.Connection{
|
|
ObjectMeta: metav1.ObjectMeta{Name: "test-connection"},
|
|
Spec: provisioning.ConnectionSpec{
|
|
Type: provisioning.GithubConnectionType,
|
|
GitHub: &provisioning.GitHubConnectionConfig{
|
|
AppID: "123",
|
|
InstallationID: "456",
|
|
},
|
|
},
|
|
Secure: provisioning.ConnectionSecure{
|
|
PrivateKey: common.InlineSecureValue{
|
|
Create: common.NewSecretValue("test-private-key"),
|
|
},
|
|
Token: common.InlineSecureValue{
|
|
Create: common.NewSecretValue("test-token"),
|
|
},
|
|
},
|
|
},
|
|
wantErr: false,
|
|
setupMock: func(mockFactory *github.MockGithubFactory) {
|
|
mockClient := github.NewMockClient(t)
|
|
|
|
mockFactory.EXPECT().New(mock.Anything, common.RawSecureValue("test-token")).Return(mockClient)
|
|
mockClient.EXPECT().GetApp(mock.Anything).Return(github.App{ID: 123, Slug: "test-app"}, nil)
|
|
mockClient.EXPECT().GetAppInstallation(mock.Anything, "456").Return(github.AppInstallation{ID: 456}, nil)
|
|
},
|
|
},
|
|
{
|
|
name: "problem getting app returns error",
|
|
connection: &provisioning.Connection{
|
|
ObjectMeta: metav1.ObjectMeta{Name: "test-connection"},
|
|
Spec: provisioning.ConnectionSpec{
|
|
Type: provisioning.GithubConnectionType,
|
|
GitHub: &provisioning.GitHubConnectionConfig{
|
|
AppID: "123",
|
|
InstallationID: "456",
|
|
},
|
|
},
|
|
Secure: provisioning.ConnectionSecure{
|
|
PrivateKey: common.InlineSecureValue{
|
|
Create: common.NewSecretValue("test-private-key"),
|
|
},
|
|
Token: common.InlineSecureValue{
|
|
Create: common.NewSecretValue("test-token"),
|
|
},
|
|
},
|
|
},
|
|
wantErr: true,
|
|
errMsgContains: []string{"spec.token", "[REDACTED]"},
|
|
setupMock: func(mockFactory *github.MockGithubFactory) {
|
|
mockClient := github.NewMockClient(t)
|
|
|
|
mockFactory.EXPECT().New(mock.Anything, common.RawSecureValue("test-token")).Return(mockClient)
|
|
mockClient.EXPECT().GetApp(mock.Anything).Return(github.App{}, assert.AnError)
|
|
},
|
|
},
|
|
{
|
|
name: "mismatched app ID returns error",
|
|
connection: &provisioning.Connection{
|
|
ObjectMeta: metav1.ObjectMeta{Name: "test-connection"},
|
|
Spec: provisioning.ConnectionSpec{
|
|
Type: provisioning.GithubConnectionType,
|
|
GitHub: &provisioning.GitHubConnectionConfig{
|
|
AppID: "123",
|
|
InstallationID: "456",
|
|
},
|
|
},
|
|
Secure: provisioning.ConnectionSecure{
|
|
PrivateKey: common.InlineSecureValue{
|
|
Create: common.NewSecretValue("test-private-key"),
|
|
},
|
|
Token: common.InlineSecureValue{
|
|
Create: common.NewSecretValue("test-token"),
|
|
},
|
|
},
|
|
},
|
|
wantErr: true,
|
|
errMsgContains: []string{"spec.appID"},
|
|
setupMock: func(mockFactory *github.MockGithubFactory) {
|
|
mockClient := github.NewMockClient(t)
|
|
|
|
mockFactory.EXPECT().New(mock.Anything, common.RawSecureValue("test-token")).Return(mockClient)
|
|
mockClient.EXPECT().GetApp(mock.Anything).Return(github.App{ID: 444, Slug: "test-app"}, nil)
|
|
},
|
|
},
|
|
{
|
|
name: "problem when getting installation returns error",
|
|
connection: &provisioning.Connection{
|
|
ObjectMeta: metav1.ObjectMeta{Name: "test-connection"},
|
|
Spec: provisioning.ConnectionSpec{
|
|
Type: provisioning.GithubConnectionType,
|
|
GitHub: &provisioning.GitHubConnectionConfig{
|
|
AppID: "123",
|
|
InstallationID: "456",
|
|
},
|
|
},
|
|
Secure: provisioning.ConnectionSecure{
|
|
PrivateKey: common.InlineSecureValue{
|
|
Create: common.NewSecretValue("test-private-key"),
|
|
},
|
|
Token: common.InlineSecureValue{
|
|
Create: common.NewSecretValue("test-token"),
|
|
},
|
|
},
|
|
},
|
|
wantErr: true,
|
|
errMsgContains: []string{"spec.installationID", "456"},
|
|
setupMock: func(mockFactory *github.MockGithubFactory) {
|
|
mockClient := github.NewMockClient(t)
|
|
|
|
mockFactory.EXPECT().New(mock.Anything, common.RawSecureValue("test-token")).Return(mockClient)
|
|
mockClient.EXPECT().GetApp(mock.Anything).Return(github.App{ID: 123, Slug: "test-app"}, nil)
|
|
mockClient.EXPECT().GetAppInstallation(mock.Anything, "456").Return(github.AppInstallation{}, assert.AnError)
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
mockFactory := github.NewMockGithubFactory(t)
|
|
if tt.setupMock != nil {
|
|
tt.setupMock(mockFactory)
|
|
}
|
|
|
|
conn := github.NewConnection(tt.connection, mockFactory, github.ConnectionSecrets{
|
|
PrivateKey: tt.connection.Secure.PrivateKey.Create,
|
|
Token: tt.connection.Secure.Token.Create,
|
|
})
|
|
err := conn.Validate(context.Background())
|
|
if tt.wantErr {
|
|
assert.Error(t, err)
|
|
for _, msg := range tt.errMsgContains {
|
|
assert.Contains(t, err.Error(), msg)
|
|
}
|
|
} else {
|
|
assert.NoError(t, err)
|
|
}
|
|
})
|
|
}
|
|
}
|