Unify root/material unknown resolution with recursive Input traversal. Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
89 lines
2.7 KiB
Go
89 lines
2.7 KiB
Go
package policy
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/containerd/platforms"
|
|
gwpb "github.com/moby/buildkit/frontend/gateway/pb"
|
|
"github.com/moby/buildkit/solver/pb"
|
|
ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
|
|
"github.com/pkg/errors"
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
const maxMaterialDepth = 24
|
|
|
|
func SourceToInput(ctx context.Context, verifier PolicyVerifierProvider, src *gwpb.ResolveSourceMetaResponse, platform *ocispecs.Platform, logf func(logrus.Level, string)) (Input, error) {
|
|
seen := map[string]struct{}{}
|
|
return sourceToInputRecursive(ctx, verifier, src, platform, 0, seen, logf)
|
|
}
|
|
|
|
func sourceToInputRecursive(ctx context.Context, verifier PolicyVerifierProvider, src *gwpb.ResolveSourceMetaResponse, platform *ocispecs.Platform, depth int, seen map[string]struct{}, logf func(logrus.Level, string)) (Input, error) {
|
|
if depth > maxMaterialDepth {
|
|
return Input{}, errors.Errorf("provenance materials depth exceeds limit %d", maxMaterialDepth)
|
|
}
|
|
if src == nil || src.Source == nil {
|
|
return Input{}, errors.New("source metadata response is required")
|
|
}
|
|
|
|
inp, unknowns, err := sourceToInput(ctx, verifier, src, platform, logf)
|
|
if err != nil {
|
|
return Input{}, err
|
|
}
|
|
inp.setUnknowns(unknowns)
|
|
inp.Env.Depth = depth
|
|
|
|
if inp.Image == nil || inp.Image.Provenance == nil || len(inp.Image.Provenance.materialsRaw) == 0 {
|
|
return inp, nil
|
|
}
|
|
|
|
key := sourceUniqueIdentifier(src.Source, platform)
|
|
if _, ok := seen[key]; ok {
|
|
return Input{}, nil
|
|
}
|
|
seen[key] = struct{}{}
|
|
defer delete(seen, key)
|
|
|
|
materials := make([]Input, 0, len(inp.Image.Provenance.materialsRaw))
|
|
for _, m := range inp.Image.Provenance.materialsRaw {
|
|
matSrc, matPlatform, err := parseSLSAMaterial(m)
|
|
if err != nil {
|
|
materials = append(materials, Input{})
|
|
continue
|
|
}
|
|
if matSrc == nil {
|
|
materials = append(materials, Input{})
|
|
continue
|
|
}
|
|
matResp := &gwpb.ResolveSourceMetaResponse{Source: matSrc}
|
|
child, err := sourceToInputRecursive(ctx, verifier, matResp, firstNonNilPlatform(matPlatform, platform), depth+1, seen, logf)
|
|
if err != nil {
|
|
return Input{}, errors.Wrapf(err, "failed to build material input for %q", m.URI)
|
|
}
|
|
materials = append(materials, child)
|
|
}
|
|
inp.Image.Provenance.Materials = materials
|
|
return inp, nil
|
|
}
|
|
|
|
// sourceUniqueIdentifier is used only for recursive cycle detection safety.
|
|
func sourceUniqueIdentifier(src *pb.SourceOp, platform *ocispecs.Platform) string {
|
|
if src == nil {
|
|
return ""
|
|
}
|
|
key := src.Identifier
|
|
if platform != nil {
|
|
key += "|" + platforms.Format(*platform)
|
|
}
|
|
return key
|
|
}
|
|
|
|
func firstNonNilPlatform(values ...*ocispecs.Platform) *ocispecs.Platform {
|
|
for _, v := range values {
|
|
if v != nil {
|
|
return v
|
|
}
|
|
}
|
|
return nil
|
|
}
|