mirror of
https://github.com/project-zot/zot.git
synced 2024-12-16 21:56:37 -05:00
cli: add dummy cli for CVE search commands (WIP)
It supports commands for searching CVEs with various params. run "zot search -h" and "zot search cve -h" for commands Does not make any API calls yet.
This commit is contained in:
parent
36efa17915
commit
90a943790c
6 changed files with 227 additions and 1 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -19,4 +19,5 @@ test/data/
|
||||||
.idea/
|
.idea/
|
||||||
coverage.html
|
coverage.html
|
||||||
tags
|
tags
|
||||||
vendor/
|
vendor/
|
||||||
|
.vscode/
|
||||||
|
|
|
@ -24,4 +24,5 @@ var (
|
||||||
ErrCacheRootBucket = errors.New("cache: unable to create/update root bucket")
|
ErrCacheRootBucket = errors.New("cache: unable to create/update root bucket")
|
||||||
ErrCacheNoBucket = errors.New("cache: unable to find bucket")
|
ErrCacheNoBucket = errors.New("cache: unable to find bucket")
|
||||||
ErrCacheMiss = errors.New("cache: miss")
|
ErrCacheMiss = errors.New("cache: miss")
|
||||||
|
ErrInvalidArgs = errors.New("cli: Invalid Arguments")
|
||||||
)
|
)
|
||||||
|
|
79
pkg/cli/cveCmd.go
Normal file
79
pkg/cli/cveCmd.go
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
package cli
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
zotErrors "github.com/anuvu/zot/errors"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
var searchParams = make(map[string]*string)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
searchCmd.AddCommand(cveCmd)
|
||||||
|
searchCmd.AddCommand(imageCmd)
|
||||||
|
setupFlags()
|
||||||
|
|
||||||
|
cveCmd.SetUsageTemplate(cveCmd.UsageTemplate() + allowedCombinations)
|
||||||
|
}
|
||||||
|
|
||||||
|
var cveCmd = &cobra.Command{
|
||||||
|
Use: "cve",
|
||||||
|
Short: "Find CVEs",
|
||||||
|
Long: `Find CVEs (Common Vulnerabilities and Exposures)`,
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
if cmd.Flags().NFlag() == 0 {
|
||||||
|
cmd.Usage()
|
||||||
|
panic(zotErrors.ErrInvalidArgs) //TODO to panic or not to panic
|
||||||
|
}
|
||||||
|
err := searchCve(searchParams)
|
||||||
|
if err != nil {
|
||||||
|
cmd.PrintErrln(err.Error())
|
||||||
|
cmd.PrintErrln()
|
||||||
|
cmd.Usage()
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func setupFlags() {
|
||||||
|
searchParams["imageName"] = cveCmd.Flags().StringP("image-name", "I", "", "Specify image name")
|
||||||
|
searchParams["tag"] = cveCmd.Flags().StringP("tag", "t", "", "Specify tag")
|
||||||
|
searchParams["packageName"] = cveCmd.Flags().StringP("package-name", "p", "", "Specify package name")
|
||||||
|
searchParams["packageVersion"] = cveCmd.Flags().StringP("package-version", "V", "", "Specify package version")
|
||||||
|
searchParams["packageVendor"] = cveCmd.Flags().StringP("package-vendor", "d", "", "Specify package vendor")
|
||||||
|
searchParams["cveID"] = cveCmd.Flags().StringP("cve-id", "i", "", "Find by CVE-ID")
|
||||||
|
searchParams["cveIDForImage"] = imageCmd.Flags().StringP("cve-id", "c", "", "Find by CVE-ID")
|
||||||
|
}
|
||||||
|
|
||||||
|
func searchCve(params map[string]*string) error {
|
||||||
|
foundResults := false
|
||||||
|
for _, searcher := range getSearchers() {
|
||||||
|
results, err := searcher.search(params)
|
||||||
|
if err == nil {
|
||||||
|
foundResults = true
|
||||||
|
fmt.Println(results)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !foundResults {
|
||||||
|
return errors.New("Invalid combination of arguments") // TODO error handling and printing updated help/usage
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var imageCmd = &cobra.Command{
|
||||||
|
Use: "image",
|
||||||
|
Short: "Find images",
|
||||||
|
Long: `Find images`,
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
if cmd.Flags().NFlag() == 0 {
|
||||||
|
cmd.Usage()
|
||||||
|
panic(zotErrors.ErrInvalidArgs)
|
||||||
|
}
|
||||||
|
searchCve(searchParams)
|
||||||
|
},
|
||||||
|
}
|
129
pkg/cli/cveSearchers.go
Normal file
129
pkg/cli/cveSearchers.go
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
package cli
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getSearchers() []searcher {
|
||||||
|
searchers := []searcher{
|
||||||
|
new(searchCveByID),
|
||||||
|
new(searchByImageName),
|
||||||
|
new(searchByImageNameAndTag),
|
||||||
|
new(searchByPackageNameAndVersion),
|
||||||
|
new(searchByPackageName),
|
||||||
|
new(searchByPackageVendor),
|
||||||
|
}
|
||||||
|
|
||||||
|
return searchers
|
||||||
|
}
|
||||||
|
|
||||||
|
var allowedCombinations = `
|
||||||
|
Only these combinations of flags(or their shorthands) are allowed:
|
||||||
|
--cve-id
|
||||||
|
--image-name
|
||||||
|
--image-name --tag
|
||||||
|
--package-vendor
|
||||||
|
--package-name
|
||||||
|
--package-name --package-version
|
||||||
|
--package-version
|
||||||
|
`
|
||||||
|
|
||||||
|
type searcher interface {
|
||||||
|
search(params map[string]*string) (string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func canSearch(params map[string]*string, requiredParams *set) bool {
|
||||||
|
for key, value := range params {
|
||||||
|
if requiredParams.contains(key) && *value == "" {
|
||||||
|
return false
|
||||||
|
} else if !requiredParams.contains(key) && *value != "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
type searchCveByID struct{}
|
||||||
|
|
||||||
|
func (search searchCveByID) search(params map[string]*string) (string, error) {
|
||||||
|
if !canSearch(params, newSet("cveID")) {
|
||||||
|
return "", errors.New("searchByCveId: cannot search with given params. Only CVE ID is required")
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("Searching with CVE ID: %s", *params["cveID"]), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type searchImageByCveID struct{}
|
||||||
|
|
||||||
|
func (search searchImageByCveID) search(params map[string]*string) (string, error) {
|
||||||
|
if !canSearch(params, newSet("cveIDForImage")) {
|
||||||
|
return "", errors.New("searchImageByCveID: cannot search image with given params. Only CVE ID is required")
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("Searching image with CVE ID: %s", *params["cveID"]), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type searchByImageNameAndTag struct{}
|
||||||
|
|
||||||
|
func (search searchByImageNameAndTag) search(params map[string]*string) (string, error) {
|
||||||
|
|
||||||
|
if !canSearch(params, newSet("imageName", "tag")) {
|
||||||
|
return "", errors.New("searchByImageNameAndTag: cannot search with given params. Only image name and tag are required")
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("Searching with image name and tag: %s and %s", *params["imageName"], *params["tag"]), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type searchByImageName struct{}
|
||||||
|
|
||||||
|
func (search searchByImageName) search(params map[string]*string) (string, error) {
|
||||||
|
if !canSearch(params, newSet("imageName")) {
|
||||||
|
return "", errors.New("searchByImageName: cannot search with given params. Only image name is required")
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("Searching with image name: %s", *params["imageName"]), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type searchByPackageNameAndVersion struct{}
|
||||||
|
|
||||||
|
func (search searchByPackageNameAndVersion) search(params map[string]*string) (string, error) {
|
||||||
|
if !canSearch(params, newSet("packageName", "packageVersion")) {
|
||||||
|
return "", errors.New("searchByPackageNameAndVersion: cannot search with given params. Only package name and version are required")
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("Searching with package name: %s and version %s", *params["packageName"], *params["packageVersion"]), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type searchByPackageName struct{}
|
||||||
|
|
||||||
|
func (search searchByPackageName) search(params map[string]*string) (string, error) {
|
||||||
|
if !canSearch(params, newSet("packageName")) {
|
||||||
|
return "", errors.New("searchByPackageName: cannot search with given params. Only package name is required")
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("Searching with package name: %s", *params["packageName"]), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type searchByPackageVendor struct{}
|
||||||
|
|
||||||
|
func (search searchByPackageVendor) search(params map[string]*string) (string, error) {
|
||||||
|
if !canSearch(params, newSet("packageVendor")) {
|
||||||
|
return "", errors.New("searchByPackageVendor: cannot search with given params. Only package vendor is required")
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("Searching with package vendor: %s", *params["packageVendor"]), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var exists = struct{}{}
|
||||||
|
|
||||||
|
type set struct {
|
||||||
|
m map[string]struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newSet(initialValues ...string) *set {
|
||||||
|
s := &set{}
|
||||||
|
s.m = make(map[string]struct{})
|
||||||
|
for _, val := range initialValues {
|
||||||
|
s.m[val] = exists
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *set) contains(value string) bool {
|
||||||
|
_, c := s.m[value]
|
||||||
|
return c
|
||||||
|
}
|
|
@ -96,6 +96,7 @@ func NewRootCmd() *cobra.Command {
|
||||||
|
|
||||||
rootCmd.AddCommand(serveCmd)
|
rootCmd.AddCommand(serveCmd)
|
||||||
rootCmd.AddCommand(gcCmd)
|
rootCmd.AddCommand(gcCmd)
|
||||||
|
initSearchCommand(rootCmd)
|
||||||
rootCmd.Flags().BoolVarP(&showVersion, "version", "v", false, "show the version and exit")
|
rootCmd.Flags().BoolVarP(&showVersion, "version", "v", false, "show the version and exit")
|
||||||
|
|
||||||
return rootCmd
|
return rootCmd
|
||||||
|
|
15
pkg/cli/searchCmd.go
Normal file
15
pkg/cli/searchCmd.go
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
package cli
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
func initSearchCommand(rootCmd *cobra.Command) {
|
||||||
|
rootCmd.AddCommand(searchCmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
var searchCmd = &cobra.Command{
|
||||||
|
Use: "search",
|
||||||
|
Short: "Search in zot",
|
||||||
|
Long: `Search in zot`,
|
||||||
|
}
|
Loading…
Reference in a new issue