From 2b50409c643d31102a7c30680ccdadf2395550d5 Mon Sep 17 00:00:00 2001 From: Julian van den Berkmortel <7153670+Serializator@users.noreply.github.com> Date: Wed, 26 Mar 2025 21:10:10 +0100 Subject: [PATCH 1/2] feat: support print statement in gator verify command (#2949) Signed-off-by: Julian van den Berkmortel <7153670+Serializator@users.noreply.github.com> --- cmd/gator/verify/verify.go | 2 +- pkg/gator/opa.go | 16 ++++++++++++++-- pkg/gator/print.go | 20 ++++++++++++++++++++ pkg/gator/verify/runner.go | 16 ++++++++++++---- pkg/gator/verify/runner_test.go | 2 +- 5 files changed, 48 insertions(+), 8 deletions(-) create mode 100644 pkg/gator/print.go diff --git a/cmd/gator/verify/verify.go b/cmd/gator/verify/verify.go index 9639126d17d..ab04a25299c 100644 --- a/cmd/gator/verify/verify.go +++ b/cmd/gator/verify/verify.go @@ -112,7 +112,7 @@ func runE(cmd *cobra.Command, args []string) error { func runSuites(ctx context.Context, fileSystem fs.FS, suites []*verify.Suite, filter verify.Filter) error { isFailure := false - runner, err := verify.NewRunner(fileSystem, gator.NewOPAClient, verify.IncludeTrace(includeTrace), verify.UseK8sCEL(flagEnableK8sCel)) + runner, err := verify.NewRunner(fileSystem, gator.NewOPAClient, verify.IncludeTrace(includeTrace), verify.EnablePrint(verbose), verify.UseK8sCEL(flagEnableK8sCel)) if err != nil { return err } diff --git a/pkg/gator/opa.go b/pkg/gator/opa.go index 621dd0eb50e..5646b0a1b5a 100644 --- a/pkg/gator/opa.go +++ b/pkg/gator/opa.go @@ -6,9 +6,10 @@ import ( "github.com/open-policy-agent/gatekeeper/v3/pkg/drivers/k8scel" "github.com/open-policy-agent/gatekeeper/v3/pkg/target" "github.com/open-policy-agent/gatekeeper/v3/pkg/util" + "os" ) -func NewOPAClient(includeTrace bool, k8sCEL bool) (Client, error) { +func NewOPAClient(includeTrace bool, printEnabled bool, k8sCEL bool) (Client, error) { args := []constraintclient.Opt{constraintclient.Targets(&target.K8sValidationTarget{})} if k8sCEL { @@ -19,7 +20,18 @@ func NewOPAClient(includeTrace bool, k8sCEL bool) (Client, error) { args = append(args, constraintclient.Driver(k8sDriver)) } - driver, err := rego.New(rego.Tracing(includeTrace)) + driverArgs := []rego.Arg{ + rego.Tracing(includeTrace), + } + + if printEnabled { + driverArgs = append(driverArgs, + rego.PrintEnabled(printEnabled), + rego.PrintHook(NewPrintHook(os.Stdout)), + ) + } + + driver, err := rego.New(driverArgs...) if err != nil { return nil, err } diff --git a/pkg/gator/print.go b/pkg/gator/print.go new file mode 100644 index 00000000000..0b824b44ce3 --- /dev/null +++ b/pkg/gator/print.go @@ -0,0 +1,20 @@ +package gator + +import ( + "fmt" + v1 "github.com/open-policy-agent/opa/v1/topdown/print" + "io" +) + +type PrintHook struct { + writer io.Writer +} + +func NewPrintHook(writer io.Writer) PrintHook { + return PrintHook{writer} +} + +func (h PrintHook) Print(ctx v1.Context, string string) error { + _, err := fmt.Fprintln(h.writer, string) + return err +} diff --git a/pkg/gator/verify/runner.go b/pkg/gator/verify/runner.go index 0f9a13a6afe..d246654d606 100644 --- a/pkg/gator/verify/runner.go +++ b/pkg/gator/verify/runner.go @@ -34,16 +34,18 @@ type Runner struct { // newClient instantiates a Client for compiling Templates/Constraints, and // validating objects against them. - newClient func(includeTrace bool, useK8sCEL bool) (gator.Client, error) + newClient func(includeTrace bool, printEnabled bool, useK8sCEL bool) (gator.Client, error) scheme *runtime.Scheme includeTrace bool + printEnabled bool + useK8sCEL bool } -func NewRunner(filesystem fs.FS, newClient func(includeTrace bool, useK8sCEL bool) (gator.Client, error), opts ...RunnerOptions) (*Runner, error) { +func NewRunner(filesystem fs.FS, newClient func(includeTrace bool, printEnabled bool, useK8sCEL bool) (gator.Client, error), opts ...RunnerOptions) (*Runner, error) { s := runtime.NewScheme() err := apis.AddToScheme(s) if err != nil { @@ -71,6 +73,12 @@ func IncludeTrace(includeTrace bool) RunnerOptions { } } +func EnablePrint(printEnabled bool) RunnerOptions { + return func(r *Runner) { + r.printEnabled = printEnabled + } +} + func UseK8sCEL(useK8sCEL bool) RunnerOptions { return func(r *Runner) { r.useK8sCEL = useK8sCEL @@ -144,7 +152,7 @@ func (r *Runner) runTest(ctx context.Context, suiteDir string, filter Filter, t } func (r *Runner) tryAddConstraint(ctx context.Context, suiteDir string, t *Test) error { - client, err := r.newClient(r.includeTrace, r.useK8sCEL) + client, err := r.newClient(r.includeTrace, r.printEnabled, r.useK8sCEL) if err != nil { return fmt.Errorf("%w: %w", gator.ErrCreatingClient, err) } @@ -213,7 +221,7 @@ func (r *Runner) skipCase(tc *Case) CaseResult { } func (r *Runner) makeTestClient(ctx context.Context, suiteDir string, t *Test) (gator.Client, error) { - client, err := r.newClient(r.includeTrace, r.useK8sCEL) + client, err := r.newClient(r.includeTrace, r.printEnabled, r.useK8sCEL) if err != nil { return nil, fmt.Errorf("%w: %w", gator.ErrCreatingClient, err) } diff --git a/pkg/gator/verify/runner_test.go b/pkg/gator/verify/runner_test.go index 2fe1a1ae088..3dae026911d 100644 --- a/pkg/gator/verify/runner_test.go +++ b/pkg/gator/verify/runner_test.go @@ -1268,7 +1268,7 @@ func TestRunner_Run_ClientError(t *testing.T) { TestResults: []TestResult{{Error: gator.ErrCreatingClient}}, } - runner, err := NewRunner(fstest.MapFS{}, func(_ bool, _ bool) (gator.Client, error) { + runner, err := NewRunner(fstest.MapFS{}, func(_ bool, _ bool, _ bool) (gator.Client, error) { return nil, errors.New("error") }) if err != nil { From cd1637c49e1b803327d664f3b67372b9350ca8b4 Mon Sep 17 00:00:00 2001 From: Julian van den Berkmortel <7153670+Serializator@users.noreply.github.com> Date: Sat, 19 Jul 2025 20:45:16 +0200 Subject: [PATCH 2/2] feat: support print statement in gator test command (#2949) Signed-off-by: Julian van den Berkmortel <7153670+Serializator@users.noreply.github.com> --- cmd/gator/test/test.go | 10 +++++++++- pkg/gator/test/test.go | 9 +++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/cmd/gator/test/test.go b/cmd/gator/test/test.go index e697b020144..c33d9ce0a8d 100644 --- a/cmd/gator/test/test.go +++ b/cmd/gator/test/test.go @@ -50,6 +50,7 @@ var ( flagTempDir string flagEnableK8sCel bool flagDenyOnly bool + flagVerbose bool ) const ( @@ -57,6 +58,7 @@ const ( flagNameOutput = "output" flagNameImage = "image" flagNameTempDir = "tempdir" + flagNameVerbose = "verbose" stringJSON = "json" stringYAML = "yaml" @@ -74,6 +76,7 @@ func init() { Cmd.Flags().StringArrayVarP(&flagImages, flagNameImage, "i", []string{}, "a URL to an OCI image containing policies. Can be specified multiple times.") Cmd.Flags().StringVarP(&flagTempDir, flagNameTempDir, "d", "", fmt.Sprintf("Specifies the temporary directory to download and unpack images to, if using the --%s flag. Optional.", flagNameImage)) Cmd.Flags().BoolVarP(&flagDenyOnly, "deny-only", "", false, "output only denied constraints") + Cmd.Flags().BoolVarP(&flagVerbose, flagNameVerbose, "v", false, "print extended test output") } func run(_ *cobra.Command, _ []string) { @@ -85,7 +88,12 @@ func run(_ *cobra.Command, _ []string) { cmdutils.ErrFatalf("no input data identified") } - responses, err := test.Test(unstrucs, test.Opts{IncludeTrace: flagIncludeTrace, GatherStats: flagGatherStats, UseK8sCEL: flagEnableK8sCel}) + responses, err := test.Test(unstrucs, test.Opts{ + IncludeTrace: flagIncludeTrace, + GatherStats: flagGatherStats, + UseK8sCEL: flagEnableK8sCel, + Verbose: flagVerbose, + }) if err != nil { cmdutils.ErrFatalf("auditing objects: %v", err) } diff --git a/pkg/gator/test/test.go b/pkg/gator/test/test.go index 3ce30a2eb8c..04333e44cfe 100644 --- a/pkg/gator/test/test.go +++ b/pkg/gator/test/test.go @@ -3,6 +3,7 @@ package test import ( "context" "fmt" + "os" "github.com/open-policy-agent/frameworks/constraint/pkg/apis" constraintclient "github.com/open-policy-agent/frameworks/constraint/pkg/client" @@ -10,6 +11,7 @@ import ( "github.com/open-policy-agent/frameworks/constraint/pkg/client/reviews" "github.com/open-policy-agent/gatekeeper/v3/pkg/drivers/k8scel" "github.com/open-policy-agent/gatekeeper/v3/pkg/expansion" + "github.com/open-policy-agent/gatekeeper/v3/pkg/gator" "github.com/open-policy-agent/gatekeeper/v3/pkg/gator/expand" "github.com/open-policy-agent/gatekeeper/v3/pkg/gator/reader" mutationtypes "github.com/open-policy-agent/gatekeeper/v3/pkg/mutation/types" @@ -35,6 +37,7 @@ type Opts struct { IncludeTrace bool GatherStats bool UseK8sCEL bool + Verbose bool } func Test(objs []*unstructured.Unstructured, tOpts Opts) (*GatorResponses, error) { @@ -184,6 +187,12 @@ func makeRegoDriver(tOpts Opts) (*rego.Driver, error) { if tOpts.IncludeTrace { args = append(args, rego.Tracing(tOpts.IncludeTrace)) } + if tOpts.Verbose { + args = append(args, + rego.PrintEnabled(tOpts.Verbose), + rego.PrintHook(gator.NewPrintHook(os.Stdout)), + ) + } return rego.New(args...) }