From d9dbd1de3280de001c88e736a187f639b9b6c2f5 Mon Sep 17 00:00:00 2001 From: Christopher Angelo Phillips <32073428+spiffcs@users.noreply.github.com> Date: Mon, 11 Dec 2023 14:22:09 -0500 Subject: [PATCH] fix: remove hard coded test (#10) * chore: alpine was the only thing we could investigate Signed-off-by: Christopher Phillips * fix: update stdin and fix rendering options Signed-off-by: Christopher Phillips --------- Signed-off-by: Christopher Phillips --- cmd/grant/cli/internal/check/report.go | 5 ++- cmd/grant/cli/option/check.go | 2 + grant/case.go | 58 ++++++++++++++++++++++---- grant/evalutation/syft.go | 3 ++ 4 files changed, 57 insertions(+), 11 deletions(-) diff --git a/cmd/grant/cli/internal/check/report.go b/cmd/grant/cli/internal/check/report.go index 2af9724..3d50fd1 100644 --- a/cmd/grant/cli/internal/check/report.go +++ b/cmd/grant/cli/internal/check/report.go @@ -63,14 +63,15 @@ func (r *Report) Render(out io.Writer) error { switch r.Format { case Table: return r.renderTable(out) + case JSON: + return errors.New("json format not yet supported") } return errors.Join(r.errors...) } func (r *Report) renderTable(out io.Writer) error { l := list.NewWriter() - l.SetStyle(list.StyleBulletStar) - + l.SetStyle(list.StyleConnectedLight) for _, result := range r.Results { l.AppendItem(result.Case.UserInput) l.Indent() diff --git a/cmd/grant/cli/option/check.go b/cmd/grant/cli/option/check.go index 3cfa0b7..7217aa8 100644 --- a/cmd/grant/cli/option/check.go +++ b/cmd/grant/cli/option/check.go @@ -8,12 +8,14 @@ type Check struct { AllowLicenses []string `json:"allow-licenses" yaml:"allow-licenses" mapstructure:"allow-licenses"` DenyLicenses []string `json:"deny-licenses" yaml:"deny-licenses" mapstructure:"deny-licenses"` IgnoreLicenses []string `json:"ignore-licenses" yaml:"ignore-licenses" mapstructure:"ignore-licenses"` + ShowPackages bool `json:"show-packages" yaml:"show-packages" mapstructure:"show-packages"` } func DefaultCheck() Check { return Check{ AllowLicenses: []string{}, DenyLicenses: []string{"*"}, + ShowPackages: true, } } diff --git a/grant/case.go b/grant/case.go index 8c7ad5b..c46e37e 100644 --- a/grant/case.go +++ b/grant/case.go @@ -1,6 +1,7 @@ package grant import ( + "bytes" "context" "fmt" "io" @@ -62,6 +63,8 @@ func NewCases(p *Policy, userInputs ...string) []Case { // - a container image (ubuntu:latest) func determineRequestCase(userRequest string) (c Case, err error) { switch { + case isStdin(userRequest): + return handleStdin(userRequest) case isFile(userRequest): return handleFile(userRequest) case isDirectory(userRequest): @@ -69,9 +72,38 @@ func determineRequestCase(userRequest string) (c Case, err error) { default: return handleContainer(userRequest) } +} + +func handleStdin(path string) (c Case, err error) { + stdReader, err := decodeStdin(os.Stdin) + if err != nil { + return c, err + } - // alright you got us here, we don't know what to do with this - return c, fmt.Errorf("unable to determine SBOM or licenses for %s", userRequest) + sb, _, _, err := format.NewDecoderCollection(format.Decoders()...).Decode(stdReader) + if sb != nil { + return Case{ + SBOMS: []sbom.SBOM{*sb}, + Licenses: make([]License, 0), + UserInput: sb.Source.Name, + }, nil + } + return c, fmt.Errorf("unable to determine SBOM or licenses for stdin") +} + +func decodeStdin(r io.Reader) (io.ReadSeeker, error) { + b, err := io.ReadAll(r) + if err != nil { + return nil, fmt.Errorf("failed reading stdin: %w", err) + } + + reader := bytes.NewReader(b) + _, err = reader.Seek(0, io.SeekStart) + if err != nil { + return nil, fmt.Errorf("failed to parse stdin: %w", err) + } + + return reader, nil } // TODO: probably need to return a multi error here @@ -87,8 +119,9 @@ func handleFile(path string) (c Case, err error) { // if there are licenses in the archive, syft should be enhanced to include them in the SBOM // this overlap is a little weird, but grant should be able to take license files as input return Case{ - SBOMS: []sbom.SBOM{sb}, - Licenses: make([]License, 0), + SBOMS: []sbom.SBOM{sb}, + Licenses: make([]License, 0), + UserInput: path, }, nil } @@ -140,8 +173,9 @@ func handleFile(path string) (c Case, err error) { licenses := grantLicenseFromClassifierResults(results) return Case{ - SBOMS: make([]sbom.SBOM, 0), - Licenses: licenses, + SBOMS: make([]sbom.SBOM, 0), + Licenses: licenses, + UserInput: path, }, nil } @@ -214,7 +248,7 @@ func grantLicenseFromClassifierResults(r results.LicenseTypes) []License { // TODO: is the default syft config good enough here? // we definitely need at least all the non default license magic turned on func generateSyftSBOM(path string) (sb sbom.SBOM, err error) { - detection, err := source.Detect("alpine:latest", source.DefaultDetectConfig()) + detection, err := source.Detect(path, source.DefaultDetectConfig()) if err != nil { return sb, err } @@ -246,7 +280,7 @@ func generateSyftSBOM(path string) (sb sbom.SBOM, err error) { func isDirectory(path string) bool { fileInfo, err := os.Stat(path) if err != nil { - log.Errorf("unable to stat directory %s: %+v", path, err) + //log.Errorf("unable to stat directory %s: %+v", path, err) return false } return fileInfo.IsDir() @@ -268,8 +302,14 @@ func isArchive(path string) bool { func isFile(path string) bool { fileInfo, err := os.Stat(path) if err != nil { - log.Errorf("unable to stat file %s: %+v", path, err) + //log.Errorf("unable to stat file %s: %+v", path, err) return false } return !fileInfo.IsDir() } + +// this is appended to the list of user requests if the user provides stdin +// and doesn't provide a "-" in the list of user requests +func isStdin(path string) bool { + return strings.EqualFold(path, "-") +} diff --git a/grant/evalutation/syft.go b/grant/evalutation/syft.go index e39d93d..28411e4 100644 --- a/grant/evalutation/syft.go +++ b/grant/evalutation/syft.go @@ -1,6 +1,8 @@ package evalutation import ( + "strings" + "github.com/github/go-spdx/v2/spdxexp" "github.com/anchore/grant/grant" @@ -60,6 +62,7 @@ func handleSPDXLicense(license syftPkg.License, licenses []grant.License, licens // process each extracted license from the SPDX expression for _, extractedLicense := range extractedLicenses { + extractedLicense = strings.TrimRight(extractedLicense, "+") // prevent duplicates from being added when using SPDX expressions // EG: "MIT AND MIT" is valid, but we want to de-duplicate these if check(checked, extractedLicense) {