Skip to content

Commit

Permalink
Merge pull request #116 from Interhyp/RELTEC-10917-multi-service-repos
Browse files Browse the repository at this point in the history
Reltec 10917 multi service repos
  • Loading branch information
StephanHCB authored Mar 22, 2023
2 parents 9b61540 + 9df6296 commit e047630
Show file tree
Hide file tree
Showing 16 changed files with 411 additions and 143 deletions.
71 changes: 0 additions & 71 deletions .github/workflows/codeql-analysis.yaml

This file was deleted.

4 changes: 4 additions & 0 deletions acorns/service/repositoriesint.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package service
import (
"context"
openapi "github.com/Interhyp/metadata-service/api/v1"
"github.com/StephanHCB/go-backend-service-common/api/apierrors"
)

const RepositoriesAcornName = "repositories"
Expand All @@ -11,6 +12,9 @@ const RepositoriesAcornName = "repositories"
type Repositories interface {
IsRepositories() bool

// ValidRepositoryKey checks validity of a repository key and returns an error describing the problem if invalid
ValidRepositoryKey(ctx context.Context, repoKey string) apierrors.AnnotatedError

GetRepositories(ctx context.Context,
ownerAliasFilter string, serviceNameFilter string,
nameFilter string, typeFilter string) (openapi.RepositoryListDto, error)
Expand Down
3 changes: 3 additions & 0 deletions internal/service/repositories/acorn.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package repositories

import (
"context"
"github.com/Interhyp/metadata-service/acorns/config"
"github.com/Interhyp/metadata-service/acorns/service"
"github.com/StephanHCB/go-autumn-acorn-registry/api"
auzerolog "github.com/StephanHCB/go-autumn-logging-zerolog"
Expand Down Expand Up @@ -29,6 +30,8 @@ func (s *Impl) AssembleAcorn(registry auacornapi.AcornRegistry) error {
s.Updater = registry.GetAcornByName(service.UpdaterAcornName).(service.Updater)
s.Owners = registry.GetAcornByName(service.OwnersAcornName).(service.Owners)

s.CustomConfiguration = config.Custom(s.Configuration)

s.Timestamp = registry.GetAcornByName(librepo.TimestampAcornName).(librepo.Timestamp)

return nil
Expand Down
36 changes: 35 additions & 1 deletion internal/service/repositories/repositories.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ package repositories
import (
"context"
"fmt"
"github.com/Interhyp/metadata-service/acorns/config"
"github.com/Interhyp/metadata-service/acorns/service"
openapi "github.com/Interhyp/metadata-service/api/v1"
"github.com/Interhyp/metadata-service/internal/service/util"
librepo "github.com/StephanHCB/go-backend-service-common/acorns/repository"
"github.com/StephanHCB/go-backend-service-common/api/apierrors"
"net/url"
"strings"
)

Expand All @@ -18,7 +20,39 @@ type Impl struct {
Updater service.Updater
Owners service.Owners

Timestamp librepo.Timestamp
CustomConfiguration config.CustomConfiguration
Timestamp librepo.Timestamp
}

func (s *Impl) ValidRepositoryKey(ctx context.Context, key string) apierrors.AnnotatedError {
keyParts := strings.Split(key, s.CustomConfiguration.RepositoryKeySeparator())
if len(keyParts) == 2 && s.validRepositoryName(keyParts[0]) && s.validRepositoryType(keyParts[1]) {
return nil
}

s.Logging.Logger().Ctx(ctx).Info().Printf("repository parameter %v invalid", url.QueryEscape(key))
permitted := s.CustomConfiguration.RepositoryNamePermittedRegex().String()
prohibited := s.CustomConfiguration.RepositoryNameProhibitedRegex().String()
max := s.CustomConfiguration.RepositoryNameMaxLength()
repoTypes := s.CustomConfiguration.RepositoryTypes()
separator := s.CustomConfiguration.RepositoryKeySeparator()
details := fmt.Sprintf("repository name must match %s, is not allowed to match %s and may have up to %d characters; repository type must be one of %v and name and type must be separated by a %s character", permitted, prohibited, max, repoTypes, separator)
return apierrors.NewBadRequestError("repository.invalid", details, nil, s.Timestamp.Now())
}

func (s *Impl) validRepositoryName(name string) bool {
return s.CustomConfiguration.RepositoryNamePermittedRegex().MatchString(name) &&
!s.CustomConfiguration.RepositoryNameProhibitedRegex().MatchString(name) &&
uint16(len(name)) <= s.CustomConfiguration.RepositoryNameMaxLength()
}

func (s *Impl) validRepositoryType(repoType string) bool {
for _, validRepoType := range s.CustomConfiguration.RepositoryTypes() {
if validRepoType == repoType {
return true
}
}
return false
}

func (s *Impl) GetRepositories(ctx context.Context,
Expand Down
9 changes: 9 additions & 0 deletions internal/service/services/acorn.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ func (s *Impl) AssembleAcorn(registry auacornapi.AcornRegistry) error {
s.Cache = registry.GetAcornByName(service.CacheAcornName).(service.Cache)
s.Updater = registry.GetAcornByName(service.UpdaterAcornName).(service.Updater)
s.Owner = registry.GetAcornByName(service.OwnersAcornName).(service.Owners)
s.Repositories = registry.GetAcornByName(service.RepositoriesAcornName).(service.Repositories)

s.CustomConfiguration = config.Custom(s.Configuration)

Expand All @@ -54,6 +55,14 @@ func (s *Impl) SetupAcorn(registry auacornapi.AcornRegistry) error {
if err != nil {
return err
}
err = registry.SetupAfter(s.Owner.(auacornapi.Acorn))
if err != nil {
return err
}
err = registry.SetupAfter(s.Repositories.(auacornapi.Acorn))
if err != nil {
return err
}

ctx := auzerolog.AddLoggerToCtx(context.Background())

Expand Down
40 changes: 24 additions & 16 deletions internal/service/services/services.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package services

import (
"context"
"errors"
"fmt"
"github.com/Interhyp/metadata-service/acorns/config"
"github.com/Interhyp/metadata-service/acorns/service"
Expand All @@ -19,6 +20,7 @@ type Impl struct {
Cache service.Cache
Updater service.Updater
Owner service.Owners
Repositories service.Repositories

Timestamp librepo.Timestamp
}
Expand All @@ -29,15 +31,15 @@ func (s *Impl) GetServices(ctx context.Context, ownerAliasFilter string) (openap
TimeStamp: s.Cache.GetServiceListTimestamp(ctx),
}
for _, name := range s.Cache.GetSortedServiceNames(ctx) {
service, err := s.GetService(ctx, name)
theService, err := s.GetService(ctx, name)
if err != nil {
// service not found errors are ok, the cache may have been changed concurrently, just drop the entry
if !apierrors.IsNotFoundError(err) {
return openapi.ServiceListDto{}, err
}
} else {
if ownerAliasFilter == "" || ownerAliasFilter == service.Owner {
result.Services[name] = service
if ownerAliasFilter == "" || ownerAliasFilter == theService.Owner {
result.Services[name] = theService
}
}
}
Expand Down Expand Up @@ -115,7 +117,7 @@ func (s *Impl) validateNewServiceDto(ctx context.Context, serviceName string, dt

messages = validateOwner(messages, dto.Owner)
messages = validateDescription(messages, dto.Description)
messages = validateRepositories(messages, serviceName, dto.Repositories)
messages = s.validateRepositories(ctx, messages, serviceName, dto.Repositories)
messages = s.validateAlertTarget(messages, dto.AlertTarget)
messages = validateOperationType(messages, dto.OperationType)
messages = validateRequiredScans(messages, dto.RequiredScans)
Expand Down Expand Up @@ -186,7 +188,7 @@ func (s *Impl) validateExistingServiceDto(ctx context.Context, serviceName strin

messages = validateOwner(messages, dto.Owner)
messages = validateDescription(messages, dto.Description)
messages = validateRepositories(messages, serviceName, dto.Repositories)
messages = s.validateRepositories(ctx, messages, serviceName, dto.Repositories)
messages = s.validateAlertTarget(messages, dto.AlertTarget)
messages = validateOperationType(messages, dto.OperationType)
messages = validateRequiredScans(messages, dto.RequiredScans)
Expand Down Expand Up @@ -272,7 +274,7 @@ func (s *Impl) validateServicePatchDto(ctx context.Context, serviceName string,

messages = validateOwner(messages, dto.Owner)
messages = validateDescription(messages, dto.Description)
messages = validateRepositories(messages, serviceName, dto.Repositories)
messages = s.validateRepositories(ctx, messages, serviceName, dto.Repositories)
messages = s.validateAlertTarget(messages, dto.AlertTarget)
messages = validateOperationType(messages, dto.OperationType)
messages = validateRequiredScans(messages, dto.RequiredScans)
Expand Down Expand Up @@ -496,11 +498,11 @@ func validateOwner(messages []string, ownerAlias string) []string {
return messages
}

func validateRepositories(messages []string, serviceName string, repoKeys []string) []string {
func (s *Impl) validateRepositories(ctx context.Context, messages []string, serviceName string, repoKeys []string) []string {
if repoKeys != nil {
for _, repo := range repoKeys {
if !validRepoKey(repo, serviceName) {
messages = append(messages, "repository key must belong to service and have acceptable type")
if err := s.validRepoKey(ctx, repo, serviceName); err != nil {
messages = append(messages, err.Error())
}
}
}
Expand Down Expand Up @@ -546,15 +548,21 @@ func (s *Impl) validAlertTarget(candidate string) bool {
strings.HasSuffix(candidate, s.CustomConfiguration.AlertTargetSuffix())
}

var validRepoTypesForServices = []string{"helm-deployment", "implementation", "api"}
func (s *Impl) validRepoKey(ctx context.Context, candidate string, serviceName string) error {
if err := s.Repositories.ValidRepositoryKey(ctx, candidate); err != nil {
return err
}

func validRepoKey(candidate string, serviceName string) bool {
for _, repoType := range validRepoTypesForServices {
if candidate == serviceName+"."+repoType {
return true
}
if strings.HasSuffix(candidate, ".implementation") {
return nil
}
return false
if strings.HasSuffix(candidate, ".api") {
return nil
}
if candidate == serviceName+".helm-deployment" {
return nil
}
return errors.New("repository key must have acceptable name and type combination (allowed types: api implementation helm-deployment), and for helm-deployment the name must match the service name")
}

var validOperationTypesForService = []string{"WORKLOAD", "PLATFORM"}
Expand Down
35 changes: 1 addition & 34 deletions internal/web/controller/repositoryctl/repositoryctl.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ import (
"github.com/StephanHCB/go-backend-service-common/api/apierrors"
"github.com/go-chi/chi/v5"
"net/http"
"net/url"
"strings"
)

const ownerParam = "owner"
Expand Down Expand Up @@ -91,7 +89,7 @@ func (c *Impl) CreateRepository(w http.ResponseWriter, r *http.Request) {
}

key := util.StringPathParam(r, "repository")
if err := c.validRepositoryKey(ctx, key); err != nil {
if err := c.Repositories.ValidRepositoryKey(ctx, key); err != nil {
apierrors.HandleError(ctx, w, r, err, apierrors.IsBadRequestError)
return
}
Expand Down Expand Up @@ -204,37 +202,6 @@ func (c *Impl) DeleteRepository(w http.ResponseWriter, r *http.Request) {

// --- helpers

func (c *Impl) validRepositoryKey(ctx context.Context, key string) apierrors.AnnotatedError {
keyParts := strings.Split(key, c.CustomConfiguration.RepositoryKeySeparator())
if len(keyParts) == 2 && c.validRepositoryName(keyParts[0]) && c.validRepositoryType(keyParts[1]) {
return nil
}

c.Logging.Logger().Ctx(ctx).Info().Printf("repository parameter %v invalid", url.QueryEscape(key))
permitted := c.CustomConfiguration.RepositoryNamePermittedRegex().String()
prohibited := c.CustomConfiguration.RepositoryNameProhibitedRegex().String()
max := c.CustomConfiguration.RepositoryNameMaxLength()
repoTypes := c.CustomConfiguration.RepositoryTypes()
separator := c.CustomConfiguration.RepositoryKeySeparator()
details := fmt.Sprintf("repository name must match %s, is not allowed to match %s and may have up to %d characters; repository type must be one of %v and name and type must be separated by a %s character", permitted, prohibited, max, repoTypes, separator)
return apierrors.NewBadRequestError("repository.invalid", details, nil, c.Timestamp.Now())
}

func (c *Impl) validRepositoryName(name string) bool {
return c.CustomConfiguration.RepositoryNamePermittedRegex().MatchString(name) &&
!c.CustomConfiguration.RepositoryNameProhibitedRegex().MatchString(name) &&
uint16(len(name)) <= c.CustomConfiguration.RepositoryNameMaxLength()
}

func (c *Impl) validRepositoryType(repoType string) bool {
for _, validRepoType := range c.CustomConfiguration.RepositoryTypes() {
if validRepoType == repoType {
return true
}
}
return false
}

func (c *Impl) parseBodyToRepositoryDto(ctx context.Context, r *http.Request) (openapi.RepositoryDto, error) {
decoder := json.NewDecoder(r.Body)
dto := openapi.RepositoryDto{}
Expand Down
Loading

0 comments on commit e047630

Please sign in to comment.