github.com/hashicorp/packer@v1.14.3/provisioner/hcp-sbom/validate.go (about) 1 package hcp_sbom 2 3 import ( 4 "bytes" 5 "fmt" 6 "strings" 7 8 "github.com/CycloneDX/cyclonedx-go" 9 hcpPackerModels "github.com/hashicorp/hcp-sdk-go/clients/cloud-packer-service/stable/2023-01-01/models" 10 spdxjson "github.com/spdx/tools-golang/json" 11 ) 12 13 // ValidationError represents an error encountered while validating an SBOM. 14 type ValidationError struct { 15 Err error 16 } 17 18 func (e *ValidationError) Error() string { 19 return e.Err.Error() 20 } 21 22 func (e *ValidationError) Unwrap() error { 23 return e.Err 24 } 25 26 // ValidateCycloneDX is a validation for CycloneDX in JSON format. 27 func validateCycloneDX(content []byte) error { 28 decoder := cyclonedx.NewBOMDecoder(bytes.NewBuffer(content), cyclonedx.BOMFileFormatJSON) 29 bom := new(cyclonedx.BOM) 30 if err := decoder.Decode(bom); err != nil { 31 return fmt.Errorf("error parsing CycloneDX SBOM: %w", err) 32 } 33 34 if !strings.EqualFold(bom.BOMFormat, "CycloneDX") { 35 return &ValidationError{ 36 Err: fmt.Errorf("invalid bomFormat: %q, expected CycloneDX", bom.BOMFormat), 37 } 38 } 39 if bom.SpecVersion.String() == "" { 40 return &ValidationError{ 41 Err: fmt.Errorf("specVersion is required"), 42 } 43 } 44 45 return nil 46 } 47 48 // validateSPDX is a validation for SPDX in JSON format. 49 func validateSPDX(content []byte) error { 50 doc, err := spdxjson.Read(bytes.NewBuffer(content)) 51 if err != nil { 52 return fmt.Errorf("error parsing SPDX JSON file: %w", err) 53 } 54 55 if doc.SPDXVersion == "" { 56 return &ValidationError{ 57 Err: fmt.Errorf("missing SPDXVersion"), 58 } 59 } 60 61 return nil 62 } 63 64 // validateSBOM validates the SBOM file and returns the format of the SBOM. 65 func validateSBOM(content []byte) (hcpPackerModels.HashicorpCloudPacker20230101SbomFormat, error) { 66 // Try validating as SPDX 67 spdxErr := validateSPDX(content) 68 if spdxErr == nil { 69 return hcpPackerModels.HashicorpCloudPacker20230101SbomFormatSPDX, nil 70 } 71 72 if vErr, ok := spdxErr.(*ValidationError); ok { 73 return "", vErr 74 } 75 76 cycloneDxErr := validateCycloneDX(content) 77 if cycloneDxErr == nil { 78 return hcpPackerModels.HashicorpCloudPacker20230101SbomFormatCYCLONEDX, nil 79 } 80 81 if vErr, ok := cycloneDxErr.(*ValidationError); ok { 82 return "", vErr 83 } 84 85 return "", fmt.Errorf("error validating SBOM file: invalid SBOM format") 86 }