Skip to content

Commit

Permalink
Generate sboms using new sbom object
Browse files Browse the repository at this point in the history
The build context will now generate the sboms using the new sbom package

Signed-off-by: Adolfo García Veytia (Puerco) <[email protected]>
  • Loading branch information
puerco committed Mar 9, 2022
1 parent a853c97 commit 81a06b6
Showing 1 changed file with 12 additions and 113 deletions.
125 changes: 12 additions & 113 deletions pkg/build/sbom.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,131 +15,30 @@
package build

import (
"encoding/json"
"fmt"
"log"
"os"
"path/filepath"
"strings"

"chainguard.dev/apko/pkg/sbom/cyclonedx"
osr "github.com/dominodatalab/os-release"
"gitlab.alpinelinux.org/alpine/go/pkg/repository"
"chainguard.dev/apko/pkg/sbom"
)

func bomRef(ns string, pkg *repository.Package) string {
return fmt.Sprintf("pkg:apk/%s/%s", ns, pkg.Name)
}

func bomPurl(ns string, pkg *repository.Package) string {
return fmt.Sprintf("pkg:apk/%s/%s@%s", ns, pkg.Name, pkg.Version)
}

// GenerateSBOM runs the sbom generation
func (bc *Context) GenerateSBOM() error {
log.Printf("generating SBOM")

installedDB, err := os.Open(filepath.Join(bc.WorkDir, "lib", "apk", "db", "installed"))
if err != nil {
return fmt.Errorf("unable to open APK installed db: %w", err)
}
defer installedDB.Close()
// TODO(puerco): Split GenerateSBOM into context implementation
s := sbom.NewWithWorkDir(bc.WorkDir)

// repository.ParsePackageIndex closes the file itself
packages, err := repository.ParsePackageIndex(installedDB)
// Generate the packages externally as we may
// move the package reader somewhere else
packages, err := s.ReadPackageIndex()
if err != nil {
return fmt.Errorf("unable to parse APK installed db: %w", err)
}

// TODO(kaniini): figure out something better to do than this
osName := "Alpine Linux"
osID := "alpine"
osVersion := "Unknown"

osReleaseData, err := os.ReadFile(filepath.Join(bc.WorkDir, "etc", "os-release"))
if err == nil {
info := osr.Parse(string(osReleaseData))

osName = info.Name
osID = info.ID
osVersion = info.VersionID
return fmt.Errorf("getting installed packagesx from sbom: %w", err)
}
s.Options.OutputDir = bc.SBOMPath
s.Options.Packages = packages

pkgComponents := []cyclonedx.Component{}
pkgDependencies := []cyclonedx.Dependency{}

for _, pkg := range packages {
// add the component
c := cyclonedx.Component{
BOMRef: bomRef(osID, pkg),
Name: pkg.Name,
Version: pkg.Version,
Description: pkg.Description,
Licenses: []cyclonedx.License{
{
Expression: pkg.License,
},
},
PUrl: bomPurl(osID, pkg),
// TODO(kaniini): Talk with CycloneDX people about adding "package" type.
Type: "operating-system",
}

pkgComponents = append(pkgComponents, c)

// walk the dependency list
depRefs := []string{}
for _, dep := range pkg.Dependencies {
// TODO(kaniini): Properly handle virtual dependencies...
if strings.ContainsRune(dep, ':') {
continue
}

i := strings.IndexAny(dep, " ~<>=/!")
if i > -1 {
dep = dep[:i]
}
if dep == "" {
continue
}

depRefs = append(depRefs, fmt.Sprintf("pkg:apk/%s/%s", osID, dep))
}

d := cyclonedx.Dependency{
Ref: bomRef(osID, pkg),
DependsOn: depRefs,
}
pkgDependencies = append(pkgDependencies, d)
}

rootComponent := cyclonedx.Component{
BOMRef: fmt.Sprintf("pkg:apk/%s", osID),
Name: osName,
Version: osVersion,
Type: "operating-system",
Components: pkgComponents,
}

bom := cyclonedx.Document{
BOMFormat: "CycloneDX",
SpecVersion: "1.4",
Version: 1,
Components: []cyclonedx.Component{rootComponent},
Dependencies: pkgDependencies,
}

out, err := os.Create(bc.SBOMPath)
if err != nil {
return fmt.Errorf("unable to open SBOM path %s for writing: %w", bc.SBOMPath, err)
}
defer out.Close()

enc := json.NewEncoder(out)
enc.SetIndent("", " ")

err = enc.Encode(bom)
if err != nil {
return fmt.Errorf("unable to encode BOM: %w", err)
if _, err := s.Generate(); err != nil {
return fmt.Errorf("generating SBOMs: %w", err)
}

return nil
Expand Down

0 comments on commit 81a06b6

Please sign in to comment.