github.com/Racer159/jackal@v0.32.7-0.20240401174413-0bd2339e4f2e/src/pkg/layout/sbom.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // SPDX-FileCopyrightText: 2021-Present The Jackal Authors 3 4 // Package layout contains functions for interacting with Jackal's package layout on disk. 5 package layout 6 7 import ( 8 "fmt" 9 "io/fs" 10 "os" 11 "path/filepath" 12 13 "github.com/defenseunicorns/pkg/helpers" 14 "github.com/mholt/archiver/v3" 15 ) 16 17 // ComponentSBOM contains paths for a component's SBOM. 18 type ComponentSBOM struct { 19 Files []string 20 Component *ComponentPaths 21 } 22 23 // SBOMs contains paths for SBOMs. 24 type SBOMs struct { 25 Path string 26 } 27 28 // Unarchive unarchives the package's SBOMs. 29 func (s *SBOMs) Unarchive() (err error) { 30 if s.Path == "" || helpers.InvalidPath(s.Path) { 31 return &fs.PathError{ 32 Op: "stat", 33 Path: s.Path, 34 Err: fs.ErrNotExist, 35 } 36 } 37 if helpers.IsDir(s.Path) { 38 return nil 39 } 40 tb := s.Path 41 dir := filepath.Join(filepath.Dir(tb), SBOMDir) 42 if err := archiver.Unarchive(tb, dir); err != nil { 43 return err 44 } 45 s.Path = dir 46 return os.Remove(tb) 47 } 48 49 // Archive archives the package's SBOMs. 50 func (s *SBOMs) Archive() (err error) { 51 if s.Path == "" || helpers.InvalidPath(s.Path) { 52 return &fs.PathError{ 53 Op: "stat", 54 Path: s.Path, 55 Err: fs.ErrNotExist, 56 } 57 } 58 if !helpers.IsDir(s.Path) { 59 return nil 60 } 61 dir := s.Path 62 tb := filepath.Join(filepath.Dir(dir), SBOMTar) 63 64 if err := helpers.CreateReproducibleTarballFromDir(dir, "", tb); err != nil { 65 return err 66 } 67 s.Path = tb 68 return os.RemoveAll(dir) 69 } 70 71 // StageSBOMViewFiles copies SBOM viewer HTML files to the Jackal SBOM directory. 72 func (s *SBOMs) StageSBOMViewFiles() (sbomViewFiles, warnings []string, err error) { 73 if s.IsTarball() { 74 return nil, nil, fmt.Errorf("unable to process the SBOM files for this package: %s is a tarball", s.Path) 75 } 76 77 // If SBOMs were loaded, temporarily place them in the deploy directory 78 if !helpers.InvalidPath(s.Path) { 79 sbomViewFiles, err = filepath.Glob(filepath.Join(s.Path, "sbom-viewer-*")) 80 if err != nil { 81 return nil, nil, err 82 } 83 84 if _, err := s.OutputSBOMFiles(SBOMDir, ""); err != nil { 85 // Don't stop the deployment, let the user decide if they want to continue the deployment 86 warning := fmt.Sprintf("Unable to process the SBOM files for this package: %s", err.Error()) 87 warnings = append(warnings, warning) 88 } 89 } 90 91 return sbomViewFiles, warnings, nil 92 } 93 94 // OutputSBOMFiles outputs SBOM files into outputDir. 95 func (s *SBOMs) OutputSBOMFiles(outputDir, packageName string) (string, error) { 96 packagePath := filepath.Join(outputDir, packageName) 97 98 if err := os.RemoveAll(packagePath); err != nil { 99 return "", err 100 } 101 102 if err := helpers.CreateDirectory(packagePath, 0700); err != nil { 103 return "", err 104 } 105 106 return packagePath, helpers.CreatePathAndCopy(s.Path, packagePath) 107 } 108 109 // IsTarball returns true if the SBOMs are a tarball. 110 func (s SBOMs) IsTarball() bool { 111 return !helpers.IsDir(s.Path) && filepath.Ext(s.Path) == ".tar" 112 }