From 333953cd8802ac30d34fcec28d701a83b887e423 Mon Sep 17 00:00:00 2001 From: Christopher Angelo Phillips <32073428+spiffcs@users.noreply.github.com> Date: Thu, 21 Mar 2024 04:01:27 -0400 Subject: [PATCH 1/2] feat: add CSV output option (#65) * feat: add CSV output option Signed-off-by: Christopher Phillips * chore: lint fix Signed-off-by: Christopher Phillips --------- Signed-off-by: Christopher Phillips --- cmd/grant/cli/internal/format.go | 7 ++++- cmd/grant/cli/internal/list/report.go | 43 +++++++++++++++++++++++++-- grant/package.go | 2 ++ 3 files changed, 49 insertions(+), 3 deletions(-) diff --git a/cmd/grant/cli/internal/format.go b/cmd/grant/cli/internal/format.go index 6ab86c7..801afae 100644 --- a/cmd/grant/cli/internal/format.go +++ b/cmd/grant/cli/internal/format.go @@ -11,9 +11,10 @@ type Format string const ( JSON Format = "json" Table Format = "table" + CSV Format = "csv" ) -var ValidFormats = []Format{JSON, Table} +var ValidFormats = []Format{JSON, Table, CSV} // ValidateFormat returns a valid format or the default format if the given format is invalid func ValidateFormat(f Format) Format { @@ -22,6 +23,8 @@ func ValidateFormat(f Format) Format { return JSON case "table": return Table + case "csv": + return CSV default: return Table } @@ -58,6 +61,7 @@ func NewLicense(l grant.License) License { type Package struct { Name string `json:"name" yaml:"name"` Version string `json:"version" yaml:"version"` + Type string `json:"type" yaml:"type"` Locations []string `json:"locations" yaml:"locations"` } @@ -69,6 +73,7 @@ func NewPackage(p *grant.Package) Package { Name: p.Name, Version: p.Version, Locations: p.Locations, + Type: p.Type, } } diff --git a/cmd/grant/cli/internal/list/report.go b/cmd/grant/cli/internal/list/report.go index e851d76..9f544f8 100644 --- a/cmd/grant/cli/internal/list/report.go +++ b/cmd/grant/cli/internal/list/report.go @@ -1,9 +1,11 @@ package list import ( + "encoding/csv" "encoding/json" "errors" "fmt" + "os" "slices" "time" @@ -55,6 +57,8 @@ func (r *Report) Render() error { return r.renderList() case internal.JSON: return r.renderJSON() + case internal.CSV: + return r.renderCSV() default: r.errors = append(r.errors, fmt.Errorf("invalid format: %s; valid formats are: %s", r.Config.Options.Format, internal.ValidFormats)) return errors.Join(r.errors...) @@ -84,7 +88,38 @@ func NewResult(input string, gl grant.License, gp ...*grant.Package) Result { } } -func (r *Report) renderJSON() error { +func (r *Report) renderCSV() error { + response := getResponse(r) + headers := []string{"component", "component_version", "license", "website", "type"} + data := [][]string{ + headers, + } + + for _, rslt := range response.Results { + for _, pkg := range rslt.Packages { + data = append(data, []string{ + pkg.Name, + pkg.Version, + rslt.License.Name, + rslt.License.Reference, + pkg.Type, + }) + } + } + + writer := csv.NewWriter(os.Stdout) + defer writer.Flush() + + for _, record := range data { + if err := writer.Write(record); err != nil { + return err + } + } + + return writer.Error() +} + +func getResponse(r *Report) Response { resp := Response{ ReportID: r.ReportID, Timestamp: r.Timestamp, @@ -94,7 +129,6 @@ func (r *Report) renderJSON() error { for _, c := range r.Cases { resp.Inputs = append(resp.Inputs, c.UserInput) - // TODO: is it better to invert this here and grab packages -> licenses since package is the cases first class licensePackages, licenses, _ := c.GetLicenses() for key, l := range licenses { packages := licensePackages[key] @@ -102,6 +136,11 @@ func (r *Report) renderJSON() error { resp.Results = append(resp.Results, result) } } + return resp +} + +func (r *Report) renderJSON() error { + resp := getResponse(r) jsonData, err := json.Marshal(resp) if err != nil { return err diff --git a/grant/package.go b/grant/package.go index e2378b5..49cbb43 100644 --- a/grant/package.go +++ b/grant/package.go @@ -10,6 +10,7 @@ type PackageID string type Package struct { ID PackageID `json:"id" yaml:"id"` Name string `json:"name" yaml:"name"` + Type string `json:"type" yaml:"type"` Version string `json:"version" yaml:"version"` Licenses []License `json:"licenses" yaml:"licenses"` Locations []string `json:"locations" yaml:"locations"` @@ -25,6 +26,7 @@ func ConvertSyftPackage(p syftPkg.Package) *Package { return &Package{ Name: p.Name, Version: p.Version, + Type: string(p.Type), Licenses: ConvertSyftLicenses(p.Licenses), Locations: packageLocations, } From f43e6cb218fffeb85314ceb311a735239fecf9a1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 21 Mar 2024 04:09:04 -0400 Subject: [PATCH 2/2] chore(deps): bump google.golang.org/protobuf from 1.31.0 to 1.33.0 (#67) Bumps google.golang.org/protobuf from 1.31.0 to 1.33.0. --- updated-dependencies: - dependency-name: google.golang.org/protobuf dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Christopher Angelo Phillips <32073428+spiffcs@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 40579fc..145a9e2 100644 --- a/go.mod +++ b/go.mod @@ -207,7 +207,7 @@ require ( google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f // indirect google.golang.org/grpc v1.59.0 // indirect - google.golang.org/protobuf v1.31.0 // indirect + google.golang.org/protobuf v1.33.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index 41b05e8..6c1c21b 100644 --- a/go.sum +++ b/go.sum @@ -1297,8 +1297,8 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= -google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=