From 55f43c03308d17b9b6e724cf35ee6baf4e581a10 Mon Sep 17 00:00:00 2001 From: "Plushnikov, Michail" Date: Fri, 12 May 2023 12:19:11 +0200 Subject: [PATCH] feat(RELTEC-11171): switched to git-url clone instead of http --- acorns/config/customconfigint.go | 12 +- acorns/repository/sshAuthProviderInt.go | 18 ++ docs/local-config.template.yaml | 2 +- internal/repository/config/accessors.go | 16 +- internal/repository/config/config.go | 31 ++- internal/repository/config/plumbing.go | 13 +- internal/repository/config/validation_test.go | 7 +- internal/repository/metadata/acorn.go | 10 +- internal/repository/metadata/metadata.go | 74 ++--- internal/repository/sshAuthProvider/acorn.go | 54 ++++ .../sshAuthProvider/sshAuthProvider.go | 40 +++ .../sshAuthProvider/sshAuthProvider_test.go | 25 ++ internal/service/services/services_test.go | 203 +------------- internal/web/app/app.go | 2 + test/acceptance/configmock/configmock.go | 255 ++++++++++++++++++ .../sshauthprovidermock.go | 22 ++ test/resources/valid-config-unique.yaml | 3 +- test/resources/valid-config.yaml | 2 +- 18 files changed, 529 insertions(+), 260 deletions(-) create mode 100644 acorns/repository/sshAuthProviderInt.go create mode 100644 internal/repository/sshAuthProvider/acorn.go create mode 100644 internal/repository/sshAuthProvider/sshAuthProvider.go create mode 100644 internal/repository/sshAuthProvider/sshAuthProvider_test.go create mode 100644 test/acceptance/configmock/configmock.go create mode 100644 test/acceptance/sshauthprovidermock/sshauthprovidermock.go diff --git a/acorns/config/customconfigint.go b/acorns/config/customconfigint.go index b20f61b..75d5b54 100644 --- a/acorns/config/customconfigint.go +++ b/acorns/config/customconfigint.go @@ -1,8 +1,9 @@ package config import ( - librepo "github.com/StephanHCB/go-backend-service-common/acorns/repository" "regexp" + + librepo "github.com/StephanHCB/go-backend-service-common/acorns/repository" ) type CustomConfiguration interface { @@ -12,6 +13,10 @@ type CustomConfiguration interface { BitbucketUsername() string BitbucketPassword() string + SSHPrivateKey() string + SSHPrivateKeyPassword() string + SSHMetadataRepositoryUrl() string + BitbucketServer() string BitbucketCacheSize() int BitbucketCacheRetentionSeconds() uint32 @@ -30,7 +35,6 @@ type CustomConfiguration interface { AuthOidcTokenAudience() string AuthGroupWrite() string - MetadataRepoUrl() string MetadataRepoMainline() string UpdateJobIntervalCronPart() string @@ -68,6 +72,9 @@ func Custom(configuration librepo.Configuration) CustomConfiguration { const ( KeyBasicAuthUsername = "BASIC_AUTH_USERNAME" KeyBasicAuthPassword = "BASIC_AUTH_PASSWORD" + KeySSHPrivateKey = "SSH_PRIVATE_KEY" + KeySSHPrivateKeyPassword = "SSH_PRIVATE_KEY_PASSWORD" + KeySSHMetadataRepositoryUrl = "SSH_METADATA_REPO_URL" KeyBitbucketUsername = "BITBUCKET_USERNAME" KeyBitbucketPassword = "BITBUCKET_PASSWORD" KeyBitbucketServer = "BITBUCKET_SERVER" @@ -84,7 +91,6 @@ const ( KeyAuthOidcKeySetUrl = "AUTH_OIDC_KEY_SET_URL" KeyAuthOidcTokenAudience = "AUTH_OIDC_TOKEN_AUDIENCE" KeyAuthGroupWrite = "AUTH_GROUP_WRITE" - KeyMetadataRepoUrl = "METADATA_REPO_URL" KeyMetadataRepoMainline = "METADATA_REPO_MAINLINE" KeyUpdateJobIntervalMinutes = "UPDATE_JOB_INTERVAL_MINUTES" KeyUpdateJobTimeoutSeconds = "UPDATE_JOB_TIMEOUT_SECONDS" diff --git a/acorns/repository/sshAuthProviderInt.go b/acorns/repository/sshAuthProviderInt.go new file mode 100644 index 0000000..4a92032 --- /dev/null +++ b/acorns/repository/sshAuthProviderInt.go @@ -0,0 +1,18 @@ +package repository + +import ( + "context" + + "github.com/go-git/go-git/v5/plumbing/transport/ssh" +) + +const SshAuthProviderAcornName = "SshAuthProvider" + +// SshAuthProvider is an SshAuthProvider business logic component. +type SshAuthProvider interface { + IsSshAuthProvider() bool + + Setup(ctx context.Context) error + + ProvideSshAuth(ctx context.Context) (*ssh.PublicKeys, error) +} diff --git a/docs/local-config.template.yaml b/docs/local-config.template.yaml index 3fcb5d6..1b991a0 100644 --- a/docs/local-config.template.yaml +++ b/docs/local-config.template.yaml @@ -32,7 +32,7 @@ VAULT_SECRETS_CONFIG: >- AUTH_OIDC_KEY_SET_URL: https://login.microsoftonline.com//discovery/v2.0/keys AUTH_OIDC_TOKEN_AUDIENCE: -METADATA_REPO_URL: https://github.com/Interhyp/service-metadata-example +SSH_METADATA_REPO_URL: ssh://git@github.com/Interhyp/service-metadata-example.git UPDATE_JOB_INTERVAL_MINUTES: 15 UPDATE_JOB_TIMEOUT_SECONDS: 30 diff --git a/internal/repository/config/accessors.go b/internal/repository/config/accessors.go index db0d88a..bd4caf5 100644 --- a/internal/repository/config/accessors.go +++ b/internal/repository/config/accessors.go @@ -14,6 +14,18 @@ func (c *CustomConfigImpl) BasicAuthPassword() string { return c.VBasicAuthPassword } +func (c *CustomConfigImpl) SSHPrivateKey() string { + return c.VSSHPrivateKey +} + +func (c *CustomConfigImpl) SSHPrivateKeyPassword() string { + return c.VSSHPrivateKeyPassword +} + +func (c *CustomConfigImpl) SSHMetadataRepositoryUrl() string { + return c.VSSHMetadataRepoUrl +} + func (c *CustomConfigImpl) BitbucketUsername() string { return c.VBitbucketUsername } @@ -78,10 +90,6 @@ func (c *CustomConfigImpl) KafkaGroupIdOverride() string { return c.VKafkaGroupIdOverride } -func (c *CustomConfigImpl) MetadataRepoUrl() string { - return c.VMetadataRepoUrl -} - func (c *CustomConfigImpl) MetadataRepoMainline() string { return c.VMetadataRepoMainline } diff --git a/internal/repository/config/config.go b/internal/repository/config/config.go index 81d90ec..6c5f10f 100644 --- a/internal/repository/config/config.go +++ b/internal/repository/config/config.go @@ -1,10 +1,11 @@ package config import ( + "math" + "github.com/Interhyp/metadata-service/acorns/config" auconfigapi "github.com/StephanHCB/go-autumn-config-api" auconfigenv "github.com/StephanHCB/go-autumn-config-env" - "math" ) var CustomConfigItems = []auconfigapi.ConfigItem{ @@ -22,6 +23,27 @@ var CustomConfigItems = []auconfigapi.ConfigItem{ Description: "password for basic-auth write access to this service", Validate: auconfigenv.ObtainNotEmptyValidator(), }, + { + Key: config.KeySSHPrivateKey, + EnvName: config.KeySSHPrivateKey, + Description: "ssh private key used to access the vcs", + Default: "", + Validate: auconfigenv.ObtainNotEmptyValidator(), + }, + { + Key: config.KeySSHPrivateKeyPassword, + EnvName: config.KeySSHPrivateKeyPassword, + Description: "ssh private key password", + Default: "", + Validate: auconfigapi.ConfigNeedsNoValidation, + }, + { + Key: config.KeySSHMetadataRepositoryUrl, + EnvName: config.KeySSHMetadataRepositoryUrl, + Default: "", + Description: "ssh git clone url for service-metadata repository", + Validate: auconfigenv.ObtainNotEmptyValidator(), + }, { Key: config.KeyBitbucketUsername, EnvName: config.KeyBitbucketUsername, @@ -134,13 +156,6 @@ var CustomConfigItems = []auconfigapi.ConfigItem{ Description: "group name or id for write access to this service", Validate: auconfigapi.ConfigNeedsNoValidation, }, - { - Key: config.KeyMetadataRepoUrl, - EnvName: config.KeyMetadataRepoUrl, - Default: "", - Description: "git clone url for service-metadata repository", - Validate: auconfigenv.ObtainNotEmptyValidator(), - }, { Key: config.KeyMetadataRepoMainline, EnvName: config.KeyMetadataRepoMainline, diff --git a/internal/repository/config/plumbing.go b/internal/repository/config/plumbing.go index 5be673f..ccab2bb 100644 --- a/internal/repository/config/plumbing.go +++ b/internal/repository/config/plumbing.go @@ -1,19 +1,23 @@ package config import ( + "regexp" + "strconv" + "github.com/Interhyp/metadata-service/acorns/config" auacornapi "github.com/StephanHCB/go-autumn-acorn-registry/api" auconfigapi "github.com/StephanHCB/go-autumn-config-api" auconfigenv "github.com/StephanHCB/go-autumn-config-env" libconfig "github.com/StephanHCB/go-backend-service-common/repository/config" "github.com/StephanHCB/go-backend-service-common/repository/vault" - "regexp" - "strconv" ) type CustomConfigImpl struct { VBasicAuthUsername string VBasicAuthPassword string + VSSHPrivateKey string + VSSHPrivateKeyPassword string + VSSHMetadataRepoUrl string VBitbucketUsername string VBitbucketPassword string VBitbucketServer string @@ -30,7 +34,6 @@ type CustomConfigImpl struct { VAuthOidcTokenAudience string VAuthGroupWrite string VKafkaGroupIdOverride string - VMetadataRepoUrl string VMetadataRepoMainline string VUpdateJobIntervalCronPart string VUpdateJobTimeoutSeconds uint16 @@ -64,6 +67,9 @@ func New() auacornapi.Acorn { func (c *CustomConfigImpl) Obtain(getter func(key string) string) { c.VBasicAuthUsername = getter(config.KeyBasicAuthUsername) c.VBasicAuthPassword = getter(config.KeyBasicAuthPassword) + c.VSSHPrivateKey = getter(config.KeySSHPrivateKey) + c.VSSHPrivateKeyPassword = getter(config.KeySSHPrivateKeyPassword) + c.VSSHMetadataRepoUrl = getter(config.KeySSHMetadataRepositoryUrl) c.VBitbucketUsername = getter(config.KeyBitbucketUsername) c.VBitbucketPassword = getter(config.KeyBitbucketPassword) c.VBitbucketServer = getter(config.KeyBitbucketServer) @@ -80,7 +86,6 @@ func (c *CustomConfigImpl) Obtain(getter func(key string) string) { c.VAuthOidcKeySetUrl = getter(config.KeyAuthOidcKeySetUrl) c.VAuthOidcTokenAudience = getter(config.KeyAuthOidcTokenAudience) c.VAuthGroupWrite = getter(config.KeyAuthGroupWrite) - c.VMetadataRepoUrl = getter(config.KeyMetadataRepoUrl) c.VMetadataRepoMainline = getter(config.KeyMetadataRepoMainline) c.VUpdateJobIntervalCronPart = getter(config.KeyUpdateJobIntervalMinutes) c.VUpdateJobTimeoutSeconds = toUint16(getter(config.KeyUpdateJobTimeoutSeconds)) diff --git a/internal/repository/config/validation_test.go b/internal/repository/config/validation_test.go index 005bc77..04ee5e9 100644 --- a/internal/repository/config/validation_test.go +++ b/internal/repository/config/validation_test.go @@ -3,6 +3,8 @@ package config import ( "bytes" "context" + "testing" + "github.com/Interhyp/metadata-service/acorns/config" "github.com/Interhyp/metadata-service/docs" auconfigenv "github.com/StephanHCB/go-autumn-config-env" @@ -12,7 +14,6 @@ import ( "github.com/StephanHCB/go-backend-service-common/repository/logging" "github.com/rs/zerolog/log" "github.com/stretchr/testify/require" - "testing" ) const basedir = "../../../test/resources/" @@ -72,7 +73,7 @@ func TestValidate_LotsOfErrors(t *testing.T) { _, err := tstSetupCutAndLogRecorder(t, "invalid-config-values.yaml") require.NotNil(t, err) - require.Contains(t, err.Error(), "some configuration values failed to validate or parse. There were 25 error(s). See details above") + require.Contains(t, err.Error(), "some configuration values failed to validate or parse. There were 26 error(s). See details above") actualLog := goauzerolog.RecordedLogForTesting.String() @@ -127,7 +128,7 @@ func TestAccessors(t *testing.T) { require.Equal(t, "http://keyset", config.Custom(cut).AuthOidcKeySetUrl()) require.Equal(t, "some-audience", config.Custom(cut).AuthOidcTokenAudience()) require.Equal(t, "admin", config.Custom(cut).AuthGroupWrite()) - require.Equal(t, "http://metadata", config.Custom(cut).MetadataRepoUrl()) + require.Equal(t, "git://metadata", config.Custom(cut).SSHMetadataRepositoryUrl()) require.Equal(t, "5", config.Custom(cut).UpdateJobIntervalCronPart()) require.Equal(t, uint16(30), config.Custom(cut).UpdateJobTimeoutSeconds()) require.Equal(t, "https://some-domain.com/", config.Custom(cut).AlertTargetPrefix()) diff --git a/internal/repository/metadata/acorn.go b/internal/repository/metadata/acorn.go index b7e2352..981e0b9 100644 --- a/internal/repository/metadata/acorn.go +++ b/internal/repository/metadata/acorn.go @@ -2,12 +2,13 @@ package metadata import ( "context" + "time" + "github.com/Interhyp/metadata-service/acorns/config" "github.com/Interhyp/metadata-service/acorns/repository" "github.com/StephanHCB/go-autumn-acorn-registry/api" auzerolog "github.com/StephanHCB/go-autumn-logging-zerolog" librepo "github.com/StephanHCB/go-backend-service-common/acorns/repository" - "time" ) // --- implementing Acorn --- @@ -33,7 +34,7 @@ func (r *Impl) AcornName() string { func (r *Impl) AssembleAcorn(registry auacornapi.AcornRegistry) error { r.Configuration = registry.GetAcornByName(librepo.ConfigurationAcornName).(librepo.Configuration) r.Logging = registry.GetAcornByName(librepo.LoggingAcornName).(librepo.Logging) - + r.SshAuthProvider = registry.GetAcornByName(repository.SshAuthProviderAcornName).(repository.SshAuthProvider) r.CustomConfiguration = config.Custom(r.Configuration) return nil @@ -46,6 +47,9 @@ func (r *Impl) SetupAcorn(registry auacornapi.AcornRegistry) error { if err := registry.SetupAfter(r.Logging.(auacornapi.Acorn)); err != nil { return err } + if err := registry.SetupAfter(r.SshAuthProvider.(auacornapi.Acorn)); err != nil { + return err + } ctx := auzerolog.AddLoggerToCtx(context.Background()) @@ -58,7 +62,7 @@ func (r *Impl) SetupAcorn(registry auacornapi.AcornRegistry) error { return nil } -func (r *Impl) TeardownAcorn(registry auacornapi.AcornRegistry) error { +func (r *Impl) TeardownAcorn(_ auacornapi.AcornRegistry) error { ctx := auzerolog.AddLoggerToCtx(context.Background()) r.Discard(ctx) return nil diff --git a/internal/repository/metadata/metadata.go b/internal/repository/metadata/metadata.go index c07da47..f592cd8 100644 --- a/internal/repository/metadata/metadata.go +++ b/internal/repository/metadata/metadata.go @@ -4,6 +4,13 @@ import ( "bytes" "context" "fmt" + "io" + "os" + "strings" + "sync" + "time" + "unicode" + "github.com/Interhyp/metadata-service/acorns/config" "github.com/Interhyp/metadata-service/acorns/errors/nochangeserror" "github.com/Interhyp/metadata-service/acorns/repository" @@ -14,14 +21,7 @@ import ( "github.com/go-git/go-git/v5/plumbing" "github.com/go-git/go-git/v5/plumbing/object" "github.com/go-git/go-git/v5/plumbing/storer" - "github.com/go-git/go-git/v5/plumbing/transport/http" "github.com/go-git/go-git/v5/storage/memory" - "io" - "os" - "strings" - "sync" - "time" - "unicode" ) type Impl struct { @@ -29,6 +29,8 @@ type Impl struct { CustomConfiguration config.CustomConfiguration Logging librepo.Logging + SshAuthProvider repository.SshAuthProvider + GitRepo *git.Repository // CommitCacheByFilePath holds information about the newest commit that touches a file, keyed by file path @@ -50,8 +52,6 @@ type Impl struct { consoleOutput bytes.Buffer } -const insecureSkipTLS = false - func (r *Impl) pathsTouchedInCommit(ctx context.Context, commit *object.Commit) ([]string, error) { result := make([]string, 0) @@ -187,16 +187,18 @@ func (r *Impl) Clone(ctx context.Context) error { childCtxWithTimeout, cancel := context.WithTimeout(ctx, 1*time.Minute) defer cancel() + sshAuth, err := r.SshAuthProvider.ProvideSshAuth(ctx) + if err != nil { + r.Logging.Logger().Ctx(ctx).Warn().Print("providing sshAuth failed") + return err + } + repo, err := git.CloneContext(childCtxWithTimeout, memory.NewStorage(), memfs.New(), &git.CloneOptions{ - Auth: &http.BasicAuth{ - Username: r.CustomConfiguration.BitbucketUsername(), - Password: r.CustomConfiguration.BitbucketPassword(), - }, - NoCheckout: false, - Progress: r, // implements io.Writer, sends to Debug logging - URL: r.CustomConfiguration.MetadataRepoUrl(), - InsecureSkipTLS: insecureSkipTLS, - ReferenceName: plumbing.ReferenceName(r.CustomConfiguration.MetadataRepoMainline()), + Auth: sshAuth, + NoCheckout: false, + Progress: r, // implements io.Writer, sends to Debug logging + URL: r.CustomConfiguration.SSHMetadataRepositoryUrl(), + ReferenceName: plumbing.ReferenceName(r.CustomConfiguration.MetadataRepoMainline()), }) if err != nil { r.Logging.Logger().Ctx(ctx).Warn().Print("git clone failed - console output was: ", r.sanitizedConsoleOutput()) @@ -229,15 +231,17 @@ func (r *Impl) Pull(ctx context.Context) error { childCtxWithTimeout, cancel := context.WithTimeout(ctx, 30*time.Second) defer cancel() + sshAuth, err := r.SshAuthProvider.ProvideSshAuth(ctx) + if err != nil { + r.Logging.Logger().Ctx(ctx).Warn().Print("providing sshAuth failed") + return err + } + err = tree.PullContext(childCtxWithTimeout, &git.PullOptions{ - Auth: &http.BasicAuth{ - Username: r.CustomConfiguration.BitbucketUsername(), - Password: r.CustomConfiguration.BitbucketPassword(), - }, - Progress: r, // implements io.Writer, sends to Debug logging - RemoteName: "origin", - InsecureSkipTLS: insecureSkipTLS, - ReferenceName: plumbing.ReferenceName(r.CustomConfiguration.MetadataRepoMainline()), + Auth: sshAuth, + Progress: r, // implements io.Writer, sends to Debug logging + RemoteName: "origin", + ReferenceName: plumbing.ReferenceName(r.CustomConfiguration.MetadataRepoMainline()), }) if err != nil && err != git.NoErrAlreadyUpToDate { r.Logging.Logger().Ctx(ctx).Warn().Print("git pull failed - console output was: ", r.sanitizedConsoleOutput()) @@ -317,14 +321,16 @@ func (r *Impl) Push(ctx context.Context) error { childCtxWithTimeout, cancel := context.WithTimeout(ctx, 30*time.Second) defer cancel() - err := r.GitRepo.PushContext(childCtxWithTimeout, &git.PushOptions{ - Auth: &http.BasicAuth{ - Username: r.CustomConfiguration.BitbucketUsername(), - Password: r.CustomConfiguration.BitbucketPassword(), - }, - Progress: r, // implements io.Writer, sends to Debug logging - RemoteName: "origin", - InsecureSkipTLS: insecureSkipTLS, + sshAuth, err := r.SshAuthProvider.ProvideSshAuth(ctx) + if err != nil { + r.Logging.Logger().Ctx(ctx).Warn().Print("providing sshAuth failed") + return err + } + + err = r.GitRepo.PushContext(childCtxWithTimeout, &git.PushOptions{ + Auth: sshAuth, + Progress: r, // implements io.Writer, sends to Debug logging + RemoteName: "origin", }) if err != nil && err != git.NoErrAlreadyUpToDate { r.Logging.Logger().Ctx(ctx).Warn().Print("git push failed - console output was: ", r.sanitizedConsoleOutput()) diff --git a/internal/repository/sshAuthProvider/acorn.go b/internal/repository/sshAuthProvider/acorn.go new file mode 100644 index 0000000..047dde9 --- /dev/null +++ b/internal/repository/sshAuthProvider/acorn.go @@ -0,0 +1,54 @@ +package sshAuthProvider + +import ( + "context" + + "github.com/Interhyp/metadata-service/acorns/config" + "github.com/Interhyp/metadata-service/acorns/repository" + "github.com/StephanHCB/go-autumn-acorn-registry/api" + auzerolog "github.com/StephanHCB/go-autumn-logging-zerolog" + librepo "github.com/StephanHCB/go-backend-service-common/acorns/repository" +) + +// --- implementing Acorn --- + +func New() auacornapi.Acorn { + return &SshAuthProviderImpl{} +} + +func (s *SshAuthProviderImpl) IsSshAuthProvider() bool { + return true +} + +func (s SshAuthProviderImpl) AcornName() string { + return repository.SshAuthProviderAcornName +} + +func (s *SshAuthProviderImpl) AssembleAcorn(registry auacornapi.AcornRegistry) error { + s.Configuration = registry.GetAcornByName(librepo.ConfigurationAcornName).(librepo.Configuration) + s.Logging = registry.GetAcornByName(librepo.LoggingAcornName).(librepo.Logging) + + s.CustomConfiguration = config.Custom(s.Configuration) + + return nil +} + +func (s *SshAuthProviderImpl) SetupAcorn(registry auacornapi.AcornRegistry) error { + if err := registry.SetupAfter(s.Logging.(auacornapi.Acorn)); err != nil { + return err + } + + ctx := auzerolog.AddLoggerToCtx(context.Background()) + + if err := s.Setup(ctx); err != nil { + s.Logging.Logger().Ctx(ctx).Error().WithErr(err).Print("failed to set up business layer SshAuthProvider. BAILING OUT") + return err + } + + s.Logging.Logger().Ctx(ctx).Info().Print("successfully set up SshAuthProvider service") + return nil +} + +func (s *SshAuthProviderImpl) TeardownAcorn(_ auacornapi.AcornRegistry) error { + return nil +} diff --git a/internal/repository/sshAuthProvider/sshAuthProvider.go b/internal/repository/sshAuthProvider/sshAuthProvider.go new file mode 100644 index 0000000..6310c64 --- /dev/null +++ b/internal/repository/sshAuthProvider/sshAuthProvider.go @@ -0,0 +1,40 @@ +package sshAuthProvider + +import ( + "context" + + "github.com/Interhyp/metadata-service/acorns/config" + aulogging "github.com/StephanHCB/go-autumn-logging" + librepo "github.com/StephanHCB/go-backend-service-common/acorns/repository" + "github.com/go-git/go-git/v5/plumbing/transport/ssh" +) + +type SshAuthProviderImpl struct { + Configuration librepo.Configuration + Logging librepo.Logging + + CustomConfiguration config.CustomConfiguration +} + +func (s *SshAuthProviderImpl) Setup(ctx context.Context) error { + return nil +} + +// SshAuthProvider for a business method + +func (s *SshAuthProviderImpl) ProvideSshAuth(ctx context.Context) (*ssh.PublicKeys, error) { + return providePublicFromPrivateSshKey(ctx, s.CustomConfiguration.SSHPrivateKey(), s.CustomConfiguration.SSHPrivateKeyPassword()) +} + +func providePublicFromPrivateSshKey(ctx context.Context, privateKeyData string, privateKeyFilePassword string) (*ssh.PublicKeys, error) { + result, err := ssh.NewPublicKeys("git", []byte(privateKeyData), privateKeyFilePassword) + if err != nil { + warn(ctx, "generation of publickeys failed", err) + return nil, err + } + return result, nil +} + +func warn(ctx context.Context, message string, err error) { + aulogging.Logger.Ctx(ctx).Warn().WithErr(err).Printf(message+": %v", err) +} diff --git a/internal/repository/sshAuthProvider/sshAuthProvider_test.go b/internal/repository/sshAuthProvider/sshAuthProvider_test.go new file mode 100644 index 0000000..6a2c99c --- /dev/null +++ b/internal/repository/sshAuthProvider/sshAuthProvider_test.go @@ -0,0 +1,25 @@ +package sshAuthProvider + +import ( + "context" + "testing" + + "github.com/Interhyp/metadata-service/test/acceptance/configmock" + "github.com/StephanHCB/go-backend-service-common/docs" + "github.com/stretchr/testify/require" +) + +func TestProvideSshAuth(t *testing.T) { + docs.Description("SshAuthProviderImpl works") + + sshAuthProvider := SshAuthProviderImpl{ + CustomConfiguration: new(configmock.MockConfig), + } + + require.NotNil(t, sshAuthProvider) + require.Equal(t, true, sshAuthProvider.IsSshAuthProvider()) + + sshAuth, err := sshAuthProvider.ProvideSshAuth(context.Background()) + require.Nil(t, err) + require.NotNil(t, sshAuth) +} diff --git a/internal/service/services/services_test.go b/internal/service/services/services_test.go index aac6e10..b53a1b0 100644 --- a/internal/service/services/services_test.go +++ b/internal/service/services/services_test.go @@ -2,15 +2,16 @@ package services import ( "context" + "testing" + "time" + openapi "github.com/Interhyp/metadata-service/api/v1" "github.com/Interhyp/metadata-service/docs" + "github.com/Interhyp/metadata-service/test/acceptance/configmock" auloggingapi "github.com/StephanHCB/go-autumn-logging/api" "github.com/StephanHCB/go-backend-service-common/api/apierrors" "github.com/StephanHCB/go-backend-service-common/repository/timestamp" "github.com/stretchr/testify/require" - "regexp" - "testing" - "time" ) func p(v string) *string { @@ -139,200 +140,6 @@ func tstCreateValid() openapi.ServiceCreateDto { } } -type MockConfig struct { -} - -func (c *MockConfig) BasicAuthUsername() string { - //TODO implement me - panic("implement me") -} - -func (c *MockConfig) BasicAuthPassword() string { - //TODO implement me - panic("implement me") -} - -func (c *MockConfig) BitbucketUsername() string { - //TODO implement me - panic("implement me") -} - -func (c *MockConfig) BitbucketPassword() string { - //TODO implement me - panic("implement me") -} - -func (c *MockConfig) BitbucketServer() string { - //TODO implement me - panic("implement me") -} - -func (c *MockConfig) BitbucketCacheSize() int { - //TODO implement me - panic("implement me") -} - -func (c *MockConfig) BitbucketCacheRetentionSeconds() uint32 { - //TODO implement me - panic("implement me") -} - -func (c *MockConfig) BitbucketReviewerFallback() string { - //TODO implement me - panic("implement me") -} - -func (c *MockConfig) GitCommitterName() string { - //TODO implement me - panic("implement me") -} - -func (c *MockConfig) GitCommitterEmail() string { - //TODO implement me - panic("implement me") -} - -func (c *MockConfig) KafkaUsername() string { - //TODO implement me - panic("implement me") -} - -func (c *MockConfig) KafkaPassword() string { - //TODO implement me - panic("implement me") -} - -func (c *MockConfig) KafkaTopic() string { - //TODO implement me - panic("implement me") -} - -func (c *MockConfig) KafkaSeedBrokers() string { - //TODO implement me - panic("implement me") -} - -func (c *MockConfig) KafkaGroupIdOverride() string { - //TODO implement me - panic("implement me") -} - -func (c *MockConfig) AuthOidcKeySetUrl() string { - //TODO implement me - panic("implement me") -} - -func (c *MockConfig) AuthOidcTokenAudience() string { - //TODO implement me - panic("implement me") -} - -func (c *MockConfig) AuthGroupWrite() string { - //TODO implement me - panic("implement me") -} - -func (c *MockConfig) MetadataRepoUrl() string { - //TODO implement me - panic("implement me") -} - -func (c *MockConfig) UpdateJobIntervalCronPart() string { - //TODO implement me - panic("implement me") -} - -func (c *MockConfig) UpdateJobTimeoutSeconds() uint16 { - //TODO implement me - panic("implement me") -} - -func (c *MockConfig) AlertTargetPrefix() string { - return "https://some-domain.com/" -} - -func (c *MockConfig) AlertTargetSuffix() string { - return "@some-organisation.com" -} - -func (c *MockConfig) AdditionalPromotersFromOwners() []string { - return make([]string, 0) -} - -func (c *MockConfig) AdditionalPromoters() []string { - //TODO implement me - panic("implement me") -} - -func (c *MockConfig) ElasticApmEnabled() bool { - return false -} - -func (c *MockConfig) OwnerAliasPermittedRegex() *regexp.Regexp { - //TODO implement me - panic("implement me") -} - -func (c *MockConfig) OwnerAliasProhibitedRegex() *regexp.Regexp { - //TODO implement me - panic("implement me") -} - -func (c *MockConfig) OwnerAliasMaxLength() uint16 { - //TODO implement me - panic("implement me") -} - -func (c *MockConfig) OwnerFilterAliasRegex() *regexp.Regexp { - //TODO implement me - panic("implement me") -} - -func (c *MockConfig) ServiceNamePermittedRegex() *regexp.Regexp { - //TODO implement me - panic("implement me") -} - -func (c *MockConfig) ServiceNameProhibitedRegex() *regexp.Regexp { - //TODO implement me - panic("implement me") -} - -func (c *MockConfig) ServiceNameMaxLength() uint16 { - //TODO implement me - panic("implement me") -} - -func (c *MockConfig) RepositoryNamePermittedRegex() *regexp.Regexp { - //TODO implement me - panic("implement me") -} - -func (c *MockConfig) RepositoryNameProhibitedRegex() *regexp.Regexp { - //TODO implement me - panic("implement me") -} - -func (c *MockConfig) RepositoryNameMaxLength() uint16 { - //TODO implement me - panic("implement me") -} - -func (c *MockConfig) RepositoryTypes() []string { - //TODO implement me - panic("implement me") -} - -func (c *MockConfig) RepositoryKeySeparator() string { - //TODO implement me - panic("implement me") -} - -func (c *MockConfig) MetadataRepoMainline() string { - //TODO implement me - panic("implement me") -} - type MockLogging struct { } @@ -420,7 +227,7 @@ func fakeNow() time.Time { } func tstValidationTestcaseAllOps(t *testing.T, expectedMessage string, data openapi.ServiceDto, create openapi.ServiceCreateDto, patch openapi.ServicePatchDto) { - mockConfig := MockConfig{} + mockConfig := configmock.MockConfig{} mockLogging := MockLogging{} fakeNow := func() time.Time { return time.Date(2022, 11, 6, 18, 14, 10, 0, time.UTC) diff --git a/internal/web/app/app.go b/internal/web/app/app.go index 27f0962..0443d56 100644 --- a/internal/web/app/app.go +++ b/internal/web/app/app.go @@ -8,6 +8,7 @@ import ( "github.com/Interhyp/metadata-service/internal/repository/idp" "github.com/Interhyp/metadata-service/internal/repository/kafka" "github.com/Interhyp/metadata-service/internal/repository/metadata" + "github.com/Interhyp/metadata-service/internal/repository/sshAuthProvider" "github.com/Interhyp/metadata-service/internal/service/cache" "github.com/Interhyp/metadata-service/internal/service/mapper" "github.com/Interhyp/metadata-service/internal/service/owners" @@ -55,6 +56,7 @@ func (a *ApplicationImpl) Register() { auacorn.Registry.Register(hostip.New) auacorn.Registry.Register(bitbucket.New) auacorn.Registry.Register(timestamp.New) + auacorn.Registry.Register(sshAuthProvider.New) // services auacorn.Registry.Register(mapper.New) auacorn.Registry.Register(trigger.New) diff --git a/test/acceptance/configmock/configmock.go b/test/acceptance/configmock/configmock.go new file mode 100644 index 0000000..97abaaa --- /dev/null +++ b/test/acceptance/configmock/configmock.go @@ -0,0 +1,255 @@ +package configmock + +import "regexp" + +type MockConfig struct { +} + +func (c *MockConfig) BasicAuthUsername() string { + //TODO implement me + panic("implement me") +} + +func (c *MockConfig) BasicAuthPassword() string { + //TODO implement me + panic("implement me") +} + +func (c *MockConfig) SSHPrivateKey() string { + return ` +-----BEGIN OPENSSH PRIVATE KEY----- +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 +-----END OPENSSH PRIVATE KEY-----` +} + +func (c *MockConfig) SSHPrivateKeyPassword() string { + return "techexgeheim" +} + +func (c *MockConfig) SSHMetadataRepositoryUrl() string { + //TODO implement me + panic("implement me") +} + +func (c *MockConfig) BitbucketUsername() string { + //TODO implement me + panic("implement me") +} + +func (c *MockConfig) BitbucketPassword() string { + //TODO implement me + panic("implement me") +} + +func (c *MockConfig) BitbucketServer() string { + //TODO implement me + panic("implement me") +} + +func (c *MockConfig) BitbucketCacheSize() int { + //TODO implement me + panic("implement me") +} + +func (c *MockConfig) BitbucketCacheRetentionSeconds() uint32 { + //TODO implement me + panic("implement me") +} + +func (c *MockConfig) BitbucketReviewerFallback() string { + //TODO implement me + panic("implement me") +} + +func (c *MockConfig) GitCommitterName() string { + //TODO implement me + panic("implement me") +} + +func (c *MockConfig) GitCommitterEmail() string { + //TODO implement me + panic("implement me") +} + +func (c *MockConfig) KafkaUsername() string { + //TODO implement me + panic("implement me") +} + +func (c *MockConfig) KafkaPassword() string { + //TODO implement me + panic("implement me") +} + +func (c *MockConfig) KafkaTopic() string { + //TODO implement me + panic("implement me") +} + +func (c *MockConfig) KafkaSeedBrokers() string { + //TODO implement me + panic("implement me") +} + +func (c *MockConfig) KafkaGroupIdOverride() string { + //TODO implement me + panic("implement me") +} + +func (c *MockConfig) AuthOidcKeySetUrl() string { + //TODO implement me + panic("implement me") +} + +func (c *MockConfig) AuthOidcTokenAudience() string { + //TODO implement me + panic("implement me") +} + +func (c *MockConfig) AuthGroupWrite() string { + //TODO implement me + panic("implement me") +} + +func (c *MockConfig) UpdateJobIntervalCronPart() string { + //TODO implement me + panic("implement me") +} + +func (c *MockConfig) UpdateJobTimeoutSeconds() uint16 { + //TODO implement me + panic("implement me") +} + +func (c *MockConfig) AlertTargetPrefix() string { + return "https://some-domain.com/" +} + +func (c *MockConfig) AlertTargetSuffix() string { + return "@some-organisation.com" +} + +func (c *MockConfig) AdditionalPromotersFromOwners() []string { + return make([]string, 0) +} + +func (c *MockConfig) AdditionalPromoters() []string { + //TODO implement me + panic("implement me") +} + +func (c *MockConfig) ElasticApmEnabled() bool { + return false +} + +func (c *MockConfig) OwnerAliasPermittedRegex() *regexp.Regexp { + //TODO implement me + panic("implement me") +} + +func (c *MockConfig) OwnerAliasProhibitedRegex() *regexp.Regexp { + //TODO implement me + panic("implement me") +} + +func (c *MockConfig) OwnerAliasMaxLength() uint16 { + //TODO implement me + panic("implement me") +} + +func (c *MockConfig) OwnerFilterAliasRegex() *regexp.Regexp { + //TODO implement me + panic("implement me") +} + +func (c *MockConfig) ServiceNamePermittedRegex() *regexp.Regexp { + //TODO implement me + panic("implement me") +} + +func (c *MockConfig) ServiceNameProhibitedRegex() *regexp.Regexp { + //TODO implement me + panic("implement me") +} + +func (c *MockConfig) ServiceNameMaxLength() uint16 { + //TODO implement me + panic("implement me") +} + +func (c *MockConfig) RepositoryNamePermittedRegex() *regexp.Regexp { + //TODO implement me + panic("implement me") +} + +func (c *MockConfig) RepositoryNameProhibitedRegex() *regexp.Regexp { + //TODO implement me + panic("implement me") +} + +func (c *MockConfig) RepositoryNameMaxLength() uint16 { + //TODO implement me + panic("implement me") +} + +func (c *MockConfig) RepositoryTypes() []string { + //TODO implement me + panic("implement me") +} + +func (c *MockConfig) RepositoryKeySeparator() string { + //TODO implement me + panic("implement me") +} + +func (c *MockConfig) MetadataRepoMainline() string { + //TODO implement me + panic("implement me") +} diff --git a/test/acceptance/sshauthprovidermock/sshauthprovidermock.go b/test/acceptance/sshauthprovidermock/sshauthprovidermock.go new file mode 100644 index 0000000..9ffeaae --- /dev/null +++ b/test/acceptance/sshauthprovidermock/sshauthprovidermock.go @@ -0,0 +1,22 @@ +package sshauthprovidermock + +import ( + "context" + + "github.com/go-git/go-git/v5/plumbing/transport/ssh" +) + +type SshAuthProviderMock struct { +} + +func (this *SshAuthProviderMock) IsSshAuthProvider() bool { + return true +} + +func (this *SshAuthProviderMock) Setup(_ context.Context) error { + return nil +} + +func (this *SshAuthProviderMock) ProvideSshAuth(_ context.Context) (*ssh.PublicKeys, error) { + return nil, nil +} diff --git a/test/resources/valid-config-unique.yaml b/test/resources/valid-config-unique.yaml index 6977a99..e859ded 100644 --- a/test/resources/valid-config-unique.yaml +++ b/test/resources/valid-config-unique.yaml @@ -22,7 +22,8 @@ AUTH_OIDC_KEY_SET_URL: http://keyset AUTH_OIDC_TOKEN_AUDIENCE: some-audience AUTH_GROUP_WRITE: admin -METADATA_REPO_URL: http://metadata +SSH_PRIVATE_KEY: some-private-key +SSH_METADATA_REPO_URL: git://metadata UPDATE_JOB_INTERVAL_MINUTES: 5 UPDATE_JOB_TIMEOUT_SECONDS: 30 diff --git a/test/resources/valid-config.yaml b/test/resources/valid-config.yaml index 568647c..47e0db1 100644 --- a/test/resources/valid-config.yaml +++ b/test/resources/valid-config.yaml @@ -8,7 +8,7 @@ BITBUCKET_REVIEWER_FALLBACK: username AUTH_OIDC_TOKEN_AUDIENCE: some-audience AUTH_GROUP_WRITE: admin -METADATA_REPO_URL: http://metadata +SSH_METADATA_REPO_URL: git://metadata UPDATE_JOB_INTERVAL_MINUTES: 5