diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/cbomkit-theia.iml b/.idea/cbomkit-theia.iml new file mode 100644 index 0000000..5e764c4 --- /dev/null +++ b/.idea/cbomkit-theia.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..e510316 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/cbomkit-theia_test.go b/cbomkit-theia_test.go index 9468199..bcb8f24 100644 --- a/cbomkit-theia_test.go +++ b/cbomkit-theia_test.go @@ -153,8 +153,8 @@ func TestScan(t *testing.T) { return a.Name < b.Name }), cmpopts.SortSlices(func(a cdx.Component, b cdx.Component) bool { - aHash := hash.HashCDXComponentWithoutRefs(a) - bHash := hash.HashCDXComponentWithoutRefs(b) + aHash := hash.CdxComponentWithoutRefs(a) + bHash := hash.CdxComponentWithoutRefs(b) return hex.EncodeToString(aHash[:]) < hex.EncodeToString(bHash[:]) }), cmpopts.SortSlices(func(a cdx.EvidenceOccurrence, b cdx.EvidenceOccurrence) bool { diff --git a/provider/cyclonedx/bom.go b/provider/cyclonedx/bom.go index ddaf2b3..22bdb98 100644 --- a/provider/cyclonedx/bom.go +++ b/provider/cyclonedx/bom.go @@ -28,7 +28,7 @@ import ( "github.com/xeipuuv/gojsonschema" ) -// Write bom to the file +// WriteBOM Write bom to the file func WriteBOM(bom *cdx.BOM, writer io.Writer) error { // Encode the BOM err := cdx.NewBOMEncoder(writer, cdx.BOMFileFormatJSON). @@ -40,7 +40,7 @@ func WriteBOM(bom *cdx.BOM, writer io.Writer) error { return nil } -// Parse and validate a CycloneDX BOM from path using the schema under schemaPath +// ParseBOM Parse and validate a CycloneDX BOM from path using the schema under schemaPath func ParseBOM(bomReader io.Reader, schemaReader io.Reader) (*cdx.BOM, error) { bomBytes, err := io.ReadAll(bomReader) if err != nil { @@ -62,7 +62,10 @@ func ParseBOM(bomReader io.Reader, schemaReader io.Reader) (*cdx.BOM, error) { } else { slog.Error("The BOM is not valid. see errors:") for _, desc := range result.Errors() { - fmt.Fprintf(os.Stderr, "- %s\n", desc) + _, err = fmt.Fprintf(os.Stderr, "- %s\n", desc) + if err != nil { + slog.Error(err.Error()) + } } return new(cdx.BOM), fmt.Errorf("provider: bom is not valid due to schema") } diff --git a/provider/docker/image.go b/provider/docker/image.go index 23614fd..09ad901 100644 --- a/provider/docker/image.go +++ b/provider/docker/image.go @@ -47,7 +47,7 @@ type ActiveImage struct { client *client.Client } -// Defer to this function to destroy the ActiveImage after use +// TearDown Defer to this function to destroy the ActiveImage after use func (image ActiveImage) TearDown() { slog.Info("Removing Image", "id", image.id) @@ -65,12 +65,12 @@ func (image ActiveImage) TearDown() { } } -// Get the image config of this image +// GetConfig Get the image config of this image func (image ActiveImage) GetConfig() (config v1.Config, ok bool) { return image.Metadata.Config.Config, true } -// Build new image from a dockerfile; +// BuildNewImage Build new image from a dockerfile; // Caller is responsible to call image.TearDown() after usage func BuildNewImage(dockerfilePath string) (image ActiveImage, err error) { ctx, cancel := context.WithCancel(context.Background()) @@ -138,7 +138,7 @@ func BuildNewImage(dockerfilePath string) (image ActiveImage, err error) { }, err } -// Parses a DockerImage from an identifier, possibly pulling it from a registry; +// GetPrebuiltImage Parses a DockerImage from an identifier, possibly pulling it from a registry; // Caller is responsible to call image.TearDown() after usage func GetPrebuiltImage(name string) (image ActiveImage, err error) { slog.Info("Getting prebuilt image", "image", name) @@ -176,12 +176,12 @@ func GetPrebuiltImage(name string) (image ActiveImage, err error) { }, err } -// Get a squashed filesystem at top layer +// GetSquashedFilesystem Get a squashed filesystem at top layer func GetSquashedFilesystem(image ActiveImage) filesystem.Filesystem { return GetSquashedFilesystemAtIndex(image, len(image.Layers)-1) } -// Get a squashed filesystem at layer with index index +// GetSquashedFilesystemAtIndex Get a squashed filesystem at layer with index func GetSquashedFilesystemAtIndex(image ActiveImage, index int) filesystem.Filesystem { return Layer{ Layer: image.Layers[index], diff --git a/provider/docker/layer.go b/provider/docker/layer.go index 7745453..426a010 100644 --- a/provider/docker/layer.go +++ b/provider/docker/layer.go @@ -23,7 +23,7 @@ import ( "log/slog" "github.com/IBM/cbomkit-theia/provider/filesystem" - scanner_errors "github.com/IBM/cbomkit-theia/scanner/errors" + scannererrors "github.com/IBM/cbomkit-theia/scanner/errors" "github.com/anchore/stereoscope/pkg/file" "github.com/anchore/stereoscope/pkg/filetree/filenode" @@ -31,14 +31,14 @@ import ( v1 "github.com/google/go-containerregistry/pkg/v1" ) -// Struct to represent a single layer in an ActiveImage +// Layer Struct to represent a single layer in an ActiveImage type Layer struct { // implements Filesystem *image.Layer index int image *ActiveImage } -// Walk all files in the squashed layer using fn +// WalkDir Walk all files in the squashed layer using fn func (layer Layer) WalkDir(fn filesystem.SimpleWalkDirFunc) error { return layer.SquashedTree.Walk( func(path file.Path, f filenode.FileNode) error { @@ -48,7 +48,7 @@ func (layer Layer) WalkDir(fn filesystem.SimpleWalkDirFunc) error { err := fn(string(path)) - if errors.Is(err, scanner_errors.ErrParsingFailedAlthoughChecked) { + if errors.Is(err, scannererrors.ErrParsingFailedAlthoughChecked) { slog.Warn(err.Error()) return nil } else { @@ -57,7 +57,7 @@ func (layer Layer) WalkDir(fn filesystem.SimpleWalkDirFunc) error { }, nil) } -// Read a file from this layer +// Open Read a file from this layer func (layer Layer) Open(path string) (io.ReadCloser, error) { readCloser, err := layer.OpenPathFromSquash(file.Path(path)) if err != nil { @@ -67,12 +67,12 @@ func (layer Layer) Open(path string) (io.ReadCloser, error) { return readCloser, err } -// Get the image config +// GetConfig Get the image config func (layer Layer) GetConfig() (config v1.Config, ok bool) { return layer.image.GetConfig() } -// Get a unique string for this layer in the image; can be used for logging etc. +// GetIdentifier Get a unique string for this layer in the image; can be used for logging etc. func (layer Layer) GetIdentifier() string { return fmt.Sprintf("Docker Image Layer (id:%v, layer:%v)", layer.image.id, layer.index) } diff --git a/provider/filesystem/filesystem.go b/provider/filesystem/filesystem.go index 8129695..daaae69 100644 --- a/provider/filesystem/filesystem.go +++ b/provider/filesystem/filesystem.go @@ -17,7 +17,7 @@ package filesystem import ( - go_errors "errors" + goerrors "errors" "fmt" "io" "io/fs" @@ -25,12 +25,12 @@ import ( "os" "path/filepath" - scanner_errors "github.com/IBM/cbomkit-theia/scanner/errors" + scannererrors "github.com/IBM/cbomkit-theia/scanner/errors" v1 "github.com/google/go-containerregistry/pkg/v1" ) -// A simple interface for a function to walk directories +// SimpleWalkDirFunc A simple interface for a function to walk directories type SimpleWalkDirFunc func(path string) error // Filesystem interface is mainly used to interact with all types of possible data source (e.g. directories, docker images etc.); for images this represents a squashed layer @@ -41,19 +41,19 @@ type Filesystem interface { GetIdentifier() string // Identifier for this specific filesystem; can be used for logging } -// Simple plain filesystem that is constructed from the directory +// PlainFilesystem Simple plain filesystem that is constructed from the directory type PlainFilesystem struct { // implements Filesystem rootPath string } -// Get a new PlainFilesystem from rootPath +// NewPlainFilesystem Get a new PlainFilesystem from rootPath func NewPlainFilesystem(rootPath string) PlainFilesystem { return PlainFilesystem{ rootPath: rootPath, } } -// Walk the whole PlainFilesystem using fn +// WalkDir Walk the whole PlainFilesystem using fn func (plainFilesystem PlainFilesystem) WalkDir(fn SimpleWalkDirFunc) error { return filepath.WalkDir(plainFilesystem.rootPath, func(path string, d fs.DirEntry, err error) error { if err != nil { @@ -72,7 +72,7 @@ func (plainFilesystem PlainFilesystem) WalkDir(fn SimpleWalkDirFunc) error { err = fn(relativePath) - if go_errors.Is(err, scanner_errors.ErrParsingFailedAlthoughChecked) { + if goerrors.Is(err, scannererrors.ErrParsingFailedAlthoughChecked) { slog.Warn(err.Error()) return nil } else { @@ -81,17 +81,17 @@ func (plainFilesystem PlainFilesystem) WalkDir(fn SimpleWalkDirFunc) error { }) } -// Read a file from this filesystem; path should be relative to PlainFilesystem.rootPath +// Open Read a file from this filesystem; path should be relative to PlainFilesystem.rootPath func (plainFilesystem PlainFilesystem) Open(path string) (io.ReadCloser, error) { return os.Open(filepath.Join(plainFilesystem.rootPath, path)) } -// A plain directory does not have filesystem, so we return an empty object and false +// GetConfig A plain directory does not have filesystem, so we return an empty object and false func (plainFilesystem PlainFilesystem) GetConfig() (config v1.Config, ok bool) { return v1.Config{}, false } -// Get a unique string for this PlainFilesystem; can be used for logging etc. +// GetIdentifier Get a unique string for this PlainFilesystem; can be used for logging etc. func (plainFilesystem PlainFilesystem) GetIdentifier() string { return fmt.Sprintf("Plain Filesystem (%v)", plainFilesystem.rootPath) } diff --git a/scanner/bom-dag/bom-dag.go b/scanner/bom-dag/bom-dag.go index 8bfe07f..824656c 100644 --- a/scanner/bom-dag/bom-dag.go +++ b/scanner/bom-dag/bom-dag.go @@ -18,48 +18,47 @@ package bomdag import ( "encoding/hex" + "errors" "fmt" - "log/slog" - "net/url" - "os" - "path/filepath" - cdx "github.com/CycloneDX/cyclonedx-go" "github.com/dominikbraun/graph" - "github.com/dominikbraun/graph/draw" + "log/slog" ) -// Type that hold the hash of a BomDAG vertex -type BomDAGVertexHash = [8]byte +// VertexHash BomDAGVertexHash Type that holds the hash of a BomDAG vertex +type VertexHash = [8]byte // BomDAG represents a directed, acyclic graph of several interconnected components type BomDAG struct { - graph.Graph[BomDAGVertexHash, bomDAGVertex] - Root BomDAGVertexHash // Hash of the root component + graph.Graph[VertexHash, bomDAGVertex] + Root VertexHash // Hash of the root component } func NewBomDAG() BomDAG { rootComponent := vertexRoot{} rootHash := hashBOMDAGVertex(rootComponent) g := graph.New(hashBOMDAGVertex, graph.Acyclic(), graph.Directed(), graph.PreventCycles(), graph.Rooted()) - g.AddVertex(rootComponent, getLabelForBOMDAGVertex(rootComponent)) + err := g.AddVertex(rootComponent, getLabelForBOMDAGVertex(rootComponent)) + if err != nil { + return BomDAG{} + } return BomDAG{ Graph: g, Root: rootHash, } } -// Type defining the different types of dependencies that components can have in the BomDAG +// BomDAGDependencyType Type defining the different types of dependencies that components can have in the BomDAG type BomDAGDependencyType string const ( - BomDAGDependencyTypeDependsOn BomDAGDependencyType = "dependsOn" - BomDAGDependencyTypeCertificatePropertiesSignatureAlgorithmRef BomDAGDependencyType = "CertificatePropertiesSignatureAlgorithmRef" - BomDAGDependencyTypeCertificatePropertiesSubjectPublicKeyRef BomDAGDependencyType = "CertificatePropertiesSubjectPublicKeyRef" - BomDAGDependencyTypeRelatedCryptoMaterialPropertiesAlgorithmRef BomDAGDependencyType = "RelatedCryptoMaterialPropertiesAlgorithmRef" - BomDAGDependencyTypeRelatedCryptoMaterialPropertiesSecuredByAlgorithmRef BomDAGDependencyType = "RelatedCryptoMaterialPropertiessecuredByAlgorithmRef" - BomDAGDependencyTypeProtocolPropertiesCryptoRefArrayElement BomDAGDependencyType = "protocolPropertiescryptoRefArray" - BomDAGDependencyTypeOccurrence BomDAGDependencyType = "occurrence" + DependencyTypeDependsOn BomDAGDependencyType = "dependsOn" + DependencyTypeCertificatePropertiesSignatureAlgorithmRef BomDAGDependencyType = "CertificatePropertiesSignatureAlgorithmRef" + DependencyTypeCertificatePropertiesSubjectPublicKeyRef BomDAGDependencyType = "CertificatePropertiesSubjectPublicKeyRef" + DependencyTypeRelatedCryptoMaterialPropertiesAlgorithmRef BomDAGDependencyType = "RelatedCryptoMaterialPropertiesAlgorithmRef" + DependencyTypeRelatedCryptoMaterialPropertiesSecuredByAlgorithmRef BomDAGDependencyType = "RelatedCryptoMaterialPropertiessecuredByAlgorithmRef" + DependencyTypeProtocolPropertiesCryptoRefArrayElement BomDAGDependencyType = "protocolPropertiescryptoRefArray" + DependencyTypeOccurrence BomDAGDependencyType = "occurrence" ) func EdgeDependencyType(dependencyType BomDAGDependencyType) func(*graph.EdgeProperties) { @@ -73,7 +72,7 @@ func EdgeDependencyType(dependencyType BomDAGDependencyType) func(*graph.EdgePro } } -// Generate slice of cyclonedx-go components from the graph; also return a map of dependencies (e.g. "bomref1" depends on "bomref2" and "bomref3") +// GetCDXComponents Generate slice of cyclonedx-go components from the graph; also return a map of dependencies (e.g. "bomref1" depends on "bomref2" and "bomref3") func (bomDAG *BomDAG) GetCDXComponents() ([]cdx.Component, map[cdx.BOMReference][]string, error) { components := make([]cdx.Component, 0) dependencyMap := make(map[cdx.BOMReference][]string, 0) @@ -99,25 +98,25 @@ func (bomDAG *BomDAG) GetCDXComponents() ([]cdx.Component, map[cdx.BOMReference] targetBomRef := cdx.BOMReference(hex.EncodeToString(edge.Target[:])) for edgeType := range edge.Properties.Attributes { switch edgeType { - case string(BomDAGDependencyTypeDependsOn): + case string(DependencyTypeDependsOn): if _, ok := dependencyMap[cdx.BOMReference(component.BOMRef)]; !ok { dependencyMap[cdx.BOMReference(component.BOMRef)] = make([]string, 0) } dependencyMap[cdx.BOMReference(component.BOMRef)] = append(dependencyMap[cdx.BOMReference(component.BOMRef)], string(targetBomRef)) - case string(BomDAGDependencyTypeCertificatePropertiesSignatureAlgorithmRef): + case string(DependencyTypeCertificatePropertiesSignatureAlgorithmRef): component.CryptoProperties.CertificateProperties.SignatureAlgorithmRef = targetBomRef - case string(BomDAGDependencyTypeCertificatePropertiesSubjectPublicKeyRef): + case string(DependencyTypeCertificatePropertiesSubjectPublicKeyRef): component.CryptoProperties.CertificateProperties.SubjectPublicKeyRef = targetBomRef - case string(BomDAGDependencyTypeRelatedCryptoMaterialPropertiesAlgorithmRef): + case string(DependencyTypeRelatedCryptoMaterialPropertiesAlgorithmRef): component.CryptoProperties.RelatedCryptoMaterialProperties.AlgorithmRef = targetBomRef - case string(BomDAGDependencyTypeRelatedCryptoMaterialPropertiesSecuredByAlgorithmRef): + case string(DependencyTypeRelatedCryptoMaterialPropertiesSecuredByAlgorithmRef): component.CryptoProperties.RelatedCryptoMaterialProperties.SecuredBy.AlgorithmRef = targetBomRef - case string(BomDAGDependencyTypeProtocolPropertiesCryptoRefArrayElement): + case string(DependencyTypeProtocolPropertiesCryptoRefArrayElement): if component.CryptoProperties.ProtocolProperties.CryptoRefArray == nil { component.CryptoProperties.ProtocolProperties.CryptoRefArray = new([]cdx.BOMReference) } *component.CryptoProperties.ProtocolProperties.CryptoRefArray = append(*component.CryptoProperties.ProtocolProperties.CryptoRefArray, targetBomRef) - case string(BomDAGDependencyTypeOccurrence): + case string(DependencyTypeOccurrence): targetVertex, _ := bomDAG.Vertex(edge.Target) *component.Evidence.Occurrences = append(*component.Evidence.Occurrences, targetVertex.(vertexOccurrence).EvidenceOccurrence) } @@ -165,7 +164,7 @@ func (bomDAG *BomDAG) Merge(other BomDAG) error { return nil } -func (bomDAG *BomDAG) mergeEdgePropertyAttributes(otherEdge graph.Edge[BomDAGVertexHash]) error { +func (bomDAG *BomDAG) mergeEdgePropertyAttributes(otherEdge graph.Edge[VertexHash]) error { mainEdge, err := bomDAG.Edge(otherEdge.Source, otherEdge.Target) if err != nil { @@ -184,7 +183,10 @@ func (bomDAG *BomDAG) mergeEdgePropertyAttributes(otherEdge graph.Edge[BomDAGVer return fmt.Errorf("attribute %v cannot be merged (both are set and cannot merge strings); mainValue: %v, otherValue: %v", key, mainValue, otherValue) } } else { - bomDAG.UpdateEdge(otherEdge.Source, otherEdge.Target, graph.EdgeAttribute(key, otherValue)) + err = bomDAG.UpdateEdge(otherEdge.Source, otherEdge.Target, graph.EdgeAttribute(key, otherValue)) + if err != nil { + slog.Error(err.Error()) + } } } @@ -222,17 +224,17 @@ func copyVertexProperties(source graph.VertexProperties) func(*graph.VertexPrope } } -// Add a component to this graph; +// AddCDXComponent Add a component to this graph; // This should be mainly used to add components to the graph -func (bomDAG *BomDAG) AddCDXComponent(value cdx.Component, options ...func(*graph.VertexProperties)) (valueHash BomDAGVertexHash, err error) { +func (bomDAG *BomDAG) AddCDXComponent(value cdx.Component, options ...func(*graph.VertexProperties)) (valueHash VertexHash, err error) { // Extract the occurrence component - var occurrenceHashes []BomDAGVertexHash + var occurrenceHashes []VertexHash if value.Evidence != nil && value.Evidence.Occurrences != nil && len(*value.Evidence.Occurrences) > 0 { - occurrenceHashes = make([]BomDAGVertexHash, len(*value.Evidence.Occurrences)) + occurrenceHashes = make([]VertexHash, len(*value.Evidence.Occurrences)) for i, occurrence := range *value.Evidence.Occurrences { hash, err := bomDAG.getVertexOrAddNew(vertexOccurrence{occurrence}) if err != nil { - return BomDAGVertexHash{}, err + return VertexHash{}, err } occurrenceHashes[i] = hash } @@ -248,37 +250,24 @@ func (bomDAG *BomDAG) AddCDXComponent(value cdx.Component, options ...func(*grap } for _, occurrenceHash := range occurrenceHashes { - bomDAG.AddEdge(valueHash, occurrenceHash, EdgeDependencyType(BomDAGDependencyTypeOccurrence)) + err = bomDAG.AddEdge(valueHash, occurrenceHash, EdgeDependencyType(DependencyTypeOccurrence)) + if err != nil { + slog.Error(err.Error()) + } } return valueHash, nil } -func (bomDAG *BomDAG) getVertexOrAddNew(value bomDAGVertex, options ...func(*graph.VertexProperties)) (hash BomDAGVertexHash, err error) { +func (bomDAG *BomDAG) getVertexOrAddNew(value bomDAGVertex, options ...func(*graph.VertexProperties)) (hash VertexHash, err error) { hash = hashBOMDAGVertex(value) // Does the component already exist? _, err = bomDAG.Vertex(hash) - if err != graph.ErrVertexNotFound { + if !errors.Is(err, graph.ErrVertexNotFound) { return hash, nil } err = bomDAG.AddVertex(value, append(options, getLabelForBOMDAGVertex(value))...) return hash, err } - -// Write a graphical representation of the graph to a file -func (bomDAG *BomDAG) WriteToFile(filenamePrefix string) { - if err := os.MkdirAll(filepath.Join(".", "cbomkit-theia_graphs"), os.ModePerm); err != nil { - slog.Warn("Failed to create directory for graphs. Skipping this step.", "error", err.Error()) - } else { - file, err := os.Create(filepath.Join(".", "cbomkit-theia_graphs", url.PathEscape(fmt.Sprintf("%v_certificate_graph.dot", filenamePrefix)))) - if err != nil { - slog.Warn("Failed to generate DOT file for graph", "error", err.Error()) - } - err = draw.DOT(bomDAG, file) - if err != nil { - slog.Warn("Failed to write to DOT file for graph", "error", err.Error()) - } - } -} diff --git a/scanner/bom-dag/vertex.go b/scanner/bom-dag/vertex.go index 3fc02d8..ff08596 100644 --- a/scanner/bom-dag/vertex.go +++ b/scanner/bom-dag/vertex.go @@ -35,14 +35,14 @@ type bomDAGVertex interface { string() string } -func hashBOMDAGVertex(bomDAGVertex bomDAGVertex) BomDAGVertexHash { +func hashBOMDAGVertex(bomDAGVertex bomDAGVertex) VertexHash { switch bomDAGVertex.getType() { case bomDAGVertexTypeComponent: - return hash.HashCDXComponentWithoutRefs(bomDAGVertex.(vertexComponent).Component) + return hash.CdxComponentWithoutRefs(bomDAGVertex.(vertexComponent).Component) case bomDAGVertexTypeRoot: - return BomDAGVertexHash{0} + return VertexHash{0} case bomDAGVertexTypeOccurrence: - return hash.HashStruct8Byte(bomDAGVertex.(vertexOccurrence)) + return hash.Struct8Byte(bomDAGVertex.(vertexOccurrence)) default: panic("Unsupported BOM DAG Vertex Type!") } diff --git a/scanner/componentwithconfidenceslice/componentwithconfidence-slice.go b/scanner/componentwithconfidenceslice/componentwithconfidence-slice.go index 18f4dbf..da0e8da 100644 --- a/scanner/componentwithconfidenceslice/componentwithconfidence-slice.go +++ b/scanner/componentwithconfidenceslice/componentwithconfidence-slice.go @@ -22,32 +22,33 @@ import ( cdx "github.com/CycloneDX/cyclonedx-go" ) -// CycloneDX component bundled with according ConfidenceLevel -type componentWithConfidence struct { +// ComponentWithConfidence CycloneDX component bundled with according ConfidenceLevel +type ComponentWithConfidence struct { *cdx.Component Confidence *confidencelevel.ConfidenceLevel printConfidenceLevel bool } -func (componentWithConfidence *componentWithConfidence) SetPrintConfidenceLevel(value bool) { +func (componentWithConfidence *ComponentWithConfidence) SetPrintConfidenceLevel(value bool) { componentWithConfidence.printConfidenceLevel = value } -// Slice of componentWithConfidence with a map mapping BOMReference to index in the components slice; bomRefMap can be used to access members of components by BOMReference without searching for the BOMReference in the structs itself +// ComponentWithConfidenceSlice Slice of componentWithConfidence with a map mapping BOMReference to index in the component slice; +// bomRefMap can be used to access members of components by BOMReference without searching for the BOMReference in the structs itself type ComponentWithConfidenceSlice struct { - components []componentWithConfidence + components []ComponentWithConfidence bomRefMap map[cdx.BOMReference]int } -// Generate a AdvancedComponentSlice from a slice of components +// FromComponentSlice Generate a AdvancedComponentSlice from a slice of components func FromComponentSlice(slice []cdx.Component) *ComponentWithConfidenceSlice { advancedComponentSlice := ComponentWithConfidenceSlice{ - components: make([]componentWithConfidence, 0, len(slice)), + components: make([]ComponentWithConfidence, 0, len(slice)), bomRefMap: make(map[cdx.BOMReference]int), } for i, comp := range slice { - advancedComponentSlice.components = append(advancedComponentSlice.components, componentWithConfidence{ + advancedComponentSlice.components = append(advancedComponentSlice.components, ComponentWithConfidence{ Component: &comp, Confidence: confidencelevel.New(), printConfidenceLevel: false, @@ -61,22 +62,22 @@ func FromComponentSlice(slice []cdx.Component) *ComponentWithConfidenceSlice { return &advancedComponentSlice } -// Get member of AdvancedComponentSlice by index -func (advancedComponentSlice *ComponentWithConfidenceSlice) GetByIndex(i int) *componentWithConfidence { +// GetByIndex Get member of AdvancedComponentSlice by index +func (advancedComponentSlice *ComponentWithConfidenceSlice) GetByIndex(i int) *ComponentWithConfidence { return &advancedComponentSlice.components[i] } -// Get member of AdvancedComponentSlice by BOMReference -func (advancedComponentSlice *ComponentWithConfidenceSlice) GetByRef(ref cdx.BOMReference) (*componentWithConfidence, bool) { +// GetByRef Get member of AdvancedComponentSlice by BOMReference +func (advancedComponentSlice *ComponentWithConfidenceSlice) GetByRef(ref cdx.BOMReference) (*ComponentWithConfidence, bool) { i, ok := advancedComponentSlice.bomRefMap[ref] if !ok { - return &componentWithConfidence{}, false + return &ComponentWithConfidence{}, false } else { return &advancedComponentSlice.components[i], true } } -// Generate CycloneDX Components from this AdvancedComponentSlice; automatically sets the confidence_level property +// GetComponentSlice Generate CycloneDX Components from this AdvancedComponentSlice; automatically sets the confidence_level property func (advancedComponentSlice *ComponentWithConfidenceSlice) GetComponentSlice() []cdx.Component { finalCompSlice := make([]cdx.Component, 0, len(advancedComponentSlice.components)) diff --git a/scanner/confidencelevel/confidencelevel.go b/scanner/confidencelevel/confidencelevel.go index 2110e4d..4800a6a 100644 --- a/scanner/confidencelevel/confidencelevel.go +++ b/scanner/confidencelevel/confidencelevel.go @@ -22,9 +22,8 @@ import ( cdx "github.com/CycloneDX/cyclonedx-go" ) -// A confidence level represents a level of confidence -// -// Example: +// ConfidenceLevel A confidence level represents a level of confidence +// Example: // A ConfidenceLevel could be used to represent the confidence that an algorithm is executable in a certain environment. type ConfidenceLevel struct { count int @@ -32,25 +31,25 @@ type ConfidenceLevel struct { value int } -// Modifiers for the ConfidenceLevel -type ConfidenceLevelModifier int +// Modifier ConfidenceLevelModifier Modifiers for the ConfidenceLevel +type Modifier int // Constant value that can be used for the modification of a ConfidenceLevel const ( - confidenceLevelMax = 100 - confidenceLevelDefault = 50 - confidenceLevelMin = 0 - ConfidenceLevelModifierPositiveExtreme ConfidenceLevelModifier = 50 - ConfidenceLevelModifierPositiveHigh ConfidenceLevelModifier = 30 - ConfidenceLevelModifierPositiveMedium ConfidenceLevelModifier = 15 - ConfidenceLevelModifierPositiveLow ConfidenceLevelModifier = 5 - ConfidenceLevelModifierNegativeExtreme ConfidenceLevelModifier = -50 - ConfidenceLevelModifierNegativeHigh ConfidenceLevelModifier = -30 - ConfidenceLevelModifierNegativeMedium ConfidenceLevelModifier = -15 - ConfidenceLevelModifierNegativeLow ConfidenceLevelModifier = -5 + confidenceLevelMax = 100 + confidenceLevelDefault = 50 + confidenceLevelMin = 0 + PositiveExtreme Modifier = 50 + PositiveHigh Modifier = 30 + PositiveMedium Modifier = 15 + PositiveLow Modifier = 5 + NegativeExtreme Modifier = -50 + NegativeHigh Modifier = -30 + NegativeMedium Modifier = -15 + NegativeLow Modifier = -5 ) -// Get a new ConfidenceLevel; default value is confidenceLevelDefault +// New Get a new ConfidenceLevel; default value is confidenceLevelDefault func New() *ConfidenceLevel { return &ConfidenceLevel{ count: 0, @@ -59,12 +58,12 @@ func New() *ConfidenceLevel { } } -// Get the value of the ConfidenceLevel +// GetValue Get the value of the ConfidenceLevel func (confidenceLevel *ConfidenceLevel) GetValue() int { return confidenceLevel.value } -// Generate a CycloneDX component property from this confidence +// GetProperty Generate a CycloneDX component property from this confidence func (confidenceLevel *ConfidenceLevel) GetProperty() cdx.Property { return cdx.Property{ Name: "confidence_level", @@ -73,7 +72,7 @@ func (confidenceLevel *ConfidenceLevel) GetProperty() cdx.Property { } // Modify the confidence level using one of the predefined ConfidenceLevelModifier values -func (confidenceLevel *ConfidenceLevel) Modify(modifier ConfidenceLevelModifier) { +func (confidenceLevel *ConfidenceLevel) Modify(modifier Modifier) { confidenceLevel.value += int(modifier) if confidenceLevel.value < confidenceLevelMin { diff --git a/scanner/errors/errors.go b/scanner/errors/errors.go index ca94fb0..6c92e62 100644 --- a/scanner/errors/errors.go +++ b/scanner/errors/errors.go @@ -21,18 +21,25 @@ import ( "fmt" ) -// Error to represent cases in which a plugin had to interrupt its execution due to missing information (e.g. in the BOM or in the filesystem) +// ErrInsufficientInformation Error +// to represent cases in which a plugin had to interrupt its execution due to missing information +// (e.g., in the BOM or in the filesystem) var ErrInsufficientInformation = errors.New("scanner: insufficient information to continue") -// Error to represent cases in which a plugin had to interrupt its execution due to missing information (e.g. in the BOM or in the filesystem) +// GetInsufficientInformationError Error to represent cases in which a plugin had +// to interrupt its execution due to missing information (e.g., in the BOM or in the filesystem) func GetInsufficientInformationError(msg string, plugin string, affectedObjectType string, affectedObjectName string) error { return fmt.Errorf("%w: (%v:%v:%v) %v", ErrInsufficientInformation, plugin, affectedObjectType, affectedObjectName, msg) } -// Error to represent cases in which parsing of a relevant file failed although the plugin verified the file beforehand; this error might suggest an bug +// ErrParsingFailedAlthoughChecked Error +// to represent cases in which parsing of a relevant file failed although the plugin verified the file beforehand; +// this error might suggest a bug var ErrParsingFailedAlthoughChecked = errors.New("scanner: failed to parse file that was assumed to be a valid configuration") -// Error to represent cases in which parsing of a relevant file failed although the plugin verified the file beforehand; this error might suggest an bug +// GetParsingFailedAlthoughCheckedError Error to represent cases in which parsing of a relevant file failed +// although the plugin verified the file beforehand; +// this error might suggest a bug func GetParsingFailedAlthoughCheckedError(parsingError error, plugin string) error { return fmt.Errorf("%w: (%v) %w", ErrParsingFailedAlthoughChecked, plugin, parsingError) } diff --git a/scanner/hash/hash.go b/scanner/hash/hash.go index b8bd995..38ebd34 100644 --- a/scanner/hash/hash.go +++ b/scanner/hash/hash.go @@ -29,7 +29,7 @@ type cleaner struct { unset func(comp *cdx.Component) any } -func HashStruct8Byte(a any) [8]byte { +func Struct8Byte(a any) [8]byte { hash, err := hashstructure.Hash(a, hashstructure.FormatV2, &hashstructure.HashOptions{ ZeroNil: true, SlicesAsSets: true, @@ -44,7 +44,7 @@ func HashStruct8Byte(a any) [8]byte { return b8 } -func HashCDXComponentWithoutRefs(a cdx.Component) [8]byte { +func CdxComponentWithoutRefs(a cdx.Component) [8]byte { cleaners := []cleaner{ { set: func(comp *cdx.Component, value any) { @@ -145,28 +145,5 @@ func HashCDXComponentWithoutRefs(a cdx.Component) [8]byte { } }(cleaners, a, temp) - return HashStruct8Byte(a) -} - -func HashCDXComponentWithoutRefsWithoutEvidence(a cdx.Component) [8]byte { - cleaner := cleaner{ - set: func(comp *cdx.Component, value any) { - if comp.Evidence != nil { - comp.Evidence = value.(*cdx.Evidence) - } - }, - unset: func(comp *cdx.Component) any { - if comp.Evidence != nil { - temp := comp.Evidence - comp.Evidence = new(cdx.Evidence) - return temp - } - return nil - }, - } - - temp := cleaner.unset(&a) - defer cleaner.set(&a, temp) - - return HashCDXComponentWithoutRefs(a) + return Struct8Byte(a) } diff --git a/scanner/pem-utility/parser.go b/scanner/pem-utility/parser.go index dafa253..5016ab9 100644 --- a/scanner/pem-utility/parser.go +++ b/scanner/pem-utility/parser.go @@ -41,15 +41,15 @@ type Filter struct { List []PEMBlockType } -// Used to specify whether a filter is an allow- or blocklist +// PEMTypeFilterType Used to specify whether a filter is an allow- or blocklist type PEMTypeFilterType bool const ( - PEMTypeFilterTypeAllowlist PEMTypeFilterType = true // Allow List - PEMTypeFilterTypeBlocklist PEMTypeFilterType = false // Block List + PEMTypeFilterTypeAllowlist PEMTypeFilterType = true // Allowlist + PEMTypeFilterTypeBlocklist PEMTypeFilterType = false // Blocklist ) -// A not complete list of PEMBlockTypes that can be detected currently +// PEMBlockType A not complete list of PEMBlockTypes that can be detected currently type PEMBlockType string const ( @@ -78,7 +78,8 @@ func parsePEMToBlocks(raw []byte) []*pem.Block { return blocks } -// Parse a the []byte of a PEM file to a map containing the *pem.Block and a PEMBlockType for each block +// ParsePEMToBlocksWithTypes Parse the []byte of a PEM file to a map +// containing the *pem.Block and a PEMBlockType for each block func ParsePEMToBlocksWithTypes(raw []byte) map[*pem.Block]PEMBlockType { blocks := parsePEMToBlocks(raw) @@ -91,7 +92,7 @@ func ParsePEMToBlocksWithTypes(raw []byte) map[*pem.Block]PEMBlockType { return blocksWithType } -// Just like ParsePEMToBlocksWithTypes but uses a filter for filtering +// ParsePEMToBlocksWithTypeFilter Just like ParsePEMToBlocksWithTypes but uses a filter for filtering func ParsePEMToBlocksWithTypeFilter(raw []byte, filter Filter) map[*pem.Block]PEMBlockType { blocksWithType := ParsePEMToBlocksWithTypes(raw) filteredBlocksWithType := make(map[*pem.Block]PEMBlockType) @@ -107,7 +108,7 @@ func ParsePEMToBlocksWithTypeFilter(raw []byte, filter Filter) map[*pem.Block]PE var errUnknownKeyAlgorithm = errors.New("key block uses unknown algorithm") -// Generate cyclonedx-go components from a block containing a key +// GenerateComponentsFromPEMKeyBlock Generate cyclone-go components from a block containing a key func GenerateComponentsFromPEMKeyBlock(block *pem.Block) ([]cdx.Component, error) { switch PEMBlockType(block.Type) { diff --git a/scanner/plugins/certificates/certificates.go b/scanner/plugins/certificates/certificates.go index c170f5a..5a6b77b 100644 --- a/scanner/plugins/certificates/certificates.go +++ b/scanner/plugins/certificates/certificates.go @@ -26,7 +26,7 @@ import ( "strings" "github.com/IBM/cbomkit-theia/provider/filesystem" - scanner_errors "github.com/IBM/cbomkit-theia/scanner/errors" + scannererrors "github.com/IBM/cbomkit-theia/scanner/errors" pemutility "github.com/IBM/cbomkit-theia/scanner/pem-utility" "github.com/IBM/cbomkit-theia/scanner/plugins" @@ -38,35 +38,38 @@ import ( ) // Plugin to parse certificates from the filesystem -type CertificatesPlugin struct{} +type Plugin struct{} -// Get the name of the plugin -func (CertificatesPlugin) GetName() string { +// GetName Get the name of the plugin +func (*Plugin) GetName() string { return "Certificate File Plugin" } -func (CertificatesPlugin) GetExplanation() string { +func (*Plugin) GetExplanation() string { return "Find x.509 certificates" } -// Get the type of the plugin -func (CertificatesPlugin) GetType() plugins.PluginType { +// GetType Get the type of the plugin +func (*Plugin) GetType() plugins.PluginType { return plugins.PluginTypeAppend } -// Parse all certificates from the given filesystem +// NewCertificatePlugin Parse all certificates from the given filesystem func NewCertificatePlugin() (plugins.Plugin, error) { - return &CertificatesPlugin{}, nil + return &Plugin{}, nil } -// Add the found certificates to the slice of components -func (certificatesPlugin *CertificatesPlugin) UpdateBOM(fs filesystem.Filesystem, bom *cdx.BOM) error { - certificates := []*x509CertificateWithMetadata{} +// UpdateBOM Add the found certificates to the slice of components +func (certificatesPlugin *Plugin) UpdateBOM(fs filesystem.Filesystem, bom *cdx.BOM) error { + var certificates []*x509CertificateWithMetadata // Set GODEBUG to allow negative serial numbers (see https://github.com/golang/go/commit/db13584baedce4909915cb4631555f6dbd7b8c38) - setX509NegativeSerial() + err := setX509NegativeSerial() + if err != nil { + slog.Error(err.Error()) + } - err := fs.WalkDir( + err = fs.WalkDir( func(path string) (err error) { switch filepath.Ext(path) { case ".pem", ".cer", ".cert", ".der", ".ca-bundle", ".crt": @@ -80,7 +83,7 @@ func (certificatesPlugin *CertificatesPlugin) UpdateBOM(fs filesystem.Filesystem } certs, err := certificatesPlugin.parsex509CertFromPath(raw, path) if err != nil { - return scanner_errors.GetParsingFailedAlthoughCheckedError(err, certificatesPlugin.GetName()) + return scannererrors.GetParsingFailedAlthoughCheckedError(err, certificatesPlugin.GetName()) } certificates = append(certificates, certs...) case ".p7a", ".p7b", ".p7c", ".p7r", ".p7s", ".spc": @@ -94,7 +97,7 @@ func (certificatesPlugin *CertificatesPlugin) UpdateBOM(fs filesystem.Filesystem } certs, err := certificatesPlugin.parsePKCS7FromPath(raw, path) if err != nil { - return scanner_errors.GetParsingFailedAlthoughCheckedError(err, certificatesPlugin.GetName()) + return scannererrors.GetParsingFailedAlthoughCheckedError(err, certificatesPlugin.GetName()) } certificates = append(certificates, certs...) default: @@ -109,7 +112,10 @@ func (certificatesPlugin *CertificatesPlugin) UpdateBOM(fs filesystem.Filesystem } // Set GODEBUG to old setting - removeX509NegativeSerial() + err = removeX509NegativeSerial() + if err != nil { + slog.Error(err.Error()) + } slog.Debug("Certificate searching done", "count", len(certificates)) @@ -157,7 +163,7 @@ func (certificatesPlugin *CertificatesPlugin) UpdateBOM(fs filesystem.Filesystem } // Parse a X.509 certificate from the given path (in base64 PEM or binary DER) -func (certificatesPlugin *CertificatesPlugin) parsex509CertFromPath(raw []byte, path string) ([]*x509CertificateWithMetadata, error) { +func (certificatesPlugin *Plugin) parsex509CertFromPath(raw []byte, path string) ([]*x509CertificateWithMetadata, error) { blocks := pemutility.ParsePEMToBlocksWithTypeFilter(raw, pemutility.Filter{ FilterType: pemutility.PEMTypeFilterTypeAllowlist, List: []pemutility.PEMBlockType{pemutility.PEMBlockTypeCertificate}, @@ -181,7 +187,7 @@ func (certificatesPlugin *CertificatesPlugin) parsex509CertFromPath(raw []byte, } // Parse X.509 certificates from a PKCS7 file (base64 PEM format) -func (certificatesPlugin CertificatesPlugin) parsePKCS7FromPath(raw []byte, path string) ([]*x509CertificateWithMetadata, error) { +func (certificatesPlugin *Plugin) parsePKCS7FromPath(raw []byte, path string) ([]*x509CertificateWithMetadata, error) { block, _ := pem.Decode(raw) pkcs7Object, err := pkcs7.Parse(block.Bytes) @@ -232,7 +238,7 @@ func MergeDependencyStructSlice(a []cdx.Dependency, b []cdx.Dependency) []cdx.De return a } -// Return index in slice if bomRef is found in slice or -1 if not present +// IndexBomRefInDependencySlice Return index in slice if bomRef is found in slice or -1 if not present func IndexBomRefInDependencySlice(slice []cdx.Dependency, bomRef cdx.BOMReference) int { for i, dep := range slice { if dep.Ref == string(bomRef) { diff --git a/scanner/plugins/certificates/x509.go b/scanner/plugins/certificates/x509.go index ffb1397..a81a837 100644 --- a/scanner/plugins/certificates/x509.go +++ b/scanner/plugins/certificates/x509.go @@ -31,15 +31,15 @@ import ( cdx "github.com/CycloneDX/cyclonedx-go" ) -// A X.509 certificate with additional metadata that is not part of the x509.Certificate struct +// An X.509 certificate with additional metadata that is not part of the x509.Certificate struct type x509CertificateWithMetadata struct { *x509.Certificate path string format string } -// During parsing of the x509.Certificate a unknown algorithm was found -var errX509UnknownAlgorithm = errors.New("X.509 certificate has unknown algorithm") +// During parsing of the x509.Certificate an unknown algorithm was found +var errX509UnknownAlgorithm = errors.New("x.509 certificate has unknown algorithm") // Create a new x509CertificateWithMetadata from a x509.Certificate and a path func newX509CertificateWithMetadata(cert *x509.Certificate, path string) (*x509CertificateWithMetadata, error) { @@ -92,7 +92,7 @@ func (x509CertificateWithMetadata *x509CertificateWithMetadata) generateDAG() (b publicKeyAlgorithmHash, err2 := dag.AddCDXComponent(publicKeyAlgorithm) publicKeyHash, err3 := dag.AddCDXComponent(publicKey) - var signatureAlgorithmHash, signatureAlgorithmPKEHash, signatureAlgorithmHashHash bomdag.BomDAGVertexHash + var signatureAlgorithmHash, signatureAlgorithmPKEHash, signatureAlgorithmHashHash bomdag.VertexHash var err4, err5, err6 error if signatureAlgorithm.signature != nil { signatureAlgorithmHash, err4 = dag.AddCDXComponent(*signatureAlgorithm.signature) @@ -112,15 +112,15 @@ func (x509CertificateWithMetadata *x509CertificateWithMetadata) generateDAG() (b // Creating Edges in DAG err6 = dag.AddEdge(dag.Root, certificateHash) err1 = dag.AddEdge(certificateHash, publicKeyHash, - bomdag.EdgeDependencyType(bomdag.BomDAGDependencyTypeCertificatePropertiesSubjectPublicKeyRef)) + bomdag.EdgeDependencyType(bomdag.DependencyTypeCertificatePropertiesSubjectPublicKeyRef)) err2 = dag.AddEdge(publicKeyHash, publicKeyAlgorithmHash, - bomdag.EdgeDependencyType(bomdag.BomDAGDependencyTypeRelatedCryptoMaterialPropertiesAlgorithmRef)) + bomdag.EdgeDependencyType(bomdag.DependencyTypeRelatedCryptoMaterialPropertiesAlgorithmRef)) err3 = dag.AddEdge(certificateHash, signatureAlgorithmHash, - bomdag.EdgeDependencyType(bomdag.BomDAGDependencyTypeCertificatePropertiesSignatureAlgorithmRef)) + bomdag.EdgeDependencyType(bomdag.DependencyTypeCertificatePropertiesSignatureAlgorithmRef)) err4 = dag.AddEdge(signatureAlgorithmHash, signatureAlgorithmPKEHash, - bomdag.EdgeDependencyType(bomdag.BomDAGDependencyTypeDependsOn)) + bomdag.EdgeDependencyType(bomdag.DependencyTypeDependsOn)) err5 = dag.AddEdge(signatureAlgorithmHash, signatureAlgorithmHashHash, - bomdag.EdgeDependencyType(bomdag.BomDAGDependencyTypeDependsOn)) + bomdag.EdgeDependencyType(bomdag.DependencyTypeDependsOn)) return dag, errors.Join(err1, err2, err3, err4, err5, err6) } diff --git a/scanner/plugins/javasecurity/config_parsing.go b/scanner/plugins/javasecurity/config_parsing.go index dc93f6b..99c30d1 100644 --- a/scanner/plugins/javasecurity/config_parsing.go +++ b/scanner/plugins/javasecurity/config_parsing.go @@ -17,7 +17,7 @@ package javasecurity import ( - go_errors "errors" + goerrors "errors" "fmt" "log/slog" "path/filepath" @@ -26,7 +26,7 @@ import ( "github.com/IBM/cbomkit-theia/provider/filesystem" advancedcomponentslice "github.com/IBM/cbomkit-theia/scanner/componentwithconfidenceslice" - scanner_errors "github.com/IBM/cbomkit-theia/scanner/errors" + scannererrors "github.com/IBM/cbomkit-theia/scanner/errors" cdx "github.com/CycloneDX/cyclonedx-go" v1 "github.com/google/go-containerregistry/pkg/v1" @@ -39,19 +39,19 @@ General ======= */ -// Checks whether the current file at path is a java.security config file -func (*JavaSecurityPlugin) isConfigFile(path string) bool { +// Checks whether the current file at a path is a java.security config file +func (*Plugin) isConfigFile(path string) bool { // Check if this file is the java.security file and if that is the case extract the path of the active crypto.policy files dir, _ := filepath.Split(path) dir = filepath.Clean(dir) - // Check correct directory + // Check the correct directory if !(strings.HasSuffix(dir, filepath.Join("jre", "lib", "security")) || strings.HasSuffix(dir, filepath.Join("conf", "security"))) { return false } - // Check file extension + // Check a file extension ext := filepath.Ext(path) if ext != ".security" { return false @@ -70,7 +70,7 @@ java.security related // JavaSecurity represents the java.security file(s) found on the system type JavaSecurity struct { *properties.Properties - tlsDisabledAlgorithms []JavaSecurityAlgorithmRestriction + tlsDisabledAlgorithms []AlgorithmRestriction } func newJavaSecurity(properties *properties.Properties, fs filesystem.Filesystem) (JavaSecurity, error) { @@ -98,10 +98,11 @@ func newJavaSecurity(properties *properties.Properties, fs filesystem.Filesystem }, err } -// Assesses if the component is from a source affected by this type of config (e.g. a java file), requires "Evidence" and "Occurrences" to be present in the BOM +// Assesses if the component is from a source affected by this type of config (e.g., a java file), +// requires "Evidence" and "Occurrences" to be present in the BOM func (*JavaSecurity) isComponentAffectedByConfig(component cdx.Component) (bool, error) { if component.Evidence == nil || component.Evidence.Occurrences == nil { // If there is no evidence telling us that whether this component comes from a java file, we cannot assess it - return false, scanner_errors.GetInsufficientInformationError("cannot evaluate due to missing evidence/occurrences in BOM", "java.security Plugin", "component", component.Name) + return false, scannererrors.GetInsufficientInformationError("cannot evaluate due to missing evidence/occurrences in BOM", "java.security Plugin", "component", component.Name) } for _, occurrence := range *component.Evidence.Occurrences { @@ -113,21 +114,20 @@ func (*JavaSecurity) isComponentAffectedByConfig(component cdx.Component) (bool, } // Update a single component; returns nil if component is not allowed -func (javaSecurity *JavaSecurity) updateComponent(index int, advancedcomponentslice *advancedcomponentslice.ComponentWithConfidenceSlice) (err error) { - - ok, err := javaSecurity.isComponentAffectedByConfig(*advancedcomponentslice.GetByIndex(index).Component) +func (javaSecurity *JavaSecurity) updateComponent(index int, advancedComponentSlice *advancedcomponentslice.ComponentWithConfidenceSlice) (err error) { + ok, err := javaSecurity.isComponentAffectedByConfig(*advancedComponentSlice.GetByIndex(index).Component) if ok { - advancedcomponentslice.GetByIndex(index).SetPrintConfidenceLevel(true) + advancedComponentSlice.GetByIndex(index).SetPrintConfidenceLevel(true) } else { - if go_errors.Is(err, scanner_errors.ErrInsufficientInformation) { + if goerrors.Is(err, scannererrors.ErrInsufficientInformation) { return err } } - switch advancedcomponentslice.GetByIndex(index).CryptoProperties.AssetType { + switch advancedComponentSlice.GetByIndex(index).CryptoProperties.AssetType { case cdx.CryptoAssetTypeProtocol: - return javaSecurity.updateProtocolComponent(index, advancedcomponentslice) + return javaSecurity.updateProtocolComponent(index, advancedComponentSlice) default: return nil } @@ -140,7 +140,8 @@ func removeFromSlice[T interface{}](slice []T, s int) []T { return append(slice[:s], slice[s+1:]...) } -// Recursively get all comma-separated values of the property key. Recursion is necessary since values can include "include" directives which refer to other properties and include them in this property. +// Recursively get all comma-separated values of the property key. Recursion is necessary since values can include +// "include" directives which refer to other properties and include them in this property. func getPropertyValuesRecursively(properties *properties.Properties, key string) (values []string, err error) { if properties == nil { return values, errNilProperties @@ -153,7 +154,7 @@ func getPropertyValuesRecursively(properties *properties.Properties, key string) values[i] = strings.TrimSpace(value) } } - toBeRemoved := []int{} // Remember the include directives and remove them later + toBeRemoved := []int{} // Remember they include directives and remove them later for i, value := range values { if strings.HasPrefix(value, "include") { toBeRemoved = append(toBeRemoved, i) @@ -175,13 +176,13 @@ func getPropertyValuesRecursively(properties *properties.Properties, key string) // Parses the TLS Rules from the java.security file // Returns a joined list of errors which occurred during parsing of algorithms -func extractTLSRules(securityProperties *properties.Properties) (restrictions []JavaSecurityAlgorithmRestriction, err error) { +func extractTLSRules(securityProperties *properties.Properties) (restrictions []AlgorithmRestriction, err error) { slog.Debug("Extracting TLS rules") securityPropertiesKey := "jdk.tls.disabledAlgorithms" algorithms, err := getPropertyValuesRecursively(securityProperties, securityPropertiesKey) - if go_errors.Is(err, errNilProperties) { + if goerrors.Is(err, errNilProperties) { slog.Warn("Properties of javaSecurity object are nil. This should not happen. Continuing anyway.") } else if err != nil { return restrictions, err @@ -242,7 +243,7 @@ func extractTLSRules(securityProperties *properties.Properties) (restrictions [] } } - restrictions = append(restrictions, JavaSecurityAlgorithmRestriction{ + restrictions = append(restrictions, AlgorithmRestriction{ name: name, keySize: keySize, keySizeOperator: keySizeOperator, @@ -252,7 +253,7 @@ func extractTLSRules(securityProperties *properties.Properties) (restrictions [] slog.Debug("No disabled algorithms specified!", "key", securityPropertiesKey) } - return restrictions, go_errors.Join(algorithmParsingErrors...) + return restrictions, goerrors.Join(algorithmParsingErrors...) } /* @@ -261,7 +262,7 @@ container image related ======= */ -const SECURITY_CMD_ARGUMENT = "-Djava.security.properties=" +const SecurityCmdArgument = "-Djava.security.properties=" // Tries to get a config from the fs and checks the Config for potentially relevant information func checkConfig(securityProperties *properties.Properties, fs filesystem.Filesystem) (additionalSecurityProperties *properties.Properties, override bool, err error) { @@ -275,7 +276,7 @@ func checkConfig(securityProperties *properties.Properties, fs filesystem.Filesy additionalSecurityProperties, override, err = checkForAdditionalSecurityFilesCMDParameter(imageConfig, securityProperties, fs) - if go_errors.Is(err, errNilProperties) { + if goerrors.Is(err, errNilProperties) { slog.Warn("Properties of javaSecurity object are nil. This should not happen. Continuing anyway.", "fs", fs.GetIdentifier()) return additionalSecurityProperties, override, nil } @@ -302,7 +303,7 @@ func checkForAdditionalSecurityFilesCMDParameter(config v1.Config, securityPrope var ok bool for _, command := range append(config.Cmd, config.Entrypoint...) { - value, override, ok = getJavaFlagValue(command, SECURITY_CMD_ARGUMENT) + value, override, ok = getJavaFlagValue(command, SecurityCmdArgument) if ok { slog.Debug("Found command that specifies new properties", "command", command) diff --git a/scanner/plugins/javasecurity/javasecurity.go b/scanner/plugins/javasecurity/javasecurity.go index 90f6f43..7c34ef5 100644 --- a/scanner/plugins/javasecurity/javasecurity.go +++ b/scanner/plugins/javasecurity/javasecurity.go @@ -17,7 +17,7 @@ package javasecurity import ( - go_errors "errors" + goerrors "errors" "fmt" "log/slog" "os" @@ -26,7 +26,7 @@ import ( "github.com/IBM/cbomkit-theia/provider/filesystem" advancedcomponentslice "github.com/IBM/cbomkit-theia/scanner/componentwithconfidenceslice" - scanner_errors "github.com/IBM/cbomkit-theia/scanner/errors" + scannererrors "github.com/IBM/cbomkit-theia/scanner/errors" "github.com/IBM/cbomkit-theia/scanner/plugins" cdx "github.com/CycloneDX/cyclonedx-go" @@ -34,31 +34,32 @@ import ( "github.com/magiconair/properties" ) -// Represents the java security plugin in a specific scanning context +// Plugin Represents the java security plugin in a specific scanning context // Implements the config/ConfigPlugin interface -type JavaSecurityPlugin struct{} +type Plugin struct{} -// Creates underlying data structure for evaluation +// NewJavaSecurityPlugin Creates underlying data structure for evaluation func NewJavaSecurityPlugin() (plugins.Plugin, error) { - return &JavaSecurityPlugin{}, nil + return &Plugin{}, nil } -// Get the name of the plugin for debugging purposes -func (JavaSecurityPlugin) GetName() string { +// GetName Get the name of the plugin for debugging purposes +func (*Plugin) GetName() string { return "java.security Plugin" } -func (JavaSecurityPlugin) GetExplanation() string { +func (*Plugin) GetExplanation() string { return "Verify the executability of cryptographic assets from Java code\nAdds a confidence level (0-100) to the CBOM components to show how likely it is that this component is actually executable" } -// Get the type of the plugin -func (JavaSecurityPlugin) GetType() plugins.PluginType { +// GetType Get the type of the plugin +func (*Plugin) GetType() plugins.PluginType { return plugins.PluginTypeVerify } -// High-level function to update a list of components (e.g. remove components and add new ones) based on the underlying filesystem -func (javaSecurityPlugin *JavaSecurityPlugin) UpdateBOM(fs filesystem.Filesystem, bom *cdx.BOM) error { +// UpdateBOM High-level function to update a list of components +// (e.g., remove components and add new ones) based on the underlying filesystem +func (javaSecurityPlugin *Plugin) UpdateBOM(fs filesystem.Filesystem, bom *cdx.BOM) error { slog.Warn("Current version of CBOMkit-theia does not take dynamic changes of java security properties (e.g. via System.setProperty) into account. Use with caution!") if bom.Components == nil { @@ -78,15 +79,15 @@ func (javaSecurityPlugin *JavaSecurityPlugin) UpdateBOM(fs filesystem.Filesystem slog.Info("Adding java.security config file", "path", path) readCloser, err := fs.Open(path) if err != nil { - return scanner_errors.GetParsingFailedAlthoughCheckedError(err, javaSecurityPlugin.GetName()) + return scannererrors.GetParsingFailedAlthoughCheckedError(err, javaSecurityPlugin.GetName()) } content, err := filesystem.ReadAllClose(readCloser) if err != nil { - return scanner_errors.GetParsingFailedAlthoughCheckedError(err, javaSecurityPlugin.GetName()) + return scannererrors.GetParsingFailedAlthoughCheckedError(err, javaSecurityPlugin.GetName()) } config, err := properties.LoadString(string(content)) if err != nil { - return scanner_errors.GetParsingFailedAlthoughCheckedError(err, javaSecurityPlugin.GetName()) + return scannererrors.GetParsingFailedAlthoughCheckedError(err, javaSecurityPlugin.GetName()) } configurations[path] = config @@ -122,7 +123,7 @@ func (javaSecurityPlugin *JavaSecurityPlugin) UpdateBOM(fs filesystem.Filesystem if comp.CryptoProperties != nil { err := security.updateComponent(i, advancedCompSlice) if err != nil { - if go_errors.Is(err, scanner_errors.ErrInsufficientInformation) { + if goerrors.Is(err, scannererrors.ErrInsufficientInformation) { insufficientInformationErrors = append(insufficientInformationErrors, err) } else { return fmt.Errorf("scanner java: error while updating component %v\n%w", advancedCompSlice.GetByIndex(i).Name, err) @@ -136,9 +137,9 @@ func (javaSecurityPlugin *JavaSecurityPlugin) UpdateBOM(fs filesystem.Filesystem } } - joinedinsufficientInformationErrors := go_errors.Join(insufficientInformationErrors...) - if joinedinsufficientInformationErrors != nil { - slog.Warn("Run finished with insufficient information errors", "errors", go_errors.Join(insufficientInformationErrors...).Error()) + joinedInsufficientInformationErrors := goerrors.Join(insufficientInformationErrors...) + if joinedInsufficientInformationErrors != nil { + slog.Warn("Run finished with insufficient information errors", "errors", goerrors.Join(insufficientInformationErrors...).Error()) } *bom.Components = advancedCompSlice.GetComponentSlice() @@ -155,7 +156,7 @@ func chooseFirstConfiguration(configurations map[string]*properties.Properties) return nil } -func (*JavaSecurityPlugin) chooseMostLikelyConfiguration(configurations map[string]*properties.Properties, dockerConfig v1.Config) (chosenProp *properties.Properties) { +func (*Plugin) chooseMostLikelyConfiguration(configurations map[string]*properties.Properties, dockerConfig v1.Config) (chosenProp *properties.Properties) { jdkPath, ok := getJDKPath(dockerConfig) if !ok { return chooseFirstConfiguration(configurations) @@ -203,7 +204,7 @@ func getJDKPathFromEnvironmentVariables(envVariables []string) (value string, ok return "", false } -const LINE_SEPARATOR = "/" +const LineSeparator = "/" func getJDKPathFromRunCommand(dockerConfig v1.Config) (value string, ok bool) { for _, s := range append(dockerConfig.Cmd, dockerConfig.Entrypoint...) { @@ -212,10 +213,10 @@ func getJDKPathFromRunCommand(dockerConfig v1.Config) (value string, ok bool) { fields := strings.Fields(s) if len(fields) > 0 { path := fields[0] - pathList := strings.Split(path, LINE_SEPARATOR) + pathList := strings.Split(path, LineSeparator) for i, pathElement := range pathList { if strings.Contains(pathElement, "jdk") { - return LINE_SEPARATOR + filepath.Join(pathList[:i+1]...), true + return LineSeparator + filepath.Join(pathList[:i+1]...), true } } } diff --git a/scanner/plugins/javasecurity/protocol_restrictions.go b/scanner/plugins/javasecurity/protocol_restrictions.go index db66524..7f78149 100644 --- a/scanner/plugins/javasecurity/protocol_restrictions.go +++ b/scanner/plugins/javasecurity/protocol_restrictions.go @@ -17,7 +17,7 @@ package javasecurity import ( - go_errors "errors" + goerrors "errors" "fmt" "log/slog" "strconv" @@ -25,13 +25,13 @@ import ( advancedcomponentslice "github.com/IBM/cbomkit-theia/scanner/componentwithconfidenceslice" "github.com/IBM/cbomkit-theia/scanner/confidencelevel" - scanner_errors "github.com/IBM/cbomkit-theia/scanner/errors" + scannererrors "github.com/IBM/cbomkit-theia/scanner/errors" cdx "github.com/CycloneDX/cyclonedx-go" ) -// Represents a single restriction on algorithms by the java.security file -type JavaSecurityAlgorithmRestriction struct { +// AlgorithmRestriction Represents a single restriction on algorithms by the java.security file +type AlgorithmRestriction struct { name string keySizeOperator keySizeOperator keySize int @@ -52,18 +52,18 @@ const ( // High-Level function to update a protocol component based on the restriction in the JavaSecurity object // Returns nil if the updateComponent is not allowed -func (javaSecurity *JavaSecurity) updateProtocolComponent(index int, advancedcomponentslice *advancedcomponentslice.ComponentWithConfidenceSlice) error { - if advancedcomponentslice.GetByIndex(index).CryptoProperties.AssetType != cdx.CryptoAssetTypeProtocol { - return fmt.Errorf("scanner java: component of type %v cannot be used in function updateProtocolComponent", advancedcomponentslice.GetByIndex(index).CryptoProperties.AssetType) +func (javaSecurity *JavaSecurity) updateProtocolComponent(index int, advancedComponentSlice *advancedcomponentslice.ComponentWithConfidenceSlice) error { + if advancedComponentSlice.GetByIndex(index).CryptoProperties.AssetType != cdx.CryptoAssetTypeProtocol { + return fmt.Errorf("scanner java: component of type %v cannot be used in function updateProtocolComponent", advancedComponentSlice.GetByIndex(index).CryptoProperties.AssetType) } - slog.Debug("Updating protocol component", "component", advancedcomponentslice.GetByIndex(index).Name) + slog.Debug("Updating protocol component", "component", advancedComponentSlice.GetByIndex(index).Name) - switch advancedcomponentslice.GetByIndex(index).CryptoProperties.ProtocolProperties.Type { + switch advancedComponentSlice.GetByIndex(index).CryptoProperties.ProtocolProperties.Type { case cdx.CryptoProtocolTypeTLS: - for _, cipherSuites := range *advancedcomponentslice.GetByIndex(index).CryptoProperties.ProtocolProperties.CipherSuites { + for _, cipherSuites := range *advancedComponentSlice.GetByIndex(index).CryptoProperties.ProtocolProperties.CipherSuites { // Test the protocol itself - cipherSuiteConfidenceLevel, err := evalAll(&javaSecurity.tlsDisabledAlgorithms, *advancedcomponentslice.GetByIndex(index).Component) + cipherSuiteConfidenceLevel, err := evalAll(&javaSecurity.tlsDisabledAlgorithms, *advancedComponentSlice.GetByIndex(index).Component) if err != nil { return err @@ -71,7 +71,7 @@ func (javaSecurity *JavaSecurity) updateProtocolComponent(index int, advancedcom // Test all algorithms in the protocol for _, algorithmRef := range *cipherSuites.Algorithms { - algo, ok := advancedcomponentslice.GetByRef(algorithmRef) + algo, ok := advancedComponentSlice.GetByRef(algorithmRef) if ok { algoConfidenceLevel, err := evalAll(&javaSecurity.tlsDisabledAlgorithms, *algo.Component) @@ -85,7 +85,7 @@ func (javaSecurity *JavaSecurity) updateProtocolComponent(index int, advancedcom } } - advancedcomponentslice.GetByIndex(index).Confidence.AddSubConfidenceLevel(cipherSuiteConfidenceLevel, false) + advancedComponentSlice.GetByIndex(index).Confidence.AddSubConfidenceLevel(cipherSuiteConfidenceLevel, false) } } @@ -93,14 +93,14 @@ func (javaSecurity *JavaSecurity) updateProtocolComponent(index int, advancedcom } // Evaluates all JavaSecurityAlgorithmRestriction in javaSecurityAlgorithmRestrictions for component -func evalAll(javaSecurityAlgorithmRestrictions *[]JavaSecurityAlgorithmRestriction, component cdx.Component) (confidencelevel.ConfidenceLevel, error) { +func evalAll(javaSecurityAlgorithmRestrictions *[]AlgorithmRestriction, component cdx.Component) (confidencelevel.ConfidenceLevel, error) { confidenceLevel := confidencelevel.New() var insufficientInformationErrors []error for _, javaSecurityAlgorithmRestriction := range *javaSecurityAlgorithmRestrictions { currentConfidenceLevel, err := javaSecurityAlgorithmRestriction.eval(component) if err != nil { - if go_errors.Is(err, scanner_errors.ErrInsufficientInformation) { + if goerrors.Is(err, scannererrors.ErrInsufficientInformation) { insufficientInformationErrors = append(insufficientInformationErrors, err) } else { return *confidenceLevel, err @@ -112,7 +112,7 @@ func evalAll(javaSecurityAlgorithmRestrictions *[]JavaSecurityAlgorithmRestricti // Did we have insufficient information with all restrictions? If so, return this. if len(insufficientInformationErrors) == len(*javaSecurityAlgorithmRestrictions) { - return *confidenceLevel, go_errors.Join(insufficientInformationErrors...) + return *confidenceLevel, goerrors.Join(insufficientInformationErrors...) } else { return *confidenceLevel, nil } @@ -127,7 +127,7 @@ func standardizeString(in string) string { // Follows the [JDK implementation] // // [JDK implementation]: https://github.com/openjdk/jdk/blob/master/src/java.base/share/classes/sun/security/util/DisabledAlgorithmConstraints.java -func (javaSecurityAlgorithmRestriction JavaSecurityAlgorithmRestriction) eval(component cdx.Component) (confidencelevel.ConfidenceLevel, error) { +func (javaSecurityAlgorithmRestriction AlgorithmRestriction) eval(component cdx.Component) (confidencelevel.ConfidenceLevel, error) { slog.Debug("Evaluating component with restriction", "component", component.Name, "restriction_name", javaSecurityAlgorithmRestriction.name, "restriction_operator", javaSecurityAlgorithmRestriction.keySizeOperator, "restriction_value", javaSecurityAlgorithmRestriction.keySize) confidenceLevel := confidencelevel.New() @@ -137,7 +137,7 @@ func (javaSecurityAlgorithmRestriction JavaSecurityAlgorithmRestriction) eval(co return *confidenceLevel, fmt.Errorf("scanner java: cannot evaluate components other than algorithm or protocol for applying restrictions") } - // Format could be: withand + // The Format could be: withand replacer := strings.NewReplacer("with", " ", "and", " ") subAlgorithms := strings.Fields(replacer.Replace(component.Name)) @@ -150,21 +150,21 @@ func (javaSecurityAlgorithmRestriction JavaSecurityAlgorithmRestriction) eval(co restrictionStandardized, subAlgorithmStandardized := standardizeString(javaSecurityAlgorithmRestriction.name), standardizeString(subAlgorithm) if strings.EqualFold(restrictionStandardized, subAlgorithmStandardized) { - confidenceLevel.Modify(confidencelevel.ConfidenceLevelModifierNegativeHigh) + confidenceLevel.Modify(confidencelevel.NegativeHigh) // Is the component a protocol? --> If yes, we do not have anything left to compare if component.CryptoProperties.AssetType == cdx.CryptoAssetTypeProtocol { - confidenceLevel.Modify(confidencelevel.ConfidenceLevelModifierNegativeMedium) + confidenceLevel.Modify(confidencelevel.NegativeMedium) return *confidenceLevel, nil } // There is no need to test further if the component does not provide a keySize if component.CryptoProperties.AlgorithmProperties.ParameterSetIdentifier == "" { if javaSecurityAlgorithmRestriction.keySizeOperator != keySizeOperatorNone { - confidenceLevel.Modify(confidencelevel.ConfidenceLevelModifierPositiveMedium) - return *confidenceLevel, scanner_errors.GetInsufficientInformationError(fmt.Sprintf("missing key size parameter in BOM for rule affecting %v", javaSecurityAlgorithmRestriction.name), "java.security Plugin", "component", component.Name) // We actually need a keySize so we cannot go on here + confidenceLevel.Modify(confidencelevel.PositiveMedium) + return *confidenceLevel, scannererrors.GetInsufficientInformationError(fmt.Sprintf("missing key size parameter in BOM for rule affecting %v", javaSecurityAlgorithmRestriction.name), "java.security Plugin", "component", component.Name) // We actually need a keySize so we cannot go on here } else { - confidenceLevel.Modify(confidencelevel.ConfidenceLevelModifierNegativeHigh) + confidenceLevel.Modify(confidencelevel.NegativeHigh) return *confidenceLevel, nil // Names match and we do not need a keySize --> The algorithm is not allowed! } } @@ -176,7 +176,7 @@ func (javaSecurityAlgorithmRestriction JavaSecurityAlgorithmRestriction) eval(co } if param <= 0 || param > 2147483647 { - confidenceLevel.Modify(confidencelevel.ConfidenceLevelModifierNegativeMedium) + confidenceLevel.Modify(confidencelevel.NegativeMedium) return *confidenceLevel, err // Following Java reference implementation (see https://github.com/openjdk/jdk/blob/4f1a10f84bcfadef263a0890b6834ccd3d5bb52f/src/java.base/share/classes/sun/security/util/DisabledAlgorithmConstraints.java#L944 and https://github.com/openjdk/jdk/blob/4f1a10f84bcfadef263a0890b6834ccd3d5bb52f/src/java.base/share/classes/sun/security/util/DisabledAlgorithmConstraints.java#L843) } @@ -197,12 +197,12 @@ func (javaSecurityAlgorithmRestriction JavaSecurityAlgorithmRestriction) eval(co case keySizeOperatorNone: allowed = false default: - confidenceLevel.Modify(confidencelevel.ConfidenceLevelModifierPositiveMedium) + confidenceLevel.Modify(confidencelevel.PositiveMedium) return *confidenceLevel, fmt.Errorf("scanner java: invalid keySizeOperator in JavaSecurityAlgorithmRestriction: %v", javaSecurityAlgorithmRestriction.keySizeOperator) } if !allowed { - confidenceLevel.Modify(confidencelevel.ConfidenceLevelModifierNegativeMedium) + confidenceLevel.Modify(confidencelevel.NegativeMedium) return *confidenceLevel, err } } diff --git a/scanner/plugins/plugin.go b/scanner/plugins/plugin.go index a6f5af0..2b82614 100644 --- a/scanner/plugins/plugin.go +++ b/scanner/plugins/plugin.go @@ -30,7 +30,7 @@ type PluginType int A list of possible plugin types Important: order these in the way you want to run the plugins; -e.g. here the plugins are running in this order: PluginTypeAppend -> PluginTypeVerify -> PluginTypeOther +e.g., here the plugins are running in this order: PluginTypeAppend -> PluginTypeVerify -> PluginTypeOther */ const ( PluginTypeAppend PluginType = iota + 1 @@ -38,7 +38,7 @@ const ( PluginTypeOther ) -// Interface to be implemented by all plugins +// Plugin Interface to be implemented by all plugins type Plugin interface { GetName() string // return a name for the plugin GetExplanation() string // explain the functionality of this plugin @@ -46,7 +46,7 @@ type Plugin interface { UpdateBOM(fs filesystem.Filesystem, bom *cdx.BOM) error // Update BOM using found files } -// This PluginConstructor function should be exposed by all plugin packages +// PluginConstructor should be exposed by all plugin packages type PluginConstructor func() (Plugin, error) func PluginSliceToString(plugins []Plugin) string { diff --git a/scanner/plugins/secrets/secrets.go b/scanner/plugins/secrets/secrets.go index 1ef4115..1966752 100644 --- a/scanner/plugins/secrets/secrets.go +++ b/scanner/plugins/secrets/secrets.go @@ -32,20 +32,20 @@ import ( ) func NewSecretsPlugin() (plugins.Plugin, error) { - return &SecretsPlugin{}, nil + return &Plugin{}, nil } -type SecretsPlugin struct{} +type Plugin struct{} -func (SecretsPlugin) GetName() string { +func (*Plugin) GetName() string { return "Secret Plugin" } -func (SecretsPlugin) GetExplanation() string { +func (*Plugin) GetExplanation() string { return "Find Secrets & Keys" } -func (SecretsPlugin) GetType() plugins.PluginType { +func (*Plugin) GetType() plugins.PluginType { return plugins.PluginTypeAppend } @@ -55,7 +55,7 @@ type findingWithMetadata struct { raw []byte } -func (SecretsPlugin) UpdateBOM(fs filesystem.Filesystem, bom *cdx.BOM) error { +func (*Plugin) UpdateBOM(fs filesystem.Filesystem, bom *cdx.BOM) error { detector, err := detect.NewDetectorDefaultConfig() if err != nil { return err @@ -64,7 +64,7 @@ func (SecretsPlugin) UpdateBOM(fs filesystem.Filesystem, bom *cdx.BOM) error { findings := make([]findingWithMetadata, 0) // Detect findings - fs.WalkDir(func(path string) error { + err = fs.WalkDir(func(path string) error { readCloser, err := fs.Open(path) if err != nil { return err @@ -105,6 +105,10 @@ func (SecretsPlugin) UpdateBOM(fs filesystem.Filesystem, bom *cdx.BOM) error { return nil }) + if err != nil { + return err + } + bomDag := bomdag.NewBomDAG() components := make([]cdx.Component, 0) @@ -124,7 +128,10 @@ func (SecretsPlugin) UpdateBOM(fs filesystem.Filesystem, bom *cdx.BOM) error { if err != nil { return err } - bomDag.AddEdge(bomDag.Root, hash) + err = bomDag.AddEdge(bomDag.Root, hash) + if err != nil { + slog.Error(err.Error()) + } } // DAG to components diff --git a/server/server.go b/server/server.go index 02bbda9..c710f7f 100644 --- a/server/server.go +++ b/server/server.go @@ -48,12 +48,18 @@ func Serve() { gin.SetMode(gin.ReleaseMode) r := gin.Default() r.Use(cors.Default()) // Allow all origins - r.SetTrustedProxies(nil) + err := r.SetTrustedProxies(nil) + if err != nil { + return + } v1 := r.Group("/api/v1") { v1.POST("/image", imageGet) } - r.Run(":8080") // listen and serve on 0.0.0.0:8080 + err = r.Run(":8080") // listen and serve on 0.0.0.0:8080 + if err != nil { + return + } } func imageGet(c *gin.Context) { @@ -105,14 +111,14 @@ func imageGet(c *gin.Context) { } if err = container.Provide(func(input []plugins.PluginConstructor) ([]plugins.Plugin, error) { - plugins := make([]plugins.Plugin, len(input)) + p := make([]plugins.Plugin, len(input)) for i, con := range input { - plugins[i], err = con() + p[i], err = con() if err != nil { - return plugins, err + return p, err } } - return plugins, nil + return p, nil }); err != nil { returnError(c, err) return