vendor: github.com/moby/buildkit v0.12.1-0.20230717122532-faa0cc7da353

full diff:

- https://github.com/moby/buildkit/compare/20230620112432...v0.12.0
- https://github.com/moby/buildkit/compare/v0.12.0...faa0cc7da3536923d85b74b2bb2d13c12a6ecc99

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
Sebastiaan van Stijn
2023-07-17 10:49:00 +02:00
parent 2666bd6996
commit 130bbda00e
65 changed files with 5389 additions and 256 deletions

161
vendor/github.com/moby/buildkit/sourcepolicy/engine.go generated vendored Normal file
View File

@ -0,0 +1,161 @@
package sourcepolicy
import (
"context"
"github.com/moby/buildkit/solver/pb"
spb "github.com/moby/buildkit/sourcepolicy/pb"
"github.com/moby/buildkit/util/bklog"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
var (
// ErrSourceDenied is returned by the policy engine when a source is denied by the policy.
ErrSourceDenied = errors.New("source denied by policy")
// ErrTooManyOps is returned by the policy engine when there are too many converts for a single source op.
ErrTooManyOps = errors.New("too many operations")
)
// Engine is the source policy engine.
// It is responsible for evaluating a source policy against a source operation.
// Create one with `NewEngine`
//
// Rule matching is delegated to the `Matcher` interface.
// Mutations are delegated to the `Mutater` interface.
type Engine struct {
pol []*spb.Policy
sources map[string]*selectorCache
}
// NewEngine creates a new source policy engine.
func NewEngine(pol []*spb.Policy) *Engine {
return &Engine{
pol: pol,
}
}
// TODO: The key here can't be used to cache attr constraint regexes.
func (e *Engine) selectorCache(src *spb.Selector) *selectorCache {
if e.sources == nil {
e.sources = map[string]*selectorCache{}
}
key := src.MatchType.String() + " " + src.Identifier
if s, ok := e.sources[key]; ok {
return s
}
s := &selectorCache{Selector: src}
e.sources[key] = s
return s
}
// Evaluate evaluates a source operation against the policy.
//
// Policies are re-evaluated for each convert rule.
// Evaluate will error if the there are too many converts for a single source op to prevent infinite loops.
// This function may error out even if the op was mutated, in which case `true` will be returned along with the error.
//
// An error is returned when the source is denied by the policy.
func (e *Engine) Evaluate(ctx context.Context, op *pb.Op) (bool, error) {
if len(e.pol) == 0 {
return false, nil
}
var mutated bool
const maxIterr = 20
for i := 0; ; i++ {
if i > maxIterr {
return mutated, errors.Wrapf(ErrTooManyOps, "too many mutations on a single source")
}
srcOp := op.GetSource()
if srcOp == nil {
return false, nil
}
if i == 0 {
ctx = bklog.WithLogger(ctx, bklog.G(ctx).WithField("orig", *srcOp).WithField("updated", op.GetSource()))
}
mut, err := e.evaluatePolicies(ctx, srcOp)
if mut {
mutated = true
}
if err != nil {
return mutated, err
}
if !mut {
break
}
}
return mutated, nil
}
func (e *Engine) evaluatePolicies(ctx context.Context, srcOp *pb.SourceOp) (bool, error) {
for _, pol := range e.pol {
mut, err := e.evaluatePolicy(ctx, pol, srcOp)
if mut || err != nil {
return mut, err
}
}
return false, nil
}
// evaluatePolicy evaluates a single policy against a source operation.
// If the source is mutated the policy is short-circuited and `true` is returned.
// If the source is denied, an error will be returned.
//
// For Allow/Deny rules, the last matching rule wins.
// E.g. `ALLOW foo; DENY foo` will deny `foo`, `DENY foo; ALLOW foo` will allow `foo`.
func (e *Engine) evaluatePolicy(ctx context.Context, pol *spb.Policy, srcOp *pb.SourceOp) (retMut bool, retErr error) {
ident := srcOp.GetIdentifier()
ctx = bklog.WithLogger(ctx, bklog.G(ctx).WithField("ref", ident))
defer func() {
if retMut || retErr != nil {
bklog.G(ctx).WithFields(
logrus.Fields{
"mutated": retMut,
"updated": srcOp.GetIdentifier(),
logrus.ErrorKey: retErr,
}).Debug("Evaluated source policy")
}
}()
var deny bool
for _, rule := range pol.Rules {
selector := e.selectorCache(rule.Selector)
matched, err := match(ctx, selector, ident, srcOp.Attrs)
if err != nil {
return false, errors.Wrap(err, "error matching source policy")
}
if !matched {
continue
}
switch rule.Action {
case spb.PolicyAction_ALLOW:
deny = false
case spb.PolicyAction_DENY:
deny = true
case spb.PolicyAction_CONVERT:
mut, err := mutate(ctx, srcOp, rule, selector, ident)
if err != nil || mut {
return mut, errors.Wrap(err, "error mutating source policy")
}
default:
return false, errors.Errorf("source policy: rule %s %s: unknown type %q", rule.Action, rule.Selector.Identifier, ident)
}
}
if deny {
return false, errors.Wrapf(ErrSourceDenied, "source %q denied by policy", ident)
}
return false, nil
}

View File

@ -0,0 +1,92 @@
package sourcepolicy
import (
"regexp"
spb "github.com/moby/buildkit/sourcepolicy/pb"
"github.com/moby/buildkit/util/wildcard"
"github.com/pkg/errors"
)
// Source wraps a a protobuf source in order to store cached state such as the compiled regexes.
type selectorCache struct {
*spb.Selector
re *regexp.Regexp
w *wildcardCache
}
// Format formats the provided ref according to the match/type of the source.
//
// For example, if the source is a wildcard, the ref will be formatted with the wildcard in the source replacing the parameters in the destination.
//
// matcher: wildcard source: "docker.io/library/golang:*" match: "docker.io/library/golang:1.19" format: "docker.io/library/golang:${1}-alpine" result: "docker.io/library/golang:1.19-alpine"
func (s *selectorCache) Format(match, format string) (string, error) {
switch s.MatchType {
case spb.MatchType_EXACT:
return s.Identifier, nil
case spb.MatchType_REGEX:
re, err := s.regex()
if err != nil {
return "", err
}
return re.ReplaceAllString(match, format), nil
case spb.MatchType_WILDCARD:
w, err := s.wildcard()
if err != nil {
return "", err
}
m := w.Match(match)
if m == nil {
return match, nil
}
return m.Format(format)
}
return "", errors.Errorf("unknown match type: %s", s.MatchType)
}
// wildcardCache wraps a wildcard.Wildcard to cache returned matches by ref.
// This way a match only needs to be computed once per ref.
type wildcardCache struct {
w *wildcard.Wildcard
m map[string]*wildcard.Match
}
func (w *wildcardCache) Match(ref string) *wildcard.Match {
if w.m == nil {
w.m = make(map[string]*wildcard.Match)
}
if m, ok := w.m[ref]; ok {
return m
}
m := w.w.Match(ref)
w.m[ref] = m
return m
}
func (s *selectorCache) wildcard() (*wildcardCache, error) {
if s.w != nil {
return s.w, nil
}
w, err := wildcard.New(s.Identifier)
if err != nil {
return nil, err
}
s.w = &wildcardCache{w: w}
return s.w, nil
}
func (s *selectorCache) regex() (*regexp.Regexp, error) {
if s.re != nil {
return s.re, nil
}
re, err := regexp.Compile(s.Identifier)
if err != nil {
return nil, err
}
s.re = re
return re, nil
}

View File

@ -0,0 +1,58 @@
package sourcepolicy
import (
"context"
"regexp"
spb "github.com/moby/buildkit/sourcepolicy/pb"
"github.com/pkg/errors"
)
func match(ctx context.Context, src *selectorCache, ref string, attrs map[string]string) (bool, error) {
for _, c := range src.Constraints {
switch c.Condition {
case spb.AttrMatch_EQUAL:
if attrs[c.Key] != c.Value {
return false, nil
}
case spb.AttrMatch_NOTEQUAL:
if attrs[c.Key] == c.Value {
return false, nil
}
case spb.AttrMatch_MATCHES:
// TODO: Cache the compiled regex
matches, err := regexp.MatchString(c.Value, attrs[c.Key])
if err != nil {
return false, errors.Errorf("invalid regex %q: %v", c.Value, err)
}
if !matches {
return false, nil
}
default:
return false, errors.Errorf("unknown attr condition: %s", c.Condition)
}
}
if src.Identifier == ref {
return true, nil
}
switch src.MatchType {
case spb.MatchType_EXACT:
return false, nil
case spb.MatchType_REGEX:
re, err := src.regex()
if err != nil {
return false, err
}
return re.MatchString(ref), nil
case spb.MatchType_WILDCARD:
w, err := src.wildcard()
if err != nil {
return false, err
}
return w.Match(ref) != nil, nil
default:
return false, errors.Errorf("unknown match type: %s", src.MatchType)
}
}

50
vendor/github.com/moby/buildkit/sourcepolicy/mutate.go generated vendored Normal file
View File

@ -0,0 +1,50 @@
package sourcepolicy
import (
"context"
"github.com/moby/buildkit/solver/pb"
spb "github.com/moby/buildkit/sourcepolicy/pb"
"github.com/moby/buildkit/util/bklog"
"github.com/pkg/errors"
)
// mutate is a MutateFn which converts the source operation to the identifier and attributes provided by the policy.
// If there is no change, then the return value should be false and is not considered an error.
func mutate(ctx context.Context, op *pb.SourceOp, rule *spb.Rule, selector *selectorCache, ref string) (bool, error) {
if rule.Updates == nil {
return false, errors.Errorf("missing destination for convert rule")
}
dest := rule.Updates.Identifier
if dest == "" {
dest = rule.Selector.Identifier
}
dest, err := selector.Format(ref, dest)
if err != nil {
return false, errors.Wrap(err, "error formatting destination")
}
bklog.G(ctx).Debugf("sourcepolicy: converting %s to %s, pattern: %s", ref, dest, rule.Updates.Identifier)
var mutated bool
if op.Identifier != dest && dest != "" {
mutated = true
op.Identifier = dest
}
if rule.Updates.Attrs != nil {
if op.Attrs == nil {
op.Attrs = make(map[string]string, len(rule.Updates.Attrs))
}
for k, v := range rule.Updates.Attrs {
if op.Attrs[k] != v {
bklog.G(ctx).Debugf("setting attr %s=%s", k, v)
op.Attrs[k] = v
mutated = true
}
}
}
return mutated, nil
}