go.mondoo.com/cnquery@v0.0.0-20231005093811-59568235f6ea/_motor/discovery/gcp/resolver_folder.go (about) 1 // Copyright (c) Mondoo, Inc. 2 // SPDX-License-Identifier: BUSL-1.1 3 4 package gcp 5 6 import ( 7 "context" 8 "fmt" 9 10 "github.com/cockroachdb/errors" 11 "go.mondoo.com/cnquery/motor/asset" 12 "go.mondoo.com/cnquery/motor/discovery/common" 13 "go.mondoo.com/cnquery/motor/platform/detector" 14 "go.mondoo.com/cnquery/motor/providers" 15 gcp_provider "go.mondoo.com/cnquery/motor/providers/google" 16 "go.mondoo.com/cnquery/motor/providers/resolver" 17 "go.mondoo.com/cnquery/motor/vault" 18 ) 19 20 var FolderDiscoveryTargets = append(ProjectDiscoveryTargets) 21 22 type GcpFolderResolver struct{} 23 24 func (k *GcpFolderResolver) Name() string { 25 return "GCP Folder Resolver" 26 } 27 28 func (r *GcpFolderResolver) AvailableDiscoveryTargets() []string { 29 return append(FolderDiscoveryTargets, common.DiscoveryAuto, common.DiscoveryAll, DiscoveryFolders) 30 } 31 32 func (r *GcpFolderResolver) Resolve(ctx context.Context, tc *providers.Config, credsResolver vault.Resolver, sfn common.QuerySecretFn, userIdDetectors ...providers.PlatformIdDetector) ([]*asset.Asset, error) { 33 resolved := []*asset.Asset{} 34 if tc == nil || tc.Options["folder-id"] == "" { 35 return resolved, nil 36 } 37 38 // Note: we use the resolver instead of the direct gcp_provider.New to resolve credentials properly 39 m, err := resolver.NewMotorConnection(ctx, tc, credsResolver) 40 if err != nil { 41 return nil, err 42 } 43 defer m.Close() 44 provider, ok := m.Provider.(*gcp_provider.Provider) 45 if !ok { 46 return nil, errors.New("could not create gcp provider") 47 } 48 49 identifier, err := provider.Identifier() 50 if err != nil { 51 return nil, err 52 } 53 54 // detect platform info for the asset 55 detector := detector.New(provider) 56 pf, err := detector.Platform() 57 if err != nil { 58 return nil, err 59 } 60 61 folderId := tc.Options["folder-id"] 62 md, err := NewMQLAssetsDiscovery(provider) 63 if err != nil { 64 return nil, err 65 } 66 67 folder, err := GetValue[string](md, fmt.Sprintf("return gcp.folder(id: '%s').name", folderId)) 68 if err != nil { 69 return nil, err 70 } 71 72 var resolvedRoot *asset.Asset 73 if tc.IncludesOneOfDiscoveryTarget(DiscoveryFolders) { 74 pf.Name = "gcp-folder" 75 resolvedRoot = &asset.Asset{ 76 PlatformIds: []string{identifier}, 77 Name: "GCP folder " + folder, 78 Platform: pf, 79 Connections: []*providers.Config{tc}, // pass-in the current config 80 } 81 resolved = append(resolved, resolvedRoot) 82 } 83 84 if tc.IncludesOneOfDiscoveryTarget(common.DiscoveryAuto, common.DiscoveryAll, 85 DiscoveryInstances, DiscoveryComputeImages, DiscoveryComputeNetworks, DiscoveryComputeSubnetworks, DiscoveryComputeFirewalls, 86 DiscoveryGkeClusters, 87 DiscoveryStorageBuckets, 88 DiscoveryBigQueryDatasets) { 89 type project struct { 90 Id string 91 } 92 projects, err := GetList[project](md, fmt.Sprintf("return gcp.folder(id: '%s').projects { id }", folderId)) 93 if err != nil { 94 return nil, err 95 } 96 97 for _, p := range projects { 98 projectConfig := tc.Clone() 99 projectConfig.Options = map[string]string{ 100 "project-id": p.Id, 101 } 102 103 assets, err := (&GcpProjectResolver{}).Resolve(ctx, projectConfig, credsResolver, sfn, userIdDetectors...) 104 if err != nil { 105 return nil, err 106 } 107 for i := range assets { 108 a := assets[i] 109 if resolvedRoot != nil && a.Platform.Name == "gcp-project" { 110 a.RelatedAssets = append(a.RelatedAssets, resolvedRoot) 111 } 112 resolved = append(resolved, a) 113 } 114 } 115 } 116 return resolved, nil 117 }