-
Notifications
You must be signed in to change notification settings - Fork 111
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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 { | ||
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) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure if necessary. ( |
||
if api.MustParse(b.API).LessThan("0.5") { | ||
// read buildpack plan | ||
var bpPlanOut Plan | ||
|
@@ -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 | ||
|
@@ -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 | ||
} | ||
|
||
|
@@ -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 { | ||
|
@@ -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 == "" { | ||
|
There was a problem hiding this comment.
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.