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  }