Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

19 configurable scoring criteria #75

Merged
merged 2 commits into from
Feb 28, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 85 additions & 0 deletions cmd/generate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*
Copyright © 2023 NAME HERE <EMAIL ADDRESS>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix Copyright for Interlynk

*/
package cmd

import (
"context"
"fmt"
"os"

"github.com/interlynk-io/sbomqs/pkg/logger"
"github.com/interlynk-io/sbomqs/pkg/scorer"
"github.com/samber/lo"
"github.com/spf13/cobra"
"gopkg.in/yaml.v3"
)

const features_file_name = "features.yaml"
const features = "features"
// generateCmd represents the generate command
var generateCmd = &cobra.Command{
Use: "generate",
Short: "provides a comprehensive config generate for your sbom to get specific criteria",
RunE: func(cmd *cobra.Command, args []string) error {
ctx := logger.WithLogger(context.Background())

if len(args) > 0 {
if args[0] == features{
return generateYaml(ctx)
}
}else{
return fmt.Errorf(fmt.Sprintf("arguments missing%s","list of valid command eg. features"))
}
return fmt.Errorf(fmt.Sprintf("invalid arguments%s","list of valid command eg. features"))

},
}

func init() {
rootCmd.AddCommand(generateCmd)
}

type Record struct {
Name string `yaml:"name" json:"name"`
Enabled bool `yaml:"enabled" json:"enabled"`
Criteria []criteria `yaml:"criteria" json:"criteria"`
}

type criteria struct {
Name string `yaml:"shortName" json:"shortName"`
Description string `yaml:"description" json:"description"`
Enabled bool `yaml:"enabled" json:"enabled"`
}

type Config struct {
Record []Record `yaml:"category" json:"category"`
}

func generateYaml(ctx context.Context) error {
cnf := Config{}
for _, category := range scorer.Categories {
record := Record{
Name: category,
Enabled: true,
}
if len(scorer.CategorieMapWithCriteria(category)) > 0 {
for _, crita := range scorer.CategorieMapWithCriteria(category) {
record.Criteria = append(record.Criteria, criteria{
Name: (string(lo.Invert(scorer.CriteriaArgMap)[crita])),
Description: crita,
Enabled: true,
})
}
}
cnf.Record = append(cnf.Record, record)

}
buf, err := yaml.Marshal(&cnf)
if err != nil {
return err
}
err = os.WriteFile(features_file_name, buf, 0755)
return err
}

89 changes: 83 additions & 6 deletions cmd/score.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/interlynk-io/sbomqs/pkg/sbom"
"github.com/interlynk-io/sbomqs/pkg/scorer"
"github.com/samber/lo"
"sigs.k8s.io/yaml"

"github.com/spf13/cobra"
)
Expand All @@ -25,7 +26,9 @@ var (
category string
feature string
reportFormat string
configPath string
)
var criterias []string

// scoreCmd represents the score command
var scoreCmd = &cobra.Command{
Expand All @@ -38,16 +41,56 @@ var scoreCmd = &cobra.Command{
return fmt.Errorf(fmt.Sprintf("Category not found %s in %s", category, strings.Join(scorer.Categories, ",")))
}

if len(reportFormat) > 0 && !lo.Contains(reporter.ReportFormats, strings.ToLower(reportFormat)) {
if len(reportFormat) > 0 && !lo.Contains(reporter.ReportFormats, reportFormat) {
return fmt.Errorf("report format options are basic or detailed")
}

if len(feature) > 0 {
features := strings.Split(feature, ",")
if len(features) > 0 {
for _, f := range features {
if lo.Contains(scorer.CriteriaArgs, f) {
criterias = append(criterias, string(scorer.CriteriaArgMap[scorer.CriteriaArg(f)]))
}
}
}
}

if len(configPath) > 0 {
err := processConfigFile(ctx, configPath)
if err != nil {
return err
}
}

var docs []sbom.Document
var scores []scorer.Scores
var paths []string

if len(reportFormat) > 0 && !lo.Contains(reporter.ReportFormats, reportFormat) {
return fmt.Errorf("report format options are basic or detailed")
}

if len(feature) > 0 {
features := strings.Split(feature, ",")
if len(features) > 0 {
for _, f := range features {
if lo.Contains(scorer.CriteriaArgs, f) {
criterias = append(criterias, string(scorer.CriteriaArgMap[scorer.CriteriaArg(f)]))
}
}
}
}

if len(configPath) > 0 {
err := processConfigFile(ctx, configPath)
if err != nil {
return err
}
}

if len(inFile) > 0 {
d, s, e := processFile(ctx, inFile)
d, s, e := processFile(ctx, inFile, criterias)
if e != nil {
return fmt.Errorf("error processing file")
}
Expand Down Expand Up @@ -76,9 +119,44 @@ func init() {
scoreCmd.MarkFlagsMutuallyExclusive("filepath", "dirpath")
scoreCmd.Flags().StringVar(&category, "category", "", "scoring category")
scoreCmd.Flags().StringVar(&reportFormat, "reportFormat", "", "reporting format basic/detailed/json")
scoreCmd.Flags().StringVar(&feature, "feature", "", "scoring features format doc-licence,comp-no-restric-licence,comp-primary-purpose,comp-no-deprecat-licence,comp-valid-licence,comp-checksums,comp-licence,doc-all-req-fileds,doc-timestamp,doc-author,doc-relationship,comp-uniq-ids,comp-version,comp-name,comp-supplier-name,spec-parsable,spec-file-format,spec-version,sbom-spec")
scoreCmd.Flags().StringVar(&configPath, "configpath", "", "scoring based on config path")
}

func processConfigFile(ctx context.Context, filePath string) error {
log := logger.FromContext(ctx)
cnf := Config{}
log.Debugf("Processing file :%s\n", filePath)
if _, err := os.Stat(filePath); err != nil {
log.Debugf("os.Stat failed for file :%s\n", filePath)
fmt.Printf("failed to stat %s\n", filePath)
return err
}
f, err := os.ReadFile(filePath)
if err != nil {
log.Debugf("os.Open failed for file :%s\n", filePath)
fmt.Printf("failed to open %s\n", filePath)
return err
}
err = yaml.Unmarshal(f, &cnf)
if err != nil {
return err
}

for _, r := range cnf.Record {
if r.Enabled {
for _, c := range r.Criteria {
if c.Enabled {
criterias = append(criterias, c.Description)
}
}
}
}

return nil
}

func processFile(ctx context.Context, filePath string) (sbom.Document, scorer.Scores, error) {
func processFile(ctx context.Context, filePath string, criterias []string) (sbom.Document, scorer.Scores, error) {
log := logger.FromContext(ctx)
log.Debugf("Processing file :%s\n", filePath)

Expand Down Expand Up @@ -107,10 +185,9 @@ func processFile(ctx context.Context, filePath string) (sbom.Document, scorer.Sc
sr := scorer.NewScorer(ctx,
doc,
scorer.WithCategory(category),
scorer.WithFeature(feature))
scorer.WithFeature(criterias))

scores := sr.Score()

return doc, scores, nil
}

Expand All @@ -133,7 +210,7 @@ func processDir(ctx context.Context, dirPath string) ([]sbom.Document, []scorer.
continue
}
path := filepath.Join(dirPath, file.Name())
doc, scs, err := processFile(ctx, path)
doc, scs, err := processFile(ctx, path, criterias)
if err != nil {
continue
}
Expand Down
73 changes: 73 additions & 0 deletions features.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
category:
- name: NTIA-minimum-elements
enabled: true
criteria:
- shortName: comp-supplier-name
description: Components have supplier names
enabled: true
- shortName: comp-name
description: Components have names
enabled: true
- shortName: comp-version
description: Components have versions
enabled: true
- shortName: comp-uniq-ids
description: Components have uniq ids
enabled: true
- shortName: doc-relationship
description: Doc has relationships
enabled: true
- shortName: doc-author
description: Doc has authors
enabled: true
- shortName: doc-timestamp
description: Doc has creation timestamp
enabled: true
- name: Quality
enabled: true
criteria:
- shortName: comp-valid-licence
description: Components have valid spdx licenses
enabled: true
- shortName: comp-primary-purpose
description: Components have primary purpose defined
enabled: true
- shortName: comp-no-deprecat-licence
description: Components have no deprecated licenses
enabled: true
- shortName: comp-no-restric-licence
description: Components have no restricted licenses
enabled: true
- name: Semantic
enabled: true
criteria:
- shortName: doc-all-req-fileds
description: Doc has all required fields
enabled: true
- shortName: comp-licence
description: Components have licenses
enabled: true
- shortName: comp-checksums
description: Components have checksums
enabled: true
- name: Sharing
enabled: true
criteria:
- shortName: doc-licence
description: Doc sharable license
enabled: true
- name: Structural
enabled: true
criteria:
- shortName: sbom-spec
description: SBOM Specification
enabled: true
- shortName: spec-version
description: Spec Version
enabled: true
- shortName: spec-file-format
description: Spec File Format
enabled: true
- shortName: spec-parsable
description: Spec is parsable
enabled: true
5 changes: 3 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ require (
github.com/spf13/cobra v1.6.1
go.uber.org/zap v1.24.0
gopkg.in/yaml.v2 v2.4.0
gopkg.in/yaml.v3 v3.0.1
sigs.k8s.io/release-utils v0.7.3
sigs.k8s.io/yaml v1.3.0
)

require (
Expand All @@ -28,7 +30,6 @@ require (
go.uber.org/multierr v1.6.0 // indirect
golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 // indirect
golang.org/x/mod v0.7.0 // indirect
golang.org/x/sys v0.4.0 // indirect
golang.org/x/sys v0.5.0 // indirect
golang.org/x/tools v0.5.0 // indirect
sigs.k8s.io/yaml v1.3.0 // indirect
)
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA=
golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.5.0 h1:GyT4nK/YDHSqa1c4753ouYCDajOYKTja9Xb/OHtgvSw=
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18=
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k=
golang.org/x/tools v0.5.0 h1:+bSpV5HIeWkuvgaMfI3UmKRThoTA5ODJTUd8T17NO+4=
golang.org/x/tools v0.5.0/go.mod h1:N+Kgy78s5I24c24dU8OfWNEotWjutIs8SnJvn5IDq+k=
Expand Down
Loading