Skip to content

Commit

Permalink
Merge input sbom to analysis result (#116)
Browse files Browse the repository at this point in the history
* merge input sbom to analysis result
  • Loading branch information
pbalogh-sa committed Apr 6, 2022
1 parent 3d8f883 commit 9ee0ebc
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 8 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,9 @@ SCANNERS_LIST="grype" BACKEND_HOST=localhost:9999 BACKEND_DISABLE_TLS=true kubec

### Merging of SBOM and vulnerabilities across different CI/CD stages
```
TBD
# Additional SBOM will be berged into the final results when '--merge-sbom' is defined during analysis. The input SBOM can be CycloneDX XML or CyclonDX json format.
# For example:
ANALYZER_LIST="syft" kubeclarity-cli analyze nginx:latest -o nginx.sbom --merge-sbom inputsbom.xml
```

## Private registries support for K8s runtime scan
Expand Down
48 changes: 46 additions & 2 deletions cli/cmd/analyze.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package cmd

import (
"fmt"
"os"

"github.com/spf13/cobra"

Expand All @@ -25,11 +26,14 @@ import (
"github.com/cisco-open/kubei/cli/pkg/utils"
sharedanalyzer "github.com/cisco-open/kubei/shared/pkg/analyzer"
"github.com/cisco-open/kubei/shared/pkg/analyzer/job"
"github.com/cisco-open/kubei/shared/pkg/converter"
"github.com/cisco-open/kubei/shared/pkg/formatter"
"github.com/cisco-open/kubei/shared/pkg/job_manager"
sharedutils "github.com/cisco-open/kubei/shared/pkg/utils"
)

const inputSBOMName = "input-sbom"

// analyzeCmd represents the analyze command.
var analyzeCmd = &cobra.Command{
Use: "analyze [SOURCE]",
Expand Down Expand Up @@ -59,6 +63,8 @@ func init() {
"ID of a defined application to associate the exported analysis")
analyzeCmd.Flags().BoolP("export", "e", false,
"export analysis results to the backend")
analyzeCmd.Flags().String("merge-sbom", "",
"SBOM file to merge to the content analysis results")
}

// nolint:cyclop
Expand Down Expand Up @@ -88,6 +94,11 @@ func analyzeContent(cmd *cobra.Command, args []string) {
logger.Fatalf("Unable to get application ID: %v", err)
}

inputSBOMFile, err := cmd.Flags().GetString("merge-sbom")
if err != nil {
logger.Fatalf("Unable to get input SBOM filepath: %v", err)
}

manager := job_manager.New(appConfig.SharedConfig.Analyzer.AnalyzerList, appConfig.SharedConfig, logger, job.CreateAnalyzerJob)
src := utils.SetSource(appConfig.LocalImageScan, sourceType, args[0])
results, err := manager.Run(sourceType, src)
Expand All @@ -100,10 +111,17 @@ func analyzeContent(cmd *cobra.Command, args []string) {
logger.Fatalf("Failed to generate hash for source %s: %v", src, err)
}

// Merge results
mergedResults := sharedanalyzer.NewMergedResults(sourceType, hash)
outputFormat := appConfig.SharedConfig.Analyzer.OutputFormat
if inputSBOMFile != "" {
cdxBOMBytes, err := convertInputSBOMIfNeeded(inputSBOMFile, outputFormat)
if err != nil {
logger.Fatalf("Failed to convert input SBOM file=%s to the results: %v", inputSBOMFile, err)
}
results[inputSBOMName] = createResultFromInputSBOM(cdxBOMBytes, inputSBOMFile)
}

// Merge results
mergedResults := sharedanalyzer.NewMergedResults(sourceType, hash)
for _, result := range results {
mergedResults = mergedResults.Merge(result.(*sharedanalyzer.Results), outputFormat)
}
Expand All @@ -126,3 +144,29 @@ func analyzeContent(cmd *cobra.Command, args []string) {
}
}
}

func createResultFromInputSBOM(sbomBytes []byte, inputSBOMFile string) *sharedanalyzer.Results {
return sharedanalyzer.CreateResults(sbomBytes, inputSBOMName, inputSBOMFile, sharedutils.SBOM)
}

func convertInputSBOMIfNeeded(inputSBOMFile, outputFormat string) ([]byte, error) {
inputSBOM, err := os.ReadFile(inputSBOMFile)
if err != nil {
return nil, fmt.Errorf("failed to read SBOM file %s: %v", inputSBOMFile, err)
}
inputSBOMFormat := converter.DetermineCycloneDXFormat(inputSBOM)
if inputSBOMFormat == outputFormat {
return inputSBOM, nil
}

// Create cycloneDX formatter to convert input SBOM to the defined output format.
cdxFormatter := formatter.New(inputSBOMFormat, inputSBOM)
if err = cdxFormatter.Decode(inputSBOMFormat); err != nil {
return nil, fmt.Errorf("failed to decode input SBOM %s: %v", inputSBOMFile, err)
}
if err := cdxFormatter.Encode(outputFormat); err != nil {
return nil, fmt.Errorf("failed to encode input SBOM: %v", err)
}

return cdxFormatter.GetSBOMBytes(), nil
}
4 changes: 3 additions & 1 deletion shared/pkg/config/analyzer.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,19 @@ type Analyzer struct {
const (
AnalyzerList = "ANALYZER_LIST"
AnalyzerScope = "ANALYZER_SCOPE"
OutputFormat = "ANALYZER_OUTPUT_FORMAT"
)

func setAnalyzerConfigDefaults() {
viper.SetDefault(AnalyzerList, []string{"syft", "gomod"})
viper.SetDefault(AnalyzerScope, "squashed")
viper.SetDefault(OutputFormat, formatter.CycloneDXFormat)
}

func LoadAnalyzerConfig() *Analyzer {
setAnalyzerConfigDefaults()
return &Analyzer{
OutputFormat: formatter.CycloneDXFormat,
OutputFormat: viper.GetString(OutputFormat),
AnalyzerList: viper.GetStringSlice(AnalyzerList),
Scope: viper.GetString(AnalyzerScope),
}
Expand Down
15 changes: 11 additions & 4 deletions shared/pkg/converter/cyclonedx_to_syft.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package converter

import (
"encoding/json"
"errors"
"fmt"
"os"
Expand Down Expand Up @@ -80,14 +81,11 @@ func saveSyftSBOMToFile(syftBOM syft_sbom.SBOM, outputSBOMFile string) error {
}

func getCycloneDXSBOMFromFile(inputSBOMFile string) (*cdx.BOM, error) {
// TODO: Peter, is that the right input format?
inputFormat := formatter.CycloneDXFormat

inputSBOM, err := os.ReadFile(inputSBOMFile)
if err != nil {
return nil, fmt.Errorf("failed to read SBOM file %s: %v", inputSBOMFile, err)
}

inputFormat := DetermineCycloneDXFormat(inputSBOM)
input := formatter.New(inputFormat, inputSBOM)
// use the formatter
if err = input.Decode(inputFormat); err != nil {
Expand All @@ -102,6 +100,15 @@ func getCycloneDXSBOMFromFile(inputSBOMFile string) (*cdx.BOM, error) {
return cdxBOM, nil
}

func DetermineCycloneDXFormat(sbom []byte) string {
var js json.RawMessage
if json.Unmarshal(sbom, &js) == nil {
return formatter.CycloneDXJSONFormat
}

return formatter.CycloneDXFormat
}

// nolint:cyclop
func convertCycloneDXtoSyft(bom *cdx.BOM) (syft_sbom.SBOM, error) {
var intype syft_source.Scheme
Expand Down

0 comments on commit 9ee0ebc

Please sign in to comment.