mirror of
https://github.com/hashicorp/packer.git
synced 2026-09-21 23:41:41 -04:00
Since the protos for uploading an SBOM for a build have been changed to use an enumeration instead of a plain string with the latest revisions to the HCP Packer SBOM support feature, we update how we reference those values for the SBOM format to use that enum instead.
87 lines
2.2 KiB
Go
87 lines
2.2 KiB
Go
package hcp_sbom
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/CycloneDX/cyclonedx-go"
|
|
hcpPackerModels "github.com/hashicorp/hcp-sdk-go/clients/cloud-packer-service/stable/2023-01-01/models"
|
|
spdxjson "github.com/spdx/tools-golang/json"
|
|
)
|
|
|
|
// ValidationError represents an error encountered while validating an SBOM.
|
|
type ValidationError struct {
|
|
Err error
|
|
}
|
|
|
|
func (e *ValidationError) Error() string {
|
|
return e.Err.Error()
|
|
}
|
|
|
|
func (e *ValidationError) Unwrap() error {
|
|
return e.Err
|
|
}
|
|
|
|
// ValidateCycloneDX is a validation for CycloneDX in JSON format.
|
|
func validateCycloneDX(content []byte) error {
|
|
decoder := cyclonedx.NewBOMDecoder(bytes.NewBuffer(content), cyclonedx.BOMFileFormatJSON)
|
|
bom := new(cyclonedx.BOM)
|
|
if err := decoder.Decode(bom); err != nil {
|
|
return fmt.Errorf("error parsing CycloneDX SBOM: %w", err)
|
|
}
|
|
|
|
if !strings.EqualFold(bom.BOMFormat, "CycloneDX") {
|
|
return &ValidationError{
|
|
Err: fmt.Errorf("invalid bomFormat: %q, expected CycloneDX", bom.BOMFormat),
|
|
}
|
|
}
|
|
if bom.SpecVersion.String() == "" {
|
|
return &ValidationError{
|
|
Err: fmt.Errorf("specVersion is required"),
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// validateSPDX is a validation for SPDX in JSON format.
|
|
func validateSPDX(content []byte) error {
|
|
doc, err := spdxjson.Read(bytes.NewBuffer(content))
|
|
if err != nil {
|
|
return fmt.Errorf("error parsing SPDX JSON file: %w", err)
|
|
}
|
|
|
|
if doc.SPDXVersion == "" {
|
|
return &ValidationError{
|
|
Err: fmt.Errorf("missing SPDXVersion"),
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// validateSBOM validates the SBOM file and returns the format of the SBOM.
|
|
func validateSBOM(content []byte) (hcpPackerModels.HashicorpCloudPacker20230101SbomFormat, error) {
|
|
// Try validating as SPDX
|
|
spdxErr := validateSPDX(content)
|
|
if spdxErr == nil {
|
|
return hcpPackerModels.HashicorpCloudPacker20230101SbomFormatSPDX, nil
|
|
}
|
|
|
|
if vErr, ok := spdxErr.(*ValidationError); ok {
|
|
return "", vErr
|
|
}
|
|
|
|
cycloneDxErr := validateCycloneDX(content)
|
|
if cycloneDxErr == nil {
|
|
return hcpPackerModels.HashicorpCloudPacker20230101SbomFormatCYCLONEDX, nil
|
|
}
|
|
|
|
if vErr, ok := cycloneDxErr.(*ValidationError); ok {
|
|
return "", vErr
|
|
}
|
|
|
|
return "", fmt.Errorf("error validating SBOM file: invalid SBOM format")
|
|
}
|