From 4cd2cbdb7d07aa34b8f12594c5b0f1c8b0dd22c5 Mon Sep 17 00:00:00 2001 From: Christoph Hartmann Date: Sat, 16 Sep 2023 21:49:36 -0700 Subject: [PATCH] =?UTF-8?q?=E2=AD=90=EF=B8=8F=20gitlab=20project=20discove?= =?UTF-8?q?ry?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- motor/discovery/gitlab/gitlab.go | 100 ++++++++++++++++++------ motor/platform/detector/detector.go | 10 +-- motor/providers/gitlab/platform.go | 59 +++++++++++++- motor/providers/gitlab/provider.go | 14 ++-- motor/providers/gitlab/provider_test.go | 24 +++++- 5 files changed, 164 insertions(+), 43 deletions(-) diff --git a/motor/discovery/gitlab/gitlab.go b/motor/discovery/gitlab/gitlab.go index d58c019b9c..f599c2b689 100644 --- a/motor/discovery/gitlab/gitlab.go +++ b/motor/discovery/gitlab/gitlab.go @@ -4,15 +4,19 @@ import ( "context" "errors" + "github.com/xanzy/go-gitlab" "go.mondoo.com/cnquery/motor/asset" "go.mondoo.com/cnquery/motor/discovery/common" "go.mondoo.com/cnquery/motor/providers" - gitlab_transport "go.mondoo.com/cnquery/motor/providers/gitlab" + gitlab_provider "go.mondoo.com/cnquery/motor/providers/gitlab" "go.mondoo.com/cnquery/motor/providers/resolver" "go.mondoo.com/cnquery/motor/vault" ) -const DiscoveryGroup = "group" +const ( + DiscoveryGroup = "group" + DiscoveryProject = "project" +) type Resolver struct{} @@ -21,23 +25,23 @@ func (r *Resolver) Name() string { } func (r *Resolver) AvailableDiscoveryTargets() []string { - return []string{common.DiscoveryAuto, common.DiscoveryAll, DiscoveryGroup} + return []string{common.DiscoveryAuto, common.DiscoveryAll, DiscoveryGroup, DiscoveryProject} } -func (r *Resolver) Resolve(ctx context.Context, root *asset.Asset, tc *providers.Config, credsResolver vault.Resolver, sfn common.QuerySecretFn, userIdDetectors ...providers.PlatformIdDetector) ([]*asset.Asset, error) { +func (r *Resolver) Resolve(ctx context.Context, root *asset.Asset, pCfg *providers.Config, credsResolver vault.Resolver, sfn common.QuerySecretFn, userIdDetectors ...providers.PlatformIdDetector) ([]*asset.Asset, error) { // establish connection to GitLab - m, err := resolver.NewMotorConnection(ctx, tc, credsResolver) + m, err := resolver.NewMotorConnection(ctx, pCfg, credsResolver) if err != nil { return nil, err } defer m.Close() - trans, ok := m.Provider.(*gitlab_transport.Provider) + p, ok := m.Provider.(*gitlab_provider.Provider) if !ok { return nil, errors.New("could not initialize gitlab transport") } - identifier, err := trans.Identifier() + identifier, err := p.Identifier() if err != nil { return nil, err } @@ -47,27 +51,71 @@ func (r *Resolver) Resolve(ctx context.Context, root *asset.Asset, tc *providers return nil, err } - var assets []*asset.Asset - if tc.IncludesOneOfDiscoveryTarget(common.DiscoveryAuto, common.DiscoveryAll, DiscoveryGroup) { - name := root.Name - if name == "" { - grp, err := trans.Group() - if err != nil { - return nil, err - } - if grp != nil { - name = "GitLab Group " + grp.Name + defaultName := root.Name + list := []*asset.Asset{} + + switch pf.Name { + case "gitlab-project": + if pCfg.IncludesOneOfDiscoveryTarget(common.DiscoveryAuto, common.DiscoveryAll, DiscoveryProject) { + name := defaultName + if name == "" { + project, _ := p.Project() + if project != nil { + name = project.NameWithNamespace + } } + + list = append(list, &asset.Asset{ + PlatformIds: []string{identifier}, + Name: name, + Platform: pf, + Connections: []*providers.Config{pCfg}, // pass-in the current config + State: asset.State_STATE_ONLINE, + }) } + case "gitlab-group": + var grp *gitlab.Group + if pCfg.IncludesOneOfDiscoveryTarget(common.DiscoveryAuto, common.DiscoveryAll, DiscoveryGroup) { + name := root.Name + if name == "" { + grp, err = p.Group() + if err != nil { + return nil, err + } + if grp != nil { + name = "GitLab Group " + grp.Name + } + } - assets = append(assets, &asset.Asset{ - PlatformIds: []string{identifier}, - Name: name, - Platform: pf, - Connections: []*providers.Config{tc}, // pass-in the current config - State: asset.State_STATE_ONLINE, - }) - } + list = append(list, &asset.Asset{ + PlatformIds: []string{identifier}, + Name: name, + Platform: pf, + Connections: []*providers.Config{pCfg}, // pass-in the current config + State: asset.State_STATE_ONLINE, + }) - return assets, nil + if pCfg.IncludesOneOfDiscoveryTarget(common.DiscoveryAuto, common.DiscoveryAll, DiscoveryProject) { + p.Client().Projects.ListProjects(&gitlab.ListProjectsOptions{}) + + for _, project := range grp.Projects { + clonedConfig := pCfg.Clone() + if clonedConfig.Options == nil { + clonedConfig.Options = map[string]string{} + } + clonedConfig.Options["group"] = grp.Name + clonedConfig.Options["project"] = project.Name + + list = append(list, &asset.Asset{ + PlatformIds: []string{identifier}, + Name: project.NameWithNamespace, + Platform: gitlab_provider.GitLabProjectPlatform, + Connections: []*providers.Config{clonedConfig}, // pass-in the current config + State: asset.State_STATE_ONLINE, + }) + } + } + } + } + return list, nil } diff --git a/motor/platform/detector/detector.go b/motor/platform/detector/detector.go index 15319b0279..1efbdf9891 100644 --- a/motor/platform/detector/detector.go +++ b/motor/platform/detector/detector.go @@ -2,9 +2,10 @@ package detector import ( "errors" - "go.mondoo.com/cnquery/motor/providers/opcua" "runtime" + "go.mondoo.com/cnquery/motor/providers/opcua" + "go.mondoo.com/cnquery/motor/platform" "go.mondoo.com/cnquery/motor/providers" "go.mondoo.com/cnquery/motor/providers/arista" @@ -104,12 +105,7 @@ func (d *Detector) Platform() (*platform.Platform, error) { case *github.Provider: return pt.PlatformInfo() case *gitlab.Provider: - return &platform.Platform{ - Name: "gitlab", - Title: "GitLab", - Kind: providers.Kind_KIND_API, - Runtime: providers.RUNTIME_GITLAB, - }, nil + return pt.PlatformInfo() case *terraform.Provider: return pt.PlatformInfo(), nil case *network.Provider: diff --git a/motor/providers/gitlab/platform.go b/motor/providers/gitlab/platform.go index f6e716f90d..1fc95b04ae 100644 --- a/motor/providers/gitlab/platform.go +++ b/motor/providers/gitlab/platform.go @@ -1,18 +1,55 @@ package gitlab import ( + "errors" + "net/url" "strconv" "github.com/xanzy/go-gitlab" + "go.mondoo.com/cnquery/motor/platform" + "go.mondoo.com/cnquery/motor/providers" ) +var ( + GitLabProjectPlatform = &platform.Platform{ + Name: "gitlab-project", + Title: "GitLab Project", + Family: []string{"gitlab"}, + Kind: providers.Kind_KIND_API, + Runtime: providers.RUNTIME_GITHUB, + } + GitLabGroupPlatform = &platform.Platform{ + Name: "gitlab-group", + Title: "GitLab Group", + Family: []string{"gitlab"}, + Kind: providers.Kind_KIND_API, + Runtime: providers.RUNTIME_GITHUB, + } +) + +func NewGitLabGroupIdentifier(groupID string) string { + return "//platformid.api.mondoo.app/runtime/gitlab/group/" + groupID +} + +func NewGitLabProjectIdentifier(groupID string, projectID string) string { + return "//platformid.api.mondoo.app/runtime/gitlab/group/" + groupID + "/project/" + projectID +} + func (t *Provider) Identifier() (string, error) { grp, err := t.Group() if err != nil { return "", err } - return "//platformid.api.mondoo.app/runtime/gitlab/group/" + strconv.Itoa(grp.ID), nil + if t.ProjectPath != "" { + project, err := t.Project() + if err != nil { + return "", err + } + return NewGitLabProjectIdentifier(strconv.Itoa(grp.ID), strconv.Itoa(project.ID)), nil + } else { + return NewGitLabGroupIdentifier(strconv.Itoa(grp.ID)), nil + } } func (t *Provider) Group() (*gitlab.Group, error) { @@ -22,3 +59,23 @@ func (t *Provider) Group() (*gitlab.Group, error) { } return grp, err } + +func (t *Provider) Project() (*gitlab.Project, error) { + project, _, err := t.Client().Projects.GetProject(url.QueryEscape(t.GroupPath)+"/"+url.QueryEscape(t.ProjectPath), nil) + if err != nil { + return nil, err + } + return project, err +} + +func (p *Provider) PlatformInfo() (*platform.Platform, error) { + if projectName := p.opts["project"]; projectName != "" { + return GitLabProjectPlatform, nil + } + + if groupName := p.opts["group"]; groupName != "" { + return GitLabGroupPlatform, nil + } + + return nil, errors.New("could not detect GitLab asset type") +} diff --git a/motor/providers/gitlab/provider.go b/motor/providers/gitlab/provider.go index 88d40aac1d..45b66bc6b0 100644 --- a/motor/providers/gitlab/provider.go +++ b/motor/providers/gitlab/provider.go @@ -50,16 +50,18 @@ func New(tc *providers.Config) (*Provider, error) { } return &Provider{ - client: client, - opts: tc.Options, - GroupPath: tc.Options["group"], + client: client, + opts: tc.Options, + GroupPath: tc.Options["group"], + ProjectPath: tc.Options["project"], }, nil } type Provider struct { - client *gitlab.Client - opts map[string]string - GroupPath string + client *gitlab.Client + opts map[string]string + GroupPath string + ProjectPath string } func (p *Provider) Close() {} diff --git a/motor/providers/gitlab/provider_test.go b/motor/providers/gitlab/provider_test.go index 83cade0561..0178980f6f 100644 --- a/motor/providers/gitlab/provider_test.go +++ b/motor/providers/gitlab/provider_test.go @@ -4,6 +4,7 @@ package gitlab import ( + "os" "strings" "testing" @@ -12,11 +13,28 @@ import ( "go.mondoo.com/cnquery/motor/providers" ) -func TestGitlab(t *testing.T) { +func TestGitlabGroup(t *testing.T) { + token := os.Getenv("GITLAB_TOKEN") p, err := New(&providers.Config{ Options: map[string]string{ - "token": "", - "group": "mondoolabs", + "token": token, + "group": "my-group", + }, + }) + require.NoError(t, err) + + id, err := p.Identifier() + require.NoError(t, err) + assert.True(t, strings.HasPrefix(id, "//platformid.api.mondoo.app/runtime/gitlab/group/")) +} + +func TestGitlabProject(t *testing.T) { + token := os.Getenv("GITLAB_TOKEN") + p, err := New(&providers.Config{ + Options: map[string]string{ + "token": token, + "group": "my-group", + "project": "my-repo", }, }) require.NoError(t, err)