Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 18 additions & 3 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,9 @@ func setupControllers(ctx context.Context, mgr ctrl.Manager, tracker *readiness.
if *externaldata.ExternalDataEnabled {
providerCache = frameworksexternaldata.NewCache()
args = append(args, rego.AddExternalDataProviderCache(providerCache))
mutationOpts.ProviderCache = providerCache
if mutation.Enabled() {
mutationOpts.ProviderCache = providerCache
}

switch {
case *externaldataProviderResponseCacheTTL > 0:
Expand Down Expand Up @@ -460,7 +462,9 @@ func setupControllers(ctx context.Context, mgr ctrl.Manager, tracker *readiness.
args = append(args, rego.EnableExternalDataClientAuth(), rego.AddExternalDataClientCertWatcher(certWatcher))

// register the client cert watcher to the mutation system
mutationOpts.ClientCertWatcher = certWatcher
if mutation.Enabled() {
mutationOpts.ClientCertWatcher = certWatcher
}
}

cfArgs := []constraintclient.Opt{constraintclient.Targets(&target.K8sValidationTarget{})}
Expand Down Expand Up @@ -508,7 +512,7 @@ func setupControllers(ctx context.Context, mgr ctrl.Manager, tracker *readiness.
}
}

mutationSystem := mutation.NewSystem(mutationOpts)
mutationSystem := newMutationSystem(mutationOpts)
expansionSystem := expansion.NewSystem(mutationSystem)
exportSystem := export.NewSystem()

Expand Down Expand Up @@ -644,6 +648,17 @@ func setupControllers(ctx context.Context, mgr ctrl.Manager, tracker *readiness.
return nil
}

// newMutationSystem constructs the mutation system only when a mutation
// operation is assigned, so non-mutation processes do not carry an unused
// mutation system. expansion.System accepts a nil mutation system and skips
// applying mutators in that case.
func newMutationSystem(opts mutation.SystemOpts) *mutation.System {
if !mutation.Enabled() {
return nil
}
return mutation.NewSystem(opts)
}

func setLoggerForProduction(encoder zapcore.LevelEncoder, dest io.Writer) {
sink := zapcore.AddSync(os.Stderr)
if dest != nil {
Expand Down
36 changes: 36 additions & 0 deletions main_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package main

import (
"flag"
"testing"

"github.com/open-policy-agent/gatekeeper/v3/pkg/mutation"
)

// TestNewMutationSystem exercises the operation-dependent construction of
// the mutation system. The --operation flag can only accumulate values
// within a process, so the mutation-disabled case runs before the
// mutation-enabled cases.
func TestNewMutationSystem(t *testing.T) {
// Non-mutation operation set: no mutation system is constructed.
if err := flag.Set("operation", "audit"); err != nil {
t.Fatalf("setting operation flag: %v", err)
}
if mutation.Enabled() {
t.Fatalf("expected mutation to be disabled for audit-only operations")
}
if system := newMutationSystem(mutation.SystemOpts{}); system != nil {
t.Errorf("newMutationSystem() = %v, want nil when no mutation operation is assigned", system)
}

// Adding a mutation operation constructs a real system.
if err := flag.Set("operation", "mutation-controller"); err != nil {
t.Fatalf("setting operation flag: %v", err)
}
if !mutation.Enabled() {
t.Fatalf("expected mutation to be enabled once a mutation operation is assigned")
}
if system := newMutationSystem(mutation.SystemOpts{}); system == nil {
t.Error("newMutationSystem() = nil, want a system when a mutation operation is assigned")
}
}
4 changes: 4 additions & 0 deletions pkg/controller/mutators/instances/mutator_controllers.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ func routeConflictEvents(ctx context.Context, events <-chan event.GenericEvent,

// Add creates all mutation controllers and adds them to the manager.
func (a *Adder) Add(mgr manager.Manager) error {
if !mutation.Enabled() {
return nil
}

// events is shared across all mutators that can affect the implied schema
// of kinds to be mutated, since these mutators can set each other into conflict
events := make(chan event.GenericEvent, eventQueueSize)
Expand Down
17 changes: 17 additions & 0 deletions pkg/controller/mutators/instances/mutator_controllers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package instances

import (
"context"
"flag"
"testing"
"time"

Expand Down Expand Up @@ -142,3 +143,19 @@ func awaitCondition(t *testing.T, cond func() bool, message string) {

t.Fatal(message)
}

func TestAddSkipsSetupWhenMutationDisabled(t *testing.T) {
// Restrict this process to a non-mutation operation. The operation set
// is process-global and only accumulates via the flag, so this test
// must not run in parallel with operation-dependent tests.
if err := flag.Set("operation", "audit"); err != nil {
t.Fatalf("setting operation flag: %v", err)
}

// When mutation is disabled Add must return before touching the manager,
// registering the conflict-routing runnable, or building any channels.
a := &Adder{}
if err := a.Add(nil); err != nil {
t.Fatalf("Add() with mutation disabled = %v, want nil", err)
}
}