github.com/vchain-us/vcn@v0.9.11-0.20210921212052-a2484d23c0b3/pkg/cmd/bom/bom.go (about)

     1  /*
     2   * Copyright (c) 2021 CodeNotary, Inc. All Rights Reserved.
     3   * This software is released under GPL3.
     4   * The full license information can be found under:
     5   * https://www.gnu.org/licenses/gpl-3.0.en.html
     6   *
     7   */
     8  
     9  package bom
    10  
    11  import (
    12  	"fmt"
    13  	"path/filepath"
    14  	"strings"
    15  
    16  	"github.com/spf13/cobra"
    17  	"github.com/spf13/viper"
    18  
    19  	"github.com/vchain-us/vcn/pkg/bom"
    20  	"github.com/vchain-us/vcn/pkg/bom/artifact"
    21  	"github.com/vchain-us/vcn/pkg/bom/docker"
    22  	"github.com/vchain-us/vcn/pkg/uri"
    23  )
    24  
    25  // NewCommand returns the cobra command for `vcn info`
    26  func NewCommand() *cobra.Command {
    27  	cmd := &cobra.Command{
    28  		Use:     "bom",
    29  		Example: "  vcn bom /bin/vcn",
    30  		Short:   "Collect BoM information",
    31  		Long: `
    32  Collect BoM (Bill of Material) information
    33  
    34  It identifies dependencies of build artifact and produces the BoM. Dependencies can be
    35  later authenticated by 'vcn a --bom', and notarized together with artifact by 'vcn n --bom'.
    36  `,
    37  		RunE: runBom,
    38  		PreRun: func(cmd *cobra.Command, args []string) {
    39  			// Bind to all flags to env vars (after flags were parsed),
    40  			// but only ones retrivied by using viper will be used.
    41  			viper.BindPFlags(cmd.Flags())
    42  		},
    43  		Args: func(cmd *cobra.Command, args []string) error {
    44  			return cobra.ExactValidArgs(1)(cmd, args)
    45  		},
    46  	}
    47  
    48  	cmd.Flags().Bool("bom-debug", false, "show extra debug info for BoM processing, also disable progress indicators")
    49  	cmd.Flags().String("bom-file", "", "store BoM int the file for later processing")
    50  	// BoM output options
    51  	cmd.Flags().String("bom-spdx", "", "name of the file to output BoM in SPDX format")
    52  	cmd.Flags().String("bom-cyclonedx-json", "", "name of the file to output BoM in CycloneDX JSON format")
    53  	cmd.Flags().String("bom-cyclonedx-xml", "", "name of the file to output BoM in CycloneDX XML format")
    54  	cmd.Flags().StringSlice("bom-container-binary", []string{}, "list of binaries to be executed inside the container - only the relevant dependencies will be processed")
    55  	cmd.Flags().String("github-token", "", "Github OAuth token for querying BoM Github package details. Either authenticated or not, requests are subject to Github limits")
    56  
    57  	return cmd
    58  }
    59  
    60  func runBom(cmd *cobra.Command, args []string) error {
    61  	path := args[0]
    62  	u, err := uri.Parse(path)
    63  	if err != nil {
    64  		return err
    65  	}
    66  	if _, ok := bom.BomSchemes[u.Scheme]; !ok {
    67  		return fmt.Errorf("unsupported URI %s for --bom option", path)
    68  	}
    69  	if u.Scheme != "" {
    70  		path = strings.TrimPrefix(u.Opaque, "//")
    71  	}
    72  
    73  	var bomArtifact artifact.Artifact
    74  	if u.Scheme == "docker" {
    75  		bomArtifact, err = docker.New(path, viper.GetStringSlice("bom-container-binary"))
    76  		if err != nil {
    77  			return err
    78  		}
    79  	} else {
    80  		path, err = filepath.Abs(path)
    81  		if err != nil {
    82  			return err
    83  		}
    84  		bomArtifact = bom.New(path)
    85  	}
    86  	if bomArtifact == nil {
    87  		return fmt.Errorf("unsupported artifact format/language")
    88  	}
    89  
    90  	outputOpts := artifact.Progress
    91  	if viper.GetBool("silent") {
    92  		outputOpts = artifact.Silent
    93  	} else if viper.GetBool("bom-debug") {
    94  		outputOpts = artifact.Debug
    95  	}
    96  
    97  	fmt.Printf("Resolving dependencies...\n")
    98  	_, err = bomArtifact.ResolveDependencies(outputOpts)
    99  	if err != nil {
   100  		return fmt.Errorf("cannot get dependencies: %w", err)
   101  	}
   102  
   103  	artifact.Display(bomArtifact, artifact.ColNameVersion)
   104  
   105  	// store deps in bom file for further processing
   106  	if bomFile := viper.GetString("bom-file"); bomFile != "" {
   107  		err := artifact.Store(bomArtifact, bomFile)
   108  		if err != nil {
   109  			return err
   110  		}
   111  	}
   112  
   113  	return bom.Output(bomArtifact) // process all possible BoM output options
   114  }