Merge pull request #3738 from tonistiigi/policy-eval-upt

Updated for policy eval
This commit is contained in:
Tõnis Tiigi
2026-03-24 17:08:04 -07:00
committed by GitHub
5 changed files with 157 additions and 24 deletions
+43 -23
View File
@@ -4,6 +4,7 @@ import (
"context"
"encoding/json"
"fmt"
"io"
"io/fs"
"maps"
"os"
@@ -33,6 +34,7 @@ type evalOpts struct {
filename string
printOutput bool
fields []string
platform string
builder *string
}
@@ -49,9 +51,14 @@ func evalCmd(dockerCli command.Cli, rootOpts RootOptions) *cobra.Command {
return runEval(cmd.Context(), dockerCli, args[0], opts)
},
}
cmd.Flags().StringVar(&opts.filename, "filename", "Dockerfile", "Policy filename to evaluate")
cmd.Flags().BoolVar(&opts.printOutput, "print", false, "Print policy output")
cmd.Flags().StringSliceVar(&opts.fields, "fields", nil, "Fields to evaluate")
flags := cmd.Flags()
flags.StringVarP(&opts.filename, "file", "f", "Dockerfile", "Policy filename to evaluate")
flags.BoolVar(&opts.printOutput, "print", false, "Print policy output")
flags.StringSliceVar(&opts.fields, "fields", nil, "Fields to evaluate")
flags.StringVar(&opts.platform, "platform", "", "Target platform for policy evaluation")
// Deprecated: use --file instead
flags.StringVar(&opts.filename, "filename", "Dockerfile", "Policy filename to evaluate")
flags.MarkHidden("filename")
return cmd
}
@@ -81,29 +88,29 @@ func runEval(ctx context.Context, dockerCli command.Cli, source string, opts eva
return err
}
workers, err := c.ListWorkers(ctx)
if err != nil {
return err
}
var p ocispecs.Platform
if opts.platform != "" {
parsedPlatform, err := parsePlatform(opts.platform)
if err != nil {
return err
}
p = *parsedPlatform
} else {
workers, err := c.ListWorkers(ctx)
if err != nil {
return err
}
if len(workers) == 0 {
return errors.New("no workers available in the builder")
}
if len(workers) == 0 {
return errors.New("no workers available in the builder")
}
defaultPlatform := workers[0].Platforms[0]
p := ocispecs.Platform{
Architecture: defaultPlatform.Architecture,
OS: defaultPlatform.OS,
Variant: defaultPlatform.Variant,
p = workers[0].Platforms[0]
}
metaResolver := sourcemeta.NewResolver(c)
defer metaResolver.Close()
platform := &pb.Platform{
Architecture: p.Architecture,
OS: p.OS,
Variant: p.Variant,
}
platform := toPBPlatform(p)
verifier := policy.SignatureVerifier(confutil.NewConfig(dockerCli))
if opts.printOutput {
@@ -185,9 +192,8 @@ func runEval(ctx context.Context, dockerCli command.Cli, source string, opts eva
if opts.filename == "" {
return errors.New("filename is required")
}
policyName := opts.filename
policyFile := policyName + ".rego"
policyData, err := os.ReadFile(policyFile)
policyName, policyFile := policyFileNames(opts.filename)
policyData, err := readPolicyData(policyFile, os.Stdin)
if err != nil {
return errors.Wrapf(err, "failed to read policy file %s", policyFile)
}
@@ -261,6 +267,20 @@ func runEval(ctx context.Context, dockerCli command.Cli, source string, opts eva
}
}
func policyFileNames(filename string) (string, string) {
if filename == "-" {
return "stdin", filename
}
return filename, filename + ".rego"
}
func readPolicyData(filename string, stdin io.Reader) ([]byte, error) {
if filename == "-" {
return io.ReadAll(stdin)
}
return os.ReadFile(filename)
}
func selectReloadFields(fields []string, unknowns []string) ([]string, []string) {
if len(fields) == 0 {
return nil, nil
+29
View File
@@ -6,10 +6,39 @@ import (
policytypes "github.com/docker/buildx/policy"
"github.com/docker/buildx/util/sourcemeta"
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/stretchr/testify/require"
)
func TestParsePlatform(t *testing.T) {
t.Run("normalize", func(t *testing.T) {
platform, err := parsePlatform("linux/arm/v7")
require.NoError(t, err)
require.Equal(t, &ocispecs.Platform{
OS: "linux",
Architecture: "arm",
Variant: "v7",
}, platform)
})
t.Run("invalid", func(t *testing.T) {
platform, err := parsePlatform("not-a-platform")
require.Nil(t, platform)
require.Error(t, err)
require.ErrorContains(t, err, "invalid platform \"not-a-platform\"")
require.ErrorContains(t, err, "unknown operating system or architecture")
})
}
func TestToPBPlatform(t *testing.T) {
platform := ocispecs.Platform{OS: "linux", Architecture: "amd64"}
require.Equal(t, &pb.Platform{
OS: "linux",
Architecture: "amd64",
}, toPBPlatform(platform))
}
func TestSourceResolverOptIncludesResolveAttestations(t *testing.T) {
req := &gwpb.ResolveSourceMetaRequest{
ResolveMode: "default",
+25
View File
@@ -0,0 +1,25 @@
package policy
import (
"github.com/containerd/platforms"
"github.com/moby/buildkit/solver/pb"
ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
)
func parsePlatform(platform string) (*ocispecs.Platform, error) {
p, err := platforms.Parse(platform)
if err != nil {
return nil, errors.Wrapf(err, "invalid platform %q", platform)
}
p = platforms.Normalize(p)
return &p, nil
}
func toPBPlatform(platform ocispecs.Platform) *pb.Platform {
return &pb.Platform{
Architecture: platform.Architecture,
OS: platform.OS,
Variant: platform.Variant,
}
}