Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Builder should warn if newer buildpacks write a bom in *.toml #728

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 96 additions & 0 deletions buildpack/bom.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package buildpack

import (
"errors"
"fmt"

"github.com/buildpacks/lifecycle/api"
)

type BOMValidator interface {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't look like it's used outside the package, so the public scope is slightly confusing.

ValidateBOM(GroupBuildpack, []BOMEntry) ([]BOMEntry, error)
}

func NewBOMValidator(bpAPI string, logger Logger) BOMValidator {
switch {
case api.MustParse(bpAPI).LessThan("0.5"):
return &legacyBOMValidator{}
case api.MustParse(bpAPI).LessThan("0.7"):
return &v05To06BOMValidator{}
default:
return &defaultBOMValidator{logger: logger}
}
}

type defaultBOMValidator struct {
logger Logger
}

func (h *defaultBOMValidator) ValidateBOM(bp GroupBuildpack, bom []BOMEntry) ([]BOMEntry, error) {
if err := h.validateBOM(bom); err != nil {
return []BOMEntry{}, err
}
return h.processBOM(bp, bom), nil
}

func (h *defaultBOMValidator) validateBOM(bom []BOMEntry) error {
if len(bom) > 0 {
h.logger.Warn("BOM table isn't supported in this buildpack api version. The BOM should be written to <layer>.bom.<ext>, launch.bom.<ext>, or build.bom.<ext>.")
}
return nil
}

func (h *defaultBOMValidator) processBOM(_ GroupBuildpack, _ []BOMEntry) []BOMEntry {
return []BOMEntry{}
}

type v05To06BOMValidator struct{}

func (h *v05To06BOMValidator) ValidateBOM(bp GroupBuildpack, bom []BOMEntry) ([]BOMEntry, error) {
if err := h.validateBOM(bom); err != nil {
return []BOMEntry{}, err
}
return h.processBOM(bp, bom), nil
}

func (h *v05To06BOMValidator) validateBOM(bom []BOMEntry) error {
for _, entry := range bom {
if entry.Version != "" {
return fmt.Errorf("bom entry '%s' has a top level version which is not allowed. The buildpack should instead set metadata.version", entry.Name)
}
}
return nil
}

func (h *v05To06BOMValidator) processBOM(buildpack GroupBuildpack, bom []BOMEntry) []BOMEntry {
return WithBuildpack(buildpack, bom)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this method wasn't created in this PR. But I'm surprised that it actually does anything

https://play.golang.org/p/DyhbKkAp2eW

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one's totally my bad. I just tested it out and it works fine.

}

type legacyBOMValidator struct{}

func (h *legacyBOMValidator) ValidateBOM(bp GroupBuildpack, bom []BOMEntry) ([]BOMEntry, error) {
if err := h.validateBOM(bom); err != nil {
return []BOMEntry{}, err
}
return h.processBOM(bp, bom), nil
}

func (h *legacyBOMValidator) validateBOM(bom []BOMEntry) error {
for _, entry := range bom {
if version, ok := entry.Metadata["version"]; ok {
metadataVersion := fmt.Sprintf("%v", version)
if entry.Version != "" && entry.Version != metadataVersion {
return errors.New("top level version does not match metadata version")
}
}
}
return nil
}

func (h *legacyBOMValidator) processBOM(buildpack GroupBuildpack, bom []BOMEntry) []BOMEntry {
bom = WithBuildpack(buildpack, bom)
for i := range bom {
bom[i].convertVersionToMetadata()
}
return bom
}
36 changes: 8 additions & 28 deletions buildpack/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,9 @@ func (b *Descriptor) readOutputFiles(bpLayersDir, bpPlanPath string, bpPlanIn Pl
var launchTOML LaunchTOML
launchPath := filepath.Join(bpLayersDir, "launch.toml")

bomValidator := NewBOMValidator(b.API, logger)

var err error
Copy link
Contributor

@aemengo aemengo Oct 12, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if necessary. (var err error)

if api.MustParse(b.API).LessThan("0.5") {
// read buildpack plan
var bpPlanOut Plan
Expand All @@ -257,13 +260,10 @@ func (b *Descriptor) readOutputFiles(bpLayersDir, bpPlanPath string, bpPlanIn Pl
}

// set BOM and MetRequires
if err := validateBOM(bpPlanOut.toBOM(), b.API); err != nil {
br.BOM, err = bomValidator.ValidateBOM(bpFromBpInfo, bpPlanOut.toBOM())
if err != nil {
return BuildResult{}, err
}
br.BOM = WithBuildpack(bpFromBpInfo, bpPlanOut.toBOM())
for i := range br.BOM {
br.BOM[i].convertVersionToMetadata()
}
br.MetRequires = names(bpPlanOut.Entries)

// read launch.toml, return if not exists
Expand All @@ -279,7 +279,7 @@ func (b *Descriptor) readOutputFiles(bpLayersDir, bpPlanPath string, bpPlanIn Pl
if _, err := toml.DecodeFile(buildPath, &bpBuild); err != nil && !os.IsNotExist(err) {
return BuildResult{}, err
}
if err := validateBOM(bpBuild.BOM, b.API); err != nil {
if _, err := bomValidator.ValidateBOM(bpFromBpInfo, bpBuild.BOM); err != nil {
return BuildResult{}, err
}

Expand All @@ -297,10 +297,10 @@ func (b *Descriptor) readOutputFiles(bpLayersDir, bpPlanPath string, bpPlanIn Pl
}

// set BOM
if err := validateBOM(launchTOML.BOM, b.API); err != nil {
br.BOM, err = bomValidator.ValidateBOM(bpFromBpInfo, launchTOML.BOM)
if err != nil {
return BuildResult{}, err
}
br.BOM = WithBuildpack(bpFromBpInfo, launchTOML.BOM)
}

if err := overrideDefaultForOldBuildpacks(launchTOML.Processes, b.API, logger); err != nil {
Expand Down Expand Up @@ -352,26 +352,6 @@ func validateNoMultipleDefaults(processes []launch.Process) error {
return nil
}

func validateBOM(bom []BOMEntry, bpAPI string) error {
if api.MustParse(bpAPI).LessThan("0.5") {
for _, entry := range bom {
if version, ok := entry.Metadata["version"]; ok {
metadataVersion := fmt.Sprintf("%v", version)
if entry.Version != "" && entry.Version != metadataVersion {
return errors.New("top level version does not match metadata version")
}
}
}
} else {
for _, entry := range bom {
if entry.Version != "" {
return fmt.Errorf("bom entry '%s' has a top level version which is not allowed. The buildpack should instead set metadata.version", entry.Name)
}
}
}
return nil
}

func validateUnmet(unmet []Unmet, bpPlan Plan) error {
for _, unmet := range unmet {
if unmet.Name == "" {
Expand Down
Loading