Make owners and repos case insensitive

Github treats owners (users and orgs) and repos as case insensitive. To
github, https://github.com/cloudbase/garm is equivalent to
https://github.com/CloudBase/GaRm. This commit makes the sql store
backend, case insensitive when querying repos and orgs.

Fixes: #25

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
This commit is contained in:
Gabriel Adrian Samfira 2022-10-05 17:12:45 +03:00
parent 8ca9a82529
commit 0ff2fd2e06
No known key found for this signature in database
GPG key ID: 7D073DCC2C074CB5
9 changed files with 30 additions and 12 deletions

View file

@ -16,4 +16,4 @@ build-static:
.PHONY: test
test:
go test -mod=vendor -tags testing -v $(TEST_ARGS) -timeout=15m -parallel=4 ./...
go test -race -mod=vendor -tags testing -v $(TEST_ARGS) -timeout=15m -parallel=4 -count=1 ./...

View file

@ -78,8 +78,8 @@ type Repository struct {
Base
CredentialsName string
Owner string `gorm:"index:idx_owner,unique"`
Name string `gorm:"index:idx_owner,unique"`
Owner string `gorm:"index:idx_owner_nocase,unique,collate:nocase"`
Name string `gorm:"index:idx_owner_nocase,unique,collate:nocase"`
WebhookSecret []byte
Pools []Pool `gorm:"foreignKey:RepoID"`
}
@ -88,7 +88,7 @@ type Organization struct {
Base
CredentialsName string
Name string `gorm:"uniqueIndex"`
Name string `gorm:"index:idx_org_name_nocase,collate:nocase"`
WebhookSecret []byte
Pools []Pool `gorm:"foreignKey:OrgID"`
}

View file

@ -374,7 +374,7 @@ func (s *sqlDatabase) getOrgByID(ctx context.Context, id string, preload ...stri
func (s *sqlDatabase) getOrg(ctx context.Context, name string) (Organization, error) {
var org Organization
q := s.conn.Where("name = ?", name)
q := s.conn.Where("name = ? COLLATE NOCASE", name)
q = q.First(&org)
if q.Error != nil {
if errors.Is(q.Error, gorm.ErrRecordNotFound) {

View file

@ -139,6 +139,13 @@ func (s *OrgTestSuite) TestGetOrganization() {
s.Require().Equal(s.Fixtures.Orgs[0].ID, org.ID)
}
func (s *OrgTestSuite) TestGetOrganizationCaseInsensitive() {
org, err := s.Store.GetOrganization(context.Background(), "TeSt-oRg-1")
s.Require().Nil(err)
s.Require().Equal("test-org-1", org.Name)
}
func (s *OrgTestSuite) TestGetOrganizationNotFound() {
_, err := s.Store.GetOrganization(context.Background(), "dummy-name")

View file

@ -282,7 +282,7 @@ func (s *sqlDatabase) UpdateRepositoryPool(ctx context.Context, repoID, poolID s
func (s *sqlDatabase) getRepo(ctx context.Context, owner, name string) (Repository, error) {
var repo Repository
q := s.conn.Where("name = ? and owner = ?", name, owner).
q := s.conn.Where("name = ? COLLATE NOCASE and owner = ? COLLATE NOCASE", name, owner).
First(&repo)
q = q.First(&repo)

View file

@ -16,6 +16,7 @@ package sql
import (
"context"
"log"
"github.com/pkg/errors"
"gorm.io/driver/mysql"
@ -79,6 +80,17 @@ type sqlDatabase struct {
}
func (s *sqlDatabase) migrateDB() error {
if s.conn.Migrator().HasIndex(&Organization{}, "idx_organizations_name") {
if err := s.conn.Migrator().DropIndex(&Organization{}, "idx_organizations_name"); err != nil {
log.Printf("failed to drop index idx_organizations_name: %s", err)
}
}
if s.conn.Migrator().HasIndex(&Repository{}, "idx_owner") {
if err := s.conn.Migrator().DropIndex(&Repository{}, "idx_owner"); err != nil {
log.Printf("failed to drop index idx_owner: %s", err)
}
}
if err := s.conn.AutoMigrate(
&Tag{},
&Pool{},

View file

@ -85,10 +85,7 @@ func (s *sqlDatabase) CreateUser(ctx context.Context, user params.NewUserParams)
func (s *sqlDatabase) HasAdminUser(ctx context.Context) bool {
var user User
q := s.conn.Model(&User{}).Where("is_admin = ?", true).First(&user)
if q.Error != nil {
return false
}
return true
return q.Error == nil
}
func (s *sqlDatabase) GetUser(ctx context.Context, user string) (params.User, error) {

View file

@ -17,6 +17,7 @@ package pool
import (
"context"
"fmt"
"strings"
"sync"
"garm/config"
@ -182,7 +183,7 @@ func (r *organization) GetPoolByID(poolID string) (params.Pool, error) {
}
func (r *organization) ValidateOwner(job params.WorkflowJob) error {
if job.Organization.Login != r.cfg.Name {
if !strings.EqualFold(job.Organization.Login, r.cfg.Name) {
return runnerErrors.NewBadRequestError("job not meant for this pool manager")
}
return nil

View file

@ -17,6 +17,7 @@ package pool
import (
"context"
"fmt"
"strings"
"sync"
"garm/config"
@ -184,7 +185,7 @@ func (r *repository) GetPoolByID(poolID string) (params.Pool, error) {
}
func (r *repository) ValidateOwner(job params.WorkflowJob) error {
if job.Repository.Name != r.cfg.Name || job.Repository.Owner.Login != r.cfg.Owner {
if !strings.EqualFold(job.Repository.Name, r.cfg.Name) || !strings.EqualFold(job.Repository.Owner.Login, r.cfg.Owner) {
return runnerErrors.NewBadRequestError("job not meant for this pool manager")
}
return nil