mirror of
https://github.com/moby/buildkit.git
synced 2025-04-18 18:04:03 +03:00
This does not cover all warning yet but split into chunks to ease review. Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
454 lines
10 KiB
Go
454 lines
10 KiB
Go
package sourcepolicy
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
|
|
"github.com/moby/buildkit/solver/pb"
|
|
spb "github.com/moby/buildkit/sourcepolicy/pb"
|
|
"github.com/moby/buildkit/util/bklog"
|
|
"github.com/sirupsen/logrus"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestEngineEvaluate(t *testing.T) {
|
|
t.Run("Deny All", testDenyAll)
|
|
t.Run("Allow Deny", testAllowDeny)
|
|
t.Run("Convert", testConvert)
|
|
t.Run("Convert Deny", testConvertDeny)
|
|
t.Run("Allow Convert Deny", testAllowConvertDeny)
|
|
t.Run("Test convert loop", testConvertLoop)
|
|
t.Run("Test convert http", testConvertHTTP)
|
|
t.Run("Test convert regex", testConvertRegex)
|
|
t.Run("Test convert wildcard", testConvertWildcard)
|
|
t.Run("Test convert multiple", testConvertMultiple)
|
|
t.Run("test multiple policies", testMultiplePolicies)
|
|
t.Run("Last rule wins", testLastRuleWins)
|
|
}
|
|
|
|
func testLastRuleWins(t *testing.T) {
|
|
pol := []*spb.Policy{
|
|
{
|
|
Rules: []*spb.Rule{
|
|
{
|
|
Action: spb.PolicyAction_ALLOW,
|
|
Selector: &spb.Selector{
|
|
Identifier: "docker-image://docker.io/library/busybox:latest",
|
|
},
|
|
},
|
|
{
|
|
Action: spb.PolicyAction_DENY,
|
|
Selector: &spb.Selector{
|
|
Identifier: "docker-image://docker.io/library/busybox:latest",
|
|
},
|
|
},
|
|
{
|
|
Action: spb.PolicyAction_ALLOW,
|
|
Selector: &spb.Selector{
|
|
Identifier: "docker-image://docker.io/library/busybox:latest",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
e := NewEngine(pol)
|
|
mut, err := e.Evaluate(context.Background(), &pb.SourceOp{
|
|
Identifier: "docker-image://docker.io/library/busybox:latest",
|
|
})
|
|
require.NoError(t, err)
|
|
require.False(t, mut)
|
|
}
|
|
|
|
func testMultiplePolicies(t *testing.T) {
|
|
pol := []*spb.Policy{
|
|
{
|
|
Rules: []*spb.Rule{
|
|
{
|
|
Action: spb.PolicyAction_ALLOW,
|
|
Selector: &spb.Selector{
|
|
Identifier: "docker-image://docker.io/library/busybox:latest",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Rules: []*spb.Rule{
|
|
{
|
|
Action: spb.PolicyAction_DENY,
|
|
Selector: &spb.Selector{
|
|
Identifier: "docker-image://docker.io/library/busybox:latest",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
e := NewEngine(pol)
|
|
mut, err := e.Evaluate(context.Background(), &pb.SourceOp{
|
|
Identifier: "docker-image://docker.io/library/busybox:latest",
|
|
})
|
|
require.ErrorIs(t, err, ErrSourceDenied)
|
|
require.False(t, mut)
|
|
}
|
|
|
|
func testConvertMultiple(t *testing.T) {
|
|
pol := []*spb.Policy{
|
|
{
|
|
Rules: []*spb.Rule{
|
|
{
|
|
Action: spb.PolicyAction_CONVERT,
|
|
Selector: &spb.Selector{
|
|
Identifier: "docker-image://docker.io/library/busybox:latest",
|
|
},
|
|
Updates: &spb.Update{
|
|
Identifier: "docker-image://docker.io/library/alpine:latest",
|
|
},
|
|
},
|
|
{
|
|
Action: spb.PolicyAction_CONVERT,
|
|
Selector: &spb.Selector{
|
|
Identifier: "docker-image://docker.io/library/alpine:latest",
|
|
},
|
|
Updates: &spb.Update{
|
|
Identifier: "docker-image://docker.io/library/debian:buster",
|
|
},
|
|
},
|
|
{
|
|
Action: spb.PolicyAction_CONVERT,
|
|
Selector: &spb.Selector{
|
|
Identifier: "docker-image://docker.io/library/debian:buster",
|
|
},
|
|
Updates: &spb.Update{
|
|
Identifier: "docker-image://docker.io/library/debian:bullseye",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
op := &pb.SourceOp{
|
|
Identifier: "docker-image://docker.io/library/busybox:latest",
|
|
}
|
|
|
|
ctx := context.Background()
|
|
e := NewEngine(pol)
|
|
|
|
mutated, err := e.Evaluate(ctx, op)
|
|
require.True(t, mutated)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func testConvertWildcard(t *testing.T) {
|
|
pol := []*spb.Policy{
|
|
{
|
|
Rules: []*spb.Rule{
|
|
{
|
|
Action: spb.PolicyAction_CONVERT,
|
|
Selector: &spb.Selector{
|
|
Identifier: "docker-image://docker.io/library/golang:*",
|
|
MatchType: spb.MatchType_WILDCARD,
|
|
},
|
|
Updates: &spb.Update{
|
|
Identifier: "docker-image://fakereg.io/library/golang:${1}",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
op := &pb.SourceOp{
|
|
Identifier: "docker-image://docker.io/library/golang:1.19",
|
|
}
|
|
|
|
ctx := context.Background()
|
|
e := NewEngine(pol)
|
|
|
|
mutated, err := e.Evaluate(ctx, op)
|
|
require.True(t, mutated)
|
|
require.NoError(t, err)
|
|
require.Equal(t, "docker-image://fakereg.io/library/golang:1.19", op.Identifier)
|
|
}
|
|
|
|
func testConvertRegex(t *testing.T) {
|
|
pol := &spb.Policy{
|
|
Rules: []*spb.Rule{
|
|
{
|
|
Action: spb.PolicyAction_CONVERT,
|
|
Selector: &spb.Selector{
|
|
Identifier: `docker\-image://docker\.io/library/golang:(.*)`,
|
|
MatchType: spb.MatchType_REGEX,
|
|
},
|
|
Updates: &spb.Update{
|
|
Identifier: "docker-image://fakereg.io/library/golang:${1}",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
op := &pb.SourceOp{
|
|
Identifier: "docker-image://docker.io/library/golang:1.19",
|
|
}
|
|
|
|
ctx := context.Background()
|
|
e := NewEngine([]*spb.Policy{pol})
|
|
|
|
mutated, err := e.Evaluate(ctx, op)
|
|
require.True(t, mutated)
|
|
require.NoError(t, err)
|
|
require.Equal(t, "docker-image://fakereg.io/library/golang:1.19", op.Identifier)
|
|
}
|
|
|
|
func testConvertHTTP(t *testing.T) {
|
|
pol := &spb.Policy{
|
|
Rules: []*spb.Rule{
|
|
{
|
|
Action: spb.PolicyAction_CONVERT,
|
|
Selector: &spb.Selector{
|
|
Identifier: "https://example.com/foo",
|
|
},
|
|
Updates: &spb.Update{
|
|
Attrs: map[string]string{"http.checksum": "sha256:1234"},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
op := &pb.SourceOp{
|
|
Identifier: "https://example.com/foo",
|
|
}
|
|
|
|
ctx := context.Background()
|
|
e := NewEngine([]*spb.Policy{pol})
|
|
|
|
mutated, err := e.Evaluate(ctx, op)
|
|
require.True(t, mutated)
|
|
require.NoError(t, err)
|
|
require.Equal(t, "https://example.com/foo", op.Identifier)
|
|
}
|
|
|
|
func testConvertLoop(t *testing.T) {
|
|
pol := &spb.Policy{
|
|
Rules: []*spb.Rule{
|
|
{
|
|
Action: spb.PolicyAction_CONVERT,
|
|
Selector: &spb.Selector{
|
|
Identifier: "docker-image://docker.io/library/busybox:latest",
|
|
},
|
|
Updates: &spb.Update{
|
|
Identifier: "docker-image://docker.io/library/alpine:latest",
|
|
},
|
|
},
|
|
{
|
|
Action: spb.PolicyAction_CONVERT,
|
|
Selector: &spb.Selector{
|
|
Identifier: "docker-image://docker.io/library/alpine:latest",
|
|
},
|
|
Updates: &spb.Update{
|
|
Identifier: "docker-image://docker.io/library/busybox:latest",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
op := &pb.SourceOp{
|
|
Identifier: "docker-image://docker.io/library/busybox:latest",
|
|
}
|
|
|
|
ctx := context.Background()
|
|
e := NewEngine([]*spb.Policy{pol})
|
|
|
|
mutated, err := e.Evaluate(ctx, op)
|
|
require.True(t, mutated)
|
|
require.ErrorIs(t, err, ErrTooManyOps)
|
|
}
|
|
|
|
func testAllowConvertDeny(t *testing.T) {
|
|
pol := &spb.Policy{
|
|
Rules: []*spb.Rule{
|
|
{
|
|
Action: spb.PolicyAction_CONVERT,
|
|
Selector: &spb.Selector{
|
|
Identifier: "docker-image://docker.io/library/busybox:latest",
|
|
},
|
|
Updates: &spb.Update{
|
|
Identifier: "docker-image://docker.io/library/alpine:latest",
|
|
},
|
|
},
|
|
{
|
|
Action: spb.PolicyAction_ALLOW,
|
|
Selector: &spb.Selector{
|
|
Identifier: "docker-image://docker.io/library/alpine:latest",
|
|
},
|
|
},
|
|
{
|
|
Action: spb.PolicyAction_DENY,
|
|
Selector: &spb.Selector{
|
|
Identifier: "docker-image://docker.io/library/alpine:*",
|
|
},
|
|
},
|
|
{
|
|
Action: spb.PolicyAction_DENY,
|
|
Selector: &spb.Selector{
|
|
Identifier: "docker-image://docker.io/library/busybox:latest",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
op := &pb.SourceOp{
|
|
Identifier: "docker-image://docker.io/library/busybox:latest",
|
|
}
|
|
|
|
ctx := context.Background()
|
|
e := NewEngine([]*spb.Policy{pol})
|
|
|
|
mutated, err := e.Evaluate(ctx, op)
|
|
require.True(t, mutated)
|
|
require.ErrorIs(t, err, ErrSourceDenied)
|
|
require.Equal(t, "docker-image://docker.io/library/alpine:latest", op.Identifier)
|
|
}
|
|
|
|
func testConvertDeny(t *testing.T) {
|
|
pol := &spb.Policy{
|
|
Rules: []*spb.Rule{
|
|
{
|
|
Action: spb.PolicyAction_DENY,
|
|
Selector: &spb.Selector{
|
|
Identifier: "docker-image://docker.io/library/alpine:*",
|
|
},
|
|
},
|
|
{
|
|
Action: spb.PolicyAction_CONVERT,
|
|
Selector: &spb.Selector{
|
|
Identifier: "docker-image://docker.io/library/busybox:latest",
|
|
},
|
|
Updates: &spb.Update{
|
|
Identifier: "docker-image://docker.io/library/alpine:latest",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
op := &pb.SourceOp{
|
|
Identifier: "docker-image://docker.io/library/busybox:latest",
|
|
}
|
|
|
|
ctx := context.Background()
|
|
e := NewEngine([]*spb.Policy{pol})
|
|
|
|
mutated, err := e.Evaluate(ctx, op)
|
|
require.True(t, mutated)
|
|
require.ErrorIs(t, err, ErrSourceDenied)
|
|
require.Equal(t, "docker-image://docker.io/library/alpine:latest", op.Identifier)
|
|
}
|
|
|
|
func testConvert(t *testing.T) {
|
|
cases := map[string]string{
|
|
"docker-image://docker.io/library/busybox:latest": "docker-image://docker.io/library/alpine:latest",
|
|
"docker-image://docker.io/library/alpine:latest": "docker-image://docker.io/library/alpine:latest@sha256:c0d488a800e4127c334ad20d61d7bc21b4097540327217dfab52262adc02380c",
|
|
}
|
|
bklog.L.Logger.SetLevel(logrus.DebugLevel)
|
|
|
|
for src, dst := range cases {
|
|
t.Run(src+"=>"+dst, func(t *testing.T) {
|
|
op := &pb.SourceOp{
|
|
Identifier: src,
|
|
}
|
|
|
|
pol := &spb.Policy{
|
|
Rules: []*spb.Rule{
|
|
{
|
|
Action: spb.PolicyAction_CONVERT,
|
|
Selector: &spb.Selector{
|
|
Identifier: src,
|
|
},
|
|
Updates: &spb.Update{
|
|
Identifier: dst,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
ctx := context.Background()
|
|
e := NewEngine([]*spb.Policy{pol})
|
|
|
|
mutated, err := e.Evaluate(ctx, op)
|
|
require.True(t, mutated)
|
|
require.NoError(t, err)
|
|
require.Equal(t, dst, op.Identifier)
|
|
})
|
|
}
|
|
}
|
|
|
|
func testAllowDeny(t *testing.T) {
|
|
op := &pb.SourceOp{
|
|
Identifier: "docker-image://docker.io/library/alpine:latest",
|
|
}
|
|
pol := &spb.Policy{
|
|
Rules: []*spb.Rule{
|
|
{
|
|
Action: spb.PolicyAction_ALLOW,
|
|
Selector: &spb.Selector{
|
|
Identifier: "docker-image://docker.io/library/alpine:latest",
|
|
},
|
|
},
|
|
{
|
|
Action: spb.PolicyAction_DENY,
|
|
Selector: &spb.Selector{
|
|
Identifier: "docker-image://*",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
ctx := context.Background()
|
|
e := NewEngine([]*spb.Policy{pol})
|
|
|
|
mutated, err := e.Evaluate(ctx, op)
|
|
require.False(t, mutated)
|
|
require.ErrorIs(t, err, ErrSourceDenied)
|
|
|
|
op = &pb.SourceOp{
|
|
Identifier: "docker-image://docker.io/library/busybox:latest",
|
|
}
|
|
|
|
mutated, err = e.Evaluate(ctx, op)
|
|
require.False(t, mutated)
|
|
require.ErrorIs(t, err, ErrSourceDenied)
|
|
}
|
|
|
|
func testDenyAll(t *testing.T) {
|
|
cases := map[string]string{
|
|
"docker-image": "docker-image://docker.io/library/alpine:latest",
|
|
"https": "https://github.com/moby/buildkit.git",
|
|
"http": "http://example.com",
|
|
}
|
|
|
|
for kind, ref := range cases {
|
|
t.Run(ref, func(t *testing.T) {
|
|
pol := &spb.Policy{
|
|
Rules: []*spb.Rule{
|
|
{
|
|
Action: spb.PolicyAction_DENY,
|
|
Selector: &spb.Selector{
|
|
Identifier: kind + "://*",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
e := NewEngine([]*spb.Policy{pol})
|
|
ctx := context.Background()
|
|
|
|
op := &pb.SourceOp{
|
|
Identifier: ref,
|
|
}
|
|
|
|
mutated, err := e.Evaluate(ctx, op)
|
|
require.False(t, mutated)
|
|
require.ErrorIs(t, err, ErrSourceDenied)
|
|
})
|
|
}
|
|
}
|