Skip to content

Commit

Permalink
🧹 refactor config gathering for sbom cmd
Browse files Browse the repository at this point in the history
  • Loading branch information
chris-rock committed Mar 11, 2024
1 parent beb40f3 commit 0285507
Show file tree
Hide file tree
Showing 4 changed files with 145 additions and 226 deletions.
120 changes: 114 additions & 6 deletions apps/cnquery/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package cmd

import (
"fmt"
"os"
"regexp"
"strings"
Expand All @@ -15,9 +16,16 @@ import (
"github.com/spf13/viper"
"go.mondoo.com/cnquery/v10/cli/config"
cli_errors "go.mondoo.com/cnquery/v10/cli/errors"
"go.mondoo.com/cnquery/v10/cli/providers"
"go.mondoo.com/cnquery/v10/cli/execruntime"
"go.mondoo.com/cnquery/v10/cli/inventoryloader"
cliproviders "go.mondoo.com/cnquery/v10/cli/providers"
"go.mondoo.com/cnquery/v10/cli/reporter"
"go.mondoo.com/cnquery/v10/cli/theme"
"go.mondoo.com/cnquery/v10/logger"
"go.mondoo.com/cnquery/v10/providers"
"go.mondoo.com/cnquery/v10/providers-sdk/v1/inventory"
"go.mondoo.com/cnquery/v10/providers-sdk/v1/plugin"
"go.mondoo.com/cnquery/v10/providers-sdk/v1/upstream"
)

const (
Expand All @@ -39,24 +47,24 @@ var rootCmd = &cobra.Command{
}

func BuildRootCmd() (*cobra.Command, error) {
err := providers.AttachCLIs(
err := cliproviders.AttachCLIs(
rootCmd,
&providers.Command{
&cliproviders.Command{
Command: shellCmd,
Run: shellRun,
Action: "Interactive shell with ",
},
&providers.Command{
&cliproviders.Command{
Command: RunCmd,
Run: RunCmdRun,
Action: "Run a query with ",
},
&providers.Command{
&cliproviders.Command{
Command: scanCmd,
Run: scanCmdRun,
Action: "Scan ",
},
&providers.Command{
&cliproviders.Command{
Command: sbomCmd,
Run: sbomCmdRun,
Action: "Collect a software bill of materials (SBOM) for ",
Expand Down Expand Up @@ -196,3 +204,103 @@ func GenerateMarkdown(dir string) error {

return nil
}

func getCobraScanConfig(cmd *cobra.Command, runtime *providers.Runtime, cliRes *plugin.ParseCLIRes) (*scanConfig, error) {
opts, err := config.Read()
if err != nil {
log.Fatal().Err(err).Msg("failed to load config")
}

config.DisplayUsedConfig()

props := viper.GetStringMapString("props")
annotations := viper.GetStringMapString("annotation")

// merge the config and the user-provided annotations with the latter having precedence
optAnnotations := opts.Annotations
if optAnnotations == nil {
optAnnotations = map[string]string{}
}
for k, v := range annotations {
optAnnotations[k] = v
}

assetName := viper.GetString("asset-name")
if assetName != "" && cliRes.Asset != nil {
cliRes.Asset.Name = assetName
}

inv, err := inventoryloader.ParseOrUse(cliRes.Asset, viper.GetBool("insecure"), optAnnotations)
if err != nil {
log.Fatal().Err(err).Msg("failed to parse inventory")
}

// TODO: We currently deduplicate this here because it leads to errors down the line,
// if the same querypack is added more than once. Fix this properly downstream.
querypackPaths := dedupe(viper.GetStringSlice("querypack-bundle"))

conf := scanConfig{
Features: opts.GetFeatures(),
IsIncognito: viper.GetBool("incognito"),
Inventory: inv,
QueryPackPaths: querypackPaths,
QueryPackNames: viper.GetStringSlice("querypacks"),
Props: props,
runtime: runtime,
}

// if users want to get more information on available output options,
// print them before executing the scan
output := viper.GetString("output")
if output == "help" {
fmt.Println("Available output formats: " + reporter.AllFormats())
os.Exit(0)
}

// --json takes precedence
if ok := viper.GetBool("json"); ok {
output = "json"
}
conf.Output = output

// detect CI/CD runs and read labels from runtime and apply them to all assets in the inventory
runtimeEnv := execruntime.Detect()
if opts.AutoDetectCICDCategory && runtimeEnv.IsAutomatedEnv() || opts.Category == "cicd" {
log.Info().Msg("detected ci-cd environment")
// NOTE: we only apply those runtime environment labels for CI/CD runs to ensure other assets from the
// inventory are not touched, we may consider to add the data to the flagAsset
if runtimeEnv != nil {
runtimeLabels := runtimeEnv.Labels()
conf.Inventory.ApplyLabels(runtimeLabels)
}
conf.Inventory.ApplyCategory(inventory.AssetCategory_CATEGORY_CICD)
}

serviceAccount := opts.GetServiceCredential()
if serviceAccount != nil {
log.Info().Msg("using service account credentials")
conf.runtime.UpstreamConfig = &upstream.UpstreamConfig{
SpaceMrn: opts.GetParentMrn(),
ApiEndpoint: opts.UpstreamApiEndpoint(),
ApiProxy: opts.APIProxy,
Incognito: conf.IsIncognito,
Creds: serviceAccount,
}
providers.DefaultRuntime().UpstreamConfig = conf.runtime.UpstreamConfig
} else {
log.Warn().Msg("No credentials provided. Switching to --incognito mode.")
conf.IsIncognito = true
}

if len(conf.QueryPackPaths) > 0 && !conf.IsIncognito {
log.Warn().Msg("Scanning with local bundles will switch into --incognito mode by default. Your results will not be sent upstream.")
conf.IsIncognito = true
}

// print headline when its not printed to yaml
if output == "" {
fmt.Fprintln(os.Stdout, theme.DefaultTheme.Welcome)
}

return &conf, nil
}
94 changes: 4 additions & 90 deletions apps/cnquery/cmd/sbom.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,10 @@ import (
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"go.mondoo.com/cnquery/v10/cli/config"
"go.mondoo.com/cnquery/v10/cli/execruntime"
"go.mondoo.com/cnquery/v10/cli/inventoryloader"
"go.mondoo.com/cnquery/v10/cli/reporter"
"go.mondoo.com/cnquery/v10/logger"
"go.mondoo.com/cnquery/v10/providers"
"go.mondoo.com/cnquery/v10/providers-sdk/v1/inventory"
"go.mondoo.com/cnquery/v10/providers-sdk/v1/plugin"
"go.mondoo.com/cnquery/v10/providers-sdk/v1/upstream"
sbom "go.mondoo.com/cnquery/v10/sbom"
"go.mondoo.com/cnquery/v10/shared"
)
Expand Down Expand Up @@ -77,14 +72,15 @@ var sbomCmdRun = func(cmd *cobra.Command, runtime *providers.Runtime, cliRes *pl
log.Fatal().Err(err).Msg("failed to load query pack")
}

conf, err := getSbomScanConfig(cmd, runtime, cliRes)
conf, err := getCobraScanConfig(cmd, runtime, cliRes)
if err != nil {
log.Fatal().Err(err).Msg("failed to get scan config")
}

conf.QueryPackNames = nil
conf.QueryPackPaths = nil
conf.Bundle = pb
conf.IsIncognito = true

report, err := RunScan(conf)
if err != nil {
Expand All @@ -98,14 +94,9 @@ var sbomCmdRun = func(cmd *cobra.Command, runtime *providers.Runtime, cliRes *pl
logger.DebugDumpJSON("mondoo-sbom-report", buf.Bytes())
}

jr, err := sbom.NewReportCollectionJson(buf.Bytes())
boms, err := sbom.NewBom(buf.Bytes())
if err != nil {
log.Fatal().Err(err).Msg("failed to parse report collection")
}

boms, err := sbom.GenerateBom(jr)
if err != nil {
log.Fatal().Err(err).Msg("failed to generate SBOM")
log.Fatal().Err(err).Msg("failed to parse bom")
}

var exporter sbom.Exporter
Expand Down Expand Up @@ -145,80 +136,3 @@ var sbomCmdRun = func(cmd *cobra.Command, runtime *providers.Runtime, cliRes *pl
}
}
}

// TODO: harmonize with getCobraScanConfig
func getSbomScanConfig(cmd *cobra.Command, runtime *providers.Runtime, cliRes *plugin.ParseCLIRes) (*scanConfig, error) {
opts, err := config.Read()
if err != nil {
log.Fatal().Err(err).Msg("failed to load config")
}

config.DisplayUsedConfig()

annotations, err := cmd.Flags().GetStringToString("annotation")
if err != nil {
log.Fatal().Err(err).Msg("failed to parse annotations")
}

// merge the config and the user-provided annotations with the latter having precedence
optAnnotations := opts.Annotations
if optAnnotations == nil {
optAnnotations = map[string]string{}
}
for k, v := range annotations {
optAnnotations[k] = v
}

assetName, err := cmd.Flags().GetString("asset-name")
if err != nil {
log.Fatal().Err(err).Msg("failed to parse asset-name")
}
if assetName != "" && cliRes.Asset != nil {
cliRes.Asset.Name = assetName
}

inv, err := inventoryloader.ParseOrUse(cliRes.Asset, viper.GetBool("insecure"), optAnnotations)
if err != nil {
log.Fatal().Err(err).Msg("failed to parse inventory")
}

conf := scanConfig{
Features: opts.GetFeatures(),
IsIncognito: true,
Inventory: inv,
runtime: runtime,
}

// detect CI/CD runs and read labels from runtime and apply them to all assets in the inventory
runtimeEnv := execruntime.Detect()
if opts.AutoDetectCICDCategory && runtimeEnv.IsAutomatedEnv() || opts.Category == "cicd" {
log.Info().Msg("detected ci-cd environment")
// NOTE: we only apply those runtime environment labels for CI/CD runs to ensure other assets from the
// inventory are not touched, we may consider to add the data to the flagAsset
if runtimeEnv != nil {
runtimeLabels := runtimeEnv.Labels()
conf.Inventory.ApplyLabels(runtimeLabels)
}
conf.Inventory.ApplyCategory(inventory.AssetCategory_CATEGORY_CICD)
}

var serviceAccount *upstream.ServiceAccountCredentials
if !conf.IsIncognito {
serviceAccount = opts.GetServiceCredential()
if serviceAccount != nil {
log.Info().Msg("using service account credentials")
conf.runtime.UpstreamConfig = &upstream.UpstreamConfig{
SpaceMrn: opts.GetParentMrn(),
ApiEndpoint: opts.UpstreamApiEndpoint(),
ApiProxy: opts.APIProxy,
Incognito: conf.IsIncognito,
Creds: serviceAccount,
}
} else {
log.Warn().Msg("No credentials provided. Switching to --incognito mode.")
conf.IsIncognito = true
}
}

return &conf, nil
}
Loading

0 comments on commit 0285507

Please sign in to comment.