Skip to content

Commit

Permalink
Merge pull request #194 from depot/feat/sbom-stable-digest
Browse files Browse the repository at this point in the history
refactor(sbom): use flattened SBOM structure
  • Loading branch information
goller authored Sep 21, 2023
2 parents 6d377ee + 0792c77 commit b13745d
Showing 1 changed file with 38 additions and 16 deletions.
54 changes: 38 additions & 16 deletions pkg/sbom/sbom.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package sbom

import (
"bytes"
"encoding/base64"
"encoding/json"
"fmt"
Expand All @@ -11,10 +12,6 @@ import (
depotbuild "github.com/depot/cli/pkg/buildx/build"
)

const SBOMsLabel = "depot/sboms"

type SBOMs map[string][]byte

func Save(outputDir string, resp []depotbuild.DepotBuildResponse) error {
err := os.MkdirAll(outputDir, 0750)
if err != nil {
Expand All @@ -35,8 +32,8 @@ func Save(outputDir string, resp []depotbuild.DepotBuildResponse) error {
}

numPlatforms := len(sboms)
for platform, sbom := range sboms {
platform = strings.ReplaceAll(platform, "/", "_")
for _, sbom := range sboms {
platform := strings.ReplaceAll(sbom.Platform, "/", "_")
var name string
if numBuilds == 1 && numPlatforms == 1 {
name = "sbom.spdx.json"
Expand All @@ -48,7 +45,7 @@ func Save(outputDir string, resp []depotbuild.DepotBuildResponse) error {
name = fmt.Sprintf("%s_%s.spdx.json", buildName, platform)
}
pathName := path.Join(outputDir, name)
err := os.WriteFile(pathName, sbom, 0644)
err := os.WriteFile(pathName, sbom.Statement, 0644)
if err != nil {
return err
}
Expand All @@ -59,21 +56,46 @@ func Save(outputDir string, resp []depotbuild.DepotBuildResponse) error {
return nil
}

func DecodeNodeResponses(nodeRes depotbuild.DepotNodeResponse) (SBOMs, error) {
sboms := map[string][]byte{}
// SBOMsLabel is the key for the SBOM attestation.
const SBOMsLabel = "depot/sboms"

type SBOM struct {
// Statement is the spdx.json SBOM scanning output.
Statement []byte `json:"statement"`
// Platform is the specific platform that was scanned.
Platform string `json:"platform"`
// If an image was created this is the image name and digest of the scanned SBOM.
Image *ImageSBOM `json:"image"`
}

// ImageSBOM describes an image that is described by an SBOM.
type ImageSBOM struct {
// Name is the image name and tag.
Name string `json:"name"`
// ManifestDigest is the digest of the manifest and can be used
// to pull the image such as:
// docker pull goller/xmarks@sha256:6839c1808eab334a9b0f400f119773a0a7d494631c083aef6d3447e3798b544f
ManifestDigest string `json:"manifest_digest"`
}

// DecodeNodeResponses decodes the SBOMs from the node responses. If the
// response does not have SBOMs, nil is returned.
func DecodeNodeResponses(nodeRes depotbuild.DepotNodeResponse) ([]SBOM, error) {
encodedSBOMs, ok := nodeRes.SolveResponse.ExporterResponse[SBOMsLabel]
if !ok {
return sboms, nil
return nil, nil
}

jsonSBOMs, err := base64.StdEncoding.DecodeString(encodedSBOMs)
sboms, err := DecodeSBOMs(encodedSBOMs)
if err != nil {
return nil, fmt.Errorf("invalid exported images encoding: %w", err)
}

if err := json.Unmarshal(jsonSBOMs, &sboms); err != nil {
return nil, fmt.Errorf("invalid exported images json: %w", err)
}

return sboms, nil
}

func DecodeSBOMs(encodedSBOMs string) ([]SBOM, error) {
b64 := base64.NewDecoder(base64.StdEncoding, bytes.NewBufferString(encodedSBOMs))
var sboms []SBOM
err := json.NewDecoder(b64).Decode(&sboms)
return sboms, err
}

0 comments on commit b13745d

Please sign in to comment.